diff options
Diffstat (limited to 'Source/WebCore/platform')
52 files changed, 845 insertions, 638 deletions
diff --git a/Source/WebCore/platform/android/RenderThemeAndroid.cpp b/Source/WebCore/platform/android/RenderThemeAndroid.cpp index 173cfea..86380e7 100644 --- a/Source/WebCore/platform/android/RenderThemeAndroid.cpp +++ b/Source/WebCore/platform/android/RenderThemeAndroid.cpp @@ -439,10 +439,8 @@ void RenderThemeAndroid::adjustSliderThumbSize(RenderObject* o) const { static const int sliderThumbWidth = RenderSkinMediaButton::sliderThumbWidth(); static const int sliderThumbHeight = RenderSkinMediaButton::sliderThumbHeight(); - if (o->style()->appearance() == MediaSliderThumbPart) { - o->style()->setWidth(Length(sliderThumbWidth, Fixed)); - o->style()->setHeight(Length(sliderThumbHeight, Fixed)); - } + o->style()->setWidth(Length(sliderThumbWidth, Fixed)); + o->style()->setHeight(Length(sliderThumbHeight, Fixed)); } #endif @@ -647,6 +645,30 @@ bool RenderThemeAndroid::paintMenuListButton(RenderObject* obj, const PaintInfo& return paintCombo(obj, info, rect); } +bool RenderThemeAndroid::paintSliderTrack(RenderObject* o, const PaintInfo& i, const IntRect& r) +{ + SkCanvas* canvas = getCanvasFromInfo(i); + if (!canvas) + return true; + static const bool translucent = true; + RenderSkinMediaButton::Draw(canvas, r, + RenderSkinMediaButton::SLIDER_TRACK, + translucent, o, false); + return false; +} + +bool RenderThemeAndroid::paintSliderThumb(RenderObject* o, const PaintInfo& i, const IntRect& r) +{ + SkCanvas* canvas = getCanvasFromInfo(i); + if (!canvas) + return true; + static const bool translucent = true; + RenderSkinMediaButton::Draw(canvas, r, + RenderSkinMediaButton::SLIDER_THUMB, + translucent, 0, false); + return false; +} + Color RenderThemeAndroid::platformFocusRingColor() const { static Color focusRingColor(0x33, 0xB5, 0xE5, 0x66); diff --git a/Source/WebCore/platform/android/RenderThemeAndroid.h b/Source/WebCore/platform/android/RenderThemeAndroid.h index ed4d07f..06d272b 100644 --- a/Source/WebCore/platform/android/RenderThemeAndroid.h +++ b/Source/WebCore/platform/android/RenderThemeAndroid.h @@ -118,6 +118,9 @@ protected: virtual void adjustSearchFieldStyle(CSSStyleSelector*, RenderStyle*, Element*) const; virtual bool paintSearchField(RenderObject*, const PaintInfo&, const IntRect&); + virtual bool paintSliderTrack(RenderObject*, const PaintInfo&, const IntRect&); + virtual bool paintSliderThumb(RenderObject*, const PaintInfo&, const IntRect&); + private: RenderThemeAndroid(); void addIntrinsicMargins(RenderStyle*) const; diff --git a/Source/WebCore/platform/android/ScrollViewAndroid.cpp b/Source/WebCore/platform/android/ScrollViewAndroid.cpp index ecaa2b5..cc1c09e 100644 --- a/Source/WebCore/platform/android/ScrollViewAndroid.cpp +++ b/Source/WebCore/platform/android/ScrollViewAndroid.cpp @@ -103,13 +103,7 @@ void ScrollView::platformOffscreenContentRectangle(const IntRect& vis, const Int android::WebViewCore* core = android::WebViewCore::getWebViewCore(this); if (!core) // SVG does not instantiate webviewcore return; // and doesn't need to record drawing offscreen - SkRegion rectRgn = SkRegion(rect); - rectRgn.op(vis, SkRegion::kDifference_Op); - SkRegion::Iterator iter(rectRgn); - for (; !iter.done(); iter.next()) { - const SkIRect& diff = iter.rect(); - core->offInvalidate(diff); - } + core->offInvalidate(rect); } #endif diff --git a/Source/WebCore/platform/android/WidgetAndroid.cpp b/Source/WebCore/platform/android/WidgetAndroid.cpp index 0f7758d..6858f29 100644 --- a/Source/WebCore/platform/android/WidgetAndroid.cpp +++ b/Source/WebCore/platform/android/WidgetAndroid.cpp @@ -59,10 +59,6 @@ void Widget::setFocus(bool focused) void Widget::paint(GraphicsContext* ctx, const IntRect& r) { - // FIXME: in what case, will this be called for the top frame? - if (!platformWidget()) - return; - platformWidget()->draw(ctx, r); } void Widget::releasePlatformWidget() diff --git a/Source/WebCore/platform/graphics/android/GLWebViewState.cpp b/Source/WebCore/platform/graphics/android/GLWebViewState.cpp index a52a3fe..bdd8028 100644 --- a/Source/WebCore/platform/graphics/android/GLWebViewState.cpp +++ b/Source/WebCore/platform/graphics/android/GLWebViewState.cpp @@ -65,14 +65,14 @@ using namespace android; GLWebViewState::GLWebViewState() : m_frameworkLayersInval(0, 0, 0, 0) , m_isScrolling(false) - , m_isViewportScrolling(false) + , m_isVisibleContentRectScrolling(false) , m_goingDown(true) , m_goingLeft(false) , m_scale(1) , m_layersRenderingMode(kAllTextures) , m_surfaceCollectionManager() { - m_viewport.setEmpty(); + m_visibleContentRect.setEmpty(); #ifdef DEBUG_COUNT ClassTracker::instance()->increment("GLWebViewState"); @@ -123,39 +123,43 @@ void GLWebViewState::scrollLayer(int layerId, int x, int y) m_surfaceCollectionManager.updateScrollableLayer(layerId, x, y); } -void GLWebViewState::setViewport(const SkRect& viewport, float scale) +void GLWebViewState::setVisibleContentRect(const SkRect& visibleContentRect, float scale) { - // allocate max possible number of tiles visible with this viewport / expandedTileBounds + // allocate max possible number of tiles visible with this visibleContentRect / expandedTileBounds const float invTileContentWidth = scale / TilesManager::tileWidth(); const float invTileContentHeight = scale / TilesManager::tileHeight(); - int viewMaxTileX = static_cast<int>(ceilf((viewport.width()-1) * invTileContentWidth)) + 1; - int viewMaxTileY = static_cast<int>(ceilf((viewport.height()-1) * invTileContentHeight)) + 1; + int viewMaxTileX = + static_cast<int>(ceilf((visibleContentRect.width()-1) * invTileContentWidth)) + 1; + int viewMaxTileY = + static_cast<int>(ceilf((visibleContentRect.height()-1) * invTileContentHeight)) + 1; TilesManager* tilesManager = TilesManager::instance(); int maxTextureCount = viewMaxTileX * viewMaxTileY * (tilesManager->highEndGfx() ? 4 : 2); - tilesManager->setMaxTextureCount(maxTextureCount); + tilesManager->setCurrentTextureCount(maxTextureCount); // TODO: investigate whether we can move this return earlier. - if ((m_viewport == viewport) + if ((m_visibleContentRect == visibleContentRect) && (m_scale == scale)) { // everything below will stay the same, early return. - m_isViewportScrolling = false; + m_isVisibleContentRectScrolling = false; return; } m_scale = scale; - m_goingDown = m_viewport.fTop - viewport.fTop <= 0; - m_goingLeft = m_viewport.fLeft - viewport.fLeft >= 0; + m_goingDown = m_visibleContentRect.fTop - visibleContentRect.fTop <= 0; + m_goingLeft = m_visibleContentRect.fLeft - visibleContentRect.fLeft >= 0; - // detect viewport scrolling from short programmatic scrolls/jumps - m_isViewportScrolling = m_viewport != viewport && SkRect::Intersects(m_viewport, viewport); - m_viewport = viewport; + // detect visibleContentRect scrolling from short programmatic scrolls/jumps + m_isVisibleContentRectScrolling = m_visibleContentRect != visibleContentRect + && SkRect::Intersects(m_visibleContentRect, visibleContentRect); + m_visibleContentRect = visibleContentRect; - ALOGV("New VIEWPORT %.2f - %.2f %.2f - %.2f (w: %2.f h: %.2f scale: %.2f )", - m_viewport.fLeft, m_viewport.fTop, m_viewport.fRight, m_viewport.fBottom, - m_viewport.width(), m_viewport.height(), scale); + ALOGV("New visibleContentRect %.2f - %.2f %.2f - %.2f (w: %2.f h: %.2f scale: %.2f )", + m_visibleContentRect.fLeft, m_visibleContentRect.fTop, + m_visibleContentRect.fRight, m_visibleContentRect.fBottom, + m_visibleContentRect.width(), m_visibleContentRect.height(), scale); } #ifdef MEASURES_PERF @@ -192,8 +196,9 @@ void GLWebViewState::resetLayersDirtyArea() m_frameworkLayersInval.setHeight(0); } -double GLWebViewState::setupDrawing(const IntRect& viewRect, const SkRect& visibleRect, - const IntRect& webViewRect, int titleBarHeight, +double GLWebViewState::setupDrawing(const IntRect& invScreenRect, + const SkRect& visibleContentRect, + const IntRect& screenRect, int titleBarHeight, const IntRect& screenClip, float scale) { TilesManager* tilesManager = TilesManager::instance(); @@ -212,12 +217,12 @@ double GLWebViewState::setupDrawing(const IntRect& viewRect, const SkRect& visib transferQueue->initGLResources(TilesManager::tileWidth(), TilesManager::tileHeight()); } - shader->setupDrawing(viewRect, visibleRect, webViewRect, + shader->setupDrawing(invScreenRect, visibleContentRect, screenRect, titleBarHeight, screenClip, scale); double currentTime = WTF::currentTime(); - setViewport(visibleRect, scale); + setVisibleContentRect(visibleContentRect, scale); return currentTime; } @@ -227,11 +232,11 @@ bool GLWebViewState::setLayersRenderingMode(TexturesResult& nbTexturesNeeded) bool invalBase = false; if (!nbTexturesNeeded.full) - TilesManager::instance()->setMaxLayerTextureCount(0); + TilesManager::instance()->setCurrentLayerTextureCount(0); else - TilesManager::instance()->setMaxLayerTextureCount((2*nbTexturesNeeded.full)+1); + TilesManager::instance()->setCurrentLayerTextureCount((2 * nbTexturesNeeded.full) + 1); - int maxTextures = TilesManager::instance()->maxLayerTextureCount(); + int maxTextures = TilesManager::instance()->currentLayerTextureCount(); LayersRenderingMode layersRenderingMode = m_layersRenderingMode; if (m_layersRenderingMode == kSingleSurfaceRendering) { @@ -287,36 +292,39 @@ bool GLWebViewState::setLayersRenderingMode(TexturesResult& nbTexturesNeeded) return (m_layersRenderingMode != layersRenderingMode && invalBase); } -// -rect(viewRect) is the webViewRect with inverted Y, in screen coordinate. -// -viewport(visibleRect) is the visible area in document coordinate. -// They are both based on webViewRect and calculated in Java side. +// -invScreenRect is the webView's rect with inverted Y screen coordinate. +// -visibleContentRect is the visible area in content coordinate. +// They are both based on webView's rect and calculated in Java side. // -// -clip is the final glViewport value in screen coordinate, and it contains the -// animation translation/scale and FBO offset. +// -screenClip is in screen coordinate, so we need to invert the Y axis before +// passing into GL functions. Clip can be smaller than the webView's rect. // // TODO: Try to decrease the number of parameters as some info is redundant. -int GLWebViewState::drawGL(IntRect& rect, SkRect& viewport, IntRect* invalRect, - IntRect& webViewRect, int titleBarHeight, - IntRect& clip, float scale, +int GLWebViewState::drawGL(IntRect& invScreenRect, SkRect& visibleContentRect, + IntRect* invalRect, IntRect& screenRect, int titleBarHeight, + IntRect& screenClip, float scale, bool* collectionsSwappedPtr, bool* newCollectionHasAnimPtr, bool shouldDraw) { TilesManager* tilesManager = TilesManager::instance(); if (shouldDraw) - tilesManager->getProfiler()->nextFrame(viewport.fLeft, viewport.fTop, - viewport.fRight, viewport.fBottom, + tilesManager->getProfiler()->nextFrame(visibleContentRect.fLeft, + visibleContentRect.fTop, + visibleContentRect.fRight, + visibleContentRect.fBottom, scale); tilesManager->incDrawGLCount(); - ALOGV("drawGL, rect/viewRect(%d, %d, %d, %d), viewport/visibleRect(%.2f, %.2f, %.2f, %.2f)", - rect.x(), rect.y(), rect.width(), rect.height(), - viewport.fLeft, viewport.fTop, viewport.fRight, viewport.fBottom); + ALOGV("drawGL, invScreenRect(%d, %d, %d, %d), visibleContentRect(%.2f, %.2f, %.2f, %.2f)", + invScreenRect.x(), invScreenRect.y(), invScreenRect.width(), invScreenRect.height(), + visibleContentRect.fLeft, visibleContentRect.fTop, + visibleContentRect.fRight, visibleContentRect.fBottom); - ALOGV("drawGL, invalRect(%d, %d, %d, %d), webViewRect(%d, %d, %d, %d)" - "clip/glViewport (%d, %d, %d, %d), scale %f titleBarHeight %d", + ALOGV("drawGL, invalRect(%d, %d, %d, %d), screenRect(%d, %d, %d, %d)" + "screenClip (%d, %d, %d, %d), scale %f titleBarHeight %d", invalRect->x(), invalRect->y(), invalRect->width(), invalRect->height(), - webViewRect.x(), webViewRect.y(), webViewRect.width(), webViewRect.height(), - clip.x(), clip.y(), clip.width(), clip.height(), scale, titleBarHeight); + screenRect.x(), screenRect.y(), screenRect.width(), screenRect.height(), + screenClip.x(), screenClip.y(), screenClip.width(), screenClip.height(), scale, titleBarHeight); resetLayersDirtyArea(); @@ -334,20 +342,23 @@ int GLWebViewState::drawGL(IntRect& rect, SkRect& viewport, IntRect* invalRect, if (scale < MIN_SCALE_WARNING || scale > MAX_SCALE_WARNING) { ALOGW("WARNING, scale seems corrupted after update: %e", scale); - CRASH(); + scale = 1.0f; // WORKAROUND for corrupted scale: use 1.0 } // gather the textures we can use tilesManager->gatherTextures(); - double currentTime = setupDrawing(rect, viewport, webViewRect, titleBarHeight, clip, scale); + double currentTime = setupDrawing(invScreenRect, visibleContentRect, screenRect, + titleBarHeight, screenClip, scale); TexturesResult nbTexturesNeeded; bool fastSwap = isScrolling() || m_layersRenderingMode == kSingleSurfaceRendering; - m_glExtras.setViewport(viewport); - returnFlags |= m_surfaceCollectionManager.drawGL(currentTime, rect, viewport, + m_glExtras.setVisibleContentRect(visibleContentRect); + returnFlags |= m_surfaceCollectionManager.drawGL(currentTime, invScreenRect, + visibleContentRect, scale, fastSwap, - collectionsSwappedPtr, newCollectionHasAnimPtr, + collectionsSwappedPtr, + newCollectionHasAnimPtr, &nbTexturesNeeded, shouldDraw); int nbTexturesForImages = ImagesManager::instance()->nbTextures(); @@ -380,7 +391,7 @@ int GLWebViewState::drawGL(IntRect& rect, SkRect& viewport, IntRect* invalRect, ALOGV("invalRect(%d, %d, %d, %d)", inval.x(), inval.y(), inval.width(), inval.height()); - if (!invalRect->intersects(rect)) { + if (!invalRect->intersects(invScreenRect)) { // invalidate is occurring offscreen, do full inval to guarantee redraw fullScreenInval = true; } @@ -395,7 +406,7 @@ int GLWebViewState::drawGL(IntRect& rect, SkRect& viewport, IntRect* invalRect, } if (shouldDraw) - showFrameInfo(rect, *collectionsSwappedPtr); + showFrameInfo(invScreenRect, *collectionsSwappedPtr); return returnFlags; } diff --git a/Source/WebCore/platform/graphics/android/GLWebViewState.h b/Source/WebCore/platform/graphics/android/GLWebViewState.h index 2b28619..7892e83 100644 --- a/Source/WebCore/platform/graphics/android/GLWebViewState.h +++ b/Source/WebCore/platform/graphics/android/GLWebViewState.h @@ -75,7 +75,7 @@ class TexturesResult; // // The rendering model is to use tiles to display the BaseLayer (as obviously a // BaseLayer's area can be arbitrarly large). The idea is to compute a set of -// tiles covering the viewport's area, paint those tiles using the webview's +// tiles covering the visibleContentRect's area, paint those tiles using the webview's // content (i.e. the BaseLayer's PictureSet), then display those tiles. // We check which tile we should use at every frame. // @@ -86,7 +86,7 @@ class TexturesResult; // the BaseLayer's surface. When drawing, we ask the TiledPage to prepare() // itself then draw itself on screen. The prepare() function is the one // that schedules tiles to be painted -- i.e. the subset of tiles that intersect -// with the current viewport. When they are ready, we can display +// with the current visibleContentRect. When they are ready, we can display // the TiledPage. // // Note that BaseLayerAndroid::drawGL() will return true to the java side if @@ -102,7 +102,7 @@ class TexturesResult; // accordingly (and therefore possible loss of quality): this is fast as it's // purely a hardware operation. When the user is done zooming, we ask for // TiledPage B to be painted at the new scale factor, covering the -// viewport's area. When B is ready, we swap it with A. +// visibleContentRect's area. When B is ready, we swap it with A. // // Texture allocation // ------------------ @@ -111,17 +111,17 @@ class TexturesResult; // get the GL textures from an existing pool, and reuse them. // // The way we do it is that when we call TiledPage::prepare(), we group the -// tiles we need (i.e. in the viewport and dirty) into a TilesSet and call +// tiles we need (i.e. in the visibleContentRect and dirty) into a TilesSet and call // Tile::reserveTexture() for each tile (which ensures there is a specific // GL textures backing the Tiles). // // reserveTexture() will ask the TilesManager for a texture. The allocation // mechanism goal is to (in order): // - prefers to allocate the same texture as the previous time -// - prefers to allocate textures that are as far from the viewport as possible +// - prefers to allocate textures that are as far from the visibleContentRect as possible // - prefers to allocate textures that are used by different TiledPages // -// Note that to compute the distance of each tile from the viewport, each time +// Note that to compute the distance of each tile from the visibleContentRect, each time // we prepare() a TiledPage. Also during each prepare() we compute which tiles // are dirty based on the info we have received from webkit. // @@ -173,12 +173,12 @@ public: GLExtras* glExtras() { return &m_glExtras; } void setIsScrolling(bool isScrolling) { m_isScrolling = isScrolling; } - bool isScrolling() { return m_isScrolling || m_isViewportScrolling; } + bool isScrolling() { return m_isScrolling || m_isVisibleContentRectScrolling; } bool setLayersRenderingMode(TexturesResult&); - int drawGL(IntRect& rect, SkRect& viewport, IntRect* invalRect, - IntRect& webViewRect, int titleBarHeight, + int drawGL(IntRect& rect, SkRect& visibleContentRect, IntRect* invalRect, + IntRect& screenRect, int titleBarHeight, IntRect& clip, float scale, bool* collectionsSwappedPtr, bool* newCollectionHasAnimPtr, bool shouldDraw); @@ -208,16 +208,16 @@ public: void scrollLayer(int layerId, int x, int y); private: - void setViewport(const SkRect& viewport, float scale); - double setupDrawing(const IntRect& viewRect, const SkRect& visibleRect, - const IntRect& webViewRect, int titleBarHeight, + void setVisibleContentRect(const SkRect& visibleContentRect, float scale); + double setupDrawing(const IntRect& invScreenRect, const SkRect& visibleContentRect, + const IntRect& screenRect, int titleBarHeight, const IntRect& screenClip, float scale); void showFrameInfo(const IntRect& rect, bool collectionsSwapped); void clearRectWithColor(const IntRect& rect, float r, float g, float b, float a); double m_prevDrawTime; - SkRect m_viewport; + SkRect m_visibleContentRect; IntRect m_frameworkLayersInval; #ifdef MEASURES_PERF @@ -229,7 +229,7 @@ private: GLExtras m_glExtras; bool m_isScrolling; - bool m_isViewportScrolling; + bool m_isVisibleContentRectScrolling; bool m_goingDown; bool m_goingLeft; diff --git a/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp b/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp index 381f0b1..8b30d9d 100644 --- a/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp +++ b/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp @@ -120,7 +120,6 @@ GraphicsLayerAndroid::GraphicsLayerAndroid(GraphicsLayerClient* client) : m_haveContents(false), m_newImage(false), m_image(0), - m_backgroundDecorationsLayer(0), m_fixedBackgroundLayer(0), m_foregroundLayer(0), m_foregroundClipLayer(0) @@ -141,7 +140,6 @@ GraphicsLayerAndroid::~GraphicsLayerAndroid() m_image->deref(); m_contentLayer->unref(); - SkSafeUnref(m_backgroundDecorationsLayer); SkSafeUnref(m_fixedBackgroundLayer); SkSafeUnref(m_foregroundLayer); SkSafeUnref(m_foregroundClipLayer); @@ -601,7 +599,6 @@ void GraphicsLayerAndroid::updateFixedBackgroundLayers() { // m_contentLayer // \- m_foregroundClipLayer // \- m_fixedBackgroundLayer - // \- m_backgroundDecorationsLayer // \- m_foregroundLayer // Grab the background image and create a layer for it @@ -617,14 +614,11 @@ void GraphicsLayerAndroid::updateFixedBackgroundLayers() { m_fixedBackgroundLayer->setContentsImage(image->nativeImageForCurrentFrame()); m_fixedBackgroundLayer->setSize(image->width(), image->height()); - // TODO: add support for the correct CSS position attributes - // for now, just pin to left(0) top(0) - FixedPositioning* fixedPosition = new FixedPositioning(m_fixedBackgroundLayer); SkRect viewRect; SkLength left, top, right, bottom; - left.setFixedValue(0); - top.setFixedValue(0); + left = convertLength(view->style()->backgroundXPosition()); + top = convertLength(view->style()->backgroundYPosition()); right.setAuto(); bottom.setAuto(); SkLength marginLeft, marginTop, marginRight, marginBottom; @@ -633,6 +627,13 @@ void GraphicsLayerAndroid::updateFixedBackgroundLayers() { marginRight.setAuto(); marginBottom.setAuto(); + Color color = view->style()->visitedDependentColor(CSSPropertyBackgroundColor); + SkColor skiaColor = SkColorSetARGB(color.alpha(), + color.red(), + color.green(), + color.blue()); + m_fixedBackgroundLayer->setBackgroundColor(skiaColor); + viewRect.set(0, 0, view->width(), view->height()); fixedPosition->setFixedPosition(left, top, right, bottom, marginLeft, marginTop, @@ -652,11 +653,8 @@ void GraphicsLayerAndroid::updateFixedBackgroundLayers() { // allow to paint background and foreground separately. For now, we'll create // two layers; the one containing the background will be painted *without* the // background image (but with the decorations, e.g. border) - // TODO: use a single layer with a new type of content (joining background/foreground?) - m_backgroundDecorationsLayer = new LayerAndroid(renderLayer); - m_backgroundDecorationsLayer->setIntrinsicallyComposited(true); m_foregroundLayer = new LayerAndroid(renderLayer); - m_foregroundLayer->setIntrinsicallyComposited(false); + m_foregroundLayer->setIntrinsicallyComposited(true); // Finally, let's assemble all the layers under a FixedBackgroundLayerAndroid layer LayerAndroid* layer = new FixedBackgroundLayerAndroid(*m_contentLayer); @@ -664,7 +662,6 @@ void GraphicsLayerAndroid::updateFixedBackgroundLayers() { m_contentLayer = layer; m_contentLayer->addChild(m_foregroundClipLayer); - m_contentLayer->addChild(m_backgroundDecorationsLayer); m_contentLayer->addChild(m_foregroundLayer); m_needsRepaint = true; @@ -756,22 +753,32 @@ bool GraphicsLayerAndroid::repaint() region.setRect(0, 0, contentsRect.width(), contentsRect.height()); m_foregroundLayer->markAsDirty(region); } else if (m_contentLayer->isFixedBackground()) { - PaintingPhase phase(this); - // Paint the background into a separate context. - ALOGV("paint background of layer %d (%d x %d)", m_contentLayer->uniqueId(), - layerBounds.width(), layerBounds.height()); - - m_backgroundDecorationsLayer->setSize(layerBounds.width(), layerBounds.height()); - phase.set(GraphicsLayerPaintBackgroundDecorations); - paintContext(m_backgroundDecorationsLayer, layerBounds); - phase.clear(GraphicsLayerPaintBackgroundDecorations); + SkPicture* picture = new SkPicture(); + SkCanvas* canvas = picture->beginRecording(layerBounds.width(), + layerBounds.height(), 0); + if (canvas) { + PaintingPhase phase(this); + PlatformGraphicsContextSkia platformContext(canvas); + GraphicsContext graphicsContext(&platformContext); + + // Paint the background (without the fixed image)... + phase.set(GraphicsLayerPaintBackgroundDecorations); + paintGraphicsLayerContents(graphicsContext, layerBounds); + phase.clear(GraphicsLayerPaintBackgroundDecorations); + + // Paint the foreground... + phase.set(GraphicsLayerPaintForeground); + paintGraphicsLayerContents(graphicsContext, layerBounds); + picture->endRecording(); + + // Now set the content for that layer. + PictureLayerContent* layerContent = new PictureLayerContent(picture); + m_foregroundLayer->setContent(layerContent); + SkSafeUnref(layerContent); + } + SkSafeUnref(picture); - // Paint the foreground into a separate context. - ALOGV("paint foreground of layer %d", m_contentLayer->uniqueId()); m_foregroundLayer->setSize(layerBounds.width(), layerBounds.height()); - phase.set(GraphicsLayerPaintForeground); - paintContext(m_foregroundLayer, layerBounds); - m_foregroundClipLayer->setPosition(layerBounds.x(), layerBounds.y()); m_foregroundClipLayer->setSize(layerBounds.width(), layerBounds.height()); } else { @@ -817,18 +824,14 @@ bool GraphicsLayerAndroid::repaint() return false; } -bool GraphicsLayerAndroid::paintContext(LayerAndroid* layer, - const IntRect& rect) +SkPicture* GraphicsLayerAndroid::paintPicture(const IntRect& rect) { - if (!layer) - return false; - SkPicture* picture = new SkPicture(); SkCanvas* canvas = picture->beginRecording(rect.width(), rect.height(), 0); if (!canvas) { picture->endRecording(); SkSafeUnref(picture); - return false; + return 0; } PlatformGraphicsContextSkia platformContext(canvas); @@ -836,6 +839,18 @@ bool GraphicsLayerAndroid::paintContext(LayerAndroid* layer, paintGraphicsLayerContents(graphicsContext, rect); + return picture; +} + +bool GraphicsLayerAndroid::paintContext(LayerAndroid* layer, + const IntRect& rect) +{ + if (!layer) + return false; + + SkPicture* picture = paintPicture(rect); + if (!picture) + return false; picture->endRecording(); PictureLayerContent* layerContent = new PictureLayerContent(picture); @@ -1107,7 +1122,6 @@ void GraphicsLayerAndroid::syncChildren() if (m_contentLayer->isFixedBackground()) { m_contentLayer->addChild(m_foregroundClipLayer); - m_contentLayer->addChild(m_backgroundDecorationsLayer); m_contentLayer->addChild(m_foregroundLayer); layer = m_foregroundLayer; layer->removeChildren(); diff --git a/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.h b/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.h index 24ba2d8..a912f57 100644 --- a/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.h +++ b/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.h @@ -145,6 +145,7 @@ private: bool repaint(); void needsNotifyClient(); + SkPicture* paintPicture(const IntRect& rect); bool paintContext(LayerAndroid* layer, const IntRect& rect); bool m_needsSyncChildren; @@ -159,7 +160,6 @@ private: SkRegion m_dirtyRegion; LayerAndroid* m_contentLayer; - LayerAndroid* m_backgroundDecorationsLayer; LayerAndroid* m_fixedBackgroundLayer; LayerAndroid* m_foregroundLayer; LayerAndroid* m_foregroundClipLayer; diff --git a/Source/WebCore/platform/graphics/android/layers/BaseLayerAndroid.cpp b/Source/WebCore/platform/graphics/android/layers/BaseLayerAndroid.cpp index bc3b04b..4f89dc9 100644 --- a/Source/WebCore/platform/graphics/android/layers/BaseLayerAndroid.cpp +++ b/Source/WebCore/platform/graphics/android/layers/BaseLayerAndroid.cpp @@ -69,6 +69,14 @@ IFrameLayerAndroid* BaseLayerAndroid::updatePosition(SkRect viewport, return LayerAndroid::updatePosition(viewport, parentIframeLayer); } +void BaseLayerAndroid::updatePositionsRecursive(const SkRect& visibleContentRect) +{ + updateLayerPositions(visibleContentRect); + TransformationMatrix ident; + FloatRect clip(0, 0, 1e10, 1e10); + updateGLPositionsAndScale(ident, clip, 1, state()->scale()); +} + ForegroundBaseLayerAndroid::ForegroundBaseLayerAndroid(LayerContent* content) : LayerAndroid((RenderLayer*)0) { diff --git a/Source/WebCore/platform/graphics/android/layers/BaseLayerAndroid.h b/Source/WebCore/platform/graphics/android/layers/BaseLayerAndroid.h index dc4c25f..6275dfd 100644 --- a/Source/WebCore/platform/graphics/android/layers/BaseLayerAndroid.h +++ b/Source/WebCore/platform/graphics/android/layers/BaseLayerAndroid.h @@ -42,6 +42,7 @@ public: virtual bool needsTexture() { return content(); } virtual IFrameLayerAndroid* updatePosition(SkRect viewport, IFrameLayerAndroid* parentIframeLayer); + void updatePositionsRecursive(const SkRect& visibleContentRect); void setBackgroundColor(Color& color) { m_color = color; } Color getBackgroundColor() { return m_color; } diff --git a/Source/WebCore/platform/graphics/android/layers/CanvasLayer.cpp b/Source/WebCore/platform/graphics/android/layers/CanvasLayer.cpp index 1813903..93806ff 100644 --- a/Source/WebCore/platform/graphics/android/layers/CanvasLayer.cpp +++ b/Source/WebCore/platform/graphics/android/layers/CanvasLayer.cpp @@ -63,13 +63,13 @@ CanvasLayer::CanvasLayer(const CanvasLayer& layer) if (!layer.m_canvas) { // The canvas has already been destroyed - this shouldn't happen ALOGW("Creating a CanvasLayer for a destroyed canvas!"); - m_contentRect = IntRect(); + m_visibleContentRect = IntRect(); m_offsetFromRenderer = IntSize(); m_texture->setHwAccelerated(false); return; } // We are making a copy for the UI, sync the interesting bits - m_contentRect = layer.contentRect(); + m_visibleContentRect = layer.visibleContentRect(); m_offsetFromRenderer = layer.offsetFromRenderer(); bool previousState = m_texture->hasValidTexture(); if (!previousState && layer.m_dirtyCanvas.isEmpty()) { @@ -86,7 +86,7 @@ CanvasLayer::CanvasLayer(const CanvasLayer& layer) // Merge the canvas invals with the layer's invals to repaint the needed // tiles. SkRegion::Iterator iter(layer.m_dirtyCanvas); - const IntPoint& offset = m_contentRect.location(); + const IntPoint& offset = m_visibleContentRect.location(); for (; !iter.done(); iter.next()) { SkIRect diff = iter.rect(); diff.fLeft += offset.x(); @@ -98,8 +98,8 @@ CanvasLayer::CanvasLayer(const CanvasLayer& layer) } if (previousState != m_texture->hasValidTexture()) { // Need to do a full inval of the canvas content as we are mode switching - m_dirtyRegion.op(m_contentRect.x(), m_contentRect.y(), - m_contentRect.maxX(), m_contentRect.maxY(), SkRegion::kUnion_Op); + m_dirtyRegion.op(m_visibleContentRect.x(), m_visibleContentRect.y(), + m_visibleContentRect.maxX(), m_visibleContentRect.maxY(), SkRegion::kUnion_Op); } } } @@ -160,7 +160,7 @@ SkBitmapRef* CanvasLayer::bitmap() const return m_canvas->copiedImage()->nativeImageForCurrentFrame(); } -IntRect CanvasLayer::contentRect() const +IntRect CanvasLayer::visibleContentRect() const { if (!m_canvas || !m_canvas->renderer() @@ -178,18 +178,18 @@ IntSize CanvasLayer::offsetFromRenderer() const bool CanvasLayer::needsTexture() { - return m_bitmap || LayerAndroid::needsTexture(); + return (m_bitmap && !masksToBounds()) || LayerAndroid::needsTexture(); } void CanvasLayer::contentDraw(SkCanvas* canvas, PaintStyle style) { LayerAndroid::contentDraw(canvas, style); - if (!m_bitmap) + if (!m_bitmap || masksToBounds()) return; SkBitmap& bitmap = m_bitmap->bitmap(); - SkRect dst = SkRect::MakeXYWH(m_contentRect.x() - m_offsetFromRenderer.width(), - m_contentRect.y() - m_offsetFromRenderer.height(), - m_contentRect.width(), m_contentRect.height()); + SkRect dst = SkRect::MakeXYWH(m_visibleContentRect.x() - m_offsetFromRenderer.width(), + m_visibleContentRect.y() - m_offsetFromRenderer.height(), + m_visibleContentRect.width(), m_visibleContentRect.height()); canvas->drawBitmapRect(bitmap, 0, dst, 0); } @@ -198,9 +198,9 @@ bool CanvasLayer::drawGL(bool layerTilesDisabled) bool ret = LayerAndroid::drawGL(layerTilesDisabled); m_texture->requireTexture(); if (!m_bitmap && m_texture->updateTexImage()) { - SkRect rect = SkRect::MakeXYWH(m_contentRect.x() - m_offsetFromRenderer.width(), - m_contentRect.y() - m_offsetFromRenderer.height(), - m_contentRect.width(), m_contentRect.height()); + SkRect rect = SkRect::MakeXYWH(m_visibleContentRect.x() - m_offsetFromRenderer.width(), + m_visibleContentRect.y() - m_offsetFromRenderer.height(), + m_visibleContentRect.width(), m_visibleContentRect.height()); TextureQuadData data(m_texture->texture(), GL_TEXTURE_EXTERNAL_OES, GL_LINEAR, LayerQuad, &m_drawTransform, &rect); TilesManager::instance()->shader()->drawQuad(&data); diff --git a/Source/WebCore/platform/graphics/android/layers/CanvasLayer.h b/Source/WebCore/platform/graphics/android/layers/CanvasLayer.h index 532dbf2..2bfed1e 100644 --- a/Source/WebCore/platform/graphics/android/layers/CanvasLayer.h +++ b/Source/WebCore/platform/graphics/android/layers/CanvasLayer.h @@ -63,11 +63,11 @@ private: void init(); SkBitmapRef* bitmap() const; - IntRect contentRect() const; + IntRect visibleContentRect() const; IntSize offsetFromRenderer() const; HTMLCanvasElement* m_canvas; - IntRect m_contentRect; + IntRect m_visibleContentRect; IntSize m_offsetFromRenderer; SkRegion m_dirtyCanvas; SkBitmapRef* m_bitmap; diff --git a/Source/WebCore/platform/graphics/android/layers/LayerAndroid.cpp b/Source/WebCore/platform/graphics/android/layers/LayerAndroid.cpp index 69c597f..5655ef6 100644 --- a/Source/WebCore/platform/graphics/android/layers/LayerAndroid.cpp +++ b/Source/WebCore/platform/graphics/android/layers/LayerAndroid.cpp @@ -20,6 +20,7 @@ #include "MediaLayer.h" #include "ParseCanvas.h" #include "PictureLayerContent.h" +#include "PrerenderedInval.h" #include "SkBitmapRef.h" #include "SkDrawFilter.h" #include "SkPaint.h" @@ -248,9 +249,12 @@ void LayerAndroid::addDirtyArea() { IntSize layerSize(getSize().width(), getSize().height()); - FloatRect area = TilesManager::instance()->shader()->rectInInvScreenCoord(m_drawTransform, layerSize); - FloatRect clippingRect = TilesManager::instance()->shader()->rectInScreenCoord(m_clippingRect); - FloatRect clip = TilesManager::instance()->shader()->convertScreenCoordToInvScreenCoord(clippingRect); + FloatRect area = + TilesManager::instance()->shader()->rectInViewCoord(m_drawTransform, layerSize); + FloatRect clippingRect = + TilesManager::instance()->shader()->rectInInvViewCoord(m_clippingRect); + FloatRect clip = + TilesManager::instance()->shader()->convertInvViewCoordToViewCoord(clippingRect); area.intersect(clip); IntRect dirtyArea(area.x(), area.y(), area.width(), area.height()); @@ -409,7 +413,8 @@ void LayerAndroid::updatePositions() } void LayerAndroid::updateGLPositionsAndScale(const TransformationMatrix& parentMatrix, - const FloatRect& clipping, float opacity, float scale) + const FloatRect& clipping, float opacity, + float scale) { IntSize layerSize(getSize().width(), getSize().height()); FloatPoint anchorPoint(getAnchorPoint().fX, getAnchorPoint().fY); @@ -440,7 +445,9 @@ void LayerAndroid::updateGLPositionsAndScale(const TransformationMatrix& parentM m_drawTransform.setM42(desiredContentY); } - m_zValue = TilesManager::instance()->shader()->zValue(m_drawTransform, getSize().width(), getSize().height()); + m_zValue = TilesManager::instance()->shader()->zValue(m_drawTransform, + getSize().width(), + getSize().height()); m_atomicSync.lock(); m_scale = scale; @@ -450,7 +457,8 @@ void LayerAndroid::updateGLPositionsAndScale(const TransformationMatrix& parentM setDrawOpacity(opacity); if (m_haveClip) { - // The clipping rect calculation and intersetion will be done in documents coordinates. + // The clipping rect calculation and intersetion will be done in content + // coordinates. FloatRect rect(0, 0, layerSize.width(), layerSize.height()); FloatRect clip = m_drawTransform.mapRect(rect); clip.intersect(clipping); @@ -460,7 +468,8 @@ void LayerAndroid::updateGLPositionsAndScale(const TransformationMatrix& parentM } ALOGV("%s - %d %f %f %f %f", subclassType() == BaseLayer ? "BASE" : "nonbase", - m_haveClip, m_clippingRect.x(), m_clippingRect.y(), m_clippingRect.width(), m_clippingRect.height()); + m_haveClip, m_clippingRect.x(), m_clippingRect.y(), + m_clippingRect.width(), m_clippingRect.height()); if (!m_backfaceVisibility && m_drawTransform.inverse().m33() < 0) { @@ -524,6 +533,23 @@ void LayerAndroid::setContent(LayerContent* content) m_content = content; } +bool LayerAndroid::canUpdateWithBlit() +{ + if (!m_content || !m_scale) + return false; + IntRect clip = clippedRect(); + IntRect dirty = m_dirtyRegion.getBounds(); + dirty.intersect(clip); + PrerenderedInval* prerendered = m_content->prerenderForRect(dirty); + if (!prerendered) + return false; + // Check that the scales are "close enough" to produce the same rects + FloatRect screenArea = prerendered->screenArea; + screenArea.scale(1 / m_scale); + IntRect enclosingDocArea = enclosingIntRect(screenArea); + return enclosingDocArea == prerendered->area; +} + bool LayerAndroid::needsTexture() { return m_content && !m_content->isEmpty(); @@ -533,7 +559,7 @@ IntRect LayerAndroid::clippedRect() const { IntRect r(0, 0, getWidth(), getHeight()); IntRect tr = m_drawTransform.mapRect(r); - IntRect cr = TilesManager::instance()->shader()->clippedRectWithViewport(tr); + IntRect cr = TilesManager::instance()->shader()->clippedRectWithVisibleContentRect(tr); IntRect rect = m_drawTransform.inverse().mapRect(cr); return rect; } @@ -567,20 +593,21 @@ void LayerAndroid::showLayer(int indent) if (!indent) { ALOGD("\n\n--- LAYERS TREE ---"); - IntRect documentViewport(TilesManager::instance()->shader()->documentViewport()); - ALOGD("documentViewport(%d, %d, %d, %d)", - documentViewport.x(), documentViewport.y(), - documentViewport.width(), documentViewport.height()); + IntRect contentViewport(TilesManager::instance()->shader()->contentViewport()); + ALOGD("contentViewport(%d, %d, %d, %d)", + contentViewport.x(), contentViewport.y(), + contentViewport.width(), contentViewport.height()); } IntRect r(0, 0, getWidth(), getHeight()); IntRect tr = m_drawTransform.mapRect(r); - IntRect visible = visibleArea(); + IntRect visible = visibleContentArea(); IntRect clip(m_clippingRect.x(), m_clippingRect.y(), m_clippingRect.width(), m_clippingRect.height()); ALOGD("%s %s %s (%d) [%d:0x%x] - %s %s - area (%d, %d, %d, %d) - visible (%d, %d, %d, %d) " "clip (%d, %d, %d, %d) %s %s m_content(%x), pic w: %d h: %d", - spaces, m_haveClip ? "CLIP LAYER" : "", subclassName().ascii().data(), subclassType(), uniqueId(), m_owningLayer, + spaces, m_haveClip ? "CLIP LAYER" : "", subclassName().ascii().data(), + subclassType(), uniqueId(), m_owningLayer, needsTexture() ? "needs a texture" : "no texture", m_imageCRC ? "has an image" : "no image", tr.x(), tr.y(), tr.width(), tr.height(), @@ -735,7 +762,7 @@ int LayerAndroid::setHwAccelerated(bool hwAccelerated) return flags | onSetHwAccelerated(hwAccelerated); } -IntRect LayerAndroid::unclippedArea() +IntRect LayerAndroid::fullContentArea() { IntRect area; area.setX(0); @@ -745,13 +772,13 @@ IntRect LayerAndroid::unclippedArea() return area; } -IntRect LayerAndroid::visibleArea() +IntRect LayerAndroid::visibleContentArea() { - IntRect area = unclippedArea(); + IntRect area = fullContentArea(); if (subclassType() == LayerAndroid::FixedBackgroundBaseLayer) return area; // First, we get the transformed area of the layer, - // in document coordinates + // in content coordinates IntRect rect = m_drawTransform.mapRect(area); int dx = rect.x(); int dy = rect.y(); @@ -760,9 +787,9 @@ IntRect LayerAndroid::visibleArea() IntRect clip(m_clippingRect); rect.intersect(clip); - // Now clip with the viewport in documents coordinate - IntRect documentViewport(TilesManager::instance()->shader()->documentViewport()); - rect.intersect(documentViewport); + // Now clip with the viewport in content coordinate + IntRect contentViewport(TilesManager::instance()->shader()->contentViewport()); + rect.intersect(contentViewport); // Finally, let's return the visible area, in layers coordinate rect.move(-dx, -dy); diff --git a/Source/WebCore/platform/graphics/android/layers/LayerAndroid.h b/Source/WebCore/platform/graphics/android/layers/LayerAndroid.h index 4f94698..170ef41 100644 --- a/Source/WebCore/platform/graphics/android/layers/LayerAndroid.h +++ b/Source/WebCore/platform/graphics/android/layers/LayerAndroid.h @@ -140,8 +140,8 @@ public: IntRect clippedRect() const; bool outsideViewport(); - IntRect unclippedArea(); - IntRect visibleArea(); + IntRect fullContentArea(); + IntRect visibleContentArea(); virtual bool needsTexture(); @@ -185,6 +185,9 @@ public: LayerContent* content() { return m_content; } void setContent(LayerContent* content); + // Check to see if the dirty area of this layer can be updated with a blit + // from the prerender instead of needing to generate tiles from the LayerContent + bool canUpdateWithBlit(); void addAnimation(PassRefPtr<AndroidAnimation> anim); void removeAnimationsForProperty(AnimatedPropertyID property); diff --git a/Source/WebCore/platform/graphics/android/layers/LayerContent.h b/Source/WebCore/platform/graphics/android/layers/LayerContent.h index 97bc32a..2cd90a90 100644 --- a/Source/WebCore/platform/graphics/android/layers/LayerContent.h +++ b/Source/WebCore/platform/graphics/android/layers/LayerContent.h @@ -26,6 +26,7 @@ #ifndef LayerContent_h #define LayerContent_h +#include "IntRect.h" #include "SkRefCnt.h" #include <utils/threads.h> @@ -35,14 +36,18 @@ class SkWStream; namespace WebCore { +class PrerenderedInval; + class LayerContent : public SkRefCnt { public: virtual int width() = 0; virtual int height() = 0; - virtual bool isEmpty() = 0; + virtual bool isEmpty() { return !width() || !height(); } virtual void checkForOptimisations() = 0; virtual bool hasText() = 0; virtual void draw(SkCanvas* canvas) = 0; + virtual PrerenderedInval* prerenderForRect(const IntRect& dirty) { return 0; } + virtual void clearPrerenders() { }; virtual void serialize(SkWStream* stream) = 0; diff --git a/Source/WebCore/platform/graphics/android/layers/MediaLayer.cpp b/Source/WebCore/platform/graphics/android/layers/MediaLayer.cpp index 6227ea4..7a3730b 100644 --- a/Source/WebCore/platform/graphics/android/layers/MediaLayer.cpp +++ b/Source/WebCore/platform/graphics/android/layers/MediaLayer.cpp @@ -56,7 +56,7 @@ MediaLayer::~MediaLayer() bool MediaLayer::drawGL(bool layerTilesDisabled) { - FloatRect clippingRect = TilesManager::instance()->shader()->rectInScreenCoord(drawClip()); + FloatRect clippingRect = TilesManager::instance()->shader()->rectInInvViewCoord(drawClip()); TilesManager::instance()->shader()->clip(clippingRect); // when the plugin gains focus webkit applies an outline to the diff --git a/Source/WebCore/platform/graphics/android/layers/PicturePileLayerContent.cpp b/Source/WebCore/platform/graphics/android/layers/PicturePileLayerContent.cpp new file mode 100644 index 0000000..b648e72 --- /dev/null +++ b/Source/WebCore/platform/graphics/android/layers/PicturePileLayerContent.cpp @@ -0,0 +1,41 @@ +#include "config.h" +#include "PicturePileLayerContent.h" + +#include "SkCanvas.h" +#include "SkPicture.h" + +namespace WebCore { + +PicturePileLayerContent::PicturePileLayerContent(const PicturePile& picturePile) + : m_picturePile(picturePile) +{ +} + +void PicturePileLayerContent::draw(SkCanvas* canvas) +{ + android::Mutex::Autolock lock(m_drawLock); + m_picturePile.draw(canvas); +} + +void PicturePileLayerContent::serialize(SkWStream* stream) +{ + if (!stream) + return; + SkPicture picture; + draw(picture.beginRecording(width(), height(), + SkPicture::kUsePathBoundsForClip_RecordingFlag)); + picture.endRecording(); + picture.serialize(stream); +} + +PrerenderedInval* PicturePileLayerContent::prerenderForRect(const IntRect& dirty) +{ + return m_picturePile.prerenderedInvalForArea(dirty); +} + +void PicturePileLayerContent::clearPrerenders() +{ + m_picturePile.clearPrerenders(); +} + +} // namespace WebCore diff --git a/Source/WebCore/platform/graphics/android/layers/PictureSetLayerContent.h b/Source/WebCore/platform/graphics/android/layers/PicturePileLayerContent.h index 61fc3f4..4216617 100644 --- a/Source/WebCore/platform/graphics/android/layers/PictureSetLayerContent.h +++ b/Source/WebCore/platform/graphics/android/layers/PicturePileLayerContent.h @@ -23,31 +23,31 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef PictureSetLayerContent_h -#define PictureSetLayerContent_h +#ifndef PicturePileLayerContent_h +#define PicturePileLayerContent_h #include "LayerContent.h" -#include "PictureSet.h" +#include "PicturePile.h" namespace WebCore { -class PictureSetLayerContent : public LayerContent { +class PicturePileLayerContent : public LayerContent { public: - PictureSetLayerContent(const android::PictureSet& pictureSet); - ~PictureSetLayerContent(); + PicturePileLayerContent(const PicturePile& picturePile); - virtual int width() { return m_pictureSet.width(); } - virtual int height() { return m_pictureSet.height(); } - virtual bool isEmpty() { return m_pictureSet.isEmpty(); } + virtual int width() { return m_picturePile.size().width(); } + virtual int height() { return m_picturePile.size().height(); } virtual void checkForOptimisations() {} virtual bool hasText() { return true; } virtual void draw(SkCanvas* canvas); virtual void serialize(SkWStream* stream); + virtual PrerenderedInval* prerenderForRect(const IntRect& dirty); + virtual void clearPrerenders(); private: - android::PictureSet m_pictureSet; + PicturePile m_picturePile; }; } // WebCore -#endif // PictureLayerContent_h +#endif // PicturePileLayerContent_h diff --git a/Source/WebCore/platform/graphics/android/layers/PictureSetLayerContent.cpp b/Source/WebCore/platform/graphics/android/layers/PictureSetLayerContent.cpp deleted file mode 100644 index 8b72b0a..0000000 --- a/Source/WebCore/platform/graphics/android/layers/PictureSetLayerContent.cpp +++ /dev/null @@ -1,41 +0,0 @@ -#include "config.h" -#include "PictureSetLayerContent.h" - -#include "SkCanvas.h" -#include "SkPicture.h" - -namespace WebCore { - -PictureSetLayerContent::PictureSetLayerContent(const android::PictureSet& pictureSet) -{ - m_pictureSet.set(pictureSet); -} - -PictureSetLayerContent::~PictureSetLayerContent() -{ - m_pictureSet.clear(); -} - -void PictureSetLayerContent::draw(SkCanvas* canvas) -{ - if (m_pictureSet.isEmpty()) - return; - - android::Mutex::Autolock lock(m_drawLock); - SkRect r = SkRect::MakeWH(width(), height()); - canvas->clipRect(r); - m_pictureSet.draw(canvas); -} - -void PictureSetLayerContent::serialize(SkWStream* stream) -{ - if (!stream) - return; - SkPicture picture; - draw(picture.beginRecording(m_pictureSet.width(), m_pictureSet.height(), - SkPicture::kUsePathBoundsForClip_RecordingFlag)); - picture.endRecording(); - picture.serialize(stream); -} - -} // namespace WebCore diff --git a/Source/WebCore/platform/graphics/android/layers/PrerenderedInval.h b/Source/WebCore/platform/graphics/android/layers/PrerenderedInval.h new file mode 100644 index 0000000..91f385d --- /dev/null +++ b/Source/WebCore/platform/graphics/android/layers/PrerenderedInval.h @@ -0,0 +1,58 @@ +/* + * 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 PrerenderedInval_h +#define PrerenderedInval_h + +#include "IntRect.h" +#include "SkBitmap.h" + +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> +#include <wtf/ThreadSafeRefCounted.h> + +namespace WebCore { + +class PrerenderedInval : public ThreadSafeRefCounted<PrerenderedInval> { + WTF_MAKE_NONCOPYABLE(PrerenderedInval); +public: + SkBitmap bitmap; + IntRect area; + IntRect screenArea; + + static PassRefPtr<PrerenderedInval> create(const IntRect& ir) + { + return adoptRef(new PrerenderedInval(ir)); + } + +private: + PrerenderedInval(const IntRect& ir) + : area(ir) + {} +}; + +} // namespace WebCore + +#endif // PrerenderedInval_h diff --git a/Source/WebCore/platform/graphics/android/rendering/BaseRenderer.cpp b/Source/WebCore/platform/graphics/android/rendering/BaseRenderer.cpp index 8bb1755..6f679da 100644 --- a/Source/WebCore/platform/graphics/android/rendering/BaseRenderer.cpp +++ b/Source/WebCore/platform/graphics/android/rendering/BaseRenderer.cpp @@ -109,7 +109,6 @@ void BaseRenderer::renderTiledContent(TileRenderInfo& renderInfo) before = currentTimeMS(); } - setupPartialInval(renderInfo, &canvas); canvas.translate(-renderInfo.x * tileSize.width(), -renderInfo.y * tileSize.height()); canvas.scale(renderInfo.scale, renderInfo.scale); renderInfo.tilePainter->paint(&canvas); @@ -127,25 +126,10 @@ void BaseRenderer::renderTiledContent(TileRenderInfo& renderInfo) // only color the invalidated area SkPaint paint; paint.setARGB(color, 0, 255, 0); - if (renderInfo.invalRect) - canvas.drawIRect(*renderInfo.invalRect, paint); - else { - SkIRect rect; - rect.set(0, 0, tileSize.width(), tileSize.height()); - canvas.drawIRect(rect, paint); - } - - if (renderInfo.invalRect) { - // if partial inval... - int x = renderInfo.invalRect->fLeft; - int y = renderInfo.invalRect->fTop; - int w = renderInfo.invalRect->width(); - int h = renderInfo.invalRect->height(); - - paint.setARGB(128, 255, 255, 0); - canvas.drawLine(x, y, x + w, y + h, paint); - canvas.drawLine(x, y + h, x + w, y, paint); - } + SkIRect rect; + rect.set(0, 0, tileSize.width(), tileSize.height()); + canvas.drawIRect(rect, paint); + drawTileInfo(&canvas, renderInfo, updateCount, after - before); // paint the tile boundaries diff --git a/Source/WebCore/platform/graphics/android/rendering/BaseRenderer.h b/Source/WebCore/platform/graphics/android/rendering/BaseRenderer.h index f225871..b25a50e 100644 --- a/Source/WebCore/platform/graphics/android/rendering/BaseRenderer.h +++ b/Source/WebCore/platform/graphics/android/rendering/BaseRenderer.h @@ -49,9 +49,6 @@ struct TileRenderInfo { // current scale factor float scale; - // inval rectangle with coordinates in the tile's coordinate space - SkIRect* invalRect; - // the expected size of the tile SkSize tileSize; @@ -89,7 +86,6 @@ public: protected: virtual void setupCanvas(const TileRenderInfo& renderInfo, SkCanvas* canvas) = 0; - virtual void setupPartialInval(const TileRenderInfo& renderInfo, SkCanvas* canvas) {} virtual void renderingComplete(const TileRenderInfo& renderInfo, SkCanvas* canvas) = 0; virtual void checkForPureColor(TileRenderInfo& renderInfo, SkCanvas* canvas) = 0; diff --git a/Source/WebCore/platform/graphics/android/rendering/DrawQuadData.h b/Source/WebCore/platform/graphics/android/rendering/DrawQuadData.h index bce82f2..719df14 100644 --- a/Source/WebCore/platform/graphics/android/rendering/DrawQuadData.h +++ b/Source/WebCore/platform/graphics/android/rendering/DrawQuadData.h @@ -29,7 +29,7 @@ #if USE(ACCELERATED_COMPOSITING) #include "Color.h" -#include "FloatPoint.h" +#include "FloatRect.h" #include "SkRect.h" #include <GLES2/gl2.h> @@ -51,13 +51,14 @@ public: const SkRect* geometry = 0, float opacity = 1.0f, bool forceBlending = true, - FloatPoint fillPortion = FloatPoint(1.0f, 1.0f)) + FloatRect fillPortion = FloatRect(0.0f, 0.0f, 1.0f, 1.0f)) : m_type(type) , m_drawMatrix(drawMatrix) , m_geometry(geometry) , m_opacity(opacity) , m_forceBlending(forceBlending) - , m_fillPortion(fillPortion.x(), fillPortion.y()) + , m_fillPortion(fillPortion.x(), fillPortion.y(), + fillPortion.width(), fillPortion.height()) { } @@ -67,7 +68,8 @@ public: , m_geometry(data.m_geometry) , m_opacity(data.m_opacity) , m_forceBlending(data.m_forceBlending) - , m_fillPortion(data.m_fillPortion.x(), data.m_fillPortion.y()) + , m_fillPortion(data.m_fillPortion.x(), data.m_fillPortion.y(), + data.m_fillPortion.width(), data.m_fillPortion.height()) { } @@ -90,7 +92,7 @@ public: virtual int textureId() const { return 0; } virtual GLint textureFilter() const { return 0; } virtual GLenum textureTarget() const { return 0; } - virtual FloatPoint fillPortion() const { return m_fillPortion; } + virtual FloatRect fillPortion() const { return m_fillPortion; } private: DrawQuadType m_type; @@ -98,7 +100,7 @@ private: const SkRect* m_geometry; float m_opacity; bool m_forceBlending; - FloatPoint m_fillPortion; + FloatRect m_fillPortion; }; class PureColorQuadData : public DrawQuadData { diff --git a/Source/WebCore/platform/graphics/android/rendering/GLExtras.cpp b/Source/WebCore/platform/graphics/android/rendering/GLExtras.cpp index 6498ecf..2c114d6 100644 --- a/Source/WebCore/platform/graphics/android/rendering/GLExtras.cpp +++ b/Source/WebCore/platform/graphics/android/rendering/GLExtras.cpp @@ -42,7 +42,7 @@ GLExtras::GLExtras() : m_drawExtra(0) - , m_viewport() + , m_visibleContentRect() { } diff --git a/Source/WebCore/platform/graphics/android/rendering/GLExtras.h b/Source/WebCore/platform/graphics/android/rendering/GLExtras.h index 59a7c3c..e9f697a 100644 --- a/Source/WebCore/platform/graphics/android/rendering/GLExtras.h +++ b/Source/WebCore/platform/graphics/android/rendering/GLExtras.h @@ -43,7 +43,10 @@ public: void drawGL(const LayerAndroid* layer); void setDrawExtra(android::DrawExtra* extra) { m_drawExtra = extra; } - void setViewport(const SkRect & viewport) { m_viewport = viewport; } + void setVisibleContentRect(const SkRect & visibleContentRect) + { + m_visibleContentRect = visibleContentRect; + } void drawRegion(const SkRegion& region, bool fill, bool drawBorder, const TransformationMatrix* drawMat, Color color = COLOR_HOLO_LIGHT); @@ -52,7 +55,7 @@ private: void drawRing(SkRect& srcRect, Color color, const TransformationMatrix* drawMat); android::DrawExtra* m_drawExtra; - SkRect m_viewport; + SkRect m_visibleContentRect; }; } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/android/rendering/GLUtils.cpp b/Source/WebCore/platform/graphics/android/rendering/GLUtils.cpp index 7206c98..32f353c 100644 --- a/Source/WebCore/platform/graphics/android/rendering/GLUtils.cpp +++ b/Source/WebCore/platform/graphics/android/rendering/GLUtils.cpp @@ -418,10 +418,6 @@ bool GLUtils::skipTransferForPureColor(const TileRenderInfo* renderInfo, bool skipTransfer = false; Tile* tilePtr = renderInfo->baseTile; - // TODO: use pure color for partial invals as well - if (renderInfo->invalRect) - return false; - if (tilePtr) { TileTexture* tileTexture = tilePtr->backTexture(); // Check the bitmap, and make everything ready here. @@ -611,6 +607,33 @@ void GLUtils::clearBackgroundIfOpaque(const Color* backgroundColor) } } +bool GLUtils::deepCopyBitmapSubset(const SkBitmap& sourceBitmap, + SkBitmap& subset, int leftOffset, int topOffset) +{ + sourceBitmap.lockPixels(); + subset.lockPixels(); + char* srcPixels = (char*) sourceBitmap.getPixels(); + char* dstPixels = (char*) subset.getPixels(); + if (!dstPixels || !srcPixels || !subset.lockPixelsAreWritable()) { + ALOGD("no pixels :( %p, %p (writable=%d)", srcPixels, dstPixels, + subset.lockPixelsAreWritable()); + subset.unlockPixels(); + sourceBitmap.unlockPixels(); + return false; + } + int srcRowSize = sourceBitmap.rowBytes(); + int destRowSize = subset.rowBytes(); + for (int i = 0; i < subset.height(); i++) { + int srcOffset = (i + topOffset) * srcRowSize; + srcOffset += (leftOffset * sourceBitmap.bytesPerPixel()); + int dstOffset = i * destRowSize; + memcpy(dstPixels + dstOffset, srcPixels + srcOffset, destRowSize); + } + subset.unlockPixels(); + sourceBitmap.unlockPixels(); + return true; +} + } // namespace WebCore #endif // USE(ACCELERATED_COMPOSITING) diff --git a/Source/WebCore/platform/graphics/android/rendering/GLUtils.h b/Source/WebCore/platform/graphics/android/rendering/GLUtils.h index a235458..1b69d6c 100644 --- a/Source/WebCore/platform/graphics/android/rendering/GLUtils.h +++ b/Source/WebCore/platform/graphics/android/rendering/GLUtils.h @@ -29,6 +29,7 @@ #if USE(ACCELERATED_COMPOSITING) #include "Color.h" +#include "IntRect.h" #include "SkBitmap.h" #include "SkMatrix.h" #include "TransformationMatrix.h" @@ -73,7 +74,8 @@ public: static GLuint createTileGLTexture(int width, int height); static void createTextureWithBitmap(GLuint texture, const SkBitmap& bitmap, GLint filter = GL_LINEAR); - static void updateTextureWithBitmap(GLuint texture, const SkBitmap& bitmap, const IntRect&, GLint filter = GL_LINEAR); + static void updateTextureWithBitmap(GLuint texture, const SkBitmap& bitmap, + const IntRect& inval = IntRect(), GLint filter = GL_LINEAR); static void createEGLImageFromTexture(GLuint texture, EGLImageKHR* image); static void createTextureFromEGLImage(GLuint texture, EGLImageKHR image, GLint filter = GL_LINEAR); @@ -82,6 +84,8 @@ public: static bool updateSharedSurfaceTextureWithBitmap(ANativeWindow* anw, const SkBitmap& bitmap); static void convertToTransformationMatrix(const float* matrix, TransformationMatrix& transformMatrix); + static bool deepCopyBitmapSubset(const SkBitmap& sourceBitmap, + SkBitmap& subset, int left, int top); static bool isPureColorBitmap(const SkBitmap& bitmap, Color& pureColor); static bool skipTransferForPureColor(const TileRenderInfo* renderInfo, const SkBitmap& bitmap); diff --git a/Source/WebCore/platform/graphics/android/rendering/GaneshRenderer.cpp b/Source/WebCore/platform/graphics/android/rendering/GaneshRenderer.cpp index 208adb6..d779af4 100644 --- a/Source/WebCore/platform/graphics/android/rendering/GaneshRenderer.cpp +++ b/Source/WebCore/platform/graphics/android/rendering/GaneshRenderer.cpp @@ -84,16 +84,6 @@ void GaneshRenderer::setupCanvas(const TileRenderInfo& renderInfo, SkCanvas* can canvas->setDevice(device); } -void GaneshRenderer::setupPartialInval(const TileRenderInfo& renderInfo, SkCanvas* canvas) -{ - // set the clip to our invalRect - SkRect clipRect = SkRect::MakeLTRB(renderInfo.invalRect->fLeft, - renderInfo.invalRect->fTop, - renderInfo.invalRect->fRight, - renderInfo.invalRect->fBottom); - canvas->clipRect(clipRect); -} - void GaneshRenderer::renderingComplete(const TileRenderInfo& renderInfo, SkCanvas* canvas) { ALOGV("rendered to tile (%d,%d)", renderInfo.x, renderInfo.y); diff --git a/Source/WebCore/platform/graphics/android/rendering/GaneshRenderer.h b/Source/WebCore/platform/graphics/android/rendering/GaneshRenderer.h index d7eda24..cdd9f3e 100644 --- a/Source/WebCore/platform/graphics/android/rendering/GaneshRenderer.h +++ b/Source/WebCore/platform/graphics/android/rendering/GaneshRenderer.h @@ -47,7 +47,6 @@ public: protected: virtual void setupCanvas(const TileRenderInfo& renderInfo, SkCanvas* canvas); - virtual void setupPartialInval(const TileRenderInfo& renderInfo, SkCanvas* canvas); virtual void renderingComplete(const TileRenderInfo& renderInfo, SkCanvas* canvas); virtual void checkForPureColor(TileRenderInfo& renderInfo, SkCanvas* canvas) { renderInfo.isPureColor = false; diff --git a/Source/WebCore/platform/graphics/android/rendering/ImageTexture.cpp b/Source/WebCore/platform/graphics/android/rendering/ImageTexture.cpp index 6e4a82c..5098b4b 100644 --- a/Source/WebCore/platform/graphics/android/rendering/ImageTexture.cpp +++ b/Source/WebCore/platform/graphics/android/rendering/ImageTexture.cpp @@ -150,8 +150,8 @@ int ImageTexture::nbTextures() // TODO: take in account the visible clip (need to maintain // a list of the clients layer, etc.) - IntRect visibleArea(0, 0, m_image->width(), m_image->height()); - int nbTextures = m_tileGrid->nbTextures(visibleArea, 1.0); + IntRect visibleContentArea(0, 0, m_image->width(), m_image->height()); + int nbTextures = m_tileGrid->nbTextures(visibleContentArea, 1.0); ALOGV("ImageTexture %p, %d x %d needs %d textures", this, m_image->width(), m_image->height(), nbTextures); @@ -184,8 +184,8 @@ bool ImageTexture::prepareGL(GLWebViewState* state) if (!m_tileGrid) return false; - IntRect unclippedArea(0, 0, m_image->width(), m_image->height()); - m_tileGrid->prepareGL(state, 1.0, unclippedArea, unclippedArea, this); + IntRect fullContentArea(0, 0, m_image->width(), m_image->height()); + m_tileGrid->prepareGL(state, 1.0, fullContentArea, fullContentArea, this); if (m_tileGrid->isReady()) { m_tileGrid->swapTiles(); return false; @@ -198,7 +198,7 @@ const TransformationMatrix* ImageTexture::transform() if (!m_layer) return 0; - IntRect layerArea = m_layer->unclippedArea(); + IntRect layerArea = m_layer->fullContentArea(); float scaleW = static_cast<float>(layerArea.width()) / static_cast<float>(m_image->width()); float scaleH = static_cast<float>(layerArea.height()) / static_cast<float>(m_image->height()); TransformationMatrix d = *(m_layer->drawTransform()); @@ -239,8 +239,8 @@ void ImageTexture::drawGL(LayerAndroid* layer, float opacity) // transform and opacity, so we need to set m_layer m_layer = layer; if (m_tileGrid) { - IntRect visibleArea = m_layer->visibleArea(); - m_tileGrid->drawGL(visibleArea, opacity, transform()); + IntRect visibleContentArea = m_layer->visibleContentArea(); + m_tileGrid->drawGL(visibleContentArea, opacity, transform()); } m_layer = 0; } diff --git a/Source/WebCore/platform/graphics/android/rendering/RasterRenderer.cpp b/Source/WebCore/platform/graphics/android/rendering/RasterRenderer.cpp index b880eef..47e5c17 100644 --- a/Source/WebCore/platform/graphics/android/rendering/RasterRenderer.cpp +++ b/Source/WebCore/platform/graphics/android/rendering/RasterRenderer.cpp @@ -80,7 +80,7 @@ void RasterRenderer::setupCanvas(const TileRenderInfo& renderInfo, SkCanvas* can ALOGV("setupCanvas use background on Base Layer %x", background->rgb()); g_bitmap->setIsOpaque(!background->hasAlpha()); g_bitmap->eraseARGB(background->alpha(), background->red(), - background->green(), background->blue()); + background->green(), background->blue()); } SkDevice* device = new SkDevice(*g_bitmap); @@ -88,15 +88,6 @@ void RasterRenderer::setupCanvas(const TileRenderInfo& renderInfo, SkCanvas* can canvas->setDevice(device); device->unref(); - - // If we have a partially painted bitmap - if (renderInfo.invalRect) { - SkRect clipRect = SkRect::MakeWH(renderInfo.invalRect->width(), - renderInfo.invalRect->height()); - // ensure the canvas origin is translated to the coordinates of our inval rect - canvas->clipRect(clipRect); - canvas->translate(-renderInfo.invalRect->fLeft, -renderInfo.invalRect->fTop); - } } void RasterRenderer::renderingComplete(const TileRenderInfo& renderInfo, SkCanvas* canvas) @@ -107,7 +98,8 @@ void RasterRenderer::renderingComplete(const TileRenderInfo& renderInfo, SkCanva void RasterRenderer::checkForPureColor(TileRenderInfo& renderInfo, SkCanvas* canvas) { - renderInfo.isPureColor = GLUtils::isPureColorBitmap(*g_bitmap, renderInfo.pureColor); + const SkBitmap& bitmap = canvas->getDevice()->accessBitmap(false); + renderInfo.isPureColor = GLUtils::isPureColorBitmap(bitmap, renderInfo.pureColor); } } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/android/rendering/ShaderProgram.cpp b/Source/WebCore/platform/graphics/android/rendering/ShaderProgram.cpp index 817efb8..70a1afe 100644 --- a/Source/WebCore/platform/graphics/android/rendering/ShaderProgram.cpp +++ b/Source/WebCore/platform/graphics/android/rendering/ShaderProgram.cpp @@ -44,14 +44,16 @@ namespace WebCore { +// fillPortion.xy = starting UV coordinates. +// fillPortion.zw = UV coordinates width and height. static const char gVertexShader[] = "attribute vec4 vPosition;\n" "uniform mat4 projectionMatrix;\n" - "uniform vec2 fillPortion;\n" + "uniform vec4 fillPortion;\n" "varying vec2 v_texCoord;\n" "void main() {\n" " gl_Position = projectionMatrix * vPosition;\n" - " v_texCoord = vPosition.xy * fillPortion;\n" + " v_texCoord = vPosition.xy * fillPortion.zw + fillPortion.xy;\n" "}\n"; static const char gFragmentShader[] = @@ -368,38 +370,54 @@ void ShaderProgram::setBlendingState(bool enableBlending) // Drawing ///////////////////////////////////////////////////////////////////////////////////////// -void ShaderProgram::setupDrawing(const IntRect& viewRect, const SkRect& visibleRect, - const IntRect& webViewRect, int titleBarHeight, +// We have multiple coordinates to deal with: first is the screen coordinates, +// second is the view coordinates and the last one is content(document) coordinates. +// Both screen and view coordinates are in pixels. +// All these coordinates start from upper left, but for the purpose of OpenGL +// operations, we may need a inverted Y version of such coordinates which +// start from lower left. +// +// invScreenRect - inv screen coordinates starting from lower left. +// visibleContentRect - local content(document) coordinates starting from upper left. +// screenRect - screen coordinates starting from upper left. +// screenClip - screen coordinates starting from upper left. +// ------------------------------------------ +// |(origin of screen) | +// |screen | +// | --------------------------------- | +// | | (origin of view) | | +// | | webview | | +// | | -------- | | +// | | | clip | | | +// | | | | | | +// | | -------- | | +// | | | | +// | |(origin of inv view) | | +// | --------------------------------- | +// |(origin of inv screen) | +// ------------------------------------------ +void ShaderProgram::setupDrawing(const IntRect& invScreenRect, + const SkRect& visibleContentRect, + const IntRect& screenRect, int titleBarHeight, const IntRect& screenClip, float scale) { - m_webViewRect = webViewRect; + m_screenRect = screenRect; m_titleBarHeight = titleBarHeight; //// viewport //// - TransformationMatrix ortho; - GLUtils::setOrthographicMatrix(ortho, visibleRect.fLeft, visibleRect.fTop, - visibleRect.fRight, visibleRect.fBottom, -1000, 1000); - // In most case , visibleRect / viewRect * scale should 1.0, but for the - // translation case, the scale factor can be 1 but visibleRect is smaller - // than viewRect, we need to tune in this factor to make sure we scale them - // right. Conceptually, that means, no matter how animation affects the - // visibleRect, the scaling should respect the viewRect if zoomScale is 1.0. - // Note that at TiledPage, we already scale the tile size inversely to make - // zooming animation right. - float orthoScaleX = scale * visibleRect.width() / viewRect.width(); - float orthoScaleY = scale * visibleRect.height() / viewRect.height(); - - TransformationMatrix orthoScale; - orthoScale.scale3d(orthoScaleX, orthoScaleY, 1.0); - - m_visibleRectProjectionMatrix = ortho * orthoScale; + GLUtils::setOrthographicMatrix(m_visibleContentRectProjectionMatrix, + visibleContentRect.fLeft, + visibleContentRect.fTop, + visibleContentRect.fRight, + visibleContentRect.fBottom, + -1000, 1000); ALOGV("set m_clipProjectionMatrix, %d, %d, %d, %d", screenClip.x(), screenClip.y(), screenClip.x() + screenClip.width(), screenClip.y() + screenClip.height()); // In order to incorporate the animation delta X and Y, using the clip as - // the GL viewport can save all the trouble of re-position from webViewRect + // the GL viewport can save all the trouble of re-position from screenRect // to final position. GLUtils::setOrthographicMatrix(m_clipProjectionMatrix, screenClip.x(), screenClip.y(), screenClip.x() + screenClip.width(), @@ -408,40 +426,45 @@ void ShaderProgram::setupDrawing(const IntRect& viewRect, const SkRect& visibleR glViewport(screenClip.x(), m_targetHeight - screenClip.y() - screenClip.height() , screenClip.width(), screenClip.height()); - m_viewport = visibleRect; + m_visibleContentRect = visibleContentRect; m_currentScale = scale; //// viewRect //// - m_viewRect = viewRect; + m_invScreenRect = invScreenRect; - // We do clipping using glScissor, which needs to take - // coordinates in screen space. The following matrix transform - // content coordinates in screen coordinates. + // The following matrices transform content coordinates into view coordinates + // and inv view coordinates. + // Note that GLUtils::setOrthographicMatrix is inverting the Y. TransformationMatrix viewTranslate; viewTranslate.translate(1.0, 1.0); TransformationMatrix viewScale; - viewScale.scale3d(m_viewRect.width() * 0.5f, m_viewRect.height() * 0.5f, 1); + viewScale.scale3d(m_invScreenRect.width() * 0.5f, m_invScreenRect.height() * 0.5f, 1); - m_documentToScreenMatrix = viewScale * viewTranslate * m_visibleRectProjectionMatrix; + m_contentToInvViewMatrix = viewScale * viewTranslate * m_visibleContentRectProjectionMatrix; viewTranslate.scale3d(1, -1, 1); - m_documentToInvScreenMatrix = viewScale * viewTranslate * m_visibleRectProjectionMatrix; + m_contentToViewMatrix = viewScale * viewTranslate * m_visibleContentRectProjectionMatrix; - IntRect rect(0, 0, m_webViewRect.width(), m_webViewRect.height()); - m_documentViewport = m_documentToScreenMatrix.inverse().mapRect(rect); + IntRect invViewRect(0, 0, m_screenRect.width(), m_screenRect.height()); + m_contentViewport = m_contentToInvViewMatrix.inverse().mapRect(invViewRect); //// clipping //// - IntRect mclip = screenClip; - - // the clip from frameworks is in full screen coordinates - mclip.setY(screenClip.y() - m_webViewRect.y() - m_titleBarHeight); - FloatRect tclip = convertInvScreenCoordToScreenCoord(mclip); - m_screenClip.setLocation(IntPoint(tclip.x(), tclip.y())); + IntRect viewClip = screenClip; + + // The incoming screenClip is in screen coordinates, we first + // translate it into view coordinates. + // Then we convert it into inverted view coordinates. + // Therefore, in the clip() function, we need to convert things back from + // inverted view coordinates to inverted screen coordinates which is used by GL. + viewClip.setX(screenClip.x() - m_screenRect.x()); + viewClip.setY(screenClip.y() - m_screenRect.y() - m_titleBarHeight); + FloatRect invViewClip = convertViewCoordToInvViewCoord(viewClip); + m_invViewClip.setLocation(IntPoint(invViewClip.x(), invViewClip.y())); // use ceilf to handle view -> doc -> view coord rounding errors - m_screenClip.setSize(IntSize(ceilf(tclip.width()), ceilf(tclip.height()))); + m_invViewClip.setSize(IntSize(ceilf(invViewClip.width()), ceilf(invViewClip.height()))); resetBlending(); @@ -492,47 +515,47 @@ ShaderType ShaderProgram::getTextureShaderType(GLenum textureTarget) } // This function transform a clip rect extracted from the current layer -// into a clip rect in screen coordinates -- used by the clipping rects -FloatRect ShaderProgram::rectInScreenCoord(const TransformationMatrix& drawMatrix, const IntSize& size) +// into a clip rect in InvView coordinates -- used by the clipping rects +FloatRect ShaderProgram::rectInInvViewCoord(const TransformationMatrix& drawMatrix, const IntSize& size) { FloatRect srect(0, 0, size.width(), size.height()); - TransformationMatrix renderMatrix = m_documentToScreenMatrix * drawMatrix; + TransformationMatrix renderMatrix = m_contentToInvViewMatrix * drawMatrix; return renderMatrix.mapRect(srect); } // used by the partial screen invals -FloatRect ShaderProgram::rectInInvScreenCoord(const TransformationMatrix& drawMatrix, const IntSize& size) +FloatRect ShaderProgram::rectInViewCoord(const TransformationMatrix& drawMatrix, const IntSize& size) { FloatRect srect(0, 0, size.width(), size.height()); - TransformationMatrix renderMatrix = m_documentToInvScreenMatrix * drawMatrix; + TransformationMatrix renderMatrix = m_contentToViewMatrix * drawMatrix; return renderMatrix.mapRect(srect); } -FloatRect ShaderProgram::rectInInvScreenCoord(const FloatRect& rect) +FloatRect ShaderProgram::rectInViewCoord(const FloatRect& rect) { - return m_documentToInvScreenMatrix.mapRect(rect); + return m_contentToViewMatrix.mapRect(rect); } -FloatRect ShaderProgram::rectInScreenCoord(const FloatRect& rect) +FloatRect ShaderProgram::rectInInvViewCoord(const FloatRect& rect) { - return m_documentToScreenMatrix.mapRect(rect); + return m_contentToInvViewMatrix.mapRect(rect); } -FloatRect ShaderProgram::convertScreenCoordToDocumentCoord(const FloatRect& rect) +FloatRect ShaderProgram::convertInvViewCoordToContentCoord(const FloatRect& rect) { - return m_documentToScreenMatrix.inverse().mapRect(rect); + return m_contentToInvViewMatrix.inverse().mapRect(rect); } -FloatRect ShaderProgram::convertInvScreenCoordToScreenCoord(const FloatRect& rect) +FloatRect ShaderProgram::convertViewCoordToInvViewCoord(const FloatRect& rect) { - FloatRect documentRect = m_documentToInvScreenMatrix.inverse().mapRect(rect); - return rectInScreenCoord(documentRect); + FloatRect visibleContentRect = m_contentToViewMatrix.inverse().mapRect(rect); + return rectInInvViewCoord(visibleContentRect); } -FloatRect ShaderProgram::convertScreenCoordToInvScreenCoord(const FloatRect& rect) +FloatRect ShaderProgram::convertInvViewCoordToViewCoord(const FloatRect& rect) { - FloatRect documentRect = m_documentToScreenMatrix.inverse().mapRect(rect); - return rectInInvScreenCoord(documentRect); + FloatRect visibleContentRect = m_contentToInvViewMatrix.inverse().mapRect(rect); + return rectInViewCoord(visibleContentRect); } // clip is in screen coordinates @@ -551,10 +574,14 @@ void ShaderProgram::clip(const FloatRect& clip) clip.y(), clip.width(), clip.height()); - if (!m_screenClip.isEmpty()) - screenClip.intersect(m_screenClip); + if (!m_invViewClip.isEmpty()) + screenClip.intersect(m_invViewClip); - screenClip.setY(screenClip.y() + m_viewRect.y()); + // The previous intersection calculation is using local screen coordinates. + // Now we need to convert things from local screen coordinates to global + // screen coordinates and pass to the GL functions. + screenClip.setX(screenClip.x() + m_invScreenRect.x()); + screenClip.setY(screenClip.y() + m_invScreenRect.y()); if (screenClip.x() < 0) { int w = screenClip.width(); w += screenClip.x(); @@ -573,10 +600,11 @@ void ShaderProgram::clip(const FloatRect& clip) m_clipRect = clip; } -IntRect ShaderProgram::clippedRectWithViewport(const IntRect& rect, int margin) +IntRect ShaderProgram::clippedRectWithVisibleContentRect(const IntRect& rect, int margin) { - IntRect viewport(m_viewport.fLeft - margin, m_viewport.fTop - margin, - m_viewport.width() + margin, m_viewport.height() + margin); + IntRect viewport(m_visibleContentRect.fLeft - margin, m_visibleContentRect.fTop - margin, + m_visibleContentRect.width() + margin, + m_visibleContentRect.height() + margin); viewport.intersect(rect); return viewport; } @@ -585,7 +613,8 @@ float ShaderProgram::zValue(const TransformationMatrix& drawMatrix, float w, flo { TransformationMatrix modifiedDrawMatrix = drawMatrix; modifiedDrawMatrix.scale3d(w, h, 1); - TransformationMatrix renderMatrix = m_visibleRectProjectionMatrix * modifiedDrawMatrix; + TransformationMatrix renderMatrix = + m_visibleContentRectProjectionMatrix * modifiedDrawMatrix; FloatPoint3D point(0.5, 0.5, 0.0); FloatPoint3D result = renderMatrix.mapPoint(point); return result.z(); @@ -594,7 +623,7 @@ float ShaderProgram::zValue(const TransformationMatrix& drawMatrix, float w, flo void ShaderProgram::drawQuadInternal(ShaderType type, const GLfloat* matrix, int textureId, float opacity, GLenum textureTarget, GLenum filter, - const Color& pureColor, const FloatPoint& fillPortion) + const Color& pureColor, const FloatRect& fillPortion) { glUseProgram(m_handleArray[type].programHandle); glUniformMatrix4fv(m_handleArray[type].projMtxHandle, 1, GL_FALSE, matrix); @@ -611,7 +640,8 @@ void ShaderProgram::drawQuadInternal(ShaderType type, const GLfloat* matrix, if (contrastHandle != -1) glUniform1f(contrastHandle, m_contrast); - glUniform2f(m_handleArray[type].fillPortionHandle, fillPortion.x(), fillPortion.y()); + glUniform4f(m_handleArray[type].fillPortionHandle, fillPortion.x(), fillPortion.y(), + fillPortion.width(), fillPortion.height()); } else { glUniform4f(m_handleArray[type].pureColorHandle, pureColor.red() / 255.0, pureColor.green() / 255.0, @@ -643,9 +673,9 @@ GLfloat* ShaderProgram::getTileProjectionMatrix(const DrawQuadData* data) const TransformationMatrix* matrix = data->drawMatrix(); const SkRect* geometry = data->geometry(); - FloatPoint fillPortion = data->fillPortion(); + FloatRect fillPortion = data->fillPortion(); // This modifiedDrawMatrix tranform (0,0)(1x1) to the final rect in screen - // coordinate, before applying the m_webViewMatrix. + // coordinates, before applying the m_webViewMatrix. // It first scale and translate the vertex array from (0,0)(1x1) to real // tile position and size. Then apply the transform from the layer's. // Finally scale to the currentScale to support zooming. @@ -654,9 +684,10 @@ GLfloat* ShaderProgram::getTileProjectionMatrix(const DrawQuadData* data) TransformationMatrix modifiedDrawMatrix; if (type == LayerQuad) modifiedDrawMatrix = *matrix; - modifiedDrawMatrix.translate(geometry->fLeft, geometry->fTop); - modifiedDrawMatrix.scale3d(geometry->width() * fillPortion.x(), - geometry->height() * fillPortion.y(), 1); + modifiedDrawMatrix.translate(geometry->fLeft + geometry->width() * fillPortion.x(), + geometry->fTop + geometry->height() * fillPortion.y()); + modifiedDrawMatrix.scale3d(geometry->width() * fillPortion.width(), + geometry->height() * fillPortion.height(), 1); // Even when we are on a alpha layer or not, we need to respect the // m_webViewMatrix, it may contain the layout offset. Normally it is diff --git a/Source/WebCore/platform/graphics/android/rendering/ShaderProgram.h b/Source/WebCore/platform/graphics/android/rendering/ShaderProgram.h index e290242..4243e12 100644 --- a/Source/WebCore/platform/graphics/android/rendering/ShaderProgram.h +++ b/Source/WebCore/platform/graphics/android/rendering/ShaderProgram.h @@ -115,8 +115,8 @@ public: void initGLResources(); void cleanupGLResources(); // Drawing - void setupDrawing(const IntRect& viewRect, const SkRect& visibleRect, - const IntRect& webViewRect, int titleBarHeight, + void setupDrawing(const IntRect& invScreenRect, const SkRect& visibleContentRect, + const IntRect& screenRect, int titleBarHeight, const IntRect& screenClip, float scale); float zValue(const TransformationMatrix& drawMatrix, float w, float h); @@ -130,20 +130,20 @@ public: void drawQuad(const DrawQuadData* data); void drawVideoLayerQuad(const TransformationMatrix& drawMatrix, float* textureMatrix, SkRect& geometry, int textureId); - FloatRect rectInScreenCoord(const TransformationMatrix& drawMatrix, + FloatRect rectInInvViewCoord(const TransformationMatrix& drawMatrix, const IntSize& size); - FloatRect rectInInvScreenCoord(const TransformationMatrix& drawMatrix, + FloatRect rectInViewCoord(const TransformationMatrix& drawMatrix, const IntSize& size); - FloatRect rectInInvScreenCoord(const FloatRect& rect); - FloatRect rectInScreenCoord(const FloatRect& rect); - FloatRect convertScreenCoordToDocumentCoord(const FloatRect& rect); - FloatRect convertInvScreenCoordToScreenCoord(const FloatRect& rect); - FloatRect convertScreenCoordToInvScreenCoord(const FloatRect& rect); + FloatRect rectInViewCoord(const FloatRect& rect); + FloatRect rectInInvViewCoord(const FloatRect& rect); + FloatRect convertInvViewCoordToContentCoord(const FloatRect& rect); + FloatRect convertViewCoordToInvViewCoord(const FloatRect& rect); + FloatRect convertInvViewCoordToViewCoord(const FloatRect& rect); void clip(const FloatRect& rect); - IntRect clippedRectWithViewport(const IntRect& rect, int margin = 0); - FloatRect documentViewport() { return m_documentViewport; } + IntRect clippedRectWithVisibleContentRect(const IntRect& rect, int margin = 0); + FloatRect contentViewport() { return m_contentViewport; } float contrast() { return m_contrast; } void setContrast(float c) @@ -167,7 +167,7 @@ private: void setBlendingState(bool enableBlending); void drawQuadInternal(ShaderType type, const GLfloat* matrix, int textureId, float opacity, GLenum textureTarget, GLenum filter, - const Color& pureColor, const FloatPoint& fillPortion); + const Color& pureColor, const FloatRect& fillPortion); Color shaderColor(Color pureColor, float opacity); ShaderType getTextureShaderType(GLenum textureTarget); void resetBlending(); @@ -185,21 +185,21 @@ private: TransformationMatrix m_surfaceProjectionMatrix; TransformationMatrix m_clipProjectionMatrix; - TransformationMatrix m_visibleRectProjectionMatrix; + TransformationMatrix m_visibleContentRectProjectionMatrix; GLuint m_textureBuffer[1]; - TransformationMatrix m_documentToScreenMatrix; - TransformationMatrix m_documentToInvScreenMatrix; - SkRect m_viewport; - IntRect m_viewRect; + TransformationMatrix m_contentToInvViewMatrix; + TransformationMatrix m_contentToViewMatrix; + SkRect m_visibleContentRect; + IntRect m_invScreenRect; FloatRect m_clipRect; - IntRect m_screenClip; + IntRect m_invViewClip; int m_titleBarHeight; // This is the layout position in screen coordinate and didn't contain the // animation offset. - IntRect m_webViewRect; + IntRect m_screenRect; - FloatRect m_documentViewport; + FloatRect m_contentViewport; float m_contrast; diff --git a/Source/WebCore/platform/graphics/android/rendering/Surface.cpp b/Source/WebCore/platform/graphics/android/rendering/Surface.cpp index 13c7d27..2617bae 100644 --- a/Source/WebCore/platform/graphics/android/rendering/Surface.cpp +++ b/Source/WebCore/platform/graphics/android/rendering/Surface.cpp @@ -33,15 +33,19 @@ #include "BaseLayerAndroid.h" #include "ClassTracker.h" #include "LayerAndroid.h" +#include "LayerContent.h" #include "GLWebViewState.h" +#include "PrerenderedInval.h" #include "SkCanvas.h" #include "SurfaceBacking.h" +#include "Tile.h" +#include "TileTexture.h" #include "TilesManager.h" #include <wtf/text/CString.h> // Surfaces with an area larger than 2048*2048 should never be unclipped -#define MAX_UNCLIPPED_AREA 4194304 +#define MAX_FULL_CONTENT_AREA 4194304 namespace WebCore { @@ -127,48 +131,48 @@ void Surface::addLayer(LayerAndroid* layer, const TransformationMatrix& transfor m_hasText |= layer->hasText(); // calculate area size for comparison later - IntRect rect = layer->unclippedArea(); + IntRect rect = layer->fullContentArea(); SkPoint pos = layer->getPosition(); rect.setLocation(IntPoint(pos.fX, pos.fY)); if (layer->needsTexture()) { - if (m_unclippedArea.isEmpty()) { + if (m_fullContentArea.isEmpty()) { m_drawTransform = transform; m_drawTransform.translate3d(-pos.fX, -pos.fY, 0); - m_unclippedArea = rect; + m_fullContentArea = rect; } else - m_unclippedArea.unite(rect); + m_fullContentArea.unite(rect); ALOGV("Surf %p adding LA %p, size %d, %d %dx%d, now Surf 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()); + m_fullContentArea.x(), m_fullContentArea.y(), + m_fullContentArea.width(), m_fullContentArea.height()); } if (isBase()) m_background = static_cast<BaseLayerAndroid*>(layer)->getBackgroundColor(); } -IntRect Surface::visibleArea() +IntRect Surface::visibleContentArea() { if (singleLayer()) - return getFirstLayer()->visibleArea(); + return getFirstLayer()->visibleContentArea(); - IntRect rect = m_unclippedArea; + IntRect rect = m_fullContentArea; - // clip with the viewport in documents coordinate - IntRect documentViewport(TilesManager::instance()->shader()->documentViewport()); - rect.intersect(documentViewport); + // clip with the viewport in content coordinate + IntRect contentViewport(TilesManager::instance()->shader()->contentViewport()); + rect.intersect(contentViewport); // TODO: handle recursive layer clip return rect; } -IntRect Surface::unclippedArea() +IntRect Surface::fullContentArea() { if (singleLayer()) - return getFirstLayer()->unclippedArea(); - return m_unclippedArea; + return getFirstLayer()->fullContentArea(); + return m_fullContentArea; } bool Surface::useAggressiveRendering() @@ -181,17 +185,17 @@ bool Surface::useAggressiveRendering() || !m_background.hasAlpha()); } -void Surface::prepareGL(bool layerTilesDisabled) +void Surface::prepareGL(bool layerTilesDisabled, bool updateWithBlit) { bool tilesDisabled = layerTilesDisabled && !isBase(); if (!m_surfaceBacking) { ALOGV("prepareGL on Surf %p, no SurfBack, needsTexture? %d", this, m_surfaceBacking, needsTexture()); - if (!needsTexture()) + if (needsTexture() || (isBase() && layerTilesDisabled)) + m_surfaceBacking = new SurfaceBacking(isBase()); + else return; - - m_surfaceBacking = new SurfaceBacking(isBase()); } if (tilesDisabled) { @@ -199,7 +203,7 @@ void Surface::prepareGL(bool layerTilesDisabled) } else { bool allowZoom = hasText(); // only allow for scale > 1 if painting vectors IntRect prepareArea = computePrepareArea(); - IntRect fullArea = unclippedArea(); + IntRect fullArea = fullContentArea(); ALOGV("prepareGL on Surf %p with SurfBack %p, %d layers, first layer %s (%d) " "prepareArea(%d, %d - %d x %d) fullArea(%d, %d - %d x %d)", @@ -210,8 +214,13 @@ void Surface::prepareGL(bool layerTilesDisabled) fullArea.x(), fullArea.y(), fullArea.width(), fullArea.height()); m_surfaceBacking->prepareGL(getFirstLayer()->state(), allowZoom, - prepareArea, fullArea, - this, useAggressiveRendering()); + prepareArea, fullArea, + this, useAggressiveRendering(), updateWithBlit); + } + for (size_t i = 0; i < m_layers.size(); i++) { + LayerContent* content = m_layers[i]->content(); + if (content) + content->clearPrerenders(); } } @@ -228,7 +237,7 @@ bool Surface::drawGL(bool layerTilesDisabled) if (!isBaseLayer) { // TODO: why are clipping regions wrong for base layer? FloatRect drawClip = getFirstLayer()->drawClip(); - FloatRect clippingRect = TilesManager::instance()->shader()->rectInScreenCoord(drawClip); + FloatRect clippingRect = TilesManager::instance()->shader()->rectInInvViewCoord(drawClip); TilesManager::instance()->shader()->clip(clippingRect); } @@ -237,7 +246,7 @@ bool Surface::drawGL(bool layerTilesDisabled) ALOGV("drawGL on Surf %p with SurfBack %p, first layer %s (%d)", this, m_surfaceBacking, getFirstLayer()->subclassName().ascii().data(), getFirstLayer()->uniqueId()); - IntRect drawArea = visibleArea(); + IntRect drawArea = visibleContentArea(); m_surfaceBacking->drawGL(drawArea, opacity(), drawTransform(), useAggressiveRendering(), background()); } @@ -273,21 +282,41 @@ bool Surface::isMissingContent() return m_surfaceBacking->isMissingContent(); } -IntRect Surface::computePrepareArea() { +bool Surface::canUpdateWithBlit() +{ + // If we don't have a texture, we have nothing to update and thus can take + // the fast path + if (!needsTexture()) + return true; + // If we have a surface backing that isn't ready, we can't update with a blit + // If it is ready, then check to see if it is dirty. We can only call isDirty() + // if isReady() returns true + if (!m_surfaceBacking) + return false; + if (!m_surfaceBacking->isReady()) + return false; + if (!m_surfaceBacking->isDirty()) + return true; + if (!singleLayer()) + return false; + return getFirstLayer()->canUpdateWithBlit(); +} + +IntRect Surface::computePrepareArea() +{ IntRect area; if (!getFirstLayer()->contentIsScrollable() && !isBase() && getFirstLayer()->state()->layersRenderingMode() == GLWebViewState::kAllTextures) { - area = unclippedArea(); + area = fullContentArea(); double total = ((double) area.width()) * ((double) area.height()); - if (total > MAX_UNCLIPPED_AREA) - area = visibleArea(); - } else { - area = visibleArea(); - } + if (total > MAX_FULL_CONTENT_AREA) + area = visibleContentArea(); + } else + area = visibleContentArea(); return area; } @@ -320,8 +349,10 @@ bool Surface::paint(SkCanvas* canvas) // In single surface mode, draw layer content onto the base layer if (isBase() && getFirstLayer()->countChildren() - && getFirstLayer()->state()->layersRenderingMode() > GLWebViewState::kClippedTextures) - getFirstLayer()->getChild(0)->drawCanvas(canvas, true, Layer::FlattenedLayers); + && getFirstLayer()->state()->layersRenderingMode() > GLWebViewState::kClippedTextures) { + for (unsigned int i = 0; i < getFirstLayer()->countChildren(); i++) + getFirstLayer()->getChild(i)->drawCanvas(canvas, true, Layer::FlattenedLayers); + } } else { SkAutoCanvasRestore acr(canvas, true); SkMatrix matrix; @@ -355,6 +386,64 @@ Color* Surface::background() return &m_background; } +bool Surface::blitFromContents(Tile* tile) +{ + if (!singleLayer() || !tile || !getFirstLayer() || !getFirstLayer()->content()) + return false; + + LayerContent* content = getFirstLayer()->content(); + // Extract the dirty rect from the region. Note that this is *NOT* constrained + // to this tile + IntRect dirtyRect = tile->dirtyArea().getBounds(); + IntRect tileRect = IntRect(tile->x() * TilesManager::tileWidth(), + tile->y() * TilesManager::tileHeight(), + TilesManager::tileWidth(), + TilesManager::tileHeight()); + FloatRect tileRectInDoc = tileRect; + tileRectInDoc.scale(1 / tile->scale()); + dirtyRect.intersect(enclosingIntRect(tileRectInDoc)); + PrerenderedInval* prerenderedInval = content->prerenderForRect(dirtyRect); + if (!prerenderedInval || prerenderedInval->bitmap.isNull()) + return false; + SkBitmap sourceBitmap = prerenderedInval->bitmap; + // Calculate the screen rect that is dirty, then intersect it with the + // tile's screen rect so that we end up with the pixels we need to blit + FloatRect screenDirty = dirtyRect; + screenDirty.scale(tile->scale()); + IntRect enclosingScreenDirty = enclosingIntRect(screenDirty); + enclosingScreenDirty.intersect(tileRect); + if (enclosingScreenDirty.isEmpty()) + return false; + // Make sure the screen area we want to blit is contained by the + // prerendered screen area + if (!prerenderedInval->screenArea.contains(enclosingScreenDirty)) { + ALOGD("prerendered->screenArea " INT_RECT_FORMAT " doesn't contain " + "enclosingScreenDirty " INT_RECT_FORMAT, + INT_RECT_ARGS(prerenderedInval->screenArea), + INT_RECT_ARGS(enclosingScreenDirty)); + return false; + } + IntPoint origin = prerenderedInval->screenArea.location(); + SkBitmap subset; + subset.setConfig(sourceBitmap.config(), enclosingScreenDirty.width(), + enclosingScreenDirty.height()); + subset.allocPixels(); + + int topOffset = enclosingScreenDirty.y() - prerenderedInval->screenArea.y(); + int leftOffset = enclosingScreenDirty.x() - prerenderedInval->screenArea.x(); + if (!GLUtils::deepCopyBitmapSubset(sourceBitmap, subset, leftOffset, topOffset)) + return false; + // Now upload + SkIRect textureInval = SkIRect::MakeXYWH(enclosingScreenDirty.x() - tileRect.x(), + enclosingScreenDirty.y() - tileRect.y(), + enclosingScreenDirty.width(), + enclosingScreenDirty.height()); + GLUtils::updateTextureWithBitmap(tile->frontTexture()->m_ownTextureId, + subset, textureInval); + tile->onBlitUpdate(); + return true; +} + const TransformationMatrix* Surface::drawTransform() { // single layer surfaces query the layer's draw transform, while multi-layer diff --git a/Source/WebCore/platform/graphics/android/rendering/Surface.h b/Source/WebCore/platform/graphics/android/rendering/Surface.h index 0fced47..50839ee 100644 --- a/Source/WebCore/platform/graphics/android/rendering/Surface.h +++ b/Source/WebCore/platform/graphics/android/rendering/Surface.h @@ -49,11 +49,12 @@ public: bool tryUpdateSurface(Surface* oldSurface); void addLayer(LayerAndroid* layer, const TransformationMatrix& transform); - void prepareGL(bool layerTilesDisabled); + void prepareGL(bool layerTilesDisabled, bool updateWithBlit); bool drawGL(bool layerTilesDisabled); void swapTiles(); bool isReady(); bool isMissingContent(); + bool canUpdateWithBlit(); void computeTexturesAmount(TexturesResult* result); @@ -66,16 +67,17 @@ public: virtual bool paint(SkCanvas* canvas); virtual float opacity(); virtual Color* background(); + virtual bool blitFromContents(Tile* tile); private: IntRect computePrepareArea(); - IntRect visibleArea(); - IntRect unclippedArea(); + IntRect visibleContentArea(); + IntRect fullContentArea(); bool singleLayer() { return m_layers.size() == 1; } bool useAggressiveRendering(); const TransformationMatrix* drawTransform(); - IntRect m_unclippedArea; + IntRect m_fullContentArea; TransformationMatrix m_drawTransform; SurfaceBacking* m_surfaceBacking; diff --git a/Source/WebCore/platform/graphics/android/rendering/SurfaceBacking.cpp b/Source/WebCore/platform/graphics/android/rendering/SurfaceBacking.cpp index f43472e..af96560 100644 --- a/Source/WebCore/platform/graphics/android/rendering/SurfaceBacking.cpp +++ b/Source/WebCore/platform/graphics/android/rendering/SurfaceBacking.cpp @@ -56,8 +56,9 @@ SurfaceBacking::~SurfaceBacking() } void SurfaceBacking::prepareGL(GLWebViewState* state, bool allowZoom, - const IntRect& prepareArea, const IntRect& unclippedArea, - TilePainter* painter, bool aggressiveRendering) + const IntRect& prepareArea, const IntRect& fullContentArea, + TilePainter* painter, bool aggressiveRendering, + bool updateWithBlit) { float scale = state->scale(); if (scale > 1 && !allowZoom) @@ -88,7 +89,7 @@ void SurfaceBacking::prepareGL(GLWebViewState* state, bool allowZoom, if (m_zooming && (m_zoomUpdateTime < WTF::currentTime())) { // prepare the visible portions of the back tile grid at the futureScale m_backTileGrid->prepareGL(state, m_futureScale, - prepareArea, unclippedArea, painter, + prepareArea, fullContentArea, painter, TileGrid::StandardRegion, false); if (m_backTileGrid->isReady()) { @@ -113,28 +114,29 @@ void SurfaceBacking::prepareGL(GLWebViewState* state, bool allowZoom, // if the front grid hasn't already prepared, or needs to prepare // expanded bounds do so now m_frontTileGrid->prepareGL(state, m_scale, - prepareArea, unclippedArea, painter, prepareRegionFlags, false); + prepareArea, fullContentArea, painter, + prepareRegionFlags, false, updateWithBlit); } if (aggressiveRendering) { // prepare low res content float lowResPrefetchScale = m_scale * LOW_RES_PREFETCH_SCALE_MODIFIER; m_lowResTileGrid->prepareGL(state, lowResPrefetchScale, - prepareArea, unclippedArea, painter, + prepareArea, fullContentArea, painter, TileGrid::StandardRegion | TileGrid::ExpandedRegion, true); m_lowResTileGrid->swapTiles(); } } } -void SurfaceBacking::drawGL(const IntRect& visibleArea, float opacity, +void SurfaceBacking::drawGL(const IntRect& visibleContentArea, float opacity, const TransformationMatrix* transform, bool aggressiveRendering, const Color* background) { // draw low res prefetch page if zooming or front texture missing content if (aggressiveRendering && isMissingContent()) - m_lowResTileGrid->drawGL(visibleArea, opacity, transform); + m_lowResTileGrid->drawGL(visibleContentArea, opacity, transform); - m_frontTileGrid->drawGL(visibleArea, opacity, transform, background); + m_frontTileGrid->drawGL(visibleContentArea, opacity, transform, background); } void SurfaceBacking::markAsDirty(const SkRegion& dirtyArea) @@ -157,14 +159,14 @@ void SurfaceBacking::computeTexturesAmount(TexturesResult* result, LayerAndroid* if (!layer) return; - IntRect unclippedArea = layer->unclippedArea(); - IntRect clippedVisibleArea = layer->visibleArea(); + IntRect fullContentArea = layer->fullContentArea(); + IntRect clippedVisibleArea = layer->visibleContentArea(); // get two numbers here: // - textures needed for a clipped area // - textures needed for an un-clipped area TileGrid* tileGrid = m_zooming ? m_backTileGrid : m_frontTileGrid; - int nbTexturesUnclipped = tileGrid->nbTextures(unclippedArea, m_scale); + int nbTexturesUnclipped = tileGrid->nbTextures(fullContentArea, m_scale); int nbTexturesClipped = tileGrid->nbTextures(clippedVisibleArea, m_scale); // Set kFixedLayers level diff --git a/Source/WebCore/platform/graphics/android/rendering/SurfaceBacking.h b/Source/WebCore/platform/graphics/android/rendering/SurfaceBacking.h index 61e3336..7d3e93c 100644 --- a/Source/WebCore/platform/graphics/android/rendering/SurfaceBacking.h +++ b/Source/WebCore/platform/graphics/android/rendering/SurfaceBacking.h @@ -41,10 +41,11 @@ public: SurfaceBacking(bool isBaseSurface); ~SurfaceBacking(); void prepareGL(GLWebViewState* state, bool allowZoom, - const IntRect& prepareArea, const IntRect& unclippedArea, - TilePainter* painter, bool aggressiveRendering); + const IntRect& prepareArea, const IntRect& fullContentArea, + TilePainter* painter, bool aggressiveRendering, + bool updateWithBlit); void swapTiles(); - void drawGL(const IntRect& visibleArea, float opacity, + void drawGL(const IntRect& visibleContentArea, float opacity, const TransformationMatrix* transform, bool aggressiveRendering, const Color* background); void markAsDirty(const SkRegion& dirtyArea); @@ -59,6 +60,11 @@ public: return !m_zooming && m_frontTileGrid->isReady() && m_scale > 0; } + bool isDirty() + { + return m_frontTileGrid->isDirty(); + } + bool isMissingContent() { return m_zooming || m_frontTileGrid->isMissingContent(); diff --git a/Source/WebCore/platform/graphics/android/rendering/SurfaceCollection.cpp b/Source/WebCore/platform/graphics/android/rendering/SurfaceCollection.cpp index 24e196b..4badf8b 100644 --- a/Source/WebCore/platform/graphics/android/rendering/SurfaceCollection.cpp +++ b/Source/WebCore/platform/graphics/android/rendering/SurfaceCollection.cpp @@ -33,7 +33,7 @@ #include "BaseLayerAndroid.h" #include "ClassTracker.h" #include "GLWebViewState.h" -#include "LayerAndroid.h" +#include "BaseLayerAndroid.h" #include "Surface.h" #include "ScrollableLayerAndroid.h" #include "TilesManager.h" @@ -44,7 +44,7 @@ namespace WebCore { // TILED PAINTING / SURFACES // //////////////////////////////////////////////////////////////////////////////// -SurfaceCollection::SurfaceCollection(LayerAndroid* layer) +SurfaceCollection::SurfaceCollection(BaseLayerAndroid* layer) : m_compositedRoot(layer) { // layer must be non-null. @@ -83,13 +83,17 @@ SurfaceCollection::~SurfaceCollection() #endif } -void SurfaceCollection::prepareGL(const SkRect& visibleRect) +void SurfaceCollection::prepareGL(const SkRect& visibleContentRect, bool tryToFastBlit) { - updateLayerPositions(visibleRect); + updateLayerPositions(visibleContentRect); bool layerTilesDisabled = m_compositedRoot->state()->layersRenderingMode() > GLWebViewState::kClippedTextures; + if (!layerTilesDisabled) { + for (unsigned int i = 0; tryToFastBlit && i < m_surfaces.size(); i++) + tryToFastBlit &= m_surfaces[i]->canUpdateWithBlit(); + } for (unsigned int i = 0; i < m_surfaces.size(); i++) - m_surfaces[i]->prepareGL(layerTilesDisabled); + m_surfaces[i]->prepareGL(layerTilesDisabled, tryToFastBlit); } static inline bool compareSurfaceZ(const Surface* a, const Surface* b) @@ -101,14 +105,14 @@ static inline bool compareSurfaceZ(const Surface* a, const Surface* b) return (la->zValue() > lb->zValue()) && (la->getParent() == lb->getParent()); } -bool SurfaceCollection::drawGL(const SkRect& visibleRect) +bool SurfaceCollection::drawGL(const SkRect& visibleContentRect) { #ifdef DEBUG_COUNT ClassTracker::instance()->show(); #endif bool needsRedraw = false; - updateLayerPositions(visibleRect); + updateLayerPositions(visibleContentRect); bool layerTilesDisabled = m_compositedRoot->state()->layersRenderingMode() > GLWebViewState::kClippedTextures; @@ -223,13 +227,9 @@ void SurfaceCollection::updateScrollableLayer(int layerId, int x, int y) static_cast<ScrollableLayerAndroid*>(layer)->scrollTo(x, y); } -void SurfaceCollection::updateLayerPositions(const SkRect& visibleRect) +void SurfaceCollection::updateLayerPositions(const SkRect& visibleContentRect) { - TransformationMatrix ident; - m_compositedRoot->updateLayerPositions(visibleRect); - FloatRect clip(0, 0, 1e10, 1e10); - m_compositedRoot->updateGLPositionsAndScale( - ident, clip, 1, m_compositedRoot->state()->scale()); + m_compositedRoot->updatePositionsRecursive(visibleContentRect); #ifdef DEBUG m_compositedRoot->showLayer(0); diff --git a/Source/WebCore/platform/graphics/android/rendering/SurfaceCollection.h b/Source/WebCore/platform/graphics/android/rendering/SurfaceCollection.h index 7dfe140..5967c70 100644 --- a/Source/WebCore/platform/graphics/android/rendering/SurfaceCollection.h +++ b/Source/WebCore/platform/graphics/android/rendering/SurfaceCollection.h @@ -37,19 +37,19 @@ class SkRegion; namespace WebCore { -class LayerAndroid; +class BaseLayerAndroid; class Surface; class TexturesResult; class SurfaceCollection : public SkRefCnt { // TODO: investigate webkit threadsafe ref counting public: - SurfaceCollection(LayerAndroid* compositedRoot); + SurfaceCollection(BaseLayerAndroid* compositedRoot); virtual ~SurfaceCollection(); // Tiled painting methods (executed on groups) - void prepareGL(const SkRect& visibleRect); - bool drawGL(const SkRect& visibleRect); + void prepareGL(const SkRect& visibleContentRect, bool tryToFastBlit = false); + bool drawGL(const SkRect& visibleContentRect); Color getBackgroundColor(); void swapTiles(); bool isReady(); @@ -67,8 +67,8 @@ public: void updateScrollableLayer(int layerId, int x, int y); private: - void updateLayerPositions(const SkRect& visibleRect); - LayerAndroid* m_compositedRoot; + void updateLayerPositions(const SkRect& visibleContentRect); + BaseLayerAndroid* m_compositedRoot; WTF::Vector<Surface*> m_surfaces; }; diff --git a/Source/WebCore/platform/graphics/android/rendering/SurfaceCollectionManager.cpp b/Source/WebCore/platform/graphics/android/rendering/SurfaceCollectionManager.cpp index 52a8e44..7c42bd9 100644 --- a/Source/WebCore/platform/graphics/android/rendering/SurfaceCollectionManager.cpp +++ b/Source/WebCore/platform/graphics/android/rendering/SurfaceCollectionManager.cpp @@ -154,7 +154,7 @@ void SurfaceCollectionManager::updateScrollableLayer(int layerId, int x, int y) } int SurfaceCollectionManager::drawGL(double currentTime, IntRect& viewRect, - SkRect& visibleRect, float scale, + SkRect& visibleContentRect, float scale, bool enterFastSwapMode, bool* collectionsSwappedPtr, bool* newCollectionHasAnimPtr, TexturesResult* texturesResultPtr, bool shouldDraw) @@ -171,7 +171,8 @@ int SurfaceCollectionManager::drawGL(double currentTime, IntRect& viewRect, m_paintingCollection->evaluateAnimations(currentTime); - m_paintingCollection->prepareGL(visibleRect); + bool tryFastBlit = !m_fastSwapMode; + m_paintingCollection->prepareGL(visibleContentRect, tryFastBlit); m_paintingCollection->computeTexturesAmount(texturesResultPtr); if (!TilesManager::instance()->useDoubleBuffering() || m_paintingCollection->isReady()) { @@ -186,7 +187,7 @@ int SurfaceCollectionManager::drawGL(double currentTime, IntRect& viewRect, } } else if (m_drawingCollection) { ALOGV("preparing drawing collection %p", m_drawingCollection); - m_drawingCollection->prepareGL(visibleRect); + m_drawingCollection->prepareGL(visibleContentRect); m_drawingCollection->computeTexturesAmount(texturesResultPtr); } @@ -254,7 +255,7 @@ int SurfaceCollectionManager::drawGL(double currentTime, IntRect& viewRect, GLUtils::clearBackgroundIfOpaque(&background); } - if (m_drawingCollection && m_drawingCollection->drawGL(visibleRect)) + if (m_drawingCollection && m_drawingCollection->drawGL(visibleContentRect)) returnFlags |= uirenderer::DrawGlInfo::kStatusDraw; ALOGV("returnFlags %d, m_paintingCollection %d ", returnFlags, m_paintingCollection); diff --git a/Source/WebCore/platform/graphics/android/rendering/SurfaceCollectionManager.h b/Source/WebCore/platform/graphics/android/rendering/SurfaceCollectionManager.h index 125bf02..be4fbca 100644 --- a/Source/WebCore/platform/graphics/android/rendering/SurfaceCollectionManager.h +++ b/Source/WebCore/platform/graphics/android/rendering/SurfaceCollectionManager.h @@ -50,7 +50,7 @@ public: void updateScrollableLayer(int layerId, int x, int y); int drawGL(double currentTime, IntRect& viewRect, - SkRect& visibleRect, float scale, + SkRect& visibleContentRect, float scale, bool enterFastSwapMode, bool* collectionsSwappedPtr, bool* newCollectionHasAnimPtr, TexturesResult* texturesResultPtr, bool shouldDraw); diff --git a/Source/WebCore/platform/graphics/android/rendering/Tile.cpp b/Source/WebCore/platform/graphics/android/rendering/Tile.cpp index 0501777..3af05f4 100644 --- a/Source/WebCore/platform/graphics/android/rendering/Tile.cpp +++ b/Source/WebCore/platform/graphics/android/rendering/Tile.cpp @@ -210,7 +210,7 @@ void Tile::setRepaintPending(bool pending) bool Tile::drawGL(float opacity, const SkRect& rect, float scale, const TransformationMatrix* transform, bool forceBlending, bool usePointSampling, - const FloatPoint& fillPortion) + const FloatRect& fillPortion) { if (m_x < 0 || m_y < 0 || m_scale != scale) return false; @@ -220,9 +220,11 @@ bool Tile::drawGL(float opacity, const SkRect& rect, float scale, if (!m_frontTexture) return false; - if (fillPortion.x() < 1.0f || fillPortion.y() < 1.0f) - ALOGV("drawing tile %p (%d, %d with fill portions %f %f", - this, m_x, m_y, fillPortion.x(), fillPortion.y()); + if (fillPortion.maxX() < 1.0f || fillPortion.maxY() < 1.0f + || fillPortion.x() > 0.0f || fillPortion.y() > 0.0f) + ALOGV("drawing tile %p (%d, %d with fill portions %f %f->%f, %f", + this, m_x, m_y, fillPortion.x(), fillPortion.y(), + fillPortion.maxX(), fillPortion.maxY()); m_frontTexture->drawGL(isLayerTile(), rect, opacity, transform, forceBlending, usePointSampling, fillPortion); @@ -325,75 +327,7 @@ void Tile::paintBitmap(TilePainter* painter) const float tileWidth = renderInfo.tileSize.width(); const float tileHeight = renderInfo.tileSize.height(); - SkRegion::Iterator cliperator(dirtyArea); - - bool fullRepaint = false; - - if (m_fullRepaint - || textureInfo->m_width != tileWidth - || textureInfo->m_height != tileHeight) { - fullRepaint = true; - } - - // For now, only do full repaint - fullRepaint = true; - - if (!fullRepaint) { - // compute the partial inval area - SkIRect totalRect; - totalRect.set(0, 0, 0, 0); - float tileSurface = tileWidth * tileHeight; - float tileSurfaceCap = MAX_INVAL_AREA * tileSurface; - - // We join all the invals in the same tile for now - while (!fullRepaint && !cliperator.done()) { - SkRect realTileRect; - SkRect dirtyRect; - dirtyRect.set(cliperator.rect()); - bool intersect = intersectWithRect(x, y, tileWidth, tileHeight, - scale, dirtyRect, realTileRect); - if (intersect) { - // initialize finalRealRect to the rounded values of realTileRect - SkIRect finalRealRect; - realTileRect.roundOut(&finalRealRect); - - // stash the int values of the current width and height - const int iWidth = finalRealRect.width(); - const int iHeight = finalRealRect.height(); - - if (iWidth == tileWidth || iHeight == tileHeight) { - fullRepaint = true; - break; - } - - // translate the rect into tile space coordinates - finalRealRect.fLeft = finalRealRect.fLeft % static_cast<int>(tileWidth); - finalRealRect.fTop = finalRealRect.fTop % static_cast<int>(tileHeight); - finalRealRect.fRight = finalRealRect.fLeft + iWidth; - finalRealRect.fBottom = finalRealRect.fTop + iHeight; - totalRect.join(finalRealRect); - float repaintSurface = totalRect.width() * totalRect.height(); - - if (repaintSurface > tileSurfaceCap) { - fullRepaint = true; - break; - } - } - - cliperator.next(); - } - - if (!fullRepaint) { - renderInfo.invalRect = &totalRect; - m_renderer->renderTiledContent(renderInfo); - } - } - - // Do a full repaint if needed - if (fullRepaint) { - renderInfo.invalRect = 0; - m_renderer->renderTiledContent(renderInfo); - } + m_renderer->renderTiledContent(renderInfo); m_atomicSync.lock(); @@ -408,13 +342,7 @@ void Tile::paintBitmap(TilePainter* painter) if (m_scale != scale) m_dirty = true; - if (fullRepaint) - m_dirtyArea.setEmpty(); - else - m_dirtyArea.op(dirtyArea, SkRegion::kDifference_Op); - - if (!m_dirtyArea.isEmpty()) - m_dirty = true; + m_dirtyArea.setEmpty(); ALOGV("painted tile %p (%d, %d), texture %p, dirty=%d", this, x, y, texture, m_dirty); @@ -496,6 +424,15 @@ void Tile::backTextureTransferFail() { // whether validatePaint is called before or after, it won't do anything } +void Tile::onBlitUpdate() +{ + // The front texture was directly updated with a blit, so mark this as clean + android::AutoMutex lock(m_atomicSync); + m_dirty = false; + m_dirtyArea.setEmpty(); + m_state = Tile::UpToDate; +} + void Tile::validatePaint() { // ONLY CALL while m_atomicSync is locked (at the end of paintBitmap()) diff --git a/Source/WebCore/platform/graphics/android/rendering/Tile.h b/Source/WebCore/platform/graphics/android/rendering/Tile.h index 58ba15b..9697b61 100644 --- a/Source/WebCore/platform/graphics/android/rendering/Tile.h +++ b/Source/WebCore/platform/graphics/android/rendering/Tile.h @@ -104,7 +104,7 @@ public: bool drawGL(float opacity, const SkRect& rect, float scale, const TransformationMatrix* transform, bool forceBlending, bool usePointSampling, - const FloatPoint& fillPortion); + const FloatRect& fillPortion); // the only thread-safe function called by the background thread void paintBitmap(TilePainter* painter); @@ -116,6 +116,7 @@ public: void markAsDirty(const SkRegion& dirtyArea); bool isDirty(); + const SkRegion& dirtyArea() { return m_dirtyArea; } virtual bool isRepaintPending(); void setRepaintPending(bool pending); float scale() const { return m_scale; } @@ -133,6 +134,7 @@ public: bool swapTexturesIfNeeded(); void backTextureTransfer(); void backTextureTransferFail(); + void onBlitUpdate(); // TextureOwner implementation virtual bool removeTexture(TileTexture* texture); diff --git a/Source/WebCore/platform/graphics/android/rendering/TileGrid.cpp b/Source/WebCore/platform/graphics/android/rendering/TileGrid.cpp index 7c6175f..7680fc9 100644 --- a/Source/WebCore/platform/graphics/android/rendering/TileGrid.cpp +++ b/Source/WebCore/platform/graphics/android/rendering/TileGrid.cpp @@ -34,6 +34,7 @@ #include "GLWebViewState.h" #include "PaintTileOperation.h" #include "Tile.h" +#include "TileTexture.h" #include "TilesManager.h" #include <wtf/CurrentTime.h> @@ -113,7 +114,7 @@ IntRect TileGrid::computeTilesArea(const IntRect& contentArea, float scale) ceilf(contentArea.width() * scale), ceilf(contentArea.height() * scale)); - ALOGV("TG %p prepare, scale %f, area %d x %d", this, scale, area.width(), area.height()); + ALOGV("TG prepare, scale %f, area %d x %d", scale, area.width(), area.height()); if (area.width() == 0 && area.height() == 0) { computedArea.setWidth(0); @@ -134,8 +135,9 @@ IntRect TileGrid::computeTilesArea(const IntRect& contentArea, float scale) } void TileGrid::prepareGL(GLWebViewState* state, float scale, - const IntRect& prepareArea, const IntRect& unclippedArea, - TilePainter* painter, int regionFlags, bool isLowResPrefetch) + const IntRect& prepareArea, const IntRect& fullContentArea, + TilePainter* painter, int regionFlags, bool isLowResPrefetch, + bool updateWithBlit) { // first, how many tiles do we need m_area = computeTilesArea(prepareArea, scale); @@ -181,17 +183,17 @@ void TileGrid::prepareGL(GLWebViewState* state, float scale, if (goingDown) { for (int j = 0; j < m_area.height(); j++) prepareTile(m_area.x() + i, m_area.y() + j, - painter, state, isLowResPrefetch, false); + painter, state, isLowResPrefetch, false, updateWithBlit); } else { for (int j = m_area.height() - 1; j >= 0; j--) prepareTile(m_area.x() + i, m_area.y() + j, - painter, state, isLowResPrefetch, false); + painter, state, isLowResPrefetch, false, updateWithBlit); } } } if (regionFlags & ExpandedRegion) { - IntRect fullArea = computeTilesArea(unclippedArea, scale); + IntRect fullArea = computeTilesArea(fullContentArea, scale); IntRect expandedArea = m_area; // on systems reporting highEndGfx=true and useMinimalMemory not set, use expanded bounds @@ -207,7 +209,7 @@ void TileGrid::prepareGL(GLWebViewState* state, float scale, for (int i = expandedArea.x(); i < expandedArea.maxX(); i++) for (int j = expandedArea.y(); j < expandedArea.maxY(); j++) if (!m_area.contains(i, j)) - prepareTile(i, j, painter, state, isLowResPrefetch, true); + prepareTile(i, j, painter, state, isLowResPrefetch, true, updateWithBlit); } } @@ -219,7 +221,8 @@ void TileGrid::markAsDirty(const SkRegion& invalRegion) } void TileGrid::prepareTile(int x, int y, TilePainter* painter, - GLWebViewState* state, bool isLowResPrefetch, bool isExpandPrefetch) + GLWebViewState* state, bool isLowResPrefetch, + bool isExpandPrefetch, bool shouldTryUpdateWithBlit) { Tile* tile = getTile(x, y); if (!tile) { @@ -232,6 +235,9 @@ void TileGrid::prepareTile(int x, int y, TilePainter* painter, tile->setContents(x, y, m_scale, isExpandPrefetch); + if (shouldTryUpdateWithBlit && tryBlitFromContents(tile, painter)) + return; + if (tile->isDirty() || !tile->frontTexture()) tile->reserveTexture(); @@ -243,6 +249,15 @@ void TileGrid::prepareTile(int x, int y, TilePainter* painter, } } +bool TileGrid::tryBlitFromContents(Tile* tile, TilePainter* painter) +{ + return tile->frontTexture() + && !tile->frontTexture()->isPureColor() + && tile->frontTexture()->m_ownTextureId + && !tile->isRepaintPending() + && painter->blitFromContents(tile); +} + Tile* TileGrid::getTile(int x, int y) { for (unsigned int i = 0; i <m_tiles.size(); i++) { @@ -270,11 +285,11 @@ int TileGrid::nbTextures(IntRect& area, float scale) return numberTextures; } -void TileGrid::drawGL(const IntRect& visibleArea, float opacity, +void TileGrid::drawGL(const IntRect& visibleContentArea, float opacity, const TransformationMatrix* transform, const Color* background) { - m_area = computeTilesArea(visibleArea, m_scale); + m_area = computeTilesArea(visibleContentArea, m_scale); if (m_area.width() == 0 || m_area.height() == 0) return; @@ -296,10 +311,12 @@ void TileGrid::drawGL(const IntRect& visibleArea, float opacity, bool usePointSampling = TilesManager::instance()->shader()->usePointSampling(m_scale, transform); - - float maxTileWidth = visibleArea.maxX() / tileWidth; - float maxTileHeight = visibleArea.maxY() / tileWidth; - + float minTileX = visibleContentArea.x() / tileWidth; + float minTileY = visibleContentArea.y() / tileWidth; + float maxTileWidth = visibleContentArea.maxX() / tileWidth; + float maxTileHeight = visibleContentArea.maxY() / tileWidth; + ALOGV("minTileX, minTileY, maxTileWidth, maxTileHeight %f, %f, %f %f", + minTileX, minTileY, maxTileWidth, maxTileHeight); for (unsigned int i = 0; i < m_tiles.size(); i++) { Tile* tile = m_tiles[i]; @@ -316,8 +333,20 @@ void TileGrid::drawGL(const IntRect& visibleArea, float opacity, bool forceBaseBlending = background ? background->hasAlpha() : false; - FloatPoint fillPortion(std::min(maxTileWidth - tile->x(), 1.0f), - std::min(maxTileHeight - tile->y(), 1.0f)); + float left = std::max(minTileX - tile->x(), 0.0f); + float top = std::max(minTileY - tile->y(), 0.0f); + float right = std::min(maxTileWidth - tile->x(), 1.0f); + float bottom = std::min(maxTileHeight - tile->y(), 1.0f); + if (left > 1.0f || top > 1.0f || right < 0.0f || bottom < 0.0f) { + ALOGE("Unexpected portion:left, top, right, bottom %f %f %f %f", + left, top, right, bottom); + left = 0.0f; + top = 0.0f; + right = 1.0f; + bottom = 1.0f; + } + FloatRect fillPortion(left, top, right - left, bottom - top); + bool success = tile->drawGL(opacity, rect, m_scale, transform, forceBaseBlending, usePointSampling, fillPortion); if (semiOpaqueBaseSurface && success) { diff --git a/Source/WebCore/platform/graphics/android/rendering/TileGrid.h b/Source/WebCore/platform/graphics/android/rendering/TileGrid.h index 2483e0e..b480419 100644 --- a/Source/WebCore/platform/graphics/android/rendering/TileGrid.h +++ b/Source/WebCore/platform/graphics/android/rendering/TileGrid.h @@ -49,15 +49,13 @@ public: static IntRect computeTilesArea(const IntRect& contentArea, float scale); void prepareGL(GLWebViewState* state, float scale, - const IntRect& prepareArea, const IntRect& unclippedArea, + const IntRect& prepareArea, const IntRect& fullContentArea, TilePainter* painter, int regionFlags = StandardRegion, - bool isLowResPrefetch = false); + bool isLowResPrefetch = false, bool updateWithBlit = false); void swapTiles(); - void drawGL(const IntRect& visibleArea, float opacity, + void drawGL(const IntRect& visibleContentArea, float opacity, const TransformationMatrix* transform, const Color* background = 0); - void prepareTile(int x, int y, TilePainter* painter, - GLWebViewState* state, bool isLowResPrefetch, bool isExpandPrefetch); void markAsDirty(const SkRegion& dirtyArea); Tile* getTile(int x, int y); @@ -67,11 +65,17 @@ public: bool isReady(); bool isMissingContent(); + bool isDirty() { return !m_dirtyRegion.isEmpty(); } int nbTextures(IntRect& area, float scale); private: + void prepareTile(int x, int y, TilePainter* painter, + GLWebViewState* state, bool isLowResPrefetch, + bool isExpandPrefetch, bool shouldTryUpdateWithBlit); void drawMissingRegion(const SkRegion& region, float opacity, const Color* tileBackground); + bool tryBlitFromContents(Tile* tile, TilePainter* painter); + WTF::Vector<Tile*> m_tiles; IntRect m_area; diff --git a/Source/WebCore/platform/graphics/android/rendering/TilePainter.h b/Source/WebCore/platform/graphics/android/rendering/TilePainter.h index 53dfadc..901db66 100644 --- a/Source/WebCore/platform/graphics/android/rendering/TilePainter.h +++ b/Source/WebCore/platform/graphics/android/rendering/TilePainter.h @@ -34,6 +34,7 @@ class SkCanvas; namespace WebCore { class Color; +class Tile; class TilePainter : public SkRefCnt { // TODO: investigate webkit threadsafe ref counting @@ -44,6 +45,7 @@ public: enum SurfaceType { Painted, Image }; virtual SurfaceType type() { return Painted; } virtual Color* background() { return 0; } + virtual bool blitFromContents(Tile* tile) { return false; } unsigned int getUpdateCount() { return m_updateCount; } void setUpdateCount(unsigned int updateCount) { m_updateCount = updateCount; } diff --git a/Source/WebCore/platform/graphics/android/rendering/TileTexture.cpp b/Source/WebCore/platform/graphics/android/rendering/TileTexture.cpp index 54c67cc..be4b4db 100644 --- a/Source/WebCore/platform/graphics/android/rendering/TileTexture.cpp +++ b/Source/WebCore/platform/graphics/android/rendering/TileTexture.cpp @@ -121,7 +121,7 @@ void TileTexture::transferComplete() void TileTexture::drawGL(bool isLayer, const SkRect& rect, float opacity, const TransformationMatrix* transform, bool forceBlending, bool usePointSampling, - const FloatPoint& fillPortion) + const FloatRect& fillPortion) { ShaderProgram* shader = TilesManager::instance()->shader(); diff --git a/Source/WebCore/platform/graphics/android/rendering/TileTexture.h b/Source/WebCore/platform/graphics/android/rendering/TileTexture.h index b694241..e31da5b 100644 --- a/Source/WebCore/platform/graphics/android/rendering/TileTexture.h +++ b/Source/WebCore/platform/graphics/android/rendering/TileTexture.h @@ -27,7 +27,7 @@ #define TileTexture_h #include "Color.h" -#include "FloatPoint.h" +#include "FloatRect.h" #include "SkBitmap.h" #include "SkRect.h" #include "SkSize.h" @@ -82,7 +82,7 @@ public: void drawGL(bool isLayer, const SkRect& rect, float opacity, const TransformationMatrix* transform, bool forceBlending, bool usePointSampling, - const FloatPoint& fillPortion); + const FloatRect& fillPortion); private: TextureInfo m_ownTextureInfo; SkSize m_size; diff --git a/Source/WebCore/platform/graphics/android/rendering/TilesManager.cpp b/Source/WebCore/platform/graphics/android/rendering/TilesManager.cpp index 731db23..6e22d25 100644 --- a/Source/WebCore/platform/graphics/android/rendering/TilesManager.cpp +++ b/Source/WebCore/platform/graphics/android/rendering/TilesManager.cpp @@ -50,10 +50,10 @@ // one viewport, otherwise the allocation may stall. // We need n textures for one TiledPage, and another n textures for the // second page used when scaling. -// In our case, we use 256*256 textures. On the tablet, this equates to -// at least 60 textures, or 112 with expanded tile boundaries. -// 112(tiles)*256*256*4(bpp)*2(pages) = 56MB -// It turns out the viewport dependent value m_maxTextureCount is a reasonable +// In our case, we use 256*256 textures. Both base and layers can use up to +// MAX_TEXTURE_ALLOCATION textures, which is 224MB GPU memory in total. +// For low end graphics systems, we cut this upper limit to half. +// We've found the viewport dependent value m_currentTextureCount is a reasonable // number to cap the layer tile texturs, it worked on both phones and tablets. // TODO: after merge the pool of base tiles and layer tiles, we should revisit // the logic of allocation management. @@ -67,24 +67,26 @@ namespace WebCore { -GLint TilesManager::getMaxTextureSize() -{ - static GLint maxTextureSize = 0; - if (!maxTextureSize) - glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize); - return maxTextureSize; -} - int TilesManager::getMaxTextureAllocation() { - return MAX_TEXTURE_ALLOCATION; + if (m_maxTextureAllocation == -1) { + GLint glMaxTextureSize = 0; + glGetIntegerv(GL_MAX_TEXTURE_SIZE, &glMaxTextureSize); + GLUtils::checkGlError("TilesManager::getMaxTextureAllocation"); + // Half of glMaxTextureSize can be used for base, the other half for layers. + m_maxTextureAllocation = std::min(MAX_TEXTURE_ALLOCATION, glMaxTextureSize / 2); + if (!m_highEndGfx) + m_maxTextureAllocation = m_maxTextureAllocation / 2; + } + return m_maxTextureAllocation; } TilesManager::TilesManager() : m_layerTexturesRemain(true) , m_highEndGfx(false) - , m_maxTextureCount(0) - , m_maxLayerTextureCount(0) + , m_currentTextureCount(0) + , m_currentLayerTextureCount(0) + , m_maxTextureAllocation(-1) , m_generatorReady(false) , m_showVisualIndicator(false) , m_invertedScreen(false) @@ -107,10 +109,10 @@ TilesManager::TilesManager() m_pixmapsGenerationThread->run("TexturesGenerator"); } -void TilesManager::allocateTiles() +void TilesManager::allocateTextures() { - int nbTexturesToAllocate = m_maxTextureCount - m_textures.size(); - ALOGV("%d tiles to allocate (%d textures planned)", nbTexturesToAllocate, m_maxTextureCount); + int nbTexturesToAllocate = m_currentTextureCount - m_textures.size(); + ALOGV("%d tiles to allocate (%d textures planned)", nbTexturesToAllocate, m_currentTextureCount); int nbTexturesAllocated = 0; for (int i = 0; i < nbTexturesToAllocate; i++) { TileTexture* texture = new TileTexture( @@ -124,9 +126,9 @@ void TilesManager::allocateTiles() nbTexturesAllocated++; } - int nbLayersTexturesToAllocate = m_maxLayerTextureCount - m_tilesTextures.size(); + int nbLayersTexturesToAllocate = m_currentLayerTextureCount - m_tilesTextures.size(); ALOGV("%d layers tiles to allocate (%d textures planned)", - nbLayersTexturesToAllocate, m_maxLayerTextureCount); + nbLayersTexturesToAllocate, m_currentLayerTextureCount); int nbLayersTexturesAllocated = 0; for (int i = 0; i < nbLayersTexturesToAllocate; i++) { TileTexture* texture = new TileTexture( @@ -202,9 +204,9 @@ void TilesManager::discardTexturesVector(unsigned long long sparedDrawCount, textures.remove(discardedIndex[i]); int remainedTextureNumber = textures.size(); - int* countPtr = base ? &m_maxTextureCount : &m_maxLayerTextureCount; + int* countPtr = base ? &m_currentTextureCount : &m_currentLayerTextureCount; if (remainedTextureNumber < *countPtr) { - ALOGV("reset maxTextureCount for %s tiles from %d to %d", + ALOGV("reset currentTextureCount for %s tiles from %d to %d", base ? "base" : "layer", *countPtr, remainedTextureNumber); *countPtr = remainedTextureNumber; } @@ -356,41 +358,39 @@ bool TilesManager::highEndGfx() return m_highEndGfx; } -int TilesManager::maxTextureCount() +int TilesManager::currentTextureCount() { android::Mutex::Autolock lock(m_texturesLock); - return m_maxTextureCount; + return m_currentTextureCount; } -int TilesManager::maxLayerTextureCount() +int TilesManager::currentLayerTextureCount() { android::Mutex::Autolock lock(m_texturesLock); - return m_maxLayerTextureCount; + return m_currentLayerTextureCount; } -void TilesManager::setMaxTextureCount(int max) +void TilesManager::setCurrentTextureCount(int newTextureCount) { - ALOGV("setMaxTextureCount: %d (current: %d, total:%d)", - max, m_maxTextureCount, MAX_TEXTURE_ALLOCATION); - if (m_maxTextureCount == MAX_TEXTURE_ALLOCATION || - max <= m_maxTextureCount) + int maxTextureAllocation = getMaxTextureAllocation(); + ALOGV("setCurrentTextureCount: %d (current: %d, max:%d)", + newTextureCount, m_currentTextureCount, maxTextureAllocation); + if (m_currentTextureCount == maxTextureAllocation || + newTextureCount <= m_currentTextureCount) return; android::Mutex::Autolock lock(m_texturesLock); + m_currentTextureCount = std::min(newTextureCount, maxTextureAllocation); - if (max < MAX_TEXTURE_ALLOCATION) - m_maxTextureCount = max; - else - m_maxTextureCount = MAX_TEXTURE_ALLOCATION; - - allocateTiles(); + allocateTextures(); } -void TilesManager::setMaxLayerTextureCount(int max) +void TilesManager::setCurrentLayerTextureCount(int newTextureCount) { - ALOGV("setMaxLayerTextureCount: %d (current: %d, total:%d)", - max, m_maxLayerTextureCount, MAX_TEXTURE_ALLOCATION); - if (!max && m_hasLayerTextures) { + int maxTextureAllocation = getMaxTextureAllocation(); + ALOGV("setCurrentLayerTextureCount: %d (current: %d, max:%d)", + newTextureCount, m_currentLayerTextureCount, maxTextureAllocation); + if (!newTextureCount && m_hasLayerTextures) { double secondsSinceLayersUsed = WTF::currentTime() - m_lastTimeLayersUsed; if (secondsSinceLayersUsed > LAYER_TEXTURES_DESTROY_TIMEOUT) { unsigned long long sparedDrawCount = ~0; // by default, spare no textures @@ -401,18 +401,14 @@ void TilesManager::setMaxLayerTextureCount(int max) return; } m_lastTimeLayersUsed = WTF::currentTime(); - if (m_maxLayerTextureCount == MAX_TEXTURE_ALLOCATION || - max <= m_maxLayerTextureCount) + if (m_currentLayerTextureCount == maxTextureAllocation || + newTextureCount <= m_currentLayerTextureCount) return; android::Mutex::Autolock lock(m_texturesLock); + m_currentLayerTextureCount = std::min(newTextureCount, maxTextureAllocation); - if (max < MAX_TEXTURE_ALLOCATION) - m_maxLayerTextureCount = max; - else - m_maxLayerTextureCount = MAX_TEXTURE_ALLOCATION; - - allocateTiles(); + allocateTextures(); m_hasLayerTextures = true; } @@ -475,12 +471,12 @@ bool TilesManager::updateContextIfChanged() return changed; } -float TilesManager::tileWidth() +int TilesManager::tileWidth() { return TILE_WIDTH; } -float TilesManager::tileHeight() +int TilesManager::tileHeight() { return TILE_HEIGHT; } diff --git a/Source/WebCore/platform/graphics/android/rendering/TilesManager.h b/Source/WebCore/platform/graphics/android/rendering/TilesManager.h index 17d44b5..295acf6 100644 --- a/Source/WebCore/platform/graphics/android/rendering/TilesManager.h +++ b/Source/WebCore/platform/graphics/android/rendering/TilesManager.h @@ -47,8 +47,6 @@ class TilesManager { public: // May only be called from the UI thread static TilesManager* instance(); - static GLint getMaxTextureSize(); - static int getMaxTextureAllocation(); static bool hardwareAccelerationEnabled() { @@ -85,14 +83,14 @@ public: void setHighEndGfx(bool highEnd); bool highEndGfx(); - int maxTextureCount(); - int maxLayerTextureCount(); - void setMaxTextureCount(int max); - void setMaxLayerTextureCount(int max); - static float tileWidth(); - static float tileHeight(); + int currentTextureCount(); + int currentLayerTextureCount(); + void setCurrentTextureCount(int newTextureCount); + void setCurrentLayerTextureCount(int newTextureCount); + static int tileWidth(); + static int tileHeight(); - void allocateTiles(); + void allocateTextures(); // remove all tiles from textures (and optionally deallocate gl memory) void discardTextures(bool allTextures, bool glTextures); @@ -168,6 +166,7 @@ private: bool deallocateGLTextures); void markAllGLTexturesZero(); bool updateContextIfChanged(); + int getMaxTextureAllocation(); WTF::Vector<TileTexture*> m_textures; WTF::Vector<TileTexture*> m_availableTextures; @@ -177,8 +176,9 @@ private: bool m_layerTexturesRemain; bool m_highEndGfx; - int m_maxTextureCount; - int m_maxLayerTextureCount; + int m_currentTextureCount; + int m_currentLayerTextureCount; + int m_maxTextureAllocation; bool m_generatorReady; diff --git a/Source/WebCore/platform/graphics/android/rendering/TransferQueue.cpp b/Source/WebCore/platform/graphics/android/rendering/TransferQueue.cpp index df5ba6e..2316014 100644 --- a/Source/WebCore/platform/graphics/android/rendering/TransferQueue.cpp +++ b/Source/WebCore/platform/graphics/android/rendering/TransferQueue.cpp @@ -166,34 +166,14 @@ void TransferQueue::blitTileFromQueue(GLuint fboID, TileTexture* destTex, int textureWidth = destTex->getSize().width(); int textureHeight = destTex->getSize().height(); - IntRect inval = m_transferQueue[index].invalRect; - bool partialInval = !inval.isEmpty(); - - if (partialInval && frontTex) { - // recopy the previous texture to the new one, as - // the partial update will not cover the entire texture - glFramebufferTexture2D(GL_FRAMEBUFFER, - GL_COLOR_ATTACHMENT0, - GL_TEXTURE_2D, - frontTex->m_ownTextureId, - 0); - glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, - textureWidth, textureHeight); - } - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, srcTexId, 0); - if (!partialInval) { - glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, - textureWidth, textureHeight); - } else { - glCopyTexSubImage2D(GL_TEXTURE_2D, 0, inval.x(), inval.y(), 0, 0, - inval.width(), inval.height()); - } + glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, + textureWidth, textureHeight); #else // Then set up the FBO and copy the SurfTex content in. @@ -412,8 +392,7 @@ void TransferQueue::updateDirtyTiles() if (m_transferQueue[index].uploadType == CpuUpload) { // Here we just need to upload the bitmap content to the GL Texture GLUtils::updateTextureWithBitmap(destTexture->m_ownTextureId, - *m_transferQueue[index].bitmap, - m_transferQueue[index].invalRect); + *m_transferQueue[index].bitmap); } else { if (!usedFboForUpload) { saveGLState(); @@ -517,13 +496,6 @@ void TransferQueue::addItemCommon(const TileRenderInfo* renderInfo, data->uploadType = type; IntRect inval(0, 0, 0, 0); - if (renderInfo->invalRect) { - inval.setX(renderInfo->invalRect->fLeft); - inval.setY(renderInfo->invalRect->fTop); - inval.setWidth(renderInfo->invalRect->width()); - inval.setHeight(renderInfo->invalRect->height()); - } - data->invalRect = inval; } // Note that there should be lock/unlock around this function call. diff --git a/Source/WebCore/platform/graphics/android/rendering/TransferQueue.h b/Source/WebCore/platform/graphics/android/rendering/TransferQueue.h index fe58336..b8563e3 100644 --- a/Source/WebCore/platform/graphics/android/rendering/TransferQueue.h +++ b/Source/WebCore/platform/graphics/android/rendering/TransferQueue.h @@ -91,7 +91,6 @@ public: TransferItemStatus status; Tile* savedTilePtr; TileTexture* savedTileTexturePtr; - IntRect invalRect; TextureUploadType uploadType; // This is only useful in Cpu upload code path, so it will be dynamically // lazily allocated. |