diff options
Diffstat (limited to 'Source/WebCore')
10 files changed, 176 insertions, 113 deletions
diff --git a/Source/WebCore/platform/graphics/android/BaseLayerAndroid.cpp b/Source/WebCore/platform/graphics/android/BaseLayerAndroid.cpp index 1fa69f8..0ab28d7 100644 --- a/Source/WebCore/platform/graphics/android/BaseLayerAndroid.cpp +++ b/Source/WebCore/platform/graphics/android/BaseLayerAndroid.cpp @@ -239,7 +239,6 @@ bool BaseLayerAndroid::drawBasePictureInGL(SkRect& viewport, float scale, tiledPage->draw(transparency, preZoomBounds); - m_glWebViewState->paintExtras(); return needsRedraw; } #endif // USE(ACCELERATED_COMPOSITING) @@ -281,12 +280,14 @@ bool BaseLayerAndroid::drawGL(double currentTime, LayerAndroid* compositedRoot, // Clean up GL textures for video layer. TilesManager::instance()->videoLayerManager()->deleteUnusedTextures(); + compositedRoot->prepare(m_glWebViewState); if (compositedRoot->drawGL(m_glWebViewState, matrix)) needsRedraw = true; else if (!animsRunning) m_glWebViewState->resetLayersDirtyArea(); } + m_glWebViewState->paintExtras(); m_previousVisible = visibleRect; diff --git a/Source/WebCore/platform/graphics/android/BaseTile.cpp b/Source/WebCore/platform/graphics/android/BaseTile.cpp index dc17a21..a4ce788 100644 --- a/Source/WebCore/platform/graphics/android/BaseTile.cpp +++ b/Source/WebCore/platform/graphics/android/BaseTile.cpp @@ -135,13 +135,12 @@ void BaseTile::reserveTexture() if (texture && m_backTexture != texture) { m_swapDrawCount = 0; // no longer ready to swap m_backTexture = texture; - - // this is to catch when the front texture is stolen from beneath us. We - // should refine the stealing method to be simpler, and not require last - // moment checks like this - if (!m_frontTexture) - m_dirty = true; } + + // a texture reservation will only happen if we're dirty, or ready to + // swap. if it's the former, ensure it's marked dirty. + if (!m_swapDrawCount) + m_dirty = true; } bool BaseTile::removeTexture(BaseTileTexture* texture) @@ -150,12 +149,15 @@ bool BaseTile::removeTexture(BaseTileTexture* texture) this, m_backTexture, m_frontTexture, m_page); // We update atomically, so paintBitmap() can see the correct value android::AutoMutex lock(m_atomicSync); - if (m_frontTexture == texture) { + if (m_frontTexture == texture) m_frontTexture = 0; - m_dirty = true; - } if (m_backTexture == texture) m_backTexture = 0; + + // mark dirty regardless of which texture was taken - the back texture may + // have been ready to swap + m_dirty = true; + return true; } diff --git a/Source/WebCore/platform/graphics/android/GLWebViewState.cpp b/Source/WebCore/platform/graphics/android/GLWebViewState.cpp index 5764a6b..40a9428 100644 --- a/Source/WebCore/platform/graphics/android/GLWebViewState.cpp +++ b/Source/WebCore/platform/graphics/android/GLWebViewState.cpp @@ -32,6 +32,7 @@ #include "ClassTracker.h" #include "GLUtils.h" #include "LayerAndroid.h" +#include "SkPath.h" #include "TilesManager.h" #include "TilesTracker.h" #include <wtf/CurrentTime.h> @@ -59,6 +60,14 @@ #define FRAMERATE_CAP 0.01666 // We cap at 60 fps +// Touch ring border width. This is doubled if the ring is not pressed +#define RING_BORDER_WIDTH 1 +// Color of the ring is 0x6633b5e5 (copied from framework) +#define RING_COLOR_ALPHA 0.4 +#define RING_COLOR_R 0x33 +#define RING_COLOR_G 0xb5 +#define RING_COLOR_B 0xe5 + namespace WebCore { using namespace android; @@ -170,7 +179,9 @@ void GLWebViewState::setRings(Vector<IntRect>& rings, bool isPressed) { android::Mutex::Autolock lock(m_baseLayerLock); m_displayRings = true; - m_rings = rings; + m_rings.setEmpty(); + for (size_t i = 0; i < rings.size(); i++) + m_rings.op(rings.at(i), SkRegion::kUnion_Op); m_ringsIsPressed = isPressed; } @@ -247,78 +258,80 @@ void GLWebViewState::resetRings() m_displayRings = false; } -void GLWebViewState::drawFocusRing(IntRect& srcRect) +void GLWebViewState::drawFocusRing(SkRect& srcRect) { - // TODO: use a 9-patch texture to draw the focus ring - // instead of plain colors - const float alpha = 0.3; - float borderAlpha = 0.4; - - const int r = 51; - const int g = 181; - const int b = 229; - - int padding = 4; - int border = 1; - int fuzzyBorder = border * 2; - if (!m_ringsIsPressed) { - padding = 0; - border = 2; - fuzzyBorder = 3; - borderAlpha = 0.2; - } if (m_focusRingTexture == -1) - m_focusRingTexture = GLUtils::createSampleColorTexture(r, g, b); - - SkRect rLeft, rTop, rRight, rBottom, rOverlay; - - IntRect rect(srcRect.x() - padding, srcRect.y() - padding, - srcRect.width() + (padding * 2), srcRect.height() + (padding * 2)); - rLeft.set(rect.x() - border, rect.y(), - rect.x(), rect.y() + rect.height()); - rTop.set(rect.x() - border, rect.y() - border, - rect.x() + rect.width() + border, rect.y()); - rRight.set(rect.x() + rect.width(), rect.y(), - rect.x() + rect.width() + border, - rect.y() + rect.height()); - rBottom.set(rect.x() - border, rect.y() + rect.height(), - rect.x() + rect.width() + border, - rect.y() + rect.height() + border); - rOverlay.set(rect.x() - fuzzyBorder, rect.y() - fuzzyBorder, - rect.x() + rect.width() + fuzzyBorder, - rect.y() + rect.height() + fuzzyBorder); - - TilesManager::instance()->shader()->drawQuad(rLeft, m_focusRingTexture, borderAlpha); - TilesManager::instance()->shader()->drawQuad(rTop, m_focusRingTexture, borderAlpha); - TilesManager::instance()->shader()->drawQuad(rRight, m_focusRingTexture, borderAlpha); - TilesManager::instance()->shader()->drawQuad(rBottom, m_focusRingTexture, borderAlpha); - if (m_ringsIsPressed) { - TilesManager::instance()->shader()->drawQuad(rOverlay, m_focusRingTexture, alpha); - } else { - rLeft.set(rect.x() - fuzzyBorder, rect.y(), - rect.x(), rect.y() + rect.height()); - rTop.set(rect.x() - fuzzyBorder, rect.y() - fuzzyBorder, - rect.x() + rect.width() + fuzzyBorder, rect.y()); - rRight.set(rect.x() + rect.width(), rect.y(), - rect.x() + rect.width() + fuzzyBorder, - rect.y() + rect.height()); - rBottom.set(rect.x() - fuzzyBorder, rect.y() + rect.height(), - rect.x() + rect.width() + fuzzyBorder, - rect.y() + rect.height() + fuzzyBorder); - TilesManager::instance()->shader()->drawQuad(rLeft, m_focusRingTexture, alpha); - TilesManager::instance()->shader()->drawQuad(rTop, m_focusRingTexture, alpha); - TilesManager::instance()->shader()->drawQuad(rRight, m_focusRingTexture, alpha); - TilesManager::instance()->shader()->drawQuad(rBottom, m_focusRingTexture, alpha); - } + m_focusRingTexture = GLUtils::createSampleColorTexture(RING_COLOR_R, + RING_COLOR_G, + RING_COLOR_B); + + TilesManager::instance()->shader()->drawQuad(srcRect, m_focusRingTexture, + RING_COLOR_ALPHA); } void GLWebViewState::paintExtras() { - if (m_displayRings) { - // TODO: handles correctly the multi-rings case - for (size_t i = 0; i < m_rings.size(); i++) { - IntRect rect = m_rings.at(i); - drawFocusRing(rect); + if (m_displayRings && !m_rings.isEmpty()) { + if (m_ringsIsPressed) { + SkRegion::Iterator rgnIter(m_rings); + while (!rgnIter.done()) { + SkIRect ir = rgnIter.rect(); + SkRect r; + r.set(ir.fLeft, ir.fTop, ir.fRight, ir.fBottom); + drawFocusRing(r); + rgnIter.next(); + } + } + SkPath path; + if (!m_rings.getBoundaryPath(&path)) + return; + SkPath::Iter iter(path, true); + SkPath::Verb verb; + SkPoint pts[4]; + SkRegion clip; + SkIRect startRect; + while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { + if (verb == SkPath::kLine_Verb) { + SkRect r; + r.set(pts, 2); + SkIRect line; + int borderWidth = RING_BORDER_WIDTH; + if (!m_ringsIsPressed) + borderWidth *= 2; + line.fLeft = r.fLeft - borderWidth; + line.fRight = r.fRight + borderWidth; + line.fTop = r.fTop - borderWidth; + line.fBottom = r.fBottom + borderWidth; + if (clip.intersects(line)) { + clip.op(line, SkRegion::kReverseDifference_Op); + if (clip.isEmpty()) + continue; // Nothing to draw, continue + line = clip.getBounds(); + if (SkIRect::Intersects(startRect, line)) { + clip.op(startRect, SkRegion::kDifference_Op); + if (clip.isEmpty()) + continue; // Nothing to draw, continue + line = clip.getBounds(); + } + } else { + clip.setRect(line); + } + r.set(line.fLeft, line.fTop, line.fRight, line.fBottom); + drawFocusRing(r); + if (!m_ringsIsPressed) { + r.fLeft += RING_BORDER_WIDTH; + r.fRight -= RING_BORDER_WIDTH; + r.fTop += RING_BORDER_WIDTH; + r.fBottom -= RING_BORDER_WIDTH; + drawFocusRing(r); + } + if (startRect.isEmpty()) { + startRect.set(line.fLeft, line.fTop, line.fRight, line.fBottom); + } + } + if (verb == SkPath::kMove_Verb) { + startRect.setEmpty(); + } } } } diff --git a/Source/WebCore/platform/graphics/android/GLWebViewState.h b/Source/WebCore/platform/graphics/android/GLWebViewState.h index a7803de..6c7d31e 100644 --- a/Source/WebCore/platform/graphics/android/GLWebViewState.h +++ b/Source/WebCore/platform/graphics/android/GLWebViewState.h @@ -179,7 +179,7 @@ public: void setRings(Vector<IntRect>& rings, bool isPressed); void resetRings(); - void drawFocusRing(IntRect& rect); + void drawFocusRing(SkRect& rect); TiledPage* sibling(TiledPage* page); TiledPage* frontPage(); @@ -269,7 +269,7 @@ private: bool m_measurePerfs; #endif bool m_displayRings; - Vector<IntRect> m_rings; + SkRegion m_rings; bool m_ringsIsPressed; int m_focusRingTexture; diff --git a/Source/WebCore/platform/graphics/android/Layer.h b/Source/WebCore/platform/graphics/android/Layer.h index 6450fde..107c457 100644 --- a/Source/WebCore/platform/graphics/android/Layer.h +++ b/Source/WebCore/platform/graphics/android/Layer.h @@ -122,14 +122,17 @@ private: kInheritFromRootTransform_Flag = 0x01 }; - Layer* fParent; - SkScalar m_opacity; - SkSize m_size; - SkPoint m_position; - SkPoint m_anchorPoint; - SkMatrix fMatrix; - SkMatrix fChildrenMatrix; - uint32_t fFlags; + Layer* fParent; + SkScalar m_opacity; + SkSize m_size; + // The position of the origin of the layer, relative to the parent layer. + SkPoint m_position; + // The point in the layer used as the origin for local transformations, + // expressed as a fraction of the layer size. + SkPoint m_anchorPoint; + SkMatrix fMatrix; + SkMatrix fChildrenMatrix; + uint32_t fFlags; SkTDArray<Layer*> m_children; diff --git a/Source/WebCore/platform/graphics/android/LayerAndroid.cpp b/Source/WebCore/platform/graphics/android/LayerAndroid.cpp index 48dcaaa..a39614f 100644 --- a/Source/WebCore/platform/graphics/android/LayerAndroid.cpp +++ b/Source/WebCore/platform/graphics/android/LayerAndroid.cpp @@ -267,7 +267,7 @@ void LayerAndroid::removeAnimationsForKeyframes(const String& name) } // We only use the bounding rect of the layer as mask... -// TODO: use a real mask? +// FIXME: use a real mask? void LayerAndroid::setMaskLayer(LayerAndroid* layer) { if (layer) @@ -546,7 +546,7 @@ void LayerAndroid::updatePositions() if (!m_isFixed) { // turn our fields into a matrix. // - // TODO: this should happen in the caller, and we should remove these + // FIXME: this should happen in the caller, and we should remove these // fields from our subclass SkMatrix matrix; GLUtils::toSkMatrix(matrix, m_transform); @@ -793,6 +793,26 @@ void LayerAndroid::clearDirtyRegion() m_dirtyRegion.setEmpty(); } +void LayerAndroid::prepare(GLWebViewState* glWebViewState) +{ + 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); + + // iterate in reverse so top layers get textures first + for (int i = count-1; i >= 0; i--) + sublayers[i]->prepare(glWebViewState); + } + + if (m_texture) + m_texture->prepare(glWebViewState); +} + bool LayerAndroid::drawGL(GLWebViewState* glWebViewState, SkMatrix& matrix) { TilesManager::instance()->shader()->clip(m_clippingRect); @@ -801,10 +821,8 @@ bool LayerAndroid::drawGL(GLWebViewState* glWebViewState, SkMatrix& matrix) bool askPaint = false; - if (m_texture) { - m_texture->prepare(glWebViewState); + if (m_texture) askPaint |= m_texture->draw(); - } // When the layer is dirty, the UI thread should be notified to redraw. askPaint |= drawChildrenGL(glWebViewState, matrix); @@ -817,7 +835,6 @@ bool LayerAndroid::drawGL(GLWebViewState* glWebViewState, SkMatrix& matrix) return askPaint; } - bool LayerAndroid::drawChildrenGL(GLWebViewState* glWebViewState, SkMatrix& matrix) { bool askPaint = false; @@ -926,6 +943,11 @@ SkRect LayerAndroid::subtractLayers(const SkRect& visibleRect) const { SkRect result; if (m_recordingPicture) { + // FIXME: This seems wrong. localToGlobal() applies the full local transform, + // se surely we should operate globalMatrix on size(), not bounds() with + // the position removed? Perhaps we never noticed the bug because most + // layers don't use a local transform? + // See http://b/5338388 SkRect globalRect = bounds(); globalRect.offset(-getPosition()); // localToGlobal adds in position SkMatrix globalMatrix; diff --git a/Source/WebCore/platform/graphics/android/LayerAndroid.h b/Source/WebCore/platform/graphics/android/LayerAndroid.h index 7192aaf..8078762 100644 --- a/Source/WebCore/platform/graphics/android/LayerAndroid.h +++ b/Source/WebCore/platform/graphics/android/LayerAndroid.h @@ -109,6 +109,10 @@ public: void setBackfaceVisibility(bool value) { m_backfaceVisibility = value; } void setTransform(const TransformationMatrix& matrix) { m_transform = matrix; } FloatPoint translation() const; + // Returns a rect describing the bounds of the layer with the local + // transformation applied, expressed relative to the parent layer. + // FIXME: Currently we use only the translation component of the local + // transformation. SkRect bounds() const; IntRect clippedRect() const; bool outsideViewport(); @@ -121,8 +125,14 @@ public: void showLayer(int indent); float getScale() { return m_scale; } + + // draw layer and its children via Z, pre-order traversal virtual bool drawGL(GLWebViewState*, SkMatrix&); bool drawChildrenGL(GLWebViewState*, SkMatrix&); + + // prepare layer and its children via reverse-Z, post-order traversal + void prepare(GLWebViewState*); + void updateGLPositionsAndScale(const TransformationMatrix& parentMatrix, const FloatRect& clip, float opacity, float scale); void setDrawOpacity(float opacity) { m_drawOpacity = opacity; } @@ -183,9 +193,10 @@ public: SkPicture* picture() const { return m_recordingPicture; } - // remove layers bounds from visible rectangle to show what can be - // scrolled into view; returns original minus layer bounds in global space. - SkRect subtractLayers(const SkRect& visibleRect) const; + // Given a rect in global space, subtracts from it the bounds of this layer + // and of all of its children. Returns the bounding rectangle of the result, + // in global space. + SkRect subtractLayers(const SkRect&) const; void dumpLayers(FILE*, int indentLevel) const; void dumpToLog() const; diff --git a/Source/WebCore/platform/graphics/android/ScrollableLayerAndroid.cpp b/Source/WebCore/platform/graphics/android/ScrollableLayerAndroid.cpp index ca8f03c..2bb8b5c 100644 --- a/Source/WebCore/platform/graphics/android/ScrollableLayerAndroid.cpp +++ b/Source/WebCore/platform/graphics/android/ScrollableLayerAndroid.cpp @@ -18,10 +18,7 @@ bool ScrollableLayerAndroid::scrollTo(int x, int y) if (newX == scrollBounds.fLeft && newY == scrollBounds.fTop) return false; - SkScalar diffX = newX - scrollBounds.fLeft; - SkScalar diffY = newY - scrollBounds.fTop; - const SkPoint& pos = getPosition(); - setPosition(pos.fX - diffX, pos.fY - diffY); + setPosition(m_scrollLimits.fLeft - newX, m_scrollLimits.fTop - newY); return true; } diff --git a/Source/WebCore/platform/graphics/android/ScrollableLayerAndroid.h b/Source/WebCore/platform/graphics/android/ScrollableLayerAndroid.h index c3fdecd..b59b4e1 100644 --- a/Source/WebCore/platform/graphics/android/ScrollableLayerAndroid.h +++ b/Source/WebCore/platform/graphics/android/ScrollableLayerAndroid.h @@ -42,15 +42,16 @@ public: virtual LayerAndroid* copy() const { return new ScrollableLayerAndroid(*this); } - // Returns true if the content position has changed. - bool scrollTo(int dx, int dy); + // Scrolls to the given position in the layer. + // Returns whether or not any scrolling was required. + bool scrollTo(int x, int y); - // Fills the rect with the current scroll offset and the maximum scroll. + // Fills the rect with the current scroll offset and the maximum scroll offset. // fLeft = scrollX // fTop = scrollY - // fRight = maxX - // fBottom = maxY - void getScrollRect(SkIRect* out) const; + // fRight = maxScrollX + // fBottom = maxScrollY + void getScrollRect(SkIRect*) const; void setScrollLimits(float x, float y, float width, float height) { @@ -61,6 +62,9 @@ public: friend LayerAndroid* android::deserializeLayer(SkStream* stream); private: + // The position of the visible area of the layer, relative to the parent + // layer. This is fixed during scrolling. We acheive scrolling by modifying + // the position of the layer. SkRect m_scrollLimits; }; diff --git a/Source/WebCore/platform/graphics/android/TilesManager.cpp b/Source/WebCore/platform/graphics/android/TilesManager.cpp index ee35ce2..e1d7665 100644 --- a/Source/WebCore/platform/graphics/android/TilesManager.cpp +++ b/Source/WebCore/platform/graphics/android/TilesManager.cpp @@ -267,11 +267,13 @@ BaseTileTexture* TilesManager::getAvailableTexture(BaseTile* owner) } // The heuristic for selecting a texture is as follows: - // 1. If a tile isn't owned, break with that one - // 2. Don't let tiles acquire their front textures - // 3. If we find a tile in the same page with a different scale, + // 1. Skip textures currently being painted, they can't be painted while + // busy anyway + // 2. If a tile isn't owned, break with that one + // 3. Don't let tiles acquire their front textures + // 4. If we find a tile in the same page with a different scale, // it's old and not visible. Break with that one - // 4. Otherwise, use the least recently prepared tile, but ignoring tiles + // 5. Otherwise, use the least recently prepared tile, but ignoring tiles // drawn in the last frame to avoid flickering BaseTileTexture* farthestTexture = 0; @@ -280,15 +282,23 @@ BaseTileTexture* TilesManager::getAvailableTexture(BaseTile* owner) for (unsigned int i = 0; i < max; i++) { BaseTileTexture* texture = (*availableTexturePool)[i]; TextureOwner* currentOwner = texture->owner(); + + if (texture->busy()) { + // don't bother, since the acquire() will likely fail + continue; + } + if (!currentOwner) { + // unused texture! take it! farthestTexture = texture; break; } - // Don't let a tile acquire its own front texture, as the acquisition - // logic doesn't handle that - if (currentOwner == owner) + if (currentOwner == owner) { + // Don't let a tile acquire its own front texture, as the + // acquisition logic doesn't handle that continue; + } if (currentOwner->page() == owner->page() && texture->scale() != owner->scale()) { // if we render the back page with one scale, then another while |