Changeset 286857 in webkit
- Timestamp:
- Dec 10, 2021, 9:28:10 AM (5 years ago)
- Location:
- trunk
- Files:
-
- 4 added
- 3 deleted
- 15 edited
-
LayoutTests/ChangeLog (modified) (1 diff)
-
LayoutTests/model-element/model-element-contents-layer-updates-with-clipping.html (modified) (1 diff)
-
LayoutTests/model-element/model-element-contents-layer-updates.html (modified) (1 diff)
-
LayoutTests/model-element/model-element-error-and-load-events-expected.txt (deleted)
-
LayoutTests/model-element/model-element-error-and-load-events.html (deleted)
-
LayoutTests/model-element/model-element-graphics-layers-opacity.html (modified) (1 diff)
-
LayoutTests/model-element/model-element-graphics-layers.html (modified) (1 diff)
-
LayoutTests/model-element/model-element-ready-expected.txt (modified) (1 diff)
-
LayoutTests/model-element/model-element-ready-load-aborted-expected.txt (added)
-
LayoutTests/model-element/model-element-ready-load-aborted.html (added)
-
LayoutTests/model-element/model-element-ready-load-failed-expected.txt (added)
-
LayoutTests/model-element/model-element-ready-load-failed.html (added)
-
LayoutTests/model-element/model-element-ready.html (modified) (1 diff)
-
LayoutTests/model-element/resources/model-element-test-utils.js (deleted)
-
LayoutTests/platform/ios-simulator/TestExpectations (modified) (1 diff)
-
LayoutTests/platform/mac/TestExpectations (modified) (2 diffs)
-
Source/WebCore/ChangeLog (modified) (1 diff)
-
Source/WebCore/Modules/model-element/HTMLModelElement.cpp (modified) (11 diffs)
-
Source/WebCore/Modules/model-element/HTMLModelElement.h (modified) (6 diffs)
-
Source/WebCore/Modules/model-element/HTMLModelElement.idl (modified) (1 diff)
-
Tools/ChangeLog (modified) (1 diff)
-
Tools/TestWebKitAPI/Tests/ios/DragAndDropTestsIOS.mm (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r286855 r286857 1 2021-12-10 Commit Queue <commit-queue@webkit.org> 2 3 Unreviewed, reverting r286836. 4 https://bugs.webkit.org/show_bug.cgi?id=234153 5 6 some tests are flaky on iOS and some are crashing on macOS 7 8 Reverted changeset: 9 10 "[Model] Add load and error events to distinguish resource 11 load from model readiness" 12 https://bugs.webkit.org/show_bug.cgi?id=233706 13 https://commits.webkit.org/r286836 14 1 15 2021-12-10 Chris Dumez <cdumez@apple.com> 2 16 -
trunk/LayoutTests/model-element/model-element-contents-layer-updates-with-clipping.html
r286836 r286857 7 7 <pre id="layers"></pre> 8 8 <script> 9 window.testRunner?.waitUntilDone();10 window.testRunner?.dumpAsText();9 let layers = document.getElementById("layers"); 10 let source = document.getElementsByTagName("source")[0]; 11 11 12 const layers = document.getElementById("layers"); 13 const source = document.querySelector("source"); 14 const model = document.getElementById("model"); 12 if (window.testRunner) { 13 testRunner.waitUntilDone(); 14 testRunner.dumpAsText(); 15 } else 16 layers.textContent = "This test requires testRunner."; 15 17 16 const modelDidLoadFirstSource = () => { 18 let model = document.getElementById("model"); 19 20 model.ready.then(value => { 17 21 layers.textContent = "Before Changing Source:\n"; 18 layers.textContent += window.internals?.platformLayerTreeAsText(model, window.internals.PLATFORM_LAYER_TREE_INCLUDE_MODELS) ?? "This test requires testRunner."; 19 20 model.addEventListener("load", event => { 21 layers.textContent += "After Changing Source:\n"; 22 layers.textContent += window.internals?.platformLayerTreeAsText(model, window.internals.PLATFORM_LAYER_TREE_INCLUDE_MODELS) ?? "This test requires testRunner."; 23 window.testRunner?.notifyDone(); 24 }, { once: true }); 25 26 model.addEventListener("error", event => { 27 layers.textContent = `Failed. Second model did not load.`; 28 window.testRunner?.notifyDone(); 29 }, { once: true }); 22 layers.textContent += window.internals.platformLayerTreeAsText(model, window.internals.PLATFORM_LAYER_TREE_INCLUDE_MODELS); 30 23 31 24 source.src = "resources/cube.usdz"; 32 } 33 34 if (model.complete) 35 modelDidLoadFirstSource(); 36 else { 37 model.addEventListener("load", modelDidLoadFirstSource, { once: true }); 38 model.addEventListener("error", event => { 39 layers.textContent = `Failed. First model did not load.`; 40 window.testRunner?.notifyDone(); 41 }, { once: true }); 42 } 25 model.ready.then(value => { 26 if (window.testRunner) { 27 layers.textContent += "After Changing Source:\n"; 28 layers.textContent += window.internals.platformLayerTreeAsText(model, window.internals.PLATFORM_LAYER_TREE_INCLUDE_MODELS); 29 } 30 }, reason => { 31 layers.textContent = `Failed. Second model did not load: ${reason}`; 32 }).finally(() => { 33 if (window.testRunner) 34 testRunner.notifyDone(); 35 }); 36 37 }, reason => { 38 layers.textContent = `Failed. First model did not load: ${reason}`; 39 if (window.testRunner) 40 testRunner.notifyDone(); 41 }); 43 42 </script> 44 43 </body> -
trunk/LayoutTests/model-element/model-element-contents-layer-updates.html
r286836 r286857 7 7 <pre id="layers"></pre> 8 8 <script> 9 window.testRunner?.waitUntilDone();10 window.testRunner?.dumpAsText();9 let layers = document.getElementById("layers"); 10 let source = document.getElementsByTagName("source")[0]; 11 11 12 const layers = document.getElementById("layers"); 13 const source = document.querySelector("source"); 14 const model = document.getElementById("model"); 12 if (window.testRunner) { 13 testRunner.waitUntilDone(); 14 testRunner.dumpAsText(); 15 } else 16 layers.textContent = "This test requires testRunner."; 15 17 16 const modelDidLoadFirstSource = () => { 18 let model = document.getElementById("model"); 19 20 model.ready.then(value => { 17 21 layers.textContent = "Before Changing Source:\n"; 18 layers.textContent += window.internals?.platformLayerTreeAsText(model, window.internals.PLATFORM_LAYER_TREE_INCLUDE_MODELS) ?? "This test requires testRunner."; 19 20 model.addEventListener("load", event => { 21 layers.textContent += "After Changing Source:\n"; 22 layers.textContent += window.internals?.platformLayerTreeAsText(model, window.internals.PLATFORM_LAYER_TREE_INCLUDE_MODELS) ?? "This test requires testRunner."; 23 window.testRunner?.notifyDone(); 24 }, { once: true }); 25 26 model.addEventListener("error", event => { 27 layers.textContent = `Failed. Second model did not load.`; 28 window.testRunner?.notifyDone(); 29 }, { once: true }); 22 layers.textContent += window.internals.platformLayerTreeAsText(model, window.internals.PLATFORM_LAYER_TREE_INCLUDE_MODELS); 30 23 31 24 source.src = "resources/cube.usdz"; 32 } 33 34 if (model.complete) 35 modelDidLoadFirstSource(); 36 else { 37 model.addEventListener("load", modelDidLoadFirstSource, { once: true }); 38 model.addEventListener("error", event => { 39 layers.textContent = `Failed. First model did not load.`; 40 window.testRunner?.notifyDone(); 41 }, { once: true }); 42 } 25 model.ready.then(value => { 26 if (window.testRunner) { 27 layers.textContent += "After Changing Source:\n"; 28 layers.textContent += window.internals.platformLayerTreeAsText(model, window.internals.PLATFORM_LAYER_TREE_INCLUDE_MODELS); 29 } 30 }, reason => { 31 layers.textContent = `Failed. Second model did not load: ${reason}`; 32 }).finally(() => { 33 if (window.testRunner) 34 testRunner.notifyDone(); 35 }); 36 37 }, reason => { 38 layers.textContent = `Failed. First model did not load: ${reason}`; 39 if (window.testRunner) 40 testRunner.notifyDone(); 41 }); 43 42 </script> 44 43 </body> -
trunk/LayoutTests/model-element/model-element-graphics-layers-opacity.html
r286836 r286857 14 14 <pre id="layers"></pre> 15 15 <script> 16 window.testRunner?.waitUntilDone(); 17 window.testRunner?.dumpAsText(); 16 let layers = document.getElementById("layers"); 18 17 19 const layers = document.getElementById("layers"); 20 const model = document.getElementById("model"); 18 if (window.testRunner) { 19 testRunner.waitUntilDone(); 20 testRunner.dumpAsText(); 21 } else 22 layers.textContent = "This test requires testRunner."; 21 23 22 const modelDidLoad = () => { 23 layers.innerText = window.internals?.platformLayerTreeAsText(model) ?? "This test requires testRunner."; 24 let model = document.getElementById("model"); 25 26 model.ready.then(value => { 27 if (window.testRunner) 28 layers.innerText = window.internals.platformLayerTreeAsText(model); 24 29 model.remove(); 25 window.testRunner?.notifyDone(); 26 }; 27 28 if (model.complete) 29 modelDidLoad(); 30 else { 31 model.addEventListener("load", modelDidLoad); 32 model.addEventListener("error", event => { 33 layers.textContent = `Failed. Model did not load.`; 34 window.testRunner?.notifyDone(); 35 }); 36 } 30 }, reason => { 31 layers.textContent = `Failed. Model did not load: ${reason}`; 32 }).finally(() => { 33 if (window.testRunner) 34 testRunner.notifyDone(); 35 }); 37 36 </script> 38 37 </body> -
trunk/LayoutTests/model-element/model-element-graphics-layers.html
r286836 r286857 7 7 <pre id="layers"></pre> 8 8 <script> 9 window.testRunner?.waitUntilDone(); 10 window.testRunner?.dumpAsText(); 9 let layers = document.getElementById("layers"); 11 10 12 const layers = document.getElementById("layers"); 13 const model = document.getElementById("model"); 11 if (window.testRunner) { 12 testRunner.waitUntilDone(); 13 testRunner.dumpAsText(); 14 } else 15 layers.textContent = "This test requires testRunner."; 14 16 15 const modelDidLoad = () => { 16 layers.innerText = window.internals?.layerTreeAsText(document) ?? "This test requires testRunner."; 17 let model = document.getElementById("model"); 18 19 model.ready.then(value => { 20 if (window.testRunner) 21 layers.innerText = window.internals.layerTreeAsText(document); 17 22 model.remove(); 18 window.testRunner?.notifyDone(); 19 } 20 21 if (model.complete) 22 modelDidLoad(); 23 else { 24 model.addEventListener("load", modelDidLoad); 25 model.addEventListener("error", event => { 26 layers.textContent = `Failed. Model did not load.`; 27 window.testRunner?.notifyDone(); 28 }); 29 } 23 }, reason => { 24 layers.textContent = `Failed. Model did not load: ${reason}`; 25 }).finally(() => { 26 if (window.testRunner) 27 testRunner.notifyDone(); 28 }); 30 29 </script> 31 30 </body> -
trunk/LayoutTests/model-element/model-element-ready-expected.txt
r286836 r286857 1 This test passes if you see the word "Passed" below: 1 2 2 PASS <model> rejects the ready promise when provided with an unknown resoure. 3 PASS <model> rejects the ready promise when its resource load is aborted. 4 PASS <model> resolves the ready promise when provided with a known resource. 5 3 Passed -
trunk/LayoutTests/model-element/model-element-ready.html
r286836 r286857 1 <!doctype html> 2 <meta charset="utf-8"> 3 <title><model> ready promise</title> 4 <script src="../resources/testharness.js"></script> 5 <script src="../resources/testharnessreport.js"></script> 6 <script src="resources/model-element-test-utils.js"></script> 1 <!DOCTYPE html><!-- webkit-test-runner [ ModelElementEnabled=true ] --> 2 <html> 7 3 <body> 4 <model id="model"> 5 <source src="resources/heart.usdz"> 6 </model> 7 <p>This test passes if you see the word "Passed" below:</p> 8 <p id="result">Failed</p> 8 9 <script> 9 'use strict'; 10 if (window.testRunner) { 11 testRunner.waitUntilDone(); 12 testRunner.dumpAsText(); 13 } 10 14 11 promise_test(async t => { 12 const [model, source] = createModelAndSource(t, "resources/does-not-exist.usdz"); 13 return model.ready.then( 14 value => assert_unreached("Unexpected ready promise resolution."), 15 reason => assert_true(reason.toString().includes("NetworkError"), "The ready promise is rejected with a NetworkError.") 16 ); 17 }, `<model> rejects the ready promise when provided with an unknown resoure.`); 15 let result = document.getElementById("result"); 16 let model = document.getElementById("model"); 18 17 19 promise_test(async t => { 20 const [model, source] = createModelAndSource(t, "resources/heart.usdz"); 21 const modelReady = model.ready; 22 23 source.remove(); 24 assert_not_equals(model.ready, modelReady, "Removing the <source> child resets the ready promise."); 25 26 return modelReady.then( 27 value => assert_unreached("Unexpected ready promise resolution."), 28 reason => assert_true(reason.toString().includes("AbortError"), "The ready promise is rejected with a NetworkError.") 29 ); 30 }, `<model> rejects the ready promise when its resource load is aborted.`); 31 32 promise_test(async t => { 33 const [model, source] = createModelAndSource(t, "resources/cube.usdz"); 34 await model.ready; 35 }, `<model> resolves the ready promise when provided with a known resource.`); 36 18 model.ready.then(value => { 19 result.textContent = `Passed`; 20 }, reason => { 21 result.textContent = `Failed. Model did not load: ${reason}`; 22 }).finally(() => { 23 if (window.testRunner) 24 testRunner.notifyDone(); 25 }); 37 26 </script> 38 27 </body> 28 </html> -
trunk/LayoutTests/platform/ios-simulator/TestExpectations
r286836 r286857 153 153 154 154 webkit.org/b/223949 crypto/crypto-random-values-oom.html [ Pass Timeout ] 155 156 # This test relies on ARQL APIs which are not available in the Simulator157 model-element/model-element-ready.html [ Skip ] -
trunk/LayoutTests/platform/mac/TestExpectations
r286836 r286857 2283 2283 [ Monterey ] imported/w3c/web-platform-tests/fetch/connection-pool/network-partition-key.html [ Failure ] 2284 2284 2285 # webkit.org/b/228200 Setting multiple test expectations for Mon terey on OpenSource:2285 # webkit.org/b/228200 Setting multiple test expectations for Monetery on OpenSource: 2286 2286 [ Monterey ] model-element/model-element-graphics-layers-opacity.html [ Pass Failure ] 2287 2287 [ Monterey Debug arm64 ] imported/w3c/web-platform-tests/webrtc/RTCPeerConnection-restartIce.https.html [ Pass Failure Crash ] … … 2429 2429 2430 2430 webkit.org/b/221230 [ BigSur+ ] imported/w3c/web-platform-tests/media-source/mediasource-addsourcebuffer.html [ Pass Failure ] 2431 2432 # <model> tests involving the ready promise can only work on Monterey and up2433 [ Catalina BigSur ] model-element/model-element-ready.html [ Skip ] -
trunk/Source/WebCore/ChangeLog
r286855 r286857 1 2021-12-10 Commit Queue <commit-queue@webkit.org> 2 3 Unreviewed, reverting r286836. 4 https://bugs.webkit.org/show_bug.cgi?id=234153 5 6 some tests are flaky on iOS and some are crashing on macOS 7 8 Reverted changeset: 9 10 "[Model] Add load and error events to distinguish resource 11 load from model readiness" 12 https://bugs.webkit.org/show_bug.cgi?id=233706 13 https://commits.webkit.org/r286836 14 1 15 2021-12-10 Chris Dumez <cdumez@apple.com> 2 16 -
trunk/Source/WebCore/Modules/model-element/HTMLModelElement.cpp
r286836 r286857 66 66 HTMLModelElement::HTMLModelElement(const QualifiedName& tagName, Document& document) 67 67 : HTMLElement(tagName, document) 68 , ActiveDOMObject(document)69 68 , m_readyPromise { makeUniqueRef<ReadyPromise>(*this, &HTMLModelElement::readyPromiseResolve) } 70 69 { 71 setHasCustomStyleResolveCallbacks();72 70 } 73 71 … … 82 80 Ref<HTMLModelElement> HTMLModelElement::create(const QualifiedName& tagName, Document& document) 83 81 { 84 auto model = adoptRef(*new HTMLModelElement(tagName, document)); 85 model->suspendIfNeeded(); 86 return model; 82 return adoptRef(*new HTMLModelElement(tagName, document)); 87 83 } 88 84 … … 136 132 137 133 m_readyPromise = makeUniqueRef<ReadyPromise>(*this, &HTMLModelElement::readyPromiseResolve); 138 m_shouldCreateModelPlayerUponRendererAttachment = false; 139 140 if (m_sourceURL.isEmpty()) { 141 queueTaskToDispatchEvent(*this, TaskSource::DOMManipulation, Event::create(eventNames().errorEvent, Event::CanBubble::No, Event::IsCancelable::No)); 142 return; 143 } 134 135 if (m_sourceURL.isEmpty()) 136 return; 144 137 145 138 ResourceLoaderOptions options = CachedResourceLoader::defaultCachedResourceOptions(); … … 153 146 auto resource = document().cachedResourceLoader().requestModelResource(WTFMove(request)); 154 147 if (!resource.has_value()) { 155 queueTaskToDispatchEvent(*this, TaskSource::DOMManipulation, Event::create(eventNames().errorEvent, Event::CanBubble::No, Event::IsCancelable::No));156 148 m_readyPromise->reject(Exception { NetworkError }); 157 149 return; … … 182 174 { 183 175 return createRenderer<RenderModel>(*this, WTFMove(style)); 184 }185 186 void HTMLModelElement::didAttachRenderers()187 {188 if (!m_shouldCreateModelPlayerUponRendererAttachment)189 return;190 191 m_shouldCreateModelPlayerUponRendererAttachment = false;192 createModelPlayer();193 176 } 194 177 … … 215 198 m_data = nullptr; 216 199 217 queueTaskToDispatchEvent(*this, TaskSource::DOMManipulation, Event::create(eventNames().errorEvent, Event::CanBubble::No, Event::IsCancelable::No));218 219 200 invalidateResourceHandleAndUpdateRenderer(); 220 201 … … 226 207 m_model = Model::create(m_data.releaseNonNull().get(), resource.mimeType(), resource.url()); 227 208 228 queueTaskToDispatchEvent(*this, TaskSource::DOMManipulation, Event::create(eventNames().loadEvent, Event::CanBubble::No, Event::IsCancelable::No));229 230 209 invalidateResourceHandleAndUpdateRenderer(); 231 210 211 m_readyPromise->resolve(*this); 212 232 213 modelDidChange(); 233 214 } … … 237 218 void HTMLModelElement::modelDidChange() 238 219 { 239 auto* page = document().page(); 240 if (!page) { 241 m_readyPromise->reject(Exception { AbortError }); 242 return; 243 } 220 // FIXME: For the early returns here, we should probably inform the page that things have 221 // failed to render. For the case of no-renderer, we should probably also build the model 222 // when/if a renderer is created. 223 224 auto page = document().page(); 225 if (!page) 226 return; 244 227 245 228 auto* renderer = this->renderer(); 246 if (!renderer) { 247 m_shouldCreateModelPlayerUponRendererAttachment = true; 248 return; 249 } 250 251 createModelPlayer(); 252 } 253 254 void HTMLModelElement::createModelPlayer() 255 { 256 ASSERT(document().page()); 257 m_modelPlayer = document().page()->modelPlayerProvider().createModelPlayer(*this); 258 if (!m_modelPlayer) { 259 m_readyPromise->reject(Exception { AbortError }); 260 return; 261 } 229 if (!renderer) 230 return; 231 232 m_modelPlayer = page->modelPlayerProvider().createModelPlayer(*this); 233 if (!m_modelPlayer) 234 return; 262 235 263 236 // FIXME: We need to tell the player if the size changes as well, so passing this 264 237 // in with load probably doesn't make sense. 265 ASSERT(renderer()); 266 auto size = renderer()->absoluteBoundingBoxRect(false).size(); 238 auto size = renderer->absoluteBoundingBoxRect(false).size(); 267 239 m_modelPlayer->load(*m_model, size); 268 240 } … … 284 256 if (auto* renderer = this->renderer()) 285 257 renderer->updateFromElement(); 286 287 m_readyPromise->resolve(*this);288 258 } 289 259 … … 291 261 { 292 262 ASSERT_UNUSED(modelPlayer, &modelPlayer == m_modelPlayer); 293 m_readyPromise->reject(Exception { AbortError });294 263 } 295 264 … … 584 553 } 585 554 586 const char* HTMLModelElement::activeDOMObjectName() const587 {588 return "HTMLModelElement";589 }590 591 bool HTMLModelElement::virtualHasPendingActivity() const592 {593 // We need to ensure the JS wrapper is kept alive if a load is in progress and we may yet dispatch594 // "load" or "error" events, ie. as long as we have a resource, meaning we are in the process of loading.595 return m_resource;596 }597 598 555 #if PLATFORM(COCOA) 599 556 Vector<RetainPtr<id>> HTMLModelElement::accessibilityChildren() -
trunk/Source/WebCore/Modules/model-element/HTMLModelElement.h
r286836 r286857 28 28 #if ENABLE(MODEL_ELEMENT) 29 29 30 #include "ActiveDOMObject.h"31 30 #include "CachedRawResource.h" 32 31 #include "CachedRawResourceClient.h" … … 51 50 template<typename IDLType> class DOMPromiseProxyWithResolveCallback; 52 51 53 class HTMLModelElement final : public HTMLElement, private CachedRawResourceClient, public ModelPlayerClient , public ActiveDOMObject{52 class HTMLModelElement final : public HTMLElement, private CachedRawResourceClient, public ModelPlayerClient { 54 53 WTF_MAKE_ISO_ALLOCATED(HTMLModelElement); 55 54 public: … … 59 58 void sourcesChanged(); 60 59 const URL& currentSrc() const { return m_sourceURL; } 61 bool complete() const { return m_dataComplete; }62 60 63 61 // MARK: DOM Functions and Attributes … … 109 107 void setSourceURL(const URL&); 110 108 void modelDidChange(); 111 void createModelPlayer();112 109 113 110 HTMLModelElement& readyPromiseResolve(); 114 115 // ActiveDOMObject116 const char* activeDOMObjectName() const final;117 bool virtualHasPendingActivity() const final;118 111 119 112 // DOM overrides. … … 122 115 // Rendering overrides. 123 116 RenderPtr<RenderElement> createElementRenderer(RenderStyle&&, const RenderTreePosition&) final; 124 void didAttachRenderers() final;125 117 126 118 // CachedRawResourceClient overrides. … … 147 139 bool m_dataComplete { false }; 148 140 bool m_isDragging { false }; 149 bool m_shouldCreateModelPlayerUponRendererAttachment { false };150 141 151 142 RefPtr<ModelPlayer> m_modelPlayer; -
trunk/Source/WebCore/Modules/model-element/HTMLModelElement.idl
r286836 r286857 31 31 [URL] readonly attribute USVString currentSrc; 32 32 33 readonly attribute boolean complete;34 33 readonly attribute Promise<HTMLModelElement> ready; 35 34 -
trunk/Tools/ChangeLog
r286838 r286857 1 2021-12-10 Commit Queue <commit-queue@webkit.org> 2 3 Unreviewed, reverting r286836. 4 https://bugs.webkit.org/show_bug.cgi?id=234153 5 6 some tests are flaky on iOS and some are crashing on macOS 7 8 Reverted changeset: 9 10 "[Model] Add load and error events to distinguish resource 11 load from model readiness" 12 https://bugs.webkit.org/show_bug.cgi?id=233706 13 https://commits.webkit.org/r286836 14 1 15 2021-12-10 Kimmo Kinnunen <kkinnunen@apple.com> 2 16 -
trunk/Tools/TestWebKitAPI/Tests/ios/DragAndDropTestsIOS.mm
r286836 r286857 2198 2198 2199 2199 auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500) configuration:configuration.get()]); 2200 [webView synchronouslyLoadHTMLString:@"<model><source src='model://cube.usdz'></model><script>document. querySelector('model').addEventListener('load', event => window.webkit.messageHandlers.modelLoading.postMessage('READY'));</script>"];2200 [webView synchronouslyLoadHTMLString:@"<model><source src='model://cube.usdz'></model><script>document.getElementsByTagName('model')[0].ready.then(() => { window.webkit.messageHandlers.modelLoading.postMessage('READY') });</script>"]; 2201 2201 2202 2202 while (![messageHandler didLoadModel])
Note:
See TracChangeset
for help on using the changeset viewer.