Source/WebCore/ChangeLog

 12020-05-29 Dean Jackson <dino@apple.com>
 2
 3 AutoTrader crashed while browsing search results
 4 https://bugs.webkit.org/show_bug.cgi?id=212461
 5 rdar://60733185
 6
 7 Reviewed by NOBODY (OOPS!).
 8
 9 On iOS, when using WebKit1 (UIWebView), CoreAnimation would
 10 call WebGLLayer's display method from a thread that is not
 11 the Web Thread. That method was performing some GL work using
 12 ANGLE, causing a crash.
 13
 14 Since all the WebGLLayer's display method really needs to do
 15 is swap buffers for compositing, the fix is to separate all
 16 the GL operations into a method that can be called after
 17 painting but before compositing. This should also have the added
 18 benefit that by the time CoreAnimation comes to call display
 19 on all the dirty layers, we will have already executed our
 20 expensive GPU work. The total amount of work done on the GPU
 21 is the same, but hopefully it is now all done in WebKit's
 22 paint cycle, rather than when the Window Server is trying
 23 to get CA to composite things.
 24
 25 A very happy side-effect is that this also fixes
 26 https://bugs.webkit.org/show_bug.cgi?id=212251
 27 which had been difficult to diagnose.
 28
 29 Covered by a new API test: WebGLPrepareDisplayOnWebThread
 30
 31 * html/HTMLCanvasElement.h:
 32 * html/HTMLCanvasElement.cpp:
 33 (WebCore::HTMLCanvasElement::HTMLCanvasElement):
 34 (WebCore::HTMLCanvasElement::~HTMLCanvasElement):
 35 (WebCore::HTMLCanvasElement::didMoveToNewDocument):
 36 (WebCore::HTMLCanvasElement::removedFromAncestor):
 37 Add or remove the document as a CanvasObserver.
 38 (WebCore::HTMLCanvasElement::needsPreparationForDisplay):
 39 Signals whether this element is the type that needs preparation.
 40 (WebCore::HTMLCanvasElement::prepareForDisplay):
 41 Tell the WebGLRenderingContext it must prepare.
 42
 43 * html/canvas/WebGLRenderingContextBase.h:
 44 * html/canvas/WebGLRenderingContextBase.cpp:
 45 (WebCore::WebGLRenderingContextBase::prepareForDisplay):
 46 The WebGLRenderingContext must forward the call
 47 to prepare down to the GraphicsContextGLOpenGL.
 48
 49 * platform/graphics/opengl/GraphicsContextGLOpenGL.h:
 50 * platform/graphics/opengl/GraphicsContextGLOpenGL.cpp:
 51 * platform/graphics/cocoa/GraphicsContextGLOpenGLCocoa.mm:
 52 (WebCore::GraphicsContextGLOpenGL::prepareForDisplay):
 53 And the GraphicsContextGLOpenGL forwards the call
 54 into the WebGLLayer.
 55
 56 * platform/graphics/cocoa/WebGLLayer.h:
 57 * platform/graphics/cocoa/WebGLLayer.mm:
 58 (-[WebGLLayer prepareForDisplay]):
 59 (-[WebGLLayer display]):
 60 Split the parts of the `display` method that deal
 61 with flushing the GL commands, preparing the framebuffer texture,
 62 and swapping the IOSurfaces into a new `prepareForDisplay`. This
 63 method is invoked at the end of the rendering/layout tasks, leaving
 64 the `display` method to only tell CoreAnimation about a new buffer
 65 to composite.
 66
 67 * dom/Document.cpp:
 68 * dom/Document.h:
 69 (WebCore::Document::prepareCanvasesForDisplayIfNeeded):
 70 (WebCore::Document::canvasChanged):
 71 (WebCore::Document::canvasDestroyed):
 72 Keep a set of HTMLCanvasElements that need to
 73 be prepared so we can tell them when they need to prepare.
 74 Do this by becoming a CanvasObserver, thus getting
 75 notified when a canvas has done something that
 76 would cause painting.
 77
 78 * page/Page.cpp:
 79 (WebCore::Page::doAfterUpdateRendering):
 80 Add a new task that asks the Document to notify
 81 all relevant canvas objects that they should prepare
 82 for display.
 83
