diff options
author | Allan Sandfeld Jensen <allan.jensen@digia.com> | 2013-09-13 12:51:20 +0200 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2013-09-19 20:50:05 +0200 |
commit | d441d6f39bb846989d95bcf5caf387b42414718d (patch) | |
tree | e367e64a75991c554930278175d403c072de6bb8 /Source/WebCore/platform/graphics/texmap | |
parent | 0060b2994c07842f4c59de64b5e3e430525c4b90 (diff) | |
download | qtwebkit-d441d6f39bb846989d95bcf5caf387b42414718d.tar.gz |
Import Qt5x2 branch of QtWebkit for Qt 5.2
Importing a new snapshot of webkit.
Change-Id: I2d01ad12cdc8af8cb015387641120a9d7ea5f10c
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@digia.com>
Diffstat (limited to 'Source/WebCore/platform/graphics/texmap')
48 files changed, 7866 insertions, 1995 deletions
diff --git a/Source/WebCore/platform/graphics/texmap/GraphicsLayerTextureMapper.cpp b/Source/WebCore/platform/graphics/texmap/GraphicsLayerTextureMapper.cpp index 5ba109066..bfca0bf17 100644 --- a/Source/WebCore/platform/graphics/texmap/GraphicsLayerTextureMapper.cpp +++ b/Source/WebCore/platform/graphics/texmap/GraphicsLayerTextureMapper.cpp @@ -24,16 +24,17 @@ #include "GraphicsLayerAnimation.h" #include "GraphicsLayerFactory.h" #include "ImageBuffer.h" -#include "NotImplemented.h" #include <wtf/CurrentTime.h> -#if USE(CAIRO) -#include "CairoUtilities.h" -#include <wtf/text/CString.h> -#endif +#if USE(TEXTURE_MAPPER) namespace WebCore { +TextureMapperLayer* toTextureMapperLayer(GraphicsLayer* layer) +{ + return layer ? toGraphicsLayerTextureMapper(layer)->layer() : 0; +} + PassOwnPtr<GraphicsLayer> GraphicsLayer::create(GraphicsLayerFactory* factory, GraphicsLayerClient* client) { if (!factory) @@ -44,8 +45,6 @@ PassOwnPtr<GraphicsLayer> GraphicsLayer::create(GraphicsLayerFactory* factory, G PassOwnPtr<GraphicsLayer> GraphicsLayer::create(GraphicsLayerClient* client) { - if (s_graphicsLayerFactory) - return (*s_graphicsLayerFactory)(client); return adoptPtr(new GraphicsLayerTextureMapper(client)); } @@ -53,18 +52,17 @@ GraphicsLayerTextureMapper::GraphicsLayerTextureMapper(GraphicsLayerClient* clie : GraphicsLayer(client) , m_layer(adoptPtr(new TextureMapperLayer())) , m_compositedNativeImagePtr(0) - , m_changeMask(0) + , m_changeMask(NoChanges) , m_needsDisplay(false) - , m_hasOwnBackingStore(true) , m_fixedToViewport(false) , m_debugBorderWidth(0) , m_contentsLayer(0) - , m_animationStartedTimer(this, &GraphicsLayerTextureMapper::animationStartedTimerFired) , m_animationStartTime(0) + , m_isScrollable(false) { } -void GraphicsLayerTextureMapper::notifyChange(TextureMapperLayer::ChangeMask changeMask) +void GraphicsLayerTextureMapper::notifyChange(ChangeMask changeMask) { m_changeMask |= changeMask; if (!client()) @@ -79,6 +77,9 @@ void GraphicsLayerTextureMapper::setName(const String& name) GraphicsLayerTextureMapper::~GraphicsLayerTextureMapper() { + if (m_contentsLayer) + m_contentsLayer->setClient(0); + willBeDestroyed(); } @@ -91,11 +92,11 @@ void GraphicsLayerTextureMapper::willBeDestroyed() */ void GraphicsLayerTextureMapper::setNeedsDisplay() { - if (!m_hasOwnBackingStore) + if (!drawsContent()) return; m_needsDisplay = true; - notifyChange(TextureMapperLayer::DisplayChange); + notifyChange(DisplayChange); addRepaintRect(FloatRect(FloatPoint(), m_size)); } @@ -103,7 +104,7 @@ void GraphicsLayerTextureMapper::setNeedsDisplay() */ void GraphicsLayerTextureMapper::setContentsNeedsDisplay() { - notifyChange(TextureMapperLayer::DisplayChange); + notifyChange(DisplayChange); addRepaintRect(contentsRect()); } @@ -111,37 +112,32 @@ void GraphicsLayerTextureMapper::setContentsNeedsDisplay() */ void GraphicsLayerTextureMapper::setNeedsDisplayInRect(const FloatRect& rect) { - if (!m_hasOwnBackingStore) + if (!drawsContent()) return; if (m_needsDisplay) return; m_needsDisplayRect.unite(rect); - notifyChange(TextureMapperLayer::DisplayChange); + notifyChange(DisplayChange); addRepaintRect(rect); } /* \reimp (GraphicsLayer.h) */ -void GraphicsLayerTextureMapper::setParent(GraphicsLayer* layer) -{ - notifyChange(TextureMapperLayer::ParentChange); - GraphicsLayer::setParent(layer); -} - -/* \reimp (GraphicsLayer.h) -*/ bool GraphicsLayerTextureMapper::setChildren(const Vector<GraphicsLayer*>& children) { - notifyChange(TextureMapperLayer::ChildrenChange); - return GraphicsLayer::setChildren(children); + if (GraphicsLayer::setChildren(children)) { + notifyChange(ChildrenChange); + return true; + } + return false; } /* \reimp (GraphicsLayer.h) */ void GraphicsLayerTextureMapper::addChild(GraphicsLayer* layer) { - notifyChange(TextureMapperLayer::ChildrenChange); + notifyChange(ChildrenChange); GraphicsLayer::addChild(layer); } @@ -150,15 +146,15 @@ void GraphicsLayerTextureMapper::addChild(GraphicsLayer* layer) void GraphicsLayerTextureMapper::addChildAtIndex(GraphicsLayer* layer, int index) { GraphicsLayer::addChildAtIndex(layer, index); - notifyChange(TextureMapperLayer::ChildrenChange); + notifyChange(ChildrenChange); } /* \reimp (GraphicsLayer.h) */ void GraphicsLayerTextureMapper::addChildAbove(GraphicsLayer* layer, GraphicsLayer* sibling) { - GraphicsLayer::addChildAbove(layer, sibling); - notifyChange(TextureMapperLayer::ChildrenChange); + GraphicsLayer::addChildAbove(layer, sibling); + notifyChange(ChildrenChange); } /* \reimp (GraphicsLayer.h) @@ -166,7 +162,7 @@ void GraphicsLayerTextureMapper::addChildAbove(GraphicsLayer* layer, GraphicsLay void GraphicsLayerTextureMapper::addChildBelow(GraphicsLayer* layer, GraphicsLayer* sibling) { GraphicsLayer::addChildBelow(layer, sibling); - notifyChange(TextureMapperLayer::ChildrenChange); + notifyChange(ChildrenChange); } /* \reimp (GraphicsLayer.h) @@ -174,7 +170,7 @@ void GraphicsLayerTextureMapper::addChildBelow(GraphicsLayer* layer, GraphicsLay bool GraphicsLayerTextureMapper::replaceChild(GraphicsLayer* oldChild, GraphicsLayer* newChild) { if (GraphicsLayer::replaceChild(oldChild, newChild)) { - notifyChange(TextureMapperLayer::ChildrenChange); + notifyChange(ChildrenChange); return true; } return false; @@ -182,22 +178,12 @@ bool GraphicsLayerTextureMapper::replaceChild(GraphicsLayer* oldChild, GraphicsL /* \reimp (GraphicsLayer.h) */ -void GraphicsLayerTextureMapper::removeFromParent() -{ - if (!parent()) - return; - notifyChange(TextureMapperLayer::ParentChange); - GraphicsLayer::removeFromParent(); -} - -/* \reimp (GraphicsLayer.h) -*/ void GraphicsLayerTextureMapper::setMaskLayer(GraphicsLayer* value) { if (value == maskLayer()) return; GraphicsLayer::setMaskLayer(value); - notifyChange(TextureMapperLayer::MaskLayerChange); + notifyChange(MaskLayerChange); if (!value) return; @@ -213,7 +199,7 @@ void GraphicsLayerTextureMapper::setReplicatedByLayer(GraphicsLayer* value) if (value == replicaLayer()) return; GraphicsLayer::setReplicatedByLayer(value); - notifyChange(TextureMapperLayer::ReplicaLayerChange); + notifyChange(ReplicaLayerChange); } /* \reimp (GraphicsLayer.h) @@ -223,7 +209,7 @@ void GraphicsLayerTextureMapper::setPosition(const FloatPoint& value) if (value == position()) return; GraphicsLayer::setPosition(value); - notifyChange(TextureMapperLayer::PositionChange); + notifyChange(PositionChange); } /* \reimp (GraphicsLayer.h) @@ -233,7 +219,7 @@ void GraphicsLayerTextureMapper::setAnchorPoint(const FloatPoint3D& value) if (value == anchorPoint()) return; GraphicsLayer::setAnchorPoint(value); - notifyChange(TextureMapperLayer::AnchorPointChange); + notifyChange(AnchorPointChange); } /* \reimp (GraphicsLayer.h) @@ -246,7 +232,7 @@ void GraphicsLayerTextureMapper::setSize(const FloatSize& value) GraphicsLayer::setSize(value); if (maskLayer()) maskLayer()->setSize(value); - notifyChange(TextureMapperLayer::SizeChange); + notifyChange(SizeChange); } /* \reimp (GraphicsLayer.h) @@ -257,7 +243,7 @@ void GraphicsLayerTextureMapper::setTransform(const TransformationMatrix& value) return; GraphicsLayer::setTransform(value); - notifyChange(TextureMapperLayer::TransformChange); + notifyChange(TransformChange); } /* \reimp (GraphicsLayer.h) @@ -267,7 +253,7 @@ void GraphicsLayerTextureMapper::setChildrenTransform(const TransformationMatrix if (value == childrenTransform()) return; GraphicsLayer::setChildrenTransform(value); - notifyChange(TextureMapperLayer::ChildrenTransformChange); + notifyChange(ChildrenTransformChange); } /* \reimp (GraphicsLayer.h) @@ -277,7 +263,7 @@ void GraphicsLayerTextureMapper::setPreserves3D(bool value) if (value == preserves3D()) return; GraphicsLayer::setPreserves3D(value); - notifyChange(TextureMapperLayer::Preserves3DChange); + notifyChange(Preserves3DChange); } /* \reimp (GraphicsLayer.h) @@ -287,7 +273,7 @@ void GraphicsLayerTextureMapper::setMasksToBounds(bool value) if (value == masksToBounds()) return; GraphicsLayer::setMasksToBounds(value); - notifyChange(TextureMapperLayer::MasksToBoundsChange); + notifyChange(MasksToBoundsChange); } /* \reimp (GraphicsLayer.h) @@ -296,8 +282,11 @@ void GraphicsLayerTextureMapper::setDrawsContent(bool value) { if (value == drawsContent()) return; - notifyChange(TextureMapperLayer::DrawsContentChange); GraphicsLayer::setDrawsContent(value); + notifyChange(DrawsContentChange); + + if (value) + setNeedsDisplay(); } /* \reimp (GraphicsLayer.h) @@ -306,7 +295,7 @@ void GraphicsLayerTextureMapper::setContentsVisible(bool value) { if (value == contentsAreVisible()) return; - notifyChange(TextureMapperLayer::ContentsVisibleChange); + notifyChange(ContentsVisibleChange); GraphicsLayer::setContentsVisible(value); if (maskLayer()) maskLayer()->setContentsVisible(value); @@ -318,7 +307,7 @@ void GraphicsLayerTextureMapper::setContentsOpaque(bool value) { if (value == contentsOpaque()) return; - notifyChange(TextureMapperLayer::ContentsOpaqueChange); + notifyChange(ContentsOpaqueChange); GraphicsLayer::setContentsOpaque(value); } @@ -329,7 +318,7 @@ void GraphicsLayerTextureMapper::setBackfaceVisibility(bool value) if (value == backfaceVisibility()) return; GraphicsLayer::setBackfaceVisibility(value); - notifyChange(TextureMapperLayer::BackfaceVisibilityChange); + notifyChange(BackfaceVisibilityChange); } /* \reimp (GraphicsLayer.h) @@ -339,7 +328,7 @@ void GraphicsLayerTextureMapper::setOpacity(float value) if (value == opacity()) return; GraphicsLayer::setOpacity(value); - notifyChange(TextureMapperLayer::OpacityChange); + notifyChange(OpacityChange); } /* \reimp (GraphicsLayer.h) @@ -349,9 +338,19 @@ void GraphicsLayerTextureMapper::setContentsRect(const IntRect& value) if (value == contentsRect()) return; GraphicsLayer::setContentsRect(value); - notifyChange(TextureMapperLayer::ContentsRectChange); + notifyChange(ContentsRectChange); } +void GraphicsLayerTextureMapper::setContentsToSolidColor(const Color& color) +{ + if (color == m_solidColor) + return; + + m_solidColor = color; + notifyChange(BackgroundColorChange); +} + + /* \reimp (GraphicsLayer.h) */ void GraphicsLayerTextureMapper::setContentsToImage(Image* image) @@ -377,7 +376,7 @@ void GraphicsLayerTextureMapper::setContentsToImage(Image* image) } setContentsToMedia(m_compositedImage.get()); - notifyChange(TextureMapperLayer::ContentChange); + notifyChange(ContentChange); GraphicsLayer::setContentsToImage(image); } @@ -387,62 +386,227 @@ void GraphicsLayerTextureMapper::setContentsToMedia(TextureMapperPlatformLayer* return; GraphicsLayer::setContentsToMedia(media); - notifyChange(TextureMapperLayer::ContentChange); + notifyChange(ContentChange); + + if (m_contentsLayer) + m_contentsLayer->setClient(0); + m_contentsLayer = media; + + if (m_contentsLayer) + m_contentsLayer->setClient(this); +} + +void GraphicsLayerTextureMapper::setShowDebugBorder(bool show) +{ + if (isShowingDebugBorder() == show) + return; + + GraphicsLayer::setShowDebugBorder(show); + notifyChange(DebugVisualsChange); +} + +void GraphicsLayerTextureMapper::setShowRepaintCounter(bool show) +{ + if (isShowingRepaintCounter() == show) + return; + + GraphicsLayer::setShowRepaintCounter(show); + notifyChange(DebugVisualsChange); +} + +void GraphicsLayerTextureMapper::didCommitScrollOffset(const IntSize& offset) +{ + if (offset.isZero()) + return; + + m_committedScrollOffset = offset; + notifyChange(CommittedScrollOffsetChange); +} + +void GraphicsLayerTextureMapper::setIsScrollable(bool isScrollable) +{ + if (m_isScrollable == isScrollable) + return; + + m_isScrollable = isScrollable; + notifyChange(IsScrollableChange); } /* \reimp (GraphicsLayer.h) */ void GraphicsLayerTextureMapper::flushCompositingStateForThisLayerOnly() { - m_layer->flushCompositingState(this); - didFlushCompositingState(); + prepareBackingStoreIfNeeded(); + commitLayerChanges(); + m_layer->syncAnimations(); + updateBackingStoreIfNeeded(); } -/* \reimp (GraphicsLayer.h) -*/ -void GraphicsLayerTextureMapper::flushCompositingState(const FloatRect&) +void GraphicsLayerTextureMapper::prepareBackingStoreIfNeeded() { - m_layer->flushCompositingState(this, TextureMapperLayer::TraverseDescendants); - didFlushCompositingStateRecursive(); + if (!shouldHaveBackingStore()) { + m_backingStore.clear(); + m_changeMask |= BackingStoreChange; + } else { + if (!m_backingStore) { + m_backingStore = TextureMapperTiledBackingStore::create(); + m_changeMask |= BackingStoreChange; + } + } + + updateDebugBorderAndRepaintCount(); } -void GraphicsLayerTextureMapper::didFlushCompositingState() +void GraphicsLayerTextureMapper::updateDebugBorderAndRepaintCount() { - updateBackingStore(); - m_changeMask = 0; + if (isShowingDebugBorder()) + updateDebugIndicators(); + + // When this has its own backing store (e.g. Qt WK1), update the repaint count before calling TextureMapperLayer::flushCompositingStateForThisLayerOnly(). + bool needsToRepaint = shouldHaveBackingStore() && (m_needsDisplay || !m_needsDisplayRect.isEmpty()); + if (isShowingRepaintCounter() && needsToRepaint) { + incrementRepaintCount(); + m_changeMask |= RepaintCountChange; + } } -void GraphicsLayerTextureMapper::didFlushCompositingStateRecursive() +void GraphicsLayerTextureMapper::setDebugBorder(const Color& color, float width) { - didFlushCompositingState(); - for (size_t i = 0; i < children().size(); ++i) - toGraphicsLayerTextureMapper(children()[i])->didFlushCompositingStateRecursive(); - if (maskLayer()) - toGraphicsLayerTextureMapper(maskLayer())->didFlushCompositingStateRecursive(); - if (replicaLayer()) - toGraphicsLayerTextureMapper(replicaLayer())->didFlushCompositingStateRecursive(); + m_debugBorderColor = color; + m_debugBorderWidth = width; + m_changeMask |= DebugVisualsChange; +} + +static void toTextureMapperLayerVector(const Vector<GraphicsLayer*>& layers, Vector<TextureMapperLayer*>& texmapLayers) +{ + texmapLayers.reserveCapacity(layers.size()); + for (size_t i = 0; i < layers.size(); ++i) + texmapLayers.append(toTextureMapperLayer(layers[i])); } -void GraphicsLayerTextureMapper::updateBackingStore() +void GraphicsLayerTextureMapper::commitLayerChanges() { - if (!m_hasOwnBackingStore) + if (m_changeMask == NoChanges) return; - prepareBackingStore(); - m_layer->setBackingStore(m_backingStore); + if (m_changeMask & ChildrenChange) { + Vector<TextureMapperLayer*> textureMapperLayerChildren; + toTextureMapperLayerVector(children(), textureMapperLayerChildren); + m_layer->setChildren(textureMapperLayerChildren); + } + + if (m_changeMask & MaskLayerChange) + m_layer->setMaskLayer(toTextureMapperLayer(maskLayer())); + + if (m_changeMask & ReplicaLayerChange) + m_layer->setReplicaLayer(toTextureMapperLayer(replicaLayer())); + + if (m_changeMask & PositionChange) + m_layer->setPosition(position()); + + if (m_changeMask & AnchorPointChange) + m_layer->setAnchorPoint(anchorPoint()); + + if (m_changeMask & SizeChange) + m_layer->setSize(size()); + + if (m_changeMask & TransformChange) + m_layer->setTransform(transform()); + + if (m_changeMask & ChildrenTransformChange) + m_layer->setChildrenTransform(childrenTransform()); + + if (m_changeMask & Preserves3DChange) + m_layer->setPreserves3D(preserves3D()); + + if (m_changeMask & ContentsRectChange) + m_layer->setContentsRect(contentsRect()); + + if (m_changeMask & MasksToBoundsChange) + m_layer->setMasksToBounds(masksToBounds()); + + if (m_changeMask & DrawsContentChange) + m_layer->setDrawsContent(drawsContent()); + + if (m_changeMask & ContentsVisibleChange) + m_layer->setContentsVisible(contentsAreVisible()); + + if (m_changeMask & ContentsOpaqueChange) + m_layer->setContentsOpaque(contentsOpaque()); + + if (m_changeMask & BackfaceVisibilityChange) + m_layer->setBackfaceVisibility(backfaceVisibility()); + + if (m_changeMask & OpacityChange) + m_layer->setOpacity(opacity()); + + if (m_changeMask & BackgroundColorChange) + m_layer->setSolidColor(solidColor()); + +#if ENABLE(CSS_FILTERS) + if (m_changeMask & FilterChange) + m_layer->setFilters(filters()); +#endif + + if (m_changeMask & BackingStoreChange) + m_layer->setBackingStore(m_backingStore); + + if (m_changeMask & DebugVisualsChange) + m_layer->setDebugVisuals(isShowingDebugBorder(), debugBorderColor(), debugBorderWidth(), isShowingRepaintCounter()); + + if (m_changeMask & RepaintCountChange) + m_layer->setRepaintCount(repaintCount()); + + if (m_changeMask & ContentChange) + m_layer->setContentsLayer(platformLayer()); + + if (m_changeMask & AnimationChange) + m_layer->setAnimations(m_animations); + + if (m_changeMask & AnimationStarted) + client()->notifyAnimationStarted(this, m_animationStartTime); + + if (m_changeMask & FixedToViewporChange) + m_layer->setFixedToViewport(fixedToViewport()); + + if (m_changeMask & IsScrollableChange) + m_layer->setIsScrollable(isScrollable()); + + if (m_changeMask & CommittedScrollOffsetChange) + m_layer->didCommitScrollOffset(m_committedScrollOffset); + + m_changeMask = NoChanges; +} + +/* \reimp (GraphicsLayer.h) +*/ +void GraphicsLayerTextureMapper::flushCompositingState(const FloatRect& rect) +{ + if (!m_layer->textureMapper()) + return; + + flushCompositingStateForThisLayerOnly(); + + if (maskLayer()) + maskLayer()->flushCompositingState(rect); + if (replicaLayer()) + replicaLayer()->flushCompositingState(rect); + for (size_t i = 0; i < children().size(); ++i) + children()[i]->flushCompositingState(rect); } -void GraphicsLayerTextureMapper::prepareBackingStore() +void GraphicsLayerTextureMapper::updateBackingStoreIfNeeded() { TextureMapper* textureMapper = m_layer->textureMapper(); if (!textureMapper) return; if (!shouldHaveBackingStore()) { - m_backingStore.clear(); + ASSERT(!m_backingStore); return; } + ASSERT(m_backingStore); IntRect dirtyRect = enclosingIntRect(FloatRect(FloatPoint::zero(), m_size)); if (!m_needsDisplay) @@ -450,42 +614,12 @@ void GraphicsLayerTextureMapper::prepareBackingStore() if (dirtyRect.isEmpty()) return; - if (!m_backingStore) - m_backingStore = TextureMapperTiledBackingStore::create(); - -#ifndef QT_NO_DYNAMIC_CAST +#if PLATFORM(QT) && !defined(QT_NO_DYNAMIC_CAST) ASSERT(dynamic_cast<TextureMapperTiledBackingStore*>(m_backingStore.get())); #endif TextureMapperTiledBackingStore* backingStore = static_cast<TextureMapperTiledBackingStore*>(m_backingStore.get()); - if (isShowingRepaintCounter()) - incrementRepaintCount(); - - // Paint into an intermediate buffer to avoid painting content more than once. - bool paintOnce = true; - const IntSize maxTextureSize = textureMapper->maxTextureSize(); - // We need to paint directly if the dirty rect exceeds one of the maximum dimensions. - if (dirtyRect.width() > maxTextureSize.width() || dirtyRect.height() > maxTextureSize.height()) - paintOnce = false; - - if (paintOnce) { - OwnPtr<ImageBuffer> imageBuffer = ImageBuffer::create(dirtyRect.size()); - GraphicsContext* context = imageBuffer->context(); - context->setImageInterpolationQuality(textureMapper->imageInterpolationQuality()); - context->setTextDrawingMode(textureMapper->textDrawingMode()); - context->translate(-dirtyRect.x(), -dirtyRect.y()); - paintGraphicsLayerContents(*context, dirtyRect); - - if (isShowingRepaintCounter()) - drawRepaintCounter(context); - - RefPtr<Image> image = imageBuffer->copyImage(DontCopyBackingStore); - backingStore->updateContents(textureMapper, image.get(), m_size, dirtyRect, BitmapTexture::UpdateCanModifyOriginalImageData); - } else - backingStore->updateContents(textureMapper, this, m_size, dirtyRect, BitmapTexture::UpdateCanModifyOriginalImageData); - - backingStore->setShowDebugBorders(isShowingDebugBorder()); - backingStore->setDebugBorder(m_debugBorderColor, m_debugBorderWidth); + backingStore->updateContents(textureMapper, this, m_size, dirtyRect, BitmapTexture::UpdateCanModifyOriginalImageData); m_needsDisplay = false; m_needsDisplayRect = IntRect(); @@ -496,40 +630,6 @@ bool GraphicsLayerTextureMapper::shouldHaveBackingStore() const return drawsContent() && contentsAreVisible() && !m_size.isEmpty(); } -#if USE(CAIRO) -void GraphicsLayerTextureMapper::drawRepaintCounter(GraphicsContext* context) -{ - cairo_t* cr = context->platformContext()->cr(); - cairo_save(cr); - - CString repaintCount = String::format("%i", this->repaintCount()).utf8(); - cairo_select_font_face(cr, "sans-serif", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD); - cairo_set_font_size(cr, 18); - - cairo_text_extents_t repaintTextExtents; - cairo_text_extents(cr, repaintCount.data(), &repaintTextExtents); - - static const int repaintCountBorderWidth = 10; - setSourceRGBAFromColor(cr, isShowingDebugBorder() ? m_debugBorderColor : Color(0, 255, 0, 127)); - cairo_rectangle(cr, 0, 0, - repaintTextExtents.width + (repaintCountBorderWidth * 2), - repaintTextExtents.height + (repaintCountBorderWidth * 2)); - cairo_fill(cr); - - cairo_set_source_rgb(cr, 1, 1, 1); - cairo_move_to(cr, repaintCountBorderWidth, repaintTextExtents.height + repaintCountBorderWidth); - cairo_show_text(cr, repaintCount.data()); - - cairo_restore(cr); -} -#else -void GraphicsLayerTextureMapper::drawRepaintCounter(GraphicsContext* context) -{ - notImplemented(); -} - -#endif - bool GraphicsLayerTextureMapper::addAnimation(const KeyframeValueList& valueList, const IntSize& boxSize, const Animation* anim, const String& keyframesName, double timeOffset) { ASSERT(!keyframesName.isEmpty()); @@ -550,15 +650,15 @@ bool GraphicsLayerTextureMapper::addAnimation(const KeyframeValueList& valueList m_animationStartTime = currentTime; else m_animationStartTime = currentTime - timeOffset; - notifyChange(TextureMapperLayer::AnimationChange); - m_animationStartedTimer.startOneShot(0); + notifyChange(AnimationChange); + notifyChange(AnimationStarted); return true; } void GraphicsLayerTextureMapper::setAnimations(const GraphicsLayerAnimations& animations) { m_animations = animations; - notifyChange(TextureMapperLayer::AnimationChange); + notifyChange(AnimationChange); } @@ -572,25 +672,28 @@ void GraphicsLayerTextureMapper::removeAnimation(const String& animationName) m_animations.remove(animationName); } -void GraphicsLayerTextureMapper::animationStartedTimerFired(Timer<GraphicsLayerTextureMapper>*) +#if ENABLE(CSS_FILTERS) +bool GraphicsLayerTextureMapper::setFilters(const FilterOperations& filters) { - client()->notifyAnimationStarted(this, m_animationStartTime); + notifyChange(FilterChange); + return GraphicsLayer::setFilters(filters); } +#endif -void GraphicsLayerTextureMapper::setDebugBorder(const Color& color, float width) +void GraphicsLayerTextureMapper::setFixedToViewport(bool fixed) { - // The default values for GraphicsLayer debug borders are a little - // hard to see (some less than one pixel wide), so we double their size here. - m_debugBorderColor = color; - m_debugBorderWidth = width * 2; + if (m_fixedToViewport == fixed) + return; + + m_fixedToViewport = fixed; + notifyChange(FixedToViewporChange); } -#if ENABLE(CSS_FILTERS) -bool GraphicsLayerTextureMapper::setFilters(const FilterOperations& filters) +void GraphicsLayerTextureMapper::setRepaintCount(int repaintCount) { - notifyChange(TextureMapperLayer::FilterChange); - return GraphicsLayer::setFilters(filters); + m_repaintCount = repaintCount; + notifyChange(RepaintCountChange); } -#endif } +#endif diff --git a/Source/WebCore/platform/graphics/texmap/GraphicsLayerTextureMapper.h b/Source/WebCore/platform/graphics/texmap/GraphicsLayerTextureMapper.h index 00b0fe7c1..61ddfb92a 100644 --- a/Source/WebCore/platform/graphics/texmap/GraphicsLayerTextureMapper.h +++ b/Source/WebCore/platform/graphics/texmap/GraphicsLayerTextureMapper.h @@ -20,36 +20,36 @@ #ifndef GraphicsLayerTextureMapper_h #define GraphicsLayerTextureMapper_h -#include "GraphicsContext.h" +#if USE(TEXTURE_MAPPER) + #include "GraphicsLayer.h" #include "GraphicsLayerClient.h" #include "Image.h" #include "TextureMapperLayer.h" +#include "TextureMapperPlatformLayer.h" +#include "TextureMapperTiledBackingStore.h" #include "Timer.h" namespace WebCore { -class TextureMapper; - -class GraphicsLayerTextureMapper : public GraphicsLayer { - friend class TextureMapperLayer; - +class GraphicsLayerTextureMapper : public GraphicsLayer, public TextureMapperPlatformLayer::Client { public: explicit GraphicsLayerTextureMapper(GraphicsLayerClient*); virtual ~GraphicsLayerTextureMapper(); + void setScrollClient(TextureMapperLayer::ScrollingClient* client) { m_layer->setScrollClient(client); } + void setID(uint32_t id) { m_layer->setID(id); } + // reimps from GraphicsLayer.h virtual void setNeedsDisplay(); virtual void setContentsNeedsDisplay(); virtual void setNeedsDisplayInRect(const FloatRect&); - virtual void setParent(GraphicsLayer* layer); virtual bool setChildren(const Vector<GraphicsLayer*>&); virtual void addChild(GraphicsLayer*); virtual void addChildAtIndex(GraphicsLayer*, int index); virtual void addChildAbove(GraphicsLayer* layer, GraphicsLayer* sibling); virtual void addChildBelow(GraphicsLayer* layer, GraphicsLayer* sibling); virtual bool replaceChild(GraphicsLayer* oldChild, GraphicsLayer* newChild); - virtual void removeFromParent(); virtual void setMaskLayer(GraphicsLayer* layer); virtual void setPosition(const FloatPoint& p); virtual void setAnchorPoint(const FloatPoint3D& p); @@ -66,14 +66,19 @@ public: virtual void setContentsRect(const IntRect& r); virtual void setReplicatedByLayer(GraphicsLayer*); virtual void setContentsToImage(Image*); + virtual void setContentsToSolidColor(const Color&); + Color solidColor() const { return m_solidColor; } virtual void setContentsToMedia(PlatformLayer*); virtual void setContentsToCanvas(PlatformLayer* canvas) { setContentsToMedia(canvas); } + virtual void setShowDebugBorder(bool) OVERRIDE; + virtual void setDebugBorder(const Color&, float width) OVERRIDE; + virtual void setShowRepaintCounter(bool) OVERRIDE; virtual void flushCompositingState(const FloatRect&); virtual void flushCompositingStateForThisLayerOnly(); virtual void setName(const String& name); + virtual bool hasContentsLayer() const { return m_contentsLayer; } virtual PlatformLayer* platformLayer() const { return m_contentsLayer; } - void notifyChange(TextureMapperLayer::ChangeMask); inline int changeMask() const { return m_changeMask; } virtual bool addAnimation(const KeyframeValueList&, const IntSize&, const Animation*, const String&, double); @@ -83,27 +88,76 @@ public: TextureMapperLayer* layer() const { return m_layer.get(); } - virtual void setDebugBorder(const Color&, float width); + void didCommitScrollOffset(const IntSize&); + void setIsScrollable(bool); + bool isScrollable() const { return m_isScrollable; } #if ENABLE(CSS_FILTERS) virtual bool setFilters(const FilterOperations&); #endif - // FIXME: It will be removed after removing dependency of LayerTreeRenderer on GraphicsLayerTextureMapper. - void setHasOwnBackingStore(bool b) { m_hasOwnBackingStore = b; } - - void setFixedToViewport(bool fixed) { m_fixedToViewport = fixed; } + void setFixedToViewport(bool); bool fixedToViewport() const { return m_fixedToViewport; } - void drawRepaintCounter(GraphicsContext*); + Color debugBorderColor() const { return m_debugBorderColor; } + float debugBorderWidth() const { return m_debugBorderWidth; } + void setRepaintCount(int); + private: virtual void willBeDestroyed(); - void didFlushCompositingState(); - void didFlushCompositingStateRecursive(); - void updateBackingStore(); - void prepareBackingStore(); + + void commitLayerChanges(); + void updateDebugBorderAndRepaintCount(); + void updateBackingStoreIfNeeded(); + void prepareBackingStoreIfNeeded(); bool shouldHaveBackingStore() const; - void animationStartedTimerFired(Timer<GraphicsLayerTextureMapper>*); + + virtual void setPlatformLayerNeedsDisplay() OVERRIDE { setContentsNeedsDisplay(); } + + // This set of flags help us defer which properties of the layer have been + // modified by the compositor, so we can know what to look for in the next flush. + enum ChangeMask { + NoChanges = 0, + + ChildrenChange = (1L << 1), + MaskLayerChange = (1L << 2), + ReplicaLayerChange = (1L << 3), + + ContentChange = (1L << 4), + ContentsRectChange = (1L << 5), + ContentsVisibleChange = (1L << 6), + ContentsOpaqueChange = (1L << 7), + + PositionChange = (1L << 8), + AnchorPointChange = (1L << 9), + SizeChange = (1L << 10), + TransformChange = (1L << 11), + ChildrenTransformChange = (1L << 12), + Preserves3DChange = (1L << 13), + + MasksToBoundsChange = (1L << 14), + DrawsContentChange = (1L << 15), + OpacityChange = (1L << 16), + BackfaceVisibilityChange = (1L << 17), + + BackingStoreChange = (1L << 18), + DisplayChange = (1L << 19), + ContentsDisplayChange = (1L << 20), + BackgroundColorChange = (1L << 21), + + AnimationChange = (1L << 22), + FilterChange = (1L << 23), + + DebugVisualsChange = (1L << 24), + RepaintCountChange = (1L << 25), + + FixedToViewporChange = (1L << 26), + AnimationStarted = (1L << 27), + + CommittedScrollOffsetChange = (1L << 28), + IsScrollableChange = (1L << 29) + }; + void notifyChange(ChangeMask); OwnPtr<TextureMapperLayer> m_layer; RefPtr<TextureMapperTiledBackingStore> m_compositedImage; @@ -114,6 +168,7 @@ private: bool m_needsDisplay; bool m_hasOwnBackingStore; bool m_fixedToViewport; + Color m_solidColor; Color m_debugBorderColor; float m_debugBorderWidth; @@ -121,8 +176,10 @@ private: TextureMapperPlatformLayer* m_contentsLayer; FloatRect m_needsDisplayRect; GraphicsLayerAnimations m_animations; - Timer<GraphicsLayerTextureMapper> m_animationStartedTimer; double m_animationStartTime; + + IntSize m_committedScrollOffset; + bool m_isScrollable; }; inline static GraphicsLayerTextureMapper* toGraphicsLayerTextureMapper(GraphicsLayer* layer) @@ -130,5 +187,9 @@ inline static GraphicsLayerTextureMapper* toGraphicsLayerTextureMapper(GraphicsL return static_cast<GraphicsLayerTextureMapper*>(layer); } +TextureMapperLayer* toTextureMapperLayer(GraphicsLayer*); + } +#endif + #endif // GraphicsLayerTextureMapper_h diff --git a/Source/WebCore/platform/graphics/texmap/TextureMapper.cpp b/Source/WebCore/platform/graphics/texmap/TextureMapper.cpp index 43fec543c..12b04ba42 100644 --- a/Source/WebCore/platform/graphics/texmap/TextureMapper.cpp +++ b/Source/WebCore/platform/graphics/texmap/TextureMapper.cpp @@ -20,6 +20,7 @@ #include "config.h" #include "TextureMapper.h" +#include "FilterOperations.h" #include "GraphicsLayer.h" #include "TextureMapperImageBuffer.h" #include "Timer.h" @@ -136,10 +137,13 @@ PassOwnPtr<TextureMapper> TextureMapper::create(AccelerationMode mode) } TextureMapper::TextureMapper(AccelerationMode accelerationMode) - : m_interpolationQuality(InterpolationDefault) + : m_context(0) + , m_interpolationQuality(InterpolationDefault) , m_textDrawingMode(TextModeFill) , m_texturePool(adoptPtr(new BitmapTexturePool())) , m_accelerationMode(accelerationMode) + , m_isMaskMode(false) + , m_wrapMode(StretchWrap) { } TextureMapper::~TextureMapper() diff --git a/Source/WebCore/platform/graphics/texmap/TextureMapper.h b/Source/WebCore/platform/graphics/texmap/TextureMapper.h index 22efd5ff7..6ec675794 100644 --- a/Source/WebCore/platform/graphics/texmap/TextureMapper.h +++ b/Source/WebCore/platform/graphics/texmap/TextureMapper.h @@ -20,7 +20,7 @@ #ifndef TextureMapper_h #define TextureMapper_h -#if USE(ACCELERATED_COMPOSITING) +#if USE(ACCELERATED_COMPOSITING) && USE(TEXTURE_MAPPER) #if PLATFORM(QT) #include <qglobal.h> @@ -28,17 +28,14 @@ #define TEXMAP_OPENGL_ES_2 #endif #endif -#if PLATFORM(GTK) && USE(OPENGL_ES_2) +#if (PLATFORM(GTK) || PLATFORM(EFL)) && USE(OPENGL_ES_2) #define TEXMAP_OPENGL_ES_2 #endif -#include "FilterOperations.h" #include "GraphicsContext.h" #include "IntRect.h" #include "IntSize.h" -#include "TextureMapperPlatformLayer.h" #include "TransformationMatrix.h" -#include <wtf/UnusedParam.h> /* TextureMapper is a mechanism that enables hardware acceleration of CSS animations (accelerated compositing) without @@ -51,6 +48,7 @@ class BitmapTexturePool; class CustomFilterProgram; class GraphicsLayer; class TextureMapper; +class FilterOperations; // A 2D texture that can be the target of software or GL rendering. class BitmapTexture : public RefCounted<BitmapTexture> { @@ -96,7 +94,7 @@ public: inline bool isOpaque() const { return !(m_flags & SupportsAlpha); } #if ENABLE(CSS_FILTERS) - virtual PassRefPtr<BitmapTexture> applyFilters(TextureMapper*, const BitmapTexture& contentTexture, const FilterOperations&) { return this; } + virtual PassRefPtr<BitmapTexture> applyFilters(TextureMapper*, const FilterOperations&) { return this; } #endif protected: @@ -116,6 +114,12 @@ public: enum PaintFlag { PaintingMirrored = 1 << 0, }; + + enum WrapMode { + StretchWrap, + RepeatWrap + }; + typedef unsigned PaintFlags; static PassOwnPtr<TextureMapper> create(AccelerationMode newMode = SoftwareMode); @@ -130,17 +134,19 @@ public: AllEdges = LeftEdge | RightEdge | TopEdge | BottomEdge, }; - virtual void drawBorder(const Color&, float borderWidth, const FloatRect& targetRect, const TransformationMatrix& modelViewMatrix = TransformationMatrix()) = 0; - virtual void drawRepaintCounter(int value, int pointSize, const FloatPoint&, const TransformationMatrix& modelViewMatrix = TransformationMatrix()) = 0; - virtual void drawTexture(const BitmapTexture&, const FloatRect& target, const TransformationMatrix& modelViewMatrix = TransformationMatrix(), float opacity = 1.0f, const BitmapTexture* maskTexture = 0, unsigned exposedEdges = AllEdges) = 0; + virtual void drawBorder(const Color&, float borderWidth, const FloatRect&, const TransformationMatrix&) = 0; + virtual void drawNumber(int number, const Color&, const FloatPoint&, const TransformationMatrix&) = 0; + + virtual void drawTexture(const BitmapTexture&, const FloatRect& target, const TransformationMatrix& modelViewMatrix = TransformationMatrix(), float opacity = 1.0f, unsigned exposedEdges = AllEdges) = 0; virtual void drawSolidColor(const FloatRect&, const TransformationMatrix&, const Color&) = 0; // makes a surface the target for the following drawTexture calls. virtual void bindSurface(BitmapTexture* surface) = 0; - virtual void setGraphicsContext(GraphicsContext* context) { m_context = context; } - virtual GraphicsContext* graphicsContext() { return m_context; } + void setGraphicsContext(GraphicsContext* context) { m_context = context; } + GraphicsContext* graphicsContext() { return m_context; } virtual void beginClip(const TransformationMatrix&, const FloatRect&) = 0; virtual void endClip() = 0; + virtual IntRect clipBounds() = 0; virtual PassRefPtr<BitmapTexture> createTexture() = 0; void setImageInterpolationQuality(InterpolationQuality quality) { m_interpolationQuality = quality; } @@ -153,6 +159,8 @@ public: virtual void beginPainting(PaintFlags = 0) { } virtual void endPainting() { } + void setMaskMode(bool m) { m_isMaskMode = m; } + virtual IntSize maxTextureSize() const = 0; virtual PassRefPtr<BitmapTexture> acquireTextureFromPool(const IntSize&); @@ -161,9 +169,18 @@ public: virtual void removeCachedCustomFilterProgram(CustomFilterProgram*) { } #endif + void setPatternTransform(const TransformationMatrix& p) { m_patternTransform = p; } + void setWrapMode(WrapMode m) { m_wrapMode = m; } + protected: explicit TextureMapper(AccelerationMode); + GraphicsContext* m_context; + + bool isInMaskMode() const { return m_isMaskMode; } + WrapMode wrapMode() const { return m_wrapMode; } + const TransformationMatrix& patternTransform() const { return m_patternTransform; } + private: #if USE(TEXTURE_MAPPER_GL) static PassOwnPtr<TextureMapper> platformCreateAccelerated(); @@ -176,8 +193,10 @@ private: InterpolationQuality m_interpolationQuality; TextDrawingModeFlags m_textDrawingMode; OwnPtr<BitmapTexturePool> m_texturePool; - GraphicsContext* m_context; AccelerationMode m_accelerationMode; + bool m_isMaskMode; + TransformationMatrix m_patternTransform; + WrapMode m_wrapMode; }; } diff --git a/Source/WebCore/platform/graphics/texmap/TextureMapperBackingStore.cpp b/Source/WebCore/platform/graphics/texmap/TextureMapperBackingStore.cpp index 788bb12a1..e68bc0914 100644 --- a/Source/WebCore/platform/graphics/texmap/TextureMapperBackingStore.cpp +++ b/Source/WebCore/platform/graphics/texmap/TextureMapperBackingStore.cpp @@ -19,7 +19,7 @@ #include "config.h" -#if USE(ACCELERATED_COMPOSITING) +#if USE(ACCELERATED_COMPOSITING) && USE(TEXTURE_MAPPER) #include "TextureMapperBackingStore.h" #include "GraphicsLayer.h" @@ -33,92 +33,6 @@ namespace WebCore { -#if USE(GRAPHICS_SURFACE) -void TextureMapperSurfaceBackingStore::setGraphicsSurface(PassRefPtr<GraphicsSurface> surface) -{ - m_graphicsSurface = surface; -} - -void TextureMapperSurfaceBackingStore::swapBuffersIfNeeded(uint32_t frontBuffer) -{ - if (m_graphicsSurface && m_graphicsSurface->frontBuffer() != frontBuffer) - m_graphicsSurface->swapBuffers(); -} - -PassRefPtr<BitmapTexture> TextureMapperSurfaceBackingStore::texture() const -{ - // FIXME: Instead of just returning an empty texture, we should wrap the texture contents into a BitmapTexture. - RefPtr<BitmapTexture> emptyTexture; - return emptyTexture; -} - -void TextureMapperSurfaceBackingStore::paintToTextureMapper(TextureMapper* textureMapper, const FloatRect& targetRect, const TransformationMatrix& transform, float opacity, BitmapTexture* mask) -{ - if (m_graphicsSurface) - m_graphicsSurface->paintToTextureMapper(textureMapper, targetRect, transform, opacity, mask); -} -#endif - -void TextureMapperTile::updateContents(TextureMapper* textureMapper, Image* image, const IntRect& dirtyRect, BitmapTexture::UpdateContentsFlag updateContentsFlag) -{ - IntRect targetRect = enclosingIntRect(m_rect); - targetRect.intersect(dirtyRect); - if (targetRect.isEmpty()) - return; - IntPoint sourceOffset = targetRect.location(); - - // Normalize sourceRect to the buffer's coordinates. - sourceOffset.move(-dirtyRect.x(), -dirtyRect.y()); - - // Normalize targetRect to the texture's coordinates. - targetRect.move(-m_rect.x(), -m_rect.y()); - if (!m_texture) { - m_texture = textureMapper->createTexture(); - m_texture->reset(targetRect.size(), image->currentFrameHasAlpha() ? BitmapTexture::SupportsAlpha : 0); - } - - m_texture->updateContents(image, targetRect, sourceOffset, updateContentsFlag); -} - -void TextureMapperTile::updateContents(TextureMapper* textureMapper, GraphicsLayer* sourceLayer, const IntRect& dirtyRect, BitmapTexture::UpdateContentsFlag updateContentsFlag) -{ - IntRect targetRect = enclosingIntRect(m_rect); - targetRect.intersect(dirtyRect); - if (targetRect.isEmpty()) - return; - IntPoint sourceOffset = targetRect.location(); - - // Normalize targetRect to the texture's coordinates. - targetRect.move(-m_rect.x(), -m_rect.y()); - - if (!m_texture) { - m_texture = textureMapper->createTexture(); - m_texture->reset(targetRect.size(), BitmapTexture::SupportsAlpha); - } - - m_texture->updateContents(textureMapper, sourceLayer, targetRect, sourceOffset, updateContentsFlag); -} - -void TextureMapperTile::paint(TextureMapper* textureMapper, const TransformationMatrix& transform, float opacity, BitmapTexture* mask, const unsigned exposedEdges) -{ - if (texture().get()) - textureMapper->drawTexture(*texture().get(), rect(), transform, opacity, mask, exposedEdges); -} - -TextureMapperTiledBackingStore::TextureMapperTiledBackingStore() - : m_drawsDebugBorders(false) -{ -} - -void TextureMapperTiledBackingStore::updateContentsFromImageIfNeeded(TextureMapper* textureMapper) -{ - if (!m_image) - return; - - updateContents(textureMapper, m_image.get(), m_image->size(), m_image->rect(), BitmapTexture::UpdateCannotModifyOriginalImageData); - m_image.clear(); -} - unsigned TextureMapperBackingStore::calculateExposedTileEdges(const FloatRect& totalRect, const FloatRect& tileRect) { unsigned exposedEdges = TextureMapper::NoEdges; @@ -133,112 +47,5 @@ unsigned TextureMapperBackingStore::calculateExposedTileEdges(const FloatRect& t return exposedEdges; } -void TextureMapperTiledBackingStore::paintToTextureMapper(TextureMapper* textureMapper, const FloatRect& targetRect, const TransformationMatrix& transform, float opacity, BitmapTexture* mask) -{ - updateContentsFromImageIfNeeded(textureMapper); - TransformationMatrix adjustedTransform = transform; - adjustedTransform.multiply(TransformationMatrix::rectToRect(rect(), targetRect)); - for (size_t i = 0; i < m_tiles.size(); ++i) { - m_tiles[i].paint(textureMapper, adjustedTransform, opacity, mask, calculateExposedTileEdges(rect(), m_tiles[i].rect())); - if (m_drawsDebugBorders) - textureMapper->drawBorder(m_debugBorderColor, m_debugBorderWidth, m_tiles[i].rect(), adjustedTransform); - } -} - -void TextureMapperTiledBackingStore::createOrDestroyTilesIfNeeded(const FloatSize& size, const IntSize& tileSize, bool hasAlpha) -{ - if (size == m_size) - return; - - m_size = size; - - Vector<FloatRect> tileRectsToAdd; - Vector<int> tileIndicesToRemove; - static const size_t TileEraseThreshold = 6; - - // This method recycles tiles. We check which tiles we need to add, which to remove, and use as many - // removable tiles as replacement for new tiles when possible. - for (float y = 0; y < m_size.height(); y += tileSize.height()) { - for (float x = 0; x < m_size.width(); x += tileSize.width()) { - FloatRect tileRect(x, y, tileSize.width(), tileSize.height()); - tileRect.intersect(rect()); - tileRectsToAdd.append(tileRect); - } - } - - // Check which tiles need to be removed, and which already exist. - for (int i = m_tiles.size() - 1; i >= 0; --i) { - FloatRect oldTile = m_tiles[i].rect(); - bool existsAlready = false; - - for (int j = tileRectsToAdd.size() - 1; j >= 0; --j) { - FloatRect newTile = tileRectsToAdd[j]; - if (oldTile != newTile) - continue; - - // A tile that we want to add already exists, no need to add or remove it. - existsAlready = true; - tileRectsToAdd.remove(j); - break; - } - - // This tile is not needed. - if (!existsAlready) - tileIndicesToRemove.append(i); - } - - // Recycle removable tiles to be used for newly requested tiles. - for (size_t i = 0; i < tileRectsToAdd.size(); ++i) { - if (!tileIndicesToRemove.isEmpty()) { - // We recycle an existing tile for usage with a new tile rect. - TextureMapperTile& tile = m_tiles[tileIndicesToRemove.last()]; - tileIndicesToRemove.removeLast(); - tile.setRect(tileRectsToAdd[i]); - - if (tile.texture()) - tile.texture()->reset(enclosingIntRect(tile.rect()).size(), hasAlpha ? BitmapTexture::SupportsAlpha : 0); - continue; - } - - m_tiles.append(TextureMapperTile(tileRectsToAdd[i])); - } - - // Remove unnecessary tiles, if they weren't recycled. - // We use a threshold to make sure we don't create/destroy tiles too eagerly. - for (size_t i = 0; i < tileIndicesToRemove.size() && m_tiles.size() > TileEraseThreshold; ++i) - m_tiles.remove(tileIndicesToRemove[i]); -} - -void TextureMapperTiledBackingStore::updateContents(TextureMapper* textureMapper, Image* image, const FloatSize& totalSize, const IntRect& dirtyRect, BitmapTexture::UpdateContentsFlag updateContentsFlag) -{ - createOrDestroyTilesIfNeeded(totalSize, textureMapper->maxTextureSize(), image->currentFrameHasAlpha()); - for (size_t i = 0; i < m_tiles.size(); ++i) - m_tiles[i].updateContents(textureMapper, image, dirtyRect, updateContentsFlag); -} - -void TextureMapperTiledBackingStore::updateContents(TextureMapper* textureMapper, GraphicsLayer* sourceLayer, const FloatSize& totalSize, const IntRect& dirtyRect, BitmapTexture::UpdateContentsFlag updateContentsFlag) -{ - createOrDestroyTilesIfNeeded(totalSize, textureMapper->maxTextureSize(), true); - for (size_t i = 0; i < m_tiles.size(); ++i) - m_tiles[i].updateContents(textureMapper, sourceLayer, dirtyRect, updateContentsFlag); -} - -PassRefPtr<BitmapTexture> TextureMapperTiledBackingStore::texture() const -{ - for (size_t i = 0; i < m_tiles.size(); ++i) { - RefPtr<BitmapTexture> texture = m_tiles[i].texture(); - if (texture) - return texture; - } - - return PassRefPtr<BitmapTexture>(); -} - -void TextureMapperTiledBackingStore::setDebugBorder(const Color& color, float width) -{ - m_debugBorderColor = color; - m_debugBorderWidth = width; -} - } #endif diff --git a/Source/WebCore/platform/graphics/texmap/TextureMapperBackingStore.h b/Source/WebCore/platform/graphics/texmap/TextureMapperBackingStore.h index 0dd2df4b1..4bae45b4f 100644 --- a/Source/WebCore/platform/graphics/texmap/TextureMapperBackingStore.h +++ b/Source/WebCore/platform/graphics/texmap/TextureMapperBackingStore.h @@ -20,7 +20,7 @@ #ifndef TextureMapperBackingStore_h #define TextureMapperBackingStore_h -#if USE(ACCELERATED_COMPOSITING) +#if USE(ACCELERATED_COMPOSITING) && USE(TEXTURE_MAPPER) #include "FloatRect.h" #include "Image.h" @@ -39,83 +39,14 @@ class GraphicsLayer; class TextureMapperBackingStore : public TextureMapperPlatformLayer, public RefCounted<TextureMapperBackingStore> { public: virtual PassRefPtr<BitmapTexture> texture() const = 0; - virtual void paintToTextureMapper(TextureMapper*, const FloatRect&, const TransformationMatrix&, float, BitmapTexture*) = 0; + virtual void paintToTextureMapper(TextureMapper*, const FloatRect&, const TransformationMatrix&, float) = 0; + virtual void drawRepaintCounter(TextureMapper*, int /* repaintCount */, const Color&, const FloatRect&, const TransformationMatrix&) { } virtual ~TextureMapperBackingStore() { } protected: static unsigned calculateExposedTileEdges(const FloatRect& totalRect, const FloatRect& tileRect); }; -#if USE(GRAPHICS_SURFACE) -class TextureMapperSurfaceBackingStore : public TextureMapperBackingStore { -public: - static PassRefPtr<TextureMapperSurfaceBackingStore> create() { return adoptRef(new TextureMapperSurfaceBackingStore); } - void setGraphicsSurface(PassRefPtr<GraphicsSurface>); - void swapBuffersIfNeeded(uint32_t frontBuffer); - virtual PassRefPtr<BitmapTexture> texture() const; - virtual void paintToTextureMapper(TextureMapper*, const FloatRect&, const TransformationMatrix&, float, BitmapTexture*); - virtual ~TextureMapperSurfaceBackingStore() { } - -private: - TextureMapperSurfaceBackingStore() - : TextureMapperBackingStore() - { } - - RefPtr<GraphicsSurface> m_graphicsSurface; -}; -#endif - -class TextureMapperTile { -public: - inline PassRefPtr<BitmapTexture> texture() const { return m_texture; } - inline FloatRect rect() const { return m_rect; } - inline void setTexture(BitmapTexture* texture) { m_texture = texture; } - inline void setRect(const FloatRect& rect) { m_rect = rect; } - - void updateContents(TextureMapper*, Image*, const IntRect&, BitmapTexture::UpdateContentsFlag UpdateCanModifyOriginalImageData); - void updateContents(TextureMapper*, GraphicsLayer*, const IntRect&, BitmapTexture::UpdateContentsFlag UpdateCanModifyOriginalImageData); - virtual void paint(TextureMapper*, const TransformationMatrix&, float, BitmapTexture*, const unsigned exposedEdges); - virtual ~TextureMapperTile() { } - - explicit TextureMapperTile(const FloatRect& rect) - : m_rect(rect) - { - } - -private: - RefPtr<BitmapTexture> m_texture; - FloatRect m_rect; -}; - -class TextureMapperTiledBackingStore : public TextureMapperBackingStore { -public: - static PassRefPtr<TextureMapperTiledBackingStore> create() { return adoptRef(new TextureMapperTiledBackingStore); } - virtual ~TextureMapperTiledBackingStore() { } - - virtual PassRefPtr<BitmapTexture> texture() const OVERRIDE; - virtual void paintToTextureMapper(TextureMapper*, const FloatRect&, const TransformationMatrix&, float, BitmapTexture*) OVERRIDE; - void updateContents(TextureMapper*, Image*, const FloatSize&, const IntRect&, BitmapTexture::UpdateContentsFlag); - void updateContents(TextureMapper*, GraphicsLayer*, const FloatSize&, const IntRect&, BitmapTexture::UpdateContentsFlag); - - void setContentsToImage(Image* image) { m_image = image; } - void setShowDebugBorders(bool drawsDebugBorders) { m_drawsDebugBorders = drawsDebugBorders; } - void setDebugBorder(const Color&, float width); - -private: - TextureMapperTiledBackingStore(); - void createOrDestroyTilesIfNeeded(const FloatSize& backingStoreSize, const IntSize& tileSize, bool hasAlpha); - void updateContentsFromImageIfNeeded(TextureMapper*); - inline FloatRect rect() const { return FloatRect(FloatPoint::zero(), m_size); } - - Vector<TextureMapperTile> m_tiles; - FloatSize m_size; - RefPtr<Image> m_image; - - bool m_drawsDebugBorders; - Color m_debugBorderColor; - float m_debugBorderWidth; -}; - } #endif diff --git a/Source/WebCore/platform/graphics/texmap/TextureMapperFPSCounter.cpp b/Source/WebCore/platform/graphics/texmap/TextureMapperFPSCounter.cpp new file mode 100644 index 000000000..1704f477d --- /dev/null +++ b/Source/WebCore/platform/graphics/texmap/TextureMapperFPSCounter.cpp @@ -0,0 +1,67 @@ +/* + Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies) + Copyright (C) 2012, 2013 Company 100, Inc. + Copyright (C) 2012, 2013 basysKom GmbH + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "config.h" + +#if USE(ACCELERATED_COMPOSITING) && USE(TEXTURE_MAPPER) + +#include "TextureMapperFPSCounter.h" + +#include "TextureMapper.h" +#include <wtf/CurrentTime.h> + +namespace WebCore { + +TextureMapperFPSCounter::TextureMapperFPSCounter() + : m_isShowingFPS(false) + , m_fpsInterval(0) + , m_fpsTimestamp(0) + , m_lastFPS(0) + , m_frameCount(0) +{ + String showFPSEnvironment = getenv("WEBKIT_SHOW_FPS"); + bool ok = false; + m_fpsInterval = showFPSEnvironment.toDouble(&ok); + if (ok && m_fpsInterval) { + m_isShowingFPS = true; + m_fpsTimestamp = WTF::currentTime(); + } +} + +void TextureMapperFPSCounter::updateFPSAndDisplay(TextureMapper* textureMapper, const FloatPoint& location, const TransformationMatrix& matrix) +{ + if (!m_isShowingFPS) + return; + + m_frameCount++; + double delta = WTF::currentTime() - m_fpsTimestamp; + if (delta >= m_fpsInterval) { + m_lastFPS = int(m_frameCount / delta); + m_frameCount = 0; + m_fpsTimestamp += delta; + } + + textureMapper->drawNumber(m_lastFPS, Color::black, location, matrix); +} + +} // namespace WebCore + +#endif // USE(ACCELERATED_COMPOSITING) diff --git a/Source/WebCore/platform/graphics/texmap/TextureMapperFPSCounter.h b/Source/WebCore/platform/graphics/texmap/TextureMapperFPSCounter.h new file mode 100644 index 000000000..006237383 --- /dev/null +++ b/Source/WebCore/platform/graphics/texmap/TextureMapperFPSCounter.h @@ -0,0 +1,54 @@ +/* + Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies) + Copyright (C) 2012, 2013 Company 100, Inc. + Copyright (C) 2012, 2013 basysKom GmbH + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef TextureMapperFPSCounter_h +#define TextureMapperFPSCounter_h + +#if USE(ACCELERATED_COMPOSITING) && USE(TEXTURE_MAPPER) +#include "FloatPoint.h" +#include "TransformationMatrix.h" +#include <wtf/Noncopyable.h> + +namespace WebCore { +class TextureMapper; + +class TextureMapperFPSCounter { + WTF_MAKE_NONCOPYABLE(TextureMapperFPSCounter); + WTF_MAKE_FAST_ALLOCATED; +public: + TextureMapperFPSCounter(); + void updateFPSAndDisplay(TextureMapper*, const FloatPoint& = FloatPoint::zero(), const TransformationMatrix& = TransformationMatrix()); + +private: + bool m_isShowingFPS; + double m_fpsInterval; + double m_fpsTimestamp; + int m_lastFPS; + int m_frameCount; +}; + +} // namespace WebCore + +#endif // USE(ACCELERATED_COMPOSITING) + +#endif // TextureMapperFPSCounter_h + + diff --git a/Source/WebCore/platform/graphics/texmap/TextureMapperGL.cpp b/Source/WebCore/platform/graphics/texmap/TextureMapperGL.cpp index 2a6f29fdf..55c0b6aca 100644 --- a/Source/WebCore/platform/graphics/texmap/TextureMapperGL.cpp +++ b/Source/WebCore/platform/graphics/texmap/TextureMapperGL.cpp @@ -22,17 +22,20 @@ #include "config.h" #include "TextureMapperGL.h" +#include "Extensions3D.h" +#include "FilterOperations.h" #include "GraphicsContext.h" #include "Image.h" #include "LengthFunctions.h" #include "NotImplemented.h" -#include "TextureMapperShaderManager.h" +#include "TextureMapperShaderProgram.h" #include "Timer.h" #include <wtf/HashMap.h> #include <wtf/OwnArrayPtr.h> #include <wtf/PassOwnArrayPtr.h> #include <wtf/PassRefPtr.h> #include <wtf/RefCounted.h> +#include <wtf/TemporaryChange.h> #if PLATFORM(QT) #include "NativeImageQt.h" @@ -56,13 +59,14 @@ #if !USE(TEXMAP_OPENGL_ES_2) // FIXME: Move to Extensions3D.h. -#define GL_TEXTURE_RECTANGLE_ARB 0x84F5 #define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367 #define GL_UNPACK_ROW_LENGTH 0x0CF2 #define GL_UNPACK_SKIP_PIXELS 0x0CF4 #define GL_UNPACK_SKIP_ROWS 0x0CF3 #endif +#if USE(ACCELERATED_COMPOSITING) && USE(TEXTURE_MAPPER) + namespace WebCore { struct TextureMapperGLData { WTF_MAKE_FAST_ALLOCATED; @@ -85,12 +89,20 @@ public: return adoptRef(new SharedGLData(context)); } + PassRefPtr<TextureMapperShaderProgram> getShaderProgram(TextureMapperShaderProgram::Options options) + { + HashMap<TextureMapperShaderProgram::Options, RefPtr<TextureMapperShaderProgram> >::AddResult result = m_programs.add(options, 0); + if (result.isNewEntry) + result.iterator->value = TextureMapperShaderProgram::create(m_context, options); + return result.iterator->value; + } - TextureMapperShaderManager textureMapperShaderManager; + HashMap<TextureMapperShaderProgram::Options, RefPtr<TextureMapperShaderProgram> > m_programs; + RefPtr<GraphicsContext3D> m_context; explicit SharedGLData(GraphicsContext3D* context) - : textureMapperShaderManager(context) + : m_context(context) { glContextDataMap().add(context->platformGraphicsContext3D(), this); } @@ -111,7 +123,7 @@ public: SharedGLData& sharedGLData() const { - return *m_sharedGLData; + return *sharedData; } void initializeStencil(); @@ -124,9 +136,15 @@ public: , didModifyStencil(false) , previousScissorState(0) , previousDepthState(0) - , m_sharedGLData(TextureMapperGLData::SharedGLData::currentSharedGLData(this->context)) + , sharedData(TextureMapperGLData::SharedGLData::currentSharedGLData(this->context)) +#if ENABLE(CSS_FILTERS) + , filterInfo(0) +#endif { } + ~TextureMapperGLData(); + Platform3DObject getStaticVBO(GC3Denum target, GC3Dsizeiptr, const void* data); + GraphicsContext3D* context; TransformationMatrix projectionMatrix; TextureMapper::PaintFlags PaintFlags; @@ -137,19 +155,59 @@ public: GC3Dint previousDepthState; GC3Dint viewport[4]; GC3Dint previousScissor[4]; - RefPtr<SharedGLData> m_sharedGLData; + RefPtr<SharedGLData> sharedData; RefPtr<BitmapTexture> currentSurface; + HashMap<const void*, Platform3DObject> vbos; +#if ENABLE(CSS_FILTERS) + const BitmapTextureGL::FilterInfo* filterInfo; +#endif }; -void TextureMapperGL::ClipStack::init(const IntRect& rect) +Platform3DObject TextureMapperGLData::getStaticVBO(GC3Denum target, GC3Dsizeiptr size, const void* data) +{ + HashMap<const void*, Platform3DObject>::AddResult result = vbos.add(data, 0); + if (result.isNewEntry) { + Platform3DObject vbo = context->createBuffer(); + context->bindBuffer(target, vbo); + context->bufferData(target, size, data, GraphicsContext3D::STATIC_DRAW); + result.iterator->value = vbo; + } + + return result.iterator->value; +} + +TextureMapperGLData::~TextureMapperGLData() +{ + HashMap<const void*, Platform3DObject>::iterator end = vbos.end(); + for (HashMap<const void*, Platform3DObject>::iterator it = vbos.begin(); it != end; ++it) + context->deleteBuffer(it->value); +} + +void TextureMapperGL::ClipStack::reset(const IntRect& rect, TextureMapperGL::ClipStack::YAxisMode mode) { clipStack.clear(); + size = rect.size(); + yAxisMode = mode; clipState = TextureMapperGL::ClipState(rect); + clipStateDirty = true; +} + +void TextureMapperGL::ClipStack::intersect(const IntRect& rect) +{ + clipState.scissorBox.intersect(rect); + clipStateDirty = true; +} + +void TextureMapperGL::ClipStack::setStencilIndex(int stencilIndex) +{ + clipState.stencilIndex = stencilIndex; + clipStateDirty = true; } void TextureMapperGL::ClipStack::push() { clipStack.append(clipState); + clipStateDirty = true; } void TextureMapperGL::ClipStack::pop() @@ -158,21 +216,17 @@ void TextureMapperGL::ClipStack::pop() return; clipState = clipStack.last(); clipStack.removeLast(); + clipStateDirty = true; } -static void scissorClip(GraphicsContext3D* context, const IntRect& rect) +void TextureMapperGL::ClipStack::apply(GraphicsContext3D* context) { - if (rect.isEmpty()) + if (clipState.scissorBox.isEmpty()) return; - GC3Dint viewport[4]; - context->getIntegerv(GraphicsContext3D::VIEWPORT, viewport); - context->scissor(rect.x(), viewport[3] - rect.maxY(), rect.width(), rect.height()); -} - -void TextureMapperGL::ClipStack::apply(GraphicsContext3D* context) -{ - scissorClip(context, clipState.scissorBox); + context->scissor(clipState.scissorBox.x(), + (yAxisMode == InvertedYAxis) ? size.height() - clipState.scissorBox.maxY() : clipState.scissorBox.y(), + clipState.scissorBox.width(), clipState.scissorBox.height()); context->stencilOp(GraphicsContext3D::KEEP, GraphicsContext3D::KEEP, GraphicsContext3D::KEEP); context->stencilFunc(GraphicsContext3D::EQUAL, clipState.stencilIndex - 1, clipState.stencilIndex - 1); if (clipState.stencilIndex == 1) @@ -181,6 +235,14 @@ void TextureMapperGL::ClipStack::apply(GraphicsContext3D* context) context->enable(GraphicsContext3D::STENCIL_TEST); } +void TextureMapperGL::ClipStack::applyIfNeeded(GraphicsContext3D* context) +{ + if (!clipStateDirty) + return; + + clipStateDirty = false; + apply(context); +} void TextureMapperGLData::initializeStencil() { @@ -207,7 +269,6 @@ BitmapTextureGL* toBitmapTextureGL(BitmapTexture* texture) TextureMapperGL::TextureMapperGL() : TextureMapper(OpenGLMode) - , m_context(0) , m_enableEdgeDistanceAntialiasing(false) { m_context3D = GraphicsContext3D::createForCurrentGLContext(); @@ -237,7 +298,7 @@ void TextureMapperGL::beginPainting(PaintFlags flags) m_context3D->depthMask(0); m_context3D->getIntegerv(GraphicsContext3D::VIEWPORT, data().viewport); m_context3D->getIntegerv(GraphicsContext3D::SCISSOR_BOX, data().previousScissor); - m_clipStack.init(IntRect(0, 0, data().viewport[2], data().viewport[3])); + m_clipStack.reset(IntRect(0, 0, data().viewport[2], data().viewport[3]), ClipStack::InvertedYAxis); m_context3D->getIntegerv(GraphicsContext3D::FRAMEBUFFER_BINDING, &data().targetFrameBuffer); data().PaintFlags = flags; bindSurface(0); @@ -272,62 +333,28 @@ void TextureMapperGL::endPainting() #endif } -void TextureMapperGL::drawQuad(const DrawQuad& quadToDraw, const TransformationMatrix& modelViewMatrix, TextureMapperShaderProgram* shaderProgram, GC3Denum drawingMode, bool needsBlending) -{ - m_context3D->enableVertexAttribArray(shaderProgram->vertexLocation()); - m_context3D->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, 0); - - const GC3Dfloat quad[] = { - quadToDraw.targetRectMappedToUnitSquare.p1().x(), quadToDraw.targetRectMappedToUnitSquare.p1().y(), - quadToDraw.targetRectMappedToUnitSquare.p2().x(), quadToDraw.targetRectMappedToUnitSquare.p2().y(), - quadToDraw.targetRectMappedToUnitSquare.p3().x(), quadToDraw.targetRectMappedToUnitSquare.p3().y(), - quadToDraw.targetRectMappedToUnitSquare.p4().x(), quadToDraw.targetRectMappedToUnitSquare.p4().y() - }; - m_context3D->vertexAttribPointer(shaderProgram->vertexLocation(), 2, GraphicsContext3D::FLOAT, false, 0, GC3Dintptr(quad)); - - TransformationMatrix matrix = TransformationMatrix(data().projectionMatrix).multiply(modelViewMatrix).multiply(TransformationMatrix( - quadToDraw.originalTargetRect.width(), 0, 0, 0, - 0, quadToDraw.originalTargetRect.height(), 0, 0, - 0, 0, 1, 0, - quadToDraw.originalTargetRect.x(), quadToDraw.originalTargetRect.y(), 0, 1)); - GC3Dfloat m4[] = { - matrix.m11(), matrix.m12(), matrix.m13(), matrix.m14(), - matrix.m21(), matrix.m22(), matrix.m23(), matrix.m24(), - matrix.m31(), matrix.m32(), matrix.m33(), matrix.m34(), - matrix.m41(), matrix.m42(), matrix.m43(), matrix.m44() - }; - m_context3D->uniformMatrix4fv(shaderProgram->matrixLocation(), 1, false, m4); - - if (needsBlending) { - m_context3D->blendFunc(GraphicsContext3D::ONE, GraphicsContext3D::ONE_MINUS_SRC_ALPHA); - m_context3D->enable(GraphicsContext3D::BLEND); - } else - m_context3D->disable(GraphicsContext3D::BLEND); - - m_context3D->drawArrays(drawingMode, 0, 4); - m_context3D->disableVertexAttribArray(shaderProgram->vertexLocation()); -} - void TextureMapperGL::drawBorder(const Color& color, float width, const FloatRect& targetRect, const TransformationMatrix& modelViewMatrix) { - if (clipStack().current().scissorBox.isEmpty()) + if (clipStack().isCurrentScissorBoxEmpty()) return; - RefPtr<TextureMapperShaderProgram> program = data().sharedGLData().textureMapperShaderManager.getShaderProgram(TextureMapperShaderManager::SolidColor); + RefPtr<TextureMapperShaderProgram> program = data().sharedGLData().getShaderProgram(TextureMapperShaderProgram::SolidColor); m_context3D->useProgram(program->programID()); float r, g, b, a; - color.getRGBA(r, g, b, a); + Color(premultipliedARGBFromColor(color)).getRGBA(r, g, b, a); m_context3D->uniform4f(program->colorLocation(), r, g, b, a); m_context3D->lineWidth(width); - drawQuad(targetRect, modelViewMatrix, program.get(), GraphicsContext3D::LINE_LOOP, color.hasAlpha()); + draw(targetRect, modelViewMatrix, program.get(), GraphicsContext3D::LINE_LOOP, color.hasAlpha() ? ShouldBlend : 0); } -void TextureMapperGL::drawRepaintCounter(int value, int pointSize, const FloatPoint& targetPoint, const TransformationMatrix& modelViewMatrix) +// FIXME: drawNumber() should save a number texture-atlas and re-use whenever possible. +void TextureMapperGL::drawNumber(int number, const Color& color, const FloatPoint& targetPoint, const TransformationMatrix& modelViewMatrix) { + int pointSize = 8; #if PLATFORM(QT) - QString counterString = QString::number(value); + QString counterString = QString::number(number); QFont font(QString::fromLatin1("Monospace"), pointSize, QFont::Bold); font.setStyleHint(QFont::TypeWriter); @@ -342,7 +369,7 @@ void TextureMapperGL::drawRepaintCounter(int value, int pointSize, const FloatPo QImage image(size, NativeImageQt::defaultFormatForAlphaEnabledImages()); QPainter painter(&image); - painter.fillRect(sourceRect, Qt::blue); // Since we won't swap R+B for speed, this will paint red. + painter.fillRect(sourceRect, Color::createUnchecked(color.blue(), color.green(), color.red())); // Since we won't swap R+B when uploading a texture, paint with the swapped R+B color. painter.setFont(font); painter.setPen(Qt::white); painter.drawText(2, height * 0.85, counterString); @@ -350,10 +377,10 @@ void TextureMapperGL::drawRepaintCounter(int value, int pointSize, const FloatPo RefPtr<BitmapTexture> texture = acquireTextureFromPool(size); const uchar* bits = image.bits(); static_cast<BitmapTextureGL*>(texture.get())->updateContentsNoSwizzle(bits, sourceRect, IntPoint::zero(), image.bytesPerLine()); - drawTexture(*texture, targetRect, modelViewMatrix, 1.0f, 0, AllEdges); + drawTexture(*texture, targetRect, modelViewMatrix, 1.0f, AllEdges); #elif USE(CAIRO) - CString counterString = String::number(value).ascii(); + CString counterString = String::number(number).ascii(); // cairo_text_extents() requires a cairo_t, so dimensions need to be guesstimated. int width = counterString.length() * pointSize * 1.2; int height = pointSize * 1.5; @@ -361,7 +388,9 @@ void TextureMapperGL::drawRepaintCounter(int value, int pointSize, const FloatPo cairo_surface_t* surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); cairo_t* cr = cairo_create(surface); - cairo_set_source_rgb(cr, 0, 0, 1); // Since we won't swap R+B for speed, this will paint red. + float r, g, b, a; + color.getRGBA(r, g, b, a); + cairo_set_source_rgba(cr, b, g, r, a); // Since we won't swap R+B when uploading a texture, paint with the swapped R+B color. cairo_rectangle(cr, 0, 0, width, height); cairo_fill(cr); @@ -379,13 +408,13 @@ void TextureMapperGL::drawRepaintCounter(int value, int pointSize, const FloatPo const unsigned char* bits = cairo_image_surface_get_data(surface); int stride = cairo_image_surface_get_stride(surface); static_cast<BitmapTextureGL*>(texture.get())->updateContentsNoSwizzle(bits, sourceRect, IntPoint::zero(), stride); - drawTexture(*texture, targetRect, modelViewMatrix, 1.0f, 0, AllEdges); + drawTexture(*texture, targetRect, modelViewMatrix, 1.0f, AllEdges); cairo_surface_destroy(surface); cairo_destroy(cr); #else - UNUSED_PARAM(value); + UNUSED_PARAM(number); UNUSED_PARAM(pointSize); UNUSED_PARAM(targetPoint); UNUSED_PARAM(modelViewMatrix); @@ -393,229 +422,337 @@ void TextureMapperGL::drawRepaintCounter(int value, int pointSize, const FloatPo #endif } -void TextureMapperGL::drawTexture(const BitmapTexture& texture, const FloatRect& targetRect, const TransformationMatrix& matrix, float opacity, const BitmapTexture* mask, unsigned exposedEdges) -{ - if (!texture.isValid()) - return; +#if ENABLE(CSS_FILTERS) - if (clipStack().current().scissorBox.isEmpty()) - return; +static TextureMapperShaderProgram::Options optionsForFilterType(FilterOperation::OperationType type, unsigned pass) +{ + switch (type) { + case FilterOperation::GRAYSCALE: + return TextureMapperShaderProgram::Texture | TextureMapperShaderProgram::GrayscaleFilter; + case FilterOperation::SEPIA: + return TextureMapperShaderProgram::Texture | TextureMapperShaderProgram::SepiaFilter; + case FilterOperation::SATURATE: + return TextureMapperShaderProgram::Texture | TextureMapperShaderProgram::SaturateFilter; + case FilterOperation::HUE_ROTATE: + return TextureMapperShaderProgram::Texture | TextureMapperShaderProgram::HueRotateFilter; + case FilterOperation::INVERT: + return TextureMapperShaderProgram::Texture | TextureMapperShaderProgram::InvertFilter; + case FilterOperation::BRIGHTNESS: + return TextureMapperShaderProgram::Texture | TextureMapperShaderProgram::BrightnessFilter; + case FilterOperation::CONTRAST: + return TextureMapperShaderProgram::Texture | TextureMapperShaderProgram::ContrastFilter; + case FilterOperation::OPACITY: + return TextureMapperShaderProgram::Texture | TextureMapperShaderProgram::OpacityFilter; + case FilterOperation::BLUR: + return TextureMapperShaderProgram::BlurFilter; + case FilterOperation::DROP_SHADOW: + return TextureMapperShaderProgram::AlphaBlur + | (pass ? TextureMapperShaderProgram::ContentTexture | TextureMapperShaderProgram::SolidColor: 0); + default: + ASSERT_NOT_REACHED(); + return 0; + } +} - const BitmapTextureGL& textureGL = static_cast<const BitmapTextureGL&>(texture); - drawTexture(textureGL.id(), textureGL.isOpaque() ? 0 : SupportsBlending, textureGL.size(), targetRect, matrix, opacity, mask, exposedEdges); +static unsigned getPassesRequiredForFilter(FilterOperation::OperationType type) +{ + switch (type) { + case FilterOperation::GRAYSCALE: + case FilterOperation::SEPIA: + case FilterOperation::SATURATE: + case FilterOperation::HUE_ROTATE: + case FilterOperation::INVERT: + case FilterOperation::BRIGHTNESS: + case FilterOperation::CONTRAST: + case FilterOperation::OPACITY: +#if ENABLE(CSS_SHADERS) + case FilterOperation::CUSTOM: + case FilterOperation::VALIDATED_CUSTOM: +#endif + return 1; + case FilterOperation::BLUR: + case FilterOperation::DROP_SHADOW: + // We use two-passes (vertical+horizontal) for blur and drop-shadow. + return 2; + default: + return 0; + } } -#if !USE(TEXMAP_OPENGL_ES_2) -void TextureMapperGL::drawTextureRectangleARB(uint32_t texture, Flags flags, const IntSize& textureSize, const FloatRect& targetRect, const TransformationMatrix& modelViewMatrix, float opacity, const BitmapTexture* maskTexture) +// Create a normal distribution of 21 values between -2 and 2. +static const unsigned GaussianKernelHalfWidth = 11; +static const float GaussianKernelStep = 0.2; + +static inline float gauss(float x) { - RefPtr<TextureMapperShaderProgram> program; - if (maskTexture) - program = data().sharedGLData().textureMapperShaderManager.getShaderProgram(TextureMapperShaderManager::MaskedRect); - else - program = data().sharedGLData().textureMapperShaderManager.getShaderProgram(TextureMapperShaderManager::Rect); - m_context3D->useProgram(program->programID()); + return exp(-(x * x) / 2.); +} - m_context3D->enableVertexAttribArray(program->vertexLocation()); - m_context3D->activeTexture(GraphicsContext3D::TEXTURE0); - m_context3D->bindTexture(GL_TEXTURE_RECTANGLE_ARB, texture); - m_context3D->uniform1i(program->samplerLocation(), 0); +static float* gaussianKernel() +{ + static bool prepared = false; + static float kernel[GaussianKernelHalfWidth] = {0, }; - m_context3D->uniform1f(program->flipLocation(), !!(flags & ShouldFlipTexture)); - m_context3D->uniform2f(program->samplerSizeLocation(), textureSize.width(), textureSize.height()); - m_context3D->uniform1f(program->opacityLocation(), opacity); + if (prepared) + return kernel; - if (maskTexture && maskTexture->isValid()) { - const BitmapTextureGL* maskTextureGL = static_cast<const BitmapTextureGL*>(maskTexture); - m_context3D->activeTexture(GraphicsContext3D::TEXTURE1); - m_context3D->bindTexture(GraphicsContext3D::TEXTURE_2D, maskTextureGL->id()); - m_context3D->uniform1i(program->maskLocation(), 1); - m_context3D->activeTexture(GraphicsContext3D::TEXTURE0); + kernel[0] = gauss(0); + float sum = kernel[0]; + for (unsigned i = 1; i < GaussianKernelHalfWidth; ++i) { + kernel[i] = gauss(i * GaussianKernelStep); + sum += 2 * kernel[i]; } - bool needsBlending = (flags & SupportsBlending) || opacity < 0.99 || maskTexture; - drawQuad(targetRect, modelViewMatrix, program.get(), GraphicsContext3D::TRIANGLE_FAN, needsBlending); + // Normalize the kernel. + float scale = 1 / sum; + for (unsigned i = 0; i < GaussianKernelHalfWidth; ++i) + kernel[i] *= scale; + + prepared = true; + return kernel; } -#endif // !USE(TEXMAP_OPENGL_ES_2) -void TextureMapperGL::drawTexture(uint32_t texture, Flags flags, const IntSize& /* textureSize */, const FloatRect& targetRect, const TransformationMatrix& modelViewMatrix, float opacity, const BitmapTexture* maskTexture, unsigned exposedEdges) +static void prepareFilterProgram(TextureMapperShaderProgram* program, const FilterOperation& operation, unsigned pass, const IntSize& size, GC3Duint contentTexture) { - bool needsAntialiasing = m_enableEdgeDistanceAntialiasing && !modelViewMatrix.isIntegerTranslation(); - if (needsAntialiasing && drawTextureWithAntialiasing(texture, flags, targetRect, modelViewMatrix, opacity, maskTexture, exposedEdges)) - return; + RefPtr<GraphicsContext3D> context = program->context(); + context->useProgram(program->programID()); - RefPtr<TextureMapperShaderProgram> program; - if (maskTexture) - program = data().sharedGLData().textureMapperShaderManager.getShaderProgram(TextureMapperShaderManager::Masked); - else - program = data().sharedGLData().textureMapperShaderManager.getShaderProgram(TextureMapperShaderManager::Default); - m_context3D->useProgram(program->programID()); + switch (operation.getOperationType()) { + case FilterOperation::GRAYSCALE: + case FilterOperation::SEPIA: + case FilterOperation::SATURATE: + case FilterOperation::HUE_ROTATE: + context->uniform1f(program->filterAmountLocation(), static_cast<const BasicColorMatrixFilterOperation&>(operation).amount()); + break; + case FilterOperation::INVERT: + case FilterOperation::BRIGHTNESS: + case FilterOperation::CONTRAST: + case FilterOperation::OPACITY: + context->uniform1f(program->filterAmountLocation(), static_cast<const BasicComponentTransferFilterOperation&>(operation).amount()); + break; + case FilterOperation::BLUR: { + const BlurFilterOperation& blur = static_cast<const BlurFilterOperation&>(operation); + FloatSize radius; - drawTexturedQuadWithProgram(program.get(), texture, flags, targetRect, modelViewMatrix, opacity, maskTexture); + // Blur is done in two passes, first horizontally and then vertically. The same shader is used for both. + if (pass) + radius.setHeight(floatValueForLength(blur.stdDeviation(), size.height()) / size.height()); + else + radius.setWidth(floatValueForLength(blur.stdDeviation(), size.width()) / size.width()); + + context->uniform2f(program->blurRadiusLocation(), radius.width(), radius.height()); + context->uniform1fv(program->gaussianKernelLocation(), GaussianKernelHalfWidth, gaussianKernel()); + break; + } + case FilterOperation::DROP_SHADOW: { + const DropShadowFilterOperation& shadow = static_cast<const DropShadowFilterOperation&>(operation); + context->uniform1fv(program->gaussianKernelLocation(), GaussianKernelHalfWidth, gaussianKernel()); + switch (pass) { + case 0: + // First pass: horizontal alpha blur. + context->uniform2f(program->blurRadiusLocation(), shadow.stdDeviation() / float(size.width()), 0); + context->uniform2f(program->shadowOffsetLocation(), float(shadow.location().x()) / float(size.width()), float(shadow.location().y()) / float(size.height())); + break; + case 1: + // Second pass: we need the shadow color and the content texture for compositing. + float r, g, b, a; + Color(premultipliedARGBFromColor(shadow.color())).getRGBA(r, g, b, a); + context->uniform4f(program->colorLocation(), r, g, b, a); + context->uniform2f(program->blurRadiusLocation(), 0, shadow.stdDeviation() / float(size.height())); + context->uniform2f(program->shadowOffsetLocation(), 0, 0); + context->activeTexture(GraphicsContext3D::TEXTURE1); + context->bindTexture(GraphicsContext3D::TEXTURE_2D, contentTexture); + context->uniform1i(program->contentTextureLocation(), 1); + break; + } + break; + } + default: + break; + } } +#endif -void TextureMapperGL::drawSolidColor(const FloatRect& rect, const TransformationMatrix& matrix, const Color& color) +void TextureMapperGL::drawTexture(const BitmapTexture& texture, const FloatRect& targetRect, const TransformationMatrix& matrix, float opacity, unsigned exposedEdges) { - RefPtr<TextureMapperShaderProgram> program = data().sharedGLData().textureMapperShaderManager.getShaderProgram(TextureMapperShaderManager::SolidColor); - m_context3D->useProgram(program->programID()); + if (!texture.isValid()) + return; - float r, g, b, a; - color.getRGBA(r, g, b, a); - m_context3D->uniform4f(program->colorLocation(), r, g, b, a); + if (clipStack().isCurrentScissorBoxEmpty()) + return; - drawQuad(rect, matrix, program.get(), GraphicsContext3D::TRIANGLE_FAN, false); + const BitmapTextureGL& textureGL = static_cast<const BitmapTextureGL&>(texture); +#if ENABLE(CSS_FILTERS) + TemporaryChange<const BitmapTextureGL::FilterInfo*> filterInfo(data().filterInfo, textureGL.filterInfo()); +#endif + + drawTexture(textureGL.id(), textureGL.isOpaque() ? 0 : ShouldBlend, textureGL.size(), targetRect, matrix, opacity, exposedEdges); } -static TransformationMatrix viewportMatrix(GraphicsContext3D* context3D) +void TextureMapperGL::drawTexture(Platform3DObject texture, Flags flags, const IntSize& textureSize, const FloatRect& targetRect, const TransformationMatrix& modelViewMatrix, float opacity, unsigned exposedEdges) { - GC3Dint viewport[4]; - context3D->getIntegerv(GraphicsContext3D::VIEWPORT, viewport); + bool useRect = flags & ShouldUseARBTextureRect; + bool useAntialiasing = m_enableEdgeDistanceAntialiasing + && exposedEdges == AllEdges + && !modelViewMatrix.mapQuad(targetRect).isRectilinear(); + + TextureMapperShaderProgram::Options options = TextureMapperShaderProgram::Texture; + if (useRect) + options |= TextureMapperShaderProgram::Rect; + if (opacity < 1) + options |= TextureMapperShaderProgram::Opacity; + if (useAntialiasing) { + options |= TextureMapperShaderProgram::Antialiasing; + flags |= ShouldAntialias; + } - TransformationMatrix matrix; - matrix.translate3d(viewport[0], viewport[1], 0); - matrix.scale3d(viewport[2], viewport[3], 0); +#if ENABLE(CSS_FILTERS) + RefPtr<FilterOperation> filter = data().filterInfo ? data().filterInfo->filter: 0; + GC3Duint filterContentTextureID = 0; + + if (filter) { + if (data().filterInfo->contentTexture) + filterContentTextureID = toBitmapTextureGL(data().filterInfo->contentTexture.get())->id(); + options |= optionsForFilterType(filter->getOperationType(), data().filterInfo->pass); + if (filter->affectsOpacity()) + flags |= ShouldBlend; + } +#endif - // Map x, y and z to unit square from OpenGL normalized device - // coordinates which are -1 to 1 on every axis. - matrix.translate3d(0.5, 0.5, 0.5); - matrix.scale3d(0.5, 0.5, 0.5); + if (useAntialiasing || opacity < 1) + flags |= ShouldBlend; - return matrix; -} + RefPtr<TextureMapperShaderProgram> program; + program = data().sharedGLData().getShaderProgram(options); -static void scaleLineEquationCoeffecientsToOptimizeDistanceCalculation(float* coeffecients) -{ - // In the fragment shader we want to calculate the distance from this - // line to a point (p), which is given by the formula: - // (A*p.x + B*p.y + C) / sqrt (a^2 + b^2) - // We can do a small amount of precalculation here to reduce the - // amount of math in the shader by scaling the coeffecients now. - float scale = 1.0 / FloatPoint(coeffecients[0], coeffecients[1]).length(); - coeffecients[0] = coeffecients[0] * scale; - coeffecients[1] = coeffecients[1] * scale; - coeffecients[2] = coeffecients[2] * scale; -} +#if ENABLE(CSS_FILTERS) + if (filter) + prepareFilterProgram(program.get(), *filter.get(), data().filterInfo->pass, textureSize, filterContentTextureID); +#endif -static void getStandardEquationCoeffecientsForLine(const FloatPoint& p1, const FloatPoint& p2, float* coeffecients) -{ - // Given two points, the standard equation of a line (Ax + By + C = 0) - // can be calculated via the formula: - // (p1.y – p2.y)x + (p1.x – p2.x)y + ((p1.x*p2.y) – (p2.x*p1.y)) = 0 - coeffecients[0] = p1.y() - p2.y(); - coeffecients[1] = p2.x() - p1.x(); - coeffecients[2] = p1.x() * p2.y() - p2.x() * p1.y(); - scaleLineEquationCoeffecientsToOptimizeDistanceCalculation(coeffecients); + drawTexturedQuadWithProgram(program.get(), texture, flags, textureSize, targetRect, modelViewMatrix, opacity); } -static void quadToEdgeArray(const FloatQuad& quad, float* edgeArray) +void TextureMapperGL::drawSolidColor(const FloatRect& rect, const TransformationMatrix& matrix, const Color& color) { - if (quad.isCounterclockwise()) { - getStandardEquationCoeffecientsForLine(quad.p4(), quad.p3(), edgeArray); - getStandardEquationCoeffecientsForLine(quad.p3(), quad.p2(), edgeArray + 3); - getStandardEquationCoeffecientsForLine(quad.p2(), quad.p1(), edgeArray + 6); - getStandardEquationCoeffecientsForLine(quad.p1(), quad.p4(), edgeArray + 9); - return; + Flags flags = 0; + TextureMapperShaderProgram::Options options = TextureMapperShaderProgram::SolidColor; + if (!matrix.mapQuad(rect).isRectilinear()) { + options |= TextureMapperShaderProgram::Antialiasing; + flags |= ShouldBlend | ShouldAntialias; } - getStandardEquationCoeffecientsForLine(quad.p4(), quad.p1(), edgeArray); - getStandardEquationCoeffecientsForLine(quad.p1(), quad.p2(), edgeArray + 3); - getStandardEquationCoeffecientsForLine(quad.p2(), quad.p3(), edgeArray + 6); - getStandardEquationCoeffecientsForLine(quad.p3(), quad.p4(), edgeArray + 9); -} -static FloatSize scaledVectorDifference(const FloatPoint& point1, const FloatPoint& point2, float scale) -{ - FloatSize vector = point1 - point2; - if (vector.diagonalLengthSquared()) - vector.scale(1.0 / vector.diagonalLength()); + RefPtr<TextureMapperShaderProgram> program = data().sharedGLData().getShaderProgram(options); + m_context3D->useProgram(program->programID()); + + float r, g, b, a; + Color(premultipliedARGBFromColor(color)).getRGBA(r, g, b, a); + m_context3D->uniform4f(program->colorLocation(), r, g, b, a); + if (a < 1) + flags |= ShouldBlend; - vector.scale(scale); - return vector; + draw(rect, matrix, program.get(), GraphicsContext3D::TRIANGLE_FAN, flags); } -static FloatQuad inflateQuad(const FloatQuad& quad, float distance) +void TextureMapperGL::drawEdgeTriangles(TextureMapperShaderProgram* program) { - FloatQuad expandedQuad = quad; - expandedQuad.setP1(expandedQuad.p1() + scaledVectorDifference(quad.p1(), quad.p2(), distance)); - expandedQuad.setP4(expandedQuad.p4() + scaledVectorDifference(quad.p4(), quad.p3(), distance)); - - expandedQuad.setP1(expandedQuad.p1() + scaledVectorDifference(quad.p1(), quad.p4(), distance)); - expandedQuad.setP2(expandedQuad.p2() + scaledVectorDifference(quad.p2(), quad.p3(), distance)); - - expandedQuad.setP2(expandedQuad.p2() + scaledVectorDifference(quad.p2(), quad.p1(), distance)); - expandedQuad.setP3(expandedQuad.p3() + scaledVectorDifference(quad.p3(), quad.p4(), distance)); + const GC3Dfloat left = 0; + const GC3Dfloat top = 0; + const GC3Dfloat right = 1; + const GC3Dfloat bottom = 1; + const GC3Dfloat center = 0.5; + +// Each 4d triangle consists of a center point and two edge points, where the zw coordinates +// of each vertex equals the nearest point to the vertex on the edge. +#define SIDE_TRIANGLE_DATA(x1, y1, x2, y2) \ + x1, y1, x1, y1, \ + x2, y2, x2, y2, \ + center, center, (x1 + x2) / 2, (y1 + y2) / 2 + + static const GC3Dfloat unitRectSideTriangles[] = { + SIDE_TRIANGLE_DATA(left, top, right, top), + SIDE_TRIANGLE_DATA(left, top, left, bottom), + SIDE_TRIANGLE_DATA(right, top, right, bottom), + SIDE_TRIANGLE_DATA(left, bottom, right, bottom) + }; +#undef SIDE_TRIANGLE_DATA - expandedQuad.setP3(expandedQuad.p3() + scaledVectorDifference(quad.p3(), quad.p2(), distance)); - expandedQuad.setP4(expandedQuad.p4() + scaledVectorDifference(quad.p4(), quad.p1(), distance)); + Platform3DObject vbo = data().getStaticVBO(GraphicsContext3D::ARRAY_BUFFER, sizeof(GC3Dfloat) * 48, unitRectSideTriangles); + m_context3D->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, vbo); + m_context3D->vertexAttribPointer(program->vertexLocation(), 4, GraphicsContext3D::FLOAT, false, 0, 0); + m_context3D->drawArrays(GraphicsContext3D::TRIANGLES, 0, 12); + m_context3D->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, 0); +} - return expandedQuad; +void TextureMapperGL::drawUnitRect(TextureMapperShaderProgram* program, GC3Denum drawingMode) +{ + static const GC3Dfloat unitRect[] = { 0, 0, 1, 0, 1, 1, 0, 1 }; + Platform3DObject vbo = data().getStaticVBO(GraphicsContext3D::ARRAY_BUFFER, sizeof(GC3Dfloat) * 8, unitRect); + m_context3D->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, vbo); + m_context3D->vertexAttribPointer(program->vertexLocation(), 2, GraphicsContext3D::FLOAT, false, 0, 0); + m_context3D->drawArrays(drawingMode, 0, 4); + m_context3D->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, 0); } -bool TextureMapperGL::drawTextureWithAntialiasing(uint32_t texture, Flags flags, const FloatRect& originalTargetRect, const TransformationMatrix& modelViewMatrix, float opacity, const BitmapTexture* maskTexture, unsigned exposedEdges) +void TextureMapperGL::draw(const FloatRect& rect, const TransformationMatrix& modelViewMatrix, TextureMapperShaderProgram* shaderProgram, GC3Denum drawingMode, Flags flags) { - // The antialiasing path does not support mask textures at the moment. - if (maskTexture) - return false; + TransformationMatrix matrix = + TransformationMatrix(modelViewMatrix).multiply(TransformationMatrix::rectToRect(FloatRect(0, 0, 1, 1), rect)); - // For now we punt on rendering tiled layers with antialiasing. It's quite hard - // to render them without seams. - if (exposedEdges != AllEdges) - return false; + m_context3D->enableVertexAttribArray(shaderProgram->vertexLocation()); + shaderProgram->setMatrix(shaderProgram->modelViewMatrixLocation(), matrix); + shaderProgram->setMatrix(shaderProgram->projectionMatrixLocation(), data().projectionMatrix); - // The goal here is render a slightly larger (0.75 pixels in screen space) quad and to - // gradually taper off the alpha values to do a simple version of edge distance - // antialiasing. Note here that we are also including the viewport matrix (which - // translates from normalized device coordinates to screen coordinates), because these - // values are consumed in the fragment shader, which works in screen coordinates. - TransformationMatrix screenSpaceTransform = viewportMatrix(m_context3D.get()).multiply(TransformationMatrix(data().projectionMatrix)).multiply(modelViewMatrix).to2dTransform(); - if (!screenSpaceTransform.isInvertible()) - return false; - FloatQuad quadInScreenSpace = screenSpaceTransform.mapQuad(originalTargetRect); - - const float inflationDistance = 0.75; - FloatQuad expandedQuadInScreenSpace = inflateQuad(quadInScreenSpace, inflationDistance); - - // In the non-antialiased case the vertices passed are the unit rectangle and double - // as the texture coordinates (0,0 1,0, 1,1 and 0,1). Here we map the expanded quad - // coordinates in screen space back to the original rect's texture coordinates. - // This has the effect of slightly increasing the size of the original quad's geometry - // in the vertex shader. - FloatQuad expandedQuadInTextureCoordinates = screenSpaceTransform.inverse().mapQuad(expandedQuadInScreenSpace); - expandedQuadInTextureCoordinates.move(-originalTargetRect.x(), -originalTargetRect.y()); - expandedQuadInTextureCoordinates.scale(1 / originalTargetRect.width(), 1 / originalTargetRect.height()); - - // We prepare both the expanded quad for the fragment shader as well as the rectangular bounding - // box of that quad, as that seems necessary to properly antialias backfacing quads. - float targetQuadEdges[24]; - quadToEdgeArray(expandedQuadInScreenSpace, targetQuadEdges); - quadToEdgeArray(inflateQuad(quadInScreenSpace.boundingBox(), inflationDistance), targetQuadEdges + 12); - - RefPtr<TextureMapperShaderProgram> program = data().sharedGLData().textureMapperShaderManager.getShaderProgram(TextureMapperShaderManager::Antialiased); - m_context3D->useProgram(program->programID()); - m_context3D->uniform3fv(program->expandedQuadEdgesInScreenSpaceLocation(), 8, targetQuadEdges); + if (isInMaskMode()) { + m_context3D->blendFunc(GraphicsContext3D::ZERO, GraphicsContext3D::SRC_ALPHA); + m_context3D->enable(GraphicsContext3D::BLEND); + } else { + if (flags & ShouldBlend) { + m_context3D->blendFunc(GraphicsContext3D::ONE, GraphicsContext3D::ONE_MINUS_SRC_ALPHA); + m_context3D->enable(GraphicsContext3D::BLEND); + } else + m_context3D->disable(GraphicsContext3D::BLEND); + } - drawTexturedQuadWithProgram(program.get(), texture, flags, DrawQuad(originalTargetRect, expandedQuadInTextureCoordinates), modelViewMatrix, opacity, 0 /* maskTexture */); - return true; + if (flags & ShouldAntialias) + drawEdgeTriangles(shaderProgram); + else + drawUnitRect(shaderProgram, drawingMode); + + m_context3D->disableVertexAttribArray(shaderProgram->vertexLocation()); + m_context3D->blendFunc(GraphicsContext3D::ONE, GraphicsContext3D::ONE_MINUS_SRC_ALPHA); + m_context3D->enable(GraphicsContext3D::BLEND); } -void TextureMapperGL::drawTexturedQuadWithProgram(TextureMapperShaderProgram* program, uint32_t texture, Flags flags, const DrawQuad& quadToDraw, const TransformationMatrix& modelViewMatrix, float opacity, const BitmapTexture* maskTexture) +void TextureMapperGL::drawTexturedQuadWithProgram(TextureMapperShaderProgram* program, uint32_t texture, Flags flags, const IntSize& size, const FloatRect& rect, const TransformationMatrix& modelViewMatrix, float opacity) { - m_context3D->enableVertexAttribArray(program->vertexLocation()); + m_context3D->useProgram(program->programID()); m_context3D->activeTexture(GraphicsContext3D::TEXTURE0); - m_context3D->bindTexture(GraphicsContext3D::TEXTURE_2D, texture); + GC3Denum target = flags & ShouldUseARBTextureRect ? GC3Denum(Extensions3D::TEXTURE_RECTANGLE_ARB) : GC3Denum(GraphicsContext3D::TEXTURE_2D); + m_context3D->bindTexture(target, texture); m_context3D->uniform1i(program->samplerLocation(), 0); + if (wrapMode() == RepeatWrap) { + m_context3D->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_S, GraphicsContext3D::REPEAT); + m_context3D->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_T, GraphicsContext3D::REPEAT); + } + + TransformationMatrix patternTransform = this->patternTransform(); + if (flags & ShouldFlipTexture) + patternTransform.flipY(); + if (flags & ShouldUseARBTextureRect) + patternTransform.scaleNonUniform(size.width(), size.height()); + if (flags & ShouldFlipTexture) + patternTransform.translate(0, -1); - m_context3D->uniform1f(program->flipLocation(), !!(flags & ShouldFlipTexture)); + program->setMatrix(program->textureSpaceMatrixLocation(), patternTransform); m_context3D->uniform1f(program->opacityLocation(), opacity); - if (maskTexture && maskTexture->isValid()) { - const BitmapTextureGL* maskTextureGL = static_cast<const BitmapTextureGL*>(maskTexture); - m_context3D->activeTexture(GraphicsContext3D::TEXTURE1); - m_context3D->bindTexture(GraphicsContext3D::TEXTURE_2D, maskTextureGL->id()); - m_context3D->uniform1i(program->maskLocation(), 1); - m_context3D->activeTexture(GraphicsContext3D::TEXTURE0); - } + if (opacity < 1) + flags |= ShouldBlend; - bool needsBlending = (flags & SupportsBlending) || opacity < 0.99 || maskTexture; - drawQuad(quadToDraw, modelViewMatrix, program, GraphicsContext3D::TRIANGLE_FAN, needsBlending); + draw(rect, modelViewMatrix, program, GraphicsContext3D::TRIANGLE_FAN, flags); + m_context3D->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_S, GraphicsContext3D::CLAMP_TO_EDGE); + m_context3D->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_T, GraphicsContext3D::CLAMP_TO_EDGE); } BitmapTextureGL::BitmapTextureGL(TextureMapperGL* textureMapper) @@ -649,24 +786,26 @@ static void swizzleBGRAToRGBA(uint32_t* data, const IntRect& rect, int stride = } } -static bool driverSupportsBGRASwizzling() +// If GL_EXT_texture_format_BGRA8888 is supported in the OpenGLES +// internal and external formats need to be BGRA +static bool driverSupportsExternalTextureBGRA(GraphicsContext3D* context) { -#if defined(TEXMAP_OPENGL_ES_2) - // FIXME: Implement reliable detection. See also https://bugs.webkit.org/show_bug.cgi?id=81103. - return false; -#else + if (context->isGLES2Compliant()) { + static bool supportsExternalTextureBGRA = context->getExtensions()->supports("GL_EXT_texture_format_BGRA8888"); + return supportsExternalTextureBGRA; + } + return true; -#endif } -static bool driverSupportsSubImage() +static bool driverSupportsSubImage(GraphicsContext3D* context) { -#if defined(TEXMAP_OPENGL_ES_2) - // FIXME: Implement reliable detection. - return false; -#else + if (context->isGLES2Compliant()) { + static bool supportsSubImage = context->getExtensions()->supports("GL_EXT_unpack_subimage"); + return supportsSubImage; + } + return true; -#endif } void BitmapTextureGL::didReset() @@ -678,7 +817,6 @@ void BitmapTextureGL::didReset() if (m_textureSize == contentSize()) return; - Platform3DObject format = driverSupportsBGRASwizzling() ? GraphicsContext3D::BGRA : GraphicsContext3D::RGBA; m_textureSize = contentSize(); m_context3D->bindTexture(GraphicsContext3D::TEXTURE_2D, m_id); @@ -686,28 +824,36 @@ void BitmapTextureGL::didReset() m_context3D->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MAG_FILTER, GraphicsContext3D::LINEAR); m_context3D->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_S, GraphicsContext3D::CLAMP_TO_EDGE); m_context3D->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_T, GraphicsContext3D::CLAMP_TO_EDGE); - m_context3D->texImage2DDirect(GraphicsContext3D::TEXTURE_2D, 0, GraphicsContext3D::RGBA, m_textureSize.width(), m_textureSize.height(), 0, format, DEFAULT_TEXTURE_PIXEL_TRANSFER_TYPE, 0); + + Platform3DObject internalFormat = GraphicsContext3D::RGBA; + Platform3DObject externalFormat = GraphicsContext3D::BGRA; + if (m_context3D->isGLES2Compliant()) { + if (driverSupportsExternalTextureBGRA(m_context3D.get())) + internalFormat = GraphicsContext3D::BGRA; + else + externalFormat = GraphicsContext3D::RGBA; + } + + m_context3D->texImage2DDirect(GraphicsContext3D::TEXTURE_2D, 0, internalFormat, m_textureSize.width(), m_textureSize.height(), 0, externalFormat, DEFAULT_TEXTURE_PIXEL_TRANSFER_TYPE, 0); } void BitmapTextureGL::updateContentsNoSwizzle(const void* srcData, const IntRect& targetRect, const IntPoint& sourceOffset, int bytesPerLine, unsigned bytesPerPixel, Platform3DObject glFormat) { m_context3D->bindTexture(GraphicsContext3D::TEXTURE_2D, m_id); -#if !defined(TEXMAP_OPENGL_ES_2) - if (driverSupportsSubImage()) { // For ES drivers that don't support sub-images. + if (driverSupportsSubImage(m_context3D.get())) { // For ES drivers that don't support sub-images. // Use the OpenGL sub-image extension, now that we know it's available. m_context3D->pixelStorei(GL_UNPACK_ROW_LENGTH, bytesPerLine / bytesPerPixel); m_context3D->pixelStorei(GL_UNPACK_SKIP_ROWS, sourceOffset.y()); m_context3D->pixelStorei(GL_UNPACK_SKIP_PIXELS, sourceOffset.x()); } -#endif + m_context3D->texSubImage2D(GraphicsContext3D::TEXTURE_2D, 0, targetRect.x(), targetRect.y(), targetRect.width(), targetRect.height(), glFormat, DEFAULT_TEXTURE_PIXEL_TRANSFER_TYPE, srcData); -#if !defined(TEXMAP_OPENGL_ES_2) - if (driverSupportsSubImage()) { // For ES drivers that don't support sub-images. + + if (driverSupportsSubImage(m_context3D.get())) { // For ES drivers that don't support sub-images. m_context3D->pixelStorei(GL_UNPACK_ROW_LENGTH, 0); m_context3D->pixelStorei(GL_UNPACK_SKIP_ROWS, 0); m_context3D->pixelStorei(GL_UNPACK_SKIP_PIXELS, 0); } -#endif } void BitmapTextureGL::updateContents(const void* srcData, const IntRect& targetRect, const IntPoint& sourceOffset, int bytesPerLine, UpdateContentsFlag updateContentsFlag) @@ -721,11 +867,11 @@ void BitmapTextureGL::updateContents(const void* srcData, const IntRect& targetR IntPoint adjustedSourceOffset = sourceOffset; // Texture upload requires subimage buffer if driver doesn't support subimage and we don't have full image upload. - bool requireSubImageBuffer = !driverSupportsSubImage() + bool requireSubImageBuffer = !driverSupportsSubImage(m_context3D.get()) && !(bytesPerLine == static_cast<int>(targetRect.width() * bytesPerPixel) && adjustedSourceOffset == IntPoint::zero()); // prepare temporaryData if necessary - if ((!driverSupportsBGRASwizzling() && updateContentsFlag == UpdateCannotModifyOriginalImageData) || requireSubImageBuffer) { + if ((!driverSupportsExternalTextureBGRA(m_context3D.get()) && updateContentsFlag == UpdateCannotModifyOriginalImageData) || requireSubImageBuffer) { temporaryData.resize(targetRect.width() * targetRect.height() * bytesPerPixel); data = temporaryData.data(); const char* bits = static_cast<const char*>(srcData); @@ -742,10 +888,10 @@ void BitmapTextureGL::updateContents(const void* srcData, const IntRect& targetR adjustedSourceOffset = IntPoint(0, 0); } - if (driverSupportsBGRASwizzling()) + if (driverSupportsExternalTextureBGRA(m_context3D.get())) glFormat = GraphicsContext3D::BGRA; else - swizzleBGRAToRGBA(reinterpret_cast<uint32_t*>(data), IntRect(adjustedSourceOffset, targetRect.size()), bytesPerLine / bytesPerPixel); + swizzleBGRAToRGBA(reinterpret_cast_ptr<uint32_t*>(data), IntRect(adjustedSourceOffset, targetRect.size()), bytesPerLine / bytesPerPixel); updateContentsNoSwizzle(data, targetRect, adjustedSourceOffset, bytesPerLine, bytesPerPixel, glFormat); } @@ -766,7 +912,7 @@ void BitmapTextureGL::updateContents(Image* image, const IntRect& targetRect, co imageData = reinterpret_cast<const char*>(qImage.constBits()); bytesPerLine = qImage.bytesPerLine(); #elif USE(CAIRO) - cairo_surface_t* surface = frameImage->surface(); + cairo_surface_t* surface = frameImage.get(); imageData = reinterpret_cast<const char*>(cairo_image_surface_get_data(surface)); bytesPerLine = cairo_image_surface_get_stride(surface); #endif @@ -774,154 +920,6 @@ void BitmapTextureGL::updateContents(Image* image, const IntRect& targetRect, co updateContents(imageData, targetRect, offset, bytesPerLine, updateContentsFlag); } -#if ENABLE(CSS_FILTERS) - -static TextureMapperShaderManager::ShaderKey keyForFilterType(FilterOperation::OperationType type, unsigned pass) -{ - switch (type) { - case FilterOperation::GRAYSCALE: - return TextureMapperShaderManager::GrayscaleFilter; - case FilterOperation::SEPIA: - return TextureMapperShaderManager::SepiaFilter; - case FilterOperation::SATURATE: - return TextureMapperShaderManager::SaturateFilter; - case FilterOperation::HUE_ROTATE: - return TextureMapperShaderManager::HueRotateFilter; - case FilterOperation::INVERT: - return TextureMapperShaderManager::InvertFilter; - case FilterOperation::BRIGHTNESS: - return TextureMapperShaderManager::BrightnessFilter; - case FilterOperation::CONTRAST: - return TextureMapperShaderManager::ContrastFilter; - case FilterOperation::OPACITY: - return TextureMapperShaderManager::OpacityFilter; - case FilterOperation::BLUR: - return TextureMapperShaderManager::BlurFilter; - case FilterOperation::DROP_SHADOW: - return pass ? TextureMapperShaderManager::ShadowFilterPass2 : TextureMapperShaderManager::ShadowFilterPass1; - default: - ASSERT_NOT_REACHED(); - return TextureMapperShaderManager::Invalid; - } -} - -static unsigned getPassesRequiredForFilter(FilterOperation::OperationType type) -{ - switch (type) { - case FilterOperation::GRAYSCALE: - case FilterOperation::SEPIA: - case FilterOperation::SATURATE: - case FilterOperation::HUE_ROTATE: - case FilterOperation::INVERT: - case FilterOperation::BRIGHTNESS: - case FilterOperation::CONTRAST: - case FilterOperation::OPACITY: -#if ENABLE(CSS_SHADERS) - case FilterOperation::CUSTOM: - case FilterOperation::VALIDATED_CUSTOM: -#endif - return 1; - case FilterOperation::BLUR: - case FilterOperation::DROP_SHADOW: - // We use two-passes (vertical+horizontal) for blur and drop-shadow. - return 2; - default: - return 0; - } -} - -// Create a normal distribution of 21 values between -2 and 2. -static const unsigned GaussianKernelHalfWidth = 11; -static const float GaussianKernelStep = 0.2; - -static inline float gauss(float x) -{ - return exp(-(x * x) / 2.); -} - -static float* gaussianKernel() -{ - static bool prepared = false; - static float kernel[GaussianKernelHalfWidth] = {0, }; - - if (prepared) - return kernel; - - kernel[0] = gauss(0); - float sum = kernel[0]; - for (unsigned i = 1; i < GaussianKernelHalfWidth; ++i) { - kernel[i] = gauss(i * GaussianKernelStep); - sum += 2 * kernel[i]; - } - - // Normalize the kernel. - float scale = 1 / sum; - for (unsigned i = 0; i < GaussianKernelHalfWidth; ++i) - kernel[i] *= scale; - - prepared = true; - return kernel; -} - -static void prepareFilterProgram(TextureMapperShaderProgram* program, const FilterOperation& operation, unsigned pass, const IntSize& size, GC3Duint contentTexture) -{ - RefPtr<GraphicsContext3D> context = program->context(); - context->useProgram(program->programID()); - - switch (operation.getOperationType()) { - case FilterOperation::GRAYSCALE: - case FilterOperation::SEPIA: - case FilterOperation::SATURATE: - case FilterOperation::HUE_ROTATE: - context->uniform1f(program->amountLocation(), static_cast<const BasicColorMatrixFilterOperation&>(operation).amount()); - break; - case FilterOperation::INVERT: - case FilterOperation::BRIGHTNESS: - case FilterOperation::CONTRAST: - case FilterOperation::OPACITY: - context->uniform1f(program->amountLocation(), static_cast<const BasicComponentTransferFilterOperation&>(operation).amount()); - break; - case FilterOperation::BLUR: { - const BlurFilterOperation& blur = static_cast<const BlurFilterOperation&>(operation); - FloatSize radius; - - // Blur is done in two passes, first horizontally and then vertically. The same shader is used for both. - if (pass) - radius.setHeight(floatValueForLength(blur.stdDeviation(), size.height()) / size.height()); - else - radius.setWidth(floatValueForLength(blur.stdDeviation(), size.width()) / size.width()); - - context->uniform2f(program->blurRadiusLocation(), radius.width(), radius.height()); - context->uniform1fv(program->gaussianKernelLocation(), GaussianKernelHalfWidth, gaussianKernel()); - break; - } - case FilterOperation::DROP_SHADOW: { - const DropShadowFilterOperation& shadow = static_cast<const DropShadowFilterOperation&>(operation); - context->uniform1fv(program->gaussianKernelLocation(), GaussianKernelHalfWidth, gaussianKernel()); - switch (pass) { - case 0: - // First pass: vertical alpha blur. - context->uniform2f(program->shadowOffsetLocation(), float(shadow.location().x()) / float(size.width()), float(shadow.location().y()) / float(size.height())); - context->uniform1f(program->blurRadiusLocation(), shadow.stdDeviation() / float(size.width())); - break; - case 1: - // Second pass: we need the shadow color and the content texture for compositing. - context->uniform1f(program->blurRadiusLocation(), shadow.stdDeviation() / float(size.height())); - context->activeTexture(GraphicsContext3D::TEXTURE1); - context->bindTexture(GraphicsContext3D::TEXTURE_2D, contentTexture); - context->uniform1i(program->contentTextureLocation(), 1); - float r, g, b, a; - shadow.color().getRGBA(r, g, b, a); - context->uniform4f(program->shadowColorLocation(), r, g, b, a); - break; - } - break; - } - default: - break; - } -} - #if ENABLE(CSS_SHADERS) void TextureMapperGL::removeCachedCustomFilterProgram(CustomFilterProgram* program) { @@ -938,15 +936,11 @@ bool TextureMapperGL::drawUsingCustomFilter(BitmapTexture& target, const BitmapT const CustomFilterOperation* customFilter = static_cast<const CustomFilterOperation*>(&filter); RefPtr<CustomFilterProgram> program = customFilter->program(); renderer = CustomFilterRenderer::create(m_context3D, program->programType(), customFilter->parameters(), - customFilter->meshRows(), customFilter->meshColumns(), customFilter->meshBoxType(), customFilter->meshType()); - RefPtr<CustomFilterCompiledProgram> compiledProgram; - CustomFilterProgramMap::iterator iter = m_customFilterPrograms.find(program->programInfo()); - if (iter == m_customFilterPrograms.end()) { - compiledProgram = CustomFilterCompiledProgram::create(m_context3D, program->vertexShaderString(), program->fragmentShaderString(), program->programType()); - m_customFilterPrograms.set(program->programInfo(), compiledProgram); - } else - compiledProgram = iter->value; - renderer->setCompiledProgram(compiledProgram.release()); + customFilter->meshRows(), customFilter->meshColumns(), customFilter->meshType()); + CustomFilterProgramMap::AddResult result = m_customFilterPrograms.add(program->programInfo(), 0); + if (result.isNewEntry) + result.iterator->value = CustomFilterCompiledProgram::create(m_context3D, program->vertexShaderString(), program->fragmentShaderString(), program->programType()); + renderer->setCompiledProgram(result.iterator->value); break; } case FilterOperation::VALIDATED_CUSTOM: { @@ -954,15 +948,12 @@ bool TextureMapperGL::drawUsingCustomFilter(BitmapTexture& target, const BitmapT const ValidatedCustomFilterOperation* customFilter = static_cast<const ValidatedCustomFilterOperation*>(&filter); RefPtr<CustomFilterValidatedProgram> program = customFilter->validatedProgram(); renderer = CustomFilterRenderer::create(m_context3D, program->programInfo().programType(), customFilter->parameters(), - customFilter->meshRows(), customFilter->meshColumns(), customFilter->meshBoxType(), customFilter->meshType()); + customFilter->meshRows(), customFilter->meshColumns(), customFilter->meshType()); RefPtr<CustomFilterCompiledProgram> compiledProgram; - CustomFilterProgramMap::iterator iter = m_customFilterPrograms.find(program->programInfo()); - if (iter == m_customFilterPrograms.end()) { - compiledProgram = CustomFilterCompiledProgram::create(m_context3D, program->validatedVertexShader(), program->validatedFragmentShader(), program->programInfo().programType()); - m_customFilterPrograms.set(program->programInfo(), compiledProgram); - } else - compiledProgram = iter->value; - renderer->setCompiledProgram(compiledProgram.release()); + CustomFilterProgramMap::AddResult result = m_customFilterPrograms.add(program->programInfo(), 0); + if (result.isNewEntry) + result.iterator->value = CustomFilterCompiledProgram::create(m_context3D, program->validatedVertexShader(), program->validatedFragmentShader(), program->programInfo().programType()); + renderer->setCompiledProgram(result.iterator->value); break; } default: @@ -988,65 +979,79 @@ bool TextureMapperGL::drawUsingCustomFilter(BitmapTexture& target, const BitmapT } #endif -void TextureMapperGL::drawFiltered(const BitmapTexture& sampler, const BitmapTexture& contentTexture, const FilterOperation& filter, int pass) +#if ENABLE(CSS_FILTERS) +void TextureMapperGL::drawFiltered(const BitmapTexture& sampler, const BitmapTexture* contentTexture, const FilterOperation& filter, int pass) { // For standard filters, we always draw the whole texture without transformations. - TextureMapperShaderManager::ShaderKey key = keyForFilterType(filter.getOperationType(), pass); - RefPtr<TextureMapperShaderProgram> program = data().sharedGLData().textureMapperShaderManager.getShaderProgram(key); + TextureMapperShaderProgram::Options options = optionsForFilterType(filter.getOperationType(), pass); + RefPtr<TextureMapperShaderProgram> program = data().sharedGLData().getShaderProgram(options); ASSERT(program); - prepareFilterProgram(program.get(), filter, pass, sampler.contentSize(), static_cast<const BitmapTextureGL&>(contentTexture).id()); + prepareFilterProgram(program.get(), filter, pass, sampler.contentSize(), contentTexture ? static_cast<const BitmapTextureGL*>(contentTexture)->id() : 0); + FloatRect targetRect(IntPoint::zero(), sampler.contentSize()); + drawTexturedQuadWithProgram(program.get(), static_cast<const BitmapTextureGL&>(sampler).id(), 0, IntSize(1, 1), targetRect, TransformationMatrix(), 1); +} - m_context3D->enableVertexAttribArray(program->vertexLocation()); - m_context3D->enableVertexAttribArray(program->texCoordLocation()); - m_context3D->activeTexture(GraphicsContext3D::TEXTURE0); - m_context3D->bindTexture(GraphicsContext3D::TEXTURE_2D, static_cast<const BitmapTextureGL&>(sampler).id()); - m_context3D->uniform1i(program->samplerLocation(), 0); - const GC3Dfloat targetVertices[] = {-1, -1, 1, -1, 1, 1, -1, 1}; - const GC3Dfloat sourceVertices[] = {0, 0, 1, 0, 1, 1, 0, 1}; - m_context3D->vertexAttribPointer(program->vertexLocation(), 2, GraphicsContext3D::FLOAT, false, 0, GC3Dintptr(targetVertices)); - m_context3D->vertexAttribPointer(program->texCoordLocation(), 2, GraphicsContext3D::FLOAT, false, 0, GC3Dintptr(sourceVertices)); - m_context3D->disable(GraphicsContext3D::BLEND); - m_context3D->drawArrays(GraphicsContext3D::TRIANGLE_FAN, 0, 4); - m_context3D->disableVertexAttribArray(program->vertexLocation()); - m_context3D->disableVertexAttribArray(program->texCoordLocation()); +static bool isCustomFilter(FilterOperation::OperationType type) +{ +#if ENABLE(CSS_SHADERS) + return type == FilterOperation::CUSTOM || type == FilterOperation::VALIDATED_CUSTOM; +#else + return false; +#endif } -PassRefPtr<BitmapTexture> BitmapTextureGL::applyFilters(TextureMapper* textureMapper, const BitmapTexture& contentTexture, const FilterOperations& filters) +PassRefPtr<BitmapTexture> BitmapTextureGL::applyFilters(TextureMapper* textureMapper, const FilterOperations& filters) { - TextureMapperGL* textureMapperGL = static_cast<TextureMapperGL*>(textureMapper); - RefPtr<BitmapTexture> previousSurface = textureMapperGL->data().currentSurface; + if (filters.isEmpty()) + return this; + + TextureMapperGL* texmapGL = static_cast<TextureMapperGL*>(textureMapper); + RefPtr<BitmapTexture> previousSurface = texmapGL->data().currentSurface; + RefPtr<BitmapTexture> resultSurface = this; + RefPtr<BitmapTexture> intermediateSurface; + RefPtr<BitmapTexture> spareSurface; - RefPtr<BitmapTexture> source = this; - RefPtr<BitmapTexture> target = textureMapper->acquireTextureFromPool(m_textureSize); + m_filterInfo = FilterInfo(); - bool useContentTexture = true; for (size_t i = 0; i < filters.size(); ++i) { - const FilterOperation* filter = filters.at(i); + RefPtr<FilterOperation> filter = filters.operations()[i]; ASSERT(filter); + bool custom = isCustomFilter(filter->getOperationType()); + int numPasses = getPassesRequiredForFilter(filter->getOperationType()); for (int j = 0; j < numPasses; ++j) { - textureMapperGL->bindSurface(target.get()); - const BitmapTexture& sourceTexture = useContentTexture ? contentTexture : *source; + bool last = (i == filters.size() - 1) && (j == numPasses - 1); + if (custom || !last) { + if (!intermediateSurface) + intermediateSurface = texmapGL->acquireTextureFromPool(contentSize()); + texmapGL->bindSurface(intermediateSurface.get()); + } + #if ENABLE(CSS_SHADERS) - if (filter->getOperationType() == FilterOperation::CUSTOM || filter->getOperationType() == FilterOperation::VALIDATED_CUSTOM) { - if (textureMapperGL->drawUsingCustomFilter(*target, sourceTexture, *filter)) { - // Only swap if the draw was successful. - std::swap(source, target); - useContentTexture = false; - } + if (custom) { + if (texmapGL->drawUsingCustomFilter(*intermediateSurface.get(), *resultSurface.get(), *filter)) + std::swap(resultSurface, intermediateSurface); continue; } #endif - textureMapperGL->drawFiltered(sourceTexture, contentTexture, *filter, j); - std::swap(source, target); - useContentTexture = false; + if (last) { + toBitmapTextureGL(resultSurface.get())->m_filterInfo = BitmapTextureGL::FilterInfo(filter, j, spareSurface); + break; + } + + texmapGL->drawFiltered(*resultSurface.get(), spareSurface.get(), *filter, j); + if (!j && filter->getOperationType() == FilterOperation::DROP_SHADOW) { + spareSurface = resultSurface; + resultSurface.clear(); + } + std::swap(resultSurface, intermediateSurface); } } - textureMapperGL->bindSurface(previousSurface.get()); - return source; + texmapGL->bindSurface(previousSurface.get()); + return resultSurface; } #endif @@ -1096,8 +1101,8 @@ void BitmapTextureGL::clearIfNeeded() if (!m_shouldClear) return; - m_clipStack.init(IntRect(IntPoint::zero(), m_textureSize)); - m_clipStack.apply(m_context3D.get()); + m_clipStack.reset(IntRect(IntPoint::zero(), m_textureSize), TextureMapperGL::ClipStack::DefaultYAxis); + m_clipStack.applyIfNeeded(m_context3D.get()); m_context3D->clearColor(0, 0, 0, 0); m_context3D->clear(GraphicsContext3D::COLOR_BUFFER_BIT); m_shouldClear = false; @@ -1190,8 +1195,8 @@ bool TextureMapperGL::beginScissorClip(const TransformationMatrix& modelViewMatr if (!quad.isRectilinear() || rect.isEmpty()) return false; - clipStack().current().scissorBox.intersect(rect); - clipStack().apply(m_context3D.get()); + clipStack().intersect(rect); + clipStack().applyIfNeeded(m_context3D.get()); return true; } @@ -1203,35 +1208,19 @@ void TextureMapperGL::beginClip(const TransformationMatrix& modelViewMatrix, con data().initializeStencil(); - RefPtr<TextureMapperShaderProgram> program = data().sharedGLData().textureMapperShaderManager.getShaderProgram(TextureMapperShaderManager::Default); + RefPtr<TextureMapperShaderProgram> program = data().sharedGLData().getShaderProgram(TextureMapperShaderProgram::SolidColor); m_context3D->useProgram(program->programID()); m_context3D->enableVertexAttribArray(program->vertexLocation()); const GC3Dfloat unitRect[] = {0, 0, 1, 0, 1, 1, 0, 1}; m_context3D->vertexAttribPointer(program->vertexLocation(), 2, GraphicsContext3D::FLOAT, false, 0, GC3Dintptr(unitRect)); - TransformationMatrix matrix = TransformationMatrix(data().projectionMatrix) - .multiply(modelViewMatrix) - .multiply(TransformationMatrix(targetRect.width(), 0, 0, 0, - 0, targetRect.height(), 0, 0, - 0, 0, 1, 0, - targetRect.x(), targetRect.y(), 0, 1)); - - const GC3Dfloat m4[] = { - matrix.m11(), matrix.m12(), matrix.m13(), matrix.m14(), - matrix.m21(), matrix.m22(), matrix.m23(), matrix.m24(), - matrix.m31(), matrix.m32(), matrix.m33(), matrix.m34(), - matrix.m41(), matrix.m42(), matrix.m43(), matrix.m44() - }; + TransformationMatrix matrix = TransformationMatrix(modelViewMatrix) + .multiply(TransformationMatrix::rectToRect(FloatRect(0, 0, 1, 1), targetRect)); - const GC3Dfloat m4all[] = { - 2, 0, 0, 0, - 0, 2, 0, 0, - 0, 0, 1, 0, - -1, -1, 0, 1 - }; + static const TransformationMatrix fullProjectionMatrix = TransformationMatrix::rectToRect(FloatRect(0, 0, 1, 1), FloatRect(-1, -1, 2, 2)); - int& stencilIndex = clipStack().current().stencilIndex; + int stencilIndex = clipStack().getStencilIndex(); m_context3D->enable(GraphicsContext3D::STENCIL_TEST); @@ -1242,13 +1231,15 @@ void TextureMapperGL::beginClip(const TransformationMatrix& modelViewMatrix, con m_context3D->stencilMask(0xff & ~(stencilIndex - 1)); // First clear the entire buffer at the current index. - m_context3D->uniformMatrix4fv(program->matrixLocation(), 1, false, const_cast<GC3Dfloat*>(m4all)); + program->setMatrix(program->projectionMatrixLocation(), fullProjectionMatrix); + program->setMatrix(program->modelViewMatrixLocation(), TransformationMatrix()); m_context3D->stencilOp(GraphicsContext3D::ZERO, GraphicsContext3D::ZERO, GraphicsContext3D::ZERO); m_context3D->drawArrays(GraphicsContext3D::TRIANGLE_FAN, 0, 4); // Now apply the current index to the new quad. m_context3D->stencilOp(GraphicsContext3D::REPLACE, GraphicsContext3D::REPLACE, GraphicsContext3D::REPLACE); - m_context3D->uniformMatrix4fv(program->matrixLocation(), 1, false, const_cast<GC3Dfloat*>(m4)); + program->setMatrix(program->projectionMatrixLocation(), data().projectionMatrix); + program->setMatrix(program->modelViewMatrixLocation(), matrix); m_context3D->drawArrays(GraphicsContext3D::TRIANGLE_FAN, 0, 4); // Clear the state. @@ -1256,14 +1247,19 @@ void TextureMapperGL::beginClip(const TransformationMatrix& modelViewMatrix, con m_context3D->stencilMask(0); // Increase stencilIndex and apply stencil testing. - stencilIndex *= 2; - clipStack().apply(m_context3D.get()); + clipStack().setStencilIndex(stencilIndex * 2); + clipStack().applyIfNeeded(m_context3D.get()); } void TextureMapperGL::endClip() { clipStack().pop(); - clipStack().apply(m_context3D.get()); + clipStack().applyIfNeeded(m_context3D.get()); +} + +IntRect TextureMapperGL::clipBounds() +{ + return clipStack().current().scissorBox; } PassRefPtr<BitmapTexture> TextureMapperGL::createTexture() @@ -1278,3 +1274,4 @@ PassOwnPtr<TextureMapper> TextureMapper::platformCreateAccelerated() } }; +#endif diff --git a/Source/WebCore/platform/graphics/texmap/TextureMapperGL.h b/Source/WebCore/platform/graphics/texmap/TextureMapperGL.h index cc556e4b1..18a5c4d6f 100644 --- a/Source/WebCore/platform/graphics/texmap/TextureMapperGL.h +++ b/Source/WebCore/platform/graphics/texmap/TextureMapperGL.h @@ -20,9 +20,10 @@ #ifndef TextureMapperGL_h #define TextureMapperGL_h -#if USE(ACCELERATED_COMPOSITING) +#if USE(ACCELERATED_COMPOSITING) && USE(TEXTURE_MAPPER) #include "CustomFilterProgramInfo.h" +#include "FilterOperation.h" #include "FloatQuad.h" #include "GraphicsContext3D.h" #include "IntSize.h" @@ -34,8 +35,8 @@ namespace WebCore { class CustomFilterProgram; class CustomFilterCompiledProgram; class TextureMapperGLData; -class GraphicsContext; class TextureMapperShaderProgram; +class FilterOperation; // An OpenGL-ES2 implementation of TextureMapper. class TextureMapperGL : public TextureMapper { @@ -44,36 +45,33 @@ public: virtual ~TextureMapperGL(); enum Flag { - SupportsBlending = 0x01, - ShouldFlipTexture = 0x02 + ShouldBlend = 0x01, + ShouldFlipTexture = 0x02, + ShouldUseARBTextureRect = 0x04, + ShouldAntialias = 0x08 }; typedef int Flags; // TextureMapper implementation - virtual void drawBorder(const Color&, float borderWidth, const FloatRect& targetRect, const TransformationMatrix& modelViewMatrix = TransformationMatrix()) OVERRIDE; - virtual void drawRepaintCounter(int value, int pointSize, const FloatPoint&, const TransformationMatrix& modelViewMatrix = TransformationMatrix()) OVERRIDE; - virtual void drawTexture(const BitmapTexture&, const FloatRect&, const TransformationMatrix&, float opacity, const BitmapTexture* maskTexture, unsigned exposedEdges) OVERRIDE; - virtual void drawTexture(uint32_t texture, Flags, const IntSize& textureSize, const FloatRect& targetRect, const TransformationMatrix& modelViewMatrix, float opacity, const BitmapTexture* maskTexture, unsigned exposedEdges = AllEdges); + virtual void drawBorder(const Color&, float borderWidth, const FloatRect&, const TransformationMatrix&) OVERRIDE; + virtual void drawNumber(int number, const Color&, const FloatPoint&, const TransformationMatrix&) OVERRIDE; + virtual void drawTexture(const BitmapTexture&, const FloatRect&, const TransformationMatrix&, float opacity, unsigned exposedEdges) OVERRIDE; + virtual void drawTexture(Platform3DObject texture, Flags, const IntSize& textureSize, const FloatRect& targetRect, const TransformationMatrix& modelViewMatrix, float opacity, unsigned exposedEdges = AllEdges); virtual void drawSolidColor(const FloatRect&, const TransformationMatrix&, const Color&) OVERRIDE; -#if !USE(TEXMAP_OPENGL_ES_2) - virtual void drawTextureRectangleARB(uint32_t texture, Flags, const IntSize& textureSize, const FloatRect& targetRect, const TransformationMatrix& modelViewMatrix, float opacity, const BitmapTexture* maskTexture); -#endif - virtual void bindSurface(BitmapTexture* surface) OVERRIDE; virtual void beginClip(const TransformationMatrix&, const FloatRect&) OVERRIDE; virtual void beginPainting(PaintFlags = 0) OVERRIDE; virtual void endPainting() OVERRIDE; virtual void endClip() OVERRIDE; + virtual IntRect clipBounds() OVERRIDE; virtual IntSize maxTextureSize() const OVERRIDE { return IntSize(2000, 2000); } virtual PassRefPtr<BitmapTexture> createTexture() OVERRIDE; - virtual GraphicsContext* graphicsContext() OVERRIDE { return m_context; } inline GraphicsContext3D* graphicsContext3D() const { return m_context3D.get(); } - virtual void setGraphicsContext(GraphicsContext* context) OVERRIDE { m_context = context; } #if ENABLE(CSS_FILTERS) - void drawFiltered(const BitmapTexture& sourceTexture, const BitmapTexture& contentTexture, const FilterOperation&, int pass); + void drawFiltered(const BitmapTexture& sourceTexture, const BitmapTexture* contentTexture, const FilterOperation&, int pass); #endif #if ENABLE(CSS_SHADERS) bool drawUsingCustomFilter(BitmapTexture& targetTexture, const BitmapTexture& sourceTexture, const FilterOperation&); @@ -94,39 +92,53 @@ private: class ClipStack { public: + ClipStack() + : clipStateDirty(false) + { } + + // Y-axis should be inverted only when painting into the window. + enum YAxisMode { + DefaultYAxis, + InvertedYAxis + }; + void push(); void pop(); void apply(GraphicsContext3D*); + void applyIfNeeded(GraphicsContext3D*); inline ClipState& current() { return clipState; } - void init(const IntRect&); + void reset(const IntRect&, YAxisMode); + void intersect(const IntRect&); + void setStencilIndex(int); + inline int getStencilIndex() const + { + return clipState.stencilIndex; + } + inline bool isCurrentScissorBoxEmpty() const + { + return clipState.scissorBox.isEmpty(); + } private: ClipState clipState; Vector<ClipState> clipStack; - }; - - struct DrawQuad { - DrawQuad(const FloatRect& originalTargetRect, const FloatQuad& targetRectMappedToUnitSquare = FloatRect(FloatPoint(), FloatSize(1, 1))) - : originalTargetRect(originalTargetRect) - , targetRectMappedToUnitSquare(targetRectMappedToUnitSquare) - { - } - - FloatRect originalTargetRect; - FloatQuad targetRectMappedToUnitSquare; + bool clipStateDirty; + IntSize size; + YAxisMode yAxisMode; }; TextureMapperGL(); - bool drawTextureWithAntialiasing(uint32_t texture, Flags, const FloatRect& originalTargetRect, const TransformationMatrix& modelViewMatrix, float opacity, const BitmapTexture* maskTexture, unsigned exposedEdges); - void drawTexturedQuadWithProgram(TextureMapperShaderProgram*, uint32_t texture, Flags, const DrawQuad&, const TransformationMatrix& modelViewMatrix, float opacity, const BitmapTexture* maskTexture); - void drawQuad(const DrawQuad&, const TransformationMatrix& modelViewMatrix, TextureMapperShaderProgram*, GC3Denum drawingMode, bool needsBlending); + void drawTexturedQuadWithProgram(TextureMapperShaderProgram*, uint32_t texture, Flags, const IntSize&, const FloatRect&, const TransformationMatrix& modelViewMatrix, float opacity); + void draw(const FloatRect&, const TransformationMatrix& modelViewMatrix, TextureMapperShaderProgram*, GC3Denum drawingMode, Flags); + + void drawUnitRect(TextureMapperShaderProgram*, GC3Denum drawingMode); + void drawEdgeTriangles(TextureMapperShaderProgram*); bool beginScissorClip(const TransformationMatrix&, const FloatRect&); void bindDefaultSurface(); ClipStack& clipStack(); inline TextureMapperGLData& data() { return *m_data; } - GraphicsContext* m_context; RefPtr<GraphicsContext3D> m_context3D; TextureMapperGLData* m_data; ClipStack m_clipStack; @@ -158,7 +170,19 @@ public: virtual bool isBackedByOpenGL() const { return true; } #if ENABLE(CSS_FILTERS) - virtual PassRefPtr<BitmapTexture> applyFilters(TextureMapper*, const BitmapTexture& contentTexture, const FilterOperations&); + virtual PassRefPtr<BitmapTexture> applyFilters(TextureMapper*, const FilterOperations&) OVERRIDE; + struct FilterInfo { + RefPtr<FilterOperation> filter; + unsigned pass; + RefPtr<BitmapTexture> contentTexture; + + FilterInfo(PassRefPtr<FilterOperation> f = 0, unsigned p = 0, PassRefPtr<BitmapTexture> t = 0) + : filter(f) + , pass(p) + , contentTexture(t) + { } + }; + const FilterInfo* filterInfo() const { return &m_filterInfo; } #endif private: @@ -180,6 +204,10 @@ private: void clearIfNeeded(); void createFboIfNeeded(); +#if ENABLE(CSS_FILTERS) + FilterInfo m_filterInfo; +#endif + friend class TextureMapperGL; }; diff --git a/Source/WebCore/platform/graphics/texmap/TextureMapperImageBuffer.cpp b/Source/WebCore/platform/graphics/texmap/TextureMapperImageBuffer.cpp index e01ed3d9f..03273ba0f 100644 --- a/Source/WebCore/platform/graphics/texmap/TextureMapperImageBuffer.cpp +++ b/Source/WebCore/platform/graphics/texmap/TextureMapperImageBuffer.cpp @@ -20,11 +20,11 @@ #include "config.h" #include "TextureMapperImageBuffer.h" -#include "FilterEffectRenderer.h" #include "GraphicsLayer.h" #if PLATFORM(QT) #include "NativeImageQt.h" #endif +#include "NotImplemented.h" #if USE(TEXTURE_MAPPER) @@ -57,7 +57,7 @@ void BitmapTextureImageBuffer::updateContents(const void* data, const IntRect& t #endif } -void BitmapTextureImageBuffer::updateContents(TextureMapper* textureMapper, GraphicsLayer* sourceLayer, const IntRect& targetRect, const IntPoint& sourceOffset, UpdateContentsFlag) +void BitmapTextureImageBuffer::updateContents(TextureMapper*, GraphicsLayer* sourceLayer, const IntRect& targetRect, const IntPoint& sourceOffset, UpdateContentsFlag) { GraphicsContext* context = m_image->context(); @@ -66,6 +66,7 @@ void BitmapTextureImageBuffer::updateContents(TextureMapper* textureMapper, Grap IntRect sourceRect(targetRect); sourceRect.setLocation(sourceOffset); context->save(); + context->clip(targetRect); context->translate(targetRect.x() - sourceOffset.x(), targetRect.y() - sourceOffset.y()); sourceLayer->paintGraphicsLayerContents(*context, sourceRect); context->restore(); @@ -113,7 +114,7 @@ void TextureMapperImageBuffer::beginClip(const TransformationMatrix& matrix, con #endif } -void TextureMapperImageBuffer::drawTexture(const BitmapTexture& texture, const FloatRect& targetRect, const TransformationMatrix& matrix, float opacity, const BitmapTexture* maskTexture, unsigned /* exposedEdges */) +void TextureMapperImageBuffer::drawTexture(const BitmapTexture& texture, const FloatRect& targetRect, const TransformationMatrix& matrix, float opacity, unsigned /* exposedEdges */) { GraphicsContext* context = currentContext(); if (!context) @@ -121,22 +122,8 @@ void TextureMapperImageBuffer::drawTexture(const BitmapTexture& texture, const F const BitmapTextureImageBuffer& textureImageBuffer = static_cast<const BitmapTextureImageBuffer&>(texture); ImageBuffer* image = textureImageBuffer.m_image.get(); - OwnPtr<ImageBuffer> maskedImage; - - if (maskTexture && maskTexture->isValid()) { - const BitmapTextureImageBuffer* mask = static_cast<const BitmapTextureImageBuffer*>(maskTexture); - maskedImage = ImageBuffer::create(maskTexture->contentSize()); - GraphicsContext* maskContext = maskedImage->context(); - maskContext->drawImageBuffer(image, ColorSpaceDeviceRGB, IntPoint::zero(), CompositeCopy); - if (opacity < 1) { - maskContext->setAlpha(opacity); - opacity = 1; - } - maskContext->drawImageBuffer(mask->m_image.get(), ColorSpaceDeviceRGB, IntPoint::zero(), CompositeDestinationIn); - image = maskedImage.get(); - } - context->save(); + context->setCompositeOperation(isInMaskMode() ? CompositeDestinationIn : CompositeSourceOver); context->setAlpha(opacity); #if ENABLE(3D_RENDERING) context->concat3DTransform(matrix); @@ -154,6 +141,7 @@ void TextureMapperImageBuffer::drawSolidColor(const FloatRect& rect, const Trans return; context->save(); + context->setCompositeOperation(isInMaskMode() ? CompositeDestinationIn : CompositeSourceOver); #if ENABLE(3D_RENDERING) context->concat3DTransform(matrix); #else @@ -164,20 +152,19 @@ void TextureMapperImageBuffer::drawSolidColor(const FloatRect& rect, const Trans context->restore(); } +void TextureMapperImageBuffer::drawBorder(const Color&, float /* borderWidth */, const FloatRect&, const TransformationMatrix&) +{ + notImplemented(); +} + +void TextureMapperImageBuffer::drawNumber(int /* number */, const Color&, const FloatPoint&, const TransformationMatrix&) +{ + notImplemented(); +} + #if ENABLE(CSS_FILTERS) -PassRefPtr<BitmapTexture> BitmapTextureImageBuffer::applyFilters(TextureMapper*, const BitmapTexture& contentTexture, const FilterOperations& filters) +PassRefPtr<BitmapTexture> BitmapTextureImageBuffer::applyFilters(TextureMapper*, const FilterOperations&) { - RefPtr<FilterEffectRenderer> renderer = FilterEffectRenderer::create(); - renderer->setSourceImageRect(FloatRect(FloatPoint::zero(), contentTexture.size())); - - // The document parameter is only needed for CSS shaders. - if (renderer->build(0 /*document */, filters)) { - renderer->allocateBackingStoreIfNeeded(); - GraphicsContext* context = renderer->inputContext(); - context->drawImageBuffer(static_cast<const BitmapTextureImageBuffer&>(contentTexture).m_image.get(), ColorSpaceDeviceRGB, IntPoint::zero()); - renderer->apply(); - m_image->context()->drawImageBuffer(renderer->output(), ColorSpaceDeviceRGB, renderer->outputRect()); - } return this; } #endif diff --git a/Source/WebCore/platform/graphics/texmap/TextureMapperImageBuffer.h b/Source/WebCore/platform/graphics/texmap/TextureMapperImageBuffer.h index 9de6d4cbd..060713ce5 100644 --- a/Source/WebCore/platform/graphics/texmap/TextureMapperImageBuffer.h +++ b/Source/WebCore/platform/graphics/texmap/TextureMapperImageBuffer.h @@ -38,7 +38,7 @@ public: virtual void updateContents(TextureMapper*, GraphicsLayer*, const IntRect& target, const IntPoint& offset, UpdateContentsFlag); virtual void updateContents(const void*, const IntRect& target, const IntPoint& sourceOffset, int bytesPerLine, UpdateContentsFlag); #if ENABLE(CSS_FILTERS) - PassRefPtr<BitmapTexture> applyFilters(TextureMapper*, const BitmapTexture&, const FilterOperations&); + PassRefPtr<BitmapTexture> applyFilters(TextureMapper*, const FilterOperations&); #endif private: @@ -53,19 +53,14 @@ public: static PassOwnPtr<TextureMapper> create() { return adoptPtr(new TextureMapperImageBuffer); } // TextureMapper implementation - virtual void drawBorder(const Color&, float /* borderWidth */, const FloatRect& /* targetRect */, const TransformationMatrix& modelViewMatrix = TransformationMatrix()) OVERRIDE - { - UNUSED_PARAM(modelViewMatrix); - }; - virtual void drawRepaintCounter(int /* value */, int /* pointSize */, const FloatPoint&, const TransformationMatrix& modelViewMatrix = TransformationMatrix()) OVERRIDE - { - UNUSED_PARAM(modelViewMatrix); - }; - virtual void drawTexture(const BitmapTexture&, const FloatRect& targetRect, const TransformationMatrix&, float opacity, const BitmapTexture* maskTexture, unsigned exposedEdges) OVERRIDE; + virtual void drawBorder(const Color&, float borderWidth, const FloatRect&, const TransformationMatrix&) OVERRIDE; + virtual void drawNumber(int number, const Color&, const FloatPoint&, const TransformationMatrix&) OVERRIDE; + virtual void drawTexture(const BitmapTexture&, const FloatRect& targetRect, const TransformationMatrix&, float opacity, unsigned exposedEdges) OVERRIDE; virtual void drawSolidColor(const FloatRect&, const TransformationMatrix&, const Color&) OVERRIDE; virtual void beginClip(const TransformationMatrix&, const FloatRect&) OVERRIDE; virtual void bindSurface(BitmapTexture* surface) OVERRIDE { m_currentSurface = surface;} virtual void endClip() OVERRIDE { graphicsContext()->restore(); } + virtual IntRect clipBounds() OVERRIDE { return currentContext()->clipBounds(); } virtual IntSize maxTextureSize() const; virtual PassRefPtr<BitmapTexture> createTexture() OVERRIDE { return BitmapTextureImageBuffer::create(); } diff --git a/Source/WebCore/platform/graphics/texmap/TextureMapperLayer.cpp b/Source/WebCore/platform/graphics/texmap/TextureMapperLayer.cpp index 40243335b..80c253543 100644 --- a/Source/WebCore/platform/graphics/texmap/TextureMapperLayer.cpp +++ b/Source/WebCore/platform/graphics/texmap/TextureMapperLayer.cpp @@ -20,16 +20,26 @@ #include "config.h" #include "TextureMapperLayer.h" -#if USE(ACCELERATED_COMPOSITING) +#include "FloatQuad.h" +#include "Region.h" +#include <wtf/MathExtras.h> -#include "GraphicsLayerTextureMapper.h" +#if USE(ACCELERATED_COMPOSITING) && USE(TEXTURE_MAPPER) namespace WebCore { -TextureMapperLayer* toTextureMapperLayer(GraphicsLayer* layer) -{ - return layer ? toGraphicsLayerTextureMapper(layer)->layer() : 0; -} +class TextureMapperPaintOptions { +public: + RefPtr<BitmapTexture> surface; + float opacity; + TransformationMatrix transform; + IntSize offset; + TextureMapper* textureMapper; + TextureMapperPaintOptions() + : opacity(1) + , textureMapper(0) + { } +}; const TextureMapperLayer* TextureMapperLayer::rootLayer() const { @@ -40,38 +50,23 @@ const TextureMapperLayer* TextureMapperLayer::rootLayer() const return this; } -void TextureMapperLayer::setTransform(const TransformationMatrix& matrix) -{ - m_transform.setLocalTransform(matrix); -} - -void TextureMapperLayer::clearBackingStoresRecursive() -{ - m_backingStore.clear(); - m_contentsLayer = 0; - for (size_t i = 0; i < m_children.size(); ++i) - m_children[i]->clearBackingStoresRecursive(); - if (m_state.maskLayer) - m_state.maskLayer->clearBackingStoresRecursive(); -} - void TextureMapperLayer::computeTransformsRecursive() { - if (m_size.isEmpty() && m_state.masksToBounds) + if (m_state.size.isEmpty() && m_state.masksToBounds) return; // Compute transforms recursively on the way down to leafs. TransformationMatrix parentTransform; if (m_parent) - parentTransform = m_parent->m_transform.combinedForChildren(); + parentTransform = m_parent->m_currentTransform.combinedForChildren(); else if (m_effectTarget) - parentTransform = m_effectTarget->m_transform.combined(); - m_transform.combineTransforms(parentTransform); + parentTransform = m_effectTarget->m_currentTransform.combined(); + m_currentTransform.combineTransforms(parentTransform); - m_state.visible = m_state.backfaceVisibility || !m_transform.combined().isBackFaceVisible(); + m_state.visible = m_state.backfaceVisibility || !m_currentTransform.combined().isBackFaceVisible(); if (m_parent && m_parent->m_state.preserves3D) - m_centerZ = m_transform.combined().mapPoint(FloatPoint3D(m_size.width() / 2, m_size.height() / 2, 0)).z(); + m_centerZ = m_currentTransform.combined().mapPoint(FloatPoint3D(m_state.size.width() / 2, m_state.size.height() / 2, 0)).z(); if (m_state.maskLayer) m_state.maskLayer->computeTransformsRecursive(); @@ -82,7 +77,7 @@ void TextureMapperLayer::computeTransformsRecursive() // Reorder children if needed on the way back up. if (m_state.preserves3D) - sortByZOrder(m_children, 0, m_children.size()); + sortByZOrder(m_children); } void TextureMapperLayer::paint() @@ -95,6 +90,26 @@ void TextureMapperLayer::paint() paintRecursive(options); } +static Color blendWithOpacity(const Color& color, float opacity) +{ + RGBA32 rgba = color.rgb(); + // See Color::getRGBA() to know how to extract alpha from color. + float alpha = alphaChannel(rgba) / 255.; + float effectiveAlpha = alpha * opacity; + return Color(colorWithOverrideAlpha(rgba, effectiveAlpha)); +} + +void TextureMapperLayer::computePatternTransformIfNeeded() +{ + if (!m_patternTransformDirty) + return; + + m_patternTransformDirty = false; + m_patternTransform = + TransformationMatrix::rectToRect(FloatRect(FloatPoint::zero(), m_state.contentsTileSize), m_state.contentsRect) + .multiply(TransformationMatrix().translate(m_state.contentsTilePhase.x() / m_state.contentsRect.width(), m_state.contentsTilePhase.y() / m_state.contentsRect.height())); +} + void TextureMapperLayer::paintSelf(const TextureMapperPaintOptions& options) { if (!m_state.visible || !m_state.contentsVisible) @@ -104,21 +119,42 @@ void TextureMapperLayer::paintSelf(const TextureMapperPaintOptions& options) TransformationMatrix transform; transform.translate(options.offset.width(), options.offset.height()); transform.multiply(options.transform); - transform.multiply(m_transform.combined()); + transform.multiply(m_currentTransform.combined()); - float opacity = options.opacity; - RefPtr<BitmapTexture> mask = options.mask; + if (m_state.solidColor.isValid() && !m_state.contentsRect.isEmpty() && m_state.solidColor.alpha()) { + options.textureMapper->drawSolidColor(m_state.contentsRect, transform, blendWithOpacity(m_state.solidColor, options.opacity)); + if (m_state.showDebugBorders) + options.textureMapper->drawBorder(m_state.debugBorderColor, m_state.debugBorderWidth, layerRect(), transform); + return; + } + + options.textureMapper->setWrapMode(TextureMapper::StretchWrap); + options.textureMapper->setPatternTransform(TransformationMatrix()); if (m_backingStore) { - ASSERT(m_state.drawsContent && m_state.contentsVisible && !m_size.isEmpty()); - ASSERT(!layerRect().isEmpty()); - m_backingStore->paintToTextureMapper(options.textureMapper, layerRect(), transform, opacity, mask.get()); + FloatRect targetRect = layerRect(); + ASSERT(!targetRect.isEmpty()); + m_backingStore->paintToTextureMapper(options.textureMapper, targetRect, transform, options.opacity); + if (m_state.showDebugBorders) + m_backingStore->drawBorder(options.textureMapper, m_state.debugBorderColor, m_state.debugBorderWidth, targetRect, transform); + // Only draw repaint count for the main backing store. + if (m_state.showRepaintCounter) + m_backingStore->drawRepaintCounter(options.textureMapper, m_state.repaintCount, m_state.debugBorderColor, targetRect, transform); } - if (m_contentsLayer) { - ASSERT(!layerRect().isEmpty()); - m_contentsLayer->paintToTextureMapper(options.textureMapper, m_state.contentsRect, transform, opacity, mask.get()); + if (!m_contentsLayer) + return; + + if (!m_state.contentsTileSize.isEmpty()) { + computePatternTransformIfNeeded(); + options.textureMapper->setWrapMode(TextureMapper::RepeatWrap); + options.textureMapper->setPatternTransform(m_patternTransform); } + + ASSERT(!layerRect().isEmpty()); + m_contentsLayer->paintToTextureMapper(options.textureMapper, m_state.contentsRect, transform, options.opacity); + if (m_state.showDebugBorders) + m_contentsLayer->drawBorder(options.textureMapper, m_state.debugBorderColor, m_state.debugBorderWidth, m_state.contentsRect, transform); } int TextureMapperLayer::compareGraphicsLayersZValue(const void* a, const void* b) @@ -128,7 +164,7 @@ int TextureMapperLayer::compareGraphicsLayersZValue(const void* a, const void* b return int(((*layerA)->m_centerZ - (*layerB)->m_centerZ) * 1000); } -void TextureMapperLayer::sortByZOrder(Vector<TextureMapperLayer* >& array, int /* first */, int /* last */) +void TextureMapperLayer::sortByZOrder(Vector<TextureMapperLayer* >& array) { qsort(array.data(), array.size(), sizeof(TextureMapperLayer*), compareGraphicsLayersZValue); } @@ -141,8 +177,13 @@ void TextureMapperLayer::paintSelfAndChildren(const TextureMapperPaintOptions& o return; bool shouldClip = m_state.masksToBounds && !m_state.preserves3D; - if (shouldClip) - options.textureMapper->beginClip(TransformationMatrix(options.transform).multiply(m_transform.combined()), layerRect()); + if (shouldClip) { + TransformationMatrix clipTransform; + clipTransform.translate(options.offset.width(), options.offset.height()); + clipTransform.multiply(options.transform); + clipTransform.multiply(m_currentTransform.combined()); + options.textureMapper->beginClip(clipTransform, layerRect()); + } for (size_t i = 0; i < m_children.size(); ++i) m_children[i]->paintRecursive(options); @@ -151,97 +192,26 @@ void TextureMapperLayer::paintSelfAndChildren(const TextureMapperPaintOptions& o options.textureMapper->endClip(); } -IntRect TextureMapperLayer::intermediateSurfaceRect() -{ - // FIXME: Add an inverse transform to LayerTransform. - return intermediateSurfaceRect(m_transform.combined().inverse()); -} - -IntRect TextureMapperLayer::intermediateSurfaceRect(const TransformationMatrix& matrix) -{ - IntRect rect; - TransformationMatrix localTransform = TransformationMatrix(matrix).multiply(m_transform.combined()); - rect = enclosingIntRect(localTransform.mapRect(layerRect())); - if (!m_state.masksToBounds && !m_state.maskLayer) { - for (size_t i = 0; i < m_children.size(); ++i) - rect.unite(m_children[i]->intermediateSurfaceRect(matrix)); - } - -#if ENABLE(CSS_FILTERS) - if (m_filters.hasOutsets()) { - int leftOutset; - int topOutset; - int bottomOutset; - int rightOutset; - m_filters.getOutsets(topOutset, rightOutset, bottomOutset, leftOutset); - IntRect unfilteredTargetRect(rect); - rect.move(std::max(0, -leftOutset), std::max(0, -topOutset)); - rect.expand(leftOutset + rightOutset, topOutset + bottomOutset); - rect.unite(unfilteredTargetRect); - } -#endif - - if (m_state.replicaLayer) - rect.unite(m_state.replicaLayer->intermediateSurfaceRect(matrix)); - - return rect; -} - -TextureMapperLayer::ContentsLayerCount TextureMapperLayer::countPotentialLayersWithContents() const -{ - int selfLayersWithContents = (m_state.drawsContent ? 1 : 0) + (m_contentsLayer ? 1 : 0); - int potentialLayersWithContents = selfLayersWithContents + m_children.size(); - - if (!potentialLayersWithContents) - return NoLayersWithContent; - - if (potentialLayersWithContents > 1) - return MultipleLayersWithContents; - - if (m_children.isEmpty()) - return SingleLayerWithContents; - - return m_children.first()->countPotentialLayersWithContents(); -} - -bool TextureMapperLayer::shouldPaintToIntermediateSurface() const +bool TextureMapperLayer::shouldBlend() const { -#if ENABLE(CSS_FILTERS) - if (m_filters.size()) - return true; -#endif - bool hasOpacity = m_opacity < 0.99; - bool canHaveMultipleLayersWithContent = countPotentialLayersWithContents() == MultipleLayersWithContents; - bool hasReplica = !!m_state.replicaLayer; - bool hasMask = !!m_state.maskLayer; - - // We don't use two-pass blending for preserves-3d, that's in sync with Safari. if (m_state.preserves3D) return false; - // We should use an intermediate surface when blending several items with an ancestor opacity. - // Tested by compositing/reflections/reflection-opacity.html - if (hasOpacity && (canHaveMultipleLayersWithContent || hasReplica)) - return true; - - // We should use an intermediate surface with a masked ancestor. - // In the case of replicas the mask is applied before replicating. - // Tested by compositing/masks/masked-ancestor.html - if (hasMask && canHaveMultipleLayersWithContent && !hasReplica) - return true; - - return false; + return m_currentOpacity < 1 + || hasFilters() + || m_state.maskLayer + || (m_state.replicaLayer && m_state.replicaLayer->m_state.maskLayer); } bool TextureMapperLayer::isVisible() const { - if (m_size.isEmpty() && (m_state.masksToBounds || m_state.maskLayer || m_children.isEmpty())) + if (m_state.size.isEmpty() && (m_state.masksToBounds || m_state.maskLayer || m_children.isEmpty())) return false; if (!m_state.visible && m_children.isEmpty()) return false; if (!m_state.contentsVisible && m_children.isEmpty()) return false; - if (m_opacity < 0.01) + if (m_currentOpacity < 0.01) return false; return true; } @@ -250,92 +220,241 @@ void TextureMapperLayer::paintSelfAndChildrenWithReplica(const TextureMapperPain { if (m_state.replicaLayer) { TextureMapperPaintOptions replicaOptions(options); - // We choose either the content's mask or the replica's mask. - // FIXME: blend the two if both exist. - if (m_state.replicaLayer->m_state.maskLayer) - replicaOptions.mask = m_state.replicaLayer->m_state.maskLayer->texture(); - replicaOptions.transform - .multiply(m_state.replicaLayer->m_transform.combined()) - .multiply(m_transform.combined().inverse()); + .multiply(m_state.replicaLayer->m_currentTransform.combined()) + .multiply(m_currentTransform.combined().inverse()); paintSelfAndChildren(replicaOptions); } paintSelfAndChildren(options); } -#if ENABLE(CSS_FILTERS) -static bool shouldKeepContentTexture(const FilterOperations& filters) +void TextureMapperLayer::setAnimatedTransform(const TransformationMatrix& matrix) { - for (size_t i = 0; i < filters.size(); ++i) { - switch (filters.operations().at(i)->getOperationType()) { - // The drop-shadow filter requires the content texture, because it needs to composite it - // on top of the blurred shadow color. - case FilterOperation::DROP_SHADOW: - return true; - default: - break; - } - } + m_currentTransform.setLocalTransform(matrix); +} - return false; +void TextureMapperLayer::setAnimatedOpacity(float opacity) +{ + m_currentOpacity = opacity; } -static PassRefPtr<BitmapTexture> applyFilters(const FilterOperations& filters, TextureMapper* textureMapper, BitmapTexture* source, IntRect& targetRect) +TransformationMatrix TextureMapperLayer::replicaTransform() { - if (!filters.size()) - return source; + return TransformationMatrix(m_state.replicaLayer->m_currentTransform.combined()).multiply(m_currentTransform.combined().inverse()); +} - RefPtr<BitmapTexture> filterSurface = shouldKeepContentTexture(filters) ? textureMapper->acquireTextureFromPool(source->size()) : source; - return filterSurface->applyFilters(textureMapper, *source, filters); +#if ENABLE(CSS_FILTERS) +void TextureMapperLayer::setAnimatedFilters(const FilterOperations& filters) +{ + m_currentFilters = filters; } #endif -void TextureMapperLayer::paintRecursive(const TextureMapperPaintOptions& options) +static void resolveOverlaps(Region newRegion, Region& overlapRegion, Region& nonOverlapRegion) { - if (!isVisible()) + Region newOverlapRegion(newRegion); + newOverlapRegion.intersect(nonOverlapRegion); + nonOverlapRegion.subtract(newOverlapRegion); + overlapRegion.unite(newOverlapRegion); + newRegion.subtract(overlapRegion); + nonOverlapRegion.unite(newRegion); +} + +void TextureMapperLayer::computeOverlapRegions(Region& overlapRegion, Region& nonOverlapRegion, ResolveSelfOverlapMode mode) +{ + if (!m_state.visible || !m_state.contentsVisible) return; - float opacity = options.opacity * m_opacity; - RefPtr<BitmapTexture> maskTexture = m_state.maskLayer ? m_state.maskLayer->texture() : 0; + FloatRect boundingRect; + if (m_backingStore || m_state.masksToBounds || m_state.maskLayer || hasFilters()) + boundingRect = layerRect(); + else if (m_contentsLayer || m_state.solidColor.alpha()) + boundingRect = m_state.contentsRect; - TextureMapperPaintOptions paintOptions(options); - paintOptions.mask = maskTexture.get(); +#if ENABLE(CSS_FILTERS) + if (m_currentFilters.hasOutsets()) { + FilterOutsets outsets = m_currentFilters.outsets(); + IntRect unfilteredTargetRect(boundingRect); + boundingRect.move(std::max(0, -outsets.left()), std::max(0, -outsets.top())); + boundingRect.expand(outsets.left() + outsets.right(), outsets.top() + outsets.bottom()); + boundingRect.unite(unfilteredTargetRect); + } +#endif - if (!shouldPaintToIntermediateSurface()) { - paintOptions.opacity = opacity; - paintSelfAndChildrenWithReplica(paintOptions); + TransformationMatrix replicaMatrix; + if (m_state.replicaLayer) { + replicaMatrix = replicaTransform(); + boundingRect.unite(replicaMatrix.mapRect(boundingRect)); + } + + boundingRect = m_currentTransform.combined().mapRect(boundingRect); + + // Count all masks and filters as overlap layers. + if (hasFilters() || m_state.maskLayer || (m_state.replicaLayer && m_state.replicaLayer->m_state.maskLayer)) { + Region newOverlapRegion(enclosingIntRect(boundingRect)); + nonOverlapRegion.subtract(newOverlapRegion); + overlapRegion.unite(newOverlapRegion); return; } - // Prepare a surface to paint into. - // We paint into the surface ignoring the opacity/transform of the current layer. - IntRect surfaceRect = intermediateSurfaceRect(); - RefPtr<BitmapTexture> surface = options.textureMapper->acquireTextureFromPool(surfaceRect.size()); - paintOptions.surface = surface; - options.textureMapper->bindSurface(surface.get()); - paintOptions.opacity = 1; + Region newOverlapRegion; + Region newNonOverlapRegion(enclosingIntRect(boundingRect)); - paintOptions.transform = m_transform.combined().inverse(); - paintOptions.offset = -IntSize(surfaceRect.x(), surfaceRect.y()); + if (!m_state.masksToBounds) { + for (size_t i = 0; i < m_children.size(); ++i) { + TextureMapperLayer* child = m_children[i]; + child->computeOverlapRegions(newOverlapRegion, newNonOverlapRegion, ResolveSelfOverlapIfNeeded); + } + } - paintSelfAndChildrenWithReplica(paintOptions); + if (m_state.replicaLayer) { + newOverlapRegion.unite(replicaMatrix.mapRect(newOverlapRegion.bounds())); + Region replicaRegion(replicaMatrix.mapRect(newNonOverlapRegion.bounds())); + resolveOverlaps(replicaRegion, newOverlapRegion, newNonOverlapRegion); + } - // If we painted the replica, the mask is already applied so we don't need to paint it again. - if (m_state.replicaLayer) - maskTexture = 0; + if ((mode != ResolveSelfOverlapAlways) && shouldBlend()) { + newNonOverlapRegion.unite(newOverlapRegion); + newOverlapRegion = Region(); + } + + overlapRegion.unite(newOverlapRegion); + resolveOverlaps(newNonOverlapRegion, overlapRegion, nonOverlapRegion); +} + +void TextureMapperLayer::paintUsingOverlapRegions(const TextureMapperPaintOptions& options) +{ + Region overlapRegion; + Region nonOverlapRegion; + computeOverlapRegions(overlapRegion, nonOverlapRegion, ResolveSelfOverlapAlways); + if (overlapRegion.isEmpty()) { + paintSelfAndChildrenWithReplica(options); + return; + } + + // Having both overlap and non-overlap regions carries some overhead. Avoid it if the overlap area + // is big anyway. + if (overlapRegion.bounds().size().area() > nonOverlapRegion.bounds().size().area()) { + overlapRegion.unite(nonOverlapRegion); + nonOverlapRegion = Region(); + } + + nonOverlapRegion.translate(options.offset); + Vector<IntRect> rects = nonOverlapRegion.rects(); + + for (size_t i = 0; i < rects.size(); ++i) { + IntRect rect = rects[i]; + if (!rect.intersects(options.textureMapper->clipBounds())) + continue; + + options.textureMapper->beginClip(TransformationMatrix(), rects[i]); + paintSelfAndChildrenWithReplica(options); + options.textureMapper->endClip(); + } + + rects = overlapRegion.rects(); + static const size_t OverlapRegionConsolidationThreshold = 4; + if (nonOverlapRegion.isEmpty() && rects.size() > OverlapRegionConsolidationThreshold) { + rects.clear(); + rects.append(overlapRegion.bounds()); + } + + IntSize maxTextureSize = options.textureMapper->maxTextureSize(); + IntRect adjustedClipBounds(options.textureMapper->clipBounds()); + adjustedClipBounds.move(-options.offset); + for (size_t i = 0; i < rects.size(); ++i) { + IntRect rect = rects[i]; + for (int x = rect.x(); x < rect.maxX(); x += maxTextureSize.width()) { + for (int y = rect.y(); y < rect.maxY(); y += maxTextureSize.height()) { + IntRect tileRect(IntPoint(x, y), maxTextureSize); + tileRect.intersect(rect); + if (!tileRect.intersects(adjustedClipBounds)) + continue; + + paintWithIntermediateSurface(options, tileRect); + } + } + } +} +void TextureMapperLayer::applyMask(const TextureMapperPaintOptions& options) +{ + options.textureMapper->setMaskMode(true); + paintSelf(options); + options.textureMapper->setMaskMode(false); +} + +PassRefPtr<BitmapTexture> TextureMapperLayer::paintIntoSurface(const TextureMapperPaintOptions& options, const IntSize& size) +{ + RefPtr<BitmapTexture> surface = options.textureMapper->acquireTextureFromPool(size); + TextureMapperPaintOptions paintOptions(options); + paintOptions.surface = surface; + options.textureMapper->bindSurface(surface.get()); + paintSelfAndChildren(paintOptions); + if (m_state.maskLayer) + m_state.maskLayer->applyMask(options); #if ENABLE(CSS_FILTERS) - surface = applyFilters(m_filters, options.textureMapper, surface.get(), surfaceRect); + surface = surface->applyFilters(options.textureMapper, m_currentFilters); #endif + options.textureMapper->bindSurface(surface.get()); + return surface; +} +static void commitSurface(const TextureMapperPaintOptions& options, PassRefPtr<BitmapTexture> surface, const IntRect& rect, float opacity) +{ options.textureMapper->bindSurface(options.surface.get()); TransformationMatrix targetTransform; targetTransform.translate(options.offset.width(), options.offset.height()); targetTransform.multiply(options.transform); - targetTransform.multiply(m_transform.combined()); + options.textureMapper->drawTexture(*surface.get(), rect, targetTransform, opacity); +} + +void TextureMapperLayer::paintWithIntermediateSurface(const TextureMapperPaintOptions& options, const IntRect& rect) +{ + RefPtr<BitmapTexture> replicaSurface; + RefPtr<BitmapTexture> mainSurface; + TextureMapperPaintOptions paintOptions(options); + paintOptions.offset = -IntSize(rect.x(), rect.y()); + paintOptions.opacity = 1; + paintOptions.transform = TransformationMatrix(); + if (m_state.replicaLayer) { + paintOptions.transform = replicaTransform(); + replicaSurface = paintIntoSurface(paintOptions, rect.size()); + paintOptions.transform = TransformationMatrix(); + if (m_state.replicaLayer->m_state.maskLayer) + m_state.replicaLayer->m_state.maskLayer->applyMask(paintOptions); + } + + if (replicaSurface && options.opacity == 1) { + commitSurface(options, replicaSurface, rect, 1); + replicaSurface.clear(); + } + + mainSurface = paintIntoSurface(paintOptions, rect.size()); + if (replicaSurface) { + options.textureMapper->bindSurface(replicaSurface.get()); + options.textureMapper->drawTexture(*mainSurface.get(), FloatRect(FloatPoint::zero(), rect.size())); + mainSurface = replicaSurface; + } + + commitSurface(options, mainSurface, rect, options.opacity); +} - options.textureMapper->drawTexture(*surface.get(), surfaceRect, targetTransform, opacity, maskTexture.get()); +void TextureMapperLayer::paintRecursive(const TextureMapperPaintOptions& options) +{ + if (!isVisible()) + return; + + TextureMapperPaintOptions paintOptions(options); + paintOptions.opacity *= m_currentOpacity; + + if (!shouldBlend()) { + paintSelfAndChildrenWithReplica(paintOptions); + return; + } + + paintUsingOverlapRegions(paintOptions); } TextureMapperLayer::~TextureMapperLayer() @@ -352,98 +471,195 @@ TextureMapper* TextureMapperLayer::textureMapper() const return rootLayer()->m_textureMapper; } -void TextureMapperLayer::flushCompositingState(GraphicsLayerTextureMapper* graphicsLayer, int options) +void TextureMapperLayer::setChildren(const Vector<TextureMapperLayer*>& newChildren) { - flushCompositingState(graphicsLayer, textureMapper(), options); + removeAllChildren(); + for (size_t i = 0; i < newChildren.size(); ++i) + addChild(newChildren[i]); } -void TextureMapperLayer::flushCompositingStateSelf(GraphicsLayerTextureMapper* graphicsLayer, TextureMapper*) +void TextureMapperLayer::addChild(TextureMapperLayer* childLayer) { - int changeMask = graphicsLayer->changeMask(); + ASSERT(childLayer != this); - if (changeMask == NoChanges && graphicsLayer->m_animations.isEmpty()) - return; + if (childLayer->m_parent) + childLayer->removeFromParent(); - graphicsLayer->updateDebugIndicators(); + childLayer->m_parent = this; + m_children.append(childLayer); +} - if (changeMask & ParentChange) { - TextureMapperLayer* newParent = toTextureMapperLayer(graphicsLayer->parent()); - if (newParent != m_parent) { - // Remove layer from current from child list first. - if (m_parent) { - size_t index = m_parent->m_children.find(this); - m_parent->m_children.remove(index); - m_parent = 0; - } - // Set new layer parent and add layer to the parents child list. - if (newParent) { - m_parent = newParent; - m_parent->m_children.append(this); +void TextureMapperLayer::removeFromParent() +{ + if (m_parent) { + unsigned i; + for (i = 0; i < m_parent->m_children.size(); i++) { + if (this == m_parent->m_children[i]) { + m_parent->m_children.remove(i); + break; } } + + m_parent = 0; } +} - if (changeMask & ChildrenChange) { - // Clear children parent pointer to avoid unsync and crash on layer delete. - for (size_t i = 0; i < m_children.size(); i++) - m_children[i]->m_parent = 0; - - m_children.clear(); - for (size_t i = 0; i < graphicsLayer->children().size(); ++i) { - TextureMapperLayer* child = toTextureMapperLayer(graphicsLayer->children()[i]); - if (!child) - continue; - m_children.append(child); - child->m_parent = this; - } +void TextureMapperLayer::removeAllChildren() +{ + while (m_children.size()) { + TextureMapperLayer* curLayer = m_children[0]; + ASSERT(curLayer->m_parent); + curLayer->removeFromParent(); } +} - m_size = graphicsLayer->size(); +void TextureMapperLayer::setMaskLayer(TextureMapperLayer* maskLayer) +{ + if (maskLayer) + maskLayer->m_effectTarget = this; + m_state.maskLayer = maskLayer; +} - if ((changeMask & DrawsContentChange) && graphicsLayer->drawsContent()) - graphicsLayer->setNeedsDisplay(); +void TextureMapperLayer::setReplicaLayer(TextureMapperLayer* replicaLayer) +{ + if (replicaLayer) + replicaLayer->m_effectTarget = this; + m_state.replicaLayer = replicaLayer; +} - if (changeMask & MaskLayerChange) { - if (TextureMapperLayer* layer = toTextureMapperLayer(graphicsLayer->maskLayer())) - layer->m_effectTarget = this; - } +void TextureMapperLayer::setPosition(const FloatPoint& position) +{ + m_state.pos = position; + m_currentTransform.setPosition(adjustedPosition()); +} - if (changeMask & ReplicaLayerChange) { - if (TextureMapperLayer* layer = toTextureMapperLayer(graphicsLayer->replicaLayer())) - layer->m_effectTarget = this; - } +void TextureMapperLayer::setSize(const FloatSize& size) +{ + m_state.size = size; + m_currentTransform.setSize(size); +} + +void TextureMapperLayer::setAnchorPoint(const FloatPoint3D& anchorPoint) +{ + m_state.anchorPoint = anchorPoint; + m_currentTransform.setAnchorPoint(anchorPoint); +} + +void TextureMapperLayer::setPreserves3D(bool preserves3D) +{ + m_state.preserves3D = preserves3D; + m_currentTransform.setFlattening(!preserves3D); +} + +void TextureMapperLayer::setTransform(const TransformationMatrix& transform) +{ + m_state.transform = transform; + m_currentTransform.setLocalTransform(transform); +} + +void TextureMapperLayer::setChildrenTransform(const TransformationMatrix& childrenTransform) +{ + m_state.childrenTransform = childrenTransform; + m_currentTransform.setChildrenTransform(childrenTransform); +} + +void TextureMapperLayer::setContentsRect(const IntRect& contentsRect) +{ + if (contentsRect == m_state.contentsRect) + return; + m_state.contentsRect = contentsRect; + m_patternTransformDirty = true; +} + +void TextureMapperLayer::setContentsTileSize(const IntSize& size) +{ + if (size == m_state.contentsTileSize) + return; + m_state.contentsTileSize = size; + m_patternTransformDirty = true; +} + +void TextureMapperLayer::setContentsTilePhase(const IntPoint& phase) +{ + if (phase == m_state.contentsTilePhase) + return; + m_state.contentsTilePhase = phase; + m_patternTransformDirty = true; +} + +void TextureMapperLayer::setMasksToBounds(bool masksToBounds) +{ + m_state.masksToBounds = masksToBounds; +} + +void TextureMapperLayer::setDrawsContent(bool drawsContent) +{ + m_state.drawsContent = drawsContent; +} + +void TextureMapperLayer::setContentsVisible(bool contentsVisible) +{ + m_state.contentsVisible = contentsVisible; +} + +void TextureMapperLayer::setContentsOpaque(bool contentsOpaque) +{ + m_state.contentsOpaque = contentsOpaque; +} + +void TextureMapperLayer::setBackfaceVisibility(bool backfaceVisibility) +{ + m_state.backfaceVisibility = backfaceVisibility; +} + +void TextureMapperLayer::setOpacity(float opacity) +{ + m_state.opacity = opacity; +} + +void TextureMapperLayer::setSolidColor(const Color& color) +{ + m_state.solidColor = color; +} - if (changeMask & AnimationChange) - m_animations = graphicsLayer->m_animations; - - m_state.maskLayer = toTextureMapperLayer(graphicsLayer->maskLayer()); - m_state.replicaLayer = toTextureMapperLayer(graphicsLayer->replicaLayer()); - m_state.pos = graphicsLayer->position(); - m_state.anchorPoint = graphicsLayer->anchorPoint(); - m_state.size = graphicsLayer->size(); - m_state.transform = graphicsLayer->transform(); - m_state.contentsRect = graphicsLayer->contentsRect(); - m_state.preserves3D = graphicsLayer->preserves3D(); - m_state.masksToBounds = graphicsLayer->masksToBounds(); - m_state.drawsContent = graphicsLayer->drawsContent(); - m_state.contentsVisible = graphicsLayer->contentsAreVisible(); - m_state.contentsOpaque = graphicsLayer->contentsOpaque(); - m_state.backfaceVisibility = graphicsLayer->backfaceVisibility(); - m_state.childrenTransform = graphicsLayer->childrenTransform(); - m_state.opacity = graphicsLayer->opacity(); #if ENABLE(CSS_FILTERS) - if (changeMask & FilterChange) - m_state.filters = graphicsLayer->filters(); +void TextureMapperLayer::setFilters(const FilterOperations& filters) +{ + m_state.filters = filters; +} #endif - m_fixedToViewport = graphicsLayer->fixedToViewport(); - m_contentsLayer = graphicsLayer->platformLayer(); +void TextureMapperLayer::setDebugVisuals(bool showDebugBorders, const Color& debugBorderColor, float debugBorderWidth, bool showRepaintCounter) +{ + m_state.showDebugBorders = showDebugBorders; + m_state.debugBorderColor = debugBorderColor; + m_state.debugBorderWidth = debugBorderWidth; + m_state.showRepaintCounter = showRepaintCounter; +} + +void TextureMapperLayer::setRepaintCount(int repaintCount) +{ + m_state.repaintCount = repaintCount; +} - m_transform.setPosition(adjustedPosition()); - m_transform.setAnchorPoint(m_state.anchorPoint); - m_transform.setSize(m_state.size); - m_transform.setFlattening(!m_state.preserves3D); - m_transform.setChildrenTransform(m_state.childrenTransform); +void TextureMapperLayer::setContentsLayer(TextureMapperPlatformLayer* platformLayer) +{ + m_contentsLayer = platformLayer; +} + +void TextureMapperLayer::setAnimations(const GraphicsLayerAnimations& animations) +{ + m_animations = animations; +} + +void TextureMapperLayer::setFixedToViewport(bool fixedToViewport) +{ + m_fixedToViewport = fixedToViewport; +} + +void TextureMapperLayer::setBackingStore(PassRefPtr<TextureMapperBackingStore> backingStore) +{ + m_backingStore = backingStore; } bool TextureMapperLayer::descendantsOrSelfHaveRunningAnimations() const @@ -470,48 +686,16 @@ void TextureMapperLayer::syncAnimations() { m_animations.apply(this); if (!m_animations.hasActiveAnimationsOfType(AnimatedPropertyWebkitTransform)) - setTransform(m_state.transform); + m_currentTransform.setLocalTransform(m_state.transform); if (!m_animations.hasActiveAnimationsOfType(AnimatedPropertyOpacity)) - setOpacity(m_state.opacity); + m_currentOpacity = m_state.opacity; + #if ENABLE(CSS_FILTERS) if (!m_animations.hasActiveAnimationsOfType(AnimatedPropertyWebkitFilter)) - setFilters(m_state.filters); + m_currentFilters = m_state.filters; #endif } -void TextureMapperLayer::flushCompositingState(GraphicsLayerTextureMapper* graphicsLayer, TextureMapper* textureMapper, int options) -{ - if (!textureMapper) - return; - - if (graphicsLayer && !(options & ComputationsOnly)) - flushCompositingStateSelf(graphicsLayer, textureMapper); - - if (graphicsLayer && m_state.maskLayer) - m_state.maskLayer->flushCompositingState(toGraphicsLayerTextureMapper(graphicsLayer->maskLayer()), textureMapper); - - if (m_state.replicaLayer) - m_state.replicaLayer->flushCompositingState(toGraphicsLayerTextureMapper(graphicsLayer->replicaLayer()), textureMapper); - - syncAnimations(); - - if (!(options & TraverseDescendants)) - options = ComputationsOnly; - - if (graphicsLayer) { - Vector<GraphicsLayer*> children = graphicsLayer->children(); - for (int i = children.size() - 1; i >= 0; --i) { - TextureMapperLayer* layer = toTextureMapperLayer(children[i]); - if (!layer) - continue; - layer->flushCompositingState(toGraphicsLayerTextureMapper(children[i]), textureMapper, options); - } - } else { - for (int i = m_children.size() - 1; i >= 0; --i) - m_children[i]->flushCompositingState(0, textureMapper, options); - } -} - bool TextureMapperLayer::isAncestorFixedToViewport() const { for (TextureMapperLayer* parent = m_parent; parent; parent = parent->m_parent) { @@ -532,7 +716,80 @@ void TextureMapperLayer::setScrollPositionDeltaIfNeeded(const FloatSize& delta) m_scrollPositionDelta = FloatSize(); else m_scrollPositionDelta = delta; - m_transform.setPosition(adjustedPosition()); + m_currentTransform.setPosition(adjustedPosition()); +} + +template<class HitTestCondition> TextureMapperLayer* TextureMapperLayer::hitTest(const FloatPoint& point, HitTestCondition condition) +{ + if (!m_state.visible || !m_state.contentsVisible) + return 0; + + TextureMapperLayer* result = 0; + for (int i = m_children.size() - 1; !result && i >= 0; --i) + result = m_children[i]->hitTest(point, condition); + + if (result) + return result; + + return condition(this, point) ? this : 0; +} + +bool TextureMapperLayer::scrollableLayerHitTestCondition(TextureMapperLayer* layer, const FloatPoint& point) +{ + // scrolling layer's m_parent->m_parent, the parent of the scrolling layes, is the one that defines the + // rectangle to be used for hit testing. + if (!layer->isScrollable() || !layer->m_parent || !layer->m_parent->m_parent) + return false; + + TextureMapperLayer* parentLayer = layer->m_parent->m_parent; + FloatRect rect = parentLayer->layerRect(); + return parentLayer->m_currentTransform.combined().mapQuad(rect).containsPoint(point); +} + +TextureMapperLayer* TextureMapperLayer::findScrollableContentsLayerAt(const FloatPoint& point) +{ + return hitTest(point, &TextureMapperLayer::scrollableLayerHitTestCondition); +} + +FloatSize TextureMapperLayer::mapScrollOffset(const FloatSize& offset) +{ + double zeroX, zeroY, offsetX, offsetY; + TransformationMatrix transform = m_currentTransform.combined().inverse(); + transform.map(0, 0, zeroX, zeroY); + transform.map(offset.width(), offset.height(), offsetX, offsetY); + return FloatSize(offsetX - zeroX, offsetY - zeroY); +} + +void TextureMapperLayer::commitScrollOffset(const FloatSize& offset) +{ + FloatSize fullOffset = m_accumulatedScrollOffsetFractionalPart + offset; + + int intWidth = round(fullOffset.width()); + int intHeight = round(fullOffset.height()); + + // m_accumulatedScrollOffsetFractionalPart holds the fractional part of the user scroll offset that + // has not yet been synced with the web process because the web process expects an IntSize. + m_accumulatedScrollOffsetFractionalPart = FloatSize(fullOffset.width() - intWidth, fullOffset.height() - intHeight); + + m_scrollClient->commitScrollOffset(m_id, IntSize(intWidth, intHeight)); +} + +void TextureMapperLayer::scrollBy(const FloatSize& offset) +{ + if (!isScrollable() || !m_scrollClient || offset.isZero()) + return; + + FloatSize scrollOffset = mapScrollOffset(offset); + m_userScrollOffset += scrollOffset; + + m_currentTransform.setPosition(adjustedPosition()); + commitScrollOffset(scrollOffset); +} + +void TextureMapperLayer::didCommitScrollOffset(const IntSize& offset) +{ + m_userScrollOffset = FloatSize(m_userScrollOffset.width() - offset.width(), m_userScrollOffset.height() - offset.height()); + m_currentTransform.setPosition(adjustedPosition()); } } diff --git a/Source/WebCore/platform/graphics/texmap/TextureMapperLayer.h b/Source/WebCore/platform/graphics/texmap/TextureMapperLayer.h index 27a77f6fe..7b62b0a0b 100644 --- a/Source/WebCore/platform/graphics/texmap/TextureMapperLayer.h +++ b/Source/WebCore/platform/graphics/texmap/TextureMapperLayer.h @@ -20,11 +20,10 @@ #ifndef TextureMapperLayer_h #define TextureMapperLayer_h -#if USE(ACCELERATED_COMPOSITING) +#if USE(ACCELERATED_COMPOSITING) && USE(TEXTURE_MAPPER) #include "FilterOperations.h" #include "FloatRect.h" -#include "GraphicsLayer.h" #include "GraphicsLayerAnimation.h" #include "GraphicsLayerTransform.h" #include "TextureMapper.h" @@ -32,132 +31,145 @@ namespace WebCore { +class Region; +class TextureMapperPaintOptions; class TextureMapperPlatformLayer; -class GraphicsLayerTextureMapper; - -class TextureMapperPaintOptions { -public: - RefPtr<BitmapTexture> surface; - RefPtr<BitmapTexture> mask; - float opacity; - TransformationMatrix transform; - IntSize offset; - TextureMapper* textureMapper; - TextureMapperPaintOptions() - : opacity(1) - , textureMapper(0) - { } -}; class TextureMapperLayer : public GraphicsLayerAnimation::Client { + WTF_MAKE_NONCOPYABLE(TextureMapperLayer); WTF_MAKE_FAST_ALLOCATED; public: - // This set of flags help us defer which properties of the layer have been - // modified by the compositor, so we can know what to look for in the next flush. - enum ChangeMask { - NoChanges = 0, - - ParentChange = (1L << 0), - ChildrenChange = (1L << 1), - MaskLayerChange = (1L << 2), - PositionChange = (1L << 3), - - AnchorPointChange = (1L << 4), - SizeChange = (1L << 5), - TransformChange = (1L << 6), - ContentChange = (1L << 7), - - ContentsOrientationChange = (1L << 9), - OpacityChange = (1L << 10), - ContentsRectChange = (1L << 11), - - Preserves3DChange = (1L << 12), - MasksToBoundsChange = (1L << 13), - DrawsContentChange = (1L << 14), - ContentsVisibleChange = (1L << 15), - ContentsOpaqueChange = (1L << 16), - - BackfaceVisibilityChange = (1L << 17), - ChildrenTransformChange = (1L << 18), - DisplayChange = (1L << 19), - BackgroundColorChange = (1L << 20), - - ReplicaLayerChange = (1L << 21), - AnimationChange = (1L << 22), - FilterChange = (1L << 23) - }; - enum SyncOptions { - TraverseDescendants = 1, - ComputationsOnly = 2 + class ScrollingClient { + public: + virtual void commitScrollOffset(uint32_t layerID, const IntSize& offset) = 0; }; TextureMapperLayer() : m_parent(0) , m_effectTarget(0) , m_contentsLayer(0) - , m_opacity(1) + , m_currentOpacity(1) , m_centerZ(0) , m_textureMapper(0) + , m_fixedToViewport(false) + , m_id(0) + , m_scrollClient(0) + , m_isScrollable(false) + , m_patternTransformDirty(false) { } virtual ~TextureMapperLayer(); + void setID(uint32_t id) { m_id = id; } + uint32_t id() { return m_id; } + + const Vector<TextureMapperLayer*>& children() const { return m_children; } + TextureMapperLayer* findScrollableContentsLayerAt(const FloatPoint& pos); + + void setScrollClient(ScrollingClient* scrollClient) { m_scrollClient = scrollClient; } + void scrollBy(const WebCore::FloatSize&); + + void didCommitScrollOffset(const IntSize&); + void setIsScrollable(bool isScrollable) { m_isScrollable = isScrollable; } + bool isScrollable() const { return m_isScrollable; } + TextureMapper* textureMapper() const; - void flushCompositingState(GraphicsLayerTextureMapper*, int syncOptions = 0); - void flushCompositingState(GraphicsLayerTextureMapper*, TextureMapper*, int syncOptions = 0); - IntSize size() const { return IntSize(m_size.width(), m_size.height()); } + void setTextureMapper(TextureMapper* texmap) { m_textureMapper = texmap; } + + void setChildren(const Vector<TextureMapperLayer*>&); + void setMaskLayer(TextureMapperLayer*); + void setReplicaLayer(TextureMapperLayer*); + void setPosition(const FloatPoint&); + void setSize(const FloatSize&); + void setAnchorPoint(const FloatPoint3D&); + void setPreserves3D(bool); void setTransform(const TransformationMatrix&); - void setOpacity(float value) { m_opacity = value; } + void setChildrenTransform(const TransformationMatrix&); + void setContentsRect(const IntRect&); + void setMasksToBounds(bool); + void setDrawsContent(bool); + bool drawsContent() const { return m_state.drawsContent; } + bool contentsAreVisible() const { return m_state.contentsVisible; } + FloatSize size() const { return m_state.size; } + float opacity() const { return m_state.opacity; } + TransformationMatrix transform() const { return m_state.transform; } + void setContentsVisible(bool); + void setContentsOpaque(bool); + void setBackfaceVisibility(bool); + void setOpacity(float); + void setSolidColor(const Color&); + void setContentsTileSize(const IntSize&); + void setContentsTilePhase(const IntPoint&); #if ENABLE(CSS_FILTERS) - void setFilters(const FilterOperations& filters) { m_filters = filters; } + void setFilters(const FilterOperations&); #endif - void setTextureMapper(TextureMapper* texmap) { m_textureMapper = texmap; } + + bool hasFilters() const + { +#if ENABLE(CSS_FILTERS) + return !m_currentFilters.isEmpty(); +#else + return false; +#endif + } + + void setDebugVisuals(bool showDebugBorders, const Color& debugBorderColor, float debugBorderWidth, bool showRepaintCounter); + bool isShowingRepaintCounter() const { return m_state.showRepaintCounter; } + void setRepaintCount(int); + void setContentsLayer(TextureMapperPlatformLayer*); + void setAnimations(const GraphicsLayerAnimations&); + void setFixedToViewport(bool); + bool fixedToViewport() const { return m_fixedToViewport; } + void setBackingStore(PassRefPtr<TextureMapperBackingStore>); + + void syncAnimations(); bool descendantsOrSelfHaveRunningAnimations() const; void paint(); - void setBackingStore(PassRefPtr<TextureMapperBackingStore> backingStore) { m_backingStore = backingStore; } - PassRefPtr<TextureMapperBackingStore> backingStore() { return m_backingStore; } - void clearBackingStoresRecursive(); - void setScrollPositionDeltaIfNeeded(const FloatSize&); void applyAnimationsRecursively(); + void addChild(TextureMapperLayer*); private: const TextureMapperLayer* rootLayer() const; void computeTransformsRecursive(); - void computeOverlapsIfNeeded(); - void computeTiles(); - IntRect intermediateSurfaceRect(const TransformationMatrix&); - IntRect intermediateSurfaceRect(); - void swapContentsBuffers(); - FloatRect targetRectForTileRect(const FloatRect& totalTargetRect, const FloatRect& tileRect) const; - void invalidateViewport(const FloatRect&); - void notifyChange(ChangeMask); - void flushCompositingStateSelf(GraphicsLayerTextureMapper*, TextureMapper*); static int compareGraphicsLayersZValue(const void* a, const void* b); - static void sortByZOrder(Vector<TextureMapperLayer* >& array, int first, int last); + static void sortByZOrder(Vector<TextureMapperLayer* >& array); PassRefPtr<BitmapTexture> texture() { return m_backingStore ? m_backingStore->texture() : 0; } - FloatPoint adjustedPosition() const { return m_state.pos + m_scrollPositionDelta; } + FloatPoint adjustedPosition() const { return m_state.pos + m_scrollPositionDelta - m_userScrollOffset; } bool isAncestorFixedToViewport() const; + TransformationMatrix replicaTransform(); + void removeFromParent(); + void removeAllChildren(); + + enum ResolveSelfOverlapMode { + ResolveSelfOverlapAlways = 0, + ResolveSelfOverlapIfNeeded + }; + void computeOverlapRegions(Region& overlapRegion, Region& nonOverlapRegion, ResolveSelfOverlapMode); void paintRecursive(const TextureMapperPaintOptions&); + void paintUsingOverlapRegions(const TextureMapperPaintOptions&); + PassRefPtr<BitmapTexture> paintIntoSurface(const TextureMapperPaintOptions&, const IntSize&); + void paintWithIntermediateSurface(const TextureMapperPaintOptions&, const IntRect&); void paintSelf(const TextureMapperPaintOptions&); void paintSelfAndChildren(const TextureMapperPaintOptions&); void paintSelfAndChildrenWithReplica(const TextureMapperPaintOptions&); + void applyMask(const TextureMapperPaintOptions&); + void computePatternTransformIfNeeded(); // GraphicsLayerAnimation::Client - void setAnimatedTransform(const TransformationMatrix& matrix) { setTransform(matrix); } - void setAnimatedOpacity(float opacity) { setOpacity(opacity); } + virtual void setAnimatedTransform(const TransformationMatrix&) OVERRIDE; + virtual void setAnimatedOpacity(float) OVERRIDE; #if ENABLE(CSS_FILTERS) - virtual void setAnimatedFilters(const FilterOperations& filters) { setFilters(filters); } + virtual void setAnimatedFilters(const FilterOperations&) OVERRIDE; #endif - void syncAnimations(); bool isVisible() const; enum ContentsLayerCount { NoLayersWithContent, @@ -165,14 +177,11 @@ private: MultipleLayersWithContents }; - ContentsLayerCount countPotentialLayersWithContents() const; - bool shouldPaintToIntermediateSurface() const; - - GraphicsLayerTransform m_transform; + bool shouldBlend() const; inline FloatRect layerRect() const { - return FloatRect(FloatPoint::zero(), m_size); + return FloatRect(FloatPoint::zero(), m_state.size); } Vector<TextureMapperLayer*> m_children; @@ -180,13 +189,18 @@ private: TextureMapperLayer* m_effectTarget; RefPtr<TextureMapperBackingStore> m_backingStore; TextureMapperPlatformLayer* m_contentsLayer; - FloatSize m_size; - float m_opacity; + GraphicsLayerTransform m_currentTransform; + float m_currentOpacity; #if ENABLE(CSS_FILTERS) - FilterOperations m_filters; + FilterOperations m_currentFilters; #endif float m_centerZ; - String m_name; + + template<class HitTestCondition> TextureMapperLayer* hitTest(const FloatPoint&, HitTestCondition); + static bool scrollableLayerHitTestCondition(TextureMapperLayer*, const FloatPoint&); + + FloatSize mapScrollOffset(const FloatSize&); + void commitScrollOffset(const FloatSize&); struct State { FloatPoint pos; @@ -196,12 +210,17 @@ private: TransformationMatrix childrenTransform; float opacity; FloatRect contentsRect; - int descendantsWithContent; + IntSize contentsTileSize; + IntPoint contentsTilePhase; TextureMapperLayer* maskLayer; TextureMapperLayer* replicaLayer; + Color solidColor; #if ENABLE(CSS_FILTERS) - FilterOperations filters; + FilterOperations filters; #endif + Color debugBorderColor; + float debugBorderWidth; + int repaintCount; bool preserves3D : 1; bool masksToBounds : 1; @@ -210,21 +229,24 @@ private: bool contentsOpaque : 1; bool backfaceVisibility : 1; bool visible : 1; - bool mightHaveOverlaps : 1; - bool needsRepaint; + bool showDebugBorders : 1; + bool showRepaintCounter : 1; + State() - : opacity(1.f) + : opacity(1) , maskLayer(0) , replicaLayer(0) + , debugBorderWidth(0) + , repaintCount(0) , preserves3D(false) , masksToBounds(false) , drawsContent(false) , contentsVisible(true) , contentsOpaque(false) - , backfaceVisibility(false) + , backfaceVisibility(true) , visible(true) - , mightHaveOverlaps(false) - , needsRepaint(false) + , showDebugBorders(false) + , showRepaintCounter(false) { } }; @@ -234,11 +256,15 @@ private: GraphicsLayerAnimations m_animations; FloatSize m_scrollPositionDelta; bool m_fixedToViewport; + uint32_t m_id; + ScrollingClient* m_scrollClient; + bool m_isScrollable; + FloatSize m_userScrollOffset; + FloatSize m_accumulatedScrollOffsetFractionalPart; + TransformationMatrix m_patternTransform; + bool m_patternTransformDirty; }; - -TextureMapperLayer* toTextureMapperLayer(GraphicsLayer*); - } #endif diff --git a/Source/WebCore/platform/graphics/texmap/TextureMapperPlatformLayer.h b/Source/WebCore/platform/graphics/texmap/TextureMapperPlatformLayer.h index 38af03e89..0cab98da4 100644 --- a/Source/WebCore/platform/graphics/texmap/TextureMapperPlatformLayer.h +++ b/Source/WebCore/platform/graphics/texmap/TextureMapperPlatformLayer.h @@ -24,23 +24,42 @@ #include "GraphicsSurface.h" #endif +#include "TextureMapper.h" #include "TransformationMatrix.h" namespace WebCore { -class TextureMapper; -class BitmapTexture; - class TextureMapperPlatformLayer { public: + class Client { + public: + virtual void setPlatformLayerNeedsDisplay() = 0; + }; + + TextureMapperPlatformLayer() : m_client(0) { } virtual ~TextureMapperPlatformLayer() { } - virtual void paintToTextureMapper(TextureMapper*, const FloatRect&, const TransformationMatrix& modelViewMatrix = TransformationMatrix(), float opacity = 1.0, BitmapTexture* mask = 0) = 0; + virtual void paintToTextureMapper(TextureMapper*, const FloatRect&, const TransformationMatrix& modelViewMatrix = TransformationMatrix(), float opacity = 1.0) = 0; virtual void swapBuffers() { } + virtual void drawBorder(TextureMapper* textureMapper, const Color& color, float borderWidth, const FloatRect& targetRect, const TransformationMatrix& transform) + { + textureMapper->drawBorder(color, borderWidth, targetRect, transform); + } + void setClient(TextureMapperPlatformLayer::Client* client) + { + m_client = client; + } #if USE(GRAPHICS_SURFACE) virtual IntSize platformLayerSize() const { return IntSize(); } virtual uint32_t copyToGraphicsSurface() { return 0; } virtual GraphicsSurfaceToken graphicsSurfaceToken() const { return GraphicsSurfaceToken(); } + virtual GraphicsSurface::Flags graphicsSurfaceFlags() const { return GraphicsSurface::SupportsTextureTarget | GraphicsSurface::SupportsSharing; } #endif + +protected: + TextureMapperPlatformLayer::Client* client() { return m_client; } + +private: + TextureMapperPlatformLayer::Client* m_client; }; }; diff --git a/Source/WebCore/platform/graphics/texmap/TextureMapperShaderManager.cpp b/Source/WebCore/platform/graphics/texmap/TextureMapperShaderManager.cpp deleted file mode 100644 index c8e1ae461..000000000 --- a/Source/WebCore/platform/graphics/texmap/TextureMapperShaderManager.cpp +++ /dev/null @@ -1,533 +0,0 @@ -/* - Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies) - Copyright (C) 2012 Igalia S.L. - Copyright (C) 2011 Google Inc. All rights reserved. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. - */ - -#include "config.h" -#include "TextureMapperShaderManager.h" - -#if USE(ACCELERATED_COMPOSITING) && USE(TEXTURE_MAPPER) - -#include "LengthFunctions.h" -#include "Logging.h" -#include "TextureMapperGL.h" - -#define STRINGIFY(...) #__VA_ARGS__ - -namespace WebCore { - - -static inline bool compositingLogEnabled() -{ -#if !LOG_DISABLED - return LogCompositing.state == WTFLogChannelOn; -#else - return false; -#endif -} - -TextureMapperShaderProgram::TextureMapperShaderProgram(PassRefPtr<GraphicsContext3D> context, const String& vertex, const String& fragment) - : m_context(context) -{ - m_vertexShader = m_context->createShader(GraphicsContext3D::VERTEX_SHADER); - m_fragmentShader = m_context->createShader(GraphicsContext3D::FRAGMENT_SHADER); - m_context->shaderSource(m_vertexShader, vertex); - m_context->shaderSource(m_fragmentShader, fragment); - m_id = m_context->createProgram(); - m_context->compileShader(m_vertexShader); - m_context->compileShader(m_fragmentShader); - m_context->attachShader(m_id, m_vertexShader); - m_context->attachShader(m_id, m_fragmentShader); - m_context->linkProgram(m_id); - - if (!compositingLogEnabled()) - return; - - if (m_context->getError() == GraphicsContext3D::NO_ERROR) - return; - - String log = m_context->getShaderInfoLog(m_vertexShader); - LOG(Compositing, "Vertex shader log: %s\n", log.utf8().data()); - log = m_context->getShaderInfoLog(m_fragmentShader); - LOG(Compositing, "Fragment shader log: %s\n", log.utf8().data()); - log = m_context->getProgramInfoLog(m_id); - LOG(Compositing, "Program log: %s\n", log.utf8().data()); -} - -GC3Duint TextureMapperShaderProgram::getLocation(const AtomicString& name, VariableType type) -{ - HashMap<AtomicString, GC3Duint>::iterator it = m_variables.find(name); - if (it != m_variables.end()) - return it->value; - - GC3Duint location = 0; - switch (type) { - case UniformVariable: - location = m_context->getUniformLocation(m_id, name); - break; - case AttribVariable: - location = m_context->getAttribLocation(m_id, name); - break; - default: - ASSERT_NOT_REACHED(); - break; - } - - m_variables.add(name, location); - return location; -} - -TextureMapperShaderProgram::~TextureMapperShaderProgram() -{ - Platform3DObject programID = m_id; - if (!programID) - return; - - m_context->detachShader(programID, m_vertexShader); - m_context->deleteShader(m_vertexShader); - m_context->detachShader(programID, m_fragmentShader); - m_context->deleteShader(m_fragmentShader); - m_context->deleteProgram(programID); -} - -struct ShaderSpec { - String vertexShader; - String fragmentShader; - ShaderSpec(const char* vertex = 0, const char* fragment = 0) - : vertexShader(vertex ? String(ASCIILiteral(vertex)) : String()) - , fragmentShader(fragment ? String(ASCIILiteral(fragment)) : String()) - { - } -}; - -static void getShaderSpec(TextureMapperShaderManager::ShaderKey key, String& vertexSource, String& fragmentSource) -{ - static Vector<ShaderSpec> specs = Vector<ShaderSpec>(); - static const char* fragmentOpacityAndMask = - STRINGIFY( - precision mediump float; - uniform sampler2D s_sampler; - uniform sampler2D s_mask; - uniform lowp float u_opacity; - varying highp vec2 v_sourceTexCoord; - varying highp vec2 v_maskTexCoord; - void main(void) - { - lowp vec4 color = texture2D(s_sampler, v_sourceTexCoord); - lowp vec4 maskColor = texture2D(s_mask, v_maskTexCoord); - lowp float fragmentAlpha = u_opacity * maskColor.a; - gl_FragColor = vec4(color.rgb * fragmentAlpha, color.a * fragmentAlpha); - } - ); - - static const char* fragmentRectOpacityAndMask = - STRINGIFY( - precision mediump float; - uniform sampler2DRect s_sampler; - uniform sampler2DRect s_mask; - uniform lowp float u_opacity; - varying highp vec2 v_sourceTexCoord; - varying highp vec2 v_maskTexCoord; - void main(void) - { - lowp vec4 color = texture2DRect(s_sampler, v_sourceTexCoord); - lowp vec4 maskColor = texture2DRect(s_mask, v_maskTexCoord); - lowp float fragmentAlpha = u_opacity * maskColor.a; - gl_FragColor = vec4(color.rgb * fragmentAlpha, color.a * fragmentAlpha); - } - ); - - static const char* vertexOpacityAndMask = - STRINGIFY( - uniform mat4 u_matrix; - uniform lowp float u_flip; - attribute vec4 a_vertex; - varying highp vec2 v_sourceTexCoord; - varying highp vec2 v_maskTexCoord; - void main(void) - { - v_sourceTexCoord = vec2(a_vertex.x, mix(a_vertex.y, 1. - a_vertex.y, u_flip)); - v_maskTexCoord = vec2(a_vertex); - gl_Position = u_matrix * a_vertex; - } - ); - - static const char* fragmentSimple = - STRINGIFY( - precision mediump float; - uniform sampler2D s_sampler; - uniform lowp float u_opacity; - varying highp vec2 v_sourceTexCoord; - void main(void) - { - lowp vec4 color = texture2D(s_sampler, v_sourceTexCoord); - gl_FragColor = vec4(color.rgb * u_opacity, color.a * u_opacity); - } - ); - - static const char* fragmentAntialiasingNoMask = - STRINGIFY( - precision mediump float; - uniform sampler2D s_sampler; - varying highp vec2 v_sourceTexCoord; - uniform lowp float u_opacity; - uniform vec3 u_expandedQuadEdgesInScreenSpace[8]; - void main() - { - vec4 sampledColor = texture2D(s_sampler, clamp(v_sourceTexCoord, 0.0, 1.0)); - vec3 pos = vec3(gl_FragCoord.xy, 1); - - // The data passed in u_expandedQuadEdgesInScreenSpace is merely the - // pre-scaled coeffecients of the line equations describing the four edges - // of the expanded quad in screen space and the rectangular bounding box - // of the expanded quad. - // - // We are doing a simple distance calculation here according to the formula: - // (A*p.x + B*p.y + C) / sqrt(A^2 + B^2) = distance from line to p - // Note that A, B and C have already been scaled by 1 / sqrt(A^2 + B^2). - float a0 = clamp(dot(u_expandedQuadEdgesInScreenSpace[0], pos), 0.0, 1.0); - float a1 = clamp(dot(u_expandedQuadEdgesInScreenSpace[1], pos), 0.0, 1.0); - float a2 = clamp(dot(u_expandedQuadEdgesInScreenSpace[2], pos), 0.0, 1.0); - float a3 = clamp(dot(u_expandedQuadEdgesInScreenSpace[3], pos), 0.0, 1.0); - float a4 = clamp(dot(u_expandedQuadEdgesInScreenSpace[4], pos), 0.0, 1.0); - float a5 = clamp(dot(u_expandedQuadEdgesInScreenSpace[5], pos), 0.0, 1.0); - float a6 = clamp(dot(u_expandedQuadEdgesInScreenSpace[6], pos), 0.0, 1.0); - float a7 = clamp(dot(u_expandedQuadEdgesInScreenSpace[7], pos), 0.0, 1.0); - - // Now we want to reduce the alpha value of the fragment if it is close to the - // edges of the expanded quad (or rectangular bounding box -- which seems to be - // important for backfacing quads). Note that we are combining the contribution - // from the (top || bottom) and (left || right) edge by simply multiplying. This follows - // the approach described at: http://http.developer.nvidia.com/GPUGems2/gpugems2_chapter22.html, - // in this case without using Gaussian weights. - gl_FragColor = sampledColor * u_opacity * min(min(a0, a2) * min(a1, a3), min(a4, a6) * min(a5, a7)); - } - ); - - static const char* fragmentRectSimple = - STRINGIFY( - precision mediump float; - uniform sampler2DRect s_sampler; - uniform lowp vec2 u_samplerSize; - uniform lowp float u_opacity; - varying highp vec2 v_sourceTexCoord; - void main(void) - { - lowp vec4 color = texture2DRect(s_sampler, u_samplerSize * v_sourceTexCoord); - gl_FragColor = vec4(color.rgb * u_opacity, color.a * u_opacity); - } - ); - - static const char* vertexSimple = - STRINGIFY( - uniform mat4 u_matrix; - uniform lowp float u_flip; - attribute vec4 a_vertex; - varying highp vec2 v_sourceTexCoord; - void main(void) - { - v_sourceTexCoord = vec2(a_vertex.x, mix(a_vertex.y, 1. - a_vertex.y, u_flip)); - gl_Position = u_matrix * a_vertex; - } - ); - - static const char* vertexSolidColor = - STRINGIFY( - uniform mat4 u_matrix; - attribute vec4 a_vertex; - void main(void) - { - gl_Position = u_matrix * a_vertex; - } - ); - - - static const char* fragmentSolidColor = - STRINGIFY( - precision mediump float; - uniform vec4 u_color; - void main(void) - { - gl_FragColor = u_color; - } - ); - - static const char* vertexFilter = - STRINGIFY( - attribute vec4 a_vertex; - attribute vec4 a_texCoord; - varying highp vec2 v_texCoord; - void main(void) - { - v_texCoord = vec2(a_texCoord); - gl_Position = a_vertex; - } - ); - -#define STANDARD_FILTER(...) \ - "precision mediump float;\n"\ - "varying highp vec2 v_texCoord;\n"\ - "uniform highp float u_amount;\n"\ - "uniform sampler2D s_sampler;\n"#__VA_ARGS__ \ - "void main(void)\n { gl_FragColor = shade(texture2D(s_sampler, v_texCoord)); }" - - static const char* fragmentGrayscaleFilter = - STANDARD_FILTER( - lowp vec4 shade(lowp vec4 color) - { - lowp float amount = 1.0 - u_amount; - return vec4((0.2126 + 0.7874 * amount) * color.r + (0.7152 - 0.7152 * amount) * color.g + (0.0722 - 0.0722 * amount) * color.b, - (0.2126 - 0.2126 * amount) * color.r + (0.7152 + 0.2848 * amount) * color.g + (0.0722 - 0.0722 * amount) * color.b, - (0.2126 - 0.2126 * amount) * color.r + (0.7152 - 0.7152 * amount) * color.g + (0.0722 + 0.9278 * amount) * color.b, - color.a); - } - ); - - static const char* fragmentSepiaFilter = - STANDARD_FILTER( - lowp vec4 shade(lowp vec4 color) - { - lowp float amount = 1.0 - u_amount; - return vec4((0.393 + 0.607 * amount) * color.r + (0.769 - 0.769 * amount) * color.g + (0.189 - 0.189 * amount) * color.b, - (0.349 - 0.349 * amount) * color.r + (0.686 + 0.314 * amount) * color.g + (0.168 - 0.168 * amount) * color.b, - (0.272 - 0.272 * amount) * color.r + (0.534 - 0.534 * amount) * color.g + (0.131 + 0.869 * amount) * color.b, - color.a); - } - ); - - static const char* fragmentSaturateFilter = - STANDARD_FILTER( - lowp vec4 shade(lowp vec4 color) - { - return vec4((0.213 + 0.787 * u_amount) * color.r + (0.715 - 0.715 * u_amount) * color.g + (0.072 - 0.072 * u_amount) * color.b, - (0.213 - 0.213 * u_amount) * color.r + (0.715 + 0.285 * u_amount) * color.g + (0.072 - 0.072 * u_amount) * color.b, - (0.213 - 0.213 * u_amount) * color.r + (0.715 - 0.715 * u_amount) * color.g + (0.072 + 0.928 * u_amount) * color.b, - color.a); - } - ); - - static const char* fragmentHueRotateFilter = - STANDARD_FILTER( - lowp vec4 shade(lowp vec4 color) - { - highp float pi = 3.14159265358979323846; - highp float c = cos(u_amount * pi / 180.0); - highp float s = sin(u_amount * pi / 180.0); - return vec4(color.r * (0.213 + c * 0.787 - s * 0.213) + color.g * (0.715 - c * 0.715 - s * 0.715) + color.b * (0.072 - c * 0.072 + s * 0.928), - color.r * (0.213 - c * 0.213 + s * 0.143) + color.g * (0.715 + c * 0.285 + s * 0.140) + color.b * (0.072 - c * 0.072 - s * 0.283), - color.r * (0.213 - c * 0.213 - s * 0.787) + color.g * (0.715 - c * 0.715 + s * 0.715) + color.b * (0.072 + c * 0.928 + s * 0.072), - color.a); - } - ); - - static const char* fragmentInvertFilter = - STANDARD_FILTER( - lowp float invert(lowp float n) { return (1.0 - n) * u_amount + n * (1.0 - u_amount); } - lowp vec4 shade(lowp vec4 color) - { - return vec4(invert(color.r), invert(color.g), invert(color.b), color.a); - } - ); - - static const char* fragmentBrightnessFilter = - STANDARD_FILTER( - lowp vec4 shade(lowp vec4 color) - { - return vec4(color.rgb * (1.0 + u_amount), color.a); - } - ); - - static const char* fragmentContrastFilter = - STANDARD_FILTER( - lowp float contrast(lowp float n) { return (n - 0.5) * u_amount + 0.5; } - lowp vec4 shade(lowp vec4 color) - { - return vec4(contrast(color.r), contrast(color.g), contrast(color.b), color.a); - } - ); - - static const char* fragmentOpacityFilter = - STANDARD_FILTER( - lowp vec4 shade(lowp vec4 color) - { - return vec4(color.r, color.g, color.b, color.a * u_amount); - } - ); - -#define BLUR_CONSTANTS "#define GAUSSIAN_KERNEL_HALF_WIDTH 11\n#define GAUSSIAN_KERNEL_STEP 0.2\n" - - static const char* fragmentBlurFilter = - BLUR_CONSTANTS - STRINGIFY( - // Create a normal distribution of 21 values between -2 and 2. - precision mediump float; - varying highp vec2 v_texCoord; - uniform lowp vec2 u_blurRadius; - uniform sampler2D s_sampler; - uniform float u_gaussianKernel[GAUSSIAN_KERNEL_HALF_WIDTH]; - - lowp vec4 sampleColor(float radius) - { - vec2 coord = v_texCoord + radius * u_blurRadius; - return texture2D(s_sampler, coord) * float(coord.x > 0. && coord.y > 0. && coord.x < 1. && coord.y < 1.); - } - - vec4 blur() - { - vec4 total = sampleColor(0.) * u_gaussianKernel[0]; - for (int i = 1; i < GAUSSIAN_KERNEL_HALF_WIDTH; i++) { - total += sampleColor(float(i) * GAUSSIAN_KERNEL_STEP) * u_gaussianKernel[i]; - total += sampleColor(float(-1 * i) * GAUSSIAN_KERNEL_STEP) * u_gaussianKernel[i]; - } - - return total; - } - - void main(void) - { - gl_FragColor = blur(); - } - ); - - static const char* fragmentShadowFilter1 = - BLUR_CONSTANTS - STRINGIFY( - precision mediump float; - varying highp vec2 v_texCoord; - uniform lowp float u_blurRadius; - uniform lowp vec2 u_shadowOffset; - uniform sampler2D s_sampler; - uniform float u_gaussianKernel[GAUSSIAN_KERNEL_HALF_WIDTH]; - - lowp float sampleAlpha(float radius) - { - vec2 coord = v_texCoord - u_shadowOffset + vec2(radius * u_blurRadius, 0.); - return texture2D(s_sampler, coord).a * float(coord.x > 0. && coord.y > 0. && coord.x < 1. && coord.y < 1.); - } - - lowp float shadowBlurHorizontal() - { - float total = sampleAlpha(0.) * u_gaussianKernel[0]; - for (int i = 1; i < GAUSSIAN_KERNEL_HALF_WIDTH; i++) { - total += sampleAlpha(float(i) * GAUSSIAN_KERNEL_STEP) * u_gaussianKernel[i]; - total += sampleAlpha(float(-1 * i) * GAUSSIAN_KERNEL_STEP) * u_gaussianKernel[i]; - } - - return total; - } - - void main(void) - { - gl_FragColor = vec4(1., 1., 1., 1.) * shadowBlurHorizontal(); - } - ); - - // Second pass: vertical alpha blur and composite with origin. - static const char* fragmentShadowFilter2 = - BLUR_CONSTANTS - STRINGIFY( - precision mediump float; - varying highp vec2 v_texCoord; - uniform lowp float u_blurRadius; - uniform lowp vec4 u_shadowColor; - uniform sampler2D s_sampler; - uniform sampler2D s_contentTexture; - uniform float u_gaussianKernel[GAUSSIAN_KERNEL_HALF_WIDTH]; - - lowp float sampleAlpha(float r) - { - vec2 coord = v_texCoord + vec2(0., r * u_blurRadius); - return texture2D(s_sampler, coord).a * float(coord.x > 0. && coord.y > 0. && coord.x < 1. && coord.y < 1.); - } - - lowp float shadowBlurVertical() - { - float total = sampleAlpha(0.) * u_gaussianKernel[0]; - for (int i = 1; i < GAUSSIAN_KERNEL_HALF_WIDTH; i++) { - total += sampleAlpha(float(i) * GAUSSIAN_KERNEL_STEP) * u_gaussianKernel[i]; - total += sampleAlpha(float(-1 * i) * GAUSSIAN_KERNEL_STEP) * u_gaussianKernel[i]; - } - - return total; - } - - lowp vec4 sourceOver(lowp vec4 source, lowp vec4 destination) - { - // Composite the shadow with the original texture. - return source + destination * (1. - source.a); - } - - void main(void) - { - gl_FragColor = sourceOver(texture2D(s_contentTexture, v_texCoord), shadowBlurVertical() * u_shadowColor); - } - ); - - if (specs.isEmpty()) { - specs.resize(TextureMapperShaderManager::LastFilter); - specs[TextureMapperShaderManager::Default] = ShaderSpec(vertexSimple, fragmentSimple); - specs[TextureMapperShaderManager::SolidColor] = ShaderSpec(vertexSolidColor, fragmentSolidColor); - specs[TextureMapperShaderManager::Rect] = ShaderSpec(vertexSimple, fragmentRectSimple); - specs[TextureMapperShaderManager::Masked] = ShaderSpec(vertexOpacityAndMask, fragmentOpacityAndMask); - specs[TextureMapperShaderManager::MaskedRect] = ShaderSpec(vertexOpacityAndMask, fragmentRectOpacityAndMask); - specs[TextureMapperShaderManager::Antialiased] = ShaderSpec(vertexSimple, fragmentAntialiasingNoMask); - specs[TextureMapperShaderManager::GrayscaleFilter] = ShaderSpec(vertexFilter, fragmentGrayscaleFilter); - specs[TextureMapperShaderManager::SepiaFilter] = ShaderSpec(vertexFilter, fragmentSepiaFilter); - specs[TextureMapperShaderManager::SaturateFilter] = ShaderSpec(vertexFilter, fragmentSaturateFilter); - specs[TextureMapperShaderManager::HueRotateFilter] = ShaderSpec(vertexFilter, fragmentHueRotateFilter); - specs[TextureMapperShaderManager::BrightnessFilter] = ShaderSpec(vertexFilter, fragmentBrightnessFilter); - specs[TextureMapperShaderManager::ContrastFilter] = ShaderSpec(vertexFilter, fragmentContrastFilter); - specs[TextureMapperShaderManager::InvertFilter] = ShaderSpec(vertexFilter, fragmentInvertFilter); - specs[TextureMapperShaderManager::OpacityFilter] = ShaderSpec(vertexFilter, fragmentOpacityFilter); - specs[TextureMapperShaderManager::BlurFilter] = ShaderSpec(vertexFilter, fragmentBlurFilter); - specs[TextureMapperShaderManager::ShadowFilterPass1] = ShaderSpec(vertexFilter, fragmentShadowFilter1); - specs[TextureMapperShaderManager::ShadowFilterPass2] = ShaderSpec(vertexFilter, fragmentShadowFilter2); - } - - ASSERT(specs.size() > key); - ShaderSpec& spec = specs[key]; - vertexSource = spec.vertexShader; - fragmentSource = spec.fragmentShader; -} - -TextureMapperShaderManager::TextureMapperShaderManager(GraphicsContext3D* context) - : m_context(context) -{ -} - -TextureMapperShaderManager::~TextureMapperShaderManager() -{ -} - -PassRefPtr<TextureMapperShaderProgram> TextureMapperShaderManager::getShaderProgram(ShaderKey key) -{ - TextureMapperShaderProgramMap::iterator it = m_programs.find(key); - if (it != m_programs.end()) - return it->value; - - String vertexShader; - String fragmentShader; - getShaderSpec(key, vertexShader, fragmentShader); - RefPtr<TextureMapperShaderProgram> program = TextureMapperShaderProgram::create(m_context, vertexShader, fragmentShader); - m_programs.add(key, program); - return program; -} -}; - -#endif diff --git a/Source/WebCore/platform/graphics/texmap/TextureMapperShaderProgram.cpp b/Source/WebCore/platform/graphics/texmap/TextureMapperShaderProgram.cpp new file mode 100644 index 000000000..3f64c4b8a --- /dev/null +++ b/Source/WebCore/platform/graphics/texmap/TextureMapperShaderProgram.cpp @@ -0,0 +1,382 @@ +/* + Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies) + Copyright (C) 2012 Igalia S.L. + Copyright (C) 2011 Google Inc. All rights reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + */ + +#include "config.h" +#include "TextureMapperShaderProgram.h" + +#if USE(ACCELERATED_COMPOSITING) && USE(TEXTURE_MAPPER) +#include "LengthFunctions.h" +#include "Logging.h" +#include "TextureMapperGL.h" + +#include <wtf/text/StringBuilder.h> + +#define STRINGIFY(...) #__VA_ARGS__ + +namespace WebCore { + +static inline bool compositingLogEnabled() +{ +#if !LOG_DISABLED + return LogCompositing.state == WTFLogChannelOn; +#else + return false; +#endif +} + +TextureMapperShaderProgram::TextureMapperShaderProgram(PassRefPtr<GraphicsContext3D> context, const String& vertex, const String& fragment) + : m_context(context) +{ + m_vertexShader = m_context->createShader(GraphicsContext3D::VERTEX_SHADER); + m_fragmentShader = m_context->createShader(GraphicsContext3D::FRAGMENT_SHADER); + m_context->shaderSource(m_vertexShader, vertex); + m_context->shaderSource(m_fragmentShader, fragment); + m_id = m_context->createProgram(); + m_context->compileShader(m_vertexShader); + m_context->compileShader(m_fragmentShader); + m_context->attachShader(m_id, m_vertexShader); + m_context->attachShader(m_id, m_fragmentShader); + m_context->linkProgram(m_id); + + if (!compositingLogEnabled()) + return; + + if (m_context->getError() == GraphicsContext3D::NO_ERROR) + return; + + String log = m_context->getShaderInfoLog(m_vertexShader); + LOG(Compositing, "Vertex shader log: %s\n", log.utf8().data()); + log = m_context->getShaderInfoLog(m_fragmentShader); + LOG(Compositing, "Fragment shader log: %s\n", log.utf8().data()); + log = m_context->getProgramInfoLog(m_id); + LOG(Compositing, "Program log: %s\n", log.utf8().data()); +} + +void TextureMapperShaderProgram::setMatrix(GC3Duint location, const TransformationMatrix& matrix) +{ + GC3Dfloat matrixAsFloats[] = { + GC3Dfloat(matrix.m11()), GC3Dfloat(matrix.m12()), GC3Dfloat(matrix.m13()), GC3Dfloat(matrix.m14()), + GC3Dfloat(matrix.m21()), GC3Dfloat(matrix.m22()), GC3Dfloat(matrix.m23()), GC3Dfloat(matrix.m24()), + GC3Dfloat(matrix.m31()), GC3Dfloat(matrix.m32()), GC3Dfloat(matrix.m33()), GC3Dfloat(matrix.m34()), + GC3Dfloat(matrix.m41()), GC3Dfloat(matrix.m42()), GC3Dfloat(matrix.m43()), GC3Dfloat(matrix.m44()) + }; + + m_context->uniformMatrix4fv(location, 1, false, matrixAsFloats); +} + +GC3Duint TextureMapperShaderProgram::getLocation(const AtomicString& name, VariableType type) +{ + HashMap<AtomicString, GC3Duint>::iterator it = m_variables.find(name); + if (it != m_variables.end()) + return it->value; + + GC3Duint location = 0; + switch (type) { + case UniformVariable: + location = m_context->getUniformLocation(m_id, name); + break; + case AttribVariable: + location = m_context->getAttribLocation(m_id, name); + break; + default: + ASSERT_NOT_REACHED(); + break; + } + + m_variables.add(name, location); + return location; +} + +TextureMapperShaderProgram::~TextureMapperShaderProgram() +{ + Platform3DObject programID = m_id; + if (!programID) + return; + + m_context->detachShader(programID, m_vertexShader); + m_context->deleteShader(m_vertexShader); + m_context->detachShader(programID, m_fragmentShader); + m_context->deleteShader(m_fragmentShader); + m_context->deleteProgram(programID); +} + +#define GLSL_DIRECTIVE(...) "#"#__VA_ARGS__"\n" +static const char* vertexTemplate = + STRINGIFY( + attribute vec4 a_vertex; + uniform mat4 u_modelViewMatrix; + uniform mat4 u_projectionMatrix; + uniform mat4 u_textureSpaceMatrix; + + varying vec2 v_texCoord; + varying float v_antialias; + + void noop(inout vec2 dummyParameter) { } + + vec4 toViewportSpace(vec2 pos) { return vec4(pos, 0., 1.) * u_modelViewMatrix; } + + // This function relies on the assumption that we get edge triangles with control points, + // a control point being the nearest point to the coordinate that is on the edge. + void applyAntialiasing(inout vec2 position) + { + // We count on the fact that quad passed in is always a unit rect, + // and the transformation matrix applies the real rect. + const vec2 center = vec2(0.5, 0.5); + const float antialiasInflationDistance = 1.; + + // We pass the control point as the zw coordinates of the vertex. + // The control point is the point on the edge closest to the current position. + // The control point is used to compute the antialias value. + vec2 controlPoint = a_vertex.zw; + + // First we calculate the distance in viewport space. + vec4 centerInViewportCoordinates = toViewportSpace(center); + vec4 controlPointInViewportCoordinates = toViewportSpace(controlPoint); + float viewportSpaceDistance = distance(centerInViewportCoordinates, controlPointInViewportCoordinates); + + // We add the inflation distance to the computed distance, and compute the ratio. + float inflationRatio = (viewportSpaceDistance + antialiasInflationDistance) / viewportSpaceDistance; + + // v_antialias needs to be 0 for the outer edge and 1. for the inner edge. + // Since the controlPoint is equal to the position in the edge vertices, the value is always 0 for those. + // For the center point, the distance is always 0.5, so we normalize to 1. by multiplying by 2. + // By multplying by inflationRatio and dividing by (inflationRatio - 1), + // We make sure that the varying interpolates between 0 (outer edge), 1 (inner edge) and n > 1 (center). + v_antialias = distance(controlPoint, position) * 2. * inflationRatio / (inflationRatio - 1.); + + // Now inflate the actual position. By using this formula instead of inflating position directly, + // we ensure that the center vertex is never inflated. + position = center + (position - center) * inflationRatio; + } + + void main(void) + { + vec2 position = a_vertex.xy; + applyAntialiasingIfNeeded(position); + + // The texture position needs to be clamped to 0..1 before the texture matrix is applied. + vec4 clampedPosition = clamp(vec4(position, 0., 1.), 0., 1.); + v_texCoord = (u_textureSpaceMatrix * clampedPosition).xy; + gl_Position = u_projectionMatrix * u_modelViewMatrix * vec4(position, 0., 1.); + } + ); + +#define RECT_TEXTURE_DIRECTIVE \ + GLSL_DIRECTIVE(ifdef ENABLE_Rect) \ + GLSL_DIRECTIVE(define SamplerType sampler2DRect) \ + GLSL_DIRECTIVE(define SamplerFunction texture2DRect) \ + GLSL_DIRECTIVE(else) \ + GLSL_DIRECTIVE(define SamplerType sampler2D) \ + GLSL_DIRECTIVE(define SamplerFunction texture2D) \ + GLSL_DIRECTIVE(endif) + +#define ENABLE_APPLIER(Name) "#define ENABLE_"#Name"\n#define apply"#Name"IfNeeded apply"#Name"\n" +#define DISABLE_APPLIER(Name) "#define apply"#Name"IfNeeded noop\n" +#define BLUR_CONSTANTS \ + GLSL_DIRECTIVE(define GAUSSIAN_KERNEL_HALF_WIDTH 11) \ + GLSL_DIRECTIVE(define GAUSSIAN_KERNEL_STEP 0.2) + + +static const char* fragmentTemplate = + RECT_TEXTURE_DIRECTIVE + BLUR_CONSTANTS + STRINGIFY( + precision mediump float; + uniform SamplerType s_sampler; + uniform sampler2D s_contentTexture; + uniform float u_opacity; + varying float v_antialias; + varying vec2 v_texCoord; + uniform float u_filterAmount; + uniform vec2 u_blurRadius; + uniform vec2 u_shadowOffset; + uniform vec4 u_color; + uniform float u_gaussianKernel[GAUSSIAN_KERNEL_HALF_WIDTH]; + + void noop(inout vec4 dummyParameter) { } + + float antialias() { return smoothstep(v_antialias, 0., 1.); } + + void applyTexture(inout vec4 color) { color = SamplerFunction(s_sampler, v_texCoord); } + void applyOpacity(inout vec4 color) { color *= u_opacity; } + void applyAntialiasing(inout vec4 color) { color *= antialias(); } + + void applyGrayscaleFilter(inout vec4 color) + { + float amount = 1.0 - u_filterAmount; + color = vec4((0.2126 + 0.7874 * amount) * color.r + (0.7152 - 0.7152 * amount) * color.g + (0.0722 - 0.0722 * amount) * color.b, + (0.2126 - 0.2126 * amount) * color.r + (0.7152 + 0.2848 * amount) * color.g + (0.0722 - 0.0722 * amount) * color.b, + (0.2126 - 0.2126 * amount) * color.r + (0.7152 - 0.7152 * amount) * color.g + (0.0722 + 0.9278 * amount) * color.b, + color.a); + } + + void applySepiaFilter(inout vec4 color) + { + float amount = 1.0 - u_filterAmount; + color = vec4((0.393 + 0.607 * amount) * color.r + (0.769 - 0.769 * amount) * color.g + (0.189 - 0.189 * amount) * color.b, + (0.349 - 0.349 * amount) * color.r + (0.686 + 0.314 * amount) * color.g + (0.168 - 0.168 * amount) * color.b, + (0.272 - 0.272 * amount) * color.r + (0.534 - 0.534 * amount) * color.g + (0.131 + 0.869 * amount) * color.b, + color.a); + } + + void applySaturateFilter(inout vec4 color) + { + color = vec4((0.213 + 0.787 * u_filterAmount) * color.r + (0.715 - 0.715 * u_filterAmount) * color.g + (0.072 - 0.072 * u_filterAmount) * color.b, + (0.213 - 0.213 * u_filterAmount) * color.r + (0.715 + 0.285 * u_filterAmount) * color.g + (0.072 - 0.072 * u_filterAmount) * color.b, + (0.213 - 0.213 * u_filterAmount) * color.r + (0.715 - 0.715 * u_filterAmount) * color.g + (0.072 + 0.928 * u_filterAmount) * color.b, + color.a); + } + + void applyHueRotateFilter(inout vec4 color) + { + float pi = 3.14159265358979323846; + float c = cos(u_filterAmount * pi / 180.0); + float s = sin(u_filterAmount * pi / 180.0); + color = vec4(color.r * (0.213 + c * 0.787 - s * 0.213) + color.g * (0.715 - c * 0.715 - s * 0.715) + color.b * (0.072 - c * 0.072 + s * 0.928), + color.r * (0.213 - c * 0.213 + s * 0.143) + color.g * (0.715 + c * 0.285 + s * 0.140) + color.b * (0.072 - c * 0.072 - s * 0.283), + color.r * (0.213 - c * 0.213 - s * 0.787) + color.g * (0.715 - c * 0.715 + s * 0.715) + color.b * (0.072 + c * 0.928 + s * 0.072), + color.a); + } + + float invert(float n) { return (1.0 - n) * u_filterAmount + n * (1.0 - u_filterAmount); } + void applyInvertFilter(inout vec4 color) + { + color = vec4(invert(color.r), invert(color.g), invert(color.b), color.a); + } + + void applyBrightnessFilter(inout vec4 color) + { + color = vec4(color.rgb * u_filterAmount, color.a); + } + + float contrast(float n) { return (n - 0.5) * u_filterAmount + 0.5; } + void applyContrastFilter(inout vec4 color) + { + color = vec4(contrast(color.r), contrast(color.g), contrast(color.b), color.a); + } + + void applyOpacityFilter(inout vec4 color) + { + color = vec4(color.r, color.g, color.b, color.a * u_filterAmount); + } + + vec4 sampleColorAtRadius(float radius) + { + vec2 coord = v_texCoord + radius * u_blurRadius; + return SamplerFunction(s_sampler, coord) * float(coord.x > 0. && coord.y > 0. && coord.x < 1. && coord.y < 1.); + } + + float sampleAlphaAtRadius(float radius) + { + vec2 coord = v_texCoord - u_shadowOffset + radius * u_blurRadius; + return SamplerFunction(s_sampler, coord).a * float(coord.x > 0. && coord.y > 0. && coord.x < 1. && coord.y < 1.); + } + + void applyBlurFilter(inout vec4 color) + { + vec4 total = sampleColorAtRadius(0.) * u_gaussianKernel[0]; + for (int i = 1; i < GAUSSIAN_KERNEL_HALF_WIDTH; i++) { + total += sampleColorAtRadius(float(i) * GAUSSIAN_KERNEL_STEP) * u_gaussianKernel[i]; + total += sampleColorAtRadius(float(-1 * i) * GAUSSIAN_KERNEL_STEP) * u_gaussianKernel[i]; + } + + color = total; + } + + void applyAlphaBlur(inout vec4 color) + { + float total = sampleAlphaAtRadius(0.) * u_gaussianKernel[0]; + for (int i = 1; i < GAUSSIAN_KERNEL_HALF_WIDTH; i++) { + total += sampleAlphaAtRadius(float(i) * GAUSSIAN_KERNEL_STEP) * u_gaussianKernel[i]; + total += sampleAlphaAtRadius(float(-1 * i) * GAUSSIAN_KERNEL_STEP) * u_gaussianKernel[i]; + } + + color *= total; + } + + vec4 sourceOver(vec4 src, vec4 dst) { return src + dst * (1. - dst.a); } + + void applyContentTexture(inout vec4 color) + { + vec4 contentColor = texture2D(s_contentTexture, v_texCoord); + color = sourceOver(contentColor, color); + } + + void applySolidColor(inout vec4 color) { color *= u_color; } + + void main(void) + { + vec4 color = vec4(1., 1., 1., 1.); + applyTextureIfNeeded(color); + applySolidColorIfNeeded(color); + applyAntialiasingIfNeeded(color); + applyOpacityIfNeeded(color); + applyGrayscaleFilterIfNeeded(color); + applySepiaFilterIfNeeded(color); + applySaturateFilterIfNeeded(color); + applyHueRotateFilterIfNeeded(color); + applyInvertFilterIfNeeded(color); + applyBrightnessFilterIfNeeded(color); + applyContrastFilterIfNeeded(color); + applyOpacityFilterIfNeeded(color); + applyBlurFilterIfNeeded(color); + applyAlphaBlurIfNeeded(color); + applyContentTextureIfNeeded(color); + gl_FragColor = color; + } + ); + +PassRefPtr<TextureMapperShaderProgram> TextureMapperShaderProgram::create(PassRefPtr<GraphicsContext3D> context, TextureMapperShaderProgram::Options options) +{ + StringBuilder shaderBuilder; +#define SET_APPLIER_FROM_OPTIONS(Applier) \ + shaderBuilder.append(\ + (options & TextureMapperShaderProgram::Applier) ? ENABLE_APPLIER(Applier) : DISABLE_APPLIER(Applier)) + + SET_APPLIER_FROM_OPTIONS(Texture); + SET_APPLIER_FROM_OPTIONS(Rect); + SET_APPLIER_FROM_OPTIONS(SolidColor); + SET_APPLIER_FROM_OPTIONS(Opacity); + SET_APPLIER_FROM_OPTIONS(Antialiasing); + SET_APPLIER_FROM_OPTIONS(GrayscaleFilter); + SET_APPLIER_FROM_OPTIONS(SepiaFilter); + SET_APPLIER_FROM_OPTIONS(SaturateFilter); + SET_APPLIER_FROM_OPTIONS(HueRotateFilter); + SET_APPLIER_FROM_OPTIONS(BrightnessFilter); + SET_APPLIER_FROM_OPTIONS(ContrastFilter); + SET_APPLIER_FROM_OPTIONS(InvertFilter); + SET_APPLIER_FROM_OPTIONS(OpacityFilter); + SET_APPLIER_FROM_OPTIONS(BlurFilter); + SET_APPLIER_FROM_OPTIONS(AlphaBlur); + SET_APPLIER_FROM_OPTIONS(ContentTexture); + StringBuilder vertexBuilder; + vertexBuilder.append(shaderBuilder.toString()); + vertexBuilder.append(vertexTemplate); + shaderBuilder.append(fragmentTemplate); + + String vertexSource = vertexBuilder.toString(); + String fragmentSource = shaderBuilder.toString(); + + return adoptRef(new TextureMapperShaderProgram(context, vertexSource, fragmentSource)); +} + +} +#endif diff --git a/Source/WebCore/platform/graphics/texmap/TextureMapperShaderManager.h b/Source/WebCore/platform/graphics/texmap/TextureMapperShaderProgram.h index 496b7e81b..3345fc9fe 100644 --- a/Source/WebCore/platform/graphics/texmap/TextureMapperShaderManager.h +++ b/Source/WebCore/platform/graphics/texmap/TextureMapperShaderProgram.h @@ -18,12 +18,12 @@ Boston, MA 02110-1301, USA. */ -#ifndef TextureMapperShaderManager_h -#define TextureMapperShaderManager_h +#ifndef TextureMapperShaderProgram_h +#define TextureMapperShaderProgram_h #if USE(TEXTURE_MAPPER) #include "GraphicsContext3D.h" -#include "TextureMapperGL.h" +#include "TransformationMatrix.h" #include <wtf/HashMap.h> #include <wtf/PassRefPtr.h> #include <wtf/RefPtr.h> @@ -37,21 +37,37 @@ namespace WebCore { class TextureMapperShaderProgram : public RefCounted<TextureMapperShaderProgram> { public: - Platform3DObject programID() const { return m_id; } - GraphicsContext3D* context() { return m_context.get(); } - static PassRefPtr<TextureMapperShaderProgram> create(PassRefPtr<GraphicsContext3D> context, const String& vertex, const String& fragment) - { - return adoptRef(new TextureMapperShaderProgram(context, vertex, fragment)); - } + enum Option { + Texture = 1L << 0, + Rect = 1L << 1, + SolidColor = 1L << 2, + Opacity = 1L << 3, + Antialiasing = 1L << 5, + GrayscaleFilter = 1L << 6, + SepiaFilter = 1L << 7, + SaturateFilter = 1L << 8, + HueRotateFilter = 1L << 9, + BrightnessFilter = 1L << 10, + ContrastFilter = 1L << 11, + InvertFilter = 1L << 12, + OpacityFilter = 1L << 13, + BlurFilter = 1L << 14, + AlphaBlur = 1L << 15, + ContentTexture = 1L << 16 + }; + + typedef unsigned Options; + static PassRefPtr<TextureMapperShaderProgram> create(PassRefPtr<GraphicsContext3D>, Options); virtual ~TextureMapperShaderProgram(); + Platform3DObject programID() const { return m_id; } + GraphicsContext3D* context() { return m_context.get(); } TEXMAP_DECLARE_ATTRIBUTE(vertex) - TEXMAP_DECLARE_ATTRIBUTE(texCoord) - TEXMAP_DECLARE_UNIFORM(matrix) - TEXMAP_DECLARE_UNIFORM(flip) - TEXMAP_DECLARE_UNIFORM(samplerSize) + TEXMAP_DECLARE_UNIFORM(modelViewMatrix) + TEXMAP_DECLARE_UNIFORM(projectionMatrix) + TEXMAP_DECLARE_UNIFORM(textureSpaceMatrix) TEXMAP_DECLARE_UNIFORM(opacity) TEXMAP_DECLARE_UNIFORM(color) TEXMAP_DECLARE_UNIFORM(expandedQuadEdgesInScreenSpace) @@ -59,14 +75,15 @@ public: TEXMAP_DECLARE_SAMPLER(mask) #if ENABLE(CSS_FILTERS) - TEXMAP_DECLARE_UNIFORM(amount) + TEXMAP_DECLARE_UNIFORM(filterAmount) TEXMAP_DECLARE_UNIFORM(gaussianKernel) TEXMAP_DECLARE_UNIFORM(blurRadius) - TEXMAP_DECLARE_UNIFORM(shadowColor) TEXMAP_DECLARE_UNIFORM(shadowOffset) TEXMAP_DECLARE_SAMPLER(contentTexture) #endif + void setMatrix(GC3Duint, const TransformationMatrix&); + private: TextureMapperShaderProgram(PassRefPtr<GraphicsContext3D>, const String& vertexShaderSource, const String& fragmentShaderSource); Platform3DObject m_vertexShader; @@ -80,43 +97,7 @@ private: HashMap<AtomicString, GC3Duint> m_variables; }; -class TextureMapperShaderManager { -public: - enum ShaderKey { - Invalid = 0, - Default, - Rect, - Masked, - MaskedRect, - SolidColor, - Antialiased, - GrayscaleFilter, - SepiaFilter, - SaturateFilter, - HueRotateFilter, - BrightnessFilter, - ContrastFilter, - OpacityFilter, - InvertFilter, - BlurFilter, - ShadowFilterPass1, - ShadowFilterPass2, - LastFilter - }; - - TextureMapperShaderManager() { } - explicit TextureMapperShaderManager(GraphicsContext3D*); - virtual ~TextureMapperShaderManager(); - - PassRefPtr<TextureMapperShaderProgram> getShaderProgram(ShaderKey); - -private: - typedef HashMap<ShaderKey, RefPtr<TextureMapperShaderProgram>, DefaultHash<int>::Hash, HashTraits<int> > TextureMapperShaderProgramMap; - TextureMapperShaderProgramMap m_programs; - RefPtr<GraphicsContext3D> m_context; -}; - } #endif -#endif // TextureMapperShaderManager_h +#endif // TextureMapperShaderProgram_h diff --git a/Source/WebCore/platform/graphics/texmap/TextureMapperSurfaceBackingStore.cpp b/Source/WebCore/platform/graphics/texmap/TextureMapperSurfaceBackingStore.cpp new file mode 100644 index 000000000..8d38776e9 --- /dev/null +++ b/Source/WebCore/platform/graphics/texmap/TextureMapperSurfaceBackingStore.cpp @@ -0,0 +1,54 @@ +/* + Copyright (C) 2013 Nokia Corporation and/or its subsidiary(-ies) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + */ + +#include "config.h" + +#if USE(ACCELERATED_COMPOSITING) && USE(GRAPHICS_SURFACE) +#include "TextureMapperSurfaceBackingStore.h" + +#include "GraphicsSurface.h" + +namespace WebCore { + +void TextureMapperSurfaceBackingStore::setGraphicsSurface(PassRefPtr<GraphicsSurface> surface) +{ + m_graphicsSurface = surface; +} + +void TextureMapperSurfaceBackingStore::swapBuffersIfNeeded(uint32_t) +{ + if (m_graphicsSurface) + m_graphicsSurface->swapBuffers(); +} + +PassRefPtr<BitmapTexture> TextureMapperSurfaceBackingStore::texture() const +{ + // FIXME: Instead of just returning an empty texture, we should wrap the texture contents into a BitmapTexture. + RefPtr<BitmapTexture> emptyTexture; + return emptyTexture; +} + +void TextureMapperSurfaceBackingStore::paintToTextureMapper(TextureMapper* textureMapper, const FloatRect& targetRect, const TransformationMatrix& transform, float opacity) +{ + if (m_graphicsSurface) + m_graphicsSurface->paintToTextureMapper(textureMapper, targetRect, transform, opacity); +} + +} // namespace WebCore +#endif diff --git a/Source/WebCore/platform/graphics/texmap/TextureMapperSurfaceBackingStore.h b/Source/WebCore/platform/graphics/texmap/TextureMapperSurfaceBackingStore.h new file mode 100644 index 000000000..793c61dc3 --- /dev/null +++ b/Source/WebCore/platform/graphics/texmap/TextureMapperSurfaceBackingStore.h @@ -0,0 +1,55 @@ +/* + Copyright (C) 2013 Nokia Corporation and/or its subsidiary(-ies) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + */ + +#ifndef TextureMapperSurfaceBackingStore_h +#define TextureMapperSurfaceBackingStore_h + +#if USE(ACCELERATED_COMPOSITING) && USE(GRAPHICS_SURFACE) + +#include "GraphicsSurface.h" +#include "TextureMapperBackingStore.h" +#include <wtf/RefPtr.h> + +namespace WebCore { + +class TextureMapper; +class FloatRect; + +class TextureMapperSurfaceBackingStore : public TextureMapperBackingStore { +public: + static PassRefPtr<TextureMapperSurfaceBackingStore> create() { return adoptRef(new TextureMapperSurfaceBackingStore); } + void setGraphicsSurface(PassRefPtr<GraphicsSurface>); + void swapBuffersIfNeeded(uint32_t frontBuffer); + virtual PassRefPtr<BitmapTexture> texture() const; + virtual void paintToTextureMapper(TextureMapper*, const FloatRect&, const TransformationMatrix&, float); + virtual ~TextureMapperSurfaceBackingStore() { } + +private: + TextureMapperSurfaceBackingStore() + : TextureMapperBackingStore() + { } + + RefPtr<GraphicsSurface> m_graphicsSurface; +}; + +} + +#endif + +#endif diff --git a/Source/WebCore/platform/graphics/texmap/TextureMapperTile.cpp b/Source/WebCore/platform/graphics/texmap/TextureMapperTile.cpp new file mode 100644 index 000000000..2ea7fb6ed --- /dev/null +++ b/Source/WebCore/platform/graphics/texmap/TextureMapperTile.cpp @@ -0,0 +1,79 @@ +/* + Copyright (C) 2013 Nokia Corporation and/or its subsidiary(-ies) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + */ +#include "config.h" + +#if USE(ACCELERATED_COMPOSITING) && USE(TEXTURE_MAPPER) +#include "TextureMapperTile.h" + +#include "Image.h" +#include "TextureMapper.h" +#include <wtf/RefPtr.h> + +namespace WebCore { + +class GraphicsLayer; + +void TextureMapperTile::updateContents(TextureMapper* textureMapper, Image* image, const IntRect& dirtyRect, BitmapTexture::UpdateContentsFlag updateContentsFlag) +{ + IntRect targetRect = enclosingIntRect(m_rect); + targetRect.intersect(dirtyRect); + if (targetRect.isEmpty()) + return; + IntPoint sourceOffset = targetRect.location(); + + // Normalize sourceRect to the buffer's coordinates. + sourceOffset.move(-dirtyRect.x(), -dirtyRect.y()); + + // Normalize targetRect to the texture's coordinates. + targetRect.move(-m_rect.x(), -m_rect.y()); + if (!m_texture) { + m_texture = textureMapper->createTexture(); + m_texture->reset(targetRect.size(), image->currentFrameKnownToBeOpaque() ? 0 : BitmapTexture::SupportsAlpha); + } + + m_texture->updateContents(image, targetRect, sourceOffset, updateContentsFlag); +} + +void TextureMapperTile::updateContents(TextureMapper* textureMapper, GraphicsLayer* sourceLayer, const IntRect& dirtyRect, BitmapTexture::UpdateContentsFlag updateContentsFlag) +{ + IntRect targetRect = enclosingIntRect(m_rect); + targetRect.intersect(dirtyRect); + if (targetRect.isEmpty()) + return; + IntPoint sourceOffset = targetRect.location(); + + // Normalize targetRect to the texture's coordinates. + targetRect.move(-m_rect.x(), -m_rect.y()); + + if (!m_texture) { + m_texture = textureMapper->createTexture(); + m_texture->reset(targetRect.size(), BitmapTexture::SupportsAlpha); + } + + m_texture->updateContents(textureMapper, sourceLayer, targetRect, sourceOffset, updateContentsFlag); +} + +void TextureMapperTile::paint(TextureMapper* textureMapper, const TransformationMatrix& transform, float opacity, const unsigned exposedEdges) +{ + if (texture().get()) + textureMapper->drawTexture(*texture().get(), rect(), transform, opacity, exposedEdges); +} + +} // namespace WebCore +#endif diff --git a/Source/WebCore/platform/graphics/texmap/TextureMapperTile.h b/Source/WebCore/platform/graphics/texmap/TextureMapperTile.h new file mode 100644 index 000000000..ee6809f20 --- /dev/null +++ b/Source/WebCore/platform/graphics/texmap/TextureMapperTile.h @@ -0,0 +1,60 @@ +/* + Copyright (C) 2013 Nokia Corporation and/or its subsidiary(-ies) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + */ + +#ifndef TextureMapperTile_h +#define TextureMapperTile_h + +#if USE(ACCELERATED_COMPOSITING) && USE(TEXTURE_MAPPER) + +#include "FloatRect.h" +#include "Image.h" +#include "TextureMapper.h" +#include "TextureMapperPlatformLayer.h" +#include <wtf/RefPtr.h> + +namespace WebCore { + +class GraphicsLayer; + +class TextureMapperTile { +public: + inline PassRefPtr<BitmapTexture> texture() const { return m_texture; } + inline FloatRect rect() const { return m_rect; } + inline void setTexture(BitmapTexture* texture) { m_texture = texture; } + inline void setRect(const FloatRect& rect) { m_rect = rect; } + + void updateContents(TextureMapper*, Image*, const IntRect&, BitmapTexture::UpdateContentsFlag UpdateCanModifyOriginalImageData); + void updateContents(TextureMapper*, GraphicsLayer*, const IntRect&, BitmapTexture::UpdateContentsFlag UpdateCanModifyOriginalImageData); + virtual void paint(TextureMapper*, const TransformationMatrix&, float, const unsigned exposedEdges); + virtual ~TextureMapperTile() { } + + explicit TextureMapperTile(const FloatRect& rect) + : m_rect(rect) + { + } + +private: + RefPtr<BitmapTexture> m_texture; + FloatRect m_rect; +}; + +} +#endif + +#endif diff --git a/Source/WebCore/platform/graphics/texmap/TextureMapperTiledBackingStore.cpp b/Source/WebCore/platform/graphics/texmap/TextureMapperTiledBackingStore.cpp new file mode 100644 index 000000000..ef564023d --- /dev/null +++ b/Source/WebCore/platform/graphics/texmap/TextureMapperTiledBackingStore.cpp @@ -0,0 +1,162 @@ +/* + Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + */ + +#include "config.h" + +#if USE(ACCELERATED_COMPOSITING) && USE(TEXTURE_MAPPER) +#include "TextureMapperTiledBackingStore.h" + +#include "ImageBuffer.h" +#include "TextureMapper.h" + +namespace WebCore { + +class GraphicsLayer; + +TextureMapperTiledBackingStore::TextureMapperTiledBackingStore() +{ +} + +void TextureMapperTiledBackingStore::updateContentsFromImageIfNeeded(TextureMapper* textureMapper) +{ + if (!m_image) + return; + + updateContents(textureMapper, m_image.get(), m_image->size(), m_image->rect(), BitmapTexture::UpdateCannotModifyOriginalImageData); + m_image.clear(); +} + +TransformationMatrix TextureMapperTiledBackingStore::adjustedTransformForRect(const FloatRect& targetRect) +{ + return TransformationMatrix::rectToRect(rect(), targetRect); +} + +void TextureMapperTiledBackingStore::paintToTextureMapper(TextureMapper* textureMapper, const FloatRect& targetRect, const TransformationMatrix& transform, float opacity) +{ + updateContentsFromImageIfNeeded(textureMapper); + TransformationMatrix adjustedTransform = transform * adjustedTransformForRect(targetRect); + for (size_t i = 0; i < m_tiles.size(); ++i) + m_tiles[i].paint(textureMapper, adjustedTransform, opacity, calculateExposedTileEdges(rect(), m_tiles[i].rect())); +} + +void TextureMapperTiledBackingStore::drawBorder(TextureMapper* textureMapper, const Color& borderColor, float borderWidth, const FloatRect& targetRect, const TransformationMatrix& transform) +{ + TransformationMatrix adjustedTransform = transform * adjustedTransformForRect(targetRect); + for (size_t i = 0; i < m_tiles.size(); ++i) + textureMapper->drawBorder(borderColor, borderWidth, m_tiles[i].rect(), adjustedTransform); +} + +void TextureMapperTiledBackingStore::drawRepaintCounter(TextureMapper* textureMapper, int repaintCount, const Color& borderColor, const FloatRect& targetRect, const TransformationMatrix& transform) +{ + TransformationMatrix adjustedTransform = transform * adjustedTransformForRect(targetRect); + for (size_t i = 0; i < m_tiles.size(); ++i) + textureMapper->drawNumber(repaintCount, borderColor, m_tiles[i].rect().location(), adjustedTransform); +} + +void TextureMapperTiledBackingStore::createOrDestroyTilesIfNeeded(const FloatSize& size, const IntSize& tileSize, bool hasAlpha) +{ + if (size == m_size) + return; + + m_size = size; + + Vector<FloatRect> tileRectsToAdd; + Vector<int> tileIndicesToRemove; + static const size_t TileEraseThreshold = 6; + + // This method recycles tiles. We check which tiles we need to add, which to remove, and use as many + // removable tiles as replacement for new tiles when possible. + for (float y = 0; y < m_size.height(); y += tileSize.height()) { + for (float x = 0; x < m_size.width(); x += tileSize.width()) { + FloatRect tileRect(x, y, tileSize.width(), tileSize.height()); + tileRect.intersect(rect()); + tileRectsToAdd.append(tileRect); + } + } + + // Check which tiles need to be removed, and which already exist. + for (int i = m_tiles.size() - 1; i >= 0; --i) { + FloatRect oldTile = m_tiles[i].rect(); + bool existsAlready = false; + + for (int j = tileRectsToAdd.size() - 1; j >= 0; --j) { + FloatRect newTile = tileRectsToAdd[j]; + if (oldTile != newTile) + continue; + + // A tile that we want to add already exists, no need to add or remove it. + existsAlready = true; + tileRectsToAdd.remove(j); + break; + } + + // This tile is not needed. + if (!existsAlready) + tileIndicesToRemove.append(i); + } + + // Recycle removable tiles to be used for newly requested tiles. + for (size_t i = 0; i < tileRectsToAdd.size(); ++i) { + if (!tileIndicesToRemove.isEmpty()) { + // We recycle an existing tile for usage with a new tile rect. + TextureMapperTile& tile = m_tiles[tileIndicesToRemove.last()]; + tileIndicesToRemove.removeLast(); + tile.setRect(tileRectsToAdd[i]); + + if (tile.texture()) + tile.texture()->reset(enclosingIntRect(tile.rect()).size(), hasAlpha ? BitmapTexture::SupportsAlpha : 0); + continue; + } + + m_tiles.append(TextureMapperTile(tileRectsToAdd[i])); + } + + // Remove unnecessary tiles, if they weren't recycled. + // We use a threshold to make sure we don't create/destroy tiles too eagerly. + for (size_t i = 0; i < tileIndicesToRemove.size() && m_tiles.size() > TileEraseThreshold; ++i) + m_tiles.remove(tileIndicesToRemove[i]); +} + +void TextureMapperTiledBackingStore::updateContents(TextureMapper* textureMapper, Image* image, const FloatSize& totalSize, const IntRect& dirtyRect, BitmapTexture::UpdateContentsFlag updateContentsFlag) +{ + createOrDestroyTilesIfNeeded(totalSize, textureMapper->maxTextureSize(), !image->currentFrameKnownToBeOpaque()); + for (size_t i = 0; i < m_tiles.size(); ++i) + m_tiles[i].updateContents(textureMapper, image, dirtyRect, updateContentsFlag); +} + +void TextureMapperTiledBackingStore::updateContents(TextureMapper* textureMapper, GraphicsLayer* sourceLayer, const FloatSize& totalSize, const IntRect& dirtyRect, BitmapTexture::UpdateContentsFlag updateContentsFlag) +{ + createOrDestroyTilesIfNeeded(totalSize, textureMapper->maxTextureSize(), true); + for (size_t i = 0; i < m_tiles.size(); ++i) + m_tiles[i].updateContents(textureMapper, sourceLayer, dirtyRect, updateContentsFlag); +} + +PassRefPtr<BitmapTexture> TextureMapperTiledBackingStore::texture() const +{ + for (size_t i = 0; i < m_tiles.size(); ++i) { + RefPtr<BitmapTexture> texture = m_tiles[i].texture(); + if (texture) + return texture; + } + + return PassRefPtr<BitmapTexture>(); +} + +} // namespace WebCore +#endif diff --git a/Source/WebCore/platform/graphics/texmap/TextureMapperTiledBackingStore.h b/Source/WebCore/platform/graphics/texmap/TextureMapperTiledBackingStore.h new file mode 100644 index 000000000..9b8568463 --- /dev/null +++ b/Source/WebCore/platform/graphics/texmap/TextureMapperTiledBackingStore.h @@ -0,0 +1,64 @@ +/* + Copyright (C) 2013 Nokia Corporation and/or its subsidiary(-ies) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + */ + +#ifndef TextureMapperTiledBackingStore_h +#define TextureMapperTiledBackingStore_h + +#if USE(ACCELERATED_COMPOSITING) && USE(TEXTURE_MAPPER) + +#include "FloatRect.h" +#include "Image.h" +#include "TextureMapperBackingStore.h" +#include "TextureMapperTile.h" +#include <wtf/RefPtr.h> + +namespace WebCore { + +class TextureMapper; + +class TextureMapperTiledBackingStore : public TextureMapperBackingStore { +public: + static PassRefPtr<TextureMapperTiledBackingStore> create() { return adoptRef(new TextureMapperTiledBackingStore); } + virtual ~TextureMapperTiledBackingStore() { } + + virtual PassRefPtr<BitmapTexture> texture() const OVERRIDE; + virtual void paintToTextureMapper(TextureMapper*, const FloatRect&, const TransformationMatrix&, float) OVERRIDE; + virtual void drawBorder(TextureMapper*, const Color&, float borderWidth, const FloatRect&, const TransformationMatrix&) OVERRIDE; + virtual void drawRepaintCounter(TextureMapper*, int repaintCount, const Color&, const FloatRect&, const TransformationMatrix&) OVERRIDE; + void updateContents(TextureMapper*, Image*, const FloatSize&, const IntRect&, BitmapTexture::UpdateContentsFlag); + void updateContents(TextureMapper*, GraphicsLayer*, const FloatSize&, const IntRect&, BitmapTexture::UpdateContentsFlag); + + void setContentsToImage(Image* image) { m_image = image; } + +private: + TextureMapperTiledBackingStore(); + void createOrDestroyTilesIfNeeded(const FloatSize& backingStoreSize, const IntSize& tileSize, bool hasAlpha); + void updateContentsFromImageIfNeeded(TextureMapper*); + TransformationMatrix adjustedTransformForRect(const FloatRect&); + inline FloatRect rect() const { return FloatRect(FloatPoint::zero(), m_size); } + + Vector<TextureMapperTile> m_tiles; + FloatSize m_size; + RefPtr<Image> m_image; +}; + +} // namespace WebCore +#endif + +#endif diff --git a/Source/WebCore/platform/graphics/texmap/coordinated/AreaAllocator.cpp b/Source/WebCore/platform/graphics/texmap/coordinated/AreaAllocator.cpp new file mode 100644 index 000000000..9f54185b9 --- /dev/null +++ b/Source/WebCore/platform/graphics/texmap/coordinated/AreaAllocator.cpp @@ -0,0 +1,335 @@ +/* + * Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "config.h" + +#if USE(COORDINATED_GRAPHICS) + +#include "AreaAllocator.h" + +namespace WebCore { + +AreaAllocator::AreaAllocator(const IntSize& size) + : m_size(size) + , m_minAlloc(1, 1) + , m_margin(0, 0) +{ +} + +AreaAllocator::~AreaAllocator() +{ +} + +void AreaAllocator::expand(const IntSize& size) +{ + m_size = m_size.expandedTo(size); +} + +void AreaAllocator::expandBy(const IntSize& size) +{ + m_size += size; +} + +void AreaAllocator::release(const IntRect&) +{ +} + +int AreaAllocator::overhead() const +{ + return 0; +} + +IntSize AreaAllocator::roundAllocation(const IntSize& size) const +{ + int width = size.width() + m_margin.width(); + int height = size.height() + m_margin.height(); + int extra = width % m_minAlloc.width(); + if (extra) + width += m_minAlloc.width() - extra; + extra = height % m_minAlloc.height(); + if (extra) + height += m_minAlloc.height() - extra; + + return IntSize(width, height); +} + +GeneralAreaAllocator::GeneralAreaAllocator(const IntSize& size) + : AreaAllocator(nextPowerOfTwo(size)) +{ + m_root = new Node(); + m_root->rect = IntRect(0, 0, m_size.width(), m_size.height()); + m_root->largestFree = m_size; + m_root->parent = 0; + m_root->left = 0; + m_root->right = 0; + m_nodeCount = 1; + setMinimumAllocation(IntSize(8, 8)); +} + +GeneralAreaAllocator::~GeneralAreaAllocator() +{ + freeNode(m_root); +} + +void GeneralAreaAllocator::freeNode(Node* node) +{ + if (node) { + freeNode(node->left); + freeNode(node->right); + } + delete node; +} + +void GeneralAreaAllocator::expand(const IntSize& size) +{ + AreaAllocator::expand(nextPowerOfTwo(size)); + + if (m_root->rect.size() == m_size) + return; // No change. + + if (!m_root->left && m_root->largestFree.width() > 0) { + // No allocations have occurred, so just adjust the root size. + m_root->rect = IntRect(0, 0, m_size.width(), m_size.height()); + m_root->largestFree = m_size; + return; + } + + // Add extra nodes above the current root to expand the tree. + Node* oldRoot = m_root; + Split split; + if (m_size.width() >= m_size.height()) + split = SplitOnX; + else + split = SplitOnY; + + while (m_root->rect.size() != m_size) { + if (m_root->rect.width() == m_size.width()) + split = SplitOnY; + else if (m_root->rect.height() == m_size.height()) + split = SplitOnX; + Node* parent = new Node(); + Node* right = new Node(); + m_nodeCount += 2; + m_root->parent = parent; + parent->parent = 0; + parent->left = m_root; + parent->right = right; + parent->largestFree = m_root->rect.size(); + right->parent = parent; + right->left = 0; + right->right = 0; + right->largestFree = m_root->rect.size(); + if (split == SplitOnX) { + parent->rect = IntRect(m_root->rect.x(), m_root->rect.y(), + m_root->rect.width() * 2, m_root->rect.height()); + right->rect = IntRect(m_root->rect.x() + m_root->rect.width(), m_root->rect.y(), + m_root->rect.width(), m_root->rect.height()); + } else { + parent->rect = IntRect(m_root->rect.x(), m_root->rect.y(), + m_root->rect.width(), m_root->rect.height() * 2); + right->rect = IntRect(m_root->rect.x(), m_root->rect.y() + m_root->rect.width(), + m_root->rect.width(), m_root->rect.height()); + } + split = (split == SplitOnX ? SplitOnY : SplitOnX); + m_root = parent; + } + updateLargestFree(oldRoot); +} + +static inline bool fitsWithin(const IntSize& size1, const IntSize& size2) +{ + return size1.width() <= size2.width() && size1.height() <= size2.height(); +} + +IntRect GeneralAreaAllocator::allocate(const IntSize& size) +{ + IntSize rounded = roundAllocation(size); + rounded = nextPowerOfTwo(rounded); + if (rounded.width() <= 0 || rounded.width() > m_size.width() + || rounded.height() <= 0 || rounded.height() > m_size.height()) + return IntRect(); + + IntPoint point = allocateFromNode(rounded, m_root); + if (point.x() >= 0) + return IntRect(point, size); + return IntRect(); +} + +IntPoint GeneralAreaAllocator::allocateFromNode(const IntSize& size, Node* node) +{ + // Find the best node to insert into, which should be + // a node with the least amount of unused space that is + // big enough to contain the requested size. + while (node) { + // Go down a level and determine if the left or right + // sub-tree contains the best chance of allocation. + Node* left = node->left; + Node* right = node->right; + if (left && fitsWithin(size, left->largestFree)) { + if (right && fitsWithin(size, right->largestFree)) { + if (left->largestFree.width() < right->largestFree.width() + || left->largestFree.height() < right->largestFree.height()) { + // The largestFree values may be a little oversized, + // so try the left sub-tree and then the right sub-tree. + IntPoint point = allocateFromNode(size, left); + if (point.x() >= 0) + return point; + return allocateFromNode(size, right); + } + node = right; + } else + node = left; + } else if (right && fitsWithin(size, right->largestFree)) + node = right; + else if (left || right) { + // Neither sub-node has enough space to allocate from. + return IntPoint(-1, -1); + } else if (fitsWithin(size, node->largestFree)) { + // Do we need to split this node into smaller pieces? + Split split; + if (fitsWithin(IntSize(size.width() * 2, size.height() * 2), node->largestFree)) { + // Split in either direction: choose the inverse of + // the parent node's split direction to try to balance + // out the wasted space as further subdivisions happen. + if (node->parent + && node->parent->left->rect.x() == node->parent->right->rect.x()) + split = SplitOnX; + else if (node->parent) + split = SplitOnY; + else if (node->rect.width() >= node->rect.height()) + split = SplitOnX; + else + split = SplitOnY; + } else if (fitsWithin(IntSize(size.width() * 2, size.height()), node->largestFree)) { + // Split along the X direction. + split = SplitOnX; + } else if (fitsWithin(IntSize(size.width(), size.height() * 2), node->largestFree)) { + // Split along the Y direction. + split = SplitOnY; + } else { + // Cannot split further - allocate this node. + node->largestFree = IntSize(0, 0); + updateLargestFree(node); + return node->rect.location(); + } + + // Split the node, then go around again using the left sub-tree. + node = splitNode(node, split); + } else { + // Cannot possibly fit into this node. + break; + } + } + return IntPoint(-1, -1); +} + +GeneralAreaAllocator::Node* GeneralAreaAllocator::splitNode + (Node* node, Split split) +{ + Node* left = new Node(); + Node* right = new Node(); + m_nodeCount += 2; + left->parent = node; + left->left = 0; + left->right = 0; + right->parent = node; + right->left = 0; + right->right = 0; + node->left = left; + node->right = right; + + if (split == SplitOnX) { + left->rect = IntRect(node->rect.x(), node->rect.y(), + node->rect.width() / 2, node->rect.height()); + right->rect = IntRect(left->rect.maxX(), node->rect.y(), + node->rect.width() / 2, node->rect.height()); + } else { + left->rect = IntRect(node->rect.x(), node->rect.y(), + node->rect.width(), node->rect.height() / 2); + right->rect = IntRect(node->rect.x(), left->rect.maxY(), + node->rect.width(), node->rect.height() / 2); + } + + left->largestFree = left->rect.size(); + right->largestFree = right->rect.size(); + node->largestFree = right->largestFree; + return left; +} + +void GeneralAreaAllocator::updateLargestFree(Node* node) +{ + while ((node = node->parent)) { + node->largestFree = IntSize( + std::max(node->left->largestFree.width(), node->right->largestFree.width()), + std::max(node->left->largestFree.height(), node->right->largestFree.height()) + ); + } +} + +void GeneralAreaAllocator::release(const IntRect& rect) +{ + // Locate the node that contains the allocated region. + Node* node = m_root; + IntPoint point = rect.location(); + while (node) { + if (node->left && node->left->rect.contains(point)) + node = node->left; + else if (node->right && node->right->rect.contains(point)) + node = node->right; + else if (node->rect.contains(point)) + break; + else + return; // Point is completely outside the tree. + } + if (!node) + return; + + // Mark the node as free and then work upwards through the tree + // recombining and deleting nodes until we reach a sibling + // that is still allocated. + node->largestFree = node->rect.size(); + while (node->parent) { + if (node->parent->left == node) { + if (node->parent->right->largestFree != node->parent->right->rect.size()) + break; + } else { + if (node->parent->left->largestFree != node->parent->left->rect.size()) + break; + } + node = node->parent; + freeNode(node->left); + freeNode(node->right); + m_nodeCount -= 2; + node->left = 0; + node->right = 0; + node->largestFree = node->rect.size(); + } + + // Make the rest of our ancestors have the correct "largest free size". + updateLargestFree(node); +} + +int GeneralAreaAllocator::overhead() const +{ + return m_nodeCount * sizeof(Node); +} + +} // namespace WebCore + +#endif // USE(COORDINATED_GRAPHICS) diff --git a/Source/WebCore/platform/graphics/texmap/coordinated/AreaAllocator.h b/Source/WebCore/platform/graphics/texmap/coordinated/AreaAllocator.h new file mode 100644 index 000000000..4180cae23 --- /dev/null +++ b/Source/WebCore/platform/graphics/texmap/coordinated/AreaAllocator.h @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef AreaAllocator_h +#define AreaAllocator_h + +#include "IntPoint.h" +#include "IntRect.h" +#include "IntSize.h" + +#if USE(COORDINATED_GRAPHICS) + +namespace WebCore { + +inline int nextPowerOfTwo(int number) +{ + // This is a fast trick to get nextPowerOfTwo for an integer. + --number; + number |= number >> 1; + number |= number >> 2; + number |= number >> 4; + number |= number >> 8; + number |= number >> 16; + number++; + return number; +} + +inline IntSize nextPowerOfTwo(const IntSize& size) +{ + return IntSize(nextPowerOfTwo(size.width()), nextPowerOfTwo(size.height())); +} + +class AreaAllocator { +public: + explicit AreaAllocator(const IntSize&); + virtual ~AreaAllocator(); + + IntSize size() const { return m_size; } + + IntSize minimumAllocation() const { return m_minAlloc; } + void setMinimumAllocation(const IntSize& size) { m_minAlloc = size; } + + IntSize margin() const { return m_margin; } + void setMargin(const IntSize &margin) { m_margin = margin; } + + virtual void expand(const IntSize&); + void expandBy(const IntSize&); + + virtual IntRect allocate(const IntSize&) = 0; + virtual void release(const IntRect&); + + virtual int overhead() const; + +protected: + IntSize m_size; + IntSize m_minAlloc; + IntSize m_margin; + + IntSize roundAllocation(const IntSize&) const; +}; + +class GeneralAreaAllocator : public AreaAllocator { +public: + explicit GeneralAreaAllocator(const IntSize&); + virtual ~GeneralAreaAllocator(); + + void expand(const IntSize&); + IntRect allocate(const IntSize&); + void release(const IntRect&); + int overhead() const; + +private: + enum Split { SplitOnX, SplitOnY }; + + struct Node { + IntRect rect; + IntSize largestFree; + Node* parent; + Node* left; + Node* right; + }; + + Node* m_root; + int m_nodeCount; + + static void freeNode(Node*); + IntPoint allocateFromNode(const IntSize&, Node*); + Node* splitNode(Node*, Split); + static void updateLargestFree(Node*); +}; + +} // namespace WebCore + +#endif // USE(COORDINATED_GRAPHICS) + +#endif // AreaAllocator_h diff --git a/Source/WebCore/platform/graphics/texmap/coordinated/CompositingCoordinator.cpp b/Source/WebCore/platform/graphics/texmap/coordinated/CompositingCoordinator.cpp new file mode 100644 index 000000000..74cd528ec --- /dev/null +++ b/Source/WebCore/platform/graphics/texmap/coordinated/CompositingCoordinator.cpp @@ -0,0 +1,434 @@ +/* + * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). + * Copyright (C) 2013 Company 100, 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. AND ITS CONTRIBUTORS ``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 INC. OR ITS 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(COORDINATED_GRAPHICS) +#include "CompositingCoordinator.h" + +#include "Frame.h" +#include "FrameView.h" +#include "GraphicsContext.h" +#include "InspectorController.h" +#include "Page.h" +#include "Settings.h" +#include <wtf/CurrentTime.h> +#include <wtf/TemporaryChange.h> + +namespace WebCore { + +PassOwnPtr<CompositingCoordinator> CompositingCoordinator::create(Page* page, CompositingCoordinator::Client* client) +{ + return adoptPtr(new CompositingCoordinator(page, client)); +} + +CompositingCoordinator::~CompositingCoordinator() +{ + purgeBackingStores(); + + LayerMap::iterator end = m_registeredLayers.end(); + for (LayerMap::iterator it = m_registeredLayers.begin(); it != end; ++it) + it->value->setCoordinator(0); +} + +CompositingCoordinator::CompositingCoordinator(Page* page, CompositingCoordinator::Client* client) + : m_page(page) + , m_client(client) + , m_rootCompositingLayer(0) + , m_isPurging(false) + , m_isFlushingLayerChanges(false) + , m_shouldSyncFrame(false) + , m_didInitializeRootCompositingLayer(false) + , m_releaseInactiveAtlasesTimer(this, &CompositingCoordinator::releaseInactiveAtlasesTimerFired) +#if ENABLE(REQUEST_ANIMATION_FRAME) + , m_lastAnimationServiceTime(0) +#endif +{ + m_page->settings()->setApplyDeviceScaleFactorInCompositor(true); + + // This is a temporary way to enable this only in the GL case, until TextureMapperImageBuffer is removed. + // See https://bugs.webkit.org/show_bug.cgi?id=114869 + CoordinatedGraphicsLayer::setShouldSupportContentsTiling(true); +} + +void CompositingCoordinator::setRootCompositingLayer(GraphicsLayer* layer) +{ + if (m_rootCompositingLayer) + m_rootCompositingLayer->removeFromParent(); + + m_rootCompositingLayer = layer; + if (m_rootCompositingLayer) + m_rootLayer->addChildAtIndex(m_rootCompositingLayer, 0); +} + +void CompositingCoordinator::sizeDidChange(const IntSize& newSize) +{ + m_rootLayer->setSize(newSize); + m_client->notifyFlushRequired(); +} + +bool CompositingCoordinator::flushPendingLayerChanges() +{ + TemporaryChange<bool> protector(m_isFlushingLayerChanges, true); + + initializeRootCompositingLayerIfNeeded(); + + m_rootLayer->flushCompositingStateForThisLayerOnly(); + m_client->didFlushRootLayer(); + + bool didSync = m_page->mainFrame()->view()->flushCompositingStateIncludingSubframes(); + + toCoordinatedGraphicsLayer(m_rootLayer.get())->updateContentBuffersIncludingSubLayers(); + toCoordinatedGraphicsLayer(m_rootLayer.get())->syncPendingStateChangesIncludingSubLayers(); + + flushPendingImageBackingChanges(); + + if (m_shouldSyncFrame) { + didSync = true; + + if (m_rootCompositingLayer) { + m_state.contentsSize = roundedIntSize(m_rootCompositingLayer->size()); + if (CoordinatedGraphicsLayer* contentsLayer = mainContentsLayer()) + m_state.coveredRect = contentsLayer->coverRect(); + } + m_state.scrollPosition = m_visibleContentsRect.location(); + + m_client->commitSceneState(m_state); + + clearPendingStateChanges(); + m_shouldSyncFrame = false; + } + + return didSync; +} + +void CompositingCoordinator::syncDisplayState() +{ +#if ENABLE(INSPECTOR) + m_page->inspectorController()->didBeginFrame(); +#endif + +#if ENABLE(REQUEST_ANIMATION_FRAME) && !USE(REQUEST_ANIMATION_FRAME_TIMER) && !USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR) + // Make sure that any previously registered animation callbacks are being executed before we flush the layers. + m_lastAnimationServiceTime = WTF::monotonicallyIncreasingTime(); + m_page->mainFrame()->view()->serviceScriptedAnimations(m_lastAnimationServiceTime); +#endif + m_page->mainFrame()->view()->updateLayoutAndStyleIfNeededRecursive(); +} + +#if ENABLE(REQUEST_ANIMATION_FRAME) +double CompositingCoordinator::nextAnimationServiceTime() const +{ + // According to the requestAnimationFrame spec, rAF callbacks should not be faster than 60FPS. + static const double MinimalTimeoutForAnimations = 1. / 60.; + return std::max<double>(0., MinimalTimeoutForAnimations - WTF::monotonicallyIncreasingTime() + m_lastAnimationServiceTime); +} +#endif + +void CompositingCoordinator::clearPendingStateChanges() +{ + m_state.layersToCreate.clear(); + m_state.layersToUpdate.clear(); + m_state.layersToRemove.clear(); + + m_state.imagesToCreate.clear(); + m_state.imagesToRemove.clear(); + m_state.imagesToUpdate.clear(); + m_state.imagesToClear.clear(); + + m_state.updateAtlasesToCreate.clear(); + m_state.updateAtlasesToRemove.clear(); + +#if ENABLE(CSS_SHADERS) + m_state.customFiltersToCreate.clear(); + m_state.customFiltersToRemove.clear(); +#endif +} + +void CompositingCoordinator::initializeRootCompositingLayerIfNeeded() +{ + if (m_didInitializeRootCompositingLayer) + return; + + m_state.rootCompositingLayer = toCoordinatedGraphicsLayer(m_rootLayer.get())->id(); + m_didInitializeRootCompositingLayer = true; + m_shouldSyncFrame = true; +} + +void CompositingCoordinator::createRootLayer(const IntSize& size) +{ + ASSERT(!m_rootLayer); + // Create a root layer. + m_rootLayer = GraphicsLayer::create(this, this); +#ifndef NDEBUG + m_rootLayer->setName("CompositingCoordinator root layer"); +#endif + m_rootLayer->setDrawsContent(false); + m_rootLayer->setSize(size); +} + +void CompositingCoordinator::syncLayerState(CoordinatedLayerID id, CoordinatedGraphicsLayerState& state) +{ + m_shouldSyncFrame = true; + m_client->willSyncLayerState(state); + m_state.layersToUpdate.append(std::make_pair(id, state)); +} + +PassRefPtr<CoordinatedImageBacking> CompositingCoordinator::createImageBackingIfNeeded(Image* image) +{ + CoordinatedImageBackingID imageID = CoordinatedImageBacking::getCoordinatedImageBackingID(image); + ImageBackingMap::iterator it = m_imageBackings.find(imageID); + RefPtr<CoordinatedImageBacking> imageBacking; + if (it == m_imageBackings.end()) { + imageBacking = CoordinatedImageBacking::create(this, image); + m_imageBackings.add(imageID, imageBacking); + } else + imageBacking = it->value; + + return imageBacking; +} + +void CompositingCoordinator::createImageBacking(CoordinatedImageBackingID imageID) +{ + m_state.imagesToCreate.append(imageID); +} + +void CompositingCoordinator::updateImageBacking(CoordinatedImageBackingID imageID, PassRefPtr<CoordinatedSurface> coordinatedSurface) +{ + m_shouldSyncFrame = true; + m_state.imagesToUpdate.append(std::make_pair(imageID, coordinatedSurface)); +} + +void CompositingCoordinator::clearImageBackingContents(CoordinatedImageBackingID imageID) +{ + m_shouldSyncFrame = true; + m_state.imagesToClear.append(imageID); +} + +void CompositingCoordinator::removeImageBacking(CoordinatedImageBackingID imageID) +{ + if (m_isPurging) + return; + + ASSERT(m_imageBackings.contains(imageID)); + m_imageBackings.remove(imageID); + + m_state.imagesToRemove.append(imageID); +} + +void CompositingCoordinator::flushPendingImageBackingChanges() +{ + ImageBackingMap::iterator end = m_imageBackings.end(); + for (ImageBackingMap::iterator iter = m_imageBackings.begin(); iter != end; ++iter) + iter->value->update(); +} + +void CompositingCoordinator::notifyAnimationStarted(const GraphicsLayer*, double /* time */) +{ +} + +void CompositingCoordinator::notifyFlushRequired(const GraphicsLayer*) +{ + m_client->notifyFlushRequired(); +} + + +void CompositingCoordinator::paintContents(const GraphicsLayer* graphicsLayer, GraphicsContext& graphicsContext, GraphicsLayerPaintingPhase, const IntRect& clipRect) +{ + m_client->paintLayerContents(graphicsLayer, graphicsContext, clipRect); +} + +PassOwnPtr<GraphicsLayer> CompositingCoordinator::createGraphicsLayer(GraphicsLayerClient* client) +{ + CoordinatedGraphicsLayer* layer = new CoordinatedGraphicsLayer(client); + layer->setCoordinator(this); + m_registeredLayers.add(layer->id(), layer); + m_state.layersToCreate.append(layer->id()); + layer->setNeedsVisibleRectAdjustment(); + m_client->notifyFlushRequired(); + return adoptPtr(layer); +} + +float CompositingCoordinator::deviceScaleFactor() const +{ + return m_page->deviceScaleFactor(); +} + +float CompositingCoordinator::pageScaleFactor() const +{ + return m_page->pageScaleFactor(); +} + +void CompositingCoordinator::createUpdateAtlas(uint32_t atlasID, PassRefPtr<CoordinatedSurface> coordinatedSurface) +{ + m_state.updateAtlasesToCreate.append(std::make_pair(atlasID, coordinatedSurface)); +} + +void CompositingCoordinator::removeUpdateAtlas(uint32_t atlasID) +{ + if (m_isPurging) + return; + m_state.updateAtlasesToRemove.append(atlasID); +} + +FloatRect CompositingCoordinator::visibleContentsRect() const +{ + return m_visibleContentsRect; +} + +CoordinatedGraphicsLayer* CompositingCoordinator::mainContentsLayer() +{ + if (!m_rootCompositingLayer) + return 0; + + return toCoordinatedGraphicsLayer(m_rootCompositingLayer)->findFirstDescendantWithContentsRecursively(); +} + +void CompositingCoordinator::setVisibleContentsRect(const FloatRect& rect, const FloatPoint& trajectoryVector) +{ + // A zero trajectoryVector indicates that tiles all around the viewport are requested. + if (CoordinatedGraphicsLayer* contentsLayer = mainContentsLayer()) + contentsLayer->setVisibleContentRectTrajectoryVector(trajectoryVector); + + bool contentsRectDidChange = rect != m_visibleContentsRect; + if (contentsRectDidChange) { + m_visibleContentsRect = rect; + + LayerMap::iterator end = m_registeredLayers.end(); + for (LayerMap::iterator it = m_registeredLayers.begin(); it != end; ++it) + it->value->setNeedsVisibleRectAdjustment(); + } + + FrameView* view = m_page->mainFrame()->view(); + if (view->useFixedLayout()) { + // Round the rect instead of enclosing it to make sure that its size stays + // the same while panning. This can have nasty effects on layout. + view->setFixedVisibleContentRect(roundedIntRect(rect)); + } +} + +void CompositingCoordinator::deviceOrPageScaleFactorChanged() +{ + m_rootLayer->deviceOrPageScaleFactorChanged(); +} + +void CompositingCoordinator::detachLayer(CoordinatedGraphicsLayer* layer) +{ + if (m_isPurging) + return; + + m_registeredLayers.remove(layer->id()); + + size_t index = m_state.layersToCreate.find(layer->id()); + if (index != notFound) { + m_state.layersToCreate.remove(index); + return; + } + + m_state.layersToRemove.append(layer->id()); + m_client->notifyFlushRequired(); +} + +void CompositingCoordinator::commitScrollOffset(uint32_t layerID, const WebCore::IntSize& offset) +{ + LayerMap::iterator i = m_registeredLayers.find(layerID); + if (i == m_registeredLayers.end()) + return; + + i->value->commitScrollOffset(offset); +} + +void CompositingCoordinator::renderNextFrame() +{ + for (unsigned i = 0; i < m_updateAtlases.size(); ++i) + m_updateAtlases[i]->didSwapBuffers(); +} + +void CompositingCoordinator::purgeBackingStores() +{ + TemporaryChange<bool> purgingToggle(m_isPurging, true); + + LayerMap::iterator end = m_registeredLayers.end(); + for (LayerMap::iterator it = m_registeredLayers.begin(); it != end; ++it) + it->value->purgeBackingStores(); + + m_imageBackings.clear(); + m_updateAtlases.clear(); +} + +bool CompositingCoordinator::paintToSurface(const IntSize& size, CoordinatedSurface::Flags flags, uint32_t& atlasID, IntPoint& offset, CoordinatedSurface::Client* client) +{ + for (unsigned i = 0; i < m_updateAtlases.size(); ++i) { + UpdateAtlas* atlas = m_updateAtlases[i].get(); + if (atlas->supportsAlpha() == (flags & CoordinatedSurface::SupportsAlpha)) { + // This will be false if there is no available buffer space. + if (atlas->paintOnAvailableBuffer(size, atlasID, offset, client)) + return true; + } + } + + static const int ScratchBufferDimension = 1024; // Should be a power of two. + m_updateAtlases.append(adoptPtr(new UpdateAtlas(this, ScratchBufferDimension, flags))); + scheduleReleaseInactiveAtlases(); + return m_updateAtlases.last()->paintOnAvailableBuffer(size, atlasID, offset, client); +} + +const double ReleaseInactiveAtlasesTimerInterval = 0.5; + +void CompositingCoordinator::scheduleReleaseInactiveAtlases() +{ + if (!m_releaseInactiveAtlasesTimer.isActive()) + m_releaseInactiveAtlasesTimer.startRepeating(ReleaseInactiveAtlasesTimerInterval); +} + +void CompositingCoordinator::releaseInactiveAtlasesTimerFired(Timer<CompositingCoordinator>*) +{ + // We always want to keep one atlas for root contents layer. + OwnPtr<UpdateAtlas> atlasToKeepAnyway; + bool foundActiveAtlasForRootContentsLayer = false; + for (int i = m_updateAtlases.size() - 1; i >= 0; --i) { + UpdateAtlas* atlas = m_updateAtlases[i].get(); + if (!atlas->isInUse()) + atlas->addTimeInactive(ReleaseInactiveAtlasesTimerInterval); + bool usableForRootContentsLayer = !atlas->supportsAlpha(); + if (atlas->isInactive()) { + if (!foundActiveAtlasForRootContentsLayer && !atlasToKeepAnyway && usableForRootContentsLayer) + atlasToKeepAnyway = m_updateAtlases[i].release(); + m_updateAtlases.remove(i); + } else if (usableForRootContentsLayer) + foundActiveAtlasForRootContentsLayer = true; + } + + if (!foundActiveAtlasForRootContentsLayer && atlasToKeepAnyway) + m_updateAtlases.append(atlasToKeepAnyway.release()); + + if (m_updateAtlases.size() <= 1) + m_releaseInactiveAtlasesTimer.stop(); +} + +} // namespace WebCore + +#endif // USE(COORDINATED_GRAPHICS) diff --git a/Source/WebCore/platform/graphics/texmap/coordinated/CompositingCoordinator.h b/Source/WebCore/platform/graphics/texmap/coordinated/CompositingCoordinator.h new file mode 100644 index 000000000..fd41cb873 --- /dev/null +++ b/Source/WebCore/platform/graphics/texmap/coordinated/CompositingCoordinator.h @@ -0,0 +1,168 @@ +/* + * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies) + * Copyright (C) 2013 Company 100, 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. AND ITS CONTRIBUTORS ``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 INC. OR ITS 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 CompositingCoordinator_h +#define CompositingCoordinator_h + +#if USE(COORDINATED_GRAPHICS) + +#include "CoordinatedGraphicsLayer.h" +#include "CoordinatedGraphicsState.h" +#include "CoordinatedImageBacking.h" +#include "FloatPoint.h" +#include "GraphicsLayerClient.h" +#include "GraphicsLayerFactory.h" +#include "IntRect.h" +#include "Timer.h" +#include "UpdateAtlas.h" +#include <wtf/OwnPtr.h> + +#if ENABLE(CSS_SHADERS) +#include "FilterOperations.h" +#endif + +namespace WebCore { + +class Page; +class GraphicsContext; +class GraphicsLayer; +class CoordinatedSurface; + +class CompositingCoordinator : public GraphicsLayerClient + , public CoordinatedGraphicsLayerClient + , public CoordinatedImageBacking::Client + , public UpdateAtlas::Client + , public GraphicsLayerFactory { + WTF_MAKE_NONCOPYABLE(CompositingCoordinator); WTF_MAKE_FAST_ALLOCATED; +public: + class Client { + public: + virtual void didFlushRootLayer() = 0; + virtual void willSyncLayerState(CoordinatedGraphicsLayerState&) = 0; + virtual void notifyFlushRequired() = 0; + virtual void commitSceneState(const CoordinatedGraphicsState&) = 0; + virtual void paintLayerContents(const GraphicsLayer*, GraphicsContext&, const IntRect& clipRect) = 0; + }; + + static PassOwnPtr<CompositingCoordinator> create(Page*, CompositingCoordinator::Client*); + virtual ~CompositingCoordinator(); + + void setRootCompositingLayer(GraphicsLayer*); + void sizeDidChange(const IntSize& newSize); + void deviceOrPageScaleFactorChanged(); + + void setVisibleContentsRect(const FloatRect&, const FloatPoint&); + void renderNextFrame(); + void purgeBackingStores(); + void commitScrollOffset(uint32_t layerID, const IntSize& offset); + + void createRootLayer(const IntSize&); + void clearRootLayer() { m_rootLayer = nullptr; } + GraphicsLayer* rootLayer() const { return m_rootLayer.get(); } + CoordinatedGraphicsLayer* mainContentsLayer(); + + bool flushPendingLayerChanges(); + CoordinatedGraphicsState& state() { return m_state; } + + void syncDisplayState(); + +#if ENABLE(REQUEST_ANIMATION_FRAME) + double nextAnimationServiceTime() const; +#endif + +private: + CompositingCoordinator(Page*, CompositingCoordinator::Client*); + + // GraphicsLayerClient + virtual void notifyAnimationStarted(const GraphicsLayer*, double time) OVERRIDE; + virtual void notifyFlushRequired(const GraphicsLayer*) OVERRIDE; + virtual void paintContents(const GraphicsLayer*, GraphicsContext&, GraphicsLayerPaintingPhase, const IntRect& clipRect) OVERRIDE; + virtual float deviceScaleFactor() const OVERRIDE; + virtual float pageScaleFactor() const OVERRIDE; + + // CoordinatedImageBacking::Client + virtual void createImageBacking(CoordinatedImageBackingID) OVERRIDE; + virtual void updateImageBacking(CoordinatedImageBackingID, PassRefPtr<CoordinatedSurface>) OVERRIDE; + virtual void clearImageBackingContents(CoordinatedImageBackingID) OVERRIDE; + virtual void removeImageBacking(CoordinatedImageBackingID) OVERRIDE; + + // CoordinatedGraphicsLayerClient + virtual bool isFlushingLayerChanges() const OVERRIDE { return m_isFlushingLayerChanges; } + virtual FloatRect visibleContentsRect() const OVERRIDE; + virtual PassRefPtr<CoordinatedImageBacking> createImageBackingIfNeeded(Image*) OVERRIDE; + virtual void detachLayer(CoordinatedGraphicsLayer*) OVERRIDE; + virtual bool paintToSurface(const WebCore::IntSize&, WebCore::CoordinatedSurface::Flags, uint32_t& /* atlasID */, WebCore::IntPoint&, WebCore::CoordinatedSurface::Client*) OVERRIDE; + virtual void syncLayerState(CoordinatedLayerID, CoordinatedGraphicsLayerState&) OVERRIDE; + + // UpdateAtlas::Client + virtual void createUpdateAtlas(uint32_t atlasID, PassRefPtr<CoordinatedSurface>) OVERRIDE; + virtual void removeUpdateAtlas(uint32_t atlasID) OVERRIDE; + + // GraphicsLayerFactory + virtual PassOwnPtr<GraphicsLayer> createGraphicsLayer(GraphicsLayerClient*) OVERRIDE; + + void initializeRootCompositingLayerIfNeeded(); + void flushPendingImageBackingChanges(); + void clearPendingStateChanges(); + + void scheduleReleaseInactiveAtlases(); + + void releaseInactiveAtlasesTimerFired(Timer<CompositingCoordinator>*); + + Page* m_page; + CompositingCoordinator::Client* m_client; + + OwnPtr<GraphicsLayer> m_rootLayer; + GraphicsLayer* m_rootCompositingLayer; + + CoordinatedGraphicsState m_state; + + typedef HashMap<CoordinatedLayerID, CoordinatedGraphicsLayer*> LayerMap; + LayerMap m_registeredLayers; + typedef HashMap<CoordinatedImageBackingID, RefPtr<CoordinatedImageBacking> > ImageBackingMap; + ImageBackingMap m_imageBackings; + Vector<OwnPtr<UpdateAtlas> > m_updateAtlases; + + // We don't send the messages related to releasing resources to renderer during purging, because renderer already had removed all resources. + bool m_isPurging; + bool m_isFlushingLayerChanges; + + FloatRect m_visibleContentsRect; + + bool m_shouldSyncFrame; + bool m_didInitializeRootCompositingLayer; + Timer<CompositingCoordinator> m_releaseInactiveAtlasesTimer; + +#if ENABLE(REQUEST_ANIMATION_FRAME) + double m_lastAnimationServiceTime; +#endif +}; + +} + +#endif + +#endif // CompositingCoordinator_h diff --git a/Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedBackingStore.cpp b/Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedBackingStore.cpp new file mode 100644 index 000000000..2737ec125 --- /dev/null +++ b/Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedBackingStore.cpp @@ -0,0 +1,194 @@ +/* + Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + */ + +#include "config.h" +#include "CoordinatedBackingStore.h" + +#if USE(COORDINATED_GRAPHICS) +#include "CoordinatedSurface.h" +#include "GraphicsLayer.h" +#include "TextureMapper.h" +#include "TextureMapperGL.h" + +namespace WebCore { + +void CoordinatedBackingStoreTile::swapBuffers(TextureMapper* textureMapper) +{ + if (!m_surface) + return; + + FloatRect tileRect(m_tileRect); + tileRect.scale(1. / m_scale); + bool shouldReset = false; + if (tileRect != rect()) { + setRect(tileRect); + shouldReset = true; + } + RefPtr<BitmapTexture> texture = this->texture(); + if (!texture) { + texture = textureMapper->createTexture(); + setTexture(texture.get()); + shouldReset = true; + } + + ASSERT(textureMapper->maxTextureSize().width() >= m_tileRect.size().width()); + ASSERT(textureMapper->maxTextureSize().height() >= m_tileRect.size().height()); + if (shouldReset) + texture->reset(m_tileRect.size(), m_surface->supportsAlpha()); + + m_surface->copyToTexture(texture, m_sourceRect, m_surfaceOffset); + m_surface.clear(); +} + +void CoordinatedBackingStoreTile::setBackBuffer(const IntRect& tileRect, const IntRect& sourceRect, PassRefPtr<CoordinatedSurface> buffer, const IntPoint& offset) +{ + m_sourceRect = sourceRect; + m_tileRect = tileRect; + m_surfaceOffset = offset; + m_surface = buffer; +} + +void CoordinatedBackingStore::createTile(uint32_t id, float scale) +{ + m_tiles.add(id, CoordinatedBackingStoreTile(scale)); + m_scale = scale; +} + +void CoordinatedBackingStore::removeTile(uint32_t id) +{ + ASSERT(m_tiles.contains(id)); + m_tilesToRemove.add(id); +} + +void CoordinatedBackingStore::removeAllTiles() +{ + CoordinatedBackingStoreTileMap::iterator end = m_tiles.end(); + for (CoordinatedBackingStoreTileMap::iterator it = m_tiles.begin(); it != end; ++it) + m_tilesToRemove.add(it->key); +} + +void CoordinatedBackingStore::updateTile(uint32_t id, const IntRect& sourceRect, const IntRect& tileRect, PassRefPtr<CoordinatedSurface> backBuffer, const IntPoint& offset) +{ + CoordinatedBackingStoreTileMap::iterator it = m_tiles.find(id); + ASSERT(it != m_tiles.end()); + it->value.setBackBuffer(tileRect, sourceRect, backBuffer, offset); +} + +PassRefPtr<BitmapTexture> CoordinatedBackingStore::texture() const +{ + CoordinatedBackingStoreTileMap::const_iterator end = m_tiles.end(); + for (CoordinatedBackingStoreTileMap::const_iterator it = m_tiles.begin(); it != end; ++it) { + RefPtr<BitmapTexture> texture = it->value.texture(); + if (texture) + return texture; + } + + return PassRefPtr<BitmapTexture>(); +} + +void CoordinatedBackingStore::setSize(const FloatSize& size) +{ + m_pendingSize = size; +} + +void CoordinatedBackingStore::paintTilesToTextureMapper(Vector<TextureMapperTile*>& tiles, TextureMapper* textureMapper, const TransformationMatrix& transform, float opacity, const FloatRect& rect) +{ + for (size_t i = 0; i < tiles.size(); ++i) + tiles[i]->paint(textureMapper, transform, opacity, calculateExposedTileEdges(rect, tiles[i]->rect())); +} + +TransformationMatrix CoordinatedBackingStore::adjustedTransformForRect(const FloatRect& targetRect) +{ + return TransformationMatrix::rectToRect(rect(), targetRect); +} + +void CoordinatedBackingStore::paintToTextureMapper(TextureMapper* textureMapper, const FloatRect& targetRect, const TransformationMatrix& transform, float opacity) +{ + if (m_tiles.isEmpty()) + return; + ASSERT(!m_size.isZero()); + + Vector<TextureMapperTile*> tilesToPaint; + Vector<TextureMapperTile*> previousTilesToPaint; + + // We have to do this every time we paint, in case the opacity has changed. + CoordinatedBackingStoreTileMap::iterator end = m_tiles.end(); + FloatRect coveredRect; + for (CoordinatedBackingStoreTileMap::iterator it = m_tiles.begin(); it != end; ++it) { + CoordinatedBackingStoreTile& tile = it->value; + if (!tile.texture()) + continue; + + if (tile.scale() == m_scale) { + tilesToPaint.append(&tile); + coveredRect.unite(tile.rect()); + continue; + } + + // Only show the previous tile if the opacity is high, otherwise effect looks like a bug. + // We show the previous-scale tile anyway if it doesn't intersect with any current-scale tile. + if (opacity < 0.95 && coveredRect.intersects(tile.rect())) + continue; + + previousTilesToPaint.append(&tile); + } + + // targetRect is on the contents coordinate system, so we must compare two rects on the contents coordinate system. + // See TiledBackingStore. + TransformationMatrix adjustedTransform = transform * adjustedTransformForRect(targetRect); + + paintTilesToTextureMapper(previousTilesToPaint, textureMapper, adjustedTransform, opacity, rect()); + paintTilesToTextureMapper(tilesToPaint, textureMapper, adjustedTransform, opacity, rect()); +} + +void CoordinatedBackingStore::drawBorder(TextureMapper* textureMapper, const Color& borderColor, float borderWidth, const FloatRect& targetRect, const TransformationMatrix& transform) +{ + TransformationMatrix adjustedTransform = transform * adjustedTransformForRect(targetRect); + CoordinatedBackingStoreTileMap::iterator end = m_tiles.end(); + for (CoordinatedBackingStoreTileMap::iterator it = m_tiles.begin(); it != end; ++it) + textureMapper->drawBorder(borderColor, borderWidth, it->value.rect(), adjustedTransform); +} + +void CoordinatedBackingStore::drawRepaintCounter(TextureMapper* textureMapper, int repaintCount, const Color& borderColor, const FloatRect& targetRect, const TransformationMatrix& transform) +{ + TransformationMatrix adjustedTransform = transform * adjustedTransformForRect(targetRect); + CoordinatedBackingStoreTileMap::iterator end = m_tiles.end(); + for (CoordinatedBackingStoreTileMap::iterator it = m_tiles.begin(); it != end; ++it) + textureMapper->drawNumber(repaintCount, borderColor, it->value.rect().location(), adjustedTransform); +} + +void CoordinatedBackingStore::commitTileOperations(TextureMapper* textureMapper) +{ + if (!m_pendingSize.isZero()) { + m_size = m_pendingSize; + m_pendingSize = FloatSize(); + } + + HashSet<uint32_t>::iterator tilesToRemoveEnd = m_tilesToRemove.end(); + for (HashSet<uint32_t>::iterator it = m_tilesToRemove.begin(); it != tilesToRemoveEnd; ++it) + m_tiles.remove(*it); + m_tilesToRemove.clear(); + + CoordinatedBackingStoreTileMap::iterator tilesEnd = m_tiles.end(); + for (CoordinatedBackingStoreTileMap::iterator it = m_tiles.begin(); it != tilesEnd; ++it) + it->value.swapBuffers(textureMapper); +} + +} // namespace WebCore +#endif // USE(COORDINATED_GRAPHICS) diff --git a/Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedBackingStore.h b/Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedBackingStore.h new file mode 100644 index 000000000..4201454bd --- /dev/null +++ b/Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedBackingStore.h @@ -0,0 +1,90 @@ +/* + Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + */ + +#ifndef CoordinatedBackingStore_h +#define CoordinatedBackingStore_h + +#if USE(COORDINATED_GRAPHICS) + +#include "TextureMapper.h" +#include "TextureMapperBackingStore.h" +#include "TextureMapperTile.h" +#include <wtf/HashMap.h> +#include <wtf/HashSet.h> + +namespace WebCore { + +class CoordinatedSurface; + +class CoordinatedBackingStoreTile : public TextureMapperTile { +public: + explicit CoordinatedBackingStoreTile(float scale = 1) + : TextureMapperTile(FloatRect()) + , m_scale(scale) + { + } + + inline float scale() const { return m_scale; } + void swapBuffers(TextureMapper*); + void setBackBuffer(const IntRect&, const IntRect&, PassRefPtr<CoordinatedSurface> buffer, const IntPoint&); + +private: + RefPtr<CoordinatedSurface> m_surface; + IntRect m_sourceRect; + IntRect m_tileRect; + IntPoint m_surfaceOffset; + float m_scale; +}; + +class CoordinatedBackingStore : public TextureMapperBackingStore { +public: + void createTile(uint32_t tileID, float); + void removeTile(uint32_t tileID); + void removeAllTiles(); + void updateTile(uint32_t tileID, const IntRect&, const IntRect&, PassRefPtr<CoordinatedSurface>, const IntPoint&); + static PassRefPtr<CoordinatedBackingStore> create() { return adoptRef(new CoordinatedBackingStore); } + void commitTileOperations(TextureMapper*); + PassRefPtr<BitmapTexture> texture() const; + void setSize(const FloatSize&); + virtual void paintToTextureMapper(TextureMapper*, const FloatRect&, const TransformationMatrix&, float); + virtual void drawBorder(TextureMapper*, const Color&, float borderWidth, const FloatRect&, const TransformationMatrix&) OVERRIDE; + virtual void drawRepaintCounter(TextureMapper*, int repaintCount, const Color&, const FloatRect&, const TransformationMatrix&) OVERRIDE; + +private: + CoordinatedBackingStore() + : m_scale(1.) + { } + void paintTilesToTextureMapper(Vector<TextureMapperTile*>&, TextureMapper*, const TransformationMatrix&, float, const FloatRect&); + TransformationMatrix adjustedTransformForRect(const FloatRect&); + FloatRect rect() const { return FloatRect(FloatPoint::zero(), m_size); } + + typedef HashMap<uint32_t, CoordinatedBackingStoreTile> CoordinatedBackingStoreTileMap; + CoordinatedBackingStoreTileMap m_tiles; + HashSet<uint32_t> m_tilesToRemove; + // FIXME: m_pendingSize should be removed after the following bug is fixed: https://bugs.webkit.org/show_bug.cgi?id=108294 + FloatSize m_pendingSize; + FloatSize m_size; + float m_scale; +}; + +} // namespace WebCore + +#endif // USE(COORDINATED_GRAPHICS) + +#endif // CoordinatedBackingStore_h diff --git a/Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedCustomFilterOperation.h b/Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedCustomFilterOperation.h new file mode 100644 index 000000000..17a7182b4 --- /dev/null +++ b/Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedCustomFilterOperation.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2012 Adobe Systems Incorporated. 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 THE COPYRIGHT HOLDER "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 THE COPYRIGHT HOLDER 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 CoordinatedCustomFilterOperation_h +#define CoordinatedCustomFilterOperation_h + +#if ENABLE(CSS_SHADERS) +#include "CustomFilterOperation.h" + +namespace WebCore { + +// This class is only adding the programId on top of CustomFilterOperation. The argument decoder has no +// context, so we cannot search in our cached CustomFilterPrograms while decoding. In that case +// it will just store the programId and no CustomFilterProgram instance. The receiver is supposed to +// iterate on this structure and inject the right CustomFilterPrograms. + +class CoordinatedCustomFilterOperation : public CustomFilterOperation { +public: + static PassRefPtr<CoordinatedCustomFilterOperation> create(PassRefPtr<CustomFilterProgram> program, int programID, const CustomFilterParameterList& sortedParameters, unsigned meshRows, unsigned meshColumns) + { + return adoptRef(new CoordinatedCustomFilterOperation(program, programID, sortedParameters, meshRows, meshColumns)); + } + + int programID() const { return m_programID; } + +private: + CoordinatedCustomFilterOperation(PassRefPtr<CustomFilterProgram> program, int programID, const CustomFilterParameterList& sortedParameters, unsigned meshRows, unsigned meshColumns) + : CustomFilterOperation(program, sortedParameters, meshRows, meshColumns) + , m_programID(programID) + { + } + + int m_programID; +}; + +} // namespace WebCore + +#endif // ENABLE(CSS_SHADERS) + +#endif // CoordinatedCustomFilterOperation_h diff --git a/Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedCustomFilterProgram.h b/Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedCustomFilterProgram.h new file mode 100644 index 000000000..7f4f154c9 --- /dev/null +++ b/Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedCustomFilterProgram.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2012 Company 100, 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. AND ITS CONTRIBUTORS ``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 INC. OR ITS 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 CoordinatedCustomFilterProgram_h +#define CoordinatedCustomFilterProgram_h + +#if USE(COORDINATED_GRAPHICS) && ENABLE(CSS_SHADERS) +#include "CustomFilterConstants.h" +#include "CustomFilterProgram.h" + +namespace WebCore { + +class CoordinatedCustomFilterProgram : public CustomFilterProgram { +public: + static PassRefPtr<CoordinatedCustomFilterProgram> create(String vertexShaderString, String m_fragmentShaderString, CustomFilterProgramType programType, CustomFilterProgramMixSettings mixSettings, CustomFilterMeshType meshType) + { + return adoptRef(new CoordinatedCustomFilterProgram(vertexShaderString, m_fragmentShaderString, programType, mixSettings, meshType)); + } + + virtual bool isLoaded() const OVERRIDE { return true; } + +protected: + virtual String vertexShaderString() const OVERRIDE { return m_vertexShaderString; } + virtual String fragmentShaderString() const OVERRIDE { return m_fragmentShaderString; } + + virtual void willHaveClients() OVERRIDE { notifyClients(); } + virtual void didRemoveLastClient() OVERRIDE { } + +private: + CoordinatedCustomFilterProgram(String vertexShaderString, String fragmentShaderString, CustomFilterProgramType programType, CustomFilterProgramMixSettings mixSettings, CustomFilterMeshType meshType) + : CustomFilterProgram(programType, mixSettings, meshType) + , m_vertexShaderString(vertexShaderString) + , m_fragmentShaderString(fragmentShaderString) + { + } + + String m_vertexShaderString; + String m_fragmentShaderString; +}; + +} // namespace WebCore + +#endif // USE(COORDINATED_GRAPHICS) && ENABLE(CSS_SHADERS) + +#endif // CoordinatedCustomFilterProgram_h diff --git a/Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedGraphicsLayer.cpp b/Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedGraphicsLayer.cpp new file mode 100644 index 000000000..7e70bbb0d --- /dev/null +++ b/Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedGraphicsLayer.cpp @@ -0,0 +1,1255 @@ +/* + Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies) + Copyright (C) 2010 Apple Inc. All rights reserved. + Copyright (C) 2012 Company 100, Inc. + Copyright (C) 2012 Intel Corporation. All rights reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + */ + +#include "config.h" + +#if USE(COORDINATED_GRAPHICS) +#include "CoordinatedGraphicsLayer.h" + +#include "CoordinatedTile.h" +#include "FloatQuad.h" +#include "Frame.h" +#include "FrameView.h" +#include "GraphicsContext.h" +#include "GraphicsLayer.h" +#include "Page.h" +#include "ScrollableArea.h" +#include "TextureMapperPlatformLayer.h" +#include <wtf/CurrentTime.h> +#include <wtf/HashMap.h> +#ifndef NDEBUG +#include <wtf/TemporaryChange.h> +#endif +#include <wtf/text/CString.h> + +namespace WebCore { + +static CoordinatedLayerID toCoordinatedLayerID(GraphicsLayer* layer) +{ + return layer ? toCoordinatedGraphicsLayer(layer)->id() : 0; +} + +void CoordinatedGraphicsLayer::didChangeLayerState() +{ + m_shouldSyncLayerState = true; + if (client()) + client()->notifyFlushRequired(this); +} + +void CoordinatedGraphicsLayer::didChangeAnimations() +{ + m_shouldSyncAnimations = true; + if (client()) + client()->notifyFlushRequired(this); +} + +void CoordinatedGraphicsLayer::didChangeChildren() +{ + m_shouldSyncChildren = true; + if (client()) + client()->notifyFlushRequired(this); +} + +#if ENABLE(CSS_FILTERS) +void CoordinatedGraphicsLayer::didChangeFilters() +{ + m_shouldSyncFilters = true; + if (client()) + client()->notifyFlushRequired(this); +} +#endif + +void CoordinatedGraphicsLayer::didChangeImageBacking() +{ + m_shouldSyncImageBacking = true; + if (client()) + client()->notifyFlushRequired(this); +} + +void CoordinatedGraphicsLayer::setShouldUpdateVisibleRect() +{ + m_shouldUpdateVisibleRect = true; + for (size_t i = 0; i < children().size(); ++i) + toCoordinatedGraphicsLayer(children()[i])->setShouldUpdateVisibleRect(); + if (replicaLayer()) + toCoordinatedGraphicsLayer(replicaLayer())->setShouldUpdateVisibleRect(); +} + +void CoordinatedGraphicsLayer::didChangeGeometry() +{ + didChangeLayerState(); + setShouldUpdateVisibleRect(); +} + +CoordinatedGraphicsLayer::CoordinatedGraphicsLayer(GraphicsLayerClient* client) + : GraphicsLayer(client) +#ifndef NDEBUG + , m_isPurging(false) +#endif + , m_shouldUpdateVisibleRect(true) + , m_shouldSyncLayerState(true) + , m_shouldSyncChildren(true) + , m_shouldSyncFilters(true) + , m_shouldSyncImageBacking(true) + , m_shouldSyncAnimations(true) + , m_fixedToViewport(false) + , m_movingVisibleRect(false) + , m_pendingContentsScaleAdjustment(false) + , m_pendingVisibleRectAdjustment(false) +#if USE(GRAPHICS_SURFACE) + , m_isValidCanvas(false) + , m_pendingCanvasOperation(None) +#endif + , m_coordinator(0) + , m_compositedNativeImagePtr(0) + , m_canvasPlatformLayer(0) + , m_animationStartedTimer(this, &CoordinatedGraphicsLayer::animationStartedTimerFired) + , m_scrollableArea(0) +{ + static CoordinatedLayerID nextLayerID = 1; + m_id = nextLayerID++; +} + +CoordinatedGraphicsLayer::~CoordinatedGraphicsLayer() +{ + if (m_coordinator) { + purgeBackingStores(); + m_coordinator->detachLayer(this); + } + ASSERT(!m_coordinatedImageBacking); + ASSERT(!m_mainBackingStore); + willBeDestroyed(); +} + +bool CoordinatedGraphicsLayer::setChildren(const Vector<GraphicsLayer*>& children) +{ + bool ok = GraphicsLayer::setChildren(children); + if (!ok) + return false; + didChangeChildren(); + return true; +} + +void CoordinatedGraphicsLayer::addChild(GraphicsLayer* layer) +{ + GraphicsLayer::addChild(layer); + didChangeChildren(); +} + +void CoordinatedGraphicsLayer::addChildAtIndex(GraphicsLayer* layer, int index) +{ + GraphicsLayer::addChildAtIndex(layer, index); + didChangeChildren(); +} + +void CoordinatedGraphicsLayer::addChildAbove(GraphicsLayer* layer, GraphicsLayer* sibling) +{ + GraphicsLayer::addChildAbove(layer, sibling); + didChangeChildren(); +} + +void CoordinatedGraphicsLayer::addChildBelow(GraphicsLayer* layer, GraphicsLayer* sibling) +{ + GraphicsLayer::addChildBelow(layer, sibling); + didChangeChildren(); +} + +bool CoordinatedGraphicsLayer::replaceChild(GraphicsLayer* oldChild, GraphicsLayer* newChild) +{ + bool ok = GraphicsLayer::replaceChild(oldChild, newChild); + if (!ok) + return false; + didChangeChildren(); + return true; +} + +void CoordinatedGraphicsLayer::removeFromParent() +{ + if (CoordinatedGraphicsLayer* parentLayer = toCoordinatedGraphicsLayer(parent())) + parentLayer->didChangeChildren(); + GraphicsLayer::removeFromParent(); +} + +void CoordinatedGraphicsLayer::setPosition(const FloatPoint& p) +{ + if (position() == p) + return; + + GraphicsLayer::setPosition(p); + m_layerState.positionChanged = true; + didChangeGeometry(); +} + +void CoordinatedGraphicsLayer::setAnchorPoint(const FloatPoint3D& p) +{ + if (anchorPoint() == p) + return; + + GraphicsLayer::setAnchorPoint(p); + m_layerState.anchorPointChanged = true; + didChangeGeometry(); +} + +void CoordinatedGraphicsLayer::setSize(const FloatSize& size) +{ + if (this->size() == size) + return; + + GraphicsLayer::setSize(size); + m_layerState.sizeChanged = true; + + if (maskLayer()) + maskLayer()->setSize(size); + didChangeGeometry(); +} + +void CoordinatedGraphicsLayer::setTransform(const TransformationMatrix& t) +{ + if (transform() == t) + return; + + GraphicsLayer::setTransform(t); + m_layerState.transformChanged = true; + + didChangeGeometry(); +} + +void CoordinatedGraphicsLayer::setChildrenTransform(const TransformationMatrix& t) +{ + if (childrenTransform() == t) + return; + + GraphicsLayer::setChildrenTransform(t); + m_layerState.childrenTransformChanged = true; + + didChangeGeometry(); +} + +void CoordinatedGraphicsLayer::setPreserves3D(bool b) +{ + if (preserves3D() == b) + return; + + GraphicsLayer::setPreserves3D(b); + m_layerState.preserves3D = b; + m_layerState.flagsChanged = true; + + didChangeGeometry(); +} + +void CoordinatedGraphicsLayer::setMasksToBounds(bool b) +{ + if (masksToBounds() == b) + return; + GraphicsLayer::setMasksToBounds(b); + m_layerState.masksToBounds = b; + m_layerState.flagsChanged = true; + + didChangeGeometry(); +} + +void CoordinatedGraphicsLayer::setDrawsContent(bool b) +{ + if (drawsContent() == b) + return; + GraphicsLayer::setDrawsContent(b); + m_layerState.drawsContent = b; + m_layerState.flagsChanged = true; + + didChangeLayerState(); +} + +void CoordinatedGraphicsLayer::setContentsVisible(bool b) +{ + if (contentsAreVisible() == b) + return; + GraphicsLayer::setContentsVisible(b); + m_layerState.contentsVisible = b; + m_layerState.flagsChanged = true; + + if (maskLayer()) + maskLayer()->setContentsVisible(b); + + didChangeLayerState(); +} + +void CoordinatedGraphicsLayer::setContentsOpaque(bool b) +{ + if (contentsOpaque() == b) + return; + if (m_mainBackingStore) + m_mainBackingStore->setSupportsAlpha(!b); + GraphicsLayer::setContentsOpaque(b); + m_layerState.contentsOpaque = b; + m_layerState.flagsChanged = true; + + didChangeLayerState(); +} + +void CoordinatedGraphicsLayer::setBackfaceVisibility(bool b) +{ + if (backfaceVisibility() == b) + return; + + GraphicsLayer::setBackfaceVisibility(b); + m_layerState.backfaceVisible = b; + m_layerState.flagsChanged = true; + + didChangeLayerState(); +} + +void CoordinatedGraphicsLayer::setOpacity(float opacity) +{ + if (this->opacity() == opacity) + return; + + GraphicsLayer::setOpacity(opacity); + m_layerState.opacity = opacity; + m_layerState.opacityChanged = true; + + didChangeLayerState(); +} + +void CoordinatedGraphicsLayer::setContentsRect(const IntRect& r) +{ + if (contentsRect() == r) + return; + + GraphicsLayer::setContentsRect(r); + m_layerState.contentsRect = r; + m_layerState.contentsRectChanged = true; + + didChangeLayerState(); +} + +void CoordinatedGraphicsLayer::setContentsTileSize(const IntSize& s) +{ + if (contentsTileSize() == s) + return; + + GraphicsLayer::setContentsTileSize(s); + m_layerState.contentsTileSize = s; + m_layerState.contentsTilingChanged = true; + didChangeLayerState(); +} + +void CoordinatedGraphicsLayer::setContentsTilePhase(const IntPoint& p) +{ + if (contentsTilePhase() == p) + return; + + GraphicsLayer::setContentsTilePhase(p); + m_layerState.contentsTilePhase = p; + m_layerState.contentsTilingChanged = true; + didChangeLayerState(); +} + +static bool s_shouldSupportContentsTiling = false; + +void CoordinatedGraphicsLayer::setShouldSupportContentsTiling(bool s) +{ + s_shouldSupportContentsTiling = s; +} + +bool GraphicsLayer::supportsContentsTiling() +{ + return s_shouldSupportContentsTiling; +} + +void CoordinatedGraphicsLayer::setContentsNeedsDisplay() +{ +#if USE(GRAPHICS_SURFACE) + if (m_canvasPlatformLayer) + m_pendingCanvasOperation |= SyncCanvas; +#endif + + if (client()) + client()->notifyFlushRequired(this); + + addRepaintRect(contentsRect()); +} + +void CoordinatedGraphicsLayer::setContentsToCanvas(PlatformLayer* platformLayer) +{ +#if USE(GRAPHICS_SURFACE) + if (m_canvasPlatformLayer) { + ASSERT(m_canvasToken.isValid()); + if (!platformLayer) { + m_pendingCanvasOperation |= DestroyCanvas; + m_pendingCanvasOperation &= ~CreateCanvas; + } else if ((m_canvasSize != platformLayer->platformLayerSize()) || (m_canvasToken != platformLayer->graphicsSurfaceToken())) { + // m_canvasToken can be different to platformLayer->graphicsSurfaceToken(), even if m_canvasPlatformLayer equals platformLayer. + m_pendingCanvasOperation |= RecreateCanvas; + } + } else { + if (platformLayer) + m_pendingCanvasOperation |= CreateAndSyncCanvas; + } + + m_canvasPlatformLayer = platformLayer; + // m_canvasToken is updated only here. In detail, when GraphicsContext3D is changed or reshaped, m_canvasToken is changed and setContentsToCanvas() is always called. + m_canvasSize = m_canvasPlatformLayer ? m_canvasPlatformLayer->platformLayerSize() : IntSize(); + m_canvasToken = m_canvasPlatformLayer ? m_canvasPlatformLayer->graphicsSurfaceToken() : GraphicsSurfaceToken(); + ASSERT(!(!m_canvasToken.isValid() && m_canvasPlatformLayer)); + + if (client()) + client()->notifyFlushRequired(this); +#else + UNUSED_PARAM(platformLayer); +#endif +} + +#if ENABLE(CSS_FILTERS) +bool CoordinatedGraphicsLayer::setFilters(const FilterOperations& newFilters) +{ + if (filters() == newFilters) + return true; + + if (!GraphicsLayer::setFilters(newFilters)) + return false; + + didChangeFilters(); + return true; +} +#endif + +void CoordinatedGraphicsLayer::setContentsToSolidColor(const Color& color) +{ + if (m_layerState.solidColor == color) + return; + + m_layerState.solidColor = color; + m_layerState.solidColorChanged = true; + + didChangeLayerState(); +} + +void CoordinatedGraphicsLayer::setShowDebugBorder(bool show) +{ + if (isShowingDebugBorder() == show) + return; + + GraphicsLayer::setShowDebugBorder(show); + m_layerState.showDebugBorders = true; + m_layerState.flagsChanged = true; + + didChangeLayerState(); +} + +void CoordinatedGraphicsLayer::setShowRepaintCounter(bool show) +{ + if (isShowingRepaintCounter() == show) + return; + + GraphicsLayer::setShowRepaintCounter(show); + m_layerState.showRepaintCounter = true; + m_layerState.flagsChanged = true; + + didChangeLayerState(); +} + +void CoordinatedGraphicsLayer::setContentsToImage(Image* image) +{ + NativeImagePtr newNativeImagePtr = image ? image->nativeImageForCurrentFrame() : 0; + if (newNativeImagePtr) { + // This code makes the assumption that pointer equality on a NativeImagePtr is a valid way to tell if the image is changed. + // This assumption is true in Qt, GTK and EFL. + if (newNativeImagePtr == m_compositedNativeImagePtr) + return; + + m_compositedImage = image; + m_compositedNativeImagePtr = newNativeImagePtr; + } else { + m_compositedImage = 0; + m_compositedNativeImagePtr = 0; + } + + GraphicsLayer::setContentsToImage(image); + didChangeImageBacking(); +} + +void CoordinatedGraphicsLayer::setMaskLayer(GraphicsLayer* layer) +{ + if (layer == maskLayer()) + return; + + GraphicsLayer::setMaskLayer(layer); + + if (!layer) + return; + + layer->setSize(size()); + layer->setContentsVisible(contentsAreVisible()); + CoordinatedGraphicsLayer* coordinatedLayer = toCoordinatedGraphicsLayer(layer); + coordinatedLayer->didChangeLayerState(); + + m_layerState.mask = coordinatedLayer->id(); + m_layerState.maskChanged = true; + + didChangeLayerState(); +} + +bool CoordinatedGraphicsLayer::shouldDirectlyCompositeImage(Image* image) const +{ + if (!image || !image->isBitmapImage()) + return false; + + enum { MaxDimenstionForDirectCompositing = 2000 }; + if (image->width() > MaxDimenstionForDirectCompositing || image->height() > MaxDimenstionForDirectCompositing) + return false; + + return true; +} + +void CoordinatedGraphicsLayer::setReplicatedByLayer(GraphicsLayer* layer) +{ + if (layer == replicaLayer()) + return; + + GraphicsLayer::setReplicatedByLayer(layer); + m_layerState.replica = toCoordinatedLayerID(layer); + m_layerState.replicaChanged = true; + didChangeLayerState(); +} + +void CoordinatedGraphicsLayer::setNeedsDisplay() +{ + setNeedsDisplayInRect(FloatRect(FloatPoint(), size())); +} + +void CoordinatedGraphicsLayer::setNeedsDisplayInRect(const FloatRect& rect) +{ + if (m_mainBackingStore) + m_mainBackingStore->invalidate(IntRect(rect)); + + didChangeLayerState(); + + addRepaintRect(rect); +} + +CoordinatedLayerID CoordinatedGraphicsLayer::id() const +{ + return m_id; +} + +void CoordinatedGraphicsLayer::setScrollableArea(ScrollableArea* scrollableArea) +{ + bool oldScrollable = isScrollable(); + m_scrollableArea = scrollableArea; + if (oldScrollable == isScrollable()) + return; + + m_layerState.isScrollable = isScrollable(); + m_layerState.flagsChanged = true; + didChangeLayerState(); +} + +void CoordinatedGraphicsLayer::commitScrollOffset(const IntSize& offset) +{ + if (!isScrollable() || offset.isZero()) + return; + + m_scrollableArea->notifyScrollPositionChanged(m_scrollableArea->scrollPosition() + offset); + m_layerState.committedScrollOffset += offset; + m_layerState.committedScrollOffsetChanged = true; + didChangeLayerState(); +} + +void CoordinatedGraphicsLayer::setFixedToViewport(bool isFixed) +{ + if (m_fixedToViewport == isFixed) + return; + + m_fixedToViewport = isFixed; + m_layerState.fixedToViewport = isFixed; + m_layerState.flagsChanged = true; + + didChangeLayerState(); +} + +void CoordinatedGraphicsLayer::flushCompositingState(const FloatRect& rect) +{ + if (!m_coordinator->isFlushingLayerChanges()) { + if (client()) + client()->notifyFlushRequired(this); + return; + } + + if (CoordinatedGraphicsLayer* mask = toCoordinatedGraphicsLayer(maskLayer())) + mask->flushCompositingStateForThisLayerOnly(); + + if (CoordinatedGraphicsLayer* replica = toCoordinatedGraphicsLayer(replicaLayer())) + replica->flushCompositingStateForThisLayerOnly(); + + flushCompositingStateForThisLayerOnly(); + + for (size_t i = 0; i < children().size(); ++i) + children()[i]->flushCompositingState(rect); +} + +CoordinatedGraphicsLayer* toCoordinatedGraphicsLayer(GraphicsLayer* layer) +{ + return static_cast<CoordinatedGraphicsLayer*>(layer); +} + +void CoordinatedGraphicsLayer::syncChildren() +{ + if (!m_shouldSyncChildren) + return; + m_shouldSyncChildren = false; + m_layerState.childrenChanged = true; + m_layerState.children.clear(); + for (size_t i = 0; i < children().size(); ++i) + m_layerState.children.append(toCoordinatedLayerID(children()[i])); +} + +#if ENABLE(CSS_FILTERS) +void CoordinatedGraphicsLayer::syncFilters() +{ + if (!m_shouldSyncFilters) + return; + m_shouldSyncFilters = false; + + m_layerState.filters = GraphicsLayer::filters(); + m_layerState.filtersChanged = true; +} +#endif + +void CoordinatedGraphicsLayer::syncImageBacking() +{ + if (!m_shouldSyncImageBacking) + return; + m_shouldSyncImageBacking = false; + + if (m_compositedNativeImagePtr) { + ASSERT(!shouldHaveBackingStore()); + ASSERT(m_compositedImage); + + bool imageInstanceReplaced = m_coordinatedImageBacking && (m_coordinatedImageBacking->id() != CoordinatedImageBacking::getCoordinatedImageBackingID(m_compositedImage.get())); + if (imageInstanceReplaced) + releaseImageBackingIfNeeded(); + + if (!m_coordinatedImageBacking) { + m_coordinatedImageBacking = m_coordinator->createImageBackingIfNeeded(m_compositedImage.get()); + m_coordinatedImageBacking->addHost(this); + m_layerState.imageID = m_coordinatedImageBacking->id(); + } + + m_coordinatedImageBacking->markDirty(); + m_layerState.imageChanged = true; + } else + releaseImageBackingIfNeeded(); + + // syncImageBacking() changed m_layerState.imageID. + didChangeLayerState(); +} + +void CoordinatedGraphicsLayer::syncLayerState() +{ + if (!m_shouldSyncLayerState) + return; + m_shouldSyncLayerState = false; + + m_layerState.childrenTransform = childrenTransform(); + m_layerState.contentsRect = contentsRect(); + m_layerState.mask = toCoordinatedLayerID(maskLayer()); + m_layerState.opacity = opacity(); + m_layerState.replica = toCoordinatedLayerID(replicaLayer()); + m_layerState.transform = transform(); + + m_layerState.anchorPoint = m_adjustedAnchorPoint; + m_layerState.pos = m_adjustedPosition; + m_layerState.size = m_adjustedSize; + + if (m_layerState.flagsChanged) { + m_layerState.drawsContent = drawsContent(); + m_layerState.contentsVisible = contentsAreVisible(); + m_layerState.backfaceVisible = backfaceVisibility(); + m_layerState.masksToBounds = masksToBounds(); + m_layerState.preserves3D = preserves3D(); + m_layerState.fixedToViewport = fixedToViewport(); + m_layerState.showDebugBorders = isShowingDebugBorder(); + m_layerState.showRepaintCounter = isShowingRepaintCounter(); + m_layerState.isScrollable = isScrollable(); + } + + if (m_layerState.showDebugBorders) + updateDebugIndicators(); +} + +void CoordinatedGraphicsLayer::setDebugBorder(const Color& color, float width) +{ + ASSERT(m_layerState.showDebugBorders); + if (m_layerState.debugBorderColor != color) { + m_layerState.debugBorderColor = color; + m_layerState.debugBorderColorChanged = true; + } + + if (m_layerState.debugBorderWidth != width) { + m_layerState.debugBorderWidth = width; + m_layerState.debugBorderWidthChanged = true; + } +} + +void CoordinatedGraphicsLayer::syncAnimations() +{ + if (!m_shouldSyncAnimations) + return; + + m_shouldSyncAnimations = false; + m_layerState.animations = m_animations.getActiveAnimations(); + m_layerState.animationsChanged = true; +} + +#if USE(GRAPHICS_SURFACE) +void CoordinatedGraphicsLayer::syncCanvas() +{ + destroyCanvasIfNeeded(); + createCanvasIfNeeded(); + + if (!(m_pendingCanvasOperation & SyncCanvas)) + return; + + m_pendingCanvasOperation &= ~SyncCanvas; + + if (!m_isValidCanvas) + return; + + ASSERT(m_canvasPlatformLayer); + m_layerState.canvasFrontBuffer = m_canvasPlatformLayer->copyToGraphicsSurface(); + m_layerState.canvasShouldSwapBuffers = true; +} + +void CoordinatedGraphicsLayer::destroyCanvasIfNeeded() +{ + if (!(m_pendingCanvasOperation & DestroyCanvas)) + return; + + if (m_isValidCanvas) { + m_isValidCanvas = false; + m_layerState.canvasToken = GraphicsSurfaceToken(); + m_layerState.canvasChanged = true; + } + + m_pendingCanvasOperation &= ~DestroyCanvas; +} + +void CoordinatedGraphicsLayer::createCanvasIfNeeded() +{ + if (!(m_pendingCanvasOperation & CreateCanvas)) + return; + + ASSERT(m_canvasPlatformLayer); + if (!m_isValidCanvas) { + m_layerState.canvasSize = m_canvasPlatformLayer->platformLayerSize(); + m_layerState.canvasToken = m_canvasPlatformLayer->graphicsSurfaceToken(); + m_layerState.canvasSurfaceFlags = m_canvasPlatformLayer->graphicsSurfaceFlags(); + m_layerState.canvasChanged = true; + m_isValidCanvas = true; + } + + m_pendingCanvasOperation &= ~CreateCanvas; +} +#endif + +void CoordinatedGraphicsLayer::flushCompositingStateForThisLayerOnly() +{ + ASSERT(m_coordinator->isFlushingLayerChanges()); + + // When we have a transform animation, we need to update visible rect every frame to adjust the visible rect of a backing store. + bool hasActiveTransformAnimation = selfOrAncestorHasActiveTransformAnimation(); + if (hasActiveTransformAnimation) + m_movingVisibleRect = true; + + // Sets the values. + computePixelAlignment(m_adjustedPosition, m_adjustedSize, m_adjustedAnchorPoint, m_pixelAlignmentOffset); + + syncImageBacking(); + syncLayerState(); + syncAnimations(); + computeTransformedVisibleRect(); + syncChildren(); +#if ENABLE(CSS_FILTERS) + syncFilters(); +#endif +#if USE(GRAPHICS_SURFACE) + syncCanvas(); +#endif + + // Only unset m_movingVisibleRect after we have updated the visible rect after the animation stopped. + if (!hasActiveTransformAnimation) + m_movingVisibleRect = false; +} + +void CoordinatedGraphicsLayer::syncPendingStateChangesIncludingSubLayers() +{ + if (m_layerState.hasPendingChanges()) { + m_coordinator->syncLayerState(m_id, m_layerState); + resetLayerState(); + } + + for (size_t i = 0; i < children().size(); ++i) + toCoordinatedGraphicsLayer(children()[i])->syncPendingStateChangesIncludingSubLayers(); +} + +void CoordinatedGraphicsLayer::resetLayerState() +{ + m_layerState.changeMask = 0; + m_layerState.tilesToCreate.clear(); + m_layerState.tilesToRemove.clear(); + m_layerState.tilesToUpdate.clear(); + m_layerState.committedScrollOffset = IntSize(); +} + +bool CoordinatedGraphicsLayer::imageBackingVisible() +{ + ASSERT(m_coordinatedImageBacking); + return tiledBackingStoreVisibleRect().intersects(contentsRect()); +} + +void CoordinatedGraphicsLayer::releaseImageBackingIfNeeded() +{ + if (!m_coordinatedImageBacking) + return; + + ASSERT(m_coordinator); + m_coordinatedImageBacking->removeHost(this); + m_coordinatedImageBacking.clear(); + m_layerState.imageID = InvalidCoordinatedImageBackingID; + m_layerState.imageChanged = true; +} + +void CoordinatedGraphicsLayer::tiledBackingStorePaintBegin() +{ +} + +CoordinatedGraphicsLayer* CoordinatedGraphicsLayer::findFirstDescendantWithContentsRecursively() +{ + if (shouldHaveBackingStore()) + return this; + + for (size_t i = 0; i < children().size(); ++i) { + CoordinatedGraphicsLayer* layer = toCoordinatedGraphicsLayer(children()[i])->findFirstDescendantWithContentsRecursively(); + if (layer) + return layer; + } + + return 0; +} + +void CoordinatedGraphicsLayer::setVisibleContentRectTrajectoryVector(const FloatPoint& trajectoryVector) +{ + if (!m_mainBackingStore) + return; + + m_mainBackingStore->setTrajectoryVector(trajectoryVector); + setNeedsVisibleRectAdjustment(); +} + +void CoordinatedGraphicsLayer::deviceOrPageScaleFactorChanged() +{ + if (shouldHaveBackingStore()) + m_pendingContentsScaleAdjustment = true; +} + +float CoordinatedGraphicsLayer::effectiveContentsScale() +{ + return selfOrAncestorHaveNonAffineTransforms() ? 1 : deviceScaleFactor() * pageScaleFactor(); +} + +void CoordinatedGraphicsLayer::adjustContentsScale() +{ + ASSERT(shouldHaveBackingStore()); + if (!m_mainBackingStore || m_mainBackingStore->contentsScale() == effectiveContentsScale()) + return; + + // Between creating the new backing store and painting the content, + // we do not want to drop the previous one as that might result in + // briefly seeing flickering as the old tiles may be dropped before + // something replaces them. + m_previousBackingStore = m_mainBackingStore.release(); + + // No reason to save the previous backing store for non-visible areas. + m_previousBackingStore->removeAllNonVisibleTiles(); +} + +void CoordinatedGraphicsLayer::createBackingStore() +{ + m_mainBackingStore = adoptPtr(new TiledBackingStore(this, CoordinatedTileBackend::create(this))); + m_mainBackingStore->setSupportsAlpha(!contentsOpaque()); + m_mainBackingStore->setContentsScale(effectiveContentsScale()); +} + +void CoordinatedGraphicsLayer::tiledBackingStorePaint(GraphicsContext* context, const IntRect& rect) +{ + if (rect.isEmpty()) + return; + paintGraphicsLayerContents(*context, rect); +} + +void CoordinatedGraphicsLayer::tiledBackingStorePaintEnd(const Vector<IntRect>& updatedRects) +{ + if (!isShowingRepaintCounter() || updatedRects.isEmpty()) + return; + + m_layerState.repaintCount = incrementRepaintCount(); + m_layerState.repaintCountChanged = true; +} + +void CoordinatedGraphicsLayer::tiledBackingStoreHasPendingTileCreation() +{ + setNeedsVisibleRectAdjustment(); + if (client()) + client()->notifyFlushRequired(this); +} + +IntRect CoordinatedGraphicsLayer::tiledBackingStoreContentsRect() +{ + return IntRect(0, 0, size().width(), size().height()); +} + +static void clampToContentsRectIfRectIsInfinite(FloatRect& rect, const IntRect& contentsRect) +{ + if (rect.width() >= LayoutUnit::nearlyMax() || rect.width() <= LayoutUnit::nearlyMin()) { + rect.setX(contentsRect.x()); + rect.setWidth(contentsRect.width()); + } + + if (rect.height() >= LayoutUnit::nearlyMax() || rect.height() <= LayoutUnit::nearlyMin()) { + rect.setY(contentsRect.y()); + rect.setHeight(contentsRect.height()); + } +} + +IntRect CoordinatedGraphicsLayer::tiledBackingStoreVisibleRect() +{ + // Non-invertible layers are not visible. + if (!m_layerTransform.combined().isInvertible()) + return IntRect(); + + // Return a projection of the visible rect (surface coordinates) onto the layer's plane (layer coordinates). + // The resulting quad might be squewed and the visible rect is the bounding box of this quad, + // so it might spread further than the real visible area (and then even more amplified by the cover rect multiplier). + ASSERT(m_cachedInverseTransform == m_layerTransform.combined().inverse()); + FloatRect rect = m_cachedInverseTransform.clampedBoundsOfProjectedQuad(FloatQuad(m_coordinator->visibleContentsRect())); + clampToContentsRectIfRectIsInfinite(rect, tiledBackingStoreContentsRect()); + return enclosingIntRect(rect); +} + +Color CoordinatedGraphicsLayer::tiledBackingStoreBackgroundColor() const +{ + return contentsOpaque() ? Color::white : Color::transparent; +} + +bool CoordinatedGraphicsLayer::paintToSurface(const IntSize& size, uint32_t& atlas, IntPoint& offset, CoordinatedSurface::Client* client) +{ + ASSERT(m_coordinator); + ASSERT(m_coordinator->isFlushingLayerChanges()); + return m_coordinator->paintToSurface(size, contentsOpaque() ? CoordinatedSurface::NoFlags : CoordinatedSurface::SupportsAlpha, atlas, offset, client); +} + +void CoordinatedGraphicsLayer::createTile(uint32_t tileID, const SurfaceUpdateInfo& updateInfo, const IntRect& tileRect) +{ + ASSERT(m_coordinator); + ASSERT(m_coordinator->isFlushingLayerChanges()); + + TileCreationInfo creationInfo; + creationInfo.tileID = tileID; + creationInfo.scale = updateInfo.scaleFactor; + + m_layerState.tilesToCreate.append(creationInfo); + updateTile(tileID, updateInfo, tileRect); +} + +void CoordinatedGraphicsLayer::updateTile(uint32_t tileID, const SurfaceUpdateInfo& updateInfo, const IntRect& tileRect) +{ + ASSERT(m_coordinator); + ASSERT(m_coordinator->isFlushingLayerChanges()); + + TileUpdateInfo tileUpdateInfo; + tileUpdateInfo.tileID = tileID; + tileUpdateInfo.tileRect = tileRect; + tileUpdateInfo.updateInfo = updateInfo; + m_layerState.tilesToUpdate.append(tileUpdateInfo); +} + +void CoordinatedGraphicsLayer::removeTile(uint32_t tileID) +{ + ASSERT(m_coordinator); + ASSERT(m_coordinator->isFlushingLayerChanges() || m_isPurging); + m_layerState.tilesToRemove.append(tileID); +} + +void CoordinatedGraphicsLayer::updateContentBuffersIncludingSubLayers() +{ + if (CoordinatedGraphicsLayer* mask = toCoordinatedGraphicsLayer(maskLayer())) + mask->updateContentBuffers(); + + if (CoordinatedGraphicsLayer* replica = toCoordinatedGraphicsLayer(replicaLayer())) + replica->updateContentBuffers(); + + updateContentBuffers(); + + for (size_t i = 0; i < children().size(); ++i) + toCoordinatedGraphicsLayer(children()[i])->updateContentBuffersIncludingSubLayers(); +} + +void CoordinatedGraphicsLayer::updateContentBuffers() +{ + if (!shouldHaveBackingStore()) { + m_mainBackingStore.clear(); + m_previousBackingStore.clear(); + return; + } + + if (m_pendingContentsScaleAdjustment) { + adjustContentsScale(); + m_pendingContentsScaleAdjustment = false; + } + + // This is the only place we (re)create the main tiled backing store, once we + // have a remote client and we are ready to send our data to the UI process. + if (!m_mainBackingStore) + createBackingStore(); + + if (m_pendingVisibleRectAdjustment) { + m_pendingVisibleRectAdjustment = false; + m_mainBackingStore->coverWithTilesIfNeeded(); + } + + m_mainBackingStore->updateTileBuffers(); + + // The previous backing store is kept around to avoid flickering between + // removing the existing tiles and painting the new ones. The first time + // the visibleRect is full painted we remove the previous backing store. + if (m_mainBackingStore->visibleAreaIsCovered()) + m_previousBackingStore.clear(); +} + +void CoordinatedGraphicsLayer::purgeBackingStores() +{ +#ifndef NDEBUG + TemporaryChange<bool> updateModeProtector(m_isPurging, true); +#endif + m_mainBackingStore.clear(); + m_previousBackingStore.clear(); + + releaseImageBackingIfNeeded(); + + didChangeLayerState(); +} + +void CoordinatedGraphicsLayer::setCoordinator(CoordinatedGraphicsLayerClient* coordinator) +{ + m_coordinator = coordinator; +} + +void CoordinatedGraphicsLayer::setNeedsVisibleRectAdjustment() +{ + if (shouldHaveBackingStore()) + m_pendingVisibleRectAdjustment = true; +} + +bool CoordinatedGraphicsLayer::hasPendingVisibleChanges() +{ + if (opacity() < 0.01 && !m_animations.hasActiveAnimationsOfType(AnimatedPropertyOpacity)) + return false; + + for (size_t i = 0; i < children().size(); ++i) { + if (toCoordinatedGraphicsLayer(children()[i])->hasPendingVisibleChanges()) + return true; + } + + bool shouldSyncCanvas = false; +#if USE(GRAPHICS_SURFACE) + shouldSyncCanvas = m_pendingCanvasOperation & SyncCanvas; +#endif + + if (!m_shouldSyncLayerState && !m_shouldSyncChildren && !m_shouldSyncFilters && !m_shouldSyncImageBacking && !m_shouldSyncAnimations && !shouldSyncCanvas) + return false; + + return tiledBackingStoreVisibleRect().intersects(tiledBackingStoreContentsRect()); +} + +static inline bool isIntegral(float value) +{ + return static_cast<int>(value) == value; +} + +FloatPoint CoordinatedGraphicsLayer::computePositionRelativeToBase() +{ + FloatPoint offset; + for (const GraphicsLayer* currLayer = this; currLayer; currLayer = currLayer->parent()) + offset += currLayer->position(); + + return offset; +} + +void CoordinatedGraphicsLayer::computePixelAlignment(FloatPoint& position, FloatSize& size, FloatPoint3D& anchorPoint, FloatSize& alignmentOffset) +{ + if (isIntegral(effectiveContentsScale())) { + position = m_position; + size = m_size; + anchorPoint = m_anchorPoint; + alignmentOffset = FloatSize(); + return; + } + + FloatPoint positionRelativeToBase = computePositionRelativeToBase(); + + FloatRect baseRelativeBounds(positionRelativeToBase, m_size); + FloatRect scaledBounds = baseRelativeBounds; + + // Scale by the effective scale factor to compute the screen-relative bounds. + scaledBounds.scale(effectiveContentsScale()); + + // Round to integer boundaries. + // NOTE: When using enclosingIntRect (as mac) it will have different sizes depending on position. + FloatRect alignedBounds = roundedIntRect(scaledBounds); + + // Convert back to layer coordinates. + alignedBounds.scale(1 / effectiveContentsScale()); + + // Convert back to layer coordinates. + alignmentOffset = baseRelativeBounds.location() - alignedBounds.location(); + + position = m_position - alignmentOffset; + size = alignedBounds.size(); + + // Now we have to compute a new anchor point which compensates for rounding. + float anchorPointX = m_anchorPoint.x(); + float anchorPointY = m_anchorPoint.y(); + + if (alignedBounds.width()) + anchorPointX = (baseRelativeBounds.width() * anchorPointX + alignmentOffset.width()) / alignedBounds.width(); + + if (alignedBounds.height()) + anchorPointY = (baseRelativeBounds.height() * anchorPointY + alignmentOffset.height()) / alignedBounds.height(); + + anchorPoint = FloatPoint3D(anchorPointX, anchorPointY, m_anchorPoint.z() * effectiveContentsScale()); +} + +void CoordinatedGraphicsLayer::computeTransformedVisibleRect() +{ + if (!m_shouldUpdateVisibleRect && !m_movingVisibleRect) + return; + + m_shouldUpdateVisibleRect = false; + TransformationMatrix currentTransform = transform(); + if (m_movingVisibleRect) + client()->getCurrentTransform(this, currentTransform); + m_layerTransform.setLocalTransform(currentTransform); + + m_layerTransform.setAnchorPoint(m_adjustedAnchorPoint); + m_layerTransform.setPosition(m_adjustedPosition); + m_layerTransform.setSize(m_adjustedSize); + + m_layerTransform.setFlattening(!preserves3D()); + m_layerTransform.setChildrenTransform(childrenTransform()); + m_layerTransform.combineTransforms(parent() ? toCoordinatedGraphicsLayer(parent())->m_layerTransform.combinedForChildren() : TransformationMatrix()); + + m_cachedInverseTransform = m_layerTransform.combined().inverse(); + + // The combined transform will be used in tiledBackingStoreVisibleRect. + setNeedsVisibleRectAdjustment(); +} + +bool CoordinatedGraphicsLayer::shouldHaveBackingStore() const +{ + return drawsContent() && contentsAreVisible() && !m_size.isEmpty(); +} + +bool CoordinatedGraphicsLayer::selfOrAncestorHasActiveTransformAnimation() const +{ + if (m_animations.hasActiveAnimationsOfType(AnimatedPropertyWebkitTransform)) + return true; + + if (!parent()) + return false; + + return toCoordinatedGraphicsLayer(parent())->selfOrAncestorHasActiveTransformAnimation(); +} + +bool CoordinatedGraphicsLayer::selfOrAncestorHaveNonAffineTransforms() +{ + if (m_animations.hasActiveAnimationsOfType(AnimatedPropertyWebkitTransform)) + return true; + + if (!m_layerTransform.combined().isAffine()) + return true; + + if (!parent()) + return false; + + return toCoordinatedGraphicsLayer(parent())->selfOrAncestorHaveNonAffineTransforms(); +} + +bool CoordinatedGraphicsLayer::addAnimation(const KeyframeValueList& valueList, const IntSize& boxSize, const Animation* anim, const String& keyframesName, double delayAsNegativeTimeOffset) +{ + ASSERT(!keyframesName.isEmpty()); + + if (!anim || anim->isEmptyOrZeroDuration() || valueList.size() < 2 || (valueList.property() != AnimatedPropertyWebkitTransform && valueList.property() != AnimatedPropertyOpacity && valueList.property() != AnimatedPropertyWebkitFilter)) + return false; + + bool listsMatch = false; + bool ignoredHasBigRotation; + + if (valueList.property() == AnimatedPropertyWebkitTransform) + listsMatch = validateTransformOperations(valueList, ignoredHasBigRotation) >= 0; + + m_lastAnimationStartTime = WTF::currentTime() - delayAsNegativeTimeOffset; + m_animations.add(GraphicsLayerAnimation(keyframesName, valueList, boxSize, anim, m_lastAnimationStartTime, listsMatch)); + m_animationStartedTimer.startOneShot(0); + didChangeAnimations(); + return true; +} + +void CoordinatedGraphicsLayer::pauseAnimation(const String& animationName, double time) +{ + m_animations.pause(animationName, time); + didChangeAnimations(); +} + +void CoordinatedGraphicsLayer::removeAnimation(const String& animationName) +{ + m_animations.remove(animationName); + didChangeAnimations(); +} + +void CoordinatedGraphicsLayer::suspendAnimations(double time) +{ + m_animations.suspend(time); + didChangeAnimations(); +} + +void CoordinatedGraphicsLayer::resumeAnimations() +{ + m_animations.resume(); + didChangeAnimations(); +} + +void CoordinatedGraphicsLayer::animationStartedTimerFired(Timer<CoordinatedGraphicsLayer>*) +{ + client()->notifyAnimationStarted(this, m_lastAnimationStartTime); +} +} // namespace WebCore +#endif // USE(COORDINATED_GRAPHICS) diff --git a/Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedGraphicsLayer.h b/Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedGraphicsLayer.h new file mode 100644 index 000000000..cfbc2135d --- /dev/null +++ b/Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedGraphicsLayer.h @@ -0,0 +1,264 @@ +/* + Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + */ + + +#ifndef CoordinatedGraphicsLayer_h +#define CoordinatedGraphicsLayer_h + +#include "CoordinatedGraphicsState.h" +#include "CoordinatedImageBacking.h" +#include "CoordinatedTile.h" +#include "FloatPoint3D.h" +#include "GraphicsLayer.h" +#include "GraphicsLayerAnimation.h" +#include "GraphicsLayerTransform.h" +#include "Image.h" +#include "IntSize.h" +#include "RunLoop.h" +#include "TiledBackingStore.h" +#include "TiledBackingStoreClient.h" +#include "TransformationMatrix.h" +#if USE(GRAPHICS_SURFACE) +#include "GraphicsSurfaceToken.h" +#endif +#include <wtf/text/StringHash.h> + +#if USE(COORDINATED_GRAPHICS) + +namespace WebCore { +class CoordinatedGraphicsLayer; +class GraphicsLayerAnimations; +class ScrollableArea; + +class CoordinatedGraphicsLayerClient { +public: + virtual bool isFlushingLayerChanges() const = 0; + virtual FloatRect visibleContentsRect() const = 0; + virtual PassRefPtr<CoordinatedImageBacking> createImageBackingIfNeeded(Image*) = 0; + virtual void detachLayer(CoordinatedGraphicsLayer*) = 0; + virtual bool paintToSurface(const IntSize&, CoordinatedSurface::Flags, uint32_t& atlasID, IntPoint&, CoordinatedSurface::Client*) = 0; + + virtual void syncLayerState(CoordinatedLayerID, CoordinatedGraphicsLayerState&) = 0; +}; + +class CoordinatedGraphicsLayer : public GraphicsLayer + , public TiledBackingStoreClient + , public CoordinatedImageBacking::Host + , public CoordinatedTileClient { +public: + explicit CoordinatedGraphicsLayer(GraphicsLayerClient*); + virtual ~CoordinatedGraphicsLayer(); + + // Reimplementations from GraphicsLayer.h. + virtual bool setChildren(const Vector<GraphicsLayer*>&) OVERRIDE; + virtual void addChild(GraphicsLayer*) OVERRIDE; + virtual void addChildAtIndex(GraphicsLayer*, int) OVERRIDE; + virtual void addChildAbove(GraphicsLayer*, GraphicsLayer*) OVERRIDE; + virtual void addChildBelow(GraphicsLayer*, GraphicsLayer*) OVERRIDE; + virtual bool replaceChild(GraphicsLayer*, GraphicsLayer*) OVERRIDE; + virtual void removeFromParent() OVERRIDE; + virtual void setPosition(const FloatPoint&) OVERRIDE; + virtual void setAnchorPoint(const FloatPoint3D&) OVERRIDE; + virtual void setSize(const FloatSize&) OVERRIDE; + virtual void setTransform(const TransformationMatrix&) OVERRIDE; + virtual void setChildrenTransform(const TransformationMatrix&) OVERRIDE; + virtual void setPreserves3D(bool) OVERRIDE; + virtual void setMasksToBounds(bool) OVERRIDE; + virtual void setDrawsContent(bool) OVERRIDE; + virtual void setContentsVisible(bool) OVERRIDE; + virtual void setContentsOpaque(bool) OVERRIDE; + virtual void setBackfaceVisibility(bool) OVERRIDE; + virtual void setOpacity(float) OVERRIDE; + virtual void setContentsRect(const IntRect&) OVERRIDE; + virtual void setContentsTilePhase(const IntPoint&) OVERRIDE; + virtual void setContentsTileSize(const IntSize&) OVERRIDE; + virtual void setContentsToImage(Image*) OVERRIDE; + virtual void setContentsToSolidColor(const Color&) OVERRIDE; + virtual void setShowDebugBorder(bool) OVERRIDE; + virtual void setShowRepaintCounter(bool) OVERRIDE; + virtual bool shouldDirectlyCompositeImage(Image*) const OVERRIDE; + virtual void setContentsToCanvas(PlatformLayer*) OVERRIDE; + virtual void setMaskLayer(GraphicsLayer*) OVERRIDE; + virtual void setReplicatedByLayer(GraphicsLayer*) OVERRIDE; + virtual void setNeedsDisplay() OVERRIDE; + virtual void setNeedsDisplayInRect(const FloatRect&) OVERRIDE; + virtual void setContentsNeedsDisplay() OVERRIDE; + virtual void deviceOrPageScaleFactorChanged() OVERRIDE; + virtual void flushCompositingState(const FloatRect&) OVERRIDE; + virtual void flushCompositingStateForThisLayerOnly() OVERRIDE; +#if ENABLE(CSS_FILTERS) + virtual bool setFilters(const FilterOperations&) OVERRIDE; +#endif + virtual bool addAnimation(const KeyframeValueList&, const IntSize&, const Animation*, const String&, double) OVERRIDE; + virtual void pauseAnimation(const String&, double) OVERRIDE; + virtual void removeAnimation(const String&) OVERRIDE; + virtual void suspendAnimations(double time) OVERRIDE; + virtual void resumeAnimations() OVERRIDE; + virtual bool hasContentsLayer() const OVERRIDE { return m_canvasPlatformLayer || m_compositedImage; } + + void syncPendingStateChangesIncludingSubLayers(); + void updateContentBuffersIncludingSubLayers(); + + FloatPoint computePositionRelativeToBase(); + void computePixelAlignment(FloatPoint& position, FloatSize&, FloatPoint3D& anchorPoint, FloatSize& alignmentOffset); + + void setVisibleContentRectTrajectoryVector(const FloatPoint&); + + void setScrollableArea(ScrollableArea*); + bool isScrollable() const { return !!m_scrollableArea; } + void commitScrollOffset(const IntSize&); + + CoordinatedLayerID id() const; + + void setFixedToViewport(bool isFixed); + + IntRect coverRect() const { return m_mainBackingStore ? m_mainBackingStore->mapToContents(m_mainBackingStore->coverRect()) : IntRect(); } + + // TiledBackingStoreClient + virtual void tiledBackingStorePaintBegin() OVERRIDE; + virtual void tiledBackingStorePaint(GraphicsContext*, const IntRect&) OVERRIDE; + virtual void tiledBackingStorePaintEnd(const Vector<IntRect>& paintedArea) OVERRIDE; + virtual void tiledBackingStoreHasPendingTileCreation() OVERRIDE; + virtual IntRect tiledBackingStoreContentsRect() OVERRIDE; + virtual IntRect tiledBackingStoreVisibleRect() OVERRIDE; + virtual Color tiledBackingStoreBackgroundColor() const OVERRIDE; + + // CoordinatedTileClient + virtual void createTile(uint32_t tileID, const SurfaceUpdateInfo&, const IntRect&) OVERRIDE; + virtual void updateTile(uint32_t tileID, const SurfaceUpdateInfo&, const IntRect&) OVERRIDE; + virtual void removeTile(uint32_t tileID) OVERRIDE; + virtual bool paintToSurface(const IntSize&, uint32_t& /* atlasID */, IntPoint&, CoordinatedSurface::Client*) OVERRIDE; + + void setCoordinator(CoordinatedGraphicsLayerClient*); + + void setNeedsVisibleRectAdjustment(); + void purgeBackingStores(); + bool hasPendingVisibleChanges(); + + static void setShouldSupportContentsTiling(bool); + CoordinatedGraphicsLayer* findFirstDescendantWithContentsRecursively(); + +private: +#if USE(GRAPHICS_SURFACE) + enum PendingCanvasOperation { + None = 0x00, + CreateCanvas = 0x01, + DestroyCanvas = 0x02, + SyncCanvas = 0x04, + CreateAndSyncCanvas = CreateCanvas | SyncCanvas, + RecreateCanvas = CreateAndSyncCanvas | DestroyCanvas + }; + + void syncCanvas(); + void destroyCanvasIfNeeded(); + void createCanvasIfNeeded(); +#endif + + virtual void setDebugBorder(const Color&, float width) OVERRIDE; + + bool fixedToViewport() const { return m_fixedToViewport; } + + void didChangeLayerState(); + void didChangeAnimations(); + void didChangeGeometry(); + void didChangeChildren(); +#if ENABLE(CSS_FILTERS) + void didChangeFilters(); +#endif + void didChangeImageBacking(); + + void resetLayerState(); + void syncLayerState(); + void syncAnimations(); + void syncChildren(); +#if ENABLE(CSS_FILTERS) + void syncFilters(); +#endif + void syncImageBacking(); + void computeTransformedVisibleRect(); + void updateContentBuffers(); + + void createBackingStore(); + void releaseImageBackingIfNeeded(); + + // CoordinatedImageBacking::Host + virtual bool imageBackingVisible() OVERRIDE; + bool shouldHaveBackingStore() const; + bool selfOrAncestorHasActiveTransformAnimation() const; + bool selfOrAncestorHaveNonAffineTransforms(); + void adjustContentsScale(); + + void setShouldUpdateVisibleRect(); + float effectiveContentsScale(); + + void animationStartedTimerFired(Timer<CoordinatedGraphicsLayer>*); + + CoordinatedLayerID m_id; + CoordinatedGraphicsLayerState m_layerState; + GraphicsLayerTransform m_layerTransform; + TransformationMatrix m_cachedInverseTransform; + FloatSize m_pixelAlignmentOffset; + FloatSize m_adjustedSize; + FloatPoint m_adjustedPosition; + FloatPoint3D m_adjustedAnchorPoint; + +#ifndef NDEBUG + bool m_isPurging; +#endif + bool m_shouldUpdateVisibleRect: 1; + bool m_shouldSyncLayerState: 1; + bool m_shouldSyncChildren: 1; + bool m_shouldSyncFilters: 1; + bool m_shouldSyncImageBacking: 1; + bool m_shouldSyncAnimations: 1; + bool m_fixedToViewport : 1; + bool m_movingVisibleRect : 1; + bool m_pendingContentsScaleAdjustment : 1; + bool m_pendingVisibleRectAdjustment : 1; +#if USE(GRAPHICS_SURFACE) + bool m_isValidCanvas : 1; + unsigned m_pendingCanvasOperation : 3; +#endif + + CoordinatedGraphicsLayerClient* m_coordinator; + OwnPtr<TiledBackingStore> m_mainBackingStore; + OwnPtr<TiledBackingStore> m_previousBackingStore; + + RefPtr<Image> m_compositedImage; + NativeImagePtr m_compositedNativeImagePtr; + RefPtr<CoordinatedImageBacking> m_coordinatedImageBacking; + + PlatformLayer* m_canvasPlatformLayer; +#if USE(GRAPHICS_SURFACE) + IntSize m_canvasSize; + GraphicsSurfaceToken m_canvasToken; +#endif + Timer<CoordinatedGraphicsLayer> m_animationStartedTimer; + GraphicsLayerAnimations m_animations; + double m_lastAnimationStartTime; + + ScrollableArea* m_scrollableArea; +}; + +CoordinatedGraphicsLayer* toCoordinatedGraphicsLayer(GraphicsLayer*); + +} // namespace WebCore +#endif // USE(COORDINATED_GRAPHICS) + +#endif // CoordinatedGraphicsLayer_h diff --git a/Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedGraphicsScene.cpp b/Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedGraphicsScene.cpp new file mode 100644 index 000000000..32c7dace4 --- /dev/null +++ b/Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedGraphicsScene.cpp @@ -0,0 +1,781 @@ +/* + Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies) + Copyright (C) 2012 Company 100, Inc. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "config.h" + +#if USE(COORDINATED_GRAPHICS) + +#include "CoordinatedGraphicsScene.h" + +#include "CoordinatedBackingStore.h" +#include "TextureMapper.h" +#include "TextureMapperBackingStore.h" +#include "TextureMapperGL.h" +#include "TextureMapperLayer.h" +#include <OpenGLShims.h> +#include <wtf/Atomics.h> +#include <wtf/MainThread.h> + +#if ENABLE(CSS_SHADERS) +#include "CoordinatedCustomFilterOperation.h" +#include "CoordinatedCustomFilterProgram.h" +#include "CustomFilterProgram.h" +#include "CustomFilterProgramInfo.h" +#endif + +namespace WebCore { + +void CoordinatedGraphicsScene::dispatchOnMainThread(const Function<void()>& function) +{ + if (isMainThread()) + function(); + else + callOnMainThread(function); +} + +static bool layerShouldHaveBackingStore(TextureMapperLayer* layer) +{ + return layer->drawsContent() && layer->contentsAreVisible() && !layer->size().isEmpty(); +} + +CoordinatedGraphicsScene::CoordinatedGraphicsScene(CoordinatedGraphicsSceneClient* client) + : m_client(client) + , m_isActive(false) + , m_rootLayerID(InvalidCoordinatedLayerID) + , m_backgroundColor(Color::white) + , m_setDrawsBackground(false) +{ + ASSERT(isMainThread()); +} + +CoordinatedGraphicsScene::~CoordinatedGraphicsScene() +{ +} + +void CoordinatedGraphicsScene::paintToCurrentGLContext(const TransformationMatrix& matrix, float opacity, const FloatRect& clipRect, TextureMapper::PaintFlags PaintFlags) +{ + if (!m_textureMapper) { + m_textureMapper = TextureMapper::create(TextureMapper::OpenGLMode); + static_cast<TextureMapperGL*>(m_textureMapper.get())->setEnableEdgeDistanceAntialiasing(true); + } + + ASSERT(m_textureMapper->accelerationMode() == TextureMapper::OpenGLMode); + syncRemoteContent(); + + adjustPositionForFixedLayers(); + TextureMapperLayer* currentRootLayer = rootLayer(); + if (!currentRootLayer) + return; + + TextureMapperLayer* layer = currentRootLayer; + + if (!layer) + return; + + layer->setTextureMapper(m_textureMapper.get()); + layer->applyAnimationsRecursively(); + m_textureMapper->beginPainting(PaintFlags); + m_textureMapper->beginClip(TransformationMatrix(), clipRect); + + if (m_setDrawsBackground) { + RGBA32 rgba = makeRGBA32FromFloats(m_backgroundColor.red(), + m_backgroundColor.green(), m_backgroundColor.blue(), + m_backgroundColor.alpha() * opacity); + m_textureMapper->drawSolidColor(clipRect, TransformationMatrix(), Color(rgba)); + } + + if (currentRootLayer->opacity() != opacity || currentRootLayer->transform() != matrix) { + currentRootLayer->setOpacity(opacity); + currentRootLayer->setTransform(matrix); + } + + layer->paint(); + m_fpsCounter.updateFPSAndDisplay(m_textureMapper.get(), clipRect.location(), matrix); + m_textureMapper->endClip(); + m_textureMapper->endPainting(); + + if (layer->descendantsOrSelfHaveRunningAnimations()) + dispatchOnMainThread(bind(&CoordinatedGraphicsScene::updateViewport, this)); +} + +void CoordinatedGraphicsScene::paintToGraphicsContext(PlatformGraphicsContext* platformContext) +{ + if (!m_textureMapper) + m_textureMapper = TextureMapper::create(); + ASSERT(m_textureMapper->accelerationMode() == TextureMapper::SoftwareMode); + syncRemoteContent(); + TextureMapperLayer* layer = rootLayer(); + + if (!layer) + return; + + GraphicsContext graphicsContext(platformContext); + m_textureMapper->setGraphicsContext(&graphicsContext); + m_textureMapper->beginPainting(); + + IntRect clipRect = graphicsContext.clipBounds(); + if (m_setDrawsBackground) + m_textureMapper->drawSolidColor(clipRect, TransformationMatrix(), m_backgroundColor); + + layer->paint(); + m_fpsCounter.updateFPSAndDisplay(m_textureMapper.get(), clipRect.location()); + m_textureMapper->endPainting(); + m_textureMapper->setGraphicsContext(0); +} + +void CoordinatedGraphicsScene::setScrollPosition(const FloatPoint& scrollPosition) +{ + m_scrollPosition = scrollPosition; +} + +void CoordinatedGraphicsScene::updateViewport() +{ + ASSERT(isMainThread()); + if (m_client) + m_client->updateViewport(); +} + +void CoordinatedGraphicsScene::adjustPositionForFixedLayers() +{ + if (m_fixedLayers.isEmpty()) + return; + + // Fixed layer positions are updated by the web process when we update the visible contents rect / scroll position. + // If we want those layers to follow accurately the viewport when we move between the web process updates, we have to offset + // them by the delta between the current position and the position of the viewport used for the last layout. + FloatSize delta = m_scrollPosition - m_renderedContentsScrollPosition; + + LayerRawPtrMap::iterator end = m_fixedLayers.end(); + for (LayerRawPtrMap::iterator it = m_fixedLayers.begin(); it != end; ++it) + it->value->setScrollPositionDeltaIfNeeded(delta); +} + +#if USE(GRAPHICS_SURFACE) +void CoordinatedGraphicsScene::createCanvasIfNeeded(TextureMapperLayer* layer, const CoordinatedGraphicsLayerState& state) +{ + if (!state.canvasToken.isValid()) + return; + + RefPtr<TextureMapperSurfaceBackingStore> canvasBackingStore(TextureMapperSurfaceBackingStore::create()); + m_surfaceBackingStores.set(layer, canvasBackingStore); + canvasBackingStore->setGraphicsSurface(GraphicsSurface::create(state.canvasSize, state.canvasSurfaceFlags, state.canvasToken)); + layer->setContentsLayer(canvasBackingStore.get()); +} + +void CoordinatedGraphicsScene::syncCanvasIfNeeded(TextureMapperLayer* layer, const CoordinatedGraphicsLayerState& state) +{ + ASSERT(m_textureMapper); + + if (state.canvasChanged) { + destroyCanvasIfNeeded(layer, state); + createCanvasIfNeeded(layer, state); + } + + if (state.canvasShouldSwapBuffers) { + ASSERT(m_surfaceBackingStores.contains(layer)); + SurfaceBackingStoreMap::iterator it = m_surfaceBackingStores.find(layer); + RefPtr<TextureMapperSurfaceBackingStore> canvasBackingStore = it->value; + canvasBackingStore->swapBuffersIfNeeded(state.canvasFrontBuffer); + } +} + +void CoordinatedGraphicsScene::destroyCanvasIfNeeded(TextureMapperLayer* layer, const CoordinatedGraphicsLayerState& state) +{ + if (state.canvasToken.isValid()) + return; + + m_surfaceBackingStores.remove(layer); + layer->setContentsLayer(0); +} +#endif + +void CoordinatedGraphicsScene::setLayerRepaintCountIfNeeded(TextureMapperLayer* layer, const CoordinatedGraphicsLayerState& state) +{ + if (!layer->isShowingRepaintCounter() || !state.repaintCountChanged) + return; + + layer->setRepaintCount(state.repaintCount); +} + +void CoordinatedGraphicsScene::setLayerChildrenIfNeeded(TextureMapperLayer* layer, const CoordinatedGraphicsLayerState& state) +{ + if (!state.childrenChanged) + return; + + Vector<TextureMapperLayer*> children; + + for (size_t i = 0; i < state.children.size(); ++i) { + CoordinatedLayerID childID = state.children[i]; + TextureMapperLayer* child = layerByID(childID); + children.append(child); + } + layer->setChildren(children); +} + +#if ENABLE(CSS_FILTERS) +void CoordinatedGraphicsScene::setLayerFiltersIfNeeded(TextureMapperLayer* layer, const CoordinatedGraphicsLayerState& state) +{ + if (!state.filtersChanged) + return; + +#if ENABLE(CSS_SHADERS) + injectCachedCustomFilterPrograms(state.filters); +#endif + layer->setFilters(state.filters); +} +#endif + +#if ENABLE(CSS_SHADERS) +void CoordinatedGraphicsScene::syncCustomFilterPrograms(const CoordinatedGraphicsState& state) +{ + for (size_t i = 0; i < state.customFiltersToCreate.size(); ++i) + createCustomFilterProgram(state.customFiltersToCreate[i].first, state.customFiltersToCreate[i].second); + + for (size_t i = 0; i < state.customFiltersToRemove.size(); ++i) + removeCustomFilterProgram(state.customFiltersToRemove[i]); +} + +void CoordinatedGraphicsScene::injectCachedCustomFilterPrograms(const FilterOperations& filters) const +{ + for (size_t i = 0; i < filters.size(); ++i) { + FilterOperation* operation = filters.operations().at(i).get(); + if (operation->getOperationType() != FilterOperation::CUSTOM) + continue; + + CoordinatedCustomFilterOperation* customOperation = static_cast<CoordinatedCustomFilterOperation*>(operation); + ASSERT(!customOperation->program()); + CustomFilterProgramMap::const_iterator iter = m_customFilterPrograms.find(customOperation->programID()); + ASSERT(iter != m_customFilterPrograms.end()); + customOperation->setProgram(iter->value.get()); + } +} + +void CoordinatedGraphicsScene::createCustomFilterProgram(int id, const CustomFilterProgramInfo& programInfo) +{ + ASSERT(!m_customFilterPrograms.contains(id)); + m_customFilterPrograms.set(id, CoordinatedCustomFilterProgram::create(programInfo.vertexShaderString(), programInfo.fragmentShaderString(), programInfo.programType(), programInfo.mixSettings(), programInfo.meshType())); +} + +void CoordinatedGraphicsScene::removeCustomFilterProgram(int id) +{ + CustomFilterProgramMap::iterator iter = m_customFilterPrograms.find(id); + ASSERT(iter != m_customFilterPrograms.end()); + if (m_textureMapper) + m_textureMapper->removeCachedCustomFilterProgram(iter->value.get()); + m_customFilterPrograms.remove(iter); +} +#endif // ENABLE(CSS_SHADERS) + +void CoordinatedGraphicsScene::setLayerState(CoordinatedLayerID id, const CoordinatedGraphicsLayerState& layerState) +{ + ASSERT(m_rootLayerID != InvalidCoordinatedLayerID); + TextureMapperLayer* layer = layerByID(id); + + if (layerState.positionChanged) + layer->setPosition(layerState.pos); + + if (layerState.anchorPointChanged) + layer->setAnchorPoint(layerState.anchorPoint); + + if (layerState.sizeChanged) + layer->setSize(layerState.size); + + if (layerState.transformChanged) + layer->setTransform(layerState.transform); + + if (layerState.childrenTransformChanged) + layer->setChildrenTransform(layerState.childrenTransform); + + if (layerState.contentsRectChanged) + layer->setContentsRect(layerState.contentsRect); + + if (layerState.contentsTilingChanged) { + layer->setContentsTilePhase(layerState.contentsTilePhase); + layer->setContentsTileSize(layerState.contentsTileSize); + } + + if (layerState.opacityChanged) + layer->setOpacity(layerState.opacity); + + if (layerState.solidColorChanged) + layer->setSolidColor(layerState.solidColor); + + if (layerState.debugBorderColorChanged || layerState.debugBorderWidthChanged) + layer->setDebugVisuals(layerState.showDebugBorders, layerState.debugBorderColor, layerState.debugBorderWidth, layerState.showRepaintCounter); + + if (layerState.replicaChanged) + layer->setReplicaLayer(getLayerByIDIfExists(layerState.replica)); + + if (layerState.maskChanged) + layer->setMaskLayer(getLayerByIDIfExists(layerState.mask)); + + if (layerState.imageChanged) + assignImageBackingToLayer(layer, layerState.imageID); + + if (layerState.flagsChanged) { + layer->setContentsOpaque(layerState.contentsOpaque); + layer->setDrawsContent(layerState.drawsContent); + layer->setContentsVisible(layerState.contentsVisible); + layer->setBackfaceVisibility(layerState.backfaceVisible); + + // Never clip the root layer. + layer->setMasksToBounds(id == m_rootLayerID ? false : layerState.masksToBounds); + layer->setPreserves3D(layerState.preserves3D); + + bool fixedToViewportChanged = layer->fixedToViewport() != layerState.fixedToViewport; + layer->setFixedToViewport(layerState.fixedToViewport); + if (fixedToViewportChanged) { + if (layerState.fixedToViewport) + m_fixedLayers.add(id, layer); + else + m_fixedLayers.remove(id); + } + + layer->setIsScrollable(layerState.isScrollable); + } + + if (layerState.committedScrollOffsetChanged) + layer->didCommitScrollOffset(layerState.committedScrollOffset); + + prepareContentBackingStore(layer); + + // Apply Operations. + setLayerChildrenIfNeeded(layer, layerState); + createTilesIfNeeded(layer, layerState); + removeTilesIfNeeded(layer, layerState); + updateTilesIfNeeded(layer, layerState); +#if ENABLE(CSS_FILTERS) + setLayerFiltersIfNeeded(layer, layerState); +#endif + setLayerAnimationsIfNeeded(layer, layerState); +#if USE(GRAPHICS_SURFACE) + syncCanvasIfNeeded(layer, layerState); +#endif + setLayerRepaintCountIfNeeded(layer, layerState); +} + +TextureMapperLayer* CoordinatedGraphicsScene::getLayerByIDIfExists(CoordinatedLayerID id) +{ + return (id != InvalidCoordinatedLayerID) ? layerByID(id) : 0; +} + +void CoordinatedGraphicsScene::createLayers(const Vector<CoordinatedLayerID>& ids) +{ + for (size_t index = 0; index < ids.size(); ++index) + createLayer(ids[index]); +} + +void CoordinatedGraphicsScene::createLayer(CoordinatedLayerID id) +{ + OwnPtr<TextureMapperLayer> newLayer = adoptPtr(new TextureMapperLayer); + newLayer->setID(id); + newLayer->setScrollClient(this); + m_layers.add(id, newLayer.release()); +} + +void CoordinatedGraphicsScene::deleteLayers(const Vector<CoordinatedLayerID>& layerIDs) +{ + for (size_t index = 0; index < layerIDs.size(); ++index) + deleteLayer(layerIDs[index]); +} + +void CoordinatedGraphicsScene::deleteLayer(CoordinatedLayerID layerID) +{ + OwnPtr<TextureMapperLayer> layer = m_layers.take(layerID); + ASSERT(layer); + + m_backingStores.remove(layer.get()); + m_fixedLayers.remove(layerID); +#if USE(GRAPHICS_SURFACE) + m_surfaceBackingStores.remove(layer.get()); +#endif +} + +void CoordinatedGraphicsScene::setRootLayerID(CoordinatedLayerID layerID) +{ + ASSERT(layerID != InvalidCoordinatedLayerID); + ASSERT(m_rootLayerID == InvalidCoordinatedLayerID); + + m_rootLayerID = layerID; + + TextureMapperLayer* layer = layerByID(layerID); + ASSERT(m_rootLayer->children().isEmpty()); + m_rootLayer->addChild(layer); +} + +void CoordinatedGraphicsScene::prepareContentBackingStore(TextureMapperLayer* layer) +{ + if (!layerShouldHaveBackingStore(layer)) { + removeBackingStoreIfNeeded(layer); + return; + } + + createBackingStoreIfNeeded(layer); + resetBackingStoreSizeToLayerSize(layer); +} + +void CoordinatedGraphicsScene::createBackingStoreIfNeeded(TextureMapperLayer* layer) +{ + if (m_backingStores.contains(layer)) + return; + + RefPtr<CoordinatedBackingStore> backingStore(CoordinatedBackingStore::create()); + m_backingStores.add(layer, backingStore); + layer->setBackingStore(backingStore); +} + +void CoordinatedGraphicsScene::removeBackingStoreIfNeeded(TextureMapperLayer* layer) +{ + RefPtr<CoordinatedBackingStore> backingStore = m_backingStores.take(layer); + if (!backingStore) + return; + + layer->setBackingStore(0); +} + +void CoordinatedGraphicsScene::resetBackingStoreSizeToLayerSize(TextureMapperLayer* layer) +{ + RefPtr<CoordinatedBackingStore> backingStore = m_backingStores.get(layer); + ASSERT(backingStore); + backingStore->setSize(layer->size()); + m_backingStoresWithPendingBuffers.add(backingStore); +} + +void CoordinatedGraphicsScene::createTilesIfNeeded(TextureMapperLayer* layer, const CoordinatedGraphicsLayerState& state) +{ + if (state.tilesToCreate.isEmpty()) + return; + + RefPtr<CoordinatedBackingStore> backingStore = m_backingStores.get(layer); + ASSERT(backingStore); + + for (size_t i = 0; i < state.tilesToCreate.size(); ++i) + backingStore->createTile(state.tilesToCreate[i].tileID, state.tilesToCreate[i].scale); +} + +void CoordinatedGraphicsScene::removeTilesIfNeeded(TextureMapperLayer* layer, const CoordinatedGraphicsLayerState& state) +{ + if (state.tilesToRemove.isEmpty()) + return; + + RefPtr<CoordinatedBackingStore> backingStore = m_backingStores.get(layer); + if (!backingStore) + return; + + for (size_t i = 0; i < state.tilesToRemove.size(); ++i) + backingStore->removeTile(state.tilesToRemove[i]); + + m_backingStoresWithPendingBuffers.add(backingStore); +} + +void CoordinatedGraphicsScene::updateTilesIfNeeded(TextureMapperLayer* layer, const CoordinatedGraphicsLayerState& state) +{ + if (state.tilesToUpdate.isEmpty()) + return; + + RefPtr<CoordinatedBackingStore> backingStore = m_backingStores.get(layer); + ASSERT(backingStore); + + for (size_t i = 0; i < state.tilesToUpdate.size(); ++i) { + const TileUpdateInfo& tileInfo = state.tilesToUpdate[i]; + const SurfaceUpdateInfo& surfaceUpdateInfo = tileInfo.updateInfo; + + SurfaceMap::iterator surfaceIt = m_surfaces.find(surfaceUpdateInfo.atlasID); + ASSERT(surfaceIt != m_surfaces.end()); + + backingStore->updateTile(tileInfo.tileID, surfaceUpdateInfo.updateRect, tileInfo.tileRect, surfaceIt->value, surfaceUpdateInfo.surfaceOffset); + m_backingStoresWithPendingBuffers.add(backingStore); + } +} + +void CoordinatedGraphicsScene::syncUpdateAtlases(const CoordinatedGraphicsState& state) +{ + for (size_t i = 0; i < state.updateAtlasesToCreate.size(); ++i) + createUpdateAtlas(state.updateAtlasesToCreate[i].first, state.updateAtlasesToCreate[i].second); + + for (size_t i = 0; i < state.updateAtlasesToRemove.size(); ++i) + removeUpdateAtlas(state.updateAtlasesToRemove[i]); +} + +void CoordinatedGraphicsScene::createUpdateAtlas(uint32_t atlasID, PassRefPtr<CoordinatedSurface> surface) +{ + ASSERT(!m_surfaces.contains(atlasID)); + m_surfaces.add(atlasID, surface); +} + +void CoordinatedGraphicsScene::removeUpdateAtlas(uint32_t atlasID) +{ + ASSERT(m_surfaces.contains(atlasID)); + m_surfaces.remove(atlasID); +} + +void CoordinatedGraphicsScene::syncImageBackings(const CoordinatedGraphicsState& state) +{ + for (size_t i = 0; i < state.imagesToRemove.size(); ++i) + removeImageBacking(state.imagesToRemove[i]); + + for (size_t i = 0; i < state.imagesToCreate.size(); ++i) + createImageBacking(state.imagesToCreate[i]); + + for (size_t i = 0; i < state.imagesToUpdate.size(); ++i) + updateImageBacking(state.imagesToUpdate[i].first, state.imagesToUpdate[i].second); + + for (size_t i = 0; i < state.imagesToClear.size(); ++i) + clearImageBackingContents(state.imagesToClear[i]); +} + +void CoordinatedGraphicsScene::createImageBacking(CoordinatedImageBackingID imageID) +{ + ASSERT(!m_imageBackings.contains(imageID)); + RefPtr<CoordinatedBackingStore> backingStore(CoordinatedBackingStore::create()); + m_imageBackings.add(imageID, backingStore.release()); +} + +void CoordinatedGraphicsScene::updateImageBacking(CoordinatedImageBackingID imageID, PassRefPtr<CoordinatedSurface> surface) +{ + ASSERT(m_imageBackings.contains(imageID)); + ImageBackingMap::iterator it = m_imageBackings.find(imageID); + RefPtr<CoordinatedBackingStore> backingStore = it->value; + + // CoordinatedImageBacking is realized to CoordinatedBackingStore with only one tile in UI Process. + backingStore->createTile(1 /* id */, 1 /* scale */); + IntRect rect(IntPoint::zero(), surface->size()); + // See CoordinatedGraphicsLayer::shouldDirectlyCompositeImage() + ASSERT(2000 >= std::max(rect.width(), rect.height())); + backingStore->setSize(rect.size()); + backingStore->updateTile(1 /* id */, rect, rect, surface, rect.location()); + + m_backingStoresWithPendingBuffers.add(backingStore); +} + +void CoordinatedGraphicsScene::clearImageBackingContents(CoordinatedImageBackingID imageID) +{ + ASSERT(m_imageBackings.contains(imageID)); + ImageBackingMap::iterator it = m_imageBackings.find(imageID); + RefPtr<CoordinatedBackingStore> backingStore = it->value; + backingStore->removeAllTiles(); + m_backingStoresWithPendingBuffers.add(backingStore); +} + +void CoordinatedGraphicsScene::removeImageBacking(CoordinatedImageBackingID imageID) +{ + ASSERT(m_imageBackings.contains(imageID)); + + // We don't want TextureMapperLayer refers a dangling pointer. + m_releasedImageBackings.append(m_imageBackings.take(imageID)); +} + +void CoordinatedGraphicsScene::assignImageBackingToLayer(TextureMapperLayer* layer, CoordinatedImageBackingID imageID) +{ +#if USE(GRAPHICS_SURFACE) + if (m_surfaceBackingStores.contains(layer)) + return; +#endif + + if (imageID == InvalidCoordinatedImageBackingID) { + layer->setContentsLayer(0); + return; + } + + ImageBackingMap::iterator it = m_imageBackings.find(imageID); + ASSERT(it != m_imageBackings.end()); + layer->setContentsLayer(it->value.get()); +} + +void CoordinatedGraphicsScene::removeReleasedImageBackingsIfNeeded() +{ + m_releasedImageBackings.clear(); +} + +void CoordinatedGraphicsScene::commitPendingBackingStoreOperations() +{ + HashSet<RefPtr<CoordinatedBackingStore> >::iterator end = m_backingStoresWithPendingBuffers.end(); + for (HashSet<RefPtr<CoordinatedBackingStore> >::iterator it = m_backingStoresWithPendingBuffers.begin(); it != end; ++it) + (*it)->commitTileOperations(m_textureMapper.get()); + + m_backingStoresWithPendingBuffers.clear(); +} + +void CoordinatedGraphicsScene::commitSceneState(const CoordinatedGraphicsState& state) +{ + m_renderedContentsScrollPosition = state.scrollPosition; + + createLayers(state.layersToCreate); + deleteLayers(state.layersToRemove); + + if (state.rootCompositingLayer != m_rootLayerID) + setRootLayerID(state.rootCompositingLayer); + + syncImageBackings(state); + syncUpdateAtlases(state); +#if ENABLE(CSS_SHADERS) + syncCustomFilterPrograms(state); +#endif + + for (size_t i = 0; i < state.layersToUpdate.size(); ++i) + setLayerState(state.layersToUpdate[i].first, state.layersToUpdate[i].second); + + commitPendingBackingStoreOperations(); + removeReleasedImageBackingsIfNeeded(); + + // The pending tiles state is on its way for the screen, tell the web process to render the next one. + dispatchOnMainThread(bind(&CoordinatedGraphicsScene::renderNextFrame, this)); +} + +void CoordinatedGraphicsScene::renderNextFrame() +{ + if (m_client) + m_client->renderNextFrame(); +} + +void CoordinatedGraphicsScene::ensureRootLayer() +{ + if (m_rootLayer) + return; + + m_rootLayer = adoptPtr(new TextureMapperLayer); + m_rootLayer->setMasksToBounds(false); + m_rootLayer->setDrawsContent(false); + m_rootLayer->setAnchorPoint(FloatPoint3D(0, 0, 0)); + + // The root layer should not have zero size, or it would be optimized out. + m_rootLayer->setSize(FloatSize(1.0, 1.0)); + + ASSERT(m_textureMapper); + m_rootLayer->setTextureMapper(m_textureMapper.get()); +} + +void CoordinatedGraphicsScene::syncRemoteContent() +{ + // We enqueue messages and execute them during paint, as they require an active GL context. + ensureRootLayer(); + + Vector<Function<void()> > renderQueue; + bool calledOnMainThread = WTF::isMainThread(); + if (!calledOnMainThread) + m_renderQueueMutex.lock(); + renderQueue.swap(m_renderQueue); + if (!calledOnMainThread) + m_renderQueueMutex.unlock(); + + for (size_t i = 0; i < renderQueue.size(); ++i) + renderQueue[i](); +} + +void CoordinatedGraphicsScene::purgeGLResources() +{ + m_imageBackings.clear(); + m_releasedImageBackings.clear(); +#if USE(GRAPHICS_SURFACE) + m_surfaceBackingStores.clear(); +#endif + m_surfaces.clear(); + + m_rootLayer.clear(); + m_rootLayerID = InvalidCoordinatedLayerID; + m_layers.clear(); + m_fixedLayers.clear(); + m_textureMapper.clear(); + m_backingStores.clear(); + m_backingStoresWithPendingBuffers.clear(); + + setActive(false); + dispatchOnMainThread(bind(&CoordinatedGraphicsScene::purgeBackingStores, this)); +} + +void CoordinatedGraphicsScene::dispatchCommitScrollOffset(uint32_t layerID, const IntSize& offset) +{ + m_client->commitScrollOffset(layerID, offset); +} + +void CoordinatedGraphicsScene::commitScrollOffset(uint32_t layerID, const IntSize& offset) +{ + dispatchOnMainThread(bind(&CoordinatedGraphicsScene::dispatchCommitScrollOffset, this, layerID, offset)); +} + +void CoordinatedGraphicsScene::purgeBackingStores() +{ + if (m_client) + m_client->purgeBackingStores(); +} + +void CoordinatedGraphicsScene::setLayerAnimationsIfNeeded(TextureMapperLayer* layer, const CoordinatedGraphicsLayerState& state) +{ + if (!state.animationsChanged) + return; + +#if ENABLE(CSS_SHADERS) + for (size_t i = 0; i < state.animations.animations().size(); ++i) { + const KeyframeValueList& keyframes = state.animations.animations().at(i).keyframes(); + if (keyframes.property() != AnimatedPropertyWebkitFilter) + continue; + for (size_t j = 0; j < keyframes.size(); ++j) { + const FilterAnimationValue& filterValue = static_cast<const FilterAnimationValue&>(keyframes.at(j)); + injectCachedCustomFilterPrograms(filterValue.value()); + } + } +#endif + layer->setAnimations(state.animations); +} + +void CoordinatedGraphicsScene::detach() +{ + ASSERT(isMainThread()); + m_renderQueue.clear(); + m_client = 0; +} + +void CoordinatedGraphicsScene::appendUpdate(const Function<void()>& function) +{ + if (!m_isActive) + return; + + ASSERT(isMainThread()); + MutexLocker locker(m_renderQueueMutex); + m_renderQueue.append(function); +} + +void CoordinatedGraphicsScene::setActive(bool active) +{ + if (m_isActive == active) + return; + + // Have to clear render queue in both cases. + // If there are some updates in queue during activation then those updates are from previous instance of paint node + // and cannot be applied to the newly created instance. + m_renderQueue.clear(); + m_isActive = active; + if (m_isActive) + dispatchOnMainThread(bind(&CoordinatedGraphicsScene::renderNextFrame, this)); +} + +void CoordinatedGraphicsScene::setBackgroundColor(const Color& color) +{ + m_backgroundColor = color; +} + +TextureMapperLayer* CoordinatedGraphicsScene::findScrollableContentsLayerAt(const FloatPoint& point) +{ + return rootLayer() ? rootLayer()->findScrollableContentsLayerAt(point) : 0; +} + +} // namespace WebCore + +#endif // USE(COORDINATED_GRAPHICS) diff --git a/Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedGraphicsScene.h b/Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedGraphicsScene.h new file mode 100644 index 000000000..7fa92ad87 --- /dev/null +++ b/Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedGraphicsScene.h @@ -0,0 +1,209 @@ +/* + Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies) + Copyright (C) 2013 Company 100, Inc. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef CoordinatedGraphicsScene_h +#define CoordinatedGraphicsScene_h + +#if USE(COORDINATED_GRAPHICS) +#include "CoordinatedGraphicsState.h" +#include "CoordinatedSurface.h" +#include "GraphicsContext.h" +#include "GraphicsLayer.h" +#include "GraphicsLayerAnimation.h" +#include "GraphicsSurface.h" +#include "IntRect.h" +#include "IntSize.h" +#include "RunLoop.h" +#include "TextureMapper.h" +#include "TextureMapperBackingStore.h" +#include "TextureMapperFPSCounter.h" +#include "TextureMapperLayer.h" +#include "Timer.h" +#include <wtf/Functional.h> +#include <wtf/HashSet.h> +#include <wtf/ThreadingPrimitives.h> +#include <wtf/Vector.h> + +#if USE(GRAPHICS_SURFACE) +#include "TextureMapperSurfaceBackingStore.h" +#endif + +namespace WebCore { + +class CoordinatedBackingStore; +class CustomFilterProgram; +class CustomFilterProgramInfo; + +class CoordinatedGraphicsSceneClient { +public: + virtual ~CoordinatedGraphicsSceneClient() { } + virtual void purgeBackingStores() = 0; + virtual void renderNextFrame() = 0; + virtual void updateViewport() = 0; + virtual void commitScrollOffset(uint32_t layerID, const IntSize& offset) = 0; +}; + +class CoordinatedGraphicsScene : public ThreadSafeRefCounted<CoordinatedGraphicsScene>, public TextureMapperLayer::ScrollingClient { +public: + explicit CoordinatedGraphicsScene(CoordinatedGraphicsSceneClient*); + virtual ~CoordinatedGraphicsScene(); + void paintToCurrentGLContext(const TransformationMatrix&, float, const FloatRect&, TextureMapper::PaintFlags = 0); + void paintToGraphicsContext(PlatformGraphicsContext*); + void setScrollPosition(const FloatPoint&); + void detach(); + void appendUpdate(const Function<void()>&); + + WebCore::TextureMapperLayer* findScrollableContentsLayerAt(const WebCore::FloatPoint&); + + virtual void commitScrollOffset(uint32_t layerID, const IntSize& offset); + + // The painting thread must lock the main thread to use below two methods, because two methods access members that the main thread manages. See m_client. + // Currently, QQuickWebPage::updatePaintNode() locks the main thread before calling both methods. + void purgeGLResources(); + void setActive(bool); + + void commitSceneState(const CoordinatedGraphicsState&); + + void setBackgroundColor(const Color&); + void setDrawsBackground(bool enable) { m_setDrawsBackground = enable; } + +private: + void setRootLayerID(CoordinatedLayerID); + void createLayers(const Vector<CoordinatedLayerID>&); + void deleteLayers(const Vector<CoordinatedLayerID>&); + void setLayerState(CoordinatedLayerID, const CoordinatedGraphicsLayerState&); + void setLayerChildrenIfNeeded(TextureMapperLayer*, const CoordinatedGraphicsLayerState&); + void updateTilesIfNeeded(TextureMapperLayer*, const CoordinatedGraphicsLayerState&); + void createTilesIfNeeded(TextureMapperLayer*, const CoordinatedGraphicsLayerState&); + void removeTilesIfNeeded(TextureMapperLayer*, const CoordinatedGraphicsLayerState&); +#if ENABLE(CSS_FILTERS) + void setLayerFiltersIfNeeded(TextureMapperLayer*, const CoordinatedGraphicsLayerState&); +#endif + void setLayerAnimationsIfNeeded(TextureMapperLayer*, const CoordinatedGraphicsLayerState&); +#if USE(GRAPHICS_SURFACE) + void createCanvasIfNeeded(TextureMapperLayer*, const CoordinatedGraphicsLayerState&); + void syncCanvasIfNeeded(TextureMapperLayer*, const CoordinatedGraphicsLayerState&); + void destroyCanvasIfNeeded(TextureMapperLayer*, const CoordinatedGraphicsLayerState&); +#endif + void setLayerRepaintCountIfNeeded(TextureMapperLayer*, const CoordinatedGraphicsLayerState&); + + void syncUpdateAtlases(const CoordinatedGraphicsState&); + void createUpdateAtlas(uint32_t atlasID, PassRefPtr<CoordinatedSurface>); + void removeUpdateAtlas(uint32_t atlasID); + + void syncImageBackings(const CoordinatedGraphicsState&); + void createImageBacking(CoordinatedImageBackingID); + void updateImageBacking(CoordinatedImageBackingID, PassRefPtr<CoordinatedSurface>); + void clearImageBackingContents(CoordinatedImageBackingID); + void removeImageBacking(CoordinatedImageBackingID); + +#if ENABLE(CSS_SHADERS) + void syncCustomFilterPrograms(const CoordinatedGraphicsState&); + void injectCachedCustomFilterPrograms(const FilterOperations& filters) const; + void createCustomFilterProgram(int id, const CustomFilterProgramInfo&); + void removeCustomFilterProgram(int id); +#endif + + TextureMapperLayer* layerByID(CoordinatedLayerID id) + { + ASSERT(m_layers.contains(id)); + ASSERT(id != InvalidCoordinatedLayerID); + return m_layers.get(id); + } + TextureMapperLayer* getLayerByIDIfExists(CoordinatedLayerID); + TextureMapperLayer* rootLayer() { return m_rootLayer.get(); } + + void syncRemoteContent(); + void adjustPositionForFixedLayers(); + + void dispatchOnMainThread(const Function<void()>&); + void updateViewport(); + void renderNextFrame(); + void purgeBackingStores(); + + void createLayer(CoordinatedLayerID); + void deleteLayer(CoordinatedLayerID); + + void assignImageBackingToLayer(TextureMapperLayer*, CoordinatedImageBackingID); + void removeReleasedImageBackingsIfNeeded(); + void ensureRootLayer(); + void commitPendingBackingStoreOperations(); + + void prepareContentBackingStore(TextureMapperLayer*); + void createBackingStoreIfNeeded(TextureMapperLayer*); + void removeBackingStoreIfNeeded(TextureMapperLayer*); + void resetBackingStoreSizeToLayerSize(TextureMapperLayer*); + + void dispatchCommitScrollOffset(uint32_t layerID, const IntSize& offset); + + // Render queue can be accessed ony from main thread or updatePaintNode call stack! + Vector<Function<void()> > m_renderQueue; + Mutex m_renderQueueMutex; + + OwnPtr<TextureMapper> m_textureMapper; + + typedef HashMap<CoordinatedImageBackingID, RefPtr<CoordinatedBackingStore> > ImageBackingMap; + ImageBackingMap m_imageBackings; + Vector<RefPtr<CoordinatedBackingStore> > m_releasedImageBackings; + + typedef HashMap<TextureMapperLayer*, RefPtr<CoordinatedBackingStore> > BackingStoreMap; + BackingStoreMap m_backingStores; + + HashSet<RefPtr<CoordinatedBackingStore> > m_backingStoresWithPendingBuffers; + +#if USE(GRAPHICS_SURFACE) + typedef HashMap<TextureMapperLayer*, RefPtr<TextureMapperSurfaceBackingStore> > SurfaceBackingStoreMap; + SurfaceBackingStoreMap m_surfaceBackingStores; +#endif + + typedef HashMap<uint32_t /* atlasID */, RefPtr<CoordinatedSurface> > SurfaceMap; + SurfaceMap m_surfaces; + + // Below two members are accessed by only the main thread. The painting thread must lock the main thread to access both members. + CoordinatedGraphicsSceneClient* m_client; + bool m_isActive; + + OwnPtr<TextureMapperLayer> m_rootLayer; + + typedef HashMap<CoordinatedLayerID, OwnPtr<TextureMapperLayer> > LayerMap; + LayerMap m_layers; + typedef HashMap<CoordinatedLayerID, TextureMapperLayer*> LayerRawPtrMap; + LayerRawPtrMap m_fixedLayers; + CoordinatedLayerID m_rootLayerID; + FloatPoint m_scrollPosition; + FloatPoint m_renderedContentsScrollPosition; + Color m_backgroundColor; + bool m_setDrawsBackground; + +#if ENABLE(CSS_SHADERS) + typedef HashMap<int, RefPtr<CustomFilterProgram> > CustomFilterProgramMap; + CustomFilterProgramMap m_customFilterPrograms; +#endif + + TextureMapperFPSCounter m_fpsCounter; +}; + +} // namespace WebCore + +#endif // USE(COORDINATED_GRAPHICS) + +#endif // CoordinatedGraphicsScene_h + + diff --git a/Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedGraphicsState.h b/Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedGraphicsState.h new file mode 100644 index 000000000..5445e62ff --- /dev/null +++ b/Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedGraphicsState.h @@ -0,0 +1,212 @@ +/* + * Copyright (C) 2013 Nokia Corporation and/or its subsidiary(-ies) + * Copyright (C) 2013 Company 100, 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. AND ITS CONTRIBUTORS ``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 INC. OR ITS 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 CoordinatedGraphicsState_h +#define CoordinatedGraphicsState_h + +#if USE(COORDINATED_GRAPHICS) + +#include "Color.h" +#include "FloatRect.h" +#include "FloatSize.h" +#include "GraphicsLayerAnimation.h" +#include "IntRect.h" +#include "IntSize.h" +#include "SurfaceUpdateInfo.h" +#include "TransformationMatrix.h" + +#if ENABLE(CSS_FILTERS) +#include "FilterOperations.h" +#endif + +#if ENABLE(CSS_FILTERS) +#include "CustomFilterProgramInfo.h" +#endif + +#if USE(GRAPHICS_SURFACE) +#include "GraphicsSurface.h" +#include "GraphicsSurfaceToken.h" +#endif + +namespace WebCore { + +class CoordinatedSurface; + +typedef uint32_t CoordinatedLayerID; +enum { InvalidCoordinatedLayerID = 0 }; + +typedef uint64_t CoordinatedImageBackingID; +enum { InvalidCoordinatedImageBackingID = 0 }; + +struct TileUpdateInfo { + uint32_t tileID; + IntRect tileRect; + WebCore::SurfaceUpdateInfo updateInfo; +}; + +struct TileCreationInfo { + uint32_t tileID; + float scale; +}; + +struct CoordinatedGraphicsLayerState { + union { + struct { + bool positionChanged: 1; + bool anchorPointChanged: 1; + bool sizeChanged: 1; + bool transformChanged: 1; + bool childrenTransformChanged: 1; + bool contentsRectChanged: 1; + bool opacityChanged: 1; + bool solidColorChanged: 1; + bool debugBorderColorChanged: 1; + bool debugBorderWidthChanged: 1; + bool replicaChanged: 1; + bool maskChanged: 1; + bool imageChanged: 1; + bool flagsChanged: 1; + bool animationsChanged: 1; + bool filtersChanged: 1; + bool childrenChanged: 1; + bool repaintCountChanged : 1; + bool canvasChanged: 1; + bool canvasShouldSwapBuffers: 1; + bool isScrollableChanged: 1; + bool committedScrollOffsetChanged: 1; + bool contentsTilingChanged: 1; + }; + unsigned changeMask; + }; + union { + struct { + bool contentsOpaque : 1; + bool drawsContent : 1; + bool contentsVisible : 1; + bool backfaceVisible : 1; + bool masksToBounds : 1; + bool preserves3D : 1; + bool fixedToViewport : 1; + bool showDebugBorders : 1; + bool showRepaintCounter : 1; + bool isScrollable: 1; + }; + unsigned flags; + }; + + CoordinatedGraphicsLayerState() + : changeMask(0) + , contentsOpaque(false) + , drawsContent(false) + , contentsVisible(true) + , backfaceVisible(true) + , masksToBounds(false) + , preserves3D(false) + , fixedToViewport(false) + , showDebugBorders(false) + , showRepaintCounter(false) + , isScrollable(false) + , opacity(0) + , debugBorderWidth(0) + , replica(InvalidCoordinatedLayerID) + , mask(InvalidCoordinatedLayerID) + , imageID(InvalidCoordinatedImageBackingID) +#if USE(GRAPHICS_SURFACE) + , canvasFrontBuffer(0) +#endif + { + } + + FloatPoint pos; + FloatPoint3D anchorPoint; + FloatSize size; + TransformationMatrix transform; + TransformationMatrix childrenTransform; + IntRect contentsRect; + IntPoint contentsTilePhase; + IntSize contentsTileSize; + float opacity; + Color solidColor; + Color debugBorderColor; + float debugBorderWidth; +#if ENABLE(CSS_FILTERS) + FilterOperations filters; +#endif + GraphicsLayerAnimations animations; + Vector<uint32_t> children; + Vector<TileCreationInfo> tilesToCreate; + Vector<uint32_t> tilesToRemove; + CoordinatedLayerID replica; + CoordinatedLayerID mask; + CoordinatedImageBackingID imageID; + + unsigned repaintCount; + Vector<TileUpdateInfo> tilesToUpdate; + +#if USE(GRAPHICS_SURFACE) + IntSize canvasSize; + GraphicsSurfaceToken canvasToken; + uint32_t canvasFrontBuffer; + GraphicsSurface::Flags canvasSurfaceFlags; +#endif + + IntSize committedScrollOffset; + + bool hasPendingChanges() const + { + return changeMask || tilesToUpdate.size() || tilesToRemove.size() || tilesToCreate.size(); + } +}; + +struct CoordinatedGraphicsState { + uint32_t rootCompositingLayer; + FloatPoint scrollPosition; + IntSize contentsSize; + IntRect coveredRect; + + Vector<CoordinatedLayerID> layersToCreate; + Vector<std::pair<CoordinatedLayerID, CoordinatedGraphicsLayerState> > layersToUpdate; + Vector<CoordinatedLayerID> layersToRemove; + + Vector<CoordinatedImageBackingID> imagesToCreate; + Vector<CoordinatedImageBackingID> imagesToRemove; + Vector<std::pair<CoordinatedImageBackingID, RefPtr<CoordinatedSurface> > > imagesToUpdate; + Vector<CoordinatedImageBackingID> imagesToClear; + + Vector<std::pair<uint32_t /* atlasID */, RefPtr<CoordinatedSurface> > > updateAtlasesToCreate; + Vector<uint32_t /* atlasID */> updateAtlasesToRemove; + +#if ENABLE(CSS_SHADERS) + Vector<std::pair<uint32_t /* FilterID */, CustomFilterProgramInfo> > customFiltersToCreate; + Vector<uint32_t> customFiltersToRemove; +#endif +}; + +} // namespace WebCore + +#endif // USE(COORDINATED_GRAPHICS) + +#endif // CoordinatedGraphicsState_h diff --git a/Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedImageBacking.cpp b/Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedImageBacking.cpp new file mode 100644 index 000000000..5ca430b47 --- /dev/null +++ b/Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedImageBacking.cpp @@ -0,0 +1,182 @@ +/* + * Copyright (C) 2012 Company 100, 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. AND ITS CONTRIBUTORS ``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 INC. OR ITS 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(COORDINATED_GRAPHICS) +#include "CoordinatedImageBacking.h" + +#include "CoordinatedGraphicsState.h" +#include "GraphicsContext.h" + +namespace WebCore { + +class ImageBackingSurfaceClient : public CoordinatedSurface::Client { +public: + ImageBackingSurfaceClient(Image* image, const IntRect& rect) + : m_image(image) + , m_rect(rect) + { + } + + virtual void paintToSurfaceContext(GraphicsContext* context) OVERRIDE + { + context->drawImage(m_image, ColorSpaceDeviceRGB, m_rect, m_rect); + } + +private: + Image* m_image; + IntRect m_rect; +}; + +CoordinatedImageBackingID CoordinatedImageBacking::getCoordinatedImageBackingID(Image* image) +{ + // CoordinatedImageBacking keeps a RefPtr<Image> member, so the same Image pointer can not refer two different instances until CoordinatedImageBacking releases the member. + return reinterpret_cast<CoordinatedImageBackingID>(image); +} + +PassRefPtr<CoordinatedImageBacking> CoordinatedImageBacking::create(Client* client, PassRefPtr<Image> image) +{ + return adoptRef(new CoordinatedImageBacking(client, image)); +} + +CoordinatedImageBacking::CoordinatedImageBacking(Client* client, PassRefPtr<Image> image) + : m_client(client) + , m_image(image) + , m_id(getCoordinatedImageBackingID(m_image.get())) + , m_clearContentsTimer(this, &CoordinatedImageBacking::clearContentsTimerFired) + , m_isDirty(false) + , m_isVisible(false) +{ + // FIXME: We would need to decode a small image directly into a GraphicsSurface. + // http://webkit.org/b/101426 + + m_client->createImageBacking(id()); +} + +CoordinatedImageBacking::~CoordinatedImageBacking() +{ +} + +void CoordinatedImageBacking::addHost(Host* host) +{ + ASSERT(!m_hosts.contains(host)); + m_hosts.append(host); +} + +void CoordinatedImageBacking::removeHost(Host* host) +{ + size_t position = m_hosts.find(host); + ASSERT(position != notFound); + m_hosts.remove(position); + + if (m_hosts.isEmpty()) + m_client->removeImageBacking(id()); +} + +void CoordinatedImageBacking::markDirty() +{ + m_isDirty = true; +} + +void CoordinatedImageBacking::update() +{ + releaseSurfaceIfNeeded(); + + bool changedToVisible; + updateVisibilityIfNeeded(changedToVisible); + if (!m_isVisible) + return; + + if (!changedToVisible) { + if (!m_isDirty) + return; + + if (m_nativeImagePtr == m_image->nativeImageForCurrentFrame()) { + m_isDirty = false; + return; + } + } + + m_surface = CoordinatedSurface::create(m_image->size(), !m_image->currentFrameKnownToBeOpaque() ? CoordinatedSurface::SupportsAlpha : CoordinatedSurface::NoFlags); + if (!m_surface) { + m_isDirty = false; + return; + } + + IntRect rect(IntPoint::zero(), m_image->size()); + + ImageBackingSurfaceClient surfaceClient(m_image.get(), rect); + m_surface->paintToSurface(rect, &surfaceClient); + + m_nativeImagePtr = m_image->nativeImageForCurrentFrame(); + + m_client->updateImageBacking(id(), m_surface); + m_isDirty = false; +} + +void CoordinatedImageBacking::releaseSurfaceIfNeeded() +{ + // We must keep m_surface until UI Process reads m_surface. + // If m_surface exists, it was created in the previous update. + m_surface.clear(); +} + +static const double clearContentsTimerInterval = 3; + +void CoordinatedImageBacking::updateVisibilityIfNeeded(bool& changedToVisible) +{ + bool previousIsVisible = m_isVisible; + + m_isVisible = false; + for (size_t i = 0; i < m_hosts.size(); ++i) { + if (m_hosts[i]->imageBackingVisible()) { + m_isVisible = true; + break; + } + } + + bool changedToInvisible = previousIsVisible && !m_isVisible; + if (changedToInvisible) { + ASSERT(!m_clearContentsTimer.isActive()); + m_clearContentsTimer.startOneShot(clearContentsTimerInterval); + } + + changedToVisible = !previousIsVisible && m_isVisible; + + if (m_isVisible && m_clearContentsTimer.isActive()) { + m_clearContentsTimer.stop(); + // We don't want to update the texture if we didn't remove the texture. + changedToVisible = false; + } +} + +void CoordinatedImageBacking::clearContentsTimerFired(Timer<CoordinatedImageBacking>*) +{ + m_client->clearImageBackingContents(id()); +} + +} // namespace WebCore +#endif diff --git a/Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedImageBacking.h b/Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedImageBacking.h new file mode 100644 index 000000000..711e491fe --- /dev/null +++ b/Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedImageBacking.h @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2012 Company 100, 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. AND ITS CONTRIBUTORS ``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 INC. OR ITS 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 CoordinatedImageBacking_h +#define CoordinatedImageBacking_h + +#if USE(COORDINATED_GRAPHICS) +#include "CoordinatedGraphicsState.h" +#include "CoordinatedSurface.h" +#include "Image.h" +#include "Timer.h" +#include <wtf/RefCounted.h> +#include <wtf/Vector.h> + +namespace WebCore { + +class CoordinatedImageBacking : public RefCounted<CoordinatedImageBacking> { +public: + class Client { + public: + virtual void createImageBacking(CoordinatedImageBackingID) = 0; + virtual void updateImageBacking(CoordinatedImageBackingID, PassRefPtr<CoordinatedSurface>) = 0; + virtual void clearImageBackingContents(CoordinatedImageBackingID) = 0; + virtual void removeImageBacking(CoordinatedImageBackingID) = 0; + }; + + class Host { + public: + virtual bool imageBackingVisible() = 0; + }; + + static PassRefPtr<CoordinatedImageBacking> create(Client*, PassRefPtr<Image>); + virtual ~CoordinatedImageBacking(); + + static CoordinatedImageBackingID getCoordinatedImageBackingID(Image*); + CoordinatedImageBackingID id() const { return m_id; } + + void addHost(Host*); + void removeHost(Host*); + + // When a new image is updated or an animated gif is progressed, CoordinatedGraphicsLayer calls markDirty(). + void markDirty(); + + // Create, remove or update its backing. + void update(); + +private: + CoordinatedImageBacking(Client*, PassRefPtr<Image>); + + void releaseSurfaceIfNeeded(); + void updateVisibilityIfNeeded(bool& changedToVisible); + void clearContentsTimerFired(Timer<CoordinatedImageBacking>*); + + Client* m_client; + RefPtr<Image> m_image; + NativeImagePtr m_nativeImagePtr; + CoordinatedImageBackingID m_id; + Vector<Host*> m_hosts; + + RefPtr<CoordinatedSurface> m_surface; + + Timer<CoordinatedImageBacking> m_clearContentsTimer; + + bool m_isDirty; + bool m_isVisible; + +}; + +} // namespace WebCore +#endif // USE(COORDINATED_GRAPHICS) + +#endif // CoordinatedImageBacking_h diff --git a/Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedSurface.cpp b/Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedSurface.cpp new file mode 100644 index 000000000..9aa67a5e0 --- /dev/null +++ b/Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedSurface.cpp @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2013 Company 100, 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. AND ITS CONTRIBUTORS ``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 INC. OR ITS 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" +#include "CoordinatedSurface.h" + +#if USE(COORDINATED_GRAPHICS) + +namespace WebCore { + +CoordinatedSurface::Factory* CoordinatedSurface::s_factory = 0; + +void CoordinatedSurface::setFactory(CoordinatedSurface::Factory factory) +{ + s_factory = factory; +} + +PassRefPtr<CoordinatedSurface> CoordinatedSurface::create(const IntSize& size, Flags flags) +{ + ASSERT(s_factory); + return s_factory(size, flags); +} + +CoordinatedSurface::CoordinatedSurface(const IntSize& size, Flags flags) + : m_size(size) + , m_flags(flags) +{ +} + +} // namespace WebCore + +#endif // USE(COORDINATED_GRAPHICS) diff --git a/Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedSurface.h b/Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedSurface.h new file mode 100644 index 000000000..9142528c6 --- /dev/null +++ b/Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedSurface.h @@ -0,0 +1,76 @@ +/* + Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies) + Copyright (C) 2012 Company 100, Inc. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + */ + +#ifndef CoordinatedSurface_h +#define CoordinatedSurface_h + +#if USE(COORDINATED_GRAPHICS) +#include "IntRect.h" +#include <wtf/PassRefPtr.h> +#include <wtf/ThreadSafeRefCounted.h> + +namespace WebCore { +class BitmapTexture; +class GraphicsContext; + +class CoordinatedSurface : public ThreadSafeRefCounted<CoordinatedSurface> { +public: + enum Flag { + NoFlags = 0, + SupportsAlpha = 1 << 0, + }; + typedef unsigned Flags; + + class Client { + public: + virtual ~Client() { } + virtual void paintToSurfaceContext(GraphicsContext*) = 0; + }; + + typedef PassRefPtr<CoordinatedSurface> Factory(const IntSize&, Flags); + static void setFactory(Factory); + static PassRefPtr<CoordinatedSurface> create(const IntSize&, Flags); + + virtual ~CoordinatedSurface() { } + + bool supportsAlpha() const { return flags() & SupportsAlpha; } + IntSize size() const { return m_size; } + + virtual void paintToSurface(const IntRect&, Client*) = 0; + +#if USE(TEXTURE_MAPPER) + virtual void copyToTexture(PassRefPtr<BitmapTexture>, const IntRect& target, const IntPoint& sourceOffset) = 0; +#endif + +protected: + CoordinatedSurface(const IntSize&, Flags); + Flags flags() const { return m_flags; } + + IntSize m_size; + Flags m_flags; + +private: + static CoordinatedSurface::Factory* s_factory; +}; + +} // namespace WebCore + +#endif // USE(COORDINATED_GRAPHICS) +#endif // CoordinatedSurface_h diff --git a/Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedTile.cpp b/Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedTile.cpp new file mode 100644 index 000000000..b24f48d23 --- /dev/null +++ b/Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedTile.cpp @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies) + * + * 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. AND ITS CONTRIBUTORS ``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 INC. OR ITS 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" +#include "CoordinatedTile.h" + +#if USE(TILED_BACKING_STORE) + +#include "GraphicsContext.h" +#include "ImageBuffer.h" +#include "SurfaceUpdateInfo.h" +#include "TiledBackingStoreClient.h" + +namespace WebCore { + +static const uint32_t InvalidCoordinatedTileID = 0; + +CoordinatedTile::CoordinatedTile(CoordinatedTileClient* client, TiledBackingStore* tiledBackingStore, const Coordinate& tileCoordinate) + : m_client(client) + , m_tiledBackingStore(tiledBackingStore) + , m_coordinate(tileCoordinate) + , m_rect(tiledBackingStore->tileRectForCoordinate(tileCoordinate)) + , m_ID(InvalidCoordinatedTileID) + , m_dirtyRect(m_rect) +{ +} + +CoordinatedTile::~CoordinatedTile() +{ + if (m_ID != InvalidCoordinatedTileID) + m_client->removeTile(m_ID); +} + +bool CoordinatedTile::isDirty() const +{ + return !m_dirtyRect.isEmpty(); +} + +void CoordinatedTile::invalidate(const IntRect& dirtyRect) +{ + IntRect tileDirtyRect = intersection(dirtyRect, m_rect); + if (tileDirtyRect.isEmpty()) + return; + + m_dirtyRect.unite(tileDirtyRect); +} + +Vector<IntRect> CoordinatedTile::updateBackBuffer() +{ + if (!isDirty()) + return Vector<IntRect>(); + + SurfaceUpdateInfo updateInfo; + + if (!m_client->paintToSurface(m_dirtyRect.size(), updateInfo.atlasID, updateInfo.surfaceOffset, this)) + return Vector<IntRect>(); + + updateInfo.updateRect = m_dirtyRect; + updateInfo.updateRect.move(-m_rect.x(), -m_rect.y()); + updateInfo.scaleFactor = m_tiledBackingStore->contentsScale(); + + static uint32_t id = 1; + if (m_ID == InvalidCoordinatedTileID) { + m_ID = id++; + // We may get an invalid ID due to wrap-around on overflow. + if (m_ID == InvalidCoordinatedTileID) + m_ID = id++; + m_client->createTile(m_ID, updateInfo, m_rect); + } else + m_client->updateTile(m_ID, updateInfo, m_rect); + + Vector<IntRect> updatedRects; + updatedRects.append(m_dirtyRect); + m_dirtyRect = IntRect(); + return updatedRects; +} + +void CoordinatedTile::paintToSurfaceContext(GraphicsContext* context) +{ + context->translate(-m_dirtyRect.x(), -m_dirtyRect.y()); + context->scale(FloatSize(m_tiledBackingStore->contentsScale(), m_tiledBackingStore->contentsScale())); + m_tiledBackingStore->client()->tiledBackingStorePaint(context, m_tiledBackingStore->mapToContents(m_dirtyRect)); +} + +void CoordinatedTile::swapBackBufferToFront() +{ + // Handled by tiledBackingStorePaintEnd. +} + +bool CoordinatedTile::isReadyToPaint() const +{ + return m_ID != InvalidCoordinatedTileID; +} + +void CoordinatedTile::paint(GraphicsContext*, const IntRect&) +{ + ASSERT_NOT_REACHED(); +} + +void CoordinatedTile::resize(const IntSize& newSize) +{ + m_rect = IntRect(m_rect.location(), newSize); + m_dirtyRect = m_rect; +} + +CoordinatedTileBackend::CoordinatedTileBackend(CoordinatedTileClient* client) + : m_client(client) +{ +} + +PassRefPtr<Tile> CoordinatedTileBackend::createTile(TiledBackingStore* tiledBackingStore, const Tile::Coordinate& tileCoordinate) +{ + return CoordinatedTile::create(m_client, tiledBackingStore, tileCoordinate); +} + +void CoordinatedTileBackend::paintCheckerPattern(GraphicsContext*, const FloatRect&) +{ +} + +} // namespace WebCore + +#endif // USE(TILED_BACKING_STORE) diff --git a/Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedTile.h b/Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedTile.h new file mode 100644 index 000000000..cab526e2b --- /dev/null +++ b/Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedTile.h @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies) + * + * 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. AND ITS CONTRIBUTORS ``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 INC. OR ITS 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 CoordinatedTile_h +#define CoordinatedTile_h + +#if USE(TILED_BACKING_STORE) + +#include "CoordinatedSurface.h" +#include "IntRect.h" +#include "Tile.h" +#include "TiledBackingStore.h" + +namespace WebCore { + +class CoordinatedTileClient; +class ImageBuffer; +class SurfaceUpdateInfo; +class TiledBackingStore; + +class CoordinatedTile : public Tile, public CoordinatedSurface::Client { +public: + static PassRefPtr<Tile> create(CoordinatedTileClient* client, TiledBackingStore* tiledBackingStore, const Coordinate& tileCoordinate) { return adoptRef(new CoordinatedTile(client, tiledBackingStore, tileCoordinate)); } + ~CoordinatedTile(); + + bool isDirty() const; + void invalidate(const IntRect&); + Vector<IntRect> updateBackBuffer(); + void swapBackBufferToFront(); + bool isReadyToPaint() const; + void paint(GraphicsContext*, const IntRect&); + + const Coordinate& coordinate() const { return m_coordinate; } + const IntRect& rect() const { return m_rect; } + void resize(const IntSize&); + + virtual void paintToSurfaceContext(GraphicsContext*) OVERRIDE; + +private: + CoordinatedTile(CoordinatedTileClient*, TiledBackingStore*, const Coordinate&); + + CoordinatedTileClient* m_client; + TiledBackingStore* m_tiledBackingStore; + Coordinate m_coordinate; + IntRect m_rect; + + uint32_t m_ID; + IntRect m_dirtyRect; + + OwnPtr<ImageBuffer> m_localBuffer; +}; + +class CoordinatedTileClient { +public: + virtual ~CoordinatedTileClient() { } + virtual void createTile(uint32_t tileID, const SurfaceUpdateInfo&, const IntRect&) = 0; + virtual void updateTile(uint32_t tileID, const SurfaceUpdateInfo&, const IntRect&) = 0; + virtual void removeTile(uint32_t tileID) = 0; + virtual bool paintToSurface(const IntSize&, uint32_t& atlasID, IntPoint&, CoordinatedSurface::Client*) = 0; +}; + +class CoordinatedTileBackend : public TiledBackingStoreBackend { +public: + static PassOwnPtr<TiledBackingStoreBackend> create(CoordinatedTileClient* client) { return adoptPtr(new CoordinatedTileBackend(client)); } + PassRefPtr<Tile> createTile(TiledBackingStore*, const Tile::Coordinate&); + void paintCheckerPattern(GraphicsContext*, const FloatRect&); + +private: + explicit CoordinatedTileBackend(CoordinatedTileClient*); + CoordinatedTileClient* m_client; +}; + +} // namespace WebCore + +#endif // USE(TILED_BACKING_STORE) + +#endif // CoordinatedTile_h diff --git a/Source/WebCore/platform/graphics/texmap/coordinated/SurfaceUpdateInfo.h b/Source/WebCore/platform/graphics/texmap/coordinated/SurfaceUpdateInfo.h new file mode 100644 index 000000000..5af069a2b --- /dev/null +++ b/Source/WebCore/platform/graphics/texmap/coordinated/SurfaceUpdateInfo.h @@ -0,0 +1,51 @@ +/* + Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + */ + +#ifndef SurfaceUpdateInfo_h +#define SurfaceUpdateInfo_h + +#if USE(COORDINATED_GRAPHICS) + +#include "IntRect.h" + +namespace WebCore { + +class SurfaceUpdateInfo { + +public: + SurfaceUpdateInfo() { } + + // The rect to be updated. + IntRect updateRect; + + // The page scale factor used to render this update. + float scaleFactor; + + // The id of the update atlas including the shareable bitmap containing the updates. + uint32_t atlasID; + + // The offset in the bitmap where the rendered contents are. + IntPoint surfaceOffset; +}; + +} // namespace WebCore + +#endif // USE(COORDINATED_GRAPHICS) + +#endif // SurfaceUpdateInfo_h diff --git a/Source/WebCore/platform/graphics/texmap/coordinated/ThreadSafeCoordinatedSurface.cpp b/Source/WebCore/platform/graphics/texmap/coordinated/ThreadSafeCoordinatedSurface.cpp new file mode 100644 index 000000000..94497dd84 --- /dev/null +++ b/Source/WebCore/platform/graphics/texmap/coordinated/ThreadSafeCoordinatedSurface.cpp @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2013 Company 100, 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. AND ITS CONTRIBUTORS ``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 INC. OR ITS 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" +#include "ThreadSafeCoordinatedSurface.h" + +#if USE(COORDINATED_GRAPHICS) + +#include "TextureMapper.h" + +namespace WebCore { + +PassRefPtr<ThreadSafeCoordinatedSurface> ThreadSafeCoordinatedSurface::create(const IntSize& size, CoordinatedSurface::Flags flags) +{ + return adoptRef(new ThreadSafeCoordinatedSurface(size, flags, ImageBuffer::create(size))); +} + +ThreadSafeCoordinatedSurface::ThreadSafeCoordinatedSurface(const IntSize& size, CoordinatedSurface::Flags flags, PassOwnPtr<ImageBuffer> buffer) + : CoordinatedSurface(size, flags) + , m_imageBuffer(buffer) +{ +} + +ThreadSafeCoordinatedSurface::~ThreadSafeCoordinatedSurface() +{ +} + +void ThreadSafeCoordinatedSurface::paintToSurface(const IntRect& rect, CoordinatedSurface::Client* client) +{ + ASSERT(client); + ASSERT(m_imageBuffer); + + GraphicsContext* context = m_imageBuffer->context(); + context->save(); + context->clip(rect); + context->translate(rect.x(), rect.y()); + + client->paintToSurfaceContext(context); + + context->restore(); +} + +void ThreadSafeCoordinatedSurface::copyToTexture(PassRefPtr<BitmapTexture> passTexture, const IntRect& target, const IntPoint& sourceOffset) +{ + RefPtr<BitmapTexture> texture(passTexture); + + ASSERT(m_imageBuffer); + RefPtr<Image> image = m_imageBuffer->copyImage(DontCopyBackingStore); + texture->updateContents(image.get(), target, sourceOffset, BitmapTexture::UpdateCanModifyOriginalImageData); +} + +} // namespace WebCore + +#endif // USE(COORDINATED_GRAPHICS) diff --git a/Source/WebCore/platform/graphics/texmap/coordinated/ThreadSafeCoordinatedSurface.h b/Source/WebCore/platform/graphics/texmap/coordinated/ThreadSafeCoordinatedSurface.h new file mode 100644 index 000000000..e003818af --- /dev/null +++ b/Source/WebCore/platform/graphics/texmap/coordinated/ThreadSafeCoordinatedSurface.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2013 Company 100, 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. AND ITS CONTRIBUTORS ``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 INC. OR ITS 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 ThreadSafeCoordinatedSurface_h +#define ThreadSafeCoordinatedSurface_h + +#if USE(COORDINATED_GRAPHICS) +#include "CoordinatedSurface.h" +#include "ImageBuffer.h" + +namespace WebCore { + +class ThreadSafeCoordinatedSurface : public CoordinatedSurface { +public: + virtual ~ThreadSafeCoordinatedSurface(); + + static PassRefPtr<ThreadSafeCoordinatedSurface> create(const IntSize&, Flags); + + virtual void paintToSurface(const IntRect&, CoordinatedSurface::Client*) OVERRIDE; + virtual void copyToTexture(PassRefPtr<BitmapTexture>, const IntRect& target, const IntPoint& sourceOffset) OVERRIDE; + +private: + ThreadSafeCoordinatedSurface(const IntSize&, Flags, PassOwnPtr<ImageBuffer>); + + OwnPtr<ImageBuffer> m_imageBuffer; +}; + +} // namespace WebCore + +#endif // USE(COORDINATED_GRAPHICS) + +#endif // ThreadSafeCoordinatedSurface_h diff --git a/Source/WebCore/platform/graphics/texmap/coordinated/UpdateAtlas.cpp b/Source/WebCore/platform/graphics/texmap/coordinated/UpdateAtlas.cpp new file mode 100644 index 000000000..319e9b8e4 --- /dev/null +++ b/Source/WebCore/platform/graphics/texmap/coordinated/UpdateAtlas.cpp @@ -0,0 +1,116 @@ +/* + Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies) + Copyright (C) 2012 Company 100, Inc. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + */ + +#include "config.h" +#include "UpdateAtlas.h" + +#if USE(COORDINATED_GRAPHICS) + +#include "CoordinatedGraphicsState.h" +#include "GraphicsContext.h" +#include "IntRect.h" +#include <wtf/MathExtras.h> + +namespace WebCore { + +class UpdateAtlasSurfaceClient : public CoordinatedSurface::Client { +public: + UpdateAtlasSurfaceClient(CoordinatedSurface::Client* client, const IntSize& size, bool supportsAlpha) + : m_client(client) + , m_size(size) + , m_supportsAlpha(supportsAlpha) + { + } + + virtual void paintToSurfaceContext(GraphicsContext* context) OVERRIDE + { + if (m_supportsAlpha) { + context->setCompositeOperation(CompositeCopy); + context->fillRect(IntRect(IntPoint::zero(), m_size), Color::transparent, ColorSpaceDeviceRGB); + context->setCompositeOperation(CompositeSourceOver); + } + + m_client->paintToSurfaceContext(context); + } + +private: + CoordinatedSurface::Client* m_client; + IntSize m_size; + bool m_supportsAlpha; +}; + +UpdateAtlas::UpdateAtlas(Client* client, int dimension, CoordinatedSurface::Flags flags) + : m_client(client) + , m_inactivityInSeconds(0) +{ + static uint32_t nextID = 0; + m_ID = ++nextID; + IntSize size = nextPowerOfTwo(IntSize(dimension, dimension)); + m_surface = CoordinatedSurface::create(size, flags); + + m_client->createUpdateAtlas(m_ID, m_surface); +} + +UpdateAtlas::~UpdateAtlas() +{ + if (m_surface) + m_client->removeUpdateAtlas(m_ID); +} + +void UpdateAtlas::buildLayoutIfNeeded() +{ + if (!m_areaAllocator) { + m_areaAllocator = adoptPtr(new GeneralAreaAllocator(size())); + m_areaAllocator->setMinimumAllocation(IntSize(32, 32)); + } +} + +void UpdateAtlas::didSwapBuffers() +{ + m_areaAllocator.clear(); +} + + +bool UpdateAtlas::paintOnAvailableBuffer(const IntSize& size, uint32_t& atlasID, IntPoint& offset, CoordinatedSurface::Client* client) +{ + m_inactivityInSeconds = 0; + buildLayoutIfNeeded(); + IntRect rect = m_areaAllocator->allocate(size); + + // No available buffer was found. + if (rect.isEmpty()) + return false; + + if (!m_surface) + return false; + + atlasID = m_ID; + + // FIXME: Use tri-state buffers, to allow faster updates. + offset = rect.location(); + + UpdateAtlasSurfaceClient surfaceClient(client, size, supportsAlpha()); + m_surface->paintToSurface(rect, &surfaceClient); + + return true; +} + +} // namespace WebCore +#endif // USE(COORDINATED_GRAPHICS) diff --git a/Source/WebCore/platform/graphics/texmap/coordinated/UpdateAtlas.h b/Source/WebCore/platform/graphics/texmap/coordinated/UpdateAtlas.h new file mode 100644 index 000000000..2eb45f7c7 --- /dev/null +++ b/Source/WebCore/platform/graphics/texmap/coordinated/UpdateAtlas.h @@ -0,0 +1,78 @@ +/* + Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies) + Copyright (C) 2012 Company 100, Inc. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + */ + +#ifndef UpdateAtlas_h +#define UpdateAtlas_h + +#include "AreaAllocator.h" +#include "CoordinatedSurface.h" +#include "IntSize.h" + +#if USE(COORDINATED_GRAPHICS) + +namespace WebCore { +class GraphicsContext; +class IntPoint; + +class UpdateAtlas { + WTF_MAKE_NONCOPYABLE(UpdateAtlas); +public: + class Client { + public: + virtual void createUpdateAtlas(uint32_t /* id */, PassRefPtr<CoordinatedSurface>) = 0; + virtual void removeUpdateAtlas(uint32_t /* id */) = 0; + }; + + UpdateAtlas(Client*, int dimension, CoordinatedSurface::Flags); + ~UpdateAtlas(); + + inline IntSize size() const { return m_surface->size(); } + + // Returns false if there is no available buffer. + bool paintOnAvailableBuffer(const IntSize&, uint32_t& atlasID, IntPoint& offset, CoordinatedSurface::Client*); + void didSwapBuffers(); + bool supportsAlpha() const { return m_surface->supportsAlpha(); } + + void addTimeInactive(double seconds) + { + ASSERT(!isInUse()); + m_inactivityInSeconds += seconds; + } + bool isInactive() const + { + const double inactiveSecondsTolerance = 3; + return m_inactivityInSeconds > inactiveSecondsTolerance; + } + bool isInUse() const { return m_areaAllocator; } + +private: + void buildLayoutIfNeeded(); + +private: + Client* m_client; + OwnPtr<GeneralAreaAllocator> m_areaAllocator; + RefPtr<CoordinatedSurface> m_surface; + double m_inactivityInSeconds; + uint32_t m_ID; +}; + +} // namespace WebCore +#endif // USE(COORDINATED_GRAPHICS) +#endif // UpdateAtlas_h |