diff options
author | Patrick Scott <phanna@android.com> | 2010-07-16 12:43:07 -0400 |
---|---|---|
committer | Patrick Scott <phanna@android.com> | 2010-07-22 08:16:26 -0400 |
commit | a8d0e5a36718ee59b84a577053458bded49e369a (patch) | |
tree | 510917186d198758676037c96296405d0a1b83f1 /WebCore/platform | |
parent | 0286594a8b68c879fc5c11deb6f14c4ccadeef2a (diff) | |
download | external_webkit-a8d0e5a36718ee59b84a577053458bded49e369a.zip external_webkit-a8d0e5a36718ee59b84a577053458bded49e369a.tar.gz external_webkit-a8d0e5a36718ee59b84a577053458bded49e369a.tar.bz2 |
Enable scrollable divs.
Force a composite layer when the style says the content is scrollable.
Record the border and background in the main content picture. When
the contents of the layer are bigger than the size, record the
foreground contents in a separate picture which is clipped by the
border and size.
When updating the base layer, remember the scroll position of each
layer and update the new layer with the same position.
Bug: 1566791
Change-Id: If440e4f215db6bda9df32a781d754d1f5a238162
Diffstat (limited to 'WebCore/platform')
4 files changed, 146 insertions, 30 deletions
diff --git a/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp b/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp index 6faee17..a5ca972 100644 --- a/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp +++ b/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp @@ -293,6 +293,9 @@ void GraphicsLayerAndroid::setSize(const FloatSize& size) MLOG("(%x) setSize (%.2f,%.2f)", this, size.width(), size.height()); GraphicsLayer::setSize(size); m_contentLayer->setSize(size.width(), size.height()); + m_contentLayer->setForegroundClip( + SkRect::MakeWH(SkFloatToScalar(size.width()), + SkFloatToScalar(size.height()))); updateFixedPosition(); askForSync(); } @@ -407,24 +410,58 @@ void GraphicsLayerAndroid::setNeedsDisplay() setNeedsDisplayInRect(rect); } +// Helper to set and clear the painting phase as well as auto restore the +// original phase. +class PaintingPhase { +public: + PaintingPhase(GraphicsLayer* layer) + : m_layer(layer) + , m_originalPhase(layer->paintingPhase()) {} + + ~PaintingPhase() { + m_layer->setPaintingPhase(m_originalPhase); + } + + void set(GraphicsLayerPaintingPhase phase) { + m_layer->setPaintingPhase(phase); + } + + void clear(GraphicsLayerPaintingPhase phase) { + m_layer->setPaintingPhase( + (GraphicsLayerPaintingPhase) (m_originalPhase & ~phase)); + } +private: + GraphicsLayer* m_layer; + GraphicsLayerPaintingPhase m_originalPhase; +}; + bool GraphicsLayerAndroid::repaint() { LOG("(%x) repaint(), gPaused(%d) m_needsRepaint(%d) m_haveContents(%d) ", this, gPaused, m_needsRepaint, m_haveContents); if (!gPaused && m_haveContents && m_needsRepaint && !m_haveImage) { - SkAutoPictureRecord arp(m_contentLayer->recordContext(), m_size.width(), m_size.height()); - SkCanvas* recordingCanvas = arp.getRecordingCanvas(); - - if (!recordingCanvas) - return false; - - PlatformGraphicsContext pgc(recordingCanvas, 0); - GraphicsContext gc(&pgc); - // with SkPicture, we request the entire layer's content. - IntRect r(0, 0, m_contentLayer->getWidth(), m_contentLayer->getHeight()); - paintGraphicsLayerContents(gc, r); + IntRect layerBounds(0, 0, m_size.width(), m_size.height()); + + if (m_contentsRect.width() > m_size.width() || + m_contentsRect.height() > m_size.height()) { + PaintingPhase phase(this); + // Paint the background into a separate context. + phase.set(GraphicsLayerPaintBackground); + if (!paintContext(m_contentLayer->recordContext(), layerBounds)) + return false; + // Paint everything else into the main recording canvas. + phase.clear(GraphicsLayerPaintBackground); + if (!paintContext(m_contentLayer->foregroundContext(), + m_contentsRect)) + return false; + } else { + // If there is no contents clip, we can draw everything into one + // picture. + if (!paintContext(m_contentLayer->recordContext(), layerBounds)) + return false; + } TLOG("(%x) repaint() on (%.2f,%.2f) contentlayer(%.2f,%.2f,%.2f,%.2f)paintGraphicsLayer called!", this, m_size.width(), m_size.height(), @@ -441,6 +478,22 @@ bool GraphicsLayerAndroid::repaint() return false; } +bool GraphicsLayerAndroid::paintContext(SkPicture* context, + const IntRect& rect) +{ + SkAutoPictureRecord arp(context, rect.width(), rect.height()); + SkCanvas* canvas = arp.getRecordingCanvas(); + + if (canvas == 0) + return false; + + PlatformGraphicsContext platformContext(canvas, 0); + GraphicsContext graphicsContext(&platformContext); + + paintGraphicsLayerContents(graphicsContext, rect); + return true; +} + void GraphicsLayerAndroid::setNeedsDisplayInRect(const FloatRect& rect) { for (unsigned int i = 0; i < m_children.size(); i++) { @@ -874,6 +927,11 @@ void GraphicsLayerAndroid::notifyClientAnimationStarted() } } +void GraphicsLayerAndroid::setContentsClip(const IntRect& clip) +{ + m_contentLayer->setForegroundClip(clip); +} + } // namespace WebCore #endif // USE(ACCELERATED_COMPOSITING) diff --git a/WebCore/platform/graphics/android/GraphicsLayerAndroid.h b/WebCore/platform/graphics/android/GraphicsLayerAndroid.h index 54a035b..7482969 100644 --- a/WebCore/platform/graphics/android/GraphicsLayerAndroid.h +++ b/WebCore/platform/graphics/android/GraphicsLayerAndroid.h @@ -115,6 +115,8 @@ public: static int instancesCount(); + void setContentsClip(const IntRect& clip); + private: void askForSync(); @@ -129,6 +131,8 @@ private: bool repaint(); void needsNotifyClient(); + bool paintContext(SkPicture* context, const IntRect& rect); + bool m_needsSyncChildren; bool m_needsSyncMask; bool m_needsRepaint; diff --git a/WebCore/platform/graphics/android/LayerAndroid.cpp b/WebCore/platform/graphics/android/LayerAndroid.cpp index 5aaa243..b80171e 100644 --- a/WebCore/platform/graphics/android/LayerAndroid.cpp +++ b/WebCore/platform/graphics/android/LayerAndroid.cpp @@ -12,6 +12,7 @@ #include "SkPicture.h" #include <wtf/CurrentTime.h> + #define LAYER_DEBUG // Add diagonals for debugging #undef LAYER_DEBUG @@ -51,6 +52,7 @@ LayerAndroid::LayerAndroid(bool isRootLayer) : SkLayer(), m_doRotation(false), m_isFixed(false), m_recordingPicture(0), + m_foregroundPicture(0), m_contentsImage(0), m_extra(0), m_uniqueId(++gUniqueId) @@ -59,6 +61,8 @@ LayerAndroid::LayerAndroid(bool isRootLayer) : SkLayer(), m_translation.set(0, 0); m_scale.set(1, 1); m_backgroundColor = 0; + m_foregroundClip.setEmpty(); + m_foregroundLocation.set(0, 0); gDebugLayerAndroidInstances++; } @@ -90,7 +94,12 @@ LayerAndroid::LayerAndroid(const LayerAndroid& layer) : SkLayer(layer), m_fixedRect = layer.m_fixedRect; m_recordingPicture = layer.m_recordingPicture; + m_foregroundPicture = layer.m_foregroundPicture; SkSafeRef(m_recordingPicture); + SkSafeRef(m_foregroundPicture); + + m_foregroundClip = layer.m_foregroundClip; + m_foregroundLocation = layer.m_foregroundLocation; for (int i = 0; i < layer.countChildren(); i++) addChild(new LayerAndroid(*layer.getChild(i)))->unref(); @@ -102,29 +111,12 @@ LayerAndroid::LayerAndroid(const LayerAndroid& layer) : SkLayer(layer), gDebugLayerAndroidInstances++; } -LayerAndroid::LayerAndroid(SkPicture* picture) : SkLayer(), - m_isRootLayer(true), - m_haveClip(false), - m_doRotation(false), - m_isFixed(false), - m_recordingPicture(picture), - m_contentsImage(0), - m_extra(0), - m_uniqueId(-1) -{ - m_angleTransform = 0; - m_translation.set(0, 0); - m_scale.set(1, 1); - m_backgroundColor = 0; - SkSafeRef(m_recordingPicture); - gDebugLayerAndroidInstances++; -} - LayerAndroid::~LayerAndroid() { removeChildren(); m_contentsImage->safeUnref(); m_recordingPicture->safeUnref(); + m_foregroundPicture->safeUnref(); m_animations.clear(); gDebugLayerAndroidInstances--; } @@ -339,6 +331,14 @@ void LayerAndroid::onDraw(SkCanvas* canvas, SkScalar opacity) { canvas->drawBitmapRect(m_contentsImage->bitmap(), 0, dest); } else { canvas->drawPicture(*m_recordingPicture); + if (m_foregroundPicture) { + canvas->save(); + canvas->clipRect(m_foregroundClip); + canvas->translate(-m_foregroundLocation.fX, + -m_foregroundLocation.fY); + canvas->drawPicture(*m_foregroundPicture); + canvas->restore(); + } } if (m_extra) m_extra->draw(canvas, this); @@ -371,6 +371,36 @@ SkPicture* LayerAndroid::recordContext() return 0; } +SkPicture* LayerAndroid::foregroundContext() +{ + // Always create a new picture since this method is called only when + // recording the foreground picture. + m_foregroundPicture = new SkPicture(); + return m_foregroundPicture; +} + +bool LayerAndroid::contentIsScrollable() const { + return m_foregroundPicture != 0 && + (getWidth() < SkIntToScalar(m_foregroundPicture->width()) || + getHeight() < SkIntToScalar(m_foregroundPicture->height())); +} + +bool LayerAndroid::scrollBy(int dx, int dy) { + if (m_foregroundPicture == 0) + return false; + SkScalar maxScrollX = SkIntToScalar(m_foregroundPicture->width()) - getWidth(); + SkScalar maxScrollY = SkIntToScalar(m_foregroundPicture->height()) - getHeight(); + SkScalar x = m_foregroundLocation.fX + dx; + SkScalar y = m_foregroundLocation.fY + dy; + x = SkScalarClampMax(x, maxScrollX); + y = SkScalarClampMax(y, maxScrollY); + if (x != m_foregroundLocation.fX || y != m_foregroundLocation.fY) { + m_foregroundLocation.set(x, y); + return true; + } + return false; +} + bool LayerAndroid::prepareContext(bool force) { if (!m_isRootLayer) { diff --git a/WebCore/platform/graphics/android/LayerAndroid.h b/WebCore/platform/graphics/android/LayerAndroid.h index b98d4dd..2c11958 100644 --- a/WebCore/platform/graphics/android/LayerAndroid.h +++ b/WebCore/platform/graphics/android/LayerAndroid.h @@ -77,7 +77,6 @@ class LayerAndroid : public SkLayer { public: LayerAndroid(bool isRootLayer); LayerAndroid(const LayerAndroid& layer); - LayerAndroid(SkPicture* ); virtual ~LayerAndroid(); static int instancesCount(); @@ -127,6 +126,21 @@ public: SkPicture* recordContext(); + // The foreground context is used to draw overflow scroll content. + SkPicture* foregroundContext(); + + // The foreground clip is set when there is content within the node that + // can be scrolled (i.e. a div with overflow:scroll). + void setForegroundClip(const SkRect& clip) { + m_foregroundClip = clip; + } + bool contentIsScrollable() const; + + // Returns true if the content position has changed. + bool scrollBy(int dx, int dy); + const SkPoint& scrollPosition() const { return m_foregroundLocation; } + void setScrollPosition(const SkPoint& pos) { m_foregroundLocation = pos; } + void addAnimation(PassRefPtr<AndroidAnimation> anim); void removeAnimation(const String& name); bool evaluateAnimations() const; @@ -215,6 +229,16 @@ private: // We do this as if the layer only contains an image, directly compositing // it is a much faster method than using m_recordingPicture. SkPicture* m_recordingPicture; + + // m_foregroundPicture is set only when compositing a scrollable div. It + // contains the contents minus the background and border which is drawn + // first by the rendering tree. When we draw the layer, we draw + // m_recordingPicture (containing the background + border) first and then + // clip to m_foregroundClip and draw m_foregroundPicture. + SkPicture* m_foregroundPicture; + SkRect m_foregroundClip; + SkPoint m_foregroundLocation; + SkBitmapRef* m_contentsImage; typedef HashMap<String, RefPtr<AndroidAnimation> > KeyframesMap; |