diff options
Diffstat (limited to 'Source')
28 files changed, 1254 insertions, 493 deletions
diff --git a/Source/WebCore/Android.mk b/Source/WebCore/Android.mk index bae08c1..4884e5b 100644 --- a/Source/WebCore/Android.mk +++ b/Source/WebCore/Android.mk @@ -640,6 +640,8 @@ LOCAL_SRC_FILES := $(LOCAL_SRC_FILES) \ platform/graphics/android/BaseTileTexture.cpp \ platform/graphics/android/BitmapAllocatorAndroid.cpp \ platform/graphics/android/ClassTracker.cpp \ + platform/graphics/android/DumpLayer.cpp \ + platform/graphics/android/FixedPositioning.cpp \ platform/graphics/android/FontAndroid.cpp \ platform/graphics/android/FontCacheAndroid.cpp \ platform/graphics/android/FontCustomPlatformData.cpp \ @@ -654,6 +656,8 @@ LOCAL_SRC_FILES := $(LOCAL_SRC_FILES) \ platform/graphics/android/GradientAndroid.cpp \ platform/graphics/android/GraphicsContextAndroid.cpp \ platform/graphics/android/GraphicsLayerAndroid.cpp \ + platform/graphics/android/IFrameContentLayerAndroid.cpp \ + platform/graphics/android/IFrameLayerAndroid.cpp \ platform/graphics/android/ImageAndroid.cpp \ platform/graphics/android/ImageBufferAndroid.cpp \ platform/graphics/android/ImageSourceAndroid.cpp \ diff --git a/Source/WebCore/platform/graphics/android/BaseLayerAndroid.cpp b/Source/WebCore/platform/graphics/android/BaseLayerAndroid.cpp index fee94d3..3cf863e 100644 --- a/Source/WebCore/platform/graphics/android/BaseLayerAndroid.cpp +++ b/Source/WebCore/platform/graphics/android/BaseLayerAndroid.cpp @@ -292,7 +292,7 @@ void BaseLayerAndroid::updateLayerPositions(const SkRect& visibleRect) if (!compositedRoot) return; TransformationMatrix ident; - compositedRoot->updateFixedLayersPositions(visibleRect); + compositedRoot->updateLayerPositions(visibleRect); FloatRect clip(0, 0, content()->width(), content()->height()); compositedRoot->updateGLPositionsAndScale( ident, clip, 1, m_state->zoomManager()->layersScale()); diff --git a/Source/WebCore/platform/graphics/android/DumpLayer.cpp b/Source/WebCore/platform/graphics/android/DumpLayer.cpp new file mode 100644 index 0000000..5551965 --- /dev/null +++ b/Source/WebCore/platform/graphics/android/DumpLayer.cpp @@ -0,0 +1,83 @@ +#include "config.h" +#include "DumpLayer.h" + +#if USE(ACCELERATED_COMPOSITING) + +namespace WebCore { + +void lwrite(FILE* file, const char* str) +{ + fwrite(str, sizeof(char), strlen(str), file); +} + +void writeIndent(FILE* file, int indentLevel) +{ + if (indentLevel) + fprintf(file, "%*s", indentLevel*2, " "); +} + +void writeln(FILE* file, int indentLevel, const char* str) +{ + writeIndent(file, indentLevel); + lwrite(file, str); + lwrite(file, "\n"); +} + +void writeIntVal(FILE* file, int indentLevel, const char* str, int value) +{ + writeIndent(file, indentLevel); + fprintf(file, "%s = %d;\n", str, value); +} + +void writeHexVal(FILE* file, int indentLevel, const char* str, int value) +{ + writeIndent(file, indentLevel); + fprintf(file, "%s = %x;\n", str, value); +} + +void writeFloatVal(FILE* file, int indentLevel, const char* str, float value) +{ + writeIndent(file, indentLevel); + fprintf(file, "%s = %.3f;\n", str, value); +} + +void writePoint(FILE* file, int indentLevel, const char* str, SkPoint point) +{ + writeIndent(file, indentLevel); + fprintf(file, "%s = { x = %.3f; y = %.3f; };\n", str, point.fX, point.fY); +} + +void writeIntPoint(FILE* file, int indentLevel, const char* str, IntPoint point) +{ + writeIndent(file, indentLevel); + fprintf(file, "%s = { x = %d; y = %d; };\n", str, point.x(), point.y()); +} + +void writeSize(FILE* file, int indentLevel, const char* str, SkSize size) +{ + writeIndent(file, indentLevel); + fprintf(file, "%s = { w = %.3f; h = %.3f; };\n", str, size.width(), size.height()); +} + +void writeRect(FILE* file, int indentLevel, const char* str, SkRect rect) +{ + writeIndent(file, indentLevel); + fprintf(file, "%s = { x = %.3f; y = %.3f; w = %.3f; h = %.3f; };\n", + str, rect.fLeft, rect.fTop, rect.width(), rect.height()); +} + +void writeMatrix(FILE* file, int indentLevel, const char* str, const TransformationMatrix& matrix) +{ + writeIndent(file, indentLevel); + fprintf(file, "%s = { (%.2f,%.2f,%.2f,%.2f),(%.2f,%.2f,%.2f,%.2f)," + "(%.2f,%.2f,%.2f,%.2f),(%.2f,%.2f,%.2f,%.2f) };\n", + str, + 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()); +} + +} // namespace WebCore + +#endif // USE(ACCELERATED_COMPOSITING) diff --git a/Source/WebCore/platform/graphics/android/DumpLayer.h b/Source/WebCore/platform/graphics/android/DumpLayer.h new file mode 100644 index 0000000..5b30952 --- /dev/null +++ b/Source/WebCore/platform/graphics/android/DumpLayer.h @@ -0,0 +1,67 @@ +/* + * 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 DumpLayer_h +#define DumpLayer_h + +#include "IntPoint.h" +#include "SkPoint.h" +#include "SkRect.h" +#include "SkSize.h" +#include "TransformationMatrix.h" + +// Debug tools : dump the layers tree in a file. +// The format is simple: +// properties have the form: key = value; +// all statements are finished with a semi-colon. +// value can be: +// - int +// - float +// - array of elements +// - composed type +// a composed type enclose properties in { and } +// an array enclose composed types in { }, separated with a comma. +// exemple: +// { +// x = 3; +// y = 4; +// value = { +// x = 3; +// y = 4; +// }; +// anarray = [ +// { x = 3; }, +// { y = 4; } +// ]; +// } + +namespace WebCore { + +void lwrite(FILE* file, const char* str); +void writeIndent(FILE* file, int indentLevel); +void writeln(FILE* file, int indentLevel, const char* str); +void writeIntVal(FILE* file, int indentLevel, const char* str, int value); +void writeHexVal(FILE* file, int indentLevel, const char* str, int value); +void writeFloatVal(FILE* file, int indentLevel, const char* str, float value); +void writePoint(FILE* file, int indentLevel, const char* str, SkPoint point); +void writeIntPoint(FILE* file, int indentLevel, const char* str, IntPoint point); +void writeSize(FILE* file, int indentLevel, const char* str, SkSize size); +void writeRect(FILE* file, int indentLevel, const char* str, SkRect rect); +void writeMatrix(FILE* file, int indentLevel, const char* str, const TransformationMatrix& matrix); + +} + +#endif // DumpLayer_h diff --git a/Source/WebCore/platform/graphics/android/FixedPositioning.cpp b/Source/WebCore/platform/graphics/android/FixedPositioning.cpp new file mode 100644 index 0000000..140411a --- /dev/null +++ b/Source/WebCore/platform/graphics/android/FixedPositioning.cpp @@ -0,0 +1,106 @@ +#include "config.h" +#include "FixedPositioning.h" + +#include "DumpLayer.h" +#include "IFrameLayerAndroid.h" +#include "TilesManager.h" + +#if USE(ACCELERATED_COMPOSITING) + +#include <cutils/log.h> +#include <wtf/CurrentTime.h> +#include <wtf/text/CString.h> +#define XLOGC(...) android_printLog(ANDROID_LOG_DEBUG, "FixedPositioning", __VA_ARGS__) + +namespace WebCore { + +// Called when copying the layer tree to the UI +FixedPositioning::FixedPositioning(LayerAndroid* layer, const FixedPositioning& position) + : m_layer(layer) + , m_fixedLeft(position.m_fixedLeft) + , m_fixedTop(position.m_fixedTop) + , m_fixedRight(position.m_fixedRight) + , m_fixedBottom(position.m_fixedBottom) + , m_fixedMarginLeft(position.m_fixedMarginLeft) + , m_fixedMarginTop(position.m_fixedMarginTop) + , m_fixedMarginRight(position.m_fixedMarginRight) + , m_fixedMarginBottom(position.m_fixedMarginBottom) + , m_fixedRect(position.m_fixedRect) + , m_renderLayerPos(position.m_renderLayerPos) +{ +} + +// Executed on the UI +IFrameLayerAndroid* FixedPositioning::updatePosition(SkRect viewport, + IFrameLayerAndroid* parentIframeLayer) +{ + // So if this is a fixed layer inside a iframe, use the iframe offset + // and the iframe's size as the viewport and pass to the children + if (parentIframeLayer) { + viewport = SkRect::MakeXYWH(parentIframeLayer->iframeOffset().x(), + parentIframeLayer->iframeOffset().y(), + parentIframeLayer->getSize().width(), + parentIframeLayer->getSize().height()); + } + float w = viewport.width(); + float h = viewport.height(); + float dx = viewport.fLeft; + float dy = viewport.fTop; + float x = dx; + float y = dy; + + // It turns out that when it is 'auto', we should use the webkit value + // from the original render layer's X,Y, that will take care of alignment + // with the parent's layer and fix Margin etc. + if (!(m_fixedLeft.defined() || m_fixedRight.defined())) + x += m_renderLayerPos.x(); + else if (m_fixedLeft.defined() || !m_fixedRight.defined()) + x += m_fixedMarginLeft.calcFloatValue(w) + m_fixedLeft.calcFloatValue(w) - m_fixedRect.fLeft; + else + x += w - m_fixedMarginRight.calcFloatValue(w) - m_fixedRight.calcFloatValue(w) - m_fixedRect.fRight; + + if (!(m_fixedTop.defined() || m_fixedBottom.defined())) + y += m_renderLayerPos.y(); + else if (m_fixedTop.defined() || !m_fixedBottom.defined()) + y += m_fixedMarginTop.calcFloatValue(h) + m_fixedTop.calcFloatValue(h) - m_fixedRect.fTop; + else + y += h - m_fixedMarginBottom.calcFloatValue(h) - m_fixedBottom.calcFloatValue(h) - m_fixedRect.fBottom; + + m_layer->setPosition(x, y); + + return parentIframeLayer; +} + +void FixedPositioning::contentDraw(SkCanvas* canvas, Layer::PaintStyle style) +{ + if (TilesManager::instance()->getShowVisualIndicator()) { + SkPaint paint; + paint.setARGB(80, 255, 0, 0); + canvas->drawRect(m_fixedRect, paint); + } +} + +void writeLength(FILE* file, int indentLevel, const char* str, SkLength length) +{ + if (!length.defined()) + return; + writeIndent(file, indentLevel); + fprintf(file, "%s = { type = %d; value = %.2f; };\n", str, length.type, length.value); +} + +void FixedPositioning::dumpLayer(FILE* file, int indentLevel) const +{ + writeLength(file, indentLevel + 1, "fixedLeft", m_fixedLeft); + writeLength(file, indentLevel + 1, "fixedTop", m_fixedTop); + writeLength(file, indentLevel + 1, "fixedRight", m_fixedRight); + writeLength(file, indentLevel + 1, "fixedBottom", m_fixedBottom); + writeLength(file, indentLevel + 1, "fixedMarginLeft", m_fixedMarginLeft); + writeLength(file, indentLevel + 1, "fixedMarginTop", m_fixedMarginTop); + writeLength(file, indentLevel + 1, "fixedMarginRight", m_fixedMarginRight); + writeLength(file, indentLevel + 1, "fixedMarginBottom", m_fixedMarginBottom); + writeRect(file, indentLevel + 1, "fixedRect", m_fixedRect); +} + +} // namespace WebCore + +#endif // USE(ACCELERATED_COMPOSITING) diff --git a/Source/WebCore/platform/graphics/android/FixedPositioning.h b/Source/WebCore/platform/graphics/android/FixedPositioning.h new file mode 100644 index 0000000..973113b --- /dev/null +++ b/Source/WebCore/platform/graphics/android/FixedPositioning.h @@ -0,0 +1,128 @@ +/* + * Copyright 2012, The Android Open Source Project + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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 HOLDERS ``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 OWNER OR + * 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 FixedPositioning_h +#define FixedPositioning_h + +#if USE(ACCELERATED_COMPOSITING) + +#include "LayerAndroid.h" + +namespace WebCore { + +class IFrameLayerAndroid; + +struct SkLength { + enum SkLengthType { Undefined, Auto, Relative, + Percent, Fixed, Static, Intrinsic, MinIntrinsic }; + SkLengthType type; + SkScalar value; + SkLength() + { + type = Undefined; + value = 0; + } + bool defined() const + { + if (type == Undefined) + return false; + return true; + } + float calcFloatValue(float max) const + { + switch (type) { + case Percent: + return (max * value) / 100.0f; + case Fixed: + return value; + default: + return value; + } + } +}; + +class FixedPositioning { + +public: + FixedPositioning(LayerAndroid* layer = 0) : m_layer(layer) {} + FixedPositioning(LayerAndroid* layer, const FixedPositioning& position); + virtual ~FixedPositioning() {}; + + void setFixedPosition(SkLength left, // CSS left property + SkLength top, // CSS top property + SkLength right, // CSS right property + SkLength bottom, // CSS bottom property + SkLength marginLeft, // CSS margin-left property + SkLength marginTop, // CSS margin-top property + SkLength marginRight, // CSS margin-right property + SkLength marginBottom, // CSS margin-bottom property + const IntPoint& renderLayerPos, // For undefined fixed position + SkRect viewRect) { // view rect, can be smaller than the layer's + m_fixedLeft = left; + m_fixedTop = top; + m_fixedRight = right; + m_fixedBottom = bottom; + m_fixedMarginLeft = marginLeft; + m_fixedMarginTop = marginTop; + m_fixedMarginRight = marginRight; + m_fixedMarginBottom = marginBottom; + m_fixedRect = viewRect; + m_renderLayerPos = renderLayerPos; + } + + IFrameLayerAndroid* updatePosition(SkRect viewPort, + IFrameLayerAndroid* parentIframeLayer); + + void contentDraw(SkCanvas* canvas, Layer::PaintStyle style); + + void dumpLayer(FILE*, int indentLevel) const; + + // ViewStateSerializer friends + friend void android::serializeLayer(LayerAndroid* layer, SkWStream* stream); + friend LayerAndroid* android::deserializeLayer(int version, SkStream* stream); + +private: + LayerAndroid* m_layer; + + SkLength m_fixedLeft; + SkLength m_fixedTop; + SkLength m_fixedRight; + SkLength m_fixedBottom; + SkLength m_fixedMarginLeft; + SkLength m_fixedMarginTop; + SkLength m_fixedMarginRight; + SkLength m_fixedMarginBottom; + SkRect m_fixedRect; + + // When fixed element is undefined or auto, the render layer's position + // is needed for offset computation + IntPoint m_renderLayerPos; +}; + +} + +#endif // USE(ACCELERATED_COMPOSITING) + +#endif // FixedPositioning_h diff --git a/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp b/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp index c50f6a6..1ac90e9 100644 --- a/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp +++ b/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp @@ -22,7 +22,10 @@ #include "AndroidAnimation.h" #include "Animation.h" #include "FloatRect.h" +#include "FixedPositioning.h" #include "GraphicsContext.h" +#include "IFrameContentLayerAndroid.h" +#include "IFrameLayerAndroid.h" #include "Image.h" #include "ImagesManager.h" #include "Layer.h" @@ -232,8 +235,12 @@ void GraphicsLayerAndroid::updateFixedPosition() return; // We will need the Iframe flag in the LayerAndroid tree for fixed position - if (view->isRenderIFrame()) - m_contentLayer->setIsIframe(true); + if (view->isRenderIFrame() && !m_contentLayer->isIFrame()) { + LayerAndroid* layer = new IFrameLayerAndroid(*m_contentLayer); + m_contentLayer->unref(); + m_contentLayer = layer; + } + // If we are a fixed position layer, just set it if (view->isPositioned() && view->style()->position() == FixedPosition) { // We need to get the passed CSS properties for the element @@ -264,12 +271,20 @@ void GraphicsLayerAndroid::updateFixedPosition() SkRect viewRect; viewRect.set(paintingOffsetX, paintingOffsetY, paintingOffsetX + w, paintingOffsetY + h); IntPoint renderLayerPos(renderLayer->x(), renderLayer->y()); - m_contentLayer->setFixedPosition(left, top, right, bottom, - marginLeft, marginTop, - marginRight, marginBottom, - renderLayerPos, - viewRect); - } + + FixedPositioning* fixedPosition = m_contentLayer->fixedPosition(); + if (!fixedPosition) { + fixedPosition = new FixedPositioning(); + m_contentLayer->setFixedPosition(fixedPosition); + } + + fixedPosition->setFixedPosition(left, top, right, bottom, + marginLeft, marginTop, + marginRight, marginBottom, + renderLayerPos, + viewRect); + } else if (m_contentLayer->isFixed()) + m_contentLayer->setFixedPosition(0); } void GraphicsLayerAndroid::setPosition(const FloatPoint& point) @@ -508,6 +523,8 @@ void GraphicsLayerAndroid::updateScrollingLayers() if (layerNeedsOverflow) { ASSERT(!m_foregroundLayer && !m_foregroundClipLayer); m_foregroundLayer = new ScrollableLayerAndroid(layer); + + // TODO: can clip layer be set to not intrinsically composited? m_foregroundClipLayer = new LayerAndroid(layer); m_foregroundClipLayer->setMasksToBounds(true); m_foregroundClipLayer->addChild(m_foregroundLayer); @@ -518,8 +535,7 @@ void GraphicsLayerAndroid::updateScrollingLayers() // No need to copy the children as they will be removed and synced. m_contentLayer->removeChildren(); // Replace the content layer with a scrollable layer. - LayerAndroid* layer = new ScrollableLayerAndroid(*m_contentLayer); - layer->setIsIframe(true); + LayerAndroid* layer = new IFrameContentLayerAndroid(*m_contentLayer); m_contentLayer->unref(); m_contentLayer = layer; if (m_parent) { @@ -563,10 +579,10 @@ void GraphicsLayerAndroid::updateScrollOffset() { if (m_foregroundLayer) { IntSize scroll = layer->scrolledContentOffset(); m_foregroundLayer->setScrollOffset(IntPoint(scroll.width(), scroll.height())); - } else if (m_contentLayer->contentIsScrollable()) { + } else if (m_contentLayer->isIFrameContent()) { IntPoint p(layer->renderer()->frame()->view()->scrollX(), layer->renderer()->frame()->view()->scrollY()); - static_cast<ScrollableLayerAndroid*>(m_contentLayer)->setIFrameScrollOffset(p); + static_cast<IFrameContentLayerAndroid*>(m_contentLayer)->setIFrameScrollOffset(p); } askForSync(); } @@ -653,9 +669,9 @@ bool GraphicsLayerAndroid::repaint() m_contentLayer->checkForPictureOptimizations(); // Check for a scrollable iframe and report the scrolling // limits based on the view size. - if (m_contentLayer->contentIsScrollable()) { + if (m_contentLayer->isIFrameContent()) { FrameView* view = layer->renderer()->frame()->view(); - static_cast<ScrollableLayerAndroid*>(m_contentLayer)->setScrollLimits( + static_cast<IFrameContentLayerAndroid*>(m_contentLayer)->setScrollLimits( m_position.x(), m_position.y(), view->layoutWidth(), view->layoutHeight()); LOG("setScrollLimits(%.2f, %.2f, w: %d h: %d) layer %d, frame scroll position is %d, %d", m_position.x(), m_position.y(), view->layoutWidth(), view->layoutHeight(), @@ -1016,6 +1032,12 @@ void GraphicsLayerAndroid::gatherRootLayers(Vector<const RenderLayer*>& list) void GraphicsLayerAndroid::syncCompositingStateForThisLayerOnly() { + if (m_contentLayer) { + RenderLayer* renderLayer = renderLayerFromClient(m_client); + int intrinsicallyComposited = renderLayer ? renderLayer->intrinsicallyComposited() : true; + m_contentLayer->setIntrinsicallyComposited(intrinsicallyComposited); + } + updateScrollingLayers(); updateFixedPosition(); syncChildren(); diff --git a/Source/WebCore/platform/graphics/android/IFrameContentLayerAndroid.cpp b/Source/WebCore/platform/graphics/android/IFrameContentLayerAndroid.cpp new file mode 100644 index 0000000..70b5c67 --- /dev/null +++ b/Source/WebCore/platform/graphics/android/IFrameContentLayerAndroid.cpp @@ -0,0 +1,42 @@ +#include "config.h" +#include "IFrameContentLayerAndroid.h" + +#if USE(ACCELERATED_COMPOSITING) + +#include <cutils/log.h> +#include <wtf/CurrentTime.h> +#include <wtf/text/CString.h> +#define XLOGC(...) android_printLog(ANDROID_LOG_DEBUG, "IFrameContentLayerAndroid", __VA_ARGS__) + +namespace WebCore { + +bool IFrameContentLayerAndroid::scrollTo(int x, int y) +{ + IntRect scrollBounds; + getScrollBounds(&scrollBounds); + if (!scrollBounds.width() && !scrollBounds.height()) + return false; + SkScalar newX = SkScalarPin(x, scrollBounds.x(), scrollBounds.width()); + SkScalar newY = SkScalarPin(y, scrollBounds.y(), scrollBounds.height()); + // Check for no change. + if (newX == m_iframeScrollOffset.x() && newY == m_iframeScrollOffset.y()) + return false; + newX = newX - m_iframeScrollOffset.x(); + newY = newY - m_iframeScrollOffset.y(); + setScrollOffset(IntPoint(newX, newY)); + return true; +} + +void IFrameContentLayerAndroid::getScrollRect(SkIRect* out) const +{ + const SkPoint& pos = getPosition(); + out->fLeft = m_scrollLimits.fLeft - pos.fX + m_iframeScrollOffset.x(); + out->fTop = m_scrollLimits.fTop - pos.fY + m_iframeScrollOffset.y(); + + out->fRight = getSize().width() - m_scrollLimits.width(); + out->fBottom = getSize().height() - m_scrollLimits.height(); +} + +} // namespace WebCore + +#endif // USE(ACCELERATED_COMPOSITING) diff --git a/Source/WebCore/platform/graphics/android/IFrameContentLayerAndroid.h b/Source/WebCore/platform/graphics/android/IFrameContentLayerAndroid.h new file mode 100644 index 0000000..64b2d06 --- /dev/null +++ b/Source/WebCore/platform/graphics/android/IFrameContentLayerAndroid.h @@ -0,0 +1,78 @@ +/* + * Copyright 2012, The Android Open Source Project + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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 HOLDERS ``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 OWNER OR + * 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 IFrameContentLayerAndroid_h +#define IFrameContentLayerAndroid_h + +#if USE(ACCELERATED_COMPOSITING) + +#include "ScrollableLayerAndroid.h" + +namespace WebCore { + +class IFrameContentLayerAndroid : public ScrollableLayerAndroid { + +public: + IFrameContentLayerAndroid(RenderLayer* owner) + : ScrollableLayerAndroid(owner) {} + IFrameContentLayerAndroid(const ScrollableLayerAndroid& layer) + : ScrollableLayerAndroid(layer) {} + IFrameContentLayerAndroid(const LayerAndroid& layer) + : ScrollableLayerAndroid(layer) {} + IFrameContentLayerAndroid(const IFrameContentLayerAndroid& layer) + : ScrollableLayerAndroid(layer) + , m_iframeScrollOffset(layer.m_iframeScrollOffset) {} + + virtual ~IFrameContentLayerAndroid() {}; + + // isIFrame() return true for compatibility reason (see ViewStateSerializer) + virtual bool isIFrame() const { return true; } + virtual bool isIFrameContent() const { return true; } + + virtual LayerAndroid* copy() const { return new IFrameContentLayerAndroid(*this); } + virtual SubclassType subclassType() { return LayerAndroid::IFrameContentLayer; } + + // Scrolls to the given position in the layer. + // Returns whether or not any scrolling was required. + virtual bool scrollTo(int x, int y); + + // Fills the rect with the current scroll offset and the maximum scroll offset. + // fLeft = scrollX + // fTop = scrollY + // fRight = maxScrollX + // fBottom = maxScrollY + virtual void getScrollRect(SkIRect*) const; + + void setIFrameScrollOffset(IntPoint offset) { m_iframeScrollOffset = offset; } + +private: + IntPoint m_iframeScrollOffset; +}; + +} + +#endif // USE(ACCELERATED_COMPOSITING) + +#endif // IFrameContentLayerAndroid_h diff --git a/Source/WebCore/platform/graphics/android/IFrameLayerAndroid.cpp b/Source/WebCore/platform/graphics/android/IFrameLayerAndroid.cpp new file mode 100644 index 0000000..dfff91b --- /dev/null +++ b/Source/WebCore/platform/graphics/android/IFrameLayerAndroid.cpp @@ -0,0 +1,42 @@ +#include "config.h" +#include "IFrameLayerAndroid.h" + +#if USE(ACCELERATED_COMPOSITING) + +#include <cutils/log.h> +#include <wtf/CurrentTime.h> +#include <wtf/text/CString.h> + +#include "DumpLayer.h" + +#define XLOGC(...) android_printLog(ANDROID_LOG_DEBUG, "IFrameLayerAndroid", __VA_ARGS__) + +namespace WebCore { + +IFrameLayerAndroid* IFrameLayerAndroid::updatePosition(SkRect viewport, + IFrameLayerAndroid* parentIframeLayer) +{ + // As we are an iframe, accumulate the offset from the parent with + // the current position, and change the parent pointer. + + // If this is the top level, take the current position + SkPoint parentOffset; + parentOffset.set(0,0); + if (parentIframeLayer) + parentOffset = parentIframeLayer->getPosition(); + + SkPoint offset = parentOffset + getPosition(); + m_iframeOffset = IntPoint(offset.fX, offset.fY); + + return this; +} + +void IFrameLayerAndroid::dumpLayer(FILE* file, int indentLevel) const +{ + writeIntVal(file, indentLevel + 1, "m_isIframe", true); + writeIntPoint(file, indentLevel + 1, "m_iframeOffset", m_iframeOffset); +} + +} // namespace WebCore + +#endif // USE(ACCELERATED_COMPOSITING) diff --git a/Source/WebCore/platform/graphics/android/IFrameLayerAndroid.h b/Source/WebCore/platform/graphics/android/IFrameLayerAndroid.h new file mode 100644 index 0000000..e12188a --- /dev/null +++ b/Source/WebCore/platform/graphics/android/IFrameLayerAndroid.h @@ -0,0 +1,68 @@ +/* + * Copyright 2012, The Android Open Source Project + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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 HOLDERS ``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 OWNER OR + * 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 IFrameLayerAndroid_h +#define IFrameLayerAndroid_h + +#if USE(ACCELERATED_COMPOSITING) + +#include "LayerAndroid.h" + +namespace WebCore { + +class IFrameLayerAndroid : public LayerAndroid { + +public: + IFrameLayerAndroid(RenderLayer* owner) + : LayerAndroid(owner) {} + IFrameLayerAndroid(const LayerAndroid& layer) + : LayerAndroid(layer) {} + IFrameLayerAndroid(const IFrameLayerAndroid& layer) + : LayerAndroid(layer) + , m_iframeOffset(layer.m_iframeOffset) {} + + virtual ~IFrameLayerAndroid() {}; + + virtual bool isIFrame() const { return true; } + + virtual LayerAndroid* copy() const { return new IFrameLayerAndroid(*this); } + virtual SubclassType subclassType() { return LayerAndroid::IFrameLayer; } + + virtual IFrameLayerAndroid* updatePosition(SkRect viewport, + IFrameLayerAndroid* parentIframeLayer); + + virtual void dumpLayer(FILE*, int indentLevel) const; + + const IntPoint& iframeOffset() const { return m_iframeOffset; } + +private: + IntPoint m_iframeOffset; +}; + +} + +#endif // USE(ACCELERATED_COMPOSITING) + +#endif // IFrameLayerAndroid_h diff --git a/Source/WebCore/platform/graphics/android/Layer.cpp b/Source/WebCore/platform/graphics/android/Layer.cpp index f58d648..7453a24 100644 --- a/Source/WebCore/platform/graphics/android/Layer.cpp +++ b/Source/WebCore/platform/graphics/android/Layer.cpp @@ -158,10 +158,6 @@ void Layer::localToAncestor(const Layer* ancestor, SkMatrix* matrix) const { /////////////////////////////////////////////////////////////////////////////// -void Layer::onDraw(SkCanvas*, SkScalar opacity, android::DrawExtra* extra) { -// SkDebugf("----- no onDraw for %p\n", this); -} - #include "SkString.h" void Layer::draw(SkCanvas* canvas, android::DrawExtra* extra, SkScalar opacity) { @@ -193,7 +189,7 @@ void Layer::draw(SkCanvas* canvas, android::DrawExtra* extra, SkScalar opacity) canvas->concat(tmp); } - onDraw(canvas, opacity, extra); + onDraw(canvas, opacity, extra, FlattenedLayers); #ifdef DEBUG_DRAW_LAYER_BOUNDS { diff --git a/Source/WebCore/platform/graphics/android/Layer.h b/Source/WebCore/platform/graphics/android/Layer.h index 9165307..e872278 100644 --- a/Source/WebCore/platform/graphics/android/Layer.h +++ b/Source/WebCore/platform/graphics/android/Layer.h @@ -151,8 +151,9 @@ public: virtual bool contentIsScrollable() const { return false; } + typedef enum { MergedLayers, UnmergedLayers, FlattenedLayers } PaintStyle; protected: - virtual void onDraw(SkCanvas*, SkScalar opacity, android::DrawExtra* extra); + virtual void onDraw(SkCanvas*, SkScalar opacity, android::DrawExtra* extra, PaintStyle style) {} bool m_hasOverflowChildren; diff --git a/Source/WebCore/platform/graphics/android/LayerAndroid.cpp b/Source/WebCore/platform/graphics/android/LayerAndroid.cpp index 67d3dd3..f101208 100644 --- a/Source/WebCore/platform/graphics/android/LayerAndroid.cpp +++ b/Source/WebCore/platform/graphics/android/LayerAndroid.cpp @@ -6,6 +6,8 @@ #include "AndroidAnimation.h" #include "ClassTracker.h" #include "DrawExtra.h" +#include "DumpLayer.h" +#include "FixedPositioning.h" #include "GLUtils.h" #include "ImagesManager.h" #include "InspectorCanvas.h" @@ -24,6 +26,12 @@ #define LAYER_DEBUG // Add diagonals for debugging #undef LAYER_DEBUG +#define DISABLE_LAYER_MERGE +#undef DISABLE_LAYER_MERGE + +#define LAYER_GROUPING_DEBUG +#undef LAYER_GROUPING_DEBUG + #include <cutils/log.h> #include <wtf/text/CString.h> #define XLOGC(...) android_printLog(ANDROID_LOG_DEBUG, "LayerAndroid", __VA_ARGS__) @@ -59,12 +67,11 @@ private: LayerAndroid::LayerAndroid(RenderLayer* owner) : Layer(), m_haveClip(false), - m_isFixed(false), - m_isIframe(false), m_backfaceVisibility(true), m_visible(true), m_preserves3D(false), m_anchorPointZ(0), + m_fixedPosition(0), m_recordingPicture(0), m_zValue(0), m_uniqueId(++gUniqueId), @@ -75,12 +82,12 @@ LayerAndroid::LayerAndroid(RenderLayer* owner) : Layer(), m_owningLayer(owner), m_type(LayerAndroid::WebCoreLayer), m_hasText(true), + m_intrinsicallyComposited(true), m_layerGroup(0) { m_backgroundColor = 0; m_preserves3D = false; - m_iframeOffset.set(0,0); m_dirtyRegion.setEmpty(); #ifdef DEBUG_COUNT ClassTracker::instance()->increment("LayerAndroid"); @@ -90,42 +97,36 @@ LayerAndroid::LayerAndroid(RenderLayer* owner) : Layer(), LayerAndroid::LayerAndroid(const LayerAndroid& layer) : Layer(layer), m_haveClip(layer.m_haveClip), - m_isIframe(layer.m_isIframe), + m_fixedPosition(0), m_zValue(layer.m_zValue), m_uniqueId(layer.m_uniqueId), m_owningLayer(layer.m_owningLayer), m_type(LayerAndroid::UILayer), - m_hasText(true), + m_hasText(layer.m_hasText), + m_intrinsicallyComposited(layer.m_intrinsicallyComposited), m_layerGroup(0) { - m_isFixed = layer.m_isFixed; m_imageCRC = layer.m_imageCRC; if (m_imageCRC) ImagesManager::instance()->retainImage(m_imageCRC); - m_renderLayerPos = layer.m_renderLayerPos; m_transform = layer.m_transform; m_backfaceVisibility = layer.m_backfaceVisibility; m_visible = layer.m_visible; m_backgroundColor = layer.m_backgroundColor; - m_fixedLeft = layer.m_fixedLeft; - m_fixedTop = layer.m_fixedTop; - m_fixedRight = layer.m_fixedRight; - m_fixedBottom = layer.m_fixedBottom; - m_fixedMarginLeft = layer.m_fixedMarginLeft; - m_fixedMarginTop = layer.m_fixedMarginTop; - m_fixedMarginRight = layer.m_fixedMarginRight; - m_fixedMarginBottom = layer.m_fixedMarginBottom; - m_fixedRect = layer.m_fixedRect; - m_iframeOffset = layer.m_iframeOffset; m_offset = layer.m_offset; - m_iframeScrollOffset = layer.m_iframeScrollOffset; m_recordingPicture = layer.m_recordingPicture; SkSafeRef(m_recordingPicture); m_preserves3D = layer.m_preserves3D; m_anchorPointZ = layer.m_anchorPointZ; + + if (layer.m_fixedPosition) { + m_fixedPosition = new FixedPositioning(this, *layer.m_fixedPosition); + Layer::setShouldInheritFromRootTransform(true); + } + m_drawTransform = layer.m_drawTransform; m_childrenTransform = layer.m_childrenTransform; m_pictureUsed = layer.m_pictureUsed; @@ -141,8 +142,6 @@ LayerAndroid::LayerAndroid(const LayerAndroid& layer) : Layer(layer), m_animations.add(it->first, it->second); } - m_hasText = layer.m_hasText; - #ifdef DEBUG_COUNT ClassTracker::instance()->increment("LayerAndroid - recopy (UI)"); ClassTracker::instance()->add(this); @@ -174,8 +173,7 @@ void LayerAndroid::checkForPictureOptimizations() LayerAndroid::LayerAndroid(SkPicture* picture) : Layer(), m_haveClip(false), - m_isFixed(false), - m_isIframe(false), + m_fixedPosition(0), m_recordingPicture(picture), m_zValue(0), m_uniqueId(++gUniqueId), @@ -185,11 +183,11 @@ LayerAndroid::LayerAndroid(SkPicture* picture) : Layer(), m_owningLayer(0), m_type(LayerAndroid::NavCacheLayer), m_hasText(true), + m_intrinsicallyComposited(true), m_layerGroup(0) { m_backgroundColor = 0; SkSafeRef(m_recordingPicture); - m_iframeOffset.set(0,0); m_dirtyRegion.setEmpty(); #ifdef DEBUG_COUNT ClassTracker::instance()->increment("LayerAndroid - from picture"); @@ -201,6 +199,8 @@ LayerAndroid::~LayerAndroid() { if (m_imageCRC) ImagesManager::instance()->releaseImage(m_imageCRC); + if (m_fixedPosition) + delete m_fixedPosition; SkSafeUnref(m_recordingPicture); // Don't unref m_layerGroup, owned by BaseLayerAndroid @@ -389,74 +389,32 @@ void LayerAndroid::clipInner(SkTDArray<SkRect>* region, getChild(i)->clipInner(region, m_haveClip ? localBounds : local); } -bool LayerAndroid::updateFixedLayersPositions(SkRect viewport, LayerAndroid* parentIframeLayer) +IFrameLayerAndroid* LayerAndroid::updatePosition(SkRect viewport, + IFrameLayerAndroid* parentIframeLayer) +{ + // subclasses can implement this virtual function to modify their position + if (m_fixedPosition) + return m_fixedPosition->updatePosition(viewport, parentIframeLayer); + return parentIframeLayer; +} + +void LayerAndroid::updateLayerPositions(SkRect viewport, IFrameLayerAndroid* parentIframeLayer) { - bool hasFixedElements = false; XLOG("updating fixed positions, using viewport %fx%f - %fx%f", viewport.fLeft, viewport.fTop, viewport.width(), viewport.height()); - // If this is an iframe, accumulate the offset from the parent with - // current position, and change the parent pointer. - if (m_isIframe) { - // If this is the top level, take the current position - SkPoint parentOffset; - parentOffset.set(0,0); - if (parentIframeLayer) - parentOffset = parentIframeLayer->getPosition(); - - m_iframeOffset = parentOffset + getPosition(); - - parentIframeLayer = this; - } - if (m_isFixed) { - hasFixedElements = true; - // So if this is a fixed layer inside a iframe, use the iframe offset - // and the iframe's size as the viewport and pass to the children - if (parentIframeLayer) { - viewport = SkRect::MakeXYWH(parentIframeLayer->m_iframeOffset.fX, - parentIframeLayer->m_iframeOffset.fY, - parentIframeLayer->getSize().width(), - parentIframeLayer->getSize().height()); - } - float w = viewport.width(); - float h = viewport.height(); - float dx = viewport.fLeft; - float dy = viewport.fTop; - float x = dx; - float y = dy; - - // It turns out that when it is 'auto', we should use the webkit value - // from the original render layer's X,Y, that will take care of alignment - // with the parent's layer and fix Margin etc. - if (!(m_fixedLeft.defined() || m_fixedRight.defined())) - x += m_renderLayerPos.x(); - else if (m_fixedLeft.defined() || !m_fixedRight.defined()) - x += m_fixedMarginLeft.calcFloatValue(w) + m_fixedLeft.calcFloatValue(w) - m_fixedRect.fLeft; - else - x += w - m_fixedMarginRight.calcFloatValue(w) - m_fixedRight.calcFloatValue(w) - m_fixedRect.fRight; - - if (!(m_fixedTop.defined() || m_fixedBottom.defined())) - y += m_renderLayerPos.y(); - else if (m_fixedTop.defined() || !m_fixedBottom.defined()) - y += m_fixedMarginTop.calcFloatValue(h) + m_fixedTop.calcFloatValue(h) - m_fixedRect.fTop; - else - y += h - m_fixedMarginBottom.calcFloatValue(h) - m_fixedBottom.calcFloatValue(h) - m_fixedRect.fBottom; - - this->setPosition(x, y); - } + IFrameLayerAndroid* iframeLayer = updatePosition(viewport, parentIframeLayer); int count = this->countChildren(); for (int i = 0; i < count; i++) - hasFixedElements |= this->getChild(i)->updateFixedLayersPositions(viewport, parentIframeLayer); - - return hasFixedElements; + this->getChild(i)->updateLayerPositions(viewport, iframeLayer); } void LayerAndroid::updatePositions() { // apply the viewport to us - if (!m_isFixed) { + if (!isFixed()) { // turn our fields into a matrix. // // FIXME: this should happen in the caller, and we should remove these @@ -482,7 +440,7 @@ void LayerAndroid::updateGLPositionsAndScale(const TransformationMatrix& parentM float originX = anchorPoint.x() * layerSize.width(); float originY = anchorPoint.y() * layerSize.height(); TransformationMatrix localMatrix; - if (!m_isFixed) + if (!isFixed()) localMatrix = parentMatrix; localMatrix.translate3d(originX + position.x(), originY + position.y(), @@ -635,9 +593,9 @@ void LayerAndroid::showLayer(int indent) IntRect visible = visibleArea(); IntRect clip(m_clippingRect.x(), m_clippingRect.y(), m_clippingRect.width(), m_clippingRect.height()); - XLOGC("%s [%d:0x%x] - %s %s - area (%d, %d, %d, %d) - visible (%d, %d, %d, %d) " + XLOGC("%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 prepareContext(%x), pic w: %d h: %d", - spaces, uniqueId(), m_owningLayer, + spaces, subclassName().latin1().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(), @@ -654,22 +612,6 @@ void LayerAndroid::showLayer(int indent) this->getChild(i)->showLayer(indent + 1); } -void LayerAndroid::setIsPainting(Layer* drawingTree) -{ - XLOG("setting layer %p as painting, needs texture %d, drawing tree %p", - this, needsTexture(), drawingTree); - int count = this->countChildren(); - for (int i = 0; i < count; i++) - this->getChild(i)->setIsPainting(drawingTree); - - - LayerAndroid* drawingLayer = 0; - if (drawingTree) - drawingLayer = static_cast<LayerAndroid*>(drawingTree)->findById(uniqueId()); - - obtainTextureForPainting(drawingLayer); -} - void LayerAndroid::mergeInvalsInto(LayerAndroid* replacementTree) { int count = this->countChildren(); @@ -725,49 +667,90 @@ bool LayerAndroid::updateWithLayer(LayerAndroid* layer) return false; } -void LayerAndroid::obtainTextureForPainting(LayerAndroid* drawingLayer) +static inline bool compareLayerZ(const LayerAndroid* a, const LayerAndroid* b) { - if (!needsTexture()) - return; - - // layer group init'd with previous drawing layer - m_layerGroup->initializeGroup(this, m_dirtyRegion, drawingLayer); - m_dirtyRegion.setEmpty(); + return a->zValue() > b->zValue(); } - -static inline bool compareLayerZ(const LayerAndroid* a, const LayerAndroid* b) +bool LayerAndroid::canJoinGroup(LayerGroup* group) { - return a->zValue() > b->zValue(); +#if DISABLE_LAYER_MERGE + return false; +#else + // returns true if the layer can be merged onto the layergroup + if (!group) + return false; + + LayerAndroid* lastLayer = group->getFirstLayer(); + + // isolate non-tiled layers + // TODO: remove this check so that multiple tiled layers with a invisible + // one inbetween can be merged + if (!needsTexture() || !lastLayer->needsTexture()) + return false; + + // isolate clipped layers + // TODO: paint correctly with clip when merged + if (m_haveClip || lastLayer->m_haveClip) + return false; + + // isolate intrinsically composited layers + if (m_intrinsicallyComposited || lastLayer->m_intrinsicallyComposited) + return false; + + // TODO: investigate potential for combining transformed layers + if (!m_drawTransform.isIdentityOrTranslation() + || !lastLayer->m_drawTransform.isIdentityOrTranslation()) + return false; + + // currently, we don't group zoomable with non-zoomable layers (unless the + // group or the layer doesn't need a texture) + if (group->needsTexture() && needsTexture() && m_hasText != group->hasText()) + return false; + + // TODO: compare other layer properties - fixed? overscroll? transformed? + return true; +#endif } -void LayerAndroid::assignGroups(Vector<LayerGroup*>* allGroups) +void LayerAndroid::assignGroups(LayerMergeState* mergeState) { - // recurse through layers in draw order - // if a layer needs isolation (e.g. has animation, is fixed, overflow:scroll) - // create new layer group on the stack + // recurse through layers in draw order, and merge layers when able - bool needsIsolation = false; - LayerGroup* currentLayerGroup = 0; - if (!allGroups->isEmpty()) - currentLayerGroup = allGroups->at(0); + bool needNewGroup = !mergeState->currentLayerGroup + || mergeState->nonMergeNestedLevel > 0 + || !canJoinGroup(mergeState->currentLayerGroup); - // TODO: compare layer with group on top of stack - fixed? overscroll? transformed? - needsIsolation = m_isFixed || (m_animations.size() != 0); + if (needNewGroup) { + mergeState->currentLayerGroup = new LayerGroup(); + mergeState->groupList->append(mergeState->currentLayerGroup); + } - if (!currentLayerGroup || needsIsolation || true) { - currentLayerGroup = new LayerGroup(); - allGroups->append(currentLayerGroup); +#ifdef LAYER_GROUPING_DEBUG + XLOGC("%*slayer %p(%d) rl %p %s group %p, fixed %d, anim %d, intCom %d, haveClip %d scroll %d", + 4*mergeState->depth, "", this, m_uniqueId, m_owningLayer, + needNewGroup ? "NEW" : "joins", mergeState->currentLayerGroup, + m_isFixed, m_animations.size() != 0, + m_intrinsicallyComposited, + m_haveClip, + contentIsScrollable()); +#endif + + mergeState->currentLayerGroup->addLayer(this, m_drawTransform); + m_layerGroup = mergeState->currentLayerGroup; + + if (m_haveClip || contentIsScrollable() || isFixed()) { + // disable layer merging within the children of these layer types + mergeState->nonMergeNestedLevel++; } - currentLayerGroup->addLayer(this); - m_layerGroup = currentLayerGroup; // pass the layergroup through children in drawing order, so that they may // attach themselves (and paint on it) if possible, or ignore it and create // a new one if not int count = this->countChildren(); if (count > 0) { + mergeState->depth++; Vector <LayerAndroid*> sublayers; for (int i = 0; i < count; i++) sublayers.append(getChild(i)); @@ -775,7 +758,16 @@ void LayerAndroid::assignGroups(Vector<LayerGroup*>* allGroups) // sort for the transparency std::stable_sort(sublayers.begin(), sublayers.end(), compareLayerZ); for (int i = 0; i < count; i++) - sublayers[i]->assignGroups(allGroups); + sublayers[i]->assignGroups(mergeState); + mergeState->depth--; + } + + if (m_haveClip || contentIsScrollable() || isFixed()) { + // re-enable joining + mergeState->nonMergeNestedLevel--; + + // disallow layers painting after to join with this group + mergeState->currentLayerGroup = 0; } } @@ -824,7 +816,7 @@ IntRect LayerAndroid::visibleArea() return rect; } -bool LayerAndroid::drawCanvas(SkCanvas* canvas) +bool LayerAndroid::drawCanvas(SkCanvas* canvas, bool drawChildren, PaintStyle style) { if (!m_visible) return false; @@ -843,11 +835,14 @@ bool LayerAndroid::drawCanvas(SkCanvas* canvas) SkMatrix canvasMatrix = canvas->getTotalMatrix(); matrix.postConcat(canvasMatrix); canvas->setMatrix(matrix); - onDraw(canvas, m_drawOpacity, 0); + onDraw(canvas, m_drawOpacity, 0, style); } + if (!drawChildren) + return false; + // When the layer is dirty, the UI thread should be notified to redraw. - askScreenUpdate |= drawChildrenCanvas(canvas); + askScreenUpdate |= drawChildrenCanvas(canvas, style); m_atomicSync.lock(); if (askScreenUpdate || m_hasRunningAnimations || m_drawTransform.hasPerspective()) addDirtyArea(); @@ -878,7 +873,7 @@ bool LayerAndroid::drawGL(bool layerTilesDisabled) return askScreenUpdate; } -bool LayerAndroid::drawChildrenCanvas(SkCanvas* canvas) +bool LayerAndroid::drawChildrenCanvas(SkCanvas* canvas, PaintStyle style) { bool askScreenUpdate = false; int count = this->countChildren(); @@ -891,14 +886,14 @@ bool LayerAndroid::drawChildrenCanvas(SkCanvas* canvas) std::stable_sort(sublayers.begin(), sublayers.end(), compareLayerZ); for (int i = 0; i < count; i++) { LayerAndroid* layer = sublayers[i]; - askScreenUpdate |= layer->drawCanvas(canvas); + askScreenUpdate |= layer->drawCanvas(canvas, true, style); } } return askScreenUpdate; } -void LayerAndroid::contentDraw(SkCanvas* canvas) +void LayerAndroid::contentDraw(SkCanvas* canvas, PaintStyle style) { if (m_recordingPicture) canvas->drawPicture(*m_recordingPicture); @@ -907,24 +902,29 @@ void LayerAndroid::contentDraw(SkCanvas* canvas) float w = getSize().width(); float h = getSize().height(); SkPaint paint; - paint.setARGB(128, 255, 0, 0); + + if (style == MergedLayers) + paint.setARGB(255, 255, 255, 0); + else if (style == UnmergedLayers) + paint.setARGB(255, 255, 0, 0); + else if (style == FlattenedLayers) + paint.setARGB(255, 255, 0, 255); + canvas->drawLine(0, 0, w, h, paint); canvas->drawLine(0, h, w, 0, paint); - paint.setARGB(128, 0, 255, 0); + canvas->drawLine(0, 0, 0, h, paint); canvas->drawLine(0, h, w, h, paint); canvas->drawLine(w, h, w, 0, paint); canvas->drawLine(w, 0, 0, 0, paint); - - if (m_isFixed) { - SkPaint paint; - paint.setARGB(80, 255, 0, 0); - canvas->drawRect(m_fixedRect, paint); - } } + + if (m_fixedPosition) + return m_fixedPosition->contentDraw(canvas, style); } -void LayerAndroid::onDraw(SkCanvas* canvas, SkScalar opacity, android::DrawExtra* extra) +void LayerAndroid::onDraw(SkCanvas* canvas, SkScalar opacity, + android::DrawExtra* extra, PaintStyle style) { if (m_haveClip) { SkRect r; @@ -953,7 +953,7 @@ void LayerAndroid::onDraw(SkCanvas* canvas, SkScalar opacity, android::DrawExtra } ImagesManager::instance()->releaseImage(m_imageCRC); } - contentDraw(canvas); + contentDraw(canvas, style); if (extra) extra->draw(canvas, this); } @@ -981,6 +981,12 @@ bool LayerAndroid::prepareContext(bool force) return m_recordingPicture; } +void LayerAndroid::setFixedPosition(FixedPositioning* position) { + if (m_fixedPosition && m_fixedPosition != position) + delete m_fixedPosition; + m_fixedPosition = position; +} + SkRect LayerAndroid::subtractLayers(const SkRect& visibleRect) const { SkRect result; @@ -1018,116 +1024,12 @@ SkRect LayerAndroid::subtractLayers(const SkRect& visibleRect) const return result; } -// Debug tools : dump the layers tree in a file. -// The format is simple: -// properties have the form: key = value; -// all statements are finished with a semi-colon. -// value can be: -// - int -// - float -// - array of elements -// - composed type -// a composed type enclose properties in { and } -// an array enclose composed types in { }, separated with a comma. -// exemple: -// { -// x = 3; -// y = 4; -// value = { -// x = 3; -// y = 4; -// }; -// anarray = [ -// { x = 3; }, -// { y = 4; } -// ]; -// } - -void lwrite(FILE* file, const char* str) -{ - fwrite(str, sizeof(char), strlen(str), file); -} - -void writeIndent(FILE* file, int indentLevel) -{ - if (indentLevel) - fprintf(file, "%*s", indentLevel*2, " "); -} - -void writeln(FILE* file, int indentLevel, const char* str) -{ - writeIndent(file, indentLevel); - lwrite(file, str); - lwrite(file, "\n"); -} - -void writeIntVal(FILE* file, int indentLevel, const char* str, int value) -{ - writeIndent(file, indentLevel); - fprintf(file, "%s = %d;\n", str, value); -} - -void writeHexVal(FILE* file, int indentLevel, const char* str, int value) +void LayerAndroid::dumpLayer(FILE* file, int indentLevel) const { - writeIndent(file, indentLevel); - fprintf(file, "%s = %x;\n", str, value); -} - -void writeFloatVal(FILE* file, int indentLevel, const char* str, float value) -{ - writeIndent(file, indentLevel); - fprintf(file, "%s = %.3f;\n", str, value); -} - -void writePoint(FILE* file, int indentLevel, const char* str, SkPoint point) -{ - writeIndent(file, indentLevel); - fprintf(file, "%s = { x = %.3f; y = %.3f; };\n", str, point.fX, point.fY); -} - -void writeSize(FILE* file, int indentLevel, const char* str, SkSize size) -{ - writeIndent(file, indentLevel); - fprintf(file, "%s = { w = %.3f; h = %.3f; };\n", str, size.width(), size.height()); -} - -void writeRect(FILE* file, int indentLevel, const char* str, SkRect rect) -{ - writeIndent(file, indentLevel); - fprintf(file, "%s = { x = %.3f; y = %.3f; w = %.3f; h = %.3f; };\n", - str, rect.fLeft, rect.fTop, rect.width(), rect.height()); -} - -void writeLength(FILE* file, int indentLevel, const char* str, SkLength length) -{ - if (!length.defined()) - return; - writeIndent(file, indentLevel); - fprintf(file, "%s = { type = %d; value = %.2f; };\n", str, length.type, length.value); -} - -void writeMatrix(FILE* file, int indentLevel, const char* str, const TransformationMatrix& matrix) -{ - writeIndent(file, indentLevel); - fprintf(file, "%s = { (%.2f,%.2f,%.2f,%.2f),(%.2f,%.2f,%.2f,%.2f)," - "(%.2f,%.2f,%.2f,%.2f),(%.2f,%.2f,%.2f,%.2f) };\n", - str, - 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()); -} - -void LayerAndroid::dumpLayers(FILE* file, int indentLevel) const -{ - writeln(file, indentLevel, "{"); - writeHexVal(file, indentLevel + 1, "layer", (int)this); writeIntVal(file, indentLevel + 1, "layerId", m_uniqueId); writeIntVal(file, indentLevel + 1, "haveClip", m_haveClip); - writeIntVal(file, indentLevel + 1, "isFixed", m_isFixed); - writeIntVal(file, indentLevel + 1, "m_isIframe", m_isIframe); - writePoint(file, indentLevel + 1, "m_iframeOffset", m_iframeOffset); + writeIntVal(file, indentLevel + 1, "isFixed", isFixed()); writeFloatVal(file, indentLevel + 1, "opacity", getOpacity()); writeSize(file, indentLevel + 1, "size", getSize()); @@ -1138,23 +1040,21 @@ void LayerAndroid::dumpLayers(FILE* file, int indentLevel) const writeMatrix(file, indentLevel + 1, "transformMatrix", m_transform); writeRect(file, indentLevel + 1, "clippingRect", SkRect(m_clippingRect)); - if (m_isFixed) { - writeLength(file, indentLevel + 1, "fixedLeft", m_fixedLeft); - writeLength(file, indentLevel + 1, "fixedTop", m_fixedTop); - writeLength(file, indentLevel + 1, "fixedRight", m_fixedRight); - writeLength(file, indentLevel + 1, "fixedBottom", m_fixedBottom); - writeLength(file, indentLevel + 1, "fixedMarginLeft", m_fixedMarginLeft); - writeLength(file, indentLevel + 1, "fixedMarginTop", m_fixedMarginTop); - writeLength(file, indentLevel + 1, "fixedMarginRight", m_fixedMarginRight); - writeLength(file, indentLevel + 1, "fixedMarginBottom", m_fixedMarginBottom); - writeRect(file, indentLevel + 1, "fixedRect", m_fixedRect); - } - if (m_recordingPicture) { writeIntVal(file, indentLevel + 1, "m_recordingPicture.width", m_recordingPicture->width()); writeIntVal(file, indentLevel + 1, "m_recordingPicture.height", m_recordingPicture->height()); } + if (m_fixedPosition) + return m_fixedPosition->dumpLayer(file, indentLevel); +} + +void LayerAndroid::dumpLayers(FILE* file, int indentLevel) const +{ + writeln(file, indentLevel, "{"); + + dumpLayer(file, indentLevel); + if (countChildren()) { writeln(file, indentLevel + 1, "children = ["); for (int i = 0; i < countChildren(); i++) { diff --git a/Source/WebCore/platform/graphics/android/LayerAndroid.h b/Source/WebCore/platform/graphics/android/LayerAndroid.h index 86d27bc..7f5d5e2 100644 --- a/Source/WebCore/platform/graphics/android/LayerAndroid.h +++ b/Source/WebCore/platform/graphics/android/LayerAndroid.h @@ -55,45 +55,20 @@ class ImageTexture; namespace android { class DrawExtra; void serializeLayer(WebCore::LayerAndroid* layer, SkWStream* stream); -WebCore::LayerAndroid* deserializeLayer(SkStream* stream); +WebCore::LayerAndroid* deserializeLayer(int version, SkStream* stream); void cleanupImageRefs(WebCore::LayerAndroid* layer); } using namespace android; -struct SkLength { - enum SkLengthType { Undefined, Auto, Relative, Percent, Fixed, Static, Intrinsic, MinIntrinsic }; - SkLengthType type; - SkScalar value; - SkLength() - { - type = Undefined; - value = 0; - } - bool defined() const - { - if (type == Undefined) - return false; - return true; - } - float calcFloatValue(float max) const - { - switch (type) { - case Percent: - return (max * value) / 100.0f; - case Fixed: - return value; - default: - return value; - } - } -}; - namespace WebCore { class AndroidAnimation; class BaseTileTexture; +class FixedPositioning; class GLWebViewState; +class IFrameLayerAndroid; +class LayerMergeState; class RenderLayer; class TiledPage; class PaintedSurface; @@ -115,7 +90,24 @@ public: class TEST_EXPORT LayerAndroid : public Layer { public: - enum LayerType { UndefinedLayer, WebCoreLayer, UILayer, NavCacheLayer }; + typedef enum { UndefinedLayer, WebCoreLayer, UILayer, NavCacheLayer } LayerType; + typedef enum { StandardLayer, ScrollableLayer, + IFrameLayer, IFrameContentLayer } SubclassType; + + String subclassName() + { + switch (subclassType()) { + case LayerAndroid::StandardLayer: + return "StandardLayer"; + case LayerAndroid::ScrollableLayer: + return "ScrollableLayer"; + case LayerAndroid::IFrameLayer: + return "IFrameLayer"; + case LayerAndroid::IFrameContentLayer: + return "IFrameContentLayer"; + } + return "Undefined"; + } LayerAndroid(RenderLayer* owner); LayerAndroid(const LayerAndroid& layer); @@ -148,8 +140,8 @@ public: float getScale() { return m_scale; } virtual bool drawGL(bool layerTilesDisabled); - virtual bool drawCanvas(SkCanvas*); - bool drawChildrenCanvas(SkCanvas*); + virtual bool drawCanvas(SkCanvas* canvas, bool drawChildren, PaintStyle style); + bool drawChildrenCanvas(SkCanvas* canvas, PaintStyle style); void updateGLPositionsAndScale(const TransformationMatrix& parentMatrix, const FloatRect& clip, float opacity, float scale); @@ -168,34 +160,8 @@ public: void setDrawClip(const FloatRect& rect) { m_clippingRect = rect; } const FloatRect& drawClip() { return m_clippingRect; } - void setFixedPosition(SkLength left, // CSS left property - SkLength top, // CSS top property - SkLength right, // CSS right property - SkLength bottom, // CSS bottom property - SkLength marginLeft, // CSS margin-left property - SkLength marginTop, // CSS margin-top property - SkLength marginRight, // CSS margin-right property - SkLength marginBottom, // CSS margin-bottom property - const IntPoint& renderLayerPos, // For undefined fixed position - SkRect viewRect) { // view rect, can be smaller than the layer's - m_fixedLeft = left; - m_fixedTop = top; - m_fixedRight = right; - m_fixedBottom = bottom; - m_fixedMarginLeft = marginLeft; - m_fixedMarginTop = marginTop; - m_fixedMarginRight = marginRight; - m_fixedMarginBottom = marginBottom; - m_fixedRect = viewRect; - m_isFixed = true; - m_renderLayerPos = renderLayerPos; - setShouldInheritFromRootTransform(true); - } - const IntPoint& scrollOffset() const { return m_offset; } - const IntPoint& iframeScrollOffset() const { return m_iframeScrollOffset; } void setScrollOffset(IntPoint offset) { m_offset = offset; } - void setIFrameScrollOffset(IntPoint offset) { m_iframeScrollOffset = offset; } void setBackgroundColor(SkColor color); void setMaskLayer(LayerAndroid*); void setMasksToBounds(bool masksToBounds) @@ -222,6 +188,7 @@ public: // in global space. SkRect subtractLayers(const SkRect&) const; + virtual void dumpLayer(FILE*, int indentLevel) const; void dumpLayers(FILE*, int indentLevel) const; void dumpToLog() const; @@ -231,7 +198,9 @@ public: This call is recursive, so it should be called on the root of the hierarchy. */ - bool updateFixedLayersPositions(SkRect viewPort, LayerAndroid* parentIframeLayer = 0); + void updateLayerPositions(SkRect viewPort, IFrameLayerAndroid* parentIframeLayer = 0); + virtual IFrameLayerAndroid* updatePosition(SkRect viewport, + IFrameLayerAndroid* parentIframeLayer); /** Call this to update the position attribute, so that later calls like bounds() will report the corrected position. @@ -253,7 +222,6 @@ public: return static_cast<LayerAndroid*>(this->INHERITED::getChild(index)); } int uniqueId() const { return m_uniqueId; } - bool isFixed() { return m_isFixed; } /** This sets a content image -- calling it means we will use the image directly when drawing the layer instead of using @@ -272,31 +240,34 @@ public: void clearDirtyRegion(); - void contentDraw(SkCanvas*); + virtual void contentDraw(SkCanvas* canvas, PaintStyle style); virtual bool isMedia() const { return false; } virtual bool isVideo() const { return false; } + bool isFixed() const { return m_fixedPosition; } + virtual bool isIFrame() const { return false; } + virtual bool isIFrameContent() const { return false; } + + void setFixedPosition(FixedPositioning* position); + FixedPositioning* fixedPosition() { return m_fixedPosition; } RenderLayer* owningLayer() const { return m_owningLayer; } - void setIsIframe(bool isIframe) { m_isIframe = isIframe; } - bool isIFrame() const { return m_isIframe; } float zValue() const { return m_zValue; } // ViewStateSerializer friends friend void android::serializeLayer(LayerAndroid* layer, SkWStream* stream); - friend LayerAndroid* android::deserializeLayer(SkStream* stream); + friend LayerAndroid* android::deserializeLayer(int version, SkStream* stream); friend void android::cleanupImageRefs(LayerAndroid* layer); - void obtainTextureForPainting(LayerAndroid* drawingLayer); - // Update layers using another tree. Only works for basic properties // such as the position, the transform. Return true if anything more // complex is needed. bool updateWithTree(LayerAndroid*); virtual bool updateWithLayer(LayerAndroid*); - int type() { return m_type; } + LayerType type() { return m_type; } + virtual SubclassType subclassType() { return LayerAndroid::StandardLayer; } bool hasText() { return m_hasText; } void checkForPictureOptimizations(); @@ -304,16 +275,18 @@ public: void copyAnimationStartTimesRecursive(LayerAndroid* oldTree); // rendering asset management - void setIsPainting(Layer* drawingTree); + SkRegion* getInvalRegion() { return &m_dirtyRegion; } void mergeInvalsInto(LayerAndroid* replacementTree); - void assignGroups(Vector<LayerGroup*>* allGroups); + bool canJoinGroup(LayerGroup* group); + void assignGroups(LayerMergeState* mergeState); LayerGroup* group() { return m_layerGroup; } + void setIntrinsicallyComposited(bool intCom) { m_intrinsicallyComposited = intCom; } + protected: - virtual void onDraw(SkCanvas*, SkScalar opacity, android::DrawExtra* extra); + virtual void onDraw(SkCanvas*, SkScalar opacity, android::DrawExtra* extra, PaintStyle style); IntPoint m_offset; - IntPoint m_iframeScrollOffset; TransformationMatrix m_drawTransform; private: @@ -330,23 +303,7 @@ private: // ------------------------------------------------------------------- bool m_haveClip; - bool m_isFixed; bool m_backgroundColorSet; - bool m_isIframe; - - SkLength m_fixedLeft; - SkLength m_fixedTop; - SkLength m_fixedRight; - SkLength m_fixedBottom; - SkLength m_fixedMarginLeft; - SkLength m_fixedMarginTop; - SkLength m_fixedMarginRight; - SkLength m_fixedMarginBottom; - SkRect m_fixedRect; - - // When fixed element is undefined or auto, the render layer's position - // is needed for offset computation - IntPoint m_renderLayerPos; bool m_backfaceVisibility; bool m_visible; @@ -357,6 +314,8 @@ private: float m_anchorPointZ; float m_drawOpacity; + FixedPositioning* m_fixedPosition; + // Note that m_recordingPicture and m_imageRef are mutually exclusive; // m_recordingPicture is used when WebKit is asked to paint the layer's // content, while m_imageRef contains an image that we directly @@ -375,8 +334,6 @@ private: // Fields that are not serialized (generated, cached, or non-serializable) // ------------------------------------------------------------------- - SkPoint m_iframeOffset; - float m_zValue; FloatRect m_clippingRect; @@ -403,9 +360,11 @@ private: RenderLayer* m_owningLayer; - int m_type; + LayerType m_type; + SubclassType m_subclassType; bool m_hasText; + bool m_intrinsicallyComposited; LayerGroup* m_layerGroup; diff --git a/Source/WebCore/platform/graphics/android/LayerGroup.cpp b/Source/WebCore/platform/graphics/android/LayerGroup.cpp index cb1cf9b..5ec41f8 100644 --- a/Source/WebCore/platform/graphics/android/LayerGroup.cpp +++ b/Source/WebCore/platform/graphics/android/LayerGroup.cpp @@ -53,13 +53,12 @@ // LayerGroups with an area larger than 2048*2048 should never be unclipped #define MAX_UNCLIPPED_AREA 4194304 -#define TEMP_LAYER m_layers[0] - namespace WebCore { LayerGroup::LayerGroup() - : m_hasText(false) - , m_dualTiledTexture(0) + : m_dualTiledTexture(0) + , m_needsTexture(false) + , m_hasText(false) { #ifdef DEBUG_COUNT ClassTracker::instance()->increment("LayerGroup"); @@ -77,61 +76,144 @@ LayerGroup::~LayerGroup() #endif } -void LayerGroup::initializeGroup(LayerAndroid* newLayer, const SkRegion& newLayerInval, - LayerAndroid* oldLayer) +bool LayerGroup::tryUpdateLayerGroup(LayerGroup* oldLayerGroup) { - if (!newLayer->needsTexture()) - return; + if (!needsTexture() || !oldLayerGroup->needsTexture()) + return false; + + // merge layer group based on first layer ID + if (getFirstLayer()->uniqueId() != oldLayerGroup->getFirstLayer()->uniqueId()) + return false; + + m_dualTiledTexture = oldLayerGroup->m_dualTiledTexture; + SkSafeRef(m_dualTiledTexture); - XLOG("init on LG %p, layer %p, oldlayer %p", this, newLayer, oldLayer); - if (oldLayer && oldLayer->group() && oldLayer->group()->m_dualTiledTexture) { - // steal DTT from old group, and apply new inval - m_dualTiledTexture = oldLayer->group()->m_dualTiledTexture; - SkSafeRef(m_dualTiledTexture); - m_dualTiledTexture->markAsDirty(newLayerInval); - } else - m_dualTiledTexture = new DualTiledTexture(); - } - -void LayerGroup::addLayer(LayerAndroid* layer) + XLOG("%p taking old DTT %p from group %p, nt %d", + this, m_dualTiledTexture, oldLayerGroup, oldLayerGroup->needsTexture()); + + if (!m_dualTiledTexture) { + // no DTT to inval, so don't worry about it. + return true; + } + + if (singleLayer() && oldLayerGroup->singleLayer()) { + // both are single matching layers, simply apply inval + SkRegion* layerInval = getFirstLayer()->getInvalRegion(); + m_dualTiledTexture->markAsDirty(*layerInval); + } else { + SkRegion invalRegion; + bool fullInval = false; + for (unsigned int i = 0; i < m_layers.size(); i++) { + if (m_layers[i]->uniqueId() != oldLayerGroup->m_layers[i]->uniqueId()) { + // layer list has changed, fully invalidate + // TODO: partially invalidate based on layer size/position + fullInval = true; + break; + } else if (!m_layers[i]->getInvalRegion()->isEmpty()) { + // merge layer inval - translate the layer's inval region into group coordinates + SkPoint pos = m_layers[i]->getPosition(); + m_layers[i]->getInvalRegion()->translate(pos.fX, pos.fY); + invalRegion.op(*(m_layers[i]->getInvalRegion()), SkRegion::kUnion_Op); + break; + } + } + + if (fullInval) + invalRegion.setRect(-1e8, -1e8, 2e8, 2e8); + + m_dualTiledTexture->markAsDirty(invalRegion); + } + return true; +} + +void LayerGroup::addLayer(LayerAndroid* layer, const TransformationMatrix& transform) { m_layers.append(layer); SkSafeRef(layer); + + m_needsTexture |= layer->needsTexture(); + m_hasText |= layer->hasText(); + + // calculate area size for comparison later + IntRect rect = layer->unclippedArea(); + SkPoint pos = layer->getPosition(); + rect.setLocation(IntPoint(pos.fX, pos.fY)); + + if (layer->needsTexture()) { + if (m_unclippedArea.isEmpty()) { + m_drawTransform = transform; + m_drawTransform.translate3d(-pos.fX, -pos.fY, 0); + m_unclippedArea = rect; + } else + m_unclippedArea.unite(rect); + XLOG("LG %p adding LA %p, size %d, %d %dx%d, now LG size %d,%d %dx%d", + this, layer, rect.x(), rect.y(), rect.width(), rect.height(), + m_unclippedArea.x(), m_unclippedArea.y(), + m_unclippedArea.width(), m_unclippedArea.height()); + } +} + +IntRect LayerGroup::visibleArea() +{ + if (singleLayer()) + return getFirstLayer()->visibleArea(); + + IntRect rect = m_unclippedArea; + + // clip with the viewport in documents coordinate + IntRect documentViewport(TilesManager::instance()->shader()->documentViewport()); + rect.intersect(documentViewport); + + // TODO: handle recursive layer clip + + return rect; } void LayerGroup::prepareGL(bool layerTilesDisabled) { - if (!m_dualTiledTexture) - return; + if (!m_dualTiledTexture) { + XLOG("prepareGL on LG %p, no DTT, needsTexture? %d", + this, m_dualTiledTexture, needsTexture()); + + if (needsTexture()) + m_dualTiledTexture = new DualTiledTexture(); + else + return; + } if (layerTilesDisabled) { m_dualTiledTexture->discardTextures(); } else { - XLOG("prepareGL on LG %p with DTT %p", this, m_dualTiledTexture); - bool allowZoom = m_hasText; // only allow for scale > 1 if painting vectors + bool allowZoom = hasText(); // only allow for scale > 1 if painting vectors IntRect prepareArea = computePrepareArea(); - m_dualTiledTexture->prepareGL(TEMP_LAYER->state(), TEMP_LAYER->hasText(), + + XLOG("prepareGL on LG %p with DTT %p, %d layers", + this, m_dualTiledTexture, m_layers.size()); + m_dualTiledTexture->prepareGL(getFirstLayer()->state(), allowZoom, prepareArea, this); } } bool LayerGroup::drawGL(bool layerTilesDisabled) { - if (!TEMP_LAYER->visible()) + if (!getFirstLayer()->visible()) return false; - FloatRect drawClip = TEMP_LAYER->drawClip(); + FloatRect drawClip = getFirstLayer()->drawClip(); FloatRect clippingRect = TilesManager::instance()->shader()->rectInScreenCoord(drawClip); TilesManager::instance()->shader()->clip(clippingRect); bool askRedraw = false; if (m_dualTiledTexture && !layerTilesDisabled) { XLOG("drawGL on LG %p with DTT %p", this, m_dualTiledTexture); - IntRect visibleArea = TEMP_LAYER->visibleArea(); - const TransformationMatrix* transform = TEMP_LAYER->drawTransform(); - askRedraw |= m_dualTiledTexture->drawGL(visibleArea, opacity(), transform); + + IntRect drawArea = visibleArea(); + askRedraw |= m_dualTiledTexture->drawGL(drawArea, opacity(), drawTransform()); } - askRedraw |= TEMP_LAYER->drawGL(layerTilesDisabled); + + // draw member layers (draws image textures, glextras) + for (unsigned int i = 0; i < m_layers.size(); i++) + askRedraw |= m_layers[i]->drawGL(layerTilesDisabled); return askRedraw; } @@ -155,15 +237,16 @@ bool LayerGroup::isReady() IntRect LayerGroup::computePrepareArea() { IntRect area; - if (!TEMP_LAYER->contentIsScrollable() - && TEMP_LAYER->state()->layersRenderingMode() == GLWebViewState::kAllTextures) { - area = TEMP_LAYER->unclippedArea(); + if (!getFirstLayer()->contentIsScrollable() + && getFirstLayer()->state()->layersRenderingMode() == GLWebViewState::kAllTextures) { + + area = singleLayer() ? getFirstLayer()->unclippedArea() : m_unclippedArea; double total = ((double) area.width()) * ((double) area.height()); if (total > MAX_UNCLIPPED_AREA) - area = TEMP_LAYER->visibleArea(); + area = visibleArea(); } else { - area = TEMP_LAYER->visibleArea(); + area = visibleArea(); } return area; @@ -174,26 +257,48 @@ void LayerGroup::computeTexturesAmount(TexturesResult* result) if (!m_dualTiledTexture) return; - // TODO: don't calculate through layer recursion, use the group list - m_dualTiledTexture->computeTexturesAmount(result, TEMP_LAYER); + m_dualTiledTexture->computeTexturesAmount(result, getFirstLayer()); } bool LayerGroup::paint(BaseTile* tile, SkCanvas* canvas, unsigned int* pictureUsed) { - SkPicture *picture = TEMP_LAYER->picture(); - if (!picture) { - XLOGC("LG %p couldn't paint, no picture in layer %p", this, TEMP_LAYER); - return false; - } + if (singleLayer()) { + getFirstLayer()->contentDraw(canvas, Layer::UnmergedLayers); + } else { + SkAutoCanvasRestore acr(canvas, true); + SkMatrix matrix; + GLUtils::toSkMatrix(matrix, m_drawTransform); + + SkMatrix inverse; + inverse.reset(); + matrix.invert(&inverse); - canvas->drawPicture(*picture); + SkMatrix canvasMatrix = canvas->getTotalMatrix(); + inverse.postConcat(canvasMatrix); + canvas->setMatrix(inverse); + for (unsigned int i=0; i<m_layers.size(); i++) + m_layers[i]->drawCanvas(canvas, false, Layer::MergedLayers); + } return true; } float LayerGroup::opacity() { - return TEMP_LAYER->getOpacity(); + if (singleLayer()) + return getFirstLayer()->getOpacity(); + return 1.0; +} + +const TransformationMatrix* LayerGroup::drawTransform() +{ + // single layer groups query the layer's draw transform, while multi-layer + // groups copy the draw transform once, during initialization + // TODO: support fixed multi-layer groups by querying the changing drawTransform + if (singleLayer()) + return getFirstLayer()->drawTransform(); + + return &m_drawTransform; } } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/android/LayerGroup.h b/Source/WebCore/platform/graphics/android/LayerGroup.h index 0546139..e3e0247 100644 --- a/Source/WebCore/platform/graphics/android/LayerGroup.h +++ b/Source/WebCore/platform/graphics/android/LayerGroup.h @@ -26,6 +26,7 @@ #ifndef LayerGroup_h #define LayerGroup_h +#include "IntRect.h" #include "TilePainter.h" #include "Vector.h" @@ -44,10 +45,11 @@ public: LayerGroup(); virtual ~LayerGroup(); - void initializeGroup(LayerAndroid* newLayer, const SkRegion& newLayerInval, - LayerAndroid* oldLayer); + bool tryUpdateLayerGroup(LayerGroup* oldLayerGroup); - void addLayer(LayerAndroid* layer); + + void addLayer(LayerAndroid* layer, const TransformationMatrix& transform); + IntRect visibleArea(); void prepareGL(bool layerTilesDisabled); bool drawGL(bool layerTilesDisabled); void swapTiles(); @@ -56,15 +58,48 @@ public: IntRect computePrepareArea(); void computeTexturesAmount(TexturesResult* result); + LayerAndroid* getFirstLayer() { return m_layers[0]; } + bool singleLayer() { return m_layers.size() == 1; } + bool needsTexture() { return m_needsTexture; } + bool hasText() { return m_hasText; } + // TilePainter methods virtual bool paint(BaseTile* tile, SkCanvas* canvas, unsigned int* pictureUsed); virtual float opacity(); private: - bool m_hasText; + const TransformationMatrix* drawTransform(); + IntRect m_unclippedArea; + TransformationMatrix m_drawTransform; + DualTiledTexture* m_dualTiledTexture; + bool m_needsTexture; + bool m_hasText; Vector<LayerAndroid*> m_layers; }; +class LayerMergeState { +public: + LayerMergeState(Vector<LayerGroup*>* const allGroups) + : groupList(allGroups) + , currentLayerGroup(0) + , nonMergeNestedLevel(-1) // start at -1 to ignore first LayerAndroid's clipping + , depth(0) + {} + + // vector storing all generated layer groups + Vector<LayerGroup*>* const groupList; + + // currently merging group. if cleared, no more layers may join + LayerGroup* currentLayerGroup; + + // records depth within non-mergeable parents (clipping, fixed, scrolling) + // and disable merging therein. + int nonMergeNestedLevel; + + // counts layer tree depth for debugging + int depth; +}; + } // namespace WebCore #endif //#define LayerGroup_h diff --git a/Source/WebCore/platform/graphics/android/ScrollableLayerAndroid.cpp b/Source/WebCore/platform/graphics/android/ScrollableLayerAndroid.cpp index 205727c..dffab58 100644 --- a/Source/WebCore/platform/graphics/android/ScrollableLayerAndroid.cpp +++ b/Source/WebCore/platform/graphics/android/ScrollableLayerAndroid.cpp @@ -21,15 +21,8 @@ bool ScrollableLayerAndroid::scrollTo(int x, int y) SkScalar newX = SkScalarPin(x, scrollBounds.x(), scrollBounds.width()); SkScalar newY = SkScalarPin(y, scrollBounds.y(), scrollBounds.height()); // Check for no change. - if (isIFrame()) { - if (newX == m_iframeScrollOffset.x() && newY == m_iframeScrollOffset.y()) - return false; - newX = newX - m_iframeScrollOffset.x(); - newY = newY - m_iframeScrollOffset.y(); - } else { - if (newX == m_offset.x() && newY == m_offset.y()) - return false; - } + if (newX == m_offset.x() && newY == m_offset.y()) + return false; setScrollOffset(IntPoint(newX, newY)); return true; } @@ -46,16 +39,8 @@ void ScrollableLayerAndroid::getScrollBounds(IntRect* out) const void ScrollableLayerAndroid::getScrollRect(SkIRect* out) const { const SkPoint& pos = getPosition(); - out->fLeft = m_scrollLimits.fLeft - pos.fX; - out->fTop = m_scrollLimits.fTop - pos.fY; - - if (isIFrame()) { - out->fLeft += m_iframeScrollOffset.x(); - out->fTop += m_iframeScrollOffset.y(); - } else { - out->fLeft += m_offset.x(); - out->fTop += m_offset.y(); - } + out->fLeft = m_scrollLimits.fLeft - pos.fX + m_offset.x(); + out->fTop = m_scrollLimits.fTop - pos.fY + m_offset.y(); out->fRight = getSize().width() - m_scrollLimits.width(); out->fBottom = getSize().height() - m_scrollLimits.height(); diff --git a/Source/WebCore/platform/graphics/android/ScrollableLayerAndroid.h b/Source/WebCore/platform/graphics/android/ScrollableLayerAndroid.h index b8ff299..1f289e6 100644 --- a/Source/WebCore/platform/graphics/android/ScrollableLayerAndroid.h +++ b/Source/WebCore/platform/graphics/android/ScrollableLayerAndroid.h @@ -41,19 +41,20 @@ public: virtual bool contentIsScrollable() const { return true; } virtual LayerAndroid* copy() const { return new ScrollableLayerAndroid(*this); } + virtual SubclassType subclassType() { return LayerAndroid::ScrollableLayer; } virtual bool updateWithLayer(LayerAndroid*) { return true; } // Scrolls to the given position in the layer. // Returns whether or not any scrolling was required. - bool scrollTo(int x, int y); + virtual bool scrollTo(int x, int y); // Fills the rect with the current scroll offset and the maximum scroll offset. // fLeft = scrollX // fTop = scrollY // fRight = maxScrollX // fBottom = maxScrollY - void getScrollRect(SkIRect*) const; + virtual void getScrollRect(SkIRect*) const; void setScrollLimits(float x, float y, float width, float height) { @@ -68,9 +69,9 @@ public: bool scrollRectIntoView(const SkIRect&); friend void android::serializeLayer(LayerAndroid* layer, SkWStream* stream); - friend LayerAndroid* android::deserializeLayer(SkStream* stream); + friend LayerAndroid* android::deserializeLayer(int version, SkStream* stream); -private: +protected: void getScrollBounds(IntRect*) const; diff --git a/Source/WebCore/platform/graphics/android/SurfaceCollection.cpp b/Source/WebCore/platform/graphics/android/SurfaceCollection.cpp index 48e4f27..55fa51a 100644 --- a/Source/WebCore/platform/graphics/android/SurfaceCollection.cpp +++ b/Source/WebCore/platform/graphics/android/SurfaceCollection.cpp @@ -72,7 +72,9 @@ SurfaceCollection::SurfaceCollection(BaseLayerAndroid* baseLayer) // allocate groups for layers, merging where possible XLOG("new tree, allocating groups for tree %p", m_baseLayer); - m_compositedRoot->assignGroups(&m_layerGroups); + + LayerMergeState layerMergeState(&m_layerGroups); + m_compositedRoot->assignGroups(&layerMergeState); } #ifdef DEBUG_COUNT ClassTracker::instance()->increment("SurfaceCollection"); @@ -183,7 +185,7 @@ void SurfaceCollection::drawCanvas(SkCanvas* canvas, bool drawLayers) // draw the layers onto the same canvas (for single surface mode) if (drawLayers && m_compositedRoot) - m_compositedRoot->drawCanvas(canvas); + m_compositedRoot->drawCanvas(canvas, true, Layer::FlattenedLayers); } @@ -198,12 +200,20 @@ void SurfaceCollection::setIsPainting(SurfaceCollection* drawingSurface) m_baseLayer->setIsPainting(); - LayerAndroid* oldCompositedSurface = 0; - if (drawingSurface) - oldCompositedSurface = drawingSurface->m_compositedRoot; + if (!drawingSurface) + return; - if (m_compositedRoot) - m_compositedRoot->setIsPainting(oldCompositedSurface); + for (unsigned int i = 0; i < m_layerGroups.size(); i++) { + LayerGroup* newLayerGroup = m_layerGroups[i]; + if (!newLayerGroup->needsTexture()) + continue; + + for (unsigned int j = 0; j < drawingSurface->m_layerGroups.size(); j++) { + LayerGroup* oldLayerGroup = drawingSurface->m_layerGroups[j]; + if (newLayerGroup->tryUpdateLayerGroup(oldLayerGroup)) + break; + } + } } void SurfaceCollection::setIsDrawing() diff --git a/Source/WebCore/rendering/RenderLayer.h b/Source/WebCore/rendering/RenderLayer.h index 02ab8e9..5e421f0 100644 --- a/Source/WebCore/rendering/RenderLayer.h +++ b/Source/WebCore/rendering/RenderLayer.h @@ -498,6 +498,12 @@ public: bool hasOverflowScroll() const { return m_hasOverflowScroll; } bool hasOverflowParent() const; #endif +#if PLATFORM(ANDROID) + bool intrinsicallyComposited() const { return m_intrinsicallyComposited; } + void setIntrinsicallyComposited(bool intrinsicallyComposited) { + m_intrinsicallyComposited = intrinsicallyComposited; + } +#endif private: // The normal operator new is disallowed on all render objects. @@ -751,6 +757,9 @@ protected: bool m_shouldComposite : 1; #endif #endif +#if PLATFORM(ANDROID) + bool m_intrinsicallyComposited : 1; +#endif bool m_containsDirtyOverlayScrollbars : 1; #if ENABLE(ANDROID_OVERFLOW_SCROLL) diff --git a/Source/WebCore/rendering/RenderLayerCompositor.cpp b/Source/WebCore/rendering/RenderLayerCompositor.cpp index 25a08e7..d7f5c6b 100644 --- a/Source/WebCore/rendering/RenderLayerCompositor.cpp +++ b/Source/WebCore/rendering/RenderLayerCompositor.cpp @@ -682,7 +682,12 @@ void RenderLayerCompositor::computeCompositingRequirements(RenderLayer* layer, O layer->updateLayerPosition(); layer->updateZOrderLists(); layer->updateNormalFlowList(); - +#if PLATFORM(ANDROID) + RenderObject* renderer = layer->renderer(); + bool intCom = requiresCompositingLayer(layer); + layer->setIntrinsicallyComposited(intCom); +#endif + // Clear the flag layer->setHasCompositingDescendant(false); diff --git a/Source/WebKit/android/WebCoreSupport/ChromeClientAndroid.cpp b/Source/WebKit/android/WebCoreSupport/ChromeClientAndroid.cpp index 1328675..5e16152 100644 --- a/Source/WebKit/android/WebCoreSupport/ChromeClientAndroid.cpp +++ b/Source/WebKit/android/WebCoreSupport/ChromeClientAndroid.cpp @@ -161,8 +161,15 @@ void ChromeClientAndroid::focus() } void ChromeClientAndroid::unfocus() { notImplemented(); } -bool ChromeClientAndroid::canTakeFocus(FocusDirection) { notImplemented(); return false; } -void ChromeClientAndroid::takeFocus(FocusDirection) { notImplemented(); } +bool ChromeClientAndroid::canTakeFocus(FocusDirection direction) +{ + return android::WebViewCore::getWebViewCore(m_webFrame->page()->mainFrame()->view())->chromeCanTakeFocus(direction); +} + +void ChromeClientAndroid::takeFocus(FocusDirection direction) +{ + android::WebViewCore::getWebViewCore(m_webFrame->page()->mainFrame()->view())->chromeTakeFocus(direction); +} void ChromeClientAndroid::focusedNodeChanged(Node* node) { diff --git a/Source/WebKit/android/jni/AndroidHitTestResult.cpp b/Source/WebKit/android/jni/AndroidHitTestResult.cpp index 16dd809..9be5613 100644 --- a/Source/WebKit/android/jni/AndroidHitTestResult.cpp +++ b/Source/WebKit/android/jni/AndroidHitTestResult.cpp @@ -135,11 +135,15 @@ void AndroidHitTestResult::buildHighlightRects() node = m_hitTestResult.innerNode(); if (!node || !node->renderer()) return; + if (!WebViewCore::nodeIsClickableOrFocusable(node)) + return; Frame* frame = node->document()->frame(); IntPoint frameOffset = m_webViewCore->convertGlobalContentToFrameContent(IntPoint(), frame); RenderObject* renderer = node->renderer(); Vector<FloatQuad> quads; renderer->absoluteFocusRingQuads(quads); + if (!quads.size()) + renderer->absoluteQuads(quads); // No fancy rings, grab some backups for (size_t i = 0; i < quads.size(); i++) { IntRect boundingBox = quads[i].enclosingBoundingBox(); boundingBox.move(-frameOffset.x(), -frameOffset.y()); diff --git a/Source/WebKit/android/jni/ViewStateSerializer.cpp b/Source/WebKit/android/jni/ViewStateSerializer.cpp index 6b473f5..a96b6b4 100644 --- a/Source/WebKit/android/jni/ViewStateSerializer.cpp +++ b/Source/WebKit/android/jni/ViewStateSerializer.cpp @@ -27,7 +27,10 @@ #include "BaseLayerAndroid.h" #include "CreateJavaOutputStreamAdaptor.h" +#include "FixedPositioning.h" #include "ImagesManager.h" +#include "IFrameContentLayerAndroid.h" +#include "IFrameLayerAndroid.h" #include "Layer.h" #include "LayerAndroid.h" #include "PictureSet.h" @@ -49,6 +52,9 @@ #undef XLOG #define XLOG(...) +#undef XLOGC +#define XLOGC(...) android_printLog(ANDROID_LOG_DEBUG, "ViewStateSerializer", __VA_ARGS__) + #endif // DEBUG namespace android { @@ -57,6 +63,7 @@ enum LayerTypes { LTNone = 0, LTLayerAndroid = 1, LTScrollableLayerAndroid = 2, + LTFixedLayerAndroid = 3 }; static bool nativeSerializeViewState(JNIEnv* env, jobject, jint jbaseLayer, @@ -91,8 +98,8 @@ static bool nativeSerializeViewState(JNIEnv* env, jobject, jint jbaseLayer, return true; } -static BaseLayerAndroid* nativeDeserializeViewState(JNIEnv* env, jobject, jobject jstream, - jbyteArray jstorage) +static BaseLayerAndroid* nativeDeserializeViewState(JNIEnv* env, jobject, jint version, + jobject jstream, jbyteArray jstorage) { SkStream* stream = CreateJavaInputStreamAdaptor(env, jstream, jstorage); if (!stream) @@ -107,7 +114,7 @@ static BaseLayerAndroid* nativeDeserializeViewState(JNIEnv* env, jobject, jobjec SkSafeUnref(picture); int childCount = stream->readS32(); for (int i = 0; i < childCount; i++) { - LayerAndroid* childLayer = deserializeLayer(stream); + LayerAndroid* childLayer = deserializeLayer(version, stream); if (childLayer) layer->addChild(childLayer); } @@ -253,9 +260,9 @@ void serializeLayer(LayerAndroid* layer, SkWStream* stream) stream->write8(LTNone); return; } - LayerTypes type = layer->contentIsScrollable() - ? LTScrollableLayerAndroid - : LTLayerAndroid; + LayerTypes type = LTLayerAndroid; + if (layer->contentIsScrollable()) + type = LTScrollableLayerAndroid; stream->write8(type); // Start with Layer fields @@ -272,20 +279,43 @@ void serializeLayer(LayerAndroid* layer, SkWStream* stream) // Next up, LayerAndroid fields stream->writeBool(layer->m_haveClip); - stream->writeBool(layer->m_isFixed); + stream->writeBool(layer->isFixed()); stream->writeBool(layer->m_backgroundColorSet); - stream->writeBool(layer->m_isIframe); - writeSkLength(stream, layer->m_fixedLeft); - writeSkLength(stream, layer->m_fixedTop); - writeSkLength(stream, layer->m_fixedRight); - writeSkLength(stream, layer->m_fixedBottom); - writeSkLength(stream, layer->m_fixedMarginLeft); - writeSkLength(stream, layer->m_fixedMarginTop); - writeSkLength(stream, layer->m_fixedMarginRight); - writeSkLength(stream, layer->m_fixedMarginBottom); - writeSkRect(stream, layer->m_fixedRect); - stream->write32(layer->m_renderLayerPos.x()); - stream->write32(layer->m_renderLayerPos.y()); + stream->writeBool(layer->isIFrame()); + + // With the current LayerAndroid hierarchy, LayerAndroid doesn't have + // those fields anymore. Let's keep the current serialization format for + // now and output blank fields... not great, but probably better than + // dealing with multiple versions. + if (layer->fixedPosition()) { + FixedPositioning* fixedPosition = layer->fixedPosition(); + writeSkLength(stream, fixedPosition->m_fixedLeft); + writeSkLength(stream, fixedPosition->m_fixedTop); + writeSkLength(stream, fixedPosition->m_fixedRight); + writeSkLength(stream, fixedPosition->m_fixedBottom); + writeSkLength(stream, fixedPosition->m_fixedMarginLeft); + writeSkLength(stream, fixedPosition->m_fixedMarginTop); + writeSkLength(stream, fixedPosition->m_fixedMarginRight); + writeSkLength(stream, fixedPosition->m_fixedMarginBottom); + writeSkRect(stream, fixedPosition->m_fixedRect); + stream->write32(fixedPosition->m_renderLayerPos.x()); + stream->write32(fixedPosition->m_renderLayerPos.y()); + } else { + SkLength length; + SkRect rect; + writeSkLength(stream, length); // fixedLeft + writeSkLength(stream, length); // fixedTop + writeSkLength(stream, length); // fixedRight + writeSkLength(stream, length); // fixedBottom + writeSkLength(stream, length); // fixedMarginLeft + writeSkLength(stream, length); // fixedMarginTop + writeSkLength(stream, length); // fixedMarginRight + writeSkLength(stream, length); // fixedMarginBottom + writeSkRect(stream, rect); // fixedRect + stream->write32(0); // renderLayerPos.x() + stream->write32(0); // renderLayerPos.y() + } + stream->writeBool(layer->m_backfaceVisibility); stream->writeBool(layer->m_visible); stream->write32(layer->m_backgroundColor); @@ -327,7 +357,7 @@ void serializeLayer(LayerAndroid* layer, SkWStream* stream) serializeLayer(layer->getChild(i), stream); } -LayerAndroid* deserializeLayer(SkStream* stream) +LayerAndroid* deserializeLayer(int version, SkStream* stream) { int type = stream->readU8(); if (type == LTNone) @@ -354,20 +384,55 @@ LayerAndroid* deserializeLayer(SkStream* stream) // LayerAndroid fields layer->m_haveClip = stream->readBool(); - layer->m_isFixed = stream->readBool(); + + // Keep the legacy serialization/deserialization format... + bool isFixed = stream->readBool(); + layer->m_backgroundColorSet = stream->readBool(); - layer->m_isIframe = stream->readBool(); - layer->m_fixedLeft = readSkLength(stream); - layer->m_fixedTop = readSkLength(stream); - layer->m_fixedRight = readSkLength(stream); - layer->m_fixedBottom = readSkLength(stream); - layer->m_fixedMarginLeft = readSkLength(stream); - layer->m_fixedMarginTop = readSkLength(stream); - layer->m_fixedMarginRight = readSkLength(stream); - layer->m_fixedMarginBottom = readSkLength(stream); - layer->m_fixedRect = readSkRect(stream); - layer->m_renderLayerPos.setX(stream->readS32()); - layer->m_renderLayerPos.setY(stream->readS32()); + + bool isIframe = stream->readBool(); + // If we are a scrollable layer android, we are an iframe content + if (isIframe && type == LTScrollableLayerAndroid) { + IFrameContentLayerAndroid* iframeContent = new IFrameContentLayerAndroid(*layer); + layer->unref(); + layer = iframeContent; + } else if (isIframe) { // otherwise we are just the iframe (we use it to compute offset) + IFrameLayerAndroid* iframe = new IFrameLayerAndroid(*layer); + layer->unref(); + layer = iframe; + } + + if (isFixed) { + FixedPositioning* fixedPosition = new FixedPositioning(layer); + + fixedPosition->m_fixedLeft = readSkLength(stream); + fixedPosition->m_fixedTop = readSkLength(stream); + fixedPosition->m_fixedRight = readSkLength(stream); + fixedPosition->m_fixedBottom = readSkLength(stream); + fixedPosition->m_fixedMarginLeft = readSkLength(stream); + fixedPosition->m_fixedMarginTop = readSkLength(stream); + fixedPosition->m_fixedMarginRight = readSkLength(stream); + fixedPosition->m_fixedMarginBottom = readSkLength(stream); + fixedPosition->m_fixedRect = readSkRect(stream); + fixedPosition->m_renderLayerPos.setX(stream->readS32()); + fixedPosition->m_renderLayerPos.setY(stream->readS32()); + + layer->setFixedPosition(fixedPosition); + } else { + // Not a fixed element, bypass the values in the stream + readSkLength(stream); // fixedLeft + readSkLength(stream); // fixedTop + readSkLength(stream); // fixedRight + readSkLength(stream); // fixedBottom + readSkLength(stream); // fixedMarginLeft + readSkLength(stream); // fixedMarginTop + readSkLength(stream); // fixedMarginRight + readSkLength(stream); // fixedMarginBottom + readSkRect(stream); // fixedRect + stream->readS32(); // renderLayerPos.x() + stream->readS32(); // renderLayerPos.y() + } + layer->m_backfaceVisibility = stream->readBool(); layer->m_visible = stream->readBool(); layer->m_backgroundColor = stream->readU32(); @@ -404,7 +469,7 @@ LayerAndroid* deserializeLayer(SkStream* stream) } int childCount = stream->readU32(); for (int i = 0; i < childCount; i++) { - LayerAndroid *childLayer = deserializeLayer(stream); + LayerAndroid *childLayer = deserializeLayer(version, stream); if (childLayer) layer->addChild(childLayer); } @@ -419,7 +484,7 @@ LayerAndroid* deserializeLayer(SkStream* stream) static JNINativeMethod gSerializerMethods[] = { { "nativeSerializeViewState", "(ILjava/io/OutputStream;[B)Z", (void*) nativeSerializeViewState }, - { "nativeDeserializeViewState", "(Ljava/io/InputStream;[B)I", + { "nativeDeserializeViewState", "(ILjava/io/InputStream;[B)I", (void*) nativeDeserializeViewState }, }; diff --git a/Source/WebKit/android/jni/WebViewCore.cpp b/Source/WebKit/android/jni/WebViewCore.cpp index 41a8339..af25b3b 100644 --- a/Source/WebKit/android/jni/WebViewCore.cpp +++ b/Source/WebKit/android/jni/WebViewCore.cpp @@ -366,6 +366,8 @@ struct WebViewCore::JavaGlue { jmethodID m_selectAt; jmethodID m_initEditField; jmethodID m_updateMatchCount; + jmethodID m_chromeCanTakeFocus; + jmethodID m_chromeTakeFocus; AutoJObject object(JNIEnv* env) { // We hold a weak reference to the Java WebViewCore to avoid memeory // leaks due to circular references when WebView.destroy() is not @@ -482,6 +484,8 @@ WebViewCore::WebViewCore(JNIEnv* env, jobject javaWebViewCore, WebCore::Frame* m m_javaGlue->m_selectAt = GetJMethod(env, clazz, "selectAt", "(II)V"); m_javaGlue->m_initEditField = GetJMethod(env, clazz, "initEditField", "(ILjava/lang/String;IZZLjava/lang/String;IIII)V"); m_javaGlue->m_updateMatchCount = GetJMethod(env, clazz, "updateMatchCount", "(IILjava/lang/String;)V"); + m_javaGlue->m_chromeCanTakeFocus = GetJMethod(env, clazz, "chromeCanTakeFocus", "(I)Z"); + m_javaGlue->m_chromeTakeFocus = GetJMethod(env, clazz, "chromeTakeFocus", "(I)V"); env->DeleteLocalRef(clazz); env->SetIntField(javaWebViewCore, gWebViewCoreFields.m_nativeClass, (jint)this); @@ -1670,6 +1674,23 @@ void WebViewCore::selectText(int startX, int startY, int endX, int endY) sc->setSelection(selection); } +bool WebViewCore::nodeIsClickableOrFocusable(Node* node) +{ + if (!node) + return false; + if (node->disabled()) + return false; + if (!node->inDocument()) + return false; + if (!node->renderer() || node->renderer()->style()->visibility() != VISIBLE) + return false; + return node->supportsFocus() + || node->hasEventListeners(eventNames().clickEvent) + || node->hasEventListeners(eventNames().mousedownEvent) + || node->hasEventListeners(eventNames().mouseupEvent) + || node->hasEventListeners(eventNames().mouseoverEvent); +} + // get the highlight rectangles for the touch point (x, y) with the slop AndroidHitTestResult WebViewCore::hitTestAtPoint(int x, int y, int slop, bool doMoveMouse) { @@ -1711,11 +1732,7 @@ AndroidHitTestResult WebViewCore::hitTestAtPoint(int x, int y, int slop, bool do RenderObject* render = eventNode->renderer(); if (render && (render->isBody() || render->isRenderView())) break; - if (eventNode->supportsFocus() - || eventNode->hasEventListeners(eventNames().clickEvent) - || eventNode->hasEventListeners(eventNames().mousedownEvent) - || eventNode->hasEventListeners(eventNames().mouseupEvent) - || eventNode->hasEventListeners(eventNames().mouseoverEvent)) { + if (nodeIsClickableOrFocusable(eventNode)) { found = true; break; } @@ -1816,15 +1833,15 @@ AndroidHitTestResult WebViewCore::hitTestAtPoint(int x, int y, int slop, bool do } // now get the node's highlight rectangles in the page coordinate system if (final.mUrlNode) { + // Update innerNode and innerNonSharedNode + androidHitResult.hitTestResult().setInnerNode(final.mInnerNode); + androidHitResult.hitTestResult().setInnerNonSharedNode(final.mInnerNode); if (final.mUrlNode->isElementNode()) { // We found a URL element. Update the hitTestResult androidHitResult.setURLElement(static_cast<Element*>(final.mUrlNode)); } else { androidHitResult.setURLElement(0); } - // Update innerNode and innerNonSharedNode - androidHitResult.hitTestResult().setInnerNode(final.mInnerNode); - androidHitResult.hitTestResult().setInnerNonSharedNode(final.mInnerNode); IntPoint frameAdjust; if (frame != m_mainFrame) { frameAdjust = frame->view()->contentsToWindow(IntPoint()); @@ -2990,6 +3007,24 @@ bool WebViewCore::key(const PlatformKeyboardEvent& event) return eventHandler->keyEvent(event); } +bool WebViewCore::chromeCanTakeFocus(FocusDirection direction) +{ + JNIEnv* env = JSC::Bindings::getJNIEnv(); + AutoJObject javaObject = m_javaGlue->object(env); + if (!javaObject.get()) + return false; + return env->CallBooleanMethod(javaObject.get(), m_javaGlue->m_chromeCanTakeFocus, direction); +} + +void WebViewCore::chromeTakeFocus(FocusDirection direction) +{ + JNIEnv* env = JSC::Bindings::getJNIEnv(); + AutoJObject javaObject = m_javaGlue->object(env); + if (!javaObject.get()) + return; + env->CallVoidMethod(javaObject.get(), m_javaGlue->m_chromeTakeFocus, direction); +} + // For when the user clicks the trackball, presses dpad center, or types into an // unfocused textfield. In the latter case, 'fake' will be true void WebViewCore::click(WebCore::Frame* frame, WebCore::Node* node, bool fake) { diff --git a/Source/WebKit/android/jni/WebViewCore.h b/Source/WebKit/android/jni/WebViewCore.h index 4cbc566..c5704e0 100644 --- a/Source/WebKit/android/jni/WebViewCore.h +++ b/Source/WebKit/android/jni/WebViewCore.h @@ -29,6 +29,7 @@ #include "DeviceMotionAndOrientationManager.h" #include "DOMSelection.h" #include "FileChooser.h" +#include "FocusDirection.h" #include "HitTestResult.h" #include "PictureSet.h" #include "PlatformGraphicsContext.h" @@ -318,6 +319,8 @@ namespace android { * @return Whether keyCode was handled by this class. */ bool key(const WebCore::PlatformKeyboardEvent& event); + bool chromeCanTakeFocus(FocusDirection direction); + void chromeTakeFocus(FocusDirection direction); /** * Handle (trackball) click event / dpad center press from Java. @@ -509,6 +512,7 @@ namespace android { Node** node, HitTestResult* hitTestResult); // This does a sloppy hit test AndroidHitTestResult hitTestAtPoint(int x, int y, int slop, bool doMoveMouse = false); + static bool nodeIsClickableOrFocusable(Node* node); // Open a file chooser for selecting a file to upload void openFileChooser(PassRefPtr<WebCore::FileChooser> ); diff --git a/Source/WebKit/android/nav/WebView.cpp b/Source/WebKit/android/nav/WebView.cpp index 830ef4e..8b7acc5 100644 --- a/Source/WebKit/android/nav/WebView.cpp +++ b/Source/WebKit/android/nav/WebView.cpp @@ -313,7 +313,7 @@ PictureSet* draw(SkCanvas* canvas, SkColor bgColor, DrawExtras extras, bool spli if (compositeLayer) { // call this to be sure we've adjusted for any scrolling or animations // before we actually draw - compositeLayer->updateFixedLayersPositions(m_visibleRect); + compositeLayer->updateLayerPositions(m_visibleRect); compositeLayer->updatePositions(); // We have to set the canvas' matrix on the base layer // (to have fixed layers work as intended) |