1842020-05-27 Darin Adler <darin@apple.com>
285
386 Remove things from FeatureDefines.xcconfig that are covered by PlatformEnableCocoa.h

Source/WebCore/dom/Document.cpp

@@LazyLoadImageObserver& Document::lazyLoadImageObserver()
85828582 return *m_lazyLoadImageObserver;
85838583}
85848584
 8585void Document::prepareCanvasesForDisplayIfNeeded()
 8586{
 8587 // Some canvas contexts need to do work when rendering has finished but
 8588 // before their content is composited.
 8589 for (auto* canvas : m_canvasesNeedingDisplayPreparation) {
 8590 auto refCountedCanvas = makeRefPtr(canvas);
 8591 refCountedCanvas->prepareForDisplay();
 8592 }
 8593 m_canvasesNeedingDisplayPreparation.clear();
 8594}
 8595
 8596void Document::canvasChanged(CanvasBase& canvasBase, const FloatRect&)
 8597{
 8598 if (is<HTMLCanvasElement>(canvasBase)) {
 8599 auto* canvas = downcast<HTMLCanvasElement>(&canvasBase);
 8600 if (canvas->needsPreparationForDisplay())
 8601 m_canvasesNeedingDisplayPreparation.add(canvas);
 8602 }
 8603}
 8604
 8605void Document::canvasDestroyed(CanvasBase& canvasBase)
 8606{
 8607 if (is<HTMLCanvasElement>(canvasBase)) {
 8608 auto* canvas = downcast<HTMLCanvasElement>(&canvasBase);
 8609 m_canvasesNeedingDisplayPreparation.remove(canvas);
 8610 }
 8611}
 8612
85858613} // namespace WebCore
85868614
85878615#undef RELEASE_LOG_IF_ALLOWED

Source/WebCore/dom/Document.h

2828#pragma once
2929
3030#include "CSSRegisteredCustomProperty.h"
 31#include "CanvasBase.h"
3132#include "Color.h"
3233#include "ContainerNode.h"
3334#include "DisabledAdaptations.h"

@@class Document
357358 , public FontSelectorClient
358359 , public FrameDestructionObserver
359360 , public Supplementable<Document>
360  , public Logger::Observer {
 361 , public Logger::Observer
 362 , public CanvasObserver {
361363 WTF_MAKE_ISO_ALLOCATED(Document);
362364public:
363365 static Ref<Document> create(const URL&);

@@public:
15921594 FrameSelection& selection() { return m_selection; }
15931595 const FrameSelection& selection() const { return m_selection; }
15941596
 1597 void prepareCanvasesForDisplayIfNeeded();
 1598 void canvasChanged(CanvasBase&, const FloatRect&) final;
 1599 void canvasResized(CanvasBase&) final { };
 1600 void canvasDestroyed(CanvasBase&) final;
 1601
15951602protected:
15961603 enum ConstructionFlags { Synthesized = 1, NonRenderedPlaceholder = 1 << 1 };
15971604 Document(Frame*, const URL&, unsigned = DefaultDocumentClass, unsigned constructionFlags = 0);

@@private:
18101817 std::unique_ptr<SVGDocumentExtensions> m_svgExtensions;
18111818 HashSet<SVGUseElement*> m_svgUseElements;
18121819
 1820 // Collection of canvas objects that need to do work after they've
 1821 // rendered but before compositing, for the next frame. The set is
 1822 // cleared after they've been called.
 1823 HashSet<HTMLCanvasElement*> m_canvasesNeedingDisplayPreparation;
 1824
18131825#if ENABLE(DARK_MODE_CSS)
18141826 OptionSet<ColorScheme> m_colorScheme;
18151827 bool m_allowsColorSchemeTransformations { true };

Source/WebCore/html/HTMLCanvasElement.cpp

@@HTMLCanvasElement::HTMLCanvasElement(const QualifiedName& tagName, Document& doc
124124 , ActiveDOMObject(document)
125125{
126126 ASSERT(hasTagName(canvasTag));
 127 addObserver(document);
127128}
128129
129130Ref<HTMLCanvasElement> HTMLCanvasElement::create(Document& document)

@@HTMLCanvasElement::~HTMLCanvasElement()
145146 // FIXME: This has to be called here because CSSCanvasValue::CanvasObserverProxy::canvasDestroyed()
146147 // downcasts the CanvasBase object to HTMLCanvasElement. That invokes virtual methods, which should be
147148 // avoided in destructors, but works as long as it's done before HTMLCanvasElement destructs completely.
 149 // This will also cause the document to remove itself as an observer.
148150 notifyObserversCanvasDestroyed();
149151
150152 m_context = nullptr; // Ensure this goes away before the ImageBuffer.

@@void HTMLCanvasElement::eventListenersDidChange()
997999#endif
9981000}
9991001
 1002void HTMLCanvasElement::didMoveToNewDocument(Document& oldDocument, Document& newDocument)
 1003{
 1004 removeObserver(oldDocument);
 1005 addObserver(newDocument);
 1006
 1007 HTMLElement::didMoveToNewDocument(oldDocument, newDocument);
 1008}
 1009
 1010void HTMLCanvasElement::removedFromAncestor(RemovalType removalType, ContainerNode& oldParentOfRemovedTree)
 1011{
 1012 if (removalType.disconnectedFromDocument)
 1013 removeObserver(oldParentOfRemovedTree.document());
 1014
 1015 HTMLElement::removedFromAncestor(removalType, oldParentOfRemovedTree);
 1016}
 1017
 1018bool HTMLCanvasElement::needsPreparationForDisplay()
 1019{
 1020 return is<WebGLRenderingContextBase>(m_context.get());
 1021}
 1022
 1023void HTMLCanvasElement::prepareForDisplay()
 1024{
 1025 ASSERT(needsPreparationForDisplay());
 1026
 1027 if (is<WebGLRenderingContextBase>(m_context.get()))
 1028 downcast<WebGLRenderingContextBase>(m_context.get())->prepareForDisplay();
 1029}
 1030
10001031}

Source/WebCore/html/HTMLCanvasElement.h

@@public:
129129
130130 WEBCORE_EXPORT static void setMaxPixelMemoryForTesting(size_t);
131131
 132 bool needsPreparationForDisplay();
 133 void prepareForDisplay();
 134
132135private:
133136 HTMLCanvasElement(const QualifiedName&, Document&);
134137

@@private:
165168
166169 ScriptExecutionContext* canvasBaseScriptExecutionContext() const final { return HTMLElement::scriptExecutionContext(); }
167170
 171 void didMoveToNewDocument(Document& oldDocument, Document& newDocument) final;
 172 void removedFromAncestor(RemovalType, ContainerNode& oldParentOfRemovedTree) final;
 173
168174 FloatRect m_dirtyRect;
169175
170176 bool m_ignoreReset { false };

Source/WebCore/html/canvas/WebGLRenderingContextBase.cpp

@@void WebGLRenderingContextBase::dispatchContextChangedNotification()
75267526 queueTaskToDispatchEvent(*canvas, TaskSource::WebGL, WebGLContextEvent::create(eventNames().webglcontextchangedEvent, Event::CanBubble::No, Event::IsCancelable::Yes, emptyString()));
75277527}
75287528
 7529void WebGLRenderingContextBase::prepareForDisplay()
 7530{
 7531 if (!m_context)
 7532 return;
 7533
 7534 m_context->prepareForDisplay();
 7535}
75297536
75307537} // namespace WebCore
75317538

Source/WebCore/html/canvas/WebGLRenderingContextBase.h

@@public:
382382 // Used for testing only, from Internals.
383383 WEBCORE_EXPORT void setFailNextGPUStatusCheck();
384384
 385 void prepareForDisplay();
 386
385387 // GraphicsContextGL::Client
386388 void didComposite() override;
387389 void forceContextLost() override;

Source/WebCore/page/Page.cpp

@@void Page::doAfterUpdateRendering()
14631463 if (UNLIKELY(isMonitoringWheelEvents()))
14641464 wheelEventTestMonitor()->checkShouldFireCallbacks();
14651465
 1466 forEachDocument([] (Document& document) {
 1467 document.prepareCanvasesForDisplayIfNeeded();
 1468 });
 1469
14661470#if ASSERT_ENABLED
14671471 for (Frame* child = mainFrame().tree().firstRenderedChild(); child; child = child->tree().traverseNextRendered()) {
14681472 auto* frameView = child->view();

Source/WebCore/platform/graphics/cocoa/GraphicsContextGLOpenGLCocoa.mm

@@void GraphicsContextGLOpenGL::screenDidChange(PlatformDisplayID displayID)
867867}
868868#endif // !PLATFORM(MAC)
869869
 870void GraphicsContextGLOpenGL::prepareForDisplay()
 871{
 872 [m_webGLLayer prepareForDisplay];
 873}
 874
870875}
871876
872877#endif // ENABLE(GRAPHICS_CONTEXT_GL)

Source/WebCore/platform/graphics/cocoa/WebGLLayer.h

@@ALLOW_DEPRECATED_DECLARATIONS_BEGIN
6262 void* _sparePbuffer;
6363 void* _latchedPbuffer;
6464#endif
 65 BOOL _prepared;
6566}
6667
6768@property (nonatomic) NakedPtr<WebCore::GraphicsContextGLOpenGL> context;

@@ALLOW_DEPRECATED_DECLARATIONS_BEGIN
7071
7172- (CGImageRef)copyImageSnapshotWithColorSpace:(CGColorSpaceRef)colorSpace;
7273
 74- (void)prepareForDisplay;
 75
7376#if USE(OPENGL) || USE(ANGLE)
7477- (void)allocateIOSurfaceBackingStoreWithSize:(WebCore::IntSize)size usingAlpha:(BOOL)usingAlpha;
7578- (void)bindFramebufferToNextAvailableSurface;

Source/WebCore/platform/graphics/cocoa/WebGLLayer.mm

@@static void freeData(void *, const void *data, size_t /* size */)
163163#endif
164164}
165165
166 - (void)display
 166- (void)prepareForDisplay
167167{
168168 if (!_context)
169169 return;
170170
 171 // To avoid running any OpenGL code in `display`, this method should be called
 172 // at the end of the rendering task. We will flush all painting commands
 173 // leaving the buffers ready to composite.
 174
171175#if USE(OPENGL)
172176 _context->prepareTexture();
173177 if (_drawingBuffer) {
174178 std::swap(_contentsBuffer, _drawingBuffer);
175  self.contents = _contentsBuffer->asLayerContents();
176  [self reloadValueForKeyPath:@"contents"];
177179 [self bindFramebufferToNextAvailableSurface];
178180 }
179 #elif USE(OPENGL_ES)
180  _context->presentRenderbuffer();
181181#elif USE(ANGLE)
182182 if (!_context->makeContextCurrent()) {
183183 // Context is likely being torn down.

@@static void freeData(void *, const void *data, size_t /* size */)
198198 }
199199 _latchedPbuffer = nullptr;
200200 }
 201
201202 std::swap(_contentsBuffer, _drawingBuffer);
202203 std::swap(_contentsPbuffer, _drawingPbuffer);
 204 [self bindFramebufferToNextAvailableSurface];
 205 }
 206#endif
 207
 208 _prepared = YES;
 209}
 210
 211- (void)display
 212{
 213 if (!_context)
 214 return;
 215
 216 // At this point we've painted into the _drawingBuffer and swapped it with the old _contentsBuffer,
 217 // so all we need to do here is tickle the CALayer to let it know it has new contents.
 218 // This avoids running any OpenGL code in this method.
 219
 220#if USE(OPENGL) || USE(ANGLE)
 221 if (_contentsBuffer && _prepared) {
203222 self.contents = _contentsBuffer->asLayerContents();
204223 [self reloadValueForKeyPath:@"contents"];
205  [self bindFramebufferToNextAvailableSurface];
206224 }
 225#elif USE(OPENGL_ES)
 226 _context->presentRenderbuffer();
207227#endif
208228
209229 _context->markLayerComposited();
210230 auto layer = WebCore::PlatformCALayer::platformCALayerForLayer((__bridge void*)self);
211231 if (layer && layer->owner())
212232 layer->owner()->platformCALayerLayerDidDisplay(layer.get());
 233
 234 _prepared = NO;
213235}
214236
215237#if USE(ANGLE)

Source/WebCore/platform/graphics/opengl/GraphicsContextGLOpenGL.cpp

@@void GraphicsContextGLOpenGL::setContextVisibility(bool)
782782void GraphicsContextGLOpenGL::simulateContextChanged()
783783{
784784}
 785
 786void GraphicsContextGLOpenGL::prepareForDisplay()
 787{
 788}
785789#endif
786790
787791} // namespace WebCore

Source/WebCore/platform/graphics/opengl/GraphicsContextGLOpenGL.h

@@public:
661661 void screenDidChange(PlatformDisplayID);
662662#endif
663663
 664 void prepareForDisplay();
 665
664666private:
665667 GraphicsContextGLOpenGL(GraphicsContextGLAttributes, HostWindow*, Destination = Destination::Offscreen, GraphicsContextGLOpenGL* sharedContext = nullptr);
666668

Tools/ChangeLog

 12020-05-29 Dean Jackson <dino@apple.com>
 2
 3 AutoTrader crashed while browsing search results
 4 https://bugs.webkit.org/show_bug.cgi?id=212461
 5 rdar://60733185
 6
 7 Reviewed by NOBODY (OOPS!).
 8
 9 * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
 10 * TestWebKitAPI/Tests/WebKitLegacy/ios/WebGLPrepareDisplayOnWebThread.mm: Added.
 11 (-[WebGLPrepareDisplayOnWebThreadDelegate webViewDidFinishLoad:]):
 12 (-[WebGLPrepareDisplayOnWebThreadDelegate webView:shouldStartLoadWithRequest:navigationType:]):
 13 (TestWebKitAPI::TEST):
 14 * TestWebKitAPI/Tests/WebKitLegacy/ios/webgl.html: Added.
 15
1162020-05-27 Darin Adler <darin@apple.com>
217
318 Remove things from FeatureDefines.xcconfig that are covered by PlatformEnableCocoa.h

Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj

192192 315118101DB1AE4000176304 /* ExtendedColorTests.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3151180F1DB1ADD500176304 /* ExtendedColorTests.cpp */; };
193193 31B76E4323298E2C007FED2C /* SystemPreview.mm in Sources */ = {isa = PBXBuildFile; fileRef = 31B76E4223298E2B007FED2C /* SystemPreview.mm */; };
194194 31B76E4523299BDC007FED2C /* system-preview-trigger.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 31B76E4423299BA3007FED2C /* system-preview-trigger.html */; };
 195 31E9BDA1247F4C62002E51A2 /* WebGLPrepareDisplayOnWebThread.mm in Sources */ = {isa = PBXBuildFile; fileRef = 31E9BDA0247F4C62002E51A2 /* WebGLPrepareDisplayOnWebThread.mm */; };
 196 31E9BDA3247F5729002E51A2 /* webgl.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 31E9BDA2247F4DD0002E51A2 /* webgl.html */; };
195197 33BE5AF9137B5AAE00705813 /* MouseMoveAfterCrash_Bundle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 33BE5AF8137B5AAE00705813 /* MouseMoveAfterCrash_Bundle.cpp */; };
196198 33DC8912141955FE00747EF7 /* simple-iframe.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 33DC890E1419539300747EF7 /* simple-iframe.html */; };
197199 33DC89141419579F00747EF7 /* LoadCanceledNoServerRedirectCallback_Bundle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 33DC89131419579F00747EF7 /* LoadCanceledNoServerRedirectCallback_Bundle.cpp */; };

15911593 57EDFC5C245A1A3F00959521 /* web-authentication-make-credential-la-no-mock.html in Copy Resources */,
15921594 5742178E2400D2DF002B303D /* web-authentication-make-credential-la.html in Copy Resources */,
15931595 1C2B81861C89259D00A5529F /* webfont.html in Copy Resources */,
 1596 31E9BDA3247F5729002E51A2 /* webgl.html in Copy Resources */,
15941597 51714EB41CF8C78C004723C4 /* WebProcessKillIDBCleanup-1.html in Copy Resources */,
15951598 51714EB51CF8C78C004723C4 /* WebProcessKillIDBCleanup-2.html in Copy Resources */,
15961599 536770361CC81B6100D425B1 /* WebScriptObjectDescription.html in Copy Resources */,

18121815 3151180F1DB1ADD500176304 /* ExtendedColorTests.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ExtendedColorTests.cpp; sourceTree = "<group>"; };
18131816 31B76E4223298E2B007FED2C /* SystemPreview.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = SystemPreview.mm; sourceTree = "<group>"; };
18141817 31B76E4423299BA3007FED2C /* system-preview-trigger.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = "system-preview-trigger.html"; sourceTree = "<group>"; };
 1818 31E9BDA0247F4C62002E51A2 /* WebGLPrepareDisplayOnWebThread.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = WebGLPrepareDisplayOnWebThread.mm; sourceTree = "<group>"; };
 1819 31E9BDA2247F4DD0002E51A2 /* webgl.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = webgl.html; sourceTree = "<group>"; };
18151820 333B9CE11277F23100FEFCE3 /* PreventEmptyUserAgent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PreventEmptyUserAgent.cpp; sourceTree = "<group>"; };
18161821 33BE5AF4137B5A6C00705813 /* MouseMoveAfterCrash.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MouseMoveAfterCrash.cpp; sourceTree = "<group>"; };
18171822 33BE5AF8137B5AAE00705813 /* MouseMoveAfterCrash_Bundle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MouseMoveAfterCrash_Bundle.cpp; sourceTree = "<group>"; };

44114416 CDC0932A21C872C10030C4B0 /* ScrollingDoesNotPauseMedia.mm */,
44124417 F434CA1922E65BCA005DDB26 /* ScrollToRevealSelection.mm */,
44134418 0F4FFA9D1ED3AA8500F7111F /* SnapshotViaRenderInContext.mm */,
 4419 31E9BDA0247F4C62002E51A2 /* WebGLPrepareDisplayOnWebThread.mm */,
44144420 );
44154421 path = ios;
44164422 sourceTree = "<group>";

44284434 CD758A6E20572D540071834A /* video-with-paused-audio-and-playing-muted.html */,
44294435 CDC8E48B1BC5C96200594FEC /* video-without-audio.html */,
44304436 CDC8E48C1BC5C96200594FEC /* video-without-audio.mp4 */,
 4437 31E9BDA2247F4DD0002E51A2 /* webgl.html */,
44314438 );
44324439 name = Resources;
44334440 sourceTree = "<group>";

52475254 57A79857224AB34E00A7F6F1 /* WebCryptoMasterKey.mm in Sources */,
52485255 C1FF9EDB244644F000839AE4 /* WebFilter.mm in Sources */,
52495256 5C973F5C1F58EF8B00359C27 /* WebGLPolicy.mm in Sources */,
 5257 31E9BDA1247F4C62002E51A2 /* WebGLPrepareDisplayOnWebThread.mm in Sources */,
52505258 7CCE7EAB1A411A2400447C4C /* WebKitAgnosticTest.mm in Sources */,
52515259 51714EB81CF8CA17004723C4 /* WebProcessKillIDBCleanup.mm in Sources */,
52525260 536770341CC8022800D425B1 /* WebScriptObjectDescription.mm in Sources */,

Tools/TestWebKitAPI/Tests/WebKitLegacy/ios/WebGLPrepareDisplayOnWebThread.mm

 1/*
 2 * Copyright (C) 2020 Apple Inc. All rights reserved.
 3 *
 4 * Redistribution and use in source and binary forms, with or without
 5 * modification, are permitted provided that the following conditions
 6 * are met:
 7 * 1. Redistributions of source code must retain the above copyright
 8 * notice, this list of conditions and the following disclaimer.
 9 * 2. Redistributions in binary form must reproduce the above copyright
 10 * notice, this list of conditions and the following disclaimer in the
 11 * documentation and/or other materials provided with the distribution.
 12 *
 13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 24 */
 25
 26#import "config.h"
 27
 28#if HAVE(UIWEBVIEW)
 29
 30#import "PlatformUtilities.h"
 31#import <JavaScriptCore/JSVirtualMachine.h>
 32#import <JavaScriptCore/JSVirtualMachineInternal.h>
 33#import <UIKit/UIKit.h>
 34#import <WebCore/WebCoreThread.h>
 35#import <stdlib.h>
 36#import <wtf/RetainPtr.h>
 37
 38@interface WebGLPrepareDisplayOnWebThreadDelegate : NSObject <UIWebViewDelegate> {
 39}
 40@end
 41
 42static bool didFinishLoad = false;
 43static bool didFinishPainting = false;
 44static bool isReady = false;
 45
 46@implementation WebGLPrepareDisplayOnWebThreadDelegate
 47
 48IGNORE_WARNINGS_BEGIN("deprecated-implementations")
 49- (void)webViewDidFinishLoad:(UIWebView *)webView
 50{
 51 didFinishLoad = true;
 52}
 53
 54- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
 55{
 56 if ([request.URL.scheme isEqualToString:@"callback"] && [request.URL.resourceSpecifier isEqualToString:@"didFinishPainting"]) {
 57 didFinishPainting = true;
 58 return NO;
 59 }
 60
 61 if ([request.URL.scheme isEqualToString:@"callback"] && [request.URL.resourceSpecifier isEqualToString:@"isReady"]) {
 62 isReady = true;
 63 return NO;
 64 }
 65
 66 return YES;
 67}
 68IGNORE_WARNINGS_END
 69
 70@end
 71
 72namespace TestWebKitAPI {
 73
 74TEST(WebKitLegacy, WebGLPrepareDisplayOnWebThread)
 75{
 76 RetainPtr<UIWindow> uiWindow = adoptNS([[UIWindow alloc] initWithFrame:NSMakeRect(0, 0, 800, 600)]);
 77 RetainPtr<UIWebView> uiWebView = adoptNS([[UIWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600)]);
 78 [uiWindow addSubview:uiWebView.get()];
 79
 80 RetainPtr<WebGLPrepareDisplayOnWebThreadDelegate> uiDelegate = adoptNS([[WebGLPrepareDisplayOnWebThreadDelegate alloc] init]);
 81 uiWebView.get().delegate = uiDelegate.get();
 82
 83 NSURL *url = [[NSBundle mainBundle] URLForResource:@"webgl" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
 84 NSLog(@"Loading %@", url);
 85 [uiWebView loadRequest:[NSURLRequest requestWithURL:url]];
 86
 87 Util::run(&didFinishLoad);
 88 Util::run(&isReady);
 89
 90 RetainPtr<JSContext> jsContext = [uiWebView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
 91
 92 EXPECT_TRUE(!!jsContext.get());
 93
 94 RetainPtr<JSVirtualMachine> jsVM = [jsContext virtualMachine];
 95 EXPECT_TRUE([jsVM isWebThreadAware]);
 96
 97 // Release WebThread lock.
 98 Util::spinRunLoop(1);
 99
 100 EXPECT_FALSE(WebThreadIsLocked());
 101
 102 [jsContext evaluateScript:@"loadColorIntoTexture(128, 128, 255, 255)"];
 103 [jsContext evaluateScript:@"draw()"];
 104 Util::run(&didFinishPainting);
 105
 106}
 107
 108}
 109
 110#endif

Tools/TestWebKitAPI/Tests/WebKitLegacy/ios/webgl.html

 1<!DOCTYPE html>
 2<head>
 3<title>WebGL drawing</title>
 4<style>
 5canvas {
 6 width: 100px;
 7 height: 100px;
 8}
 9</style>
 10</head>
 11<script id="vertexShaderSource" type="text/glsl">
 12attribute vec4 a_position;
 13varying vec2 v_texturePosition;
 14
 15void main() {
 16 v_texturePosition = vec2((a_position.x + 1.0) / 2.0, (a_position.y + 1.0) / 2.0);
 17 gl_Position = a_position;
 18}
 19</script>
 20<script id="fragmentShaderSource" type="text/glsl">
 21precision mediump float;
 22
 23varying vec2 v_texturePosition;
 24
 25uniform sampler2D texture;
 26
 27void main() {
 28 gl_FragColor = texture2D(texture, v_texturePosition);
 29}
 30</script>
 31<script>
 32let texture;
 33let gl;
 34let textureUniform;
 35let NUMBER_OF_PAINTS_REMAINING = 60;
 36
 37function signalReady() {
 38 window.location = "callback:isReady";
 39}
 40
 41function signalFinished() {
 42 window.location = "callback:didFinishPainting";
 43}
 44
 45function loadColorIntoTexture(r, g, b, a) {
 46 gl.bindTexture(gl.TEXTURE_2D, texture);
 47 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array([r, g, b, a]));
 48}
 49
 50function draw() {
 51 gl.clear(gl.COLOR_BUFFER_BIT);
 52
 53 gl.activeTexture(gl.TEXTURE0);
 54 gl.bindTexture(gl.TEXTURE_2D, texture);
 55
 56 gl.drawArrays(gl.TRIANGLES, 0, 6);
 57
 58 if (NUMBER_OF_PAINTS_REMAINING--) {
 59 window.requestAnimationFrame(draw);
 60 } else {
 61 signalFinished();
 62 }
 63};
 64
 65function run() {
 66
 67 let canvas = document.querySelector("canvas");
 68 canvas.width = 100;
 69 canvas.height = 100;
 70
 71 gl = canvas.getContext("webgl");
 72
 73 gl.clearColor(0, 0, 1, 1);
 74
 75 let vertexShader = gl.createShader(gl.VERTEX_SHADER);
 76
 77 gl.shaderSource(vertexShader, document.getElementById("vertexShaderSource").textContent);
 78
 79 gl.compileShader(vertexShader);
 80 if (!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)) {
 81 // We failed to compile. Output to the console and quit.
 82 console.error("Vertex Shader failed to compile.");
 83 console.log(gl.getShaderInfoLog(vertexShader));
 84 return;
 85 }
 86
 87 let fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
 88 gl.shaderSource(fragmentShader, document.getElementById("fragmentShaderSource").textContent);
 89 gl.compileShader(fragmentShader);
 90 if (!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)) {
 91 console.error("Fragment Shader failed to compile.");
 92 console.log(gl.getShaderInfoLog(fragmentShader));
 93 return;
 94 }
 95
 96 let program = gl.createProgram();
 97 gl.attachShader(program, vertexShader);
 98 gl.attachShader(program, fragmentShader);
 99 gl.linkProgram(program);
 100
 101 if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
 102 console.error("Unable to link shaders into program.");
 103 return;
 104 }
 105
 106 gl.useProgram(program);
 107
 108 let textureUniform = gl.getUniformLocation(program, "texture");
 109
 110 let positionAttribute = gl.getAttribLocation(program, "a_position");
 111 gl.enableVertexAttribArray(positionAttribute);
 112
 113 let vertices = new Float32Array([
 114 -1, -1,
 115 1, -1,
 116 1, 1,
 117 1, 1,
 118 -1, 1,
 119 -1, -1
 120 ]);
 121
 122 let quadBuffer = gl.createBuffer();
 123
 124 gl.bindBuffer(gl.ARRAY_BUFFER, quadBuffer);
 125 gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
 126
 127 texture = gl.createTexture();
 128 loadColorIntoTexture(0, 128, 255, 255);
 129
 130 gl.bindBuffer(gl.ARRAY_BUFFER, quadBuffer);
 131 gl.vertexAttribPointer(positionAttribute, 2, gl.FLOAT, false, 0, 0);
 132
 133 gl.uniform1i(textureUniform, 0);
 134
 135 signalReady();
 136}
 137
 138window.addEventListener("load", run, false);
 139</script>
 140<body>
 141 <canvas></canvas>
 142</body>