From a15d30f54c6edc68da7e82c198b5916dd023ac4d Mon Sep 17 00:00:00 2001 From: Nicolas Roard Date: Fri, 6 Apr 2012 15:16:28 -0700 Subject: CSS Background image implementation bug:1352305 Change-Id: Id9caaae9b9442729110b52c75004f634d8284db4 --- .../platform/graphics/GraphicsLayerClient.h | 3 + .../graphics/android/GraphicsLayerAndroid.cpp | 152 +++++++++++++++++++-- .../graphics/android/GraphicsLayerAndroid.h | 7 +- .../context/GraphicsOperationCollection.cpp | 4 +- .../graphics/android/layers/BaseLayerAndroid.cpp | 44 +++++- .../graphics/android/layers/BaseLayerAndroid.h | 29 ++-- .../android/layers/FixedBackgroundLayerAndroid.h | 49 +++++++ .../graphics/android/layers/FixedPositioning.h | 9 ++ .../graphics/android/layers/LayerAndroid.cpp | 6 +- .../graphics/android/layers/LayerAndroid.h | 10 ++ .../graphics/android/rendering/Surface.cpp | 20 ++- .../graphics/android/utils/ClassTracker.cpp | 2 +- Source/WebCore/rendering/PaintPhase.h | 4 + Source/WebCore/rendering/RenderBlock.cpp | 6 +- Source/WebCore/rendering/RenderBox.cpp | 5 + Source/WebCore/rendering/RenderBoxModelObject.h | 4 + Source/WebCore/rendering/RenderLayerBacking.cpp | 12 ++ Source/WebCore/rendering/RenderLayerCompositor.cpp | 3 + Source/WebKit/android/jni/WebViewCore.cpp | 68 ++++++--- Source/WebKit/android/nav/WebView.cpp | 2 +- 20 files changed, 383 insertions(+), 56 deletions(-) create mode 100644 Source/WebCore/platform/graphics/android/layers/FixedBackgroundLayerAndroid.h (limited to 'Source') diff --git a/Source/WebCore/platform/graphics/GraphicsLayerClient.h b/Source/WebCore/platform/graphics/GraphicsLayerClient.h index aab176b..3f09f32 100644 --- a/Source/WebCore/platform/graphics/GraphicsLayerClient.h +++ b/Source/WebCore/platform/graphics/GraphicsLayerClient.h @@ -43,6 +43,9 @@ enum GraphicsLayerPaintingPhase { GraphicsLayerPaintBackground = (1 << 0), GraphicsLayerPaintForeground = (1 << 1), GraphicsLayerPaintMask = (1 << 2), +#if PLATFORM(ANDROID) + GraphicsLayerPaintBackgroundDecorations = (1 << 3), +#endif GraphicsLayerPaintAll = (GraphicsLayerPaintBackground | GraphicsLayerPaintForeground | GraphicsLayerPaintMask) }; diff --git a/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp b/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp index 00e6918..381f0b1 100644 --- a/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp +++ b/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp @@ -25,9 +25,11 @@ #include "AndroidAnimation.h" #include "AndroidLog.h" #include "Animation.h" +#include "CachedImage.h" #include "CanvasLayer.h" -#include "FloatRect.h" +#include "FixedBackgroundLayerAndroid.h" #include "FixedPositioning.h" +#include "FloatRect.h" #include "GraphicsContext.h" #include "IFrameContentLayerAndroid.h" #include "IFrameLayerAndroid.h" @@ -47,6 +49,7 @@ #include "ScrollableLayerAndroid.h" #include "SkCanvas.h" #include "SkRegion.h" +#include "StyleCachedImage.h" #include "TransformationMatrix.h" #include "TranslateTransformOperation.h" @@ -117,6 +120,8 @@ GraphicsLayerAndroid::GraphicsLayerAndroid(GraphicsLayerClient* client) : m_haveContents(false), m_newImage(false), m_image(0), + m_backgroundDecorationsLayer(0), + m_fixedBackgroundLayer(0), m_foregroundLayer(0), m_foregroundClipLayer(0) { @@ -136,6 +141,8 @@ GraphicsLayerAndroid::~GraphicsLayerAndroid() m_image->deref(); m_contentLayer->unref(); + SkSafeUnref(m_backgroundDecorationsLayer); + SkSafeUnref(m_fixedBackgroundLayer); SkSafeUnref(m_foregroundLayer); SkSafeUnref(m_foregroundClipLayer); gDebugGraphicsLayerAndroidInstances--; @@ -167,7 +174,7 @@ void GraphicsLayerAndroid::addChild(GraphicsLayer* childLayer) { #ifndef NDEBUG const String& name = childLayer->name(); - ALOGV("(%x) addChild: %x (%s)", this, childLayer, name.latin1().data()); + ALOGV("(%x) addChild: %x (%s)", this, childLayer, name.ascii().data()); #endif GraphicsLayer::addChild(childLayer); m_needsSyncChildren = true; @@ -328,7 +335,8 @@ void GraphicsLayerAndroid::setSize(const FloatSize& size) { if (size == m_size) return; - ALOGV("(%x) setSize (%.2f,%.2f)", this, size.width(), size.height()); + ALOGV("(%x) layer %d setSize (%.2f,%.2f)", this, + m_contentLayer->uniqueId(), size.width(), size.height()); GraphicsLayer::setSize(size); // If it is a media layer the size may have changed as a result of the media @@ -547,7 +555,7 @@ void GraphicsLayerAndroid::updateScrollingLayers() } // Need to rebuild our children based on the new structure. m_needsSyncChildren = true; - } else { + } else if (!m_contentLayer->isFixedBackground()) { ASSERT(hasOverflowScroll && !layerNeedsOverflow && !iframeNeedsOverflow); ASSERT(m_contentLayer); // Remove the foreground layers. @@ -573,6 +581,96 @@ void GraphicsLayerAndroid::updateScrollingLayers() #endif } +void GraphicsLayerAndroid::updateFixedBackgroundLayers() { + RenderLayer* renderLayer = renderLayerFromClient(m_client); + if (!renderLayer) + return; + RenderView* view = static_cast(renderLayer->renderer()); + if (!view) + return; + if (view->isBody()) // body element is already handled + return; + if (!view->style()->hasFixedBackgroundImage()) + return; + if (m_contentLayer->isFixedBackground()) + return; + if (m_fixedBackgroundLayer) // already created + return; + + // we will have: + // m_contentLayer + // \- m_foregroundClipLayer + // \- m_fixedBackgroundLayer + // \- m_backgroundDecorationsLayer + // \- m_foregroundLayer + + // Grab the background image and create a layer for it + // the layer will be fixed positioned. + // TODO: if there's a background color, we don't honor it. + FillLayer* layers = view->style()->accessBackgroundLayers(); + StyleImage* styleImage = layers->image(); + if (styleImage->isCachedImage()) { + CachedImage* cachedImage = static_cast(styleImage)->cachedImage(); + Image* image = cachedImage->image(); + if (image) { + m_fixedBackgroundLayer = new LayerAndroid(renderLayer); + m_fixedBackgroundLayer->setContentsImage(image->nativeImageForCurrentFrame()); + m_fixedBackgroundLayer->setSize(image->width(), image->height()); + + // TODO: add support for the correct CSS position attributes + // for now, just pin to left(0) top(0) + + FixedPositioning* fixedPosition = new FixedPositioning(m_fixedBackgroundLayer); + SkRect viewRect; + SkLength left, top, right, bottom; + left.setFixedValue(0); + top.setFixedValue(0); + right.setAuto(); + bottom.setAuto(); + SkLength marginLeft, marginTop, marginRight, marginBottom; + marginLeft.setAuto(); + marginTop.setAuto(); + marginRight.setAuto(); + marginBottom.setAuto(); + + viewRect.set(0, 0, view->width(), view->height()); + fixedPosition->setFixedPosition(left, top, right, bottom, + marginLeft, marginTop, + marginRight, marginBottom, + IntPoint(0, 0), viewRect); + + m_fixedBackgroundLayer->setFixedPosition(fixedPosition); + } + } + + // We need to clip the background image to the bounds of the original element + m_foregroundClipLayer = new LayerAndroid(renderLayer); + m_foregroundClipLayer->setMasksToBounds(true); + m_foregroundClipLayer->addChild(m_fixedBackgroundLayer); + + // We then want to display the content above the image background; webkit + // allow to paint background and foreground separately. For now, we'll create + // two layers; the one containing the background will be painted *without* the + // background image (but with the decorations, e.g. border) + // TODO: use a single layer with a new type of content (joining background/foreground?) + m_backgroundDecorationsLayer = new LayerAndroid(renderLayer); + m_backgroundDecorationsLayer->setIntrinsicallyComposited(true); + m_foregroundLayer = new LayerAndroid(renderLayer); + m_foregroundLayer->setIntrinsicallyComposited(false); + + // Finally, let's assemble all the layers under a FixedBackgroundLayerAndroid layer + LayerAndroid* layer = new FixedBackgroundLayerAndroid(*m_contentLayer); + m_contentLayer->unref(); + m_contentLayer = layer; + + m_contentLayer->addChild(m_foregroundClipLayer); + m_contentLayer->addChild(m_backgroundDecorationsLayer); + m_contentLayer->addChild(m_foregroundLayer); + + m_needsRepaint = true; + m_needsSyncChildren = true; +} + void GraphicsLayerAndroid::updateScrollOffset() { RenderLayer* layer = renderLayerFromClient(m_client); if (!layer || !(m_foregroundLayer || m_contentLayer->contentIsScrollable())) @@ -600,7 +698,7 @@ bool GraphicsLayerAndroid::repaint() RenderLayer* layer = renderLayerFromClient(m_client); if (!layer) return false; - if (m_foregroundLayer) { + if (m_foregroundLayer && !m_contentLayer->isFixedBackground()) { PaintingPhase phase(this); // Paint the background into a separate context. phase.set(GraphicsLayerPaintBackground); @@ -648,7 +746,7 @@ bool GraphicsLayerAndroid::repaint() // for the contents to be in the correct position. m_foregroundLayer->setPosition(-x, -y); // Set the scrollable bounds of the layer. - m_foregroundLayer->setScrollLimits(-x, -y, m_size.width(), m_size.height()); + static_cast(m_foregroundLayer)->setScrollLimits(-x, -y, m_size.width(), m_size.height()); // Invalidate the entire layer for now, as webkit will only send the // setNeedsDisplayInRect() for the visible (clipped) scrollable area, @@ -657,6 +755,25 @@ bool GraphicsLayerAndroid::repaint() SkRegion region; region.setRect(0, 0, contentsRect.width(), contentsRect.height()); m_foregroundLayer->markAsDirty(region); + } else if (m_contentLayer->isFixedBackground()) { + PaintingPhase phase(this); + // Paint the background into a separate context. + ALOGV("paint background of layer %d (%d x %d)", m_contentLayer->uniqueId(), + layerBounds.width(), layerBounds.height()); + + m_backgroundDecorationsLayer->setSize(layerBounds.width(), layerBounds.height()); + phase.set(GraphicsLayerPaintBackgroundDecorations); + paintContext(m_backgroundDecorationsLayer, layerBounds); + phase.clear(GraphicsLayerPaintBackgroundDecorations); + + // Paint the foreground into a separate context. + ALOGV("paint foreground of layer %d", m_contentLayer->uniqueId()); + m_foregroundLayer->setSize(layerBounds.width(), layerBounds.height()); + phase.set(GraphicsLayerPaintForeground); + paintContext(m_foregroundLayer, layerBounds); + + m_foregroundClipLayer->setPosition(layerBounds.x(), layerBounds.y()); + m_foregroundClipLayer->setSize(layerBounds.width(), layerBounds.height()); } else { // If there is no contents clip, we can draw everything into one // picture. @@ -788,7 +905,7 @@ bool GraphicsLayerAndroid::createAnimationFromKeyframes(const KeyframeValueList& { bool isKeyframe = valueList.size() > 2; ALOGV("createAnimationFromKeyframes(%d), name(%s) beginTime(%.2f)", - isKeyframe, keyframesName.latin1().data(), beginTime); + isKeyframe, keyframesName.ascii().data(), beginTime); switch (valueList.property()) { case AnimatedPropertyInvalid: break; @@ -837,7 +954,7 @@ bool GraphicsLayerAndroid::createTransformAnimationsFromKeyframes(const Keyframe { ASSERT(valueList.property() == AnimatedPropertyWebkitTransform); ALOGV("createTransformAnimationFromKeyframes, name(%s) beginTime(%.2f)", - keyframesName.latin1().data(), beginTime); + keyframesName.ascii().data(), beginTime); KeyframeValueList* operationsList = new KeyframeValueList(AnimatedPropertyWebkitTransform); for (unsigned int i = 0; i < valueList.size(); i++) { @@ -874,14 +991,14 @@ void GraphicsLayerAndroid::removeAnimationsForProperty(AnimatedPropertyID anID) void GraphicsLayerAndroid::removeAnimationsForKeyframes(const String& keyframesName) { - ALOGV("NRO removeAnimationsForKeyframes(%s)", keyframesName.latin1().data()); + ALOGV("NRO removeAnimationsForKeyframes(%s)", keyframesName.ascii().data()); m_contentLayer->removeAnimationsForKeyframes(keyframesName); askForSync(); } void GraphicsLayerAndroid::pauseAnimation(const String& keyframesName) { - ALOGV("NRO pauseAnimation(%s)", keyframesName.latin1().data()); + ALOGV("NRO pauseAnimation(%s)", keyframesName.ascii().data()); } void GraphicsLayerAndroid::suspendAnimations(double time) @@ -984,20 +1101,28 @@ void GraphicsLayerAndroid::askForSync() void GraphicsLayerAndroid::syncChildren() { - if (m_needsSyncChildren) { + if (m_needsSyncChildren && !m_contentLayer->isFixedBackground()) { m_contentLayer->removeChildren(); LayerAndroid* layer = m_contentLayer; - if (m_foregroundClipLayer) { + + if (m_contentLayer->isFixedBackground()) { + m_contentLayer->addChild(m_foregroundClipLayer); + m_contentLayer->addChild(m_backgroundDecorationsLayer); + m_contentLayer->addChild(m_foregroundLayer); + layer = m_foregroundLayer; + layer->removeChildren(); + } else if (m_foregroundClipLayer) { m_contentLayer->addChild(m_foregroundClipLayer); // Use the scrollable content layer as the parent of the children so // that they move with the content. layer = m_foregroundLayer; layer->removeChildren(); } + for (unsigned int i = 0; i < m_children.size(); i++) layer->addChild(m_children[i]->platformLayer()); - m_needsSyncChildren = false; } + m_needsSyncChildren = false; } void GraphicsLayerAndroid::syncMask() @@ -1046,6 +1171,7 @@ void GraphicsLayerAndroid::syncCompositingStateForThisLayerOnly() } updateScrollingLayers(); + updateFixedBackgroundLayers(); updatePositionedLayers(); syncChildren(); syncMask(); diff --git a/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.h b/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.h index 97f974e..24ba2d8 100644 --- a/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.h +++ b/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.h @@ -124,7 +124,7 @@ public: void notifyClientAnimationStarted(); LayerAndroid* contentLayer() { return m_contentLayer; } - ScrollableLayerAndroid* foregroundLayer() { return m_foregroundLayer; } + LayerAndroid* foregroundLayer() { return m_foregroundLayer; } static int instancesCount(); @@ -139,6 +139,7 @@ private: void updatePositionedLayers(); void updateScrollingLayers(); + void updateFixedBackgroundLayers(); // with SkPicture, we always repaint the entire layer's content. bool repaint(); @@ -158,7 +159,9 @@ private: SkRegion m_dirtyRegion; LayerAndroid* m_contentLayer; - ScrollableLayerAndroid* m_foregroundLayer; + LayerAndroid* m_backgroundDecorationsLayer; + LayerAndroid* m_fixedBackgroundLayer; + LayerAndroid* m_foregroundLayer; LayerAndroid* m_foregroundClipLayer; }; diff --git a/Source/WebCore/platform/graphics/android/context/GraphicsOperationCollection.cpp b/Source/WebCore/platform/graphics/android/context/GraphicsOperationCollection.cpp index 6118160..9e6208d 100644 --- a/Source/WebCore/platform/graphics/android/context/GraphicsOperationCollection.cpp +++ b/Source/WebCore/platform/graphics/android/context/GraphicsOperationCollection.cpp @@ -28,8 +28,8 @@ void GraphicsOperationCollection::apply(PlatformGraphicsContext* context) { ALOGD("\nApply GraphicsOperationCollection %x, %d operations", this, m_operations.size()); for (unsigned int i = 0; i < m_operations.size(); i++) { - ALOGD("[%d] (%x) %s %s", i, this, m_operations[i]->name().latin1().data(), - m_operations[i]->parameters().latin1().data()); + ALOGD("[%d] (%x) %s %s", i, this, m_operations[i]->name().ascii().data(), + m_operations[i]->parameters().ascii().data()); m_operations[i]->apply(context); } } diff --git a/Source/WebCore/platform/graphics/android/layers/BaseLayerAndroid.cpp b/Source/WebCore/platform/graphics/android/layers/BaseLayerAndroid.cpp index ce520b4..bc3b04b 100644 --- a/Source/WebCore/platform/graphics/android/layers/BaseLayerAndroid.cpp +++ b/Source/WebCore/platform/graphics/android/layers/BaseLayerAndroid.cpp @@ -30,6 +30,7 @@ #include "BaseLayerAndroid.h" #include "AndroidLog.h" +#include "FixedPositioning.h" #include "GLWebViewState.h" #include "LayerContent.h" @@ -42,8 +43,10 @@ BaseLayerAndroid::BaseLayerAndroid(LayerContent* content) : LayerAndroid((RenderLayer*)0) , m_color(Color::white) { - setContent(content); - setSize(content->width(), content->height()); + if (content) { + setContent(content); + setSize(content->width(), content->height()); + } m_uniqueId = BASE_UNIQUE_ID; } @@ -66,4 +69,41 @@ IFrameLayerAndroid* BaseLayerAndroid::updatePosition(SkRect viewport, return LayerAndroid::updatePosition(viewport, parentIframeLayer); } +ForegroundBaseLayerAndroid::ForegroundBaseLayerAndroid(LayerContent* content) + : LayerAndroid((RenderLayer*)0) +{ + setIntrinsicallyComposited(true); +} + +FixedBackgroundBaseLayerAndroid::FixedBackgroundBaseLayerAndroid(LayerContent* content) + : LayerAndroid((RenderLayer*)0) +{ + if (content) { + setContent(content); + setSize(content->width(), content->height()); + } + setIntrinsicallyComposited(true); + + // TODO: add support for fixed positioning attributes + SkRect viewRect; + SkLength left, top, right, bottom; + left.setFixedValue(0); + top.setFixedValue(0); + right.setAuto(); + bottom.setAuto(); + SkLength marginLeft, marginTop, marginRight, marginBottom; + marginLeft.setAuto(); + marginTop.setAuto(); + marginRight.setAuto(); + marginBottom.setAuto(); + + viewRect.set(0, 0, content->width(), content->height()); + FixedPositioning* fixedPosition = new FixedPositioning(this); + setFixedPosition(fixedPosition); + fixedPosition->setFixedPosition(left, top, right, bottom, + marginLeft, marginTop, + marginRight, marginBottom, + IntPoint(0, 0), viewRect); +} + } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/android/layers/BaseLayerAndroid.h b/Source/WebCore/platform/graphics/android/layers/BaseLayerAndroid.h index f4cf9f3..dc4c25f 100644 --- a/Source/WebCore/platform/graphics/android/layers/BaseLayerAndroid.h +++ b/Source/WebCore/platform/graphics/android/layers/BaseLayerAndroid.h @@ -34,28 +34,37 @@ namespace WebCore { class RenderLayerCompositor; class BaseLayerAndroid : public LayerAndroid { - public: BaseLayerAndroid(LayerContent* content); - - virtual ~BaseLayerAndroid() {}; - virtual SubclassType subclassType() { return LayerAndroid::BaseLayer; } - virtual bool needsTexture() { return true; } - - void setBackgroundColor(Color& color) { m_color = color; } - Color getBackgroundColor() { return m_color; } - virtual void getLocalTransform(SkMatrix* matrix) const; virtual const TransformationMatrix* drawTransform() const { return 0; } - + virtual bool needsTexture() { return content(); } virtual IFrameLayerAndroid* updatePosition(SkRect viewport, IFrameLayerAndroid* parentIframeLayer); + void setBackgroundColor(Color& color) { m_color = color; } + Color getBackgroundColor() { return m_color; } + private: // TODO: move to SurfaceCollection. Color m_color; }; +class ForegroundBaseLayerAndroid : public LayerAndroid { +public: + ForegroundBaseLayerAndroid(LayerContent* content); + virtual SubclassType subclassType() { return LayerAndroid::ForegroundBaseLayer; } + + virtual bool needsTexture() { return false; } +}; + +class FixedBackgroundBaseLayerAndroid : public LayerAndroid { +public: + FixedBackgroundBaseLayerAndroid(LayerContent* content); + virtual bool needsTexture() { return true; } + virtual SubclassType subclassType() { return LayerAndroid::FixedBackgroundBaseLayer; } +}; + } // namespace WebCore #endif //BaseLayerAndroid_h diff --git a/Source/WebCore/platform/graphics/android/layers/FixedBackgroundLayerAndroid.h b/Source/WebCore/platform/graphics/android/layers/FixedBackgroundLayerAndroid.h new file mode 100644 index 0000000..6c8f42c --- /dev/null +++ b/Source/WebCore/platform/graphics/android/layers/FixedBackgroundLayerAndroid.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FixedBackgroundLayerAndroid_h +#define FixedBackgroundLayerAndroid_h + +#if USE(ACCELERATED_COMPOSITING) + +#include "LayerAndroid.h" + +namespace WebCore { + +// TODO: the hierarchy manipulation in GraphicsLayerAndroid should +// (at least partly) be handled in this class +class FixedBackgroundLayerAndroid : public LayerAndroid { +public: + FixedBackgroundLayerAndroid(RenderLayer* owner) + : LayerAndroid(owner) {} + FixedBackgroundLayerAndroid(const FixedBackgroundLayerAndroid& layer) + : LayerAndroid(layer) {} + FixedBackgroundLayerAndroid(const LayerAndroid& layer) + : LayerAndroid(layer) {} + virtual ~FixedBackgroundLayerAndroid() {}; + + virtual LayerAndroid* copy() const { return new FixedBackgroundLayerAndroid(*this); } + + virtual bool isFixedBackground() const { return true; } + + virtual SubclassType subclassType() { return LayerAndroid::FixedBackgroundLayer; } +}; + +} + +#endif // USE(ACCELERATED_COMPOSITING) + +#endif // FixedBackgroundLayerAndroid_h diff --git a/Source/WebCore/platform/graphics/android/layers/FixedPositioning.h b/Source/WebCore/platform/graphics/android/layers/FixedPositioning.h index 973113b..2fa7ae9 100644 --- a/Source/WebCore/platform/graphics/android/layers/FixedPositioning.h +++ b/Source/WebCore/platform/graphics/android/layers/FixedPositioning.h @@ -50,6 +50,15 @@ struct SkLength { return false; return true; } + void setFixedValue(float v) + { + type = Fixed; + value = v; + } + void setAuto() + { + type = Auto; + } float calcFloatValue(float max) const { switch (type) { diff --git a/Source/WebCore/platform/graphics/android/layers/LayerAndroid.cpp b/Source/WebCore/platform/graphics/android/layers/LayerAndroid.cpp index a02759d..69c597f 100644 --- a/Source/WebCore/platform/graphics/android/layers/LayerAndroid.cpp +++ b/Source/WebCore/platform/graphics/android/layers/LayerAndroid.cpp @@ -578,9 +578,9 @@ void LayerAndroid::showLayer(int indent) IntRect visible = visibleArea(); IntRect clip(m_clippingRect.x(), m_clippingRect.y(), m_clippingRect.width(), m_clippingRect.height()); - ALOGD("%s %s (%d) [%d:0x%x] - %s %s - area (%d, %d, %d, %d) - visible (%d, %d, %d, %d) " + ALOGD("%s %s %s (%d) [%d:0x%x] - %s %s - area (%d, %d, %d, %d) - visible (%d, %d, %d, %d) " "clip (%d, %d, %d, %d) %s %s m_content(%x), pic w: %d h: %d", - spaces, subclassName().latin1().data(), subclassType(), uniqueId(), m_owningLayer, + spaces, m_haveClip ? "CLIP LAYER" : "", subclassName().ascii().data(), subclassType(), uniqueId(), m_owningLayer, needsTexture() ? "needs a texture" : "no texture", m_imageCRC ? "has an image" : "no image", tr.x(), tr.y(), tr.width(), tr.height(), @@ -748,6 +748,8 @@ IntRect LayerAndroid::unclippedArea() IntRect LayerAndroid::visibleArea() { IntRect area = unclippedArea(); + if (subclassType() == LayerAndroid::FixedBackgroundBaseLayer) + return area; // First, we get the transformed area of the layer, // in document coordinates IntRect rect = m_drawTransform.mapRect(area); diff --git a/Source/WebCore/platform/graphics/android/layers/LayerAndroid.h b/Source/WebCore/platform/graphics/android/layers/LayerAndroid.h index 9a803a9..4f94698 100644 --- a/Source/WebCore/platform/graphics/android/layers/LayerAndroid.h +++ b/Source/WebCore/platform/graphics/android/layers/LayerAndroid.h @@ -94,6 +94,9 @@ public: typedef enum { UndefinedLayer, WebCoreLayer, UILayer } LayerType; typedef enum { StandardLayer, ScrollableLayer, IFrameLayer, IFrameContentLayer, + FixedBackgroundLayer, + FixedBackgroundBaseLayer, + ForegroundBaseLayer, CanvasLayer, BaseLayer } SubclassType; typedef enum { InvalidateNone = 0, InvalidateLayers } InvalidateFlags; @@ -108,6 +111,12 @@ public: return "IFrameLayer"; case LayerAndroid::IFrameContentLayer: return "IFrameContentLayer"; + case LayerAndroid::FixedBackgroundLayer: + return "FixedBackgroundLayer"; + case LayerAndroid::FixedBackgroundBaseLayer: + return "FixedBackgroundBaseLayer"; + case LayerAndroid::ForegroundBaseLayer: + return "ForegroundBaseLayer"; case LayerAndroid::CanvasLayer: return "CanvasLayer"; case LayerAndroid::BaseLayer: @@ -241,6 +250,7 @@ public: virtual bool isVideo() const { return false; } virtual bool isIFrame() const { return false; } virtual bool isIFrameContent() const { return false; } + virtual bool isFixedBackground() const { return false; } bool isPositionFixed() const { return m_fixedPosition; } void setAbsolutePosition(bool isAbsolute) { m_isPositionAbsolute = isAbsolute; } diff --git a/Source/WebCore/platform/graphics/android/rendering/Surface.cpp b/Source/WebCore/platform/graphics/android/rendering/Surface.cpp index a9ebd1e..563b0f5 100644 --- a/Source/WebCore/platform/graphics/android/rendering/Surface.cpp +++ b/Source/WebCore/platform/graphics/android/rendering/Surface.cpp @@ -38,6 +38,8 @@ #include "SurfaceBacking.h" #include "TilesManager.h" +#include + // Surfaces with an area larger than 2048*2048 should never be unclipped #define MAX_UNCLIPPED_AREA 4194304 @@ -199,8 +201,13 @@ void Surface::prepareGL(bool layerTilesDisabled) IntRect prepareArea = computePrepareArea(); IntRect fullArea = unclippedArea(); - ALOGV("prepareGL on Surf %p with SurfBack %p, %d layers", - this, m_surfaceBacking, m_layers.size()); + ALOGV("prepareGL on Surf %p with SurfBack %p, %d layers, first layer %s (%d) " + "prepareArea(%d, %d - %d x %d) fullArea(%d, %d - %d x %d)", + this, m_surfaceBacking, m_layers.size(), + getFirstLayer()->subclassName().ascii().data(), + getFirstLayer()->uniqueId(), + prepareArea.x(), prepareArea.y(), prepareArea.width(), prepareArea.height(), + fullArea.x(), fullArea.y(), fullArea.width(), fullArea.height()); m_surfaceBacking->prepareGL(getFirstLayer()->state(), allowZoom, prepareArea, fullArea, @@ -214,7 +221,11 @@ bool Surface::drawGL(bool layerTilesDisabled) if (!getFirstLayer()->visible()) return false; - if (!isBase()) { + bool isBaseLayer = isBase() + || getFirstLayer()->subclassType() == LayerAndroid::FixedBackgroundBaseLayer + || getFirstLayer()->subclassType() == LayerAndroid::ForegroundBaseLayer; + + if (!isBaseLayer) { // TODO: why are clipping regions wrong for base layer? FloatRect drawClip = getFirstLayer()->drawClip(); FloatRect clippingRect = TilesManager::instance()->shader()->rectInScreenCoord(drawClip); @@ -223,7 +234,8 @@ bool Surface::drawGL(bool layerTilesDisabled) bool askRedraw = false; if (m_surfaceBacking && !tilesDisabled) { - ALOGV("drawGL on Surf %p with SurfBack %p", this, m_surfaceBacking); + ALOGV("drawGL on Surf %p with SurfBack %p, first layer %s (%d)", this, m_surfaceBacking, + getFirstLayer()->subclassName().ascii().data(), getFirstLayer()->uniqueId()); // TODO: why this visibleArea is different from visibleRect at zooming for base? IntRect drawArea = visibleArea(); diff --git a/Source/WebCore/platform/graphics/android/utils/ClassTracker.cpp b/Source/WebCore/platform/graphics/android/utils/ClassTracker.cpp index 98e33d9..a73ece8 100644 --- a/Source/WebCore/platform/graphics/android/utils/ClassTracker.cpp +++ b/Source/WebCore/platform/graphics/android/utils/ClassTracker.cpp @@ -87,7 +87,7 @@ void ClassTracker::show() ALOGD("*** Tracking %d classes ***", m_classes.size()); for (HashMap::iterator iter = m_classes.begin(); iter != m_classes.end(); ++iter) { ALOGD("class %s has %d instances", - iter->first.latin1().data(), iter->second); + iter->first.ascii().data(), iter->second); } ALOGD("*** %d Layers ***", m_layers.size()); int nbTextures = 0; diff --git a/Source/WebCore/rendering/PaintPhase.h b/Source/WebCore/rendering/PaintPhase.h index 396131f..7dc205d 100644 --- a/Source/WebCore/rendering/PaintPhase.h +++ b/Source/WebCore/rendering/PaintPhase.h @@ -39,6 +39,10 @@ namespace WebCore { enum PaintPhase { PaintPhaseBlockBackground, +#if PLATFORM(ANDROID) + // Used for fixed background support in layers + PaintPhaseBlockBackgroundDecorations, +#endif PaintPhaseChildBlockBackground, PaintPhaseChildBlockBackgrounds, PaintPhaseFloat, diff --git a/Source/WebCore/rendering/RenderBlock.cpp b/Source/WebCore/rendering/RenderBlock.cpp index a3bd41a..49dd169 100644 --- a/Source/WebCore/rendering/RenderBlock.cpp +++ b/Source/WebCore/rendering/RenderBlock.cpp @@ -2499,7 +2499,11 @@ void RenderBlock::paintObject(PaintInfo& paintInfo, int tx, int ty) PaintPhase paintPhase = paintInfo.phase; // 1. paint background, borders etc - if ((paintPhase == PaintPhaseBlockBackground || paintPhase == PaintPhaseChildBlockBackground) && style()->visibility() == VISIBLE) { + if ((paintPhase == PaintPhaseBlockBackground || paintPhase == PaintPhaseChildBlockBackground +#if PLATFORM(ANDROID) + || paintPhase == PaintPhaseBlockBackgroundDecorations +#endif + ) && style()->visibility() == VISIBLE) { if (hasBoxDecorations()) paintBoxDecorations(paintInfo, tx, ty); if (hasColumns()) diff --git a/Source/WebCore/rendering/RenderBox.cpp b/Source/WebCore/rendering/RenderBox.cpp index 9c40d5b..bc7d03a 100644 --- a/Source/WebCore/rendering/RenderBox.cpp +++ b/Source/WebCore/rendering/RenderBox.cpp @@ -843,6 +843,11 @@ void RenderBox::paintBoxDecorationsWithSize(PaintInfo& paintInfo, int tx, int ty else if (!isBody() || document()->documentElement()->renderer()->hasBackground()) { // The only paints its background if the root element has defined a background // independent of the body. +#if PLATFORM(ANDROID) + // If we only want to draw the decorations, don't draw + // the background + if (paintInfo.phase != PaintPhaseBlockBackgroundDecorations) +#endif paintFillLayers(paintInfo, style()->visitedDependentColor(CSSPropertyBackgroundColor), style()->backgroundLayers(), tx, ty, width, height); } if (style()->hasAppearance()) diff --git a/Source/WebCore/rendering/RenderBoxModelObject.h b/Source/WebCore/rendering/RenderBoxModelObject.h index d2f5972..ac4152f 100644 --- a/Source/WebCore/rendering/RenderBoxModelObject.h +++ b/Source/WebCore/rendering/RenderBoxModelObject.h @@ -62,7 +62,11 @@ public: bool hasSelfPaintingLayer() const; RenderLayer* layer() const { return m_layer; } +#if PLATFORM(ANDROID) + virtual bool requiresLayer() const { return isRoot() || isPositioned() || isRelPositioned() || isTransparent() || hasOverflowClip() || hasTransform() || hasMask() || hasReflection() || style()->specifiesColumns() || style()->hasFixedBackgroundImage(); } +#else virtual bool requiresLayer() const { return isRoot() || isPositioned() || isRelPositioned() || isTransparent() || hasOverflowClip() || hasTransform() || hasMask() || hasReflection() || style()->specifiesColumns(); } +#endif // This will work on inlines to return the bounding box of all of the lines' border boxes. virtual IntRect borderBoundingBox() const = 0; diff --git a/Source/WebCore/rendering/RenderLayerBacking.cpp b/Source/WebCore/rendering/RenderLayerBacking.cpp index 6f56eca..c0c562a 100644 --- a/Source/WebCore/rendering/RenderLayerBacking.cpp +++ b/Source/WebCore/rendering/RenderLayerBacking.cpp @@ -1114,12 +1114,24 @@ void RenderLayerBacking::paintIntoLayer(RenderLayer* rootLayer, GraphicsContext* bool shouldPaint = (m_owningLayer->hasVisibleContent() || m_owningLayer->hasVisibleDescendant()) && m_owningLayer->isSelfPaintingLayer(); +#if PLATFORM(ANDROID) + if (shouldPaint && ((paintingPhase & GraphicsLayerPaintBackground) + || (paintingPhase & GraphicsLayerPaintBackgroundDecorations))) { +#else if (shouldPaint && (paintingPhase & GraphicsLayerPaintBackground)) { +#endif // Paint our background first, before painting any child layers. // Establish the clip used to paint our background. setClip(context, paintDirtyRect, damageRect); +#if PLATFORM(ANDROID) + PaintPhase phase = PaintPhaseBlockBackground; + if (paintingPhase & GraphicsLayerPaintBackgroundDecorations) + phase = PaintPhaseBlockBackgroundDecorations; + PaintInfo info(context, damageRect, phase, false, paintingRootForRenderer, 0); +#else PaintInfo info(context, damageRect, PaintPhaseBlockBackground, false, paintingRootForRenderer, 0); +#endif renderer()->paint(info, tx, ty); // Our scrollbar widgets paint exactly when we tell them to, so that they work properly with diff --git a/Source/WebCore/rendering/RenderLayerCompositor.cpp b/Source/WebCore/rendering/RenderLayerCompositor.cpp index 1871b57..6b669e8 100644 --- a/Source/WebCore/rendering/RenderLayerCompositor.cpp +++ b/Source/WebCore/rendering/RenderLayerCompositor.cpp @@ -1432,6 +1432,9 @@ bool RenderLayerCompositor::requiresCompositingForAndroidLayers(const RenderLaye if (layer->renderer()->isCanvas()) return true; + if (layer->renderer()->style()->hasFixedBackgroundImage()) + return true; + return false; } #endif diff --git a/Source/WebKit/android/jni/WebViewCore.cpp b/Source/WebKit/android/jni/WebViewCore.cpp index 7cc427f..726a225 100644 --- a/Source/WebKit/android/jni/WebViewCore.cpp +++ b/Source/WebKit/android/jni/WebViewCore.cpp @@ -88,6 +88,7 @@ #include "NodeList.h" #include "Page.h" #include "PageGroup.h" +#include "PictureLayerContent.h" #include "PictureSetLayerContent.h" #include "PlatformKeyboardEvent.h" #include "PlatformString.h" @@ -872,37 +873,69 @@ void WebViewCore::notifyAnimationStarted() BaseLayerAndroid* WebViewCore::createBaseLayer(SkRegion* region) { - PictureSetLayerContent* content = new PictureSetLayerContent(m_content); - BaseLayerAndroid* base = new BaseLayerAndroid(content); - SkSafeUnref(content); - - m_skipContentDraw = true; - bool layoutSucceeded = layoutIfNeededRecursive(m_mainFrame); - m_skipContentDraw = false; - // Layout only fails if called during a layout. - ALOG_ASSERT(layoutSucceeded, "Can never be called recursively"); - -#if USE(ACCELERATED_COMPOSITING) // We set the background color Color background = Color::white; + + bool bodyHasFixedBackgroundImage = false; + bool bodyHasCSSBackground = false; + if (m_mainFrame && m_mainFrame->document() && m_mainFrame->document()->body()) { - bool hasCSSBackground = false; Document* document = m_mainFrame->document(); RefPtr style = document->styleForElementIgnoringPendingStylesheets(document->body()); if (style->hasBackground()) { background = style->visitedDependentColor(CSSPropertyBackgroundColor); - hasCSSBackground = true; + bodyHasCSSBackground = true; } - WebCore::FrameView* view = m_mainFrame->view(); if (view) { Color viewBackground = view->baseBackgroundColor(); - background = hasCSSBackground ? viewBackground.blend(background) : viewBackground; + background = bodyHasCSSBackground ? viewBackground.blend(background) : viewBackground; } + bodyHasFixedBackgroundImage = style->hasFixedBackgroundImage(); + } + + PictureSetLayerContent* content = new PictureSetLayerContent(m_content); + + BaseLayerAndroid* realBase = 0; + LayerAndroid* base = 0; + + //If we have a fixed background image on the body element, the fixed image + // will be contained in the PictureSet (the content object), and the foreground + //of the body element will be moved to a layer. + //In that case, let's change the hierarchy to obtain: + // + //BaseLayerAndroid + // \- FixedBackgroundBaseLayerAndroid (fixed positioning) + // \- ForegroundBaseLayerAndroid + // \- root layer (webkit composited tree) + + if (bodyHasFixedBackgroundImage) { + base = new ForegroundBaseLayerAndroid(0); + base->setSize(content->width(), content->height()); + FixedBackgroundBaseLayerAndroid* baseBackground = + new FixedBackgroundBaseLayerAndroid(content); + + // TODO -- check we don't have the assumption that baselayer has only one child + realBase = new BaseLayerAndroid(0); + realBase->setSize(content->width(), content->height()); + realBase->addChild(baseBackground); + realBase->addChild(base); + } else { + realBase = new BaseLayerAndroid(content); + base = realBase; } - base->setBackgroundColor(background); + + realBase->setBackgroundColor(background); + + SkSafeUnref(content); + + m_skipContentDraw = true; + bool layoutSucceeded = layoutIfNeededRecursive(m_mainFrame); + m_skipContentDraw = false; + // Layout only fails if called during a layout. + ALOG_ASSERT(layoutSucceeded, "Can never be called recursively"); // We update the layers ChromeClientAndroid* chromeC = static_cast(m_mainFrame->page()->chrome()->client()); @@ -913,9 +946,8 @@ BaseLayerAndroid* WebViewCore::createBaseLayer(SkRegion* region) copyLayer->unref(); root->contentLayer()->clearDirtyRegion(); } -#endif - return base; + return realBase; } BaseLayerAndroid* WebViewCore::recordContent(SkRegion* region, SkIPoint* point) diff --git a/Source/WebKit/android/nav/WebView.cpp b/Source/WebKit/android/nav/WebView.cpp index fbd0d94..a852dc7 100644 --- a/Source/WebKit/android/nav/WebView.cpp +++ b/Source/WebKit/android/nav/WebView.cpp @@ -305,7 +305,7 @@ PictureSet* draw(SkCanvas* canvas, SkColor bgColor, DrawExtras extras, bool spli LayerContent* content = m_baseLayer->content(); int sc = canvas->save(SkCanvas::kClip_SaveFlag); canvas->clipRect(SkRect::MakeLTRB(0, 0, content->width(), - content->height()), SkRegion::kDifference_Op); + content->height()), SkRegion::kDifference_Op); Color c = m_baseLayer->getBackgroundColor(); canvas->drawColor(SkColorSetARGBInline(c.alpha(), c.red(), c.green(), c.blue())); canvas->restoreToCount(sc); -- cgit v1.1