diff options
Diffstat (limited to 'WebCore/platform/graphics/win')
-rw-r--r-- | WebCore/platform/graphics/win/GraphicsLayerCACF.cpp | 185 | ||||
-rw-r--r-- | WebCore/platform/graphics/win/GraphicsLayerCACF.h | 3 | ||||
-rw-r--r-- | WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeVisualContext.cpp | 72 | ||||
-rw-r--r-- | WebCore/platform/graphics/win/QTMovieVisualContext.h | 1 | ||||
-rw-r--r-- | WebCore/platform/graphics/win/QTPixelBuffer.cpp | 5 | ||||
-rw-r--r-- | WebCore/platform/graphics/win/QTPixelBuffer.h | 2 | ||||
-rw-r--r-- | WebCore/platform/graphics/win/WKCACFContextFlusher.cpp | 4 | ||||
-rw-r--r-- | WebCore/platform/graphics/win/WKCACFLayer.cpp | 69 | ||||
-rw-r--r-- | WebCore/platform/graphics/win/WKCACFLayer.h | 52 | ||||
-rw-r--r-- | WebCore/platform/graphics/win/WKCACFLayerRenderer.cpp | 142 | ||||
-rw-r--r-- | WebCore/platform/graphics/win/WKCACFLayerRenderer.h | 14 | ||||
-rwxr-xr-x | WebCore/platform/graphics/win/WebLayer.cpp | 143 | ||||
-rwxr-xr-x | WebCore/platform/graphics/win/WebLayer.h | 62 | ||||
-rwxr-xr-x | WebCore/platform/graphics/win/WebTiledLayer.cpp | 274 | ||||
-rwxr-xr-x | WebCore/platform/graphics/win/WebTiledLayer.h | 80 |
15 files changed, 841 insertions, 267 deletions
diff --git a/WebCore/platform/graphics/win/GraphicsLayerCACF.cpp b/WebCore/platform/graphics/win/GraphicsLayerCACF.cpp index 0065191..20d76ef 100644 --- a/WebCore/platform/graphics/win/GraphicsLayerCACF.cpp +++ b/WebCore/platform/graphics/win/GraphicsLayerCACF.cpp @@ -36,7 +36,8 @@ #include "Image.h" #include "PlatformString.h" #include "SystemTime.h" -#include "WKCACFLayer.h" +#include "WebLayer.h" +#include "WebTiledLayer.h" #include <wtf/CurrentTime.h> #include <wtf/StringExtras.h> #include <wtf/text/CString.h> @@ -45,115 +46,15 @@ using namespace std; namespace WebCore { -class WebLayer : public WKCACFLayer { -public: - static PassRefPtr<WKCACFLayer> create(LayerType layerType, GraphicsLayerCACF* owner) - { - return adoptRef(new WebLayer(layerType, owner)); - } - - virtual void setNeedsDisplay(const CGRect* dirtyRect) - { - if (m_owner) { - if (m_owner->showRepaintCounter()) { - CGRect layerBounds = bounds(); - CGRect repaintCounterRect = layerBounds; - // We assume a maximum of 4 digits and a font size of 22. - repaintCounterRect.size.width = 48; - repaintCounterRect.size.height = 25; - if (m_owner->contentsOrientation() == WebCore::GraphicsLayer::CompositingCoordinatesTopDown) - repaintCounterRect.origin.y = layerBounds.size.height - (layerBounds.origin.y + repaintCounterRect.size.height); - WKCACFLayer::setNeedsDisplay(&repaintCounterRect); - } - if (dirtyRect && m_owner->contentsOrientation() == WebCore::GraphicsLayer::CompositingCoordinatesTopDown) { - CGRect flippedDirtyRect = *dirtyRect; - flippedDirtyRect.origin.y = bounds().size.height - (flippedDirtyRect.origin.y + flippedDirtyRect.size.height); - WKCACFLayer::setNeedsDisplay(&flippedDirtyRect); - return; - } - } - WKCACFLayer::setNeedsDisplay(dirtyRect); - } - - virtual void drawInContext(PlatformGraphicsContext* context) - { - if (!m_owner) - return; - - CGContextSaveGState(context); - - CGRect layerBounds = bounds(); - if (m_owner->contentsOrientation() == WebCore::GraphicsLayer::CompositingCoordinatesTopDown) { - CGContextScaleCTM(context, 1, -1); - CGContextTranslateCTM(context, 0, -layerBounds.size.height); - } - - if (m_owner->client()) { - GraphicsContext graphicsContext(context); - - // It's important to get the clip from the context, because it may be significantly - // smaller than the layer bounds (e.g. tiled layers) - CGRect clipBounds = CGContextGetClipBoundingBox(context); - IntRect clip(enclosingIntRect(clipBounds)); - m_owner->paintGraphicsLayerContents(graphicsContext, clip); - } -#ifndef NDEBUG - else { - ASSERT_NOT_REACHED(); - - // FIXME: ideally we'd avoid calling -setNeedsDisplay on a layer that is a plain color, - // so CA never makes backing store for it (which is what -setNeedsDisplay will do above). - CGContextSetRGBFillColor(context, 0.0f, 1.0f, 0.0f, 1.0f); - CGContextFillRect(context, layerBounds); - } -#endif - - if (m_owner->showRepaintCounter()) { - String text = String::format("%d", m_owner->incrementRepaintCount());; - - CGContextSaveGState(context); - CGContextSetRGBFillColor(context, 1.0f, 0.0f, 0.0f, 0.8f); - - CGRect aBounds = layerBounds; - - aBounds.size.width = 10 + 12 * text.length(); - aBounds.size.height = 25; - CGContextFillRect(context, aBounds); - - FontDescription desc; - - NONCLIENTMETRICS metrics; - metrics.cbSize = sizeof(metrics); - SystemParametersInfo(SPI_GETNONCLIENTMETRICS, metrics.cbSize, &metrics, 0); - FontFamily family; - family.setFamily(metrics.lfSmCaptionFont.lfFaceName); - desc.setFamily(family); - - desc.setComputedSize(22); - - Font font = Font(desc, 0, 0); - font.update(0); - - GraphicsContext cg(context); - cg.setFillColor(Color::black, DeviceColorSpace); - cg.drawText(font, TextRun(text), IntPoint(aBounds.origin.x + 3, aBounds.origin.y + 20)); - - CGContextRestoreGState(context); - } - - CGContextRestoreGState(context); - } - -protected: - WebLayer(LayerType layerType, GraphicsLayerCACF* owner) - : WKCACFLayer(layerType) - , m_owner(owner) - { - } +// The threshold width or height above which a tiled layer will be used. This should be +// large enough to avoid tiled layers for most GraphicsLayers, but less than the D3D +// texture size limit on all supported hardware. +static const int cMaxPixelDimension = 2000; -private: - GraphicsLayer* m_owner; -}; +// The width and height of a single tile in a tiled layer. Should be large enough to +// avoid lots of small tiles (and therefore lots of drawing callbacks), but small enough +// to keep the overall tile cost low. +static const int cTiledLayerTileSize = 512; static inline void copyTransform(CATransform3D& toT3D, const TransformationMatrix& t) { @@ -537,6 +438,64 @@ void GraphicsLayerCACF::setDebugBorder(const Color& color, float borderWidth) } } +bool GraphicsLayerCACF::requiresTiledLayer(const FloatSize& size) const +{ + if (!m_drawsContent) + return false; + + // FIXME: catch zero-size height or width here (or earlier)? + return size.width() > cMaxPixelDimension || size.height() > cMaxPixelDimension; +} + +void GraphicsLayerCACF::swapFromOrToTiledLayer(bool useTiledLayer) +{ + if (useTiledLayer == m_usingTiledLayer) + return; + + CGSize tileSize = CGSizeMake(cTiledLayerTileSize, cTiledLayerTileSize); + + RefPtr<WKCACFLayer> oldLayer = m_layer; + if (useTiledLayer) + m_layer = WebTiledLayer::create(tileSize, this); + else + m_layer = WebLayer::create(WKCACFLayer::Layer, this); + + m_usingTiledLayer = useTiledLayer; + + if (useTiledLayer) { + if (GraphicsLayer::compositingCoordinatesOrientation() == GraphicsLayer::CompositingCoordinatesBottomUp) + m_layer->setContentsGravity(WKCACFLayer::BottomLeft); + else + m_layer->setContentsGravity(WKCACFLayer::TopLeft); + } + + m_layer->adoptSublayers(oldLayer.get()); + if (oldLayer->superlayer()) + oldLayer->superlayer()->replaceSublayer(oldLayer.get(), m_layer.get()); + + updateLayerPosition(); + updateLayerSize(); + updateAnchorPoint(); + updateTransform(); + updateChildrenTransform(); + updateMasksToBounds(); + updateContentsOpaque(); + updateBackfaceVisibility(); + updateLayerBackgroundColor(); + + updateOpacityOnLayer(); + +#ifndef NDEBUG + String name = String::format("CALayer(%p) GraphicsLayer(%p) %s", m_layer.get(), this, m_usingTiledLayer ? "[Tiled Layer] " : "") + m_name; + m_layer->setName(name); +#endif + + // need to tell new layer to draw itself + setNeedsDisplay(); + + updateDebugIndicators(); +} + GraphicsLayer::CompositingCoordinatesOrientation GraphicsLayerCACF::defaultContentsOrientation() const { return CompositingCoordinatesTopDown; @@ -600,6 +559,10 @@ void GraphicsLayerCACF::updateLayerSize() m_layer->setPosition(centerPoint); } + bool needTiledLayer = requiresTiledLayer(m_size); + if (needTiledLayer != m_usingTiledLayer) + swapFromOrToTiledLayer(needTiledLayer); + m_layer->setBounds(rect); // Note that we don't resize m_contentsLayer. It's up the caller to do that. @@ -699,6 +662,10 @@ void GraphicsLayerCACF::updateLayerPreserves3D() void GraphicsLayerCACF::updateLayerDrawsContent() { + bool needTiledLayer = requiresTiledLayer(m_size); + if (needTiledLayer != m_usingTiledLayer) + swapFromOrToTiledLayer(needTiledLayer); + if (m_drawsContent) m_layer->setNeedsDisplay(); else diff --git a/WebCore/platform/graphics/win/GraphicsLayerCACF.h b/WebCore/platform/graphics/win/GraphicsLayerCACF.h index 8c3f848..171cdbf 100644 --- a/WebCore/platform/graphics/win/GraphicsLayerCACF.h +++ b/WebCore/platform/graphics/win/GraphicsLayerCACF.h @@ -98,6 +98,9 @@ private: WKCACFLayer* hostLayerForSublayers() const; WKCACFLayer* layerForSuperlayer() const; + bool requiresTiledLayer(const FloatSize&) const; + void swapFromOrToTiledLayer(bool useTiledLayer); + CompositingCoordinatesOrientation defaultContentsOrientation() const; void updateSublayerList(); void updateLayerPosition(); diff --git a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeVisualContext.cpp b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeVisualContext.cpp index 87625d3..e1d457f 100644 --- a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeVisualContext.cpp +++ b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeVisualContext.cpp @@ -45,6 +45,7 @@ #include "StringHash.h" #include "TimeRanges.h" #include "Timer.h" +#include <CoreGraphics/CGContext.h> #include <Wininet.h> #include <wtf/CurrentTime.h> #include <wtf/HashSet.h> @@ -64,6 +65,8 @@ const CFStringRef kMinCoreVideoVersion = CFSTR("1.0.0.2"); namespace WebCore { +static CGImageRef CreateCGImageFromPixelBuffer(QTPixelBuffer buffer); + SOFT_LINK_LIBRARY(Wininet) SOFT_LINK(Wininet, InternetSetCookieExW, DWORD, WINAPI, (LPCWSTR lpszUrl, LPCWSTR lpszCookieName, LPCWSTR lpszCookieData, DWORD dwFlags, DWORD_PTR dwReserved), (lpszUrl, lpszCookieName, lpszCookieData, dwFlags, dwReserved)) @@ -141,12 +144,13 @@ MediaPlayerPrivateQuickTimeVisualContext::MediaPlayerPrivateQuickTimeVisualConte MediaPlayerPrivateQuickTimeVisualContext::~MediaPlayerPrivateQuickTimeVisualContext() { tearDownVideoRendering(); + m_visualContext->setMovie(0); cancelCallOnMainThread(&VisualContextClient::retrieveCurrentImageProc, this); } bool MediaPlayerPrivateQuickTimeVisualContext::supportsFullscreen() const { - return true; + return false; } PlatformMedia MediaPlayerPrivateQuickTimeVisualContext::platformMedia() const @@ -284,6 +288,7 @@ void MediaPlayerPrivateQuickTimeVisualContext::load(const String& url) CFDictionaryRef options = QTMovieVisualContext::getCGImageOptions(); m_visualContext = adoptRef(new QTMovieVisualContext(m_visualContextClient.get(), options)); + m_visualContext->setMovie(m_movie.get()); } void MediaPlayerPrivateQuickTimeVisualContext::play() @@ -629,7 +634,20 @@ void MediaPlayerPrivateQuickTimeVisualContext::paint(GraphicsContext* p, const I if (m_qtVideoLayer) return; #endif + QTPixelBuffer buffer = m_visualContext->imageForTime(0); + if (buffer.pixelBufferRef()) { + CGImageRef image = CreateCGImageFromPixelBuffer(buffer); + + CGContextRef context = p->platformContext(); + CGContextSaveGState(context); + CGContextTranslateCTM(context, r.x(), r.y()); + CGContextTranslateCTM(context, 0, r.height()); + CGContextScaleCTM(context, 1, -1); + CGContextDrawImage(context, CGRectMake(0, 0, r.width(), r.height()), image); + CGContextRestoreGState(context); + CGImageRelease(image); + } paintCompleted(*p, r); } @@ -654,16 +672,17 @@ void MediaPlayerPrivateQuickTimeVisualContext::VisualContextClient::imageAvailab void MediaPlayerPrivateQuickTimeVisualContext::visualContextTimerFired(Timer<MediaPlayerPrivateQuickTimeVisualContext>*) { - retrieveCurrentImage(); + if (m_visualContext && m_visualContext->isImageAvailableForTime(0)) + retrieveCurrentImage(); } static CFDictionaryRef QTCFDictionaryCreateWithDataCallback(CFAllocatorRef allocator, const UInt8* bytes, CFIndex length) { - CFDataRef data = CFDataCreateWithBytesNoCopy(allocator, bytes, length, 0); + RetainPtr<CFDataRef> data(AdoptCF, CFDataCreateWithBytesNoCopy(allocator, bytes, length, kCFAllocatorNull)); if (!data) return 0; - return reinterpret_cast<CFDictionaryRef>(CFPropertyListCreateFromXMLData(allocator, data, kCFPropertyListImmutable, 0)); + return reinterpret_cast<CFDictionaryRef>(CFPropertyListCreateFromXMLData(allocator, data.get(), kCFPropertyListImmutable, 0)); } static CGImageRef CreateCGImageFromPixelBuffer(QTPixelBuffer buffer) @@ -729,38 +748,29 @@ void MediaPlayerPrivateQuickTimeVisualContext::retrieveCurrentImage() return; #if USE(ACCELERATED_COMPOSITING) - if (!m_qtVideoLayer) - return; + if (m_qtVideoLayer) { - QTPixelBuffer buffer = m_visualContext->imageForTime(0); - if (!buffer.pixelBufferRef()) - return; + QTPixelBuffer buffer = m_visualContext->imageForTime(0); + if (!buffer.pixelBufferRef()) + return; - WKCACFLayer* layer = static_cast<WKCACFLayer*>(m_qtVideoLayer->platformLayer()); + WKCACFLayer* layer = static_cast<WKCACFLayer*>(m_qtVideoLayer->platformLayer()); - if (!buffer.lockBaseAddress()) { -#ifndef NDEBUG - // Debug QuickTime links against a non-Debug version of CoreFoundation, so the CFDictionary attached to the CVPixelBuffer cannot be directly passed on into the CAImageQueue without being converted to a non-Debug CFDictionary: - CFDictionaryRef attachments = QTCFDictionaryCreateCopyWithDataCallback(kCFAllocatorDefault, buffer.attachments(), &QTCFDictionaryCreateWithDataCallback); -#else - // However, this is unnecssesary in the non-Debug case: - CFDictionaryRef attachments = static_cast<CFDictionaryRef>(CFRetain(buffer.attachments())); -#endif + if (!buffer.lockBaseAddress()) { + CFTimeInterval imageTime = QTMovieVisualContext::currentHostTime(); - CFTimeInterval imageTime = QTMovieVisualContext::currentHostTime(); + CGImageRef image = CreateCGImageFromPixelBuffer(buffer); + layer->setContents(image); + CGImageRelease(image); - CGImageRef image = CreateCGImageFromPixelBuffer(buffer); - layer->setContents(image); - CGImageRelease(image); - - if (attachments) - CFRelease(attachments); + buffer.unlockBaseAddress(); + layer->rootLayer()->setNeedsRender(); + } + } else +#endif + m_player->repaint(); - buffer.unlockBaseAddress(); - layer->rootLayer()->setNeedsRender(); - } m_visualContext->task(); -#endif } static HashSet<String> mimeTypeCache() @@ -886,8 +896,6 @@ void MediaPlayerPrivateQuickTimeVisualContext::setUpVideoRendering() if (currentMode == MediaRenderingMovieLayer || preferredMode == MediaRenderingMovieLayer) m_player->mediaPlayerClient()->mediaPlayerRenderingModeChanged(m_player); #endif - - m_visualContext->setMovie(m_movie.get()); } void MediaPlayerPrivateQuickTimeVisualContext::tearDownVideoRendering() @@ -896,8 +904,6 @@ void MediaPlayerPrivateQuickTimeVisualContext::tearDownVideoRendering() if (m_qtVideoLayer) destroyLayerForMovie(); #endif - - m_visualContext->setMovie(0); } bool MediaPlayerPrivateQuickTimeVisualContext::hasSetUpVideoRendering() const diff --git a/WebCore/platform/graphics/win/QTMovieVisualContext.h b/WebCore/platform/graphics/win/QTMovieVisualContext.h index 7afe589..8846416 100644 --- a/WebCore/platform/graphics/win/QTMovieVisualContext.h +++ b/WebCore/platform/graphics/win/QTMovieVisualContext.h @@ -38,6 +38,7 @@ #include <WTF/OwnPtr.h> #include <WTF/RefCounted.h> +typedef const struct __CFDictionary* CFDictionaryRef; typedef struct OpaqueQTVisualContext* QTVisualContextRef; // QTCVTimeStamp is a struct containing only a CVTimeStamp. This is to diff --git a/WebCore/platform/graphics/win/QTPixelBuffer.cpp b/WebCore/platform/graphics/win/QTPixelBuffer.cpp index 657b68e..f874287 100644 --- a/WebCore/platform/graphics/win/QTPixelBuffer.cpp +++ b/WebCore/platform/graphics/win/QTPixelBuffer.cpp @@ -172,11 +172,6 @@ void QTPixelBuffer::getExtendedPixels(size_t* left, size_t* right, size_t* top, return CVPixelBufferGetExtendedPixels(m_pixelBuffer, left, right, top, bottom); } -CFDictionaryRef QTPixelBuffer::attachments() const -{ - return CVBufferGetAttachments(m_pixelBuffer, kCVAttachmentMode_ShouldPropagate); -} - void QTPixelBuffer::retainCallback(void* refcon) { CVPixelBufferRetain(static_cast<CVPixelBufferRef>(refcon)); diff --git a/WebCore/platform/graphics/win/QTPixelBuffer.h b/WebCore/platform/graphics/win/QTPixelBuffer.h index 22f8ba4..3af2197 100644 --- a/WebCore/platform/graphics/win/QTPixelBuffer.h +++ b/WebCore/platform/graphics/win/QTPixelBuffer.h @@ -38,7 +38,6 @@ typedef struct __CVBuffer *CVBufferRef; typedef CVBufferRef CVPixelBufferRef; typedef struct CGImage* CGImageRef; typedef int32_t CVReturn; -typedef const struct __CFDictionary * CFDictionaryRef; // QTPixelBuffer wraps QuickTime's implementation of CVPixelBuffer, so its functions are // safe to call within WebKit. @@ -75,7 +74,6 @@ public: size_t bytesPerRowOfPlane(size_t) const; void getExtendedPixels(size_t* left, size_t* right, size_t* top, size_t* bottom) const; - CFDictionaryRef attachments() const; // Generic CFRetain/CFRelease callbacks static void releaseCallback(void* refcon); diff --git a/WebCore/platform/graphics/win/WKCACFContextFlusher.cpp b/WebCore/platform/graphics/win/WKCACFContextFlusher.cpp index e97b530..1685a30 100644 --- a/WebCore/platform/graphics/win/WKCACFContextFlusher.cpp +++ b/WebCore/platform/graphics/win/WKCACFContextFlusher.cpp @@ -52,8 +52,8 @@ void WKCACFContextFlusher::addContext(CACFContextRef context) { ASSERT(context); - m_contexts.add(context); - CFRetain(context); + if (m_contexts.add(context).second) + CFRetain(context); } void WKCACFContextFlusher::removeContext(CACFContextRef context) diff --git a/WebCore/platform/graphics/win/WKCACFLayer.cpp b/WebCore/platform/graphics/win/WKCACFLayer.cpp index 4a0461d..3f332d8 100644 --- a/WebCore/platform/graphics/win/WKCACFLayer.cpp +++ b/WebCore/platform/graphics/win/WKCACFLayer.cpp @@ -200,12 +200,12 @@ bool WKCACFLayer::isTransformLayer() const void WKCACFLayer::addSublayer(PassRefPtr<WKCACFLayer> sublayer) { - insertSublayer(sublayer, numSublayers()); + insertSublayer(sublayer, sublayerCount()); } -void WKCACFLayer::insertSublayer(PassRefPtr<WKCACFLayer> sublayer, size_t index) +void WKCACFLayer::internalInsertSublayer(PassRefPtr<WKCACFLayer> sublayer, size_t index) { - index = min(index, numSublayers()); + index = min(index, sublayerCount()); sublayer->removeFromSuperlayer(); CACFLayerInsertSublayer(layer(), sublayer->layer(), index); setNeedsCommit(); @@ -218,7 +218,7 @@ void WKCACFLayer::insertSublayerAboveLayer(PassRefPtr<WKCACFLayer> sublayer, con return; } - int referenceIndex = indexOfSublayer(reference); + int referenceIndex = internalIndexOfSublayer(reference); if (referenceIndex == -1) { addSublayer(sublayer); return; @@ -234,7 +234,7 @@ void WKCACFLayer::insertSublayerBelowLayer(PassRefPtr<WKCACFLayer> sublayer, con return; } - int referenceIndex = indexOfSublayer(reference); + int referenceIndex = internalIndexOfSublayer(reference); if (referenceIndex == -1) { addSublayer(sublayer); return; @@ -251,7 +251,7 @@ void WKCACFLayer::replaceSublayer(WKCACFLayer* reference, PassRefPtr<WKCACFLayer if (reference == newLayer) return; - int referenceIndex = indexOfSublayer(reference); + int referenceIndex = internalIndexOfSublayer(reference); ASSERT(referenceIndex != -1); if (referenceIndex == -1) return; @@ -264,6 +264,25 @@ void WKCACFLayer::replaceSublayer(WKCACFLayer* reference, PassRefPtr<WKCACFLayer } } +size_t WKCACFLayer::internalSublayerCount() const +{ + CFArrayRef sublayers = CACFLayerGetSublayers(layer()); + return sublayers ? CFArrayGetCount(sublayers) : 0; +} + +void WKCACFLayer::adoptSublayers(WKCACFLayer* source) +{ + // We will use setSublayers() because it properly nulls + // out the superlayer pointer. + Vector<RefPtr<WKCACFLayer> > sublayers; + size_t n = source->sublayerCount(); + + for (size_t i = 0; i < n; ++i) + sublayers.append(source->internalSublayerAtIndex(i)); + + setSublayers(sublayers); +} + void WKCACFLayer::removeFromSuperlayer() { WKCACFLayer* superlayer = this->superlayer(); @@ -274,22 +293,25 @@ void WKCACFLayer::removeFromSuperlayer() superlayer->setNeedsCommit(); } -const WKCACFLayer* WKCACFLayer::sublayerAtIndex(int index) const +WKCACFLayer* WKCACFLayer::internalSublayerAtIndex(int index) const { CFArrayRef sublayers = CACFLayerGetSublayers(layer()); - if (index < 0 || CFArrayGetCount(sublayers) <= index) + if (!sublayers || index < 0 || CFArrayGetCount(sublayers) <= index) return 0; return layer(static_cast<CACFLayerRef>(const_cast<void*>(CFArrayGetValueAtIndex(sublayers, index)))); } -int WKCACFLayer::indexOfSublayer(const WKCACFLayer* reference) +int WKCACFLayer::internalIndexOfSublayer(const WKCACFLayer* reference) { CACFLayerRef ref = reference->layer(); if (!ref) return -1; CFArrayRef sublayers = CACFLayerGetSublayers(layer()); + if (!sublayers) + return -1; + size_t n = CFArrayGetCount(sublayers); for (size_t i = 0; i < n; ++i) @@ -321,19 +343,6 @@ void WKCACFLayer::setBounds(const CGRect& rect) setNeedsDisplay(); } -void WKCACFLayer::setFrame(const CGRect& rect) -{ - CGRect oldFrame = frame(); - if (CGRectEqualToRect(rect, oldFrame)) - return; - - CACFLayerSetFrame(layer(), rect); - setNeedsCommit(); - - if (m_needsDisplayOnBoundsChange) - setNeedsDisplay(); -} - void WKCACFLayer::setContentsGravity(ContentsGravityType type) { CACFLayerSetContentsGravity(layer(), toCACFContentsGravityType(type)); @@ -374,13 +383,13 @@ WKCACFLayer* WKCACFLayer::rootLayer() const return layer; } -void WKCACFLayer::removeAllSublayers() +void WKCACFLayer::internalRemoveAllSublayers() { CACFLayerSetSublayers(layer(), 0); setNeedsCommit(); } -void WKCACFLayer::setSublayers(const Vector<RefPtr<WKCACFLayer> >& sublayers) +void WKCACFLayer::internalSetSublayers(const Vector<RefPtr<WKCACFLayer> >& sublayers) { // Remove all the current sublayers and add the passed layers CACFLayerSetSublayers(layer(), 0); @@ -404,15 +413,9 @@ WKCACFLayer* WKCACFLayer::superlayer() const return WKCACFLayer::layer(super); } -void WKCACFLayer::setNeedsDisplay(const CGRect* dirtyRect) +void WKCACFLayer::internalSetNeedsDisplay(const CGRect* dirtyRect) { CACFLayerSetNeedsDisplay(layer(), dirtyRect); - setNeedsCommit(); -} - -void WKCACFLayer::setNeedsDisplay() -{ - setNeedsDisplay(0); } #ifndef NDEBUG @@ -502,12 +505,12 @@ void WKCACFLayer::printLayer(int indent) const } // Print sublayers if needed - int n = numSublayers(); + int n = sublayerCount(); if (n > 0) { printIndent(indent + 1); fprintf(stderr, "(sublayers\n"); for (int i = 0; i < n; ++i) - sublayerAtIndex(i)->printLayer(indent + 2); + internalSublayerAtIndex(i)->printLayer(indent + 2); printIndent(indent + 1); fprintf(stderr, ")\n"); diff --git a/WebCore/platform/graphics/win/WKCACFLayer.h b/WebCore/platform/graphics/win/WKCACFLayer.h index f1b2613..bdc427e 100644 --- a/WebCore/platform/graphics/win/WKCACFLayer.h +++ b/WebCore/platform/graphics/win/WKCACFLayer.h @@ -60,9 +60,14 @@ public: virtual ~WKCACFLayer(); virtual void setNeedsRender() { } + virtual void drawInContext(PlatformGraphicsContext*) { } - virtual void setNeedsDisplay(const CGRect* dirtyRect); - void setNeedsDisplay(); + + void setNeedsDisplay(const CGRect* dirtyRect = 0) + { + internalSetNeedsDisplay(dirtyRect); + setNeedsCommit(); + } // Makes this layer the root when the passed context is rendered void becomeRootLayerForContext(CACFContextRef); @@ -113,10 +118,18 @@ public: bool isTransformLayer() const; void addSublayer(PassRefPtr<WKCACFLayer> sublayer); - void insertSublayer(PassRefPtr<WKCACFLayer>, size_t index); void insertSublayerAboveLayer(PassRefPtr<WKCACFLayer>, const WKCACFLayer* reference); void insertSublayerBelowLayer(PassRefPtr<WKCACFLayer>, const WKCACFLayer* reference); void replaceSublayer(WKCACFLayer* reference, PassRefPtr<WKCACFLayer>); + void adoptSublayers(WKCACFLayer* source); + + void removeAllSublayers() { internalRemoveAllSublayers(); } + void setSublayers(const Vector<RefPtr<WKCACFLayer> >& sublayers) { internalSetSublayers(sublayers); } + + void insertSublayer(PassRefPtr<WKCACFLayer> layer, size_t index) { internalInsertSublayer(layer, index); } + + size_t sublayerCount() const { return internalSublayerCount(); } + void removeFromSuperlayer(); WKCACFLayer* ancestorOrSelfWithSuperlayer(WKCACFLayer*) const; @@ -136,7 +149,7 @@ public: void setBorderWidth(CGFloat width) { CACFLayerSetBorderWidth(layer(), width); setNeedsCommit(); } CGFloat borderWidth() const { return CACFLayerGetBorderWidth(layer()); } - void setBounds(const CGRect&); + virtual void setBounds(const CGRect&); CGRect bounds() const { return CACFLayerGetBounds(layer()); } void setClearsContext(bool clears) { CACFLayerSetClearsContext(layer(), clears); setNeedsCommit(); } @@ -160,9 +173,6 @@ public: void setFilters(CFArrayRef filters) { CACFLayerSetFilters(layer(), filters); setNeedsCommit(); } CFArrayRef filters() const { return CACFLayerGetFilters(layer()); } - void setFrame(const CGRect&); - CGRect frame() const { return CACFLayerGetFrame(layer()); } - void setHidden(bool hidden) { CACFLayerSetHidden(layer(), hidden); setNeedsCommit(); } bool isHidden() const { return CACFLayerIsHidden(layer()); } @@ -206,10 +216,6 @@ public: void setSortsSublayers(bool sorts) { CACFLayerSetSortsSublayers(layer(), sorts); setNeedsCommit(); } bool sortsSublayers() const { return CACFLayerGetSortsSublayers(layer()); } - void removeAllSublayers(); - - void setSublayers(const Vector<RefPtr<WKCACFLayer> >&); - void setSublayerTransform(const CATransform3D& transform) { CACFLayerSetSublayerTransform(layer(), transform); setNeedsCommit(); } CATransform3D sublayerTransform() const { return CACFLayerGetSublayerTransform(layer()); } @@ -231,28 +237,30 @@ protected: void setNeedsCommit(); -private: CACFLayerRef layer() const { return m_layer.get(); } - size_t numSublayers() const - { - CFArrayRef sublayers = CACFLayerGetSublayers(layer()); - return sublayers ? CFArrayGetCount(sublayers) : 0; - } + // This should only be called from removeFromSuperlayer. + void removeSublayer(const WKCACFLayer*); + + // Methods to be overridden for sublayer and rendering management + virtual WKCACFLayer* internalSublayerAtIndex(int) const; - const WKCACFLayer* sublayerAtIndex(int) const; - // Returns the index of the passed layer in this layer's sublayers list // or -1 if not found - int indexOfSublayer(const WKCACFLayer*); + virtual int internalIndexOfSublayer(const WKCACFLayer*); - // This should only be called from removeFromSuperlayer. - void removeSublayer(const WKCACFLayer*); + virtual size_t internalSublayerCount() const; + virtual void internalInsertSublayer(PassRefPtr<WKCACFLayer>, size_t index); + virtual void internalRemoveAllSublayers(); + virtual void internalSetSublayers(const Vector<RefPtr<WKCACFLayer> >&); + + virtual void internalSetNeedsDisplay(const CGRect* dirtyRect); #ifndef NDEBUG // Print this layer and its children to the console void printLayer(int indent) const; #endif +private: RetainPtr<CACFLayerRef> m_layer; bool m_needsDisplayOnBoundsChange; }; diff --git a/WebCore/platform/graphics/win/WKCACFLayerRenderer.cpp b/WebCore/platform/graphics/win/WKCACFLayerRenderer.cpp index 994d079..0ee61f3 100644 --- a/WebCore/platform/graphics/win/WKCACFLayerRenderer.cpp +++ b/WebCore/platform/graphics/win/WKCACFLayerRenderer.cpp @@ -198,7 +198,7 @@ bool WKCACFLayerRenderer::acceleratedCompositingAvailable() return available; } - OwnPtr<WKCACFLayerRenderer> testLayerRenderer = WKCACFLayerRenderer::create(); + OwnPtr<WKCACFLayerRenderer> testLayerRenderer = WKCACFLayerRenderer::create(0); testLayerRenderer->setHostWindow(testWindow); available = testLayerRenderer->createRenderer(); ::DestroyWindow(testWindow); @@ -215,16 +215,21 @@ void WKCACFLayerRenderer::didFlushContext(CACFContextRef context) window->renderSoon(); } -PassOwnPtr<WKCACFLayerRenderer> WKCACFLayerRenderer::create() +PassOwnPtr<WKCACFLayerRenderer> WKCACFLayerRenderer::create(WKCACFLayerRendererClient* client) { if (!acceleratedCompositingAvailable()) return 0; - return new WKCACFLayerRenderer; + return new WKCACFLayerRenderer(client); } -WKCACFLayerRenderer::WKCACFLayerRenderer() - : m_triedToCreateD3DRenderer(false) - , m_renderContext(0) +WKCACFLayerRenderer::WKCACFLayerRenderer(WKCACFLayerRendererClient* client) + : m_client(client) + , m_mightBeAbleToCreateDeviceLater(true) + , m_rootLayer(WKCACFRootLayer::create(this)) + , m_scrollLayer(WKCACFLayer::create(WKCACFLayer::Layer)) + , m_clipLayer(WKCACFLayer::create(WKCACFLayer::Layer)) + , m_context(AdoptCF, CACFContextCreate(0)) + , m_renderContext(static_cast<CARenderContext*>(CACFContextGetRenderContext(m_context.get()))) , m_renderer(0) , m_hostWindow(0) , m_renderTimer(this, &WKCACFLayerRenderer::renderTimerFired) @@ -233,6 +238,37 @@ WKCACFLayerRenderer::WKCACFLayerRenderer() , m_backingStoreDirty(false) , m_mustResetLostDeviceBeforeRendering(false) { + windowsForContexts().set(m_context.get(), this); + + // Under the root layer, we have a clipping layer to clip the content, + // that contains a scroll layer that we use for scrolling the content. + // The root layer is the size of the client area of the window. + // The clipping layer is the size of the WebView client area (window less the scrollbars). + // The scroll layer is the size of the root child layer. + // Resizing the window will change the bounds of the rootLayer and the clip layer and will not + // cause any repositioning. + // Scrolling will affect only the position of the scroll layer without affecting the bounds. + + m_rootLayer->setName("WKCACFLayerRenderer rootLayer"); + m_clipLayer->setName("WKCACFLayerRenderer clipLayer"); + m_scrollLayer->setName("WKCACFLayerRenderer scrollLayer"); + + m_rootLayer->addSublayer(m_clipLayer); + m_clipLayer->addSublayer(m_scrollLayer); + m_clipLayer->setMasksToBounds(true); + m_rootLayer->setAnchorPoint(CGPointMake(0, 0)); + m_scrollLayer->setAnchorPoint(CGPointMake(0, 1)); + m_clipLayer->setAnchorPoint(CGPointMake(0, 1)); + +#ifndef NDEBUG + CGColorRef debugColor = createCGColor(Color(255, 0, 0, 204)); + m_rootLayer->setBackgroundColor(debugColor); + CGColorRelease(debugColor); +#endif + + if (m_context) + m_rootLayer->becomeRootLayerForContext(m_context.get()); + #ifndef NDEBUG char* printTreeFlag = getenv("CA_PRINT_TREE"); m_printTree = printTreeFlag && atoi(printTreeFlag); @@ -306,10 +342,10 @@ void WKCACFLayerRenderer::setNeedsDisplay() bool WKCACFLayerRenderer::createRenderer() { - if (m_triedToCreateD3DRenderer) + if (m_d3dDevice || !m_mightBeAbleToCreateDeviceLater) return m_d3dDevice; - m_triedToCreateD3DRenderer = true; + m_mightBeAbleToCreateDeviceLater = false; D3DPRESENT_PARAMETERS parameters = initialPresentationParameters(); if (!d3d() || !::IsWindow(m_hostWindow)) @@ -326,9 +362,31 @@ bool WKCACFLayerRenderer::createRenderer() parameters.BackBufferHeight = 1; } + D3DCAPS9 d3dCaps; + if (FAILED(d3d()->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &d3dCaps))) + return false; + + DWORD behaviorFlags = D3DCREATE_FPU_PRESERVE; + if ((d3dCaps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) && d3dCaps.VertexProcessingCaps) + behaviorFlags |= D3DCREATE_HARDWARE_VERTEXPROCESSING; + else + behaviorFlags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING; + COMPtr<IDirect3DDevice9> device; - if (FAILED(d3d()->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, m_hostWindow, D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_FPU_PRESERVE, ¶meters, &device))) + if (FAILED(d3d()->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, m_hostWindow, behaviorFlags, ¶meters, &device))) { + // In certain situations (e.g., shortly after waking from sleep), Direct3DCreate9() will + // return an IDirect3D9 for which IDirect3D9::CreateDevice will always fail. In case we + // have one of these bad IDirect3D9s, get rid of it so we'll fetch a new one the next time + // we want to call CreateDevice. + s_d3d->Release(); + s_d3d = 0; + + // Even if we don't have a bad IDirect3D9, in certain situations (e.g., shortly after + // waking from sleep), CreateDevice will fail, but will later succeed if called again. + m_mightBeAbleToCreateDeviceLater = true; + return false; + } // Now that we've created the IDirect3DDevice9 based on the capabilities we // got from the IDirect3D9 global object, we requery the device for its @@ -349,48 +407,10 @@ bool WKCACFLayerRenderer::createRenderer() m_d3dDevice->SetTransform(D3DTS_PROJECTION, &projection); - m_context.adoptCF(CACFContextCreate(0)); - windowsForContexts().set(m_context.get(), this); - - m_renderContext = static_cast<CARenderContext*>(CACFContextGetRenderContext(m_context.get())); m_renderer = CARenderOGLNew(&kCARenderDX9Callbacks, m_d3dDevice.get(), 0); - // Create the root hierarchy. - // Under the root layer, we have a clipping layer to clip the content, - // that contains a scroll layer that we use for scrolling the content. - // The root layer is the size of the client area of the window. - // The clipping layer is the size of the WebView client area (window less the scrollbars). - // The scroll layer is the size of the root child layer. - // Resizing the window will change the bounds of the rootLayer and the clip layer and will not - // cause any repositioning. - // Scrolling will affect only the position of the scroll layer without affecting the bounds. - - m_rootLayer = WKCACFRootLayer::create(this); - m_rootLayer->setName("WKCACFLayerRenderer rootLayer"); - - m_clipLayer = WKCACFLayer::create(WKCACFLayer::Layer); - m_clipLayer->setName("WKCACFLayerRenderer clipLayer"); - - m_scrollLayer = WKCACFLayer::create(WKCACFLayer::Layer); - m_scrollLayer->setName("WKCACFLayerRenderer scrollLayer"); - - m_rootLayer->addSublayer(m_clipLayer); - m_clipLayer->addSublayer(m_scrollLayer); - m_clipLayer->setMasksToBounds(true); - m_scrollLayer->setAnchorPoint(CGPointMake(0, 1)); - m_clipLayer->setAnchorPoint(CGPointMake(0, 1)); - -#ifndef NDEBUG - CGColorRef debugColor = createCGColor(Color(255, 0, 0, 204)); - m_rootLayer->setBackgroundColor(debugColor); - CGColorRelease(debugColor); -#endif - if (IsWindow(m_hostWindow)) - m_rootLayer->setFrame(bounds()); - - if (m_context) - m_rootLayer->becomeRootLayerForContext(m_context.get()); + m_rootLayer->setBounds(bounds()); return true; } @@ -398,6 +418,7 @@ bool WKCACFLayerRenderer::createRenderer() void WKCACFLayerRenderer::destroyRenderer() { if (m_context) { + CACFContextSetLayer(m_context.get(), 0); windowsForContexts().remove(m_context.get()); WKCACFContextFlusher::shared().removeContext(m_context.get()); } @@ -415,7 +436,7 @@ void WKCACFLayerRenderer::destroyRenderer() m_scrollLayer = 0; m_rootChildLayer = 0; - m_triedToCreateD3DRenderer = false; + m_mightBeAbleToCreateDeviceLater = true; } void WKCACFLayerRenderer::resize() @@ -428,7 +449,7 @@ void WKCACFLayerRenderer::resize() resetDevice(ChangedWindowSize); if (m_rootLayer) { - m_rootLayer->setFrame(bounds()); + m_rootLayer->setBounds(bounds()); WKCACFContextFlusher::shared().flushAllContexts(); updateScrollFrame(); } @@ -442,8 +463,8 @@ static void getDirtyRects(HWND window, Vector<CGRect>& outRects) if (!GetClientRect(window, &clientRect)) return; - HRGN region = CreateRectRgn(0, 0, 0, 0); - int regionType = GetUpdateRgn(window, region, false); + OwnPtr<HRGN> region(CreateRectRgn(0, 0, 0, 0)); + int regionType = GetUpdateRgn(window, region.get(), false); if (regionType != COMPLEXREGION) { RECT dirtyRect; if (GetUpdateRect(window, &dirtyRect, false)) @@ -451,10 +472,10 @@ static void getDirtyRects(HWND window, Vector<CGRect>& outRects) return; } - DWORD dataSize = GetRegionData(region, 0, 0); + DWORD dataSize = GetRegionData(region.get(), 0, 0); OwnArrayPtr<unsigned char> regionDataBuffer(new unsigned char[dataSize]); RGNDATA* regionData = reinterpret_cast<RGNDATA*>(regionDataBuffer.get()); - if (!GetRegionData(region, dataSize, regionData)) + if (!GetRegionData(region.get(), dataSize, regionData)) return; outRects.resize(regionData->rdh.nCount); @@ -462,8 +483,6 @@ static void getDirtyRects(HWND window, Vector<CGRect>& outRects) RECT* rect = reinterpret_cast<RECT*>(regionData->Buffer); for (size_t i = 0; i < outRects.size(); ++i, ++rect) outRects[i] = winRectToCGRect(*rect, clientRect); - - DeleteObject(region); } void WKCACFLayerRenderer::renderTimerFired(Timer<WKCACFLayerRenderer>*) @@ -473,8 +492,12 @@ void WKCACFLayerRenderer::renderTimerFired(Timer<WKCACFLayerRenderer>*) void WKCACFLayerRenderer::paint() { - if (!m_d3dDevice) + createRenderer(); + if (!m_d3dDevice) { + if (m_mightBeAbleToCreateDeviceLater) + renderSoon(); return; + } if (m_backingStoreDirty) { // If the backing store is still dirty when we are about to draw the @@ -500,6 +523,11 @@ void WKCACFLayerRenderer::render(const Vector<CGRect>& dirtyRects) return; } + if (m_client && !m_client->shouldRender()) { + renderSoon(); + return; + } + // Flush the root layer to the render tree. WKCACFContextFlusher::shared().flushAllContexts(); diff --git a/WebCore/platform/graphics/win/WKCACFLayerRenderer.h b/WebCore/platform/graphics/win/WKCACFLayerRenderer.h index 259c52f..1ff955a 100644 --- a/WebCore/platform/graphics/win/WKCACFLayerRenderer.h +++ b/WebCore/platform/graphics/win/WKCACFLayerRenderer.h @@ -49,12 +49,18 @@ namespace WebCore { class WKCACFRootLayer; +class WKCACFLayerRendererClient { +public: + virtual ~WKCACFLayerRendererClient() { } + virtual bool shouldRender() const = 0; +}; + // FIXME: Currently there is a WKCACFLayerRenderer for each WebView and each // has its own CARenderOGLContext and Direct3DDevice9, which is inefficient. // (https://bugs.webkit.org/show_bug.cgi?id=31855) class WKCACFLayerRenderer : public Noncopyable { public: - static PassOwnPtr<WKCACFLayerRenderer> create(); + static PassOwnPtr<WKCACFLayerRenderer> create(WKCACFLayerRendererClient*); ~WKCACFLayerRenderer(); static bool acceleratedCompositingAvailable(); @@ -77,7 +83,7 @@ protected: WKCACFLayer* rootLayer() const; private: - WKCACFLayerRenderer(); + WKCACFLayerRenderer(WKCACFLayerRendererClient*); void renderTimerFired(Timer<WKCACFLayerRenderer>*); @@ -94,10 +100,10 @@ private: void render(const Vector<CGRect>& dirtyRects = Vector<CGRect>()); void paint(); - bool m_triedToCreateD3DRenderer; + WKCACFLayerRendererClient* m_client; + bool m_mightBeAbleToCreateDeviceLater; COMPtr<IDirect3DDevice9> m_d3dDevice; RefPtr<WKCACFRootLayer> m_rootLayer; - RefPtr<WKCACFLayer> m_viewLayer; RefPtr<WKCACFLayer> m_scrollLayer; RefPtr<WKCACFLayer> m_rootChildLayer; RefPtr<WKCACFLayer> m_clipLayer; diff --git a/WebCore/platform/graphics/win/WebLayer.cpp b/WebCore/platform/graphics/win/WebLayer.cpp new file mode 100755 index 0000000..70a522d --- /dev/null +++ b/WebCore/platform/graphics/win/WebLayer.cpp @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if USE(ACCELERATED_COMPOSITING) + +#include "WebLayer.h" + +#include "Font.h" +#include "GraphicsLayer.h" + +namespace WebCore { + +using namespace std; + +void WebLayer::internalSetNeedsDisplay(const CGRect* dirtyRect) +{ + if (m_owner) { + if (m_owner->showRepaintCounter()) { + CGRect layerBounds = bounds(); + CGRect repaintCounterRect = layerBounds; + // We assume a maximum of 4 digits and a font size of 18. + repaintCounterRect.size.width = 80; + repaintCounterRect.size.height = 22; + if (m_owner->contentsOrientation() == WebCore::GraphicsLayer::CompositingCoordinatesTopDown) + repaintCounterRect.origin.y = layerBounds.size.height - (layerBounds.origin.y + repaintCounterRect.size.height); + WKCACFLayer::internalSetNeedsDisplay(&repaintCounterRect); + } + if (dirtyRect && m_owner->contentsOrientation() == WebCore::GraphicsLayer::CompositingCoordinatesTopDown) { + CGRect flippedDirtyRect = *dirtyRect; + flippedDirtyRect.origin.y = bounds().size.height - (flippedDirtyRect.origin.y + flippedDirtyRect.size.height); + WKCACFLayer::internalSetNeedsDisplay(&flippedDirtyRect); + return; + } + } + + WKCACFLayer::internalSetNeedsDisplay(dirtyRect); +} + +void WebLayer::drawInContext(PlatformGraphicsContext* context) +{ + if (!m_owner) + return; + + CGContextSaveGState(context); + + CGRect layerBounds = bounds(); + if (m_owner->contentsOrientation() == WebCore::GraphicsLayer::CompositingCoordinatesTopDown) { + CGContextScaleCTM(context, 1, -1); + CGContextTranslateCTM(context, 0, -layerBounds.size.height); + } + + if (m_owner->client()) { + GraphicsContext graphicsContext(context); + + // It's important to get the clip from the context, because it may be significantly + // smaller than the layer bounds (e.g. tiled layers) + CGRect clipBounds = CGContextGetClipBoundingBox(context); + IntRect clip(enclosingIntRect(clipBounds)); + m_owner->paintGraphicsLayerContents(graphicsContext, clip); + } +#ifndef NDEBUG + else { + ASSERT_NOT_REACHED(); + + // FIXME: ideally we'd avoid calling -setNeedsDisplay on a layer that is a plain color, + // so CA never makes backing store for it (which is what -setNeedsDisplay will do above). + CGContextSetRGBFillColor(context, 0.0f, 1.0f, 0.0f, 1.0f); + CGContextFillRect(context, layerBounds); + } +#endif + + if (m_owner->showRepaintCounter()) { + String text = String::format("%d", m_owner->incrementRepaintCount());; + + CGContextSaveGState(context); + + // Make the background of the counter the same as the border color, + // unless there is no border, then make it red + float borderWidth = CACFLayerGetBorderWidth(layer()); + if (borderWidth > 0) { + CGColorRef borderColor = CACFLayerGetBorderColor(layer()); + const CGFloat* colors = CGColorGetComponents(borderColor); + CGContextSetRGBFillColor(context, colors[0], colors[1], colors[2], colors[3]); + } else + CGContextSetRGBFillColor(context, 1.0f, 0.0f, 0.0f, 0.8f); + + CGRect aBounds = layerBounds; + + aBounds.size.width = 10 + 10 * text.length(); + aBounds.size.height = 22; + CGContextFillRect(context, aBounds); + + FontDescription desc; + + NONCLIENTMETRICS metrics; + metrics.cbSize = sizeof(metrics); + SystemParametersInfo(SPI_GETNONCLIENTMETRICS, metrics.cbSize, &metrics, 0); + FontFamily family; + family.setFamily(metrics.lfSmCaptionFont.lfFaceName); + desc.setFamily(family); + + desc.setComputedSize(18); + + Font font = Font(desc, 0, 0); + font.update(0); + + GraphicsContext cg(context); + cg.setFillColor(Color::black, DeviceColorSpace); + cg.drawText(font, TextRun(text), IntPoint(aBounds.origin.x + 5, aBounds.origin.y + 17)); + + CGContextRestoreGState(context); + } + + CGContextRestoreGState(context); +} + +} + +#endif // USE(ACCELERATED_COMPOSITING) diff --git a/WebCore/platform/graphics/win/WebLayer.h b/WebCore/platform/graphics/win/WebLayer.h new file mode 100755 index 0000000..8dab5cc --- /dev/null +++ b/WebCore/platform/graphics/win/WebLayer.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef WebLayer_h +#define WebLayer_h + +#if USE(ACCELERATED_COMPOSITING) + +#include "WKCACFLayer.h" + +namespace WebCore { + +class GraphicsLayer; + +class WebLayer : public WKCACFLayer { +public: + static PassRefPtr<WKCACFLayer> create(LayerType layerType, GraphicsLayer* owner) + { + return adoptRef(new WebLayer(layerType, owner)); + } + + virtual void drawInContext(PlatformGraphicsContext*); + +protected: + WebLayer(LayerType layerType, GraphicsLayer* owner) + : WKCACFLayer(layerType) + , m_owner(owner) + { + } + + virtual void internalSetNeedsDisplay(const CGRect* dirtyRect); + + GraphicsLayer* m_owner; +}; + +} + +#endif // USE(ACCELERATED_COMPOSITING) + +#endif // WebLayer_h diff --git a/WebCore/platform/graphics/win/WebTiledLayer.cpp b/WebCore/platform/graphics/win/WebTiledLayer.cpp new file mode 100755 index 0000000..0cf3f9d --- /dev/null +++ b/WebCore/platform/graphics/win/WebTiledLayer.cpp @@ -0,0 +1,274 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if USE(ACCELERATED_COMPOSITING) + +#include "WebTiledLayer.h" + +#include "GraphicsLayer.h" +#include "WKCACFLayerRenderer.h" + +namespace WebCore { + +using namespace std; + +void WebTiledLayer::tileDisplayCallback(CACFLayerRef layer, CGContextRef context) +{ + static_cast<WebTiledLayer*>(CACFLayerGetUserData(layer))->drawTile(layer, context); +} + +PassRefPtr<WebTiledLayer> WebTiledLayer::create(const CGSize& tileSize, GraphicsLayer* owner) +{ + ASSERT(WKCACFLayerRenderer::acceleratedCompositingAvailable()); + return adoptRef(new WebTiledLayer(tileSize, owner)); +} + +WebTiledLayer::WebTiledLayer(const CGSize& tileSize, GraphicsLayer* owner) + : WebLayer(WKCACFLayer::Layer, owner) + , m_tileSize(tileSize) + , m_constrainedSize(constrainedSize(bounds().size)) +{ + // Tiled layers are placed in a child layer that is always the first child of the TiledLayer + m_tileParent.adoptCF(CACFLayerCreate(kCACFLayer)); + CACFLayerInsertSublayer(layer(), m_tileParent.get(), 0); + + updateTiles(); +} + +WebTiledLayer::~WebTiledLayer() +{ +} + +void WebTiledLayer::setBounds(const CGRect& rect) +{ + if (CGRectEqualToRect(rect, bounds())) + return; + + WebLayer::setBounds(rect); + m_constrainedSize = constrainedSize(rect.size); + updateTiles(); +} + +void WebTiledLayer::internalSetNeedsDisplay(const CGRect* dirtyRect) +{ + // FIXME: Only setNeedsDisplay for tiles that are currently visible + int numTileLayers = tileCount(); + for (int i = 0; i < numTileLayers; ++i) + CACFLayerSetNeedsDisplay(tileAtIndex(i), dirtyRect); + + if (m_owner->showRepaintCounter()) { + CGRect layerBounds = bounds(); + CGRect indicatorRect = CGRectMake(layerBounds.origin.x, layerBounds.origin.y, 80, 25); + CACFLayerSetNeedsDisplay(tileAtIndex(0), &indicatorRect); + } +} + +size_t WebTiledLayer::internalSublayerCount() const +{ + ASSERT(WebLayer::internalSublayerCount() > 0); + + // Subtract 1 to account for the tile parent layer + return WebLayer::internalSublayerCount() - 1; +} + +void WebTiledLayer::internalRemoveAllSublayers() +{ + // Restore the tile parent after removal + WebLayer::internalRemoveAllSublayers(); + CACFLayerInsertSublayer(layer(), m_tileParent.get(), 0); +} + +void WebTiledLayer::internalSetSublayers(const Vector<RefPtr<WKCACFLayer> >& sublayers) +{ + // Preserve the tile parent after set + WebLayer::internalSetSublayers(sublayers); + CACFLayerInsertSublayer(layer(), m_tileParent.get(), 0); +} + +void WebTiledLayer::internalInsertSublayer(PassRefPtr<WKCACFLayer> layer, size_t index) +{ + // Add 1 to account for the tile parent layer + WebLayer::internalInsertSublayer(layer, index + 1); +} + +WKCACFLayer* WebTiledLayer::internalSublayerAtIndex(int i) const +{ + // Add 1 to account for the tile parent layer + return WebLayer::internalSublayerAtIndex(i + 1); +} + +int WebTiledLayer::internalIndexOfSublayer(const WKCACFLayer* layer) +{ + int i = WebLayer::internalIndexOfSublayer(layer); + + // Add 1 to account for the tile parent layer (but be safe about it) + return (i > 0) ? i - 1 : -1; +} + +CGSize WebTiledLayer::constrainedSize(const CGSize& size) const +{ + const int cMaxTileCount = 512; + const float cSqrtMaxTileCount = sqrtf(cMaxTileCount); + + CGSize constrainedSize = size; + + int tileColumns = ceilf(constrainedSize.width / m_tileSize.width); + int tileRows = ceilf(constrainedSize.height / m_tileSize.height); + int numTiles = tileColumns * tileRows; + + // If number of tiles vertically or horizontally is < sqrt(cMaxTileCount) + // just shorten the longer dimension. Otherwise shorten both dimensions + // according to the ratio of width to height + + if (numTiles > cMaxTileCount) { + if (tileRows < cSqrtMaxTileCount) + tileColumns = floorf(cMaxTileCount / tileRows); + else if (tileColumns < cSqrtMaxTileCount) + tileRows = floorf(cMaxTileCount / tileColumns); + else { + tileRows = ceilf(sqrtf(cMaxTileCount * constrainedSize.height / constrainedSize.width)); + tileColumns = floorf(cMaxTileCount / tileRows); + } + + constrainedSize.width = tileColumns * m_tileSize.width; + constrainedSize.height = tileRows * m_tileSize.height; + } + + return constrainedSize; +} + +void WebTiledLayer::addTile() +{ + RetainPtr<CACFLayerRef> newLayer(AdoptCF, CACFLayerCreate(kCACFLayer)); + CACFLayerSetAnchorPoint(newLayer.get(), CGPointMake(0, 1)); + CACFLayerSetUserData(newLayer.get(), this); + CACFLayerSetDisplayCallback(newLayer.get(), tileDisplayCallback); + + CFArrayRef sublayers = CACFLayerGetSublayers(m_tileParent.get()); + CACFLayerInsertSublayer(m_tileParent.get(), newLayer.get(), sublayers ? CFArrayGetCount(sublayers) : 0); + + if (m_owner->showDebugBorders()) { + CGColorRef borderColor = createCGColor(Color(128, 0, 128, 180)); + CACFLayerSetBorderColor(newLayer.get(), borderColor); + CGColorRelease(borderColor); + CACFLayerSetBorderWidth(newLayer.get(), 2); + } +} + +void WebTiledLayer::removeTile() +{ + CACFLayerRemoveFromSuperlayer(tileAtIndex(tileCount() - 1)); +} + +CACFLayerRef WebTiledLayer::tileAtIndex(int index) +{ + CFArrayRef sublayers = CACFLayerGetSublayers(m_tileParent.get()); + if (!sublayers || index < 0 || index >= tileCount() ) + return 0; + + return static_cast<CACFLayerRef>(const_cast<void*>(CFArrayGetValueAtIndex(sublayers, index))); +} + +int WebTiledLayer::tileCount() const +{ + CFArrayRef sublayers = CACFLayerGetSublayers(m_tileParent.get()); + return sublayers ? CFArrayGetCount(sublayers) : 0; +} + +void WebTiledLayer::updateTiles() +{ + // FIXME: In addition to redoing the number of tiles, we need to only render and have backing + // store for visible layers + int numTilesHorizontal = ceil(m_constrainedSize.width / m_tileSize.width); + int numTilesVertical = ceil(m_constrainedSize.height / m_tileSize.height); + int numTilesTotal = numTilesHorizontal * numTilesVertical; + + int numTilesToChange = numTilesTotal - tileCount(); + if (numTilesToChange >= 0) { + // Add new tiles + for (int i = 0; i < numTilesToChange; ++i) + addTile(); + } else { + // Remove old tiles + numTilesToChange = -numTilesToChange; + for (int i = 0; i < numTilesToChange; ++i) + removeTile(); + } + + // Set coordinates for all tiles + CFArrayRef tileArray = CACFLayerGetSublayers(m_tileParent.get()); + + for (int i = 0; i < numTilesHorizontal; ++i) { + for (int j = 0; j < numTilesVertical; ++j) { + CACFLayerRef tile = static_cast<CACFLayerRef>(const_cast<void*>(CFArrayGetValueAtIndex(tileArray, i * numTilesVertical + j))); + CACFLayerSetPosition(tile, CGPointMake(i * m_tileSize.width, j * m_tileSize.height)); + int width = min(m_tileSize.width, m_constrainedSize.width - i * m_tileSize.width); + int height = min(m_tileSize.height, m_constrainedSize.height - j * m_tileSize.height); + CACFLayerSetBounds(tile, CGRectMake(i * m_tileSize.width, j * m_tileSize.height, width, height)); + + // Flip Y to compensate for the flipping that happens during render to match the CG context coordinate space + CATransform3D transform = CATransform3DMakeScale(1, -1, 1); + CATransform3DTranslate(transform, 0, height, 0); + CACFLayerSetTransform(tile, transform); + +#ifndef NDEBUG + String name = "Tile (" + String::number(i) + "," + String::number(j) + ")"; + CACFLayerSetName(tile, RetainPtr<CFStringRef>(AdoptCF, name.createCFString()).get()); +#endif + } + } +} + +void WebTiledLayer::drawTile(CACFLayerRef tile, CGContextRef context) +{ + CGPoint tilePosition = CACFLayerGetPosition(tile); + CGRect tileBounds = CACFLayerGetBounds(tile); + + CGContextSaveGState(context); + + // Transform context to be at the origin of the parent layer + CGContextTranslateCTM(context, -tilePosition.x, -tilePosition.y); + + // Set the context clipping rectangle to the current tile + CGContextClipToRect(context, CGRectMake(tilePosition.x, tilePosition.y, tileBounds.size.width, tileBounds.size.height)); + + if (m_owner->contentsOrientation() == WebCore::GraphicsLayer::CompositingCoordinatesTopDown) { + // If the layer is rendering top-down, it will flip the coordinates in y. Tiled layers are + // already flipping, so we need to undo that here. + CGContextTranslateCTM(context, 0, bounds().size.height); + CGContextScaleCTM(context, 1, -1); + } + + // Draw the tile + drawInContext(context); + + CGContextRestoreGState(context); +} + +} + +#endif // USE(ACCELERATED_COMPOSITING) diff --git a/WebCore/platform/graphics/win/WebTiledLayer.h b/WebCore/platform/graphics/win/WebTiledLayer.h new file mode 100755 index 0000000..ed61656 --- /dev/null +++ b/WebCore/platform/graphics/win/WebTiledLayer.h @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef WebTiledLayer_h +#define WebTiledLayer_h + +#if USE(ACCELERATED_COMPOSITING) + +#include "WebLayer.h" + +namespace WebCore { + +class WebTiledLayer : public WebLayer { +public: + static PassRefPtr<WebTiledLayer> create(const CGSize& tileSize, GraphicsLayer* owner); + + virtual ~WebTiledLayer(); + + virtual void setBounds(const CGRect&); + +protected: + WebTiledLayer(const CGSize& tileSize, GraphicsLayer* owner); + + // Overridden from WKCACFLayer + virtual WKCACFLayer* internalSublayerAtIndex(int) const; + virtual int internalIndexOfSublayer(const WKCACFLayer*); + + virtual size_t internalSublayerCount() const; + virtual void internalInsertSublayer(PassRefPtr<WKCACFLayer>, size_t index); + + virtual void internalRemoveAllSublayers(); + virtual void internalSetSublayers(const Vector<RefPtr<WKCACFLayer> >&); + + virtual void internalSetNeedsDisplay(const CGRect* dirtyRect); + +private: + static void tileDisplayCallback(CACFLayerRef, CGContextRef); + void drawTile(CACFLayerRef, CGContextRef); + + CGSize constrainedSize(const CGSize& size) const; + + void addTile(); + void removeTile(); + CACFLayerRef tileAtIndex(int); + int tileCount() const; + + void updateTiles(); + + CGSize m_tileSize; + CGSize m_constrainedSize; + RetainPtr<CACFLayerRef> m_tileParent; +}; + +} + +#endif // USE(ACCELERATED_COMPOSITING) + +#endif // WebTiledLayer_h |