diff options
Diffstat (limited to 'Source')
28 files changed, 682 insertions, 134 deletions
diff --git a/Source/WebCore/platform/android/RenderThemeAndroid.cpp b/Source/WebCore/platform/android/RenderThemeAndroid.cpp index 481ecbf..93c99a4 100644 --- a/Source/WebCore/platform/android/RenderThemeAndroid.cpp +++ b/Source/WebCore/platform/android/RenderThemeAndroid.cpp @@ -428,6 +428,7 @@ static void adjustMenuListStyleCommon(RenderStyle* style) style->setPaddingTop(Length(RenderSkinCombo::padding(), Fixed)); style->setPaddingBottom(Length(RenderSkinCombo::padding(), Fixed)); style->setPaddingRight(Length(RenderSkinCombo::extraWidth(), Fixed)); + style->setMinHeight(Length(RenderSkinCombo::minHeight(), Fixed)); } void RenderThemeAndroid::adjustListboxStyle(CSSStyleSelector*, RenderStyle* style, Element*) const diff --git a/Source/WebCore/platform/android/ScrollViewAndroid.cpp b/Source/WebCore/platform/android/ScrollViewAndroid.cpp index f54e5ea..f29e998 100644 --- a/Source/WebCore/platform/android/ScrollViewAndroid.cpp +++ b/Source/WebCore/platform/android/ScrollViewAndroid.cpp @@ -100,7 +100,8 @@ void ScrollView::platformSetScrollPosition(const WebCore::IntPoint& pt) { if (parent()) // don't attempt to scroll subframes; they're fully visible return; - PlatformBridge::setScrollPosition(this, pt.x(), pt.y()); + PlatformBridge::setScrollPosition(this, m_scrollOrigin.x() + pt.x(), + m_scrollOrigin.y() + pt.y()); } void ScrollView::platformSetScrollbarModes() @@ -119,7 +120,9 @@ void ScrollView::platformScrollbarModes(ScrollbarMode& h, ScrollbarMode& v) cons void ScrollView::platformRepaintContentRectangle(const IntRect &rect, bool now) { - android::WebViewCore::getWebViewCore(this)->contentInvalidate(rect); + IntRect offsetRect = rect; + offsetRect.move(m_scrollOrigin.x(), m_scrollOrigin.y()); + android::WebViewCore::getWebViewCore(this)->contentInvalidate(offsetRect); } #ifdef ANDROID_CAPTURE_OFFSCREEN_PAINTS diff --git a/Source/WebCore/platform/graphics/android/BaseLayerAndroid.cpp b/Source/WebCore/platform/graphics/android/BaseLayerAndroid.cpp index 2a1b1de..0e6f64f 100644 --- a/Source/WebCore/platform/graphics/android/BaseLayerAndroid.cpp +++ b/Source/WebCore/platform/graphics/android/BaseLayerAndroid.cpp @@ -101,13 +101,14 @@ void BaseLayerAndroid::setContent(const PictureSet& src) // setSize(src.width(), src.height()); } -void BaseLayerAndroid::drawCanvas(SkCanvas* canvas) +bool BaseLayerAndroid::drawCanvas(SkCanvas* canvas) { #if USE(ACCELERATED_COMPOSITING) android::Mutex::Autolock lock(m_drawLock); #endif if (!m_content.isEmpty()) m_content.draw(canvas); + return true; } #if USE(ACCELERATED_COMPOSITING) @@ -307,16 +308,6 @@ bool BaseLayerAndroid::drawGL(double currentTime, LayerAndroid* compositedRoot, m_glWebViewState->resetFrameworkInval(); if (compositedRoot) { - TransformationMatrix ident; - - bool animsRunning = compositedRoot->evaluateAnimations(); - if (animsRunning) - needsRedraw = true; - - compositedRoot->updateFixedLayersPositions(visibleRect); - FloatRect clip(0, 0, viewRect.width(), viewRect.height()); - compositedRoot->updateGLPositionsAndScale( - ident, clip, 1, m_glWebViewState->zoomManager()->layersScale()); SkMatrix matrix; matrix.setTranslate(viewRect.x(), viewRect.y()); @@ -326,20 +317,16 @@ bool BaseLayerAndroid::drawGL(double currentTime, LayerAndroid* compositedRoot, compositedRoot->nbLayers(), compositedRoot->nbTexturedLayers()); #endif - - // Clean up GL textures for video layer. - TilesManager::instance()->videoLayerManager()->deleteUnusedTextures(); - - compositedRoot->prepare(m_glWebViewState); - if (compositedRoot->drawGL(m_glWebViewState, matrix)) { + // For now, we render layers only if the rendering mode + // is kAllTextures or kClippedTextures + if (m_glWebViewState->layersRenderingMode() < GLWebViewState::kScrollableAndFixedLayers + && compositedRoot->drawGL(m_glWebViewState, matrix)) { if (TilesManager::instance()->layerTexturesRemain()) { // only try redrawing for layers if layer textures remain, // otherwise we'll repaint without getting anything done needsRedraw = true; } - } else if (!animsRunning) - m_glWebViewState->resetLayersDirtyArea(); - + } } m_previousVisible = visibleRect; diff --git a/Source/WebCore/platform/graphics/android/BaseLayerAndroid.h b/Source/WebCore/platform/graphics/android/BaseLayerAndroid.h index ad77013..20942ec 100644 --- a/Source/WebCore/platform/graphics/android/BaseLayerAndroid.h +++ b/Source/WebCore/platform/graphics/android/BaseLayerAndroid.h @@ -58,7 +58,7 @@ public: // the passed canvas. We used it to paint the GL tiles as well as // WebView::copyBaseContentToPicture(), so a lock is necessary as // we are running in different threads. - void drawCanvas(SkCanvas* canvas); + virtual bool drawCanvas(SkCanvas* canvas); bool drawGL(double currentTime, LayerAndroid* compositedRoot, IntRect& rect, SkRect& viewport, float scale, bool* buffersSwappedPtr); diff --git a/Source/WebCore/platform/graphics/android/GLWebViewState.cpp b/Source/WebCore/platform/graphics/android/GLWebViewState.cpp index 3fb2384..fa22593 100644 --- a/Source/WebCore/platform/graphics/android/GLWebViewState.cpp +++ b/Source/WebCore/platform/graphics/android/GLWebViewState.cpp @@ -33,11 +33,14 @@ #include "GLUtils.h" #include "ImagesManager.h" #include "LayerAndroid.h" +#include "ScrollableLayerAndroid.h" #include "SkPath.h" #include "TilesManager.h" #include "TilesTracker.h" #include <wtf/CurrentTime.h> +#include <pthread.h> + #include <cutils/log.h> #include <wtf/text/CString.h> @@ -86,6 +89,7 @@ GLWebViewState::GLWebViewState() , m_expandedTileBoundsX(0) , m_expandedTileBoundsY(0) , m_scale(1) + , m_layersRenderingMode(kAllTextures) { m_viewport.setEmpty(); m_futureViewportTileBounds.setEmpty(); @@ -151,7 +155,6 @@ void GLWebViewState::setBaseLayer(BaseLayerAndroid* layer, const SkRegion& inval SkSafeUnref(m_currentBaseLayer); m_currentBaseLayer = layer; - // copy content from old composited root to new LayerAndroid* oldRoot = m_currentBaseLayerRoot; if (layer) { @@ -173,7 +176,13 @@ void GLWebViewState::setBaseLayer(BaseLayerAndroid* layer, const SkRegion& inval m_paintingBaseLayer = layer; } m_glExtras.setDrawExtra(0); - invalRegion(inval); + + // TODO: do the union of both layers tree to compute + // the minimum inval instead of doing a fullInval() + if (m_layersRenderingMode == kSingleSurfaceRendering) + fullInval(); + else + invalRegion(inval); #ifdef MEASURES_PERF if (m_measurePerfs && !showVisualIndicator) @@ -184,6 +193,14 @@ void GLWebViewState::setBaseLayer(BaseLayerAndroid* layer, const SkRegion& inval TilesManager::instance()->setShowVisualIndicator(showVisualIndicator); } +void GLWebViewState::scrolledLayer(ScrollableLayerAndroid*) +{ + // TODO: only inval the area of the scrolled layer instead of + // doing a fullInval() + if (m_layersRenderingMode == kSingleSurfaceRendering) + fullInval(); +} + void GLWebViewState::invalRegion(const SkRegion& region) { SkRegion::Iterator iterator(region); @@ -241,6 +258,11 @@ unsigned int GLWebViewState::paintBaseLayerContent(SkCanvas* canvas) m_baseLayerLock.unlock(); if (base) { base->drawCanvas(canvas); + if (m_layersRenderingMode == kSingleSurfaceRendering) { + LayerAndroid* rootLayer = static_cast<LayerAndroid*>(base->getChild(0)); + if (rootLayer) + rootLayer->drawCanvas(canvas); + } } SkSafeUnref(base); return m_currentPictureCounter; @@ -402,6 +424,69 @@ double GLWebViewState::setupDrawing(IntRect& viewRect, SkRect& visibleRect, return currentTime; } +bool GLWebViewState::setLayersRenderingMode(TexturesResult& nbTexturesNeeded) +{ + bool invalBase = false; + int maxTextures = TilesManager::instance()->maxTextureCount(); + LayersRenderingMode layersRenderingMode = m_layersRenderingMode; + + m_layersRenderingMode = kSingleSurfaceRendering; + if (nbTexturesNeeded.fixed < maxTextures) + m_layersRenderingMode = kFixedLayers; + if (nbTexturesNeeded.scrollable < maxTextures) + m_layersRenderingMode = kScrollableAndFixedLayers; + if (nbTexturesNeeded.clipped < maxTextures) + m_layersRenderingMode = kClippedTextures; + if (nbTexturesNeeded.full < maxTextures) + m_layersRenderingMode = kAllTextures; + + if (m_layersRenderingMode < layersRenderingMode + && m_layersRenderingMode != kAllTextures) + invalBase = true; + + if (m_layersRenderingMode > layersRenderingMode + && m_layersRenderingMode != kClippedTextures) + invalBase = true; + +#ifdef DEBUG + if (m_layersRenderingMode != layersRenderingMode) { + char* mode[] = { "kAllTextures", "kClippedTextures", + "kScrollableAndFixedLayers", "kFixedLayers", "kSingleSurfaceRendering" }; + XLOGC("Change from mode %s to %s -- We need textures: fixed: %d," + " scrollable: %d, clipped: %d, full: %d, max textures: %d", + static_cast<char*>(mode[layersRenderingMode]), + static_cast<char*>(mode[m_layersRenderingMode]), + nbTexturesNeeded.fixed, + nbTexturesNeeded.scrollable, + nbTexturesNeeded.clipped, + nbTexturesNeeded.full, maxTextures); + } +#endif + + // For now, anything below kClippedTextures is equivalent + // to kSingleSurfaceRendering + // TODO: implement the other rendering modes + if (m_layersRenderingMode > kClippedTextures) + m_layersRenderingMode = kSingleSurfaceRendering; + + // update the base surface if needed + if (m_layersRenderingMode != layersRenderingMode + && invalBase) { + m_tiledPageA->discardTextures(); + m_tiledPageB->discardTextures(); + fullInval(); + return true; + } + return false; +} + +void GLWebViewState::fullInval() +{ + // TODO -- use base layer's size. + IntRect ir(0, 0, 1E6, 1E6); + inval(ir); +} + bool GLWebViewState::drawGL(IntRect& rect, SkRect& viewport, IntRect* invalRect, IntRect& webViewRect, int titleBarHeight, IntRect& clip, float scale, bool* buffersSwappedPtr) @@ -473,10 +558,45 @@ bool GLWebViewState::drawGL(IntRect& rect, SkRect& viewport, IntRect* invalRect, // set up zoom manager, shaders, etc. m_backgroundColor = baseLayer->getBackgroundColor(); double currentTime = setupDrawing(rect, viewport, webViewRect, titleBarHeight, clip, scale); + + if (compositedRoot) + compositedRoot->setState(this); + + bool animsRunning = false; + TexturesResult nbTexturesNeeded; + if (compositedRoot) { + TransformationMatrix ident; + animsRunning = compositedRoot->evaluateAnimations(); + bool hasFixedElements = compositedRoot->updateFixedLayersPositions(viewport); + if (m_layersRenderingMode == kSingleSurfaceRendering) { + // If we are in single surface rendering, we may have to fully + // invalidate if we have fixed elements or if we have CSS + // animations. + // TODO: compute the minimum invals + if (animsRunning || hasFixedElements) + fullInval(); + } + + // TODO: get the base document area for the original clip + FloatRect clip(0, 0, 1E6, 1E6); + compositedRoot->updateGLPositionsAndScale(ident, clip, 1, zoomManager()->layersScale()); + compositedRoot->prepare(this); + + ret |= animsRunning; + + compositedRoot->computeTexturesAmount(&nbTexturesNeeded); + } + ret |= setLayersRenderingMode(nbTexturesNeeded); + + // Clean up GL textures for video layer. + TilesManager::instance()->videoLayerManager()->deleteUnusedTextures(); + ret |= baseLayer->drawGL(currentTime, compositedRoot, rect, viewport, scale, buffersSwappedPtr); + FloatRect extrasclip(0, 0, rect.width(), rect.height()); TilesManager::instance()->shader()->clip(extrasclip); + m_glExtras.drawGL(webViewRect, viewport, titleBarHeight); glBindBuffer(GL_ARRAY_BUFFER, 0); @@ -541,6 +661,7 @@ bool GLWebViewState::drawGL(IntRect& rect, SkRect& viewport, IntRect* invalRect, TilesManager::instance()->getTilesTracker()->showTrackTextures(); ImagesManager::instance()->showImages(); #endif + return ret; } diff --git a/Source/WebCore/platform/graphics/android/GLWebViewState.h b/Source/WebCore/platform/graphics/android/GLWebViewState.h index 5f7ca71..a1adaf1 100644 --- a/Source/WebCore/platform/graphics/android/GLWebViewState.h +++ b/Source/WebCore/platform/graphics/android/GLWebViewState.h @@ -57,6 +57,8 @@ namespace WebCore { class BaseLayerAndroid; class LayerAndroid; +class ScrollableLayerAndroid; +class TexturesResult; ///////////////////////////////////////////////////////////////////////////////// // GL Architecture @@ -208,6 +210,9 @@ public: int titleBarHeight, IntRect& screenClip, float scale); + bool setLayersRenderingMode(TexturesResult&); + void fullInval(); + bool drawGL(IntRect& rect, SkRect& viewport, IntRect* invalRect, IntRect& webViewRect, int titleBarHeight, IntRect& clip, float scale, bool* buffersSwappedPtr); @@ -232,6 +237,18 @@ public: float scale() { return m_scale; } + enum LayersRenderingMode { + kAllTextures = 0, // all layers are drawn with textures fully covering them + kClippedTextures = 1, // all layers are drawn, but their textures will be clipped + kScrollableAndFixedLayers = 2, // only scrollable and fixed layers will be drawn + kFixedLayers = 3, // only fixed layers will be drawn + kSingleSurfaceRendering = 4 // no layers will be drawn on separate textures + // -- everything is drawn on the base surface. + }; + + LayersRenderingMode layersRenderingMode() { return m_layersRenderingMode; } + void scrolledLayer(ScrollableLayerAndroid*); + private: void inval(const IntRect& rect); // caller must hold m_baseLayerLock void invalRegion(const SkRegion& region); @@ -276,6 +293,8 @@ private: int m_expandedTileBoundsY; float m_scale; + + LayersRenderingMode m_layersRenderingMode; }; } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp b/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp index 05a0fdc..3e062f8 100644 --- a/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp +++ b/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp @@ -564,6 +564,7 @@ bool GraphicsLayerAndroid::repaint() phase.set(GraphicsLayerPaintBackground); if (!paintContext(m_contentLayer->recordContext(), layerBounds)) return false; + m_contentLayer->checkTextPresence(); // Construct the foreground layer and draw. RenderBox* box = layer->renderBox(); @@ -582,6 +583,7 @@ bool GraphicsLayerAndroid::repaint() layer->scrollToOffset(0, 0); // At this point, it doesn't matter if painting failed. (void) paintContext(m_foregroundLayer->recordContext(), contentsRect); + m_foregroundLayer->checkTextPresence(); layer->scrollToOffset(scroll.width(), scroll.height()); // Construct the clip layer for masking the contents. @@ -607,6 +609,7 @@ bool GraphicsLayerAndroid::repaint() // picture. if (!paintContext(m_contentLayer->recordContext(), layerBounds)) return false; + m_contentLayer->checkTextPresence(); // Check for a scrollable iframe and report the scrolling // limits based on the view size. if (m_contentLayer->contentIsScrollable()) { diff --git a/Source/WebCore/platform/graphics/android/Layer.h b/Source/WebCore/platform/graphics/android/Layer.h index c8bb81d..89e101c 100644 --- a/Source/WebCore/platform/graphics/android/Layer.h +++ b/Source/WebCore/platform/graphics/android/Layer.h @@ -122,6 +122,7 @@ public: // paint method + virtual bool drawCanvas(SkCanvas*) { return false; } void draw(SkCanvas*, SkScalar opacity); void draw(SkCanvas* canvas) { this->draw(canvas, SK_Scalar1); diff --git a/Source/WebCore/platform/graphics/android/LayerAndroid.cpp b/Source/WebCore/platform/graphics/android/LayerAndroid.cpp index e0898e6..12a11bf 100644 --- a/Source/WebCore/platform/graphics/android/LayerAndroid.cpp +++ b/Source/WebCore/platform/graphics/android/LayerAndroid.cpp @@ -55,6 +55,87 @@ private: int m_opacity; }; +class HasTextBounder : public SkBounder { + virtual bool onIRect(const SkIRect& rect) + { + return false; + } +}; + +class HasTextCanvas : public SkCanvas { +public: + HasTextCanvas(SkBounder* bounder, SkPicture* picture) + : m_picture(picture) + , m_hasText(false) + { + setBounder(bounder); + } + + void setHasText() + { + m_hasText = true; + m_picture->abortPlayback(); + } + + bool hasText() + { + return m_hasText; + } + + virtual bool clipPath(const SkPath&, SkRegion::Op) { + return true; + } + + virtual void commonDrawBitmap(const SkBitmap& bitmap, + const SkIRect* rect, + const SkMatrix&, + const SkPaint&) {} + + virtual void drawPaint(const SkPaint& paint) {} + virtual void drawPath(const SkPath&, const SkPaint& paint) {} + virtual void drawPoints(PointMode, size_t, + const SkPoint [], const SkPaint& paint) {} + + virtual void drawRect(const SkRect& , const SkPaint& paint) {} + virtual void drawSprite(const SkBitmap& , int , int , + const SkPaint* paint = NULL) {} + + virtual void drawText(const void*, size_t byteLength, SkScalar, + SkScalar, const SkPaint& paint) + { + setHasText(); + } + + virtual void drawPosText(const void* , size_t byteLength, + const SkPoint [], const SkPaint& paint) + { + setHasText(); + } + + virtual void drawPosTextH(const void*, size_t byteLength, + const SkScalar [], SkScalar, + const SkPaint& paint) + { + setHasText(); + } + + virtual void drawTextOnPath(const void*, size_t byteLength, + const SkPath&, const SkMatrix*, + const SkPaint& paint) + { + setHasText(); + } + + virtual void drawPicture(SkPicture& picture) { + SkCanvas::drawPicture(picture); + } + +private: + + SkPicture* m_picture; + bool m_hasText; +}; + /////////////////////////////////////////////////////////////////////////////// LayerAndroid::LayerAndroid(RenderLayer* owner) : Layer(), @@ -75,7 +156,9 @@ LayerAndroid::LayerAndroid(RenderLayer* owner) : Layer(), m_scale(1), m_lastComputeTextureSize(0), m_owningLayer(owner), - m_type(LayerAndroid::WebCoreLayer) + m_type(LayerAndroid::WebCoreLayer), + m_state(0), + m_hasText(true) { m_backgroundColor = 0; @@ -97,7 +180,9 @@ LayerAndroid::LayerAndroid(const LayerAndroid& layer) : Layer(layer), m_imageTexture(0), m_requestSent(false), m_owningLayer(layer.m_owningLayer), - m_type(LayerAndroid::UILayer) + m_type(LayerAndroid::UILayer), + m_state(0), + m_hasText(true) { m_isFixed = layer.m_isFixed; m_imageRef = layer.m_imageRef; @@ -141,12 +226,31 @@ LayerAndroid::LayerAndroid(const LayerAndroid& layer) : Layer(layer), m_animations.add(key, (it->second)->copy()); } + m_hasText = layer.m_hasText; + #ifdef DEBUG_COUNT ClassTracker::instance()->increment("LayerAndroid - recopy (UI?)"); ClassTracker::instance()->add(this); #endif } +void LayerAndroid::checkTextPresence() +{ + if (m_recordingPicture) { + // Let's check if we have text or not. If we don't, we can limit + // ourselves to scale 1! + HasTextBounder hasTextBounder; + HasTextCanvas checker(&hasTextBounder, m_recordingPicture); + SkBitmap bitmap; + bitmap.setConfig(SkBitmap::kARGB_8888_Config, + m_recordingPicture->width(), + m_recordingPicture->height()); + checker.setBitmapDevice(bitmap); + checker.drawPicture(*m_recordingPicture); + m_hasText = checker.hasText(); + } +} + LayerAndroid::LayerAndroid(SkPicture* picture) : Layer(), m_haveClip(false), m_isFixed(false), @@ -160,7 +264,9 @@ LayerAndroid::LayerAndroid(SkPicture* picture) : Layer(), m_scale(1), m_lastComputeTextureSize(0), m_owningLayer(0), - m_type(LayerAndroid::NavCacheLayer) + m_type(LayerAndroid::NavCacheLayer), + m_state(0), + m_hasText(true) { m_backgroundColor = 0; m_dirty = false; @@ -234,7 +340,8 @@ void LayerAndroid::addDirtyArea(GLWebViewState* glWebViewState) IntSize layerSize(getSize().width(), getSize().height()); FloatRect area = TilesManager::instance()->shader()->rectInInvScreenCoord(m_drawTransform, layerSize); - FloatRect clip = TilesManager::instance()->shader()->convertScreenCoordToInvScreenCoord(m_clippingRect); + FloatRect clippingRect = TilesManager::instance()->shader()->rectInScreenCoord(m_clippingRect); + FloatRect clip = TilesManager::instance()->shader()->convertScreenCoordToInvScreenCoord(clippingRect); area.intersect(clip); IntRect dirtyArea(area.x(), area.y(), area.width(), area.height()); @@ -489,8 +596,9 @@ const LayerAndroid* LayerAndroid::find(int* xPtr, int* yPtr, SkPicture* root) co /////////////////////////////////////////////////////////////////////////////// -void LayerAndroid::updateFixedLayersPositions(SkRect viewport, LayerAndroid* parentIframeLayer) +bool LayerAndroid::updateFixedLayersPositions(SkRect viewport, LayerAndroid* parentIframeLayer) { + bool hasFixedElements = false; XLOG("updating fixed positions, using viewport %fx%f - %fx%f", viewport.fLeft, viewport.fTop, viewport.width(), viewport.height()); @@ -509,6 +617,7 @@ void LayerAndroid::updateFixedLayersPositions(SkRect viewport, LayerAndroid* par } if (m_isFixed) { + hasFixedElements = true; // So if this is a fixed layer inside a iframe, use the iframe offset // and the iframe's size as the viewport and pass to the children if (parentIframeLayer) { @@ -546,7 +655,9 @@ void LayerAndroid::updateFixedLayersPositions(SkRect viewport, LayerAndroid* par int count = this->countChildren(); for (int i = 0; i < count; i++) - this->getChild(i)->updateFixedLayersPositions(viewport, parentIframeLayer); + hasFixedElements |= this->getChild(i)->updateFixedLayersPositions(viewport, parentIframeLayer); + + return hasFixedElements; } void LayerAndroid::updatePositions() @@ -614,9 +725,9 @@ void LayerAndroid::updateGLPositionsAndScale(const TransformationMatrix& parentM setDrawOpacity(opacity); if (m_haveClip) { - // The clipping rect calculation and intersetion will be done in Screen Coord now. - FloatRect clip = - TilesManager::instance()->shader()->rectInScreenCoord(m_drawTransform, layerSize); + // The clipping rect calculation and intersetion will be done in documents coordinates. + FloatRect rect(0, 0, layerSize.width(), layerSize.height()); + FloatRect clip = m_drawTransform.mapRect(rect); clip.intersect(clipping); setDrawClip(clip); } else { @@ -707,6 +818,15 @@ int LayerAndroid::nbTexturedLayers() return nb; } +void LayerAndroid::computeTexturesAmount(TexturesResult* result) +{ + int count = this->countChildren(); + for (int i = 0; i < count; i++) + this->getChild(i)->computeTexturesAmount(result); + if (m_texture && m_visible) + m_texture->computeTexturesAmount(result); +} + void LayerAndroid::showLayer(int indent) { char spaces[256]; @@ -714,15 +834,26 @@ void LayerAndroid::showLayer(int indent) for (int i = 0; i < indent; i++) spaces[i] = ' '; - if (!indent) + if (!indent) { XLOGC("\n\n--- LAYERS TREE ---"); + IntRect documentViewport(TilesManager::instance()->shader()->documentViewport()); + XLOGC("documentViewport(%d, %d, %d, %d)", + documentViewport.x(), documentViewport.y(), + documentViewport.width(), documentViewport.height()); + } IntRect r(0, 0, getWidth(), getHeight()); IntRect tr = m_drawTransform.mapRect(r); - XLOGC("%s [%d:0x%x] - %s - (%d, %d, %d, %d) %s prepareContext(%d), pic w: %d h: %d", + IntRect visible = visibleArea(); + IntRect clip(m_clippingRect.x(), m_clippingRect.y(), + m_clippingRect.width(), m_clippingRect.height()); + XLOGC("%s [%d:0x%x] - %s - area (%d, %d, %d, %d) - visible (%d, %d, %d, %d) " + "clip (%d, %d, %d, %d) %s prepareContext(%d), pic w: %d h: %d", spaces, uniqueId(), m_owningLayer, needsTexture() ? "needs a texture" : "no texture", tr.x(), tr.y(), tr.width(), tr.height(), + visible.x(), visible.y(), visible.width(), visible.height(), + clip.x(), clip.y(), clip.width(), clip.height(), contentIsScrollable() ? "SCROLLABLE" : "", prepareContext(), m_recordingPicture ? m_recordingPicture->width() : -1, @@ -855,6 +986,15 @@ void LayerAndroid::clearDirtyRegion() m_dirtyRegion.setEmpty(); } +void LayerAndroid::setState(GLWebViewState* state) +{ + int count = this->countChildren(); + for (int i = 0; i < count; i++) + this->getChild(i)->setState(state); + + m_state = state; +} + void LayerAndroid::prepare(GLWebViewState* glWebViewState) { m_state = glWebViewState; @@ -880,9 +1020,80 @@ void LayerAndroid::prepare(GLWebViewState* glWebViewState) m_imageTexture->prepareGL(); } +IntRect LayerAndroid::unclippedArea() +{ + IntRect area; + area.setX(0); + area.setY(0); + area.setWidth(getSize().width()); + area.setHeight(getSize().height()); + return area; +} + +IntRect LayerAndroid::visibleArea() +{ + IntRect area = unclippedArea(); + // First, we get the transformed area of the layer, + // in document coordinates + IntRect rect = m_drawTransform.mapRect(area); + int dx = rect.x(); + int dy = rect.y(); + + // Then we apply the clipping + IntRect clip(m_clippingRect); + rect.intersect(clip); + + // Now clip with the viewport in documents coordinate + IntRect documentViewport(TilesManager::instance()->shader()->documentViewport()); + rect.intersect(documentViewport); + + // Finally, let's return the visible area, in layers coordinate + rect.move(-dx, -dy); + return rect; +} + +bool LayerAndroid::drawCanvas(SkCanvas* canvas) +{ + if (!m_visible) + return false; + + bool askScreenUpdate = false; + + { + SkAutoCanvasRestore acr(canvas, true); + SkRect r; + r.set(m_clippingRect.x(), m_clippingRect.y(), + m_clippingRect.x() + m_clippingRect.width(), + m_clippingRect.y() + m_clippingRect.height()); + canvas->clipRect(r); + SkMatrix matrix; + GLUtils::toSkMatrix(matrix, m_drawTransform); + SkMatrix canvasMatrix = canvas->getTotalMatrix(); + matrix.postConcat(canvasMatrix); + canvas->setMatrix(matrix); + SkRect layerRect; + layerRect.fLeft = 0; + layerRect.fTop = 0; + layerRect.fRight = getWidth(); + layerRect.fBottom = getHeight(); + onDraw(canvas, m_drawOpacity); + } + + // When the layer is dirty, the UI thread should be notified to redraw. + askScreenUpdate |= drawChildrenCanvas(canvas); + m_atomicSync.lock(); + askScreenUpdate |= m_dirty; + if (askScreenUpdate || m_hasRunningAnimations || m_drawTransform.hasPerspective()) + addDirtyArea(m_state); + + m_atomicSync.unlock(); + return askScreenUpdate; +} + bool LayerAndroid::drawGL(GLWebViewState* glWebViewState, SkMatrix& matrix) { - TilesManager::instance()->shader()->clip(m_clippingRect); + FloatRect clippingRect = TilesManager::instance()->shader()->rectInScreenCoord(m_clippingRect); + TilesManager::instance()->shader()->clip(clippingRect); if (!m_visible) return false; @@ -905,6 +1116,26 @@ bool LayerAndroid::drawGL(GLWebViewState* glWebViewState, SkMatrix& matrix) return askScreenUpdate; } +bool LayerAndroid::drawChildrenCanvas(SkCanvas* canvas) +{ + bool askScreenUpdate = false; + int count = this->countChildren(); + if (count > 0) { + Vector <LayerAndroid*> sublayers; + for (int i = 0; i < count; i++) + sublayers.append(this->getChild(i)); + + // now we sort for the transparency + std::stable_sort(sublayers.begin(), sublayers.end(), compareLayerZ); + for (int i = 0; i < count; i++) { + LayerAndroid* layer = sublayers[i]; + askScreenUpdate |= layer->drawCanvas(canvas); + } + } + + return askScreenUpdate; +} + bool LayerAndroid::drawChildrenGL(GLWebViewState* glWebViewState, SkMatrix& matrix) { bool askScreenUpdate = false; diff --git a/Source/WebCore/platform/graphics/android/LayerAndroid.h b/Source/WebCore/platform/graphics/android/LayerAndroid.h index 15a581e..b536b22 100644 --- a/Source/WebCore/platform/graphics/android/LayerAndroid.h +++ b/Source/WebCore/platform/graphics/android/LayerAndroid.h @@ -99,9 +99,25 @@ class RenderLayer; class TiledPage; class PaintedSurface; +class TexturesResult { +public: + TexturesResult() + : fixed(0) + , scrollable(0) + , clipped(0) + , full(0) + {} + + int fixed; + int scrollable; + int clipped; + int full; +}; + class LayerAndroid : public Layer { public: enum LayerType { UndefinedLayer, WebCoreLayer, UILayer, NavCacheLayer }; + LayerAndroid(RenderLayer* owner); LayerAndroid(const LayerAndroid& layer); LayerAndroid(SkPicture*); @@ -121,6 +137,9 @@ public: IntRect clippedRect() const; bool outsideViewport(); + IntRect unclippedArea(); + IntRect visibleArea(); + virtual bool needsTexture(); void removeTexture(PaintedSurface*); @@ -129,11 +148,17 @@ public: int nbTexturedLayers(); void showLayer(int indent); + void computeTexturesAmount(TexturesResult*); + float getScale() { return m_scale; } + void setState(GLWebViewState*); + // draw layer and its children via Z, pre-order traversal virtual bool drawGL(GLWebViewState*, SkMatrix&); bool drawChildrenGL(GLWebViewState*, SkMatrix&); + virtual bool drawCanvas(SkCanvas*); + bool drawChildrenCanvas(SkCanvas*); // prepare layer and its children via reverse-Z, post-order traversal void prepare(GLWebViewState*); @@ -212,7 +237,7 @@ public: This call is recursive, so it should be called on the root of the hierarchy. */ - void updateFixedLayersPositions(SkRect viewPort, LayerAndroid* parentIframeLayer = 0); + bool updateFixedLayersPositions(SkRect viewPort, LayerAndroid* parentIframeLayer = 0); /** Call this to update the position attribute, so that later calls like bounds() will report the corrected position. @@ -284,6 +309,9 @@ public: ImageTexture* imageTexture() { return m_imageTexture; } int type() { return m_type; } + bool hasText() { return m_hasText; } + void checkTextPresence(); + protected: virtual void onDraw(SkCanvas*, SkScalar opacity); @@ -387,8 +415,11 @@ private: RenderLayer* m_owningLayer; - GLWebViewState* m_state; int m_type; + GLWebViewState* m_state; + + bool m_hasText; + typedef Layer INHERITED; }; diff --git a/Source/WebCore/platform/graphics/android/PaintedSurface.cpp b/Source/WebCore/platform/graphics/android/PaintedSurface.cpp index c0597a9..939d106 100644 --- a/Source/WebCore/platform/graphics/android/PaintedSurface.cpp +++ b/Source/WebCore/platform/graphics/android/PaintedSurface.cpp @@ -142,24 +142,17 @@ void PaintedSurface::prepare(GLWebViewState* state) m_layer->uniqueId(), m_layer, m_layer->getScale()); - int w = m_layer->getSize().width(); - int h = m_layer->getSize().height(); - - if (w != m_area.width()) - m_area.setWidth(w); - - if (h != m_area.height()) - m_area.setHeight(h); - - computeVisibleArea(); + IntRect visibleArea = computeVisibleArea(m_layer); m_scale = state->scale(); - XLOG("%x layer %d %x prepared at size (%d, %d) @ scale %.2f", this, m_layer->uniqueId(), - m_layer, w, h, m_scale); + // If we do not have text, we may as well limit ourselves to + // a scale factor of one... this saves up textures. + if (m_scale > 1 && !m_layer->hasText()) + m_scale = 1; m_tiledTexture->prepare(state, m_scale, m_pictureUsed != m_layer->pictureUsed(), - startFastSwap, m_visibleArea); + startFastSwap, visibleArea); } bool PaintedSurface::draw() @@ -192,20 +185,53 @@ const TransformationMatrix* PaintedSurface::transform() { return m_layer->drawTransform(); } -void PaintedSurface::computeVisibleArea() { +void PaintedSurface::computeTexturesAmount(TexturesResult* result) +{ + if (!m_tiledTexture) + return; + if (!m_layer) return; - IntRect layerRect = (*m_layer->drawTransform()).mapRect(m_area); - IntRect clippedRect = TilesManager::instance()->shader()->clippedRectWithViewport(layerRect); - m_visibleArea = (*m_layer->drawTransform()).inverse().mapRect(clippedRect); - if (!m_visibleArea.isEmpty()) { - float tileWidth = TilesManager::instance()->layerTileWidth(); - float tileHeight = TilesManager::instance()->layerTileHeight(); - int w = ceilf(m_area.width() * m_scale / tileWidth); - int h = ceilf(m_area.height() * m_scale / tileHeight); - if (w * h < MAX_UNCLIPPED_AREA) - m_visibleArea = m_area; - } + + IntRect unclippedArea = m_layer->unclippedArea(); + IntRect clippedVisibleArea = m_layer->visibleArea(); + // get two numbers here: + // - textures needed for a clipped area + // - textures needed for an un-clipped area + int nbTexturesUnclipped = m_tiledTexture->nbTextures(unclippedArea, m_scale); + int nbTexturesClipped = m_tiledTexture->nbTextures(clippedVisibleArea, m_scale); + + // Set kFixedLayers level + if (m_layer->isFixed()) + result->fixed += nbTexturesClipped; + + // Set kScrollableAndFixedLayers level + if (m_layer->contentIsScrollable() + || m_layer->isFixed()) + result->scrollable += nbTexturesClipped; + + // Set kClippedTextures level + result->clipped += nbTexturesClipped; + + // Set kAllTextures level + if (m_layer->contentIsScrollable()) + result->full += nbTexturesClipped; + else + result->full += nbTexturesUnclipped; +} + +IntRect PaintedSurface::computeVisibleArea(LayerAndroid* layer) { + IntRect area; + if (!layer) + return area; + + if (!layer->contentIsScrollable() + && layer->state()->layersRenderingMode() == GLWebViewState::kAllTextures) + area = layer->unclippedArea(); + else + area = layer->visibleArea(); + + return area; } bool PaintedSurface::owns(BaseTileTexture* texture) diff --git a/Source/WebCore/platform/graphics/android/PaintedSurface.h b/Source/WebCore/platform/graphics/android/PaintedSurface.h index 2e01b80..83b2c9b 100644 --- a/Source/WebCore/platform/graphics/android/PaintedSurface.h +++ b/Source/WebCore/platform/graphics/android/PaintedSurface.h @@ -63,14 +63,13 @@ public: bool owns(BaseTileTexture* texture); - void computeVisibleArea(); + void computeTexturesAmount(TexturesResult*); + IntRect computeVisibleArea(LayerAndroid*); // TilePainter methods for TiledTexture virtual const TransformationMatrix* transform(); // used by TiledTexture - const IntRect& area() { return m_area; } - const IntRect& visibleArea() { return m_visibleArea; } float scale() { return m_scale; } float opacity(); unsigned int pictureUsed() { return m_pictureUsed; } @@ -81,8 +80,6 @@ private: LayerAndroid* m_layer; DualTiledTexture* m_tiledTexture; - IntRect m_area; - IntRect m_visibleArea; float m_scale; unsigned int m_pictureUsed; diff --git a/Source/WebCore/platform/graphics/android/PerformanceMonitor.cpp b/Source/WebCore/platform/graphics/android/PerformanceMonitor.cpp index 20d1299..241cbef 100644 --- a/Source/WebCore/platform/graphics/android/PerformanceMonitor.cpp +++ b/Source/WebCore/platform/graphics/android/PerformanceMonitor.cpp @@ -27,6 +27,11 @@ #include <wtf/text/CString.h> +#include <wtf/CurrentTime.h> +#include <cutils/log.h> +#include <wtf/text/CString.h> +#define XLOGC(...) android_printLog(ANDROID_LOG_DEBUG, "PerformanceMonitor", __VA_ARGS__) + namespace WebCore { PerformanceMonitor::PerformanceMonitor() @@ -78,4 +83,22 @@ float PerformanceMonitor::getAverageDuration(const String &tag) return m_tags.get(tag)->average_ms; } +void PerformanceMonitor::display(int limit) +{ + bool shown = false; + HashMap<String, PerfItem*, StringHash>::iterator end = m_tags.end(); + for (HashMap<String, PerfItem*, StringHash>::iterator it = m_tags.begin(); it != end; ++it) { + PerfItem* item = it->second; + if (item->average_ms > limit) { + if (!shown) { + XLOGC("=== DISPLAY MONITOR ===="); + shown = true; + } + XLOGC("item %s took longer than %d ms: %.2f", it->first.latin1().data(), limit, item->average_ms); + } + } + if (shown) + XLOGC("=== END DISPLAY MONITOR ===="); +} + } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/android/PerformanceMonitor.h b/Source/WebCore/platform/graphics/android/PerformanceMonitor.h index f4aaa92..4ebbf6a 100644 --- a/Source/WebCore/platform/graphics/android/PerformanceMonitor.h +++ b/Source/WebCore/platform/graphics/android/PerformanceMonitor.h @@ -48,6 +48,7 @@ public: void start(const String &tag); void stop(const String &tag); float getAverageDuration(const String &tag); + void display(int limit); private: HashMap<String, PerfItem*, StringHash> m_tags; diff --git a/Source/WebCore/platform/graphics/android/RasterRenderer.cpp b/Source/WebCore/platform/graphics/android/RasterRenderer.cpp index f66c7c1..8bf6fcc 100644 --- a/Source/WebCore/platform/graphics/android/RasterRenderer.cpp +++ b/Source/WebCore/platform/graphics/android/RasterRenderer.cpp @@ -70,6 +70,10 @@ RasterRenderer::RasterRenderer() : BaseRenderer(BaseRenderer::Raster) #ifdef DEBUG_COUNT ClassTracker::instance()->increment("RasterRenderer"); #endif + m_bitmap.setConfig(SkBitmap::kARGB_8888_Config, + TilesManager::instance()->tileWidth(), + TilesManager::instance()->tileHeight()); + m_bitmap.allocPixels(); } RasterRenderer::~RasterRenderer() @@ -84,20 +88,15 @@ void RasterRenderer::setupCanvas(const TileRenderInfo& renderInfo, SkCanvas* can if (renderInfo.measurePerf) m_perfMon.start(TAG_CREATE_BITMAP); - - SkBitmap bitmap; - bitmap.setConfig(SkBitmap::kARGB_8888_Config, - renderInfo.invalRect->width(), renderInfo.invalRect->height()); - bitmap.allocPixels(); if (renderInfo.baseTile->isLayerTile()) { - bitmap.setIsOpaque(false); - bitmap.eraseARGB(0, 0, 0, 0); + m_bitmap.setIsOpaque(false); + m_bitmap.eraseARGB(0, 0, 0, 0); } else { - bitmap.setIsOpaque(true); - bitmap.eraseARGB(255, 255, 255, 255); + m_bitmap.setIsOpaque(true); + m_bitmap.eraseARGB(255, 255, 255, 255); } - SkDevice* device = new SkDevice(NULL, bitmap, false); + SkDevice* device = new SkDevice(NULL, m_bitmap, false); if (renderInfo.measurePerf) { m_perfMon.stop(TAG_CREATE_BITMAP); diff --git a/Source/WebCore/platform/graphics/android/RasterRenderer.h b/Source/WebCore/platform/graphics/android/RasterRenderer.h index 4308452..69dfaf8 100644 --- a/Source/WebCore/platform/graphics/android/RasterRenderer.h +++ b/Source/WebCore/platform/graphics/android/RasterRenderer.h @@ -29,6 +29,7 @@ #if USE(ACCELERATED_COMPOSITING) #include "BaseRenderer.h" +#include "SkBitmap.h" #include "SkRect.h" class SkCanvas; @@ -50,6 +51,9 @@ protected: virtual void renderingComplete(const TileRenderInfo& renderInfo, SkCanvas* canvas); virtual const String* getPerformanceTags(int& tagCount); +private: + SkBitmap m_bitmap; + }; } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/android/ScrollableLayerAndroid.cpp b/Source/WebCore/platform/graphics/android/ScrollableLayerAndroid.cpp index bca2fd4..2643d2c 100644 --- a/Source/WebCore/platform/graphics/android/ScrollableLayerAndroid.cpp +++ b/Source/WebCore/platform/graphics/android/ScrollableLayerAndroid.cpp @@ -1,6 +1,8 @@ #include "config.h" #include "ScrollableLayerAndroid.h" +#include "GLWebViewState.h" + #if USE(ACCELERATED_COMPOSITING) namespace WebCore { @@ -19,6 +21,10 @@ bool ScrollableLayerAndroid::scrollTo(int x, int y) return false; setPosition(m_scrollLimits.fLeft - newX, m_scrollLimits.fTop - newY); + + if (state()) + state()->scrolledLayer(this); + return true; } diff --git a/Source/WebCore/platform/graphics/android/ShaderProgram.cpp b/Source/WebCore/platform/graphics/android/ShaderProgram.cpp index 0aad081..30b5c86 100644 --- a/Source/WebCore/platform/graphics/android/ShaderProgram.cpp +++ b/Source/WebCore/platform/graphics/android/ShaderProgram.cpp @@ -408,6 +408,8 @@ void ShaderProgram::setViewRect(const IntRect& viewRect) translate.scale3d(1, -1, 1); m_documentToInvScreenMatrix = scale * translate * m_projectionMatrix; + + m_documentViewport = m_documentToScreenMatrix.inverse().mapRect(viewRect); } // This function transform a clip rect extracted from the current layer @@ -437,6 +439,11 @@ FloatRect ShaderProgram::rectInScreenCoord(const FloatRect& rect) return m_documentToScreenMatrix.mapRect(rect); } +FloatRect ShaderProgram::convertScreenCoordToDocumentCoord(const FloatRect& rect) +{ + return m_documentToScreenMatrix.inverse().mapRect(rect); +} + FloatRect ShaderProgram::convertInvScreenCoordToScreenCoord(const FloatRect& rect) { FloatRect documentRect = m_documentToInvScreenMatrix.inverse().mapRect(rect); diff --git a/Source/WebCore/platform/graphics/android/ShaderProgram.h b/Source/WebCore/platform/graphics/android/ShaderProgram.h index dbacd57..b309872 100644 --- a/Source/WebCore/platform/graphics/android/ShaderProgram.h +++ b/Source/WebCore/platform/graphics/android/ShaderProgram.h @@ -67,6 +67,7 @@ public: 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); @@ -75,6 +76,7 @@ public: void setScreenClip(const IntRect& clip); void clip(const FloatRect& rect); IntRect clippedRectWithViewport(const IntRect& rect, int margin = 0); + FloatRect documentViewport() { return m_documentViewport; } void resetBlending(); float contrast() { return m_contrast; } @@ -125,6 +127,8 @@ private: int m_titleBarHeight; IntRect m_webViewRect; + FloatRect m_documentViewport; + // uniforms GLint m_hProjectionMatrix; GLint m_hAlpha; diff --git a/Source/WebCore/platform/graphics/android/TiledPage.cpp b/Source/WebCore/platform/graphics/android/TiledPage.cpp index c097c58..3c262d4 100644 --- a/Source/WebCore/platform/graphics/android/TiledPage.cpp +++ b/Source/WebCore/platform/graphics/android/TiledPage.cpp @@ -374,8 +374,8 @@ void TiledPage::draw(float transparency, const SkIRect& tileBounds) bool TiledPage::paint(BaseTile* tile, SkCanvas* canvas, unsigned int* pictureUsed) { - // TODO: consider other flags so the pre-rendered tiles aren't so ugly - static SkPaintFlagsDrawFilter prefetchFilter(SkPaint::kAllFlags, 0); + static SkPaintFlagsDrawFilter prefetchFilter(SkPaint::kAllFlags, + SkPaint::kAntiAlias_Flag); if (!m_glWebViewState) return false; diff --git a/Source/WebCore/platform/graphics/android/TiledTexture.cpp b/Source/WebCore/platform/graphics/android/TiledTexture.cpp index b252303..e1e5ec9 100644 --- a/Source/WebCore/platform/graphics/android/TiledTexture.cpp +++ b/Source/WebCore/platform/graphics/android/TiledTexture.cpp @@ -59,12 +59,13 @@ bool TiledTexture::ready() { bool tilesVisible = false; for (unsigned int i = 0; i < m_tiles.size(); i++) { BaseTile* tile = m_tiles[i]; - if (tile->isTileVisible(m_area) && !tile->isTileReady()) { - tilesAllReady = false; - break; - } - if (tile->isTileVisible(m_area)) + if (tile->isTileVisible(m_area)) { tilesVisible = true; + if (!tile->isTileReady()) { + tilesAllReady = false; + break; + } + } } // For now, if no textures are available, consider ourselves as ready // in order to unblock the zooming process. @@ -74,38 +75,47 @@ bool TiledTexture::ready() { || !tilesVisible || tilesAllReady; } -void TiledTexture::prepare(GLWebViewState* state, float scale, bool repaint, - bool startFastSwap, IntRect& visibleArea) +IntRect TiledTexture::computeTilesArea(IntRect& visibleArea, float scale) { - if (!m_surface) - return; - - if (!m_surface->layer()) - return; - - // first, how many tiles do we need + IntRect computedArea; IntRect area(visibleArea.x() * scale, visibleArea.y() * scale, ceilf(visibleArea.width() * scale), ceilf(visibleArea.height() * scale)); if (area.width() == 0 && area.height() == 0) { - m_area.setWidth(0); - m_area.setHeight(0); - return; + computedArea.setWidth(0); + computedArea.setHeight(0); + return computedArea; } int tileWidth = TilesManager::instance()->layerTileWidth(); int tileHeight = TilesManager::instance()->layerTileHeight(); - m_area.setX(area.x() / tileWidth); - m_area.setY(area.y() / tileHeight); + computedArea.setX(area.x() / tileWidth); + computedArea.setY(area.y() / tileHeight); float right = (area.x() + area.width()) / (float) tileWidth; float bottom = (area.y() + area.height()) / (float) tileHeight; - m_area.setWidth(ceilf(right) - m_area.x()); - m_area.setHeight(ceilf(bottom) - m_area.y()); + computedArea.setWidth(ceilf(right) - computedArea.x()); + computedArea.setHeight(ceilf(bottom) - computedArea.y()); + return computedArea; +} - XLOG("for TiledTexture %p, we prepare with scale %.2f, have a visible area of %d, %d - %d x %d, corresponding to %d, %d x - %d x %d tiles", +void TiledTexture::prepare(GLWebViewState* state, float scale, bool repaint, + bool startFastSwap, IntRect& area) +{ + if (!m_surface) + return; + + if (!m_surface->layer()) + return; + + m_area = computeTilesArea(area, scale); + if (m_area.isEmpty()) + return; + + XLOG("for TiledTexture %p, we prepare with scale %.2f, have a visible area of " + " %d, %d - %d x %d, corresponding to %d, %d x - %d x %d tiles", this, scale, visibleArea.x(), visibleArea.y(), visibleArea.width(), visibleArea.height(), @@ -210,6 +220,12 @@ BaseTile* TiledTexture::getTile(int x, int y) return 0; } +int TiledTexture::nbTextures(IntRect& area, float scale) +{ + IntRect computedTilesArea = computeTilesArea(area, scale); + return computedTilesArea.width() * computedTilesArea.height(); +} + bool TiledTexture::draw() { #ifdef DEBUG diff --git a/Source/WebCore/platform/graphics/android/TiledTexture.h b/Source/WebCore/platform/graphics/android/TiledTexture.h index c6e9e09..5a47cd9 100644 --- a/Source/WebCore/platform/graphics/android/TiledTexture.h +++ b/Source/WebCore/platform/graphics/android/TiledTexture.h @@ -65,6 +65,8 @@ public: removeTiles(); }; + IntRect computeTilesArea(IntRect& visibleArea, float scale); + void prepare(GLWebViewState* state, float scale, bool repaint, bool startFastSwap, IntRect& visibleArea); bool draw(); @@ -87,6 +89,8 @@ public: PaintedSurface* surface() { return m_surface; } + int nbTextures(IntRect& area, float scale); + private: bool tileIsVisible(BaseTile* tile); @@ -117,6 +121,15 @@ public: bool draw(); void update(const SkRegion& dirtyArea, SkPicture* picture); bool owns(BaseTileTexture* texture); + + int nbTextures(IntRect& area, float scale) + { + // TODO: consider the zooming case for the backTexture + if (!m_frontTexture) + return 0; + return m_frontTexture->nbTextures(area, scale); + } + private: // Delay before we schedule a new tile at the new scale factor static const double s_zoomUpdateDelay = 0.2; // 200 ms diff --git a/Source/WebKit/android/RenderSkinCombo.cpp b/Source/WebKit/android/RenderSkinCombo.cpp index 970e093..1711cfa 100644 --- a/Source/WebKit/android/RenderSkinCombo.cpp +++ b/Source/WebKit/android/RenderSkinCombo.cpp @@ -58,14 +58,14 @@ enum BorderStyle { // width on all sides, except on the right when it's significantly // wider to allow for the arrow. const int RenderSkinCombo::arrowMargin[ResolutionCount] = { - 22, // Medium resolution - 34, // High resolution - 46 // Extra high resolution + 16, // Medium resolution + 25, // High resolution + 34 // Extra high resolution }; const int RenderSkinCombo::padMargin[ResolutionCount] = { - 2, // Medium resolution - 5, // High resolution - 6 // Extra high resolution + 1, // Medium resolution + 1, // High resolution + 1 // Extra high resolution }; namespace { @@ -76,15 +76,15 @@ namespace { // right hand border width happens to be the same as arrowMargin // defined above. const int stretchMargin[RenderSkinAndroid::ResolutionCount] = { // border width for the bottom and left of the 9-patch - 3, // Medium resolution - 5, // High resolution - 6 // Extra high resolution + 2, // Medium resolution + 2, // High resolution + 3 // Extra high resolution }; const int stretchTop[RenderSkinAndroid::ResolutionCount] = { // border width for the top of the 9-patch - 15, // Medium resolution + 16, // Medium resolution 23, // High resolution - 34 // Extra high resolution + 32 // Extra high resolution }; // Finally, if the border is defined by the CSS, we only draw the @@ -95,9 +95,16 @@ const int stretchTop[RenderSkinAndroid::ResolutionCount] = { // border width for // image is the same as stretchMargin above, but we need to know the width // of the arrow. const int arrowWidth[RenderSkinAndroid::ResolutionCount] = { - 22, // Medium resolution - 31, // High resolution - 42 // Extra high resolution + 18, // Medium resolution + 27, // High resolution + 36 // Extra high resolution +}; + +// scale factors for various resolutions +const float scaleFactor[RenderSkinAndroid::ResolutionCount] = { + 1.0f, // medium res + 1.5f, // high res + 2.0f // extra high res }; // Store the calculated 9 patch margins for each border style. @@ -109,6 +116,11 @@ bool isDecoded = false; // True if all assets were decoded } // namespace +int RenderSkinCombo::minHeight() { + return SkScalarRound(stretchTop[RenderSkinAndroid::DrawableResolution()] + / scaleFactor[RenderSkinAndroid::DrawableResolution()]); +} + void RenderSkinCombo::Decode() { if (isDecodingAttempted) @@ -135,9 +147,9 @@ void RenderSkinCombo::Decode() // Calculate 9 patch margins. SkIRect fullAssetMargin; fullAssetMargin.fLeft = stretchMargin[res]; - fullAssetMargin.fTop = stretchTop[res]; + fullAssetMargin.fTop = stretchMargin[res]; fullAssetMargin.fRight = arrowMargin[res] + stretchMargin[res]; - fullAssetMargin.fBottom = stretchMargin[res]; + fullAssetMargin.fBottom = stretchTop[res]; SkIRect noBorderMargin; noBorderMargin.fLeft = 0; @@ -157,8 +169,9 @@ bool RenderSkinCombo::Draw(SkCanvas* canvas, Node* element, int x, int y, int wi if (!isDecoded) return true; + int resolution = RenderSkinAndroid::DrawableResolution(); State state = (element->isElementNode() && static_cast<Element*>(element)->isEnabledFormControl()) ? kNormal : kDisabled; - height = std::max(height, (stretchMargin[RenderSkinAndroid::DrawableResolution()]<<1) + 1); + height = std::max(height, (stretchMargin[resolution] * 2)); SkRect bounds; BorderStyle drawBorder = FullAsset; @@ -185,7 +198,15 @@ bool RenderSkinCombo::Draw(SkCanvas* canvas, Node* element, int x, int y, int wi bounds.fBottom -= SkIntToScalar(style->borderBottomWidth()); drawBorder = NoBorder; } + float scale = scaleFactor[resolution]; + bounds.fLeft = bounds.fLeft * scale; + bounds.fRight = bounds.fRight * scale; + bounds.fTop = bounds.fTop * scale; + bounds.fBottom = bounds.fBottom * scale; + int count = canvas->save(); + canvas->scale(1.0f / scale, 1.0f / scale); SkNinePatch::DrawNine(canvas, bounds, bitmaps[state][drawBorder], margin[drawBorder]); + canvas->restoreToCount(count); return false; } diff --git a/Source/WebKit/android/RenderSkinCombo.h b/Source/WebKit/android/RenderSkinCombo.h index 4814199..a11faac 100644 --- a/Source/WebKit/android/RenderSkinCombo.h +++ b/Source/WebKit/android/RenderSkinCombo.h @@ -48,6 +48,7 @@ public: // The image is wider than the RenderObject, so this accounts for that. static int extraWidth() { return arrowMargin[RenderSkinAndroid::DrawableResolution()]; } + static int minHeight(); static int padding() { return padMargin[RenderSkinAndroid::DrawableResolution()]; } diff --git a/Source/WebKit/android/jni/WebCoreFrameBridge.cpp b/Source/WebKit/android/jni/WebCoreFrameBridge.cpp index bb28d28..d53ddb6 100644 --- a/Source/WebKit/android/jni/WebCoreFrameBridge.cpp +++ b/Source/WebKit/android/jni/WebCoreFrameBridge.cpp @@ -2117,6 +2117,25 @@ static void OrientationChanged(JNIEnv *env, jobject obj, int orientation) pFrame->sendOrientationChangeEvent(orientation); } +static jboolean GetShouldStartScrolledRight(JNIEnv *env, jobject obj, + jint browserFrame) +{ + jboolean startScrolledRight = false; // default is start scrolled left + WebCore::Frame* frame = reinterpret_cast<WebCore::Frame*>(browserFrame); + WebCore::Document* document = frame->document(); + if (document) { + RenderStyle* style = document->renderer()->style(); + WritingMode writingMode = style->writingMode(); + LOG_ASSERT(writingMode != WebCore::BottomToTopWritingMode, + "BottomToTopWritingMode isn't supported"); + if (writingMode == WebCore::RightToLeftWritingMode) + startScrolledRight = true; // vertical-rl pages start scrolled right + else if (writingMode == WebCore::TopToBottomWritingMode) + startScrolledRight = !style->isLeftToRightDirection(); // RTL starts right + } + return startScrolledRight; +} + #if USE(CHROME_NETWORK_STACK) static void AuthenticationProceed(JNIEnv *env, jobject obj, int handle, jstring jUsername, jstring jPassword) @@ -2315,6 +2334,8 @@ static JNINativeMethod gBrowserFrameNativeMethods[] = { (void*) SslCertErrorCancel }, { "nativeSslClientCert", "(I[B[[B)V", (void*) SslClientCert }, + { "nativeGetShouldStartScrolledRight", "(I)Z", + (void*) GetShouldStartScrolledRight }, }; int registerWebFrame(JNIEnv* env) diff --git a/Source/WebKit/android/jni/WebViewCore.cpp b/Source/WebKit/android/jni/WebViewCore.cpp index 0708d5c..7692de1 100644 --- a/Source/WebKit/android/jni/WebViewCore.cpp +++ b/Source/WebKit/android/jni/WebViewCore.cpp @@ -832,10 +832,12 @@ SkPicture* WebViewCore::rebuildPicture(const SkIRect& inval) WebCore::PlatformGraphicsContext pgc(recordingCanvas); WebCore::GraphicsContext gc(&pgc); - recordingCanvas->translate(-inval.fLeft, -inval.fTop); + IntPoint origin = view->minimumScrollPosition(); + WebCore::IntRect drawArea(inval.fLeft + origin.x(), inval.fTop + origin.y(), + inval.width(), inval.height()); + recordingCanvas->translate(-drawArea.x(), -drawArea.y()); recordingCanvas->save(); - view->platformWidget()->draw(&gc, WebCore::IntRect(inval.fLeft, - inval.fTop, inval.width(), inval.height())); + view->platformWidget()->draw(&gc, drawArea); m_rebuildInval.op(inval, SkRegion::kUnion_Op); DBG_SET_LOGD("m_rebuildInval={%d,%d,r=%d,b=%d}", m_rebuildInval.getBounds().fLeft, m_rebuildInval.getBounds().fTop, @@ -1094,7 +1096,10 @@ void WebViewCore::didFirstLayout() // When redirect with locked history, we would like to reset the // scale factor. This is important for www.yahoo.com as it is // redirected to www.yahoo.com/?rs=1 on load. - || loadType == WebCore::FrameLoadTypeRedirectWithLockedBackForwardList); + || loadType == WebCore::FrameLoadTypeRedirectWithLockedBackForwardList + // When "request desktop page" is used, we want to treat it as + // a newly-loaded page. + || loadType == WebCore::FrameLoadTypeSame); checkException(env); DBG_NAV_LOG("call updateFrameCache"); @@ -1340,11 +1345,11 @@ void WebViewCore::setSizeScreenWidthAndScale(int width, int height, if (width != screenWidth) { m_mainFrame->view()->setUseFixedLayout(true); m_mainFrame->view()->setFixedLayoutSize(IntSize(width, height)); - } else { + } else m_mainFrame->view()->setUseFixedLayout(false); - } r->setNeedsLayoutAndPrefWidthsRecalc(); - m_mainFrame->view()->forceLayout(); + if (m_mainFrame->view()->didFirstLayout()) + m_mainFrame->view()->forceLayout(); // scroll to restore current screen center if (node) { @@ -1382,9 +1387,8 @@ void WebViewCore::setSizeScreenWidthAndScale(int width, int height, if (width != screenWidth) { m_mainFrame->view()->setUseFixedLayout(true); m_mainFrame->view()->setFixedLayoutSize(IntSize(width, height)); - } else { + } else m_mainFrame->view()->setUseFixedLayout(false); - } } // update the currently visible screen as perceived by the plugin diff --git a/Source/WebKit/android/nav/CacheBuilder.cpp b/Source/WebKit/android/nav/CacheBuilder.cpp index 623d2cb..0c9e85c 100644 --- a/Source/WebKit/android/nav/CacheBuilder.cpp +++ b/Source/WebKit/android/nav/CacheBuilder.cpp @@ -2882,8 +2882,6 @@ bool CacheBuilder::setData(CachedFrame* cachedFrame) RenderLayer* layer = renderer->enclosingLayer(); if (layer == NULL) return false; - if (layer->width() == 0 || layer->height() == 0) - return false; if (!frame->view()) return false; int x, y; diff --git a/Source/WebKit/android/nav/WebView.cpp b/Source/WebKit/android/nav/WebView.cpp index 60bdd3e..59fd6da 100644 --- a/Source/WebKit/android/nav/WebView.cpp +++ b/Source/WebKit/android/nav/WebView.cpp @@ -204,6 +204,7 @@ WebView(JNIEnv* env, jobject javaWebView, int viewImpl, WTF::String drawableDir) m_ringAnimationEnd = 0; m_baseLayer = 0; m_glDrawFunctor = 0; + m_isDrawingPaused = false; m_buttonSkin = drawableDir.isEmpty() ? 0 : new RenderSkinButton(drawableDir); #if USE(ACCELERATED_COMPOSITING) m_glWebViewState = 0; @@ -542,7 +543,7 @@ bool drawGL(WebCore::IntRect& viewRect, WebCore::IntRect* invalRect, WebCore::In } } if (ret || m_glWebViewState->currentPictureCounter() != pic) - return true; + return !m_isDrawingPaused; #endif return false; } @@ -1544,6 +1545,7 @@ BaseLayerAndroid* getBaseLayer() { return m_baseLayer; } + bool m_isDrawingPaused; private: // local state for WebView // private to getFrameCache(); other functions operate in a different thread CachedRoot* m_frameCacheUI; // navigation data ready for use @@ -2044,8 +2046,8 @@ static jobject nativeFocusCandidateNodeBounds(JNIEnv *env, jobject obj) : WebCore::IntRect(0, 0, 0, 0); // Inset the rect by 1 unit, so that the focus candidate's border can still // be seen behind it. - return createJavaRect(env, bounds.x() + 1, bounds.y() + 1, - bounds.maxX() - 1, bounds.maxY() - 1); + return createJavaRect(env, bounds.x(), bounds.y(), + bounds.maxX(), bounds.maxY()); } static jobject nativeFocusCandidatePaddingRect(JNIEnv *env, jobject obj) @@ -2703,6 +2705,12 @@ static int nativeGetBackgroundColor(JNIEnv* env, jobject obj) return SK_ColorWHITE; } +static void nativeSetPauseDrawing(JNIEnv *env, jobject obj, jint nativeView, + jboolean pause) +{ + ((WebView*)nativeView)->m_isDrawingPaused = pause; +} + /* * JNI registration */ @@ -2915,6 +2923,8 @@ static JNINativeMethod gJavaWebViewMethods[] = { (void*) nativeGetProperty }, { "nativeOnTrimMemory", "(I)V", (void*) nativeOnTrimMemory }, + { "nativeSetPauseDrawing", "(IZ)V", + (void*) nativeSetPauseDrawing }, }; int registerWebView(JNIEnv* env) |