From d38abfbac01ae23acad018d42382d604a45bc005 Mon Sep 17 00:00:00 2001 From: John Reck Date: Fri, 17 Aug 2012 14:24:46 -0700 Subject: Support partial invals on layers Change-Id: Iab18e8b5e2f0e37c380c8a15e51255121c3b1966 --- .../graphics/android/GraphicsLayerAndroid.cpp | 49 ++++++++++------------ .../graphics/android/GraphicsLayerAndroid.h | 9 ++-- Source/WebKit/android/jni/PicturePile.cpp | 38 ++++++----------- Source/WebKit/android/jni/PicturePile.h | 2 +- 4 files changed, 39 insertions(+), 59 deletions(-) diff --git a/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp b/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp index 7f4352b..9cb81e6 100644 --- a/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp +++ b/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp @@ -116,7 +116,6 @@ GraphicsLayerAndroid::GraphicsLayerAndroid(GraphicsLayerClient* client) : static_cast(renderLayer->renderer()->node())); } else m_contentLayer = new LayerAndroid(renderLayer); - m_dirtyRegion.setEmpty(); gDebugGraphicsLayerAndroidInstances++; } @@ -695,7 +694,7 @@ bool GraphicsLayerAndroid::repaint() PaintingPhase phase(this); // Paint the background into a separate context. phase.set(GraphicsLayerPaintBackground); - if (!paintContext(m_contentLayer, layerBounds)) + if (!paintContext(m_contentLayer, m_contentLayerContent)) return false; // Construct the foreground layer and draw. @@ -712,11 +711,17 @@ bool GraphicsLayerAndroid::repaint() // Paint everything else into the main recording canvas. phase.clear(GraphicsLayerPaintBackground); + // Invalidate the entire layer for now, as webkit will only send the + // setNeedsDisplayInRect() for the visible (clipped) scrollable area, + // offsetting the invals by the scroll position would not be enough. + // TODO: have webkit send us invals even for non visible area + m_foregroundLayerContent.invalidate(IntRect(0, 0, contentsRect.width(), contentsRect.height())); + // Paint at 0,0. IntSize scroll = layer->scrolledContentOffset(); layer->scrollToOffset(0, 0); // At this point, it doesn't matter if painting failed. - (void) paintContext(m_foregroundLayer, contentsRect); + (void) paintContext(m_foregroundLayer, m_foregroundLayerContent); layer->scrollToOffset(scroll.width(), scroll.height()); // Construct the clip layer for masking the contents. @@ -741,13 +746,8 @@ bool GraphicsLayerAndroid::repaint() // Set the scrollable bounds of the layer. setScrollLimits(static_cast(m_foregroundLayer), layer); - // Invalidate the entire layer for now, as webkit will only send the - // setNeedsDisplayInRect() for the visible (clipped) scrollable area, - // offsetting the invals by the scroll position would not be enough. - // TODO: have webkit send us invals even for non visible area - SkRegion region; - region.setRect(0, 0, contentsRect.width(), contentsRect.height()); - m_foregroundLayer->markAsDirty(region); + m_foregroundLayer->markAsDirty(m_foregroundLayerContent.dirtyRegion()); + m_foregroundLayerContent.dirtyRegion().setEmpty(); } else if (m_contentLayer->isFixedBackground()) { SkPicture* picture = new SkPicture(); SkCanvas* canvas = picture->beginRecording(layerBounds.width(), @@ -784,13 +784,13 @@ bool GraphicsLayerAndroid::repaint() GraphicsLayerAndroid* replicatedLayer = static_cast(replicaLayer()); if (replicatedLayer->maskLayer()) { GraphicsLayerAndroid* mask = static_cast(replicatedLayer->maskLayer()); - mask->paintContext(mask->m_contentLayer, layerBounds, false); + mask->paintContext(mask->m_contentLayer, m_contentLayerContent); } } // If there is no contents clip, we can draw everything into one // picture. - bool painting = paintContext(m_contentLayer, layerBounds); + bool painting = paintContext(m_contentLayer, m_contentLayerContent); if (!painting) return false; // Check for a scrollable iframe and report the scrolling @@ -811,8 +811,8 @@ bool GraphicsLayerAndroid::repaint() m_contentLayer->getSize().width(), m_contentLayer->getSize().height()); - m_contentLayer->markAsDirty(m_dirtyRegion); - m_dirtyRegion.setEmpty(); + m_contentLayer->markAsDirty(m_contentLayerContent.dirtyRegion()); + m_contentLayerContent.dirtyRegion().setEmpty(); m_needsRepaint = false; return true; @@ -820,8 +820,8 @@ bool GraphicsLayerAndroid::repaint() if (m_needsRepaint && m_image && m_newImage) { // We need to tell the GL thread that we will need to repaint the // texture. Only do so if we effectively have a new image! - m_contentLayer->markAsDirty(m_dirtyRegion); - m_dirtyRegion.setEmpty(); + m_contentLayer->markAsDirty(m_contentLayerContent.dirtyRegion()); + m_contentLayerContent.dirtyRegion().setEmpty(); m_newImage = false; m_needsRepaint = false; return true; @@ -835,19 +835,14 @@ void GraphicsLayerAndroid::paintContents(GraphicsContext* gc, IntRect& dirty) } bool GraphicsLayerAndroid::paintContext(LayerAndroid* layer, - const IntRect& rect, - bool checkOptimisations) + PicturePile& picture) { if (!layer) return false; TRACE_METHOD(); - // TODO: we might be able to reuse an existing picture instead of recreating it. - // we can't do that because of transparency -- for now, we just create - // a new picture every time. - WebCore::PicturePile picture; - picture.setSize(IntSize(rect.width(), rect.height())); + picture.setSize(IntSize(layer->getWidth(), layer->getHeight())); // TODO: add content checks (text, opacity, etc.) picture.updatePicturesIfNeeded(this); @@ -870,11 +865,9 @@ void GraphicsLayerAndroid::setNeedsDisplayInRect(const FloatRect& rect) return; } - SkRegion region; - region.setRect(rect.x(), rect.y(), - rect.x() + rect.width(), - rect.y() + rect.height()); - m_dirtyRegion.op(region, SkRegion::kUnion_Op); + m_contentLayerContent.invalidate(enclosingIntRect(rect)); + if (m_foregroundLayer) + m_foregroundLayerContent.invalidate(enclosingIntRect(rect)); m_needsRepaint = true; askForSync(); diff --git a/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.h b/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.h index b40459d..28d4b09 100644 --- a/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.h +++ b/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.h @@ -154,9 +154,7 @@ private: bool repaint(); void needsNotifyClient(); - bool paintContext(LayerAndroid* layer, - const IntRect& rect, - bool checkOptimisations = true); + bool paintContext(LayerAndroid* layer, PicturePile& picture); bool m_needsSyncChildren; bool m_needsSyncMask; @@ -167,12 +165,13 @@ private: bool m_newImage; Image* m_image; - SkRegion m_dirtyRegion; - LayerAndroid* m_contentLayer; FixedBackgroundImageLayerAndroid* m_fixedBackgroundLayer; LayerAndroid* m_foregroundLayer; LayerAndroid* m_foregroundClipLayer; + + PicturePile m_contentLayerContent; + PicturePile m_foregroundLayerContent; }; } // namespace WebCore diff --git a/Source/WebKit/android/jni/PicturePile.cpp b/Source/WebKit/android/jni/PicturePile.cpp index 91f3e74..f995e92 100644 --- a/Source/WebKit/android/jni/PicturePile.cpp +++ b/Source/WebKit/android/jni/PicturePile.cpp @@ -55,16 +55,6 @@ static SkIRect toSkIRect(const IntRect& rect) { return SkIRect::MakeXYWH(rect.x(), rect.y(), rect.width(), rect.height()); } -static IntRect extractClipBounds(SkCanvas* canvas, const IntSize& size) { - SkRect clip; - if (!canvas->getClipBounds(&clip)) { - ALOGW("Empty clip!"); - return IntRect(); - } - clip.intersect(0, 0, size.width(), size.height()); - return enclosingIntRect(clip); -} - PictureContainer::PictureContainer(const PictureContainer& other) : picture(other.picture) , area(other.area) @@ -94,11 +84,10 @@ void PicturePile::draw(SkCanvas* canvas) * the rect bounds of the SkRegion for the clip, so this still can't be * used for translucent surfaces */ - IntRect clipBounds = extractClipBounds(canvas, m_size); - if (clipBounds.isEmpty()) + if (canvas->quickReject(SkRect::MakeWH(m_size.width(), m_size.height()), + SkCanvas::kBW_EdgeType)) return; - SkRegion clipRegion(toSkIRect(clipBounds)); - drawWithClipRecursive(canvas, clipRegion, m_pile.size() - 1); + drawWithClipRecursive(canvas, m_pile.size() - 1); } void PicturePile::clearPrerenders() @@ -107,24 +96,23 @@ void PicturePile::clearPrerenders() m_pile[i].prerendered.clear(); } -void PicturePile::drawWithClipRecursive(SkCanvas* canvas, SkRegion& clipRegion, - int index) +void PicturePile::drawWithClipRecursive(SkCanvas* canvas, int index) { // TODO: Add some debug visualizations of this - if (index < 0 || clipRegion.isEmpty()) + if (index < 0) return; PictureContainer& pc = m_pile[index]; - IntRect intersection = clipRegion.getBounds(); - intersection.intersect(pc.area); - if (pc.picture && !intersection.isEmpty()) { - clipRegion.op(intersection, SkRegion::kDifference_Op); - drawWithClipRecursive(canvas, clipRegion, index - 1); - int saved = canvas->save(); - if (canvas->clipRect(intersection)) + if (pc.picture && !canvas->quickReject(pc.area, SkCanvas::kBW_EdgeType)) { + int saved = canvas->save(SkCanvas::kClip_SaveFlag); + if (canvas->clipRect(pc.area, SkRegion::kDifference_Op)) + drawWithClipRecursive(canvas, index - 1); + canvas->restoreToCount(saved); + saved = canvas->save(SkCanvas::kClip_SaveFlag); + if (canvas->clipRect(pc.area)) drawPicture(canvas, pc); canvas->restoreToCount(saved); } else - drawWithClipRecursive(canvas, clipRegion, index - 1); + drawWithClipRecursive(canvas, index - 1); } // Used by WebViewCore diff --git a/Source/WebKit/android/jni/PicturePile.h b/Source/WebKit/android/jni/PicturePile.h index 6e3e46d..1f99054 100644 --- a/Source/WebKit/android/jni/PicturePile.h +++ b/Source/WebKit/android/jni/PicturePile.h @@ -113,7 +113,7 @@ private: void updatePicture(PicturePainter* painter, PictureContainer& container); Picture* recordPicture(PicturePainter* painter, PictureContainer& container); void appendToPile(const IntRect& inval, const IntRect& originalInval = IntRect()); - void drawWithClipRecursive(SkCanvas* canvas, SkRegion& clipRegion, int index); + void drawWithClipRecursive(SkCanvas* canvas, int index); void drawPicture(SkCanvas* canvas, PictureContainer& pc); IntSize m_size; -- cgit v1.1