summaryrefslogtreecommitdiffstats
path: root/WebCore
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore')
-rw-r--r--WebCore/config.h3
-rw-r--r--WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp80
-rw-r--r--WebCore/platform/graphics/android/GraphicsLayerAndroid.h4
-rw-r--r--WebCore/platform/graphics/android/LayerAndroid.cpp66
-rw-r--r--WebCore/platform/graphics/android/LayerAndroid.h26
-rw-r--r--WebCore/rendering/RenderLayer.cpp26
-rw-r--r--WebCore/rendering/RenderLayerBacking.cpp40
-rw-r--r--WebCore/rendering/RenderLayerCompositor.cpp15
8 files changed, 230 insertions, 30 deletions
diff --git a/WebCore/config.h b/WebCore/config.h
index 84e50fe..df4d06b 100644
--- a/WebCore/config.h
+++ b/WebCore/config.h
@@ -200,6 +200,9 @@
// Enable hit test with point plus a size
#define ANDROID_HITTEST_WITHSIZE
+// Enable scrollable divs in separate layers. This might be upstreamed to
+// webkit.org but for now, it is just an Android feature.
+#define ENABLE_ANDROID_OVERFLOW_SCROLL 1
#endif /* PLATFORM(ANDROID) */
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;
diff --git a/WebCore/rendering/RenderLayer.cpp b/WebCore/rendering/RenderLayer.cpp
index d9d2be1..75daa94 100644
--- a/WebCore/rendering/RenderLayer.cpp
+++ b/WebCore/rendering/RenderLayer.cpp
@@ -3237,8 +3237,17 @@ void RenderLayer::calculateRects(const RenderLayer* rootLayer, const IntRect& pa
// Update the clip rects that will be passed to child layers.
if (renderer()->hasOverflowClip() || renderer()->hasClip()) {
// This layer establishes a clip of some kind.
+#if ENABLE(ANDROID_OVERFLOW_SCROLL)
+ if (renderer()->hasOverflowClip()) {
+ RenderBox* box = toRenderBox(renderer());
+ layerBounds = backgroundRect = foregroundRect = outlineRect =
+ IntRect(x, y, box->borderLeft() + box->borderRight() + m_scrollWidth,
+ box->borderTop() + box->borderBottom() + m_scrollHeight);
+ }
+#else
if (renderer()->hasOverflowClip())
foregroundRect.intersect(toRenderBox(renderer())->overflowClipRect(x, y));
+#endif
if (renderer()->hasClip()) {
// Clip applies to *us* as well, so go ahead and update the damageRect.
IntRect newPosClip = toRenderBox(renderer())->clipRect(x, y);
@@ -3748,8 +3757,25 @@ bool RenderLayer::shouldBeNormalFlowOnly() const
&& !isTransparent();
}
+#if ENABLE(ANDROID_OVERFLOW_SCROLL)
+static bool hasOverflowScroll(const RenderLayer* l)
+{
+ RenderLayer* layer = const_cast<RenderLayer*>(l);
+ RenderBox* box = layer->renderBox();
+ EOverflow x = box->style()->overflowX();
+ EOverflow y = box->style()->overflowY();
+ return (x == OAUTO || x == OSCROLL || y == OAUTO || y == OSCROLL) &&
+ (layer->scrollWidth() > box->clientWidth() ||
+ layer->scrollHeight() > box->clientHeight());
+}
+#endif
+
bool RenderLayer::isSelfPaintingLayer() const
{
+#if ENABLE(ANDROID_OVERFLOW_SCROLL)
+ if (hasOverflowScroll(this))
+ return true;
+#endif
return !isNormalFlowOnly() || renderer()->hasReflection() || renderer()->hasMask() || renderer()->isTableRow() || renderer()->isVideo() || renderer()->isEmbeddedObject() || renderer()->isRenderIFrame();
}
diff --git a/WebCore/rendering/RenderLayerBacking.cpp b/WebCore/rendering/RenderLayerBacking.cpp
index ae01799..1153727 100644
--- a/WebCore/rendering/RenderLayerBacking.cpp
+++ b/WebCore/rendering/RenderLayerBacking.cpp
@@ -55,6 +55,10 @@
#include "RenderLayerBacking.h"
+#if ENABLE(ANDROID_OVERFLOW_SCROLL)
+#include "GraphicsLayerAndroid.h"
+#endif
+
using namespace std;
namespace WebCore {
@@ -397,6 +401,18 @@ void RenderLayerBacking::updateGraphicsLayerGeometry()
}
m_graphicsLayer->setContentsRect(contentsBox());
+#if ENABLE(ANDROID_OVERFLOW_SCROLL)
+ if (m_owningLayer->hasOverflowControls()) {
+ RenderBoxModelObject* box = renderer();
+ IntRect clip = compositedBounds();
+ IntPoint location = clip.location();
+ location.move(box->borderLeft(), box->borderTop());
+ clip.setLocation(location);
+ clip.setWidth(clip.width() - box->borderLeft() - box->borderRight());
+ clip.setHeight(clip.height() - box->borderTop() - box->borderBottom());
+ static_cast<GraphicsLayerAndroid*>(m_graphicsLayer.get())->setContentsClip(clip);
+ }
+#endif
updateDrawsContent();
updateAfterWidgetResize();
}
@@ -819,6 +835,24 @@ IntRect RenderLayerBacking::contentsBox() const
} else
#endif
contentsRect = toRenderBox(renderer())->contentBoxRect();
+#if ENABLE(ANDROID_OVERFLOW_SCROLL)
+ if (m_owningLayer->hasOverflowControls()) {
+ // Update the contents rect to have the width and height of the entire
+ // contents. This rect is only used by the platform GraphicsLayer and
+ // the position of the rectangle is ignored. Use the layer's scroll
+ // width/height (which contain the padding).
+ RenderBox* box = toRenderBox(renderer());
+ contentsRect.setWidth(box->borderLeft() + box->borderRight() +
+ m_owningLayer->scrollWidth());
+ contentsRect.setHeight(box->borderTop() + box->borderBottom() +
+ m_owningLayer->scrollHeight());
+ // Move the contents rect by the padding since
+ // RenderBox::contentBoxRect includes the padding. The end result is
+ // to have a box representing the entires contents plus border and
+ // padding. This will be the size of the underlying picture.
+ contentsRect.setLocation(IntPoint(0, 0));
+ }
+#endif
IntSize contentOffset = contentOffsetInCompostingLayer();
contentsRect.move(contentOffset);
@@ -1053,6 +1087,12 @@ void RenderLayerBacking::paintContents(const GraphicsLayer*, GraphicsContext& co
// We have to use the same root as for hit testing, because both methods
// can compute and cache clipRects.
IntRect enclosingBBox = compositedBounds();
+#if ENABLE(ANDROID_OVERFLOW_SCROLL)
+ if (m_owningLayer->hasOverflowControls()) {
+ enclosingBBox.setSize(contentsBox().size());
+ enclosingBBox.setLocation(m_compositedBounds.location());
+ }
+#endif
IntRect clipRect(clip);
diff --git a/WebCore/rendering/RenderLayerCompositor.cpp b/WebCore/rendering/RenderLayerCompositor.cpp
index c485acc..1a28c37 100644
--- a/WebCore/rendering/RenderLayerCompositor.cpp
+++ b/WebCore/rendering/RenderLayerCompositor.cpp
@@ -1153,6 +1153,18 @@ bool RenderLayerCompositor::requiresCompositingForMobileSites(const RenderLayer*
}
#endif
+#if ENABLE(ANDROID_OVERFLOW_SCROLL)
+static bool requiresCompositingForOverflowScroll(const RenderLayer* l) {
+ RenderLayer* layer = const_cast<RenderLayer*>(l);
+ RenderBox* box = layer->renderBox();
+ EOverflow x = box->style()->overflowX();
+ EOverflow y = box->style()->overflowY();
+ return (x == OAUTO || x == OSCROLL || y == OAUTO || y == OSCROLL) &&
+ (layer->scrollWidth() > box->contentWidth() ||
+ layer->scrollHeight() > box->contentHeight());
+}
+#endif
+
// Note: this specifies whether the RL needs a compositing layer for intrinsic reasons.
// Use needsToBeComposited() to determine if a RL actually needs a compositing layer.
// static
@@ -1167,6 +1179,9 @@ bool RenderLayerCompositor::requiresCompositingLayer(const RenderLayer* layer) c
return requiresCompositingForTransform(renderer)
#if PLATFORM(ANDROID)
|| requiresCompositingForMobileSites(layer)
+#if ENABLE(ANDROID_OVERFLOW_SCROLL)
+ || requiresCompositingForOverflowScroll(layer)
+#endif
#endif
|| requiresCompositingForVideo(renderer)
|| requiresCompositingForCanvas(renderer)