diff options
69 files changed, 2421 insertions, 1222 deletions
diff --git a/Source/WebCore/Android.mk b/Source/WebCore/Android.mk index a516f48..6542931 100644 --- a/Source/WebCore/Android.mk +++ b/Source/WebCore/Android.mk @@ -680,7 +680,7 @@ LOCAL_SRC_FILES := $(LOCAL_SRC_FILES) \ platform/graphics/android/TiledPage.cpp \ platform/graphics/android/TiledTexture.cpp \ platform/graphics/android/TransferQueue.cpp \ - platform/graphics/android/UpdateManager.cpp \ + platform/graphics/android/TreeManager.cpp \ platform/graphics/android/VerticalTextMap.cpp \ platform/graphics/android/VideoLayerAndroid.cpp \ platform/graphics/android/VideoLayerManager.cpp \ diff --git a/Source/WebCore/loader/cache/CachedImage.cpp b/Source/WebCore/loader/cache/CachedImage.cpp index ba30860..6867302 100644 --- a/Source/WebCore/loader/cache/CachedImage.cpp +++ b/Source/WebCore/loader/cache/CachedImage.cpp @@ -57,6 +57,7 @@ CachedImage::CachedImage(const String& url) , m_image(0) , m_decodedDataDeletionTimer(this, &CachedImage::decodedDataDeletionTimerFired) , m_shouldPaintBrokenImage(true) + , m_autoLoadWasPreventedBySettings(false) { setStatus(Unknown); } @@ -66,6 +67,7 @@ CachedImage::CachedImage(Image* image) , m_image(image) , m_decodedDataDeletionTimer(this, &CachedImage::decodedDataDeletionTimerFired) , m_shouldPaintBrokenImage(true) + , m_autoLoadWasPreventedBySettings(false) { setStatus(Cached); setLoading(false); diff --git a/Source/WebCore/loader/cache/CachedImage.h b/Source/WebCore/loader/cache/CachedImage.h index 42c7814..79643d7 100644 --- a/Source/WebCore/loader/cache/CachedImage.h +++ b/Source/WebCore/loader/cache/CachedImage.h @@ -75,7 +75,7 @@ public: void clear(); - bool stillNeedsLoad() const { return !errorOccurred() && status() == Unknown && !isLoading(); } + bool stillNeedsLoad() const { return (!errorOccurred() && status() == Unknown && !isLoading()) || (m_autoLoadWasPreventedBySettings && !inCache()); } void load(); // ImageObserver @@ -86,6 +86,8 @@ public: virtual void animationAdvanced(const Image*); virtual void changedInRect(const Image*, const IntRect&); + void setAutoLoadWasPreventedBySettings(bool prevented) { m_autoLoadWasPreventedBySettings = prevented; } + private: void createImage(); size_t maximumDecodedImageSize(); @@ -98,6 +100,7 @@ private: RefPtr<Image> m_image; Timer<CachedImage> m_decodedDataDeletionTimer; bool m_shouldPaintBrokenImage; + bool m_autoLoadWasPreventedBySettings; }; } diff --git a/Source/WebCore/loader/cache/CachedResource.cpp b/Source/WebCore/loader/cache/CachedResource.cpp index 95f5522..e599769 100644 --- a/Source/WebCore/loader/cache/CachedResource.cpp +++ b/Source/WebCore/loader/cache/CachedResource.cpp @@ -261,7 +261,7 @@ void CachedResource::addClient(CachedResourceClient* client) void CachedResource::didAddClient(CachedResourceClient* c) { - if (!isLoading()) + if (!isLoading() && !stillNeedsLoad()) c->notifyFinished(this); } diff --git a/Source/WebCore/loader/cache/CachedResource.h b/Source/WebCore/loader/cache/CachedResource.h index 72b00e5..2f33ac7 100644 --- a/Source/WebCore/loader/cache/CachedResource.h +++ b/Source/WebCore/loader/cache/CachedResource.h @@ -127,6 +127,7 @@ public: bool isLoading() const { return m_loading; } void setLoading(bool b) { m_loading = b; } + virtual bool stillNeedsLoad() const { return false; } virtual bool isImage() const { return false; } bool isLinkResource() const diff --git a/Source/WebCore/loader/cache/CachedResourceLoader.cpp b/Source/WebCore/loader/cache/CachedResourceLoader.cpp index 38fcee4..91c0629 100644 --- a/Source/WebCore/loader/cache/CachedResourceLoader.cpp +++ b/Source/WebCore/loader/cache/CachedResourceLoader.cpp @@ -138,14 +138,21 @@ CachedImage* CachedResourceLoader::requestImage(const String& url) } } CachedImage* resource = static_cast<CachedImage*>(requestResource(CachedResource::ImageResource, url, String())); - if (autoLoadImages() && resource && resource->stillNeedsLoad()) { + if (resource) { #ifdef ANDROID_BLOCK_NETWORK_IMAGE - if (shouldBlockNetworkImage(url)) { - return resource; - } + resource->setAutoLoadWasPreventedBySettings(!autoLoadImages() || shouldBlockNetworkImage(url)); +#else + resource->setAutoLoadWasPreventedBySettings(!autoLoadImages()); +#endif + if (autoLoadImages() && resource->stillNeedsLoad()) { +#ifdef ANDROID_BLOCK_NETWORK_IMAGE + if (shouldBlockNetworkImage(url)) { + return resource; + } #endif - resource->setLoading(true); - load(resource, true); + resource->setLoading(true); + load(resource, true); + } } return resource; } @@ -520,9 +527,12 @@ void CachedResourceLoader::setAutoLoadImages(bool enable) if (shouldBlockNetworkImage(image->url())) continue; #endif + image->setAutoLoadWasPreventedBySettings(false); - if (image->stillNeedsLoad()) + if (image->stillNeedsLoad()) { + image->setLoading(true); load(image, true); + } } } } @@ -536,7 +546,6 @@ bool CachedResourceLoader::shouldBlockNetworkImage(const String& url) const KURL kurl = m_document->completeURL(url); if (kurl.protocolIs("http") || kurl.protocolIs("https")) return true; - return false; } @@ -555,8 +564,11 @@ void CachedResourceLoader::setBlockNetworkImage(bool block) CachedResource* resource = it->second.get(); if (resource->type() == CachedResource::ImageResource) { CachedImage* image = const_cast<CachedImage*>(static_cast<const CachedImage*>(resource)); - if (image->stillNeedsLoad()) + image->setAutoLoadWasPreventedBySettings(false); + if (image->stillNeedsLoad()) { + image->setLoading(true); load(image, true); + } } } } diff --git a/Source/WebCore/platform/graphics/android/AndroidAnimation.cpp b/Source/WebCore/platform/graphics/android/AndroidAnimation.cpp index 5601269..6b22359 100644 --- a/Source/WebCore/platform/graphics/android/AndroidAnimation.cpp +++ b/Source/WebCore/platform/graphics/android/AndroidAnimation.cpp @@ -49,6 +49,8 @@ namespace WebCore { +static int gUniqueId; + static long gDebugAndroidAnimationInstances; long AndroidAnimation::instancesCount() @@ -69,27 +71,11 @@ AndroidAnimation::AndroidAnimation(AnimatedPropertyID type, , m_timingFunction(animation->timingFunction()) , m_type(type) , m_operations(operations) + , m_uniqueId(++gUniqueId) + , m_hasFinished(false) { ASSERT(m_timingFunction); - if (!static_cast<int>(beginTime)) // time not set - m_beginTime = WTF::currentTime(); - - gDebugAndroidAnimationInstances++; -} - -AndroidAnimation::AndroidAnimation(AndroidAnimation* anim) - : m_beginTime(anim->m_beginTime) - , m_duration(anim->m_duration) - , m_fillsBackwards(anim->m_fillsBackwards) - , m_fillsForwards(anim->m_fillsForwards) - , m_iterationCount(anim->m_iterationCount) - , m_direction(anim->m_direction) - , m_timingFunction(anim->m_timingFunction) - , m_name(anim->name()) - , m_type(anim->m_type) - , m_operations(anim->m_operations) -{ gDebugAndroidAnimationInstances++; } @@ -98,20 +84,23 @@ AndroidAnimation::~AndroidAnimation() gDebugAndroidAnimationInstances--; } -double AndroidAnimation::elapsedTime(double time) +void AndroidAnimation::suggestBeginTime(double time) { - if (m_beginTime <= 0.000001) // overflow or not correctly set + if (m_beginTime <= 0.000001) // overflow or not yet set m_beginTime = time; +} - m_elapsedTime = time - m_beginTime; +double AndroidAnimation::elapsedTime(double time) +{ + double elapsedTime = (m_beginTime < 0.000001) ? 0 : time - m_beginTime; if (m_duration <= 0) m_duration = 0.000001; - if (m_elapsedTime < 0) // animation not yet started. + if (elapsedTime < 0) // animation not yet started. return 0; - return m_elapsedTime; + return elapsedTime; } bool AndroidAnimation::checkIterationsAndProgress(double time, float* finalProgress) @@ -127,6 +116,13 @@ bool AndroidAnimation::checkIterationsAndProgress(double time, float* finalProgr // If not infinite, return false if we are done if (m_iterationCount > 0 && progress > dur) { *finalProgress = 1.0; + if (!m_hasFinished) { + // first time past duration, continue with progress 1.0 so the + // element's final position lines up with it's last keyframe + m_hasFinished = true; + return true; + } + return false; } @@ -187,7 +183,7 @@ bool AndroidAnimation::evaluate(LayerAndroid* layer, double time) if (progress < 0) { // The animation hasn't started yet - if (m_fillsBackwards) { + if (m_fillsBackwards || m_beginTime <= 0.000001) { // in this case we want to apply the initial keyframe to the layer applyForProgress(layer, 0); } @@ -195,7 +191,7 @@ bool AndroidAnimation::evaluate(LayerAndroid* layer, double time) return true; } - if (progress >= 1) { + if (progress > 1) { if (!m_fillsForwards) return false; progress = 1; @@ -225,16 +221,6 @@ AndroidOpacityAnimation::AndroidOpacityAnimation(const Animation* animation, { } -AndroidOpacityAnimation::AndroidOpacityAnimation(AndroidOpacityAnimation* anim) - : AndroidAnimation(anim) -{ -} - -PassRefPtr<AndroidAnimation> AndroidOpacityAnimation::copy() -{ - return adoptRef(new AndroidOpacityAnimation(this)); -} - void AndroidAnimation::pickValues(double progress, int* start, int* end) { float distance = -1; @@ -298,16 +284,6 @@ AndroidTransformAnimation::AndroidTransformAnimation(const Animation* animation, { } -AndroidTransformAnimation::AndroidTransformAnimation(AndroidTransformAnimation* anim) - : AndroidAnimation(anim) -{ -} - -PassRefPtr<AndroidAnimation> AndroidTransformAnimation::copy() -{ - return adoptRef(new AndroidTransformAnimation(this)); -} - void AndroidTransformAnimation::applyForProgress(LayerAndroid* layer, float progress) { // First, we need to get the from and to values diff --git a/Source/WebCore/platform/graphics/android/AndroidAnimation.h b/Source/WebCore/platform/graphics/android/AndroidAnimation.h index 16a63e8..dca769f 100644 --- a/Source/WebCore/platform/graphics/android/AndroidAnimation.h +++ b/Source/WebCore/platform/graphics/android/AndroidAnimation.h @@ -33,16 +33,15 @@ namespace WebCore { class TimingFunction; -class AndroidAnimation : public RefCounted<AndroidAnimation> { +class AndroidAnimation : public ThreadSafeRefCounted<AndroidAnimation> { public: AndroidAnimation(AnimatedPropertyID type, const Animation* animation, KeyframeValueList* operations, double beginTime); - AndroidAnimation(AndroidAnimation* anim); virtual ~AndroidAnimation(); - virtual PassRefPtr<AndroidAnimation> copy() = 0; + void suggestBeginTime(double time); double elapsedTime(double time); void pickValues(double progress, int* start, int* end); bool checkIterationsAndProgress(double time, float* finalProgress); @@ -56,11 +55,10 @@ public: AnimatedPropertyID type() { return m_type; } bool fillsBackwards() { return m_fillsBackwards; } bool fillsForwards() { return m_fillsForwards; } - + int uniqueId() { return m_uniqueId; } protected: double m_beginTime; - double m_elapsedTime; double m_duration; bool m_fillsBackwards; bool m_fillsForwards; @@ -70,6 +68,8 @@ protected: String m_name; AnimatedPropertyID m_type; KeyframeValueList* m_operations; + int m_uniqueId; + bool m_hasFinished; }; class AndroidOpacityAnimation : public AndroidAnimation { @@ -80,8 +80,6 @@ public: AndroidOpacityAnimation(const Animation* animation, KeyframeValueList* operations, double beginTime); - AndroidOpacityAnimation(AndroidOpacityAnimation* anim); - virtual PassRefPtr<AndroidAnimation> copy(); virtual void applyForProgress(LayerAndroid* layer, float progress); }; @@ -96,9 +94,6 @@ public: KeyframeValueList* operations, double beginTime); - AndroidTransformAnimation(AndroidTransformAnimation* anim); - virtual PassRefPtr<AndroidAnimation> copy(); - virtual void applyForProgress(LayerAndroid* layer, float progress); }; diff --git a/Source/WebCore/platform/graphics/android/BaseLayerAndroid.cpp b/Source/WebCore/platform/graphics/android/BaseLayerAndroid.cpp index 0e6f64f..7ec2d78 100644 --- a/Source/WebCore/platform/graphics/android/BaseLayerAndroid.cpp +++ b/Source/WebCore/platform/graphics/android/BaseLayerAndroid.cpp @@ -66,8 +66,7 @@ using namespace android; BaseLayerAndroid::BaseLayerAndroid() #if USE(ACCELERATED_COMPOSITING) - : m_glWebViewState(0) - , m_color(Color::white) + : m_color(Color::white) , m_scrollState(NotScrolling) #endif { @@ -123,8 +122,8 @@ void BaseLayerAndroid::prefetchBasePicture(SkRect& viewport, float currentScale, / TilesManager::instance()->tileWidth(); float invTileHeight = (prefetchScale) / TilesManager::instance()->tileHeight(); - bool goingDown = m_glWebViewState->goingDown(); - bool goingLeft = m_glWebViewState->goingLeft(); + bool goingDown = m_state->goingDown(); + bool goingLeft = m_state->goingLeft(); XLOG("fetch rect %f %f %f %f, scale %f", @@ -150,21 +149,82 @@ void BaseLayerAndroid::prefetchBasePicture(SkRect& viewport, float currentScale, prefetchTiledPage->prepare(goingDown, goingLeft, bounds, TiledPage::ExpandedBounds); prefetchTiledPage->swapBuffersIfReady(bounds, - prefetchScale, - TiledPage::SwapWhateverIsReady); + prefetchScale); if (draw) - prefetchTiledPage->draw(PREFETCH_OPACITY, bounds); + prefetchTiledPage->prepareForDrawGL(PREFETCH_OPACITY, bounds); } -bool BaseLayerAndroid::drawBasePictureInGL(SkRect& viewport, float scale, - double currentTime, bool* buffersSwappedPtr) +bool BaseLayerAndroid::isReady() { - ZoomManager* zoomManager = m_glWebViewState->zoomManager(); + ZoomManager* zoomManager = m_state->zoomManager(); + if (ZoomManager::kNoScaleRequest != zoomManager->scaleRequestState()) { + XLOG("base layer not ready, still zooming"); + return false; // still zooming + } + + if (!m_state->frontPage()->isReady(m_state->preZoomBounds())) { + XLOG("base layer not ready, front page not done painting"); + return false; + } + + LayerAndroid* compositedRoot = static_cast<LayerAndroid*>(getChild(0)); + if (compositedRoot) { + XLOG("base layer is ready, how about children?"); + return compositedRoot->isReady(); + } + + return true; +} + +void BaseLayerAndroid::swapTiles() +{ + if (countChildren()) + getChild(0)->swapTiles(); // TODO: move to parent impl + + m_state->frontPage()->swapBuffersIfReady(m_state->preZoomBounds(), + m_state->zoomManager()->currentScale()); + + m_state->backPage()->swapBuffersIfReady(m_state->preZoomBounds(), + m_state->zoomManager()->currentScale()); +} + +void BaseLayerAndroid::setIsDrawing(bool isDrawing) +{ + if (countChildren()) + getChild(0)->setIsDrawing(isDrawing); // TODO: move to parent impl +} + +void BaseLayerAndroid::setIsPainting(Layer* drawingTree) +{ + XLOG("BLA %p painting, dirty %d", this, isDirty()); + if (drawingTree) + drawingTree = drawingTree->getChild(0); + + if (countChildren()) + getChild(0)->setIsPainting(drawingTree); // TODO: move to parent impl + + m_state->invalRegion(m_dirtyRegion); + m_dirtyRegion.setEmpty(); +} + +void BaseLayerAndroid::mergeInvalsInto(Layer* replacementTree) +{ + XLOG("merging invals (empty=%d) from BLA %p to %p", m_dirtyRegion.isEmpty(), this, replacementTree); + if (countChildren() && replacementTree->countChildren()) + getChild(0)->mergeInvalsInto(replacementTree->getChild(0)); - bool goingDown = m_glWebViewState->goingDown(); - bool goingLeft = m_glWebViewState->goingLeft(); + replacementTree->markAsDirty(m_dirtyRegion); +} + +bool BaseLayerAndroid::prepareBasePictureInGL(SkRect& viewport, float scale, + double currentTime) +{ + ZoomManager* zoomManager = m_state->zoomManager(); + + bool goingDown = m_state->goingDown(); + bool goingLeft = m_state->goingLeft(); - const SkIRect& viewportTileBounds = m_glWebViewState->viewportTileBounds(); + const SkIRect& viewportTileBounds = m_state->viewportTileBounds(); XLOG("drawBasePicture, TX: %d, TY: %d scale %.2f", viewportTileBounds.fLeft, viewportTileBounds.fTop, scale); @@ -172,15 +232,14 @@ bool BaseLayerAndroid::drawBasePictureInGL(SkRect& viewport, float scale, bool prepareNextTiledPage = zoomManager->needPrepareNextTiledPage(); // Display the current page - TiledPage* tiledPage = m_glWebViewState->frontPage(); - TiledPage* nextTiledPage = m_glWebViewState->backPage(); + TiledPage* tiledPage = m_state->frontPage(); + TiledPage* nextTiledPage = m_state->backPage(); tiledPage->setScale(zoomManager->currentScale()); // Let's prepare the page if needed so that it will start painting if (prepareNextTiledPage) { nextTiledPage->setScale(scale); - m_glWebViewState->setFutureViewport(viewportTileBounds); - m_glWebViewState->lockBaseLayerUpdate(); + m_state->setFutureViewport(viewportTileBounds); // ignore dirtiness return value since while zooming we repaint regardless nextTiledPage->updateTileDirtiness(viewportTileBounds); @@ -194,8 +253,7 @@ bool BaseLayerAndroid::drawBasePictureInGL(SkRect& viewport, float scale, // If we fired a request, let's check if it's ready to use if (zoomManager->didFireRequest()) { if (nextTiledPage->swapBuffersIfReady(viewportTileBounds, - zoomManager->futureScale(), - TiledPage::SwapWholePage)) + zoomManager->futureScale())) zoomManager->setReceivedRequest(); // transition to received request state } @@ -208,74 +266,31 @@ bool BaseLayerAndroid::drawBasePictureInGL(SkRect& viewport, float scale, float nextTiledPageTransparency = 1; zoomManager->processTransition(currentTime, scale, &doZoomPageSwap, &nextTiledPageTransparency, &transparency); - nextTiledPage->draw(nextTiledPageTransparency, viewportTileBounds); + nextTiledPage->prepareForDrawGL(nextTiledPageTransparency, viewportTileBounds); } - const SkIRect& preZoomBounds = m_glWebViewState->preZoomBounds(); + const SkIRect& preZoomBounds = m_state->preZoomBounds(); - // update scrolling state machine by querying glwebviewstate - note that the - // NotScrolling state is only set below - if (m_glWebViewState->isScrolling()) - m_scrollState = Scrolling; - else if (m_scrollState == Scrolling) - m_scrollState = ScrollingFinishPaint; - - bool scrolling = m_scrollState != NotScrolling; bool zooming = ZoomManager::kNoScaleRequest != zoomManager->scaleRequestState(); - // When we aren't zooming, we should TRY and swap tile buffers if they're - // ready. When scrolling, we swap whatever's ready. Otherwise, buffer until - // the entire page is ready and then swap. - bool tilesFinished = false; - if (!zooming) { - TiledPage::SwapMethod swapMethod; - if (scrolling) - swapMethod = TiledPage::SwapWhateverIsReady; - else - swapMethod = TiledPage::SwapWholePage; - - tilesFinished = tiledPage->swapBuffersIfReady(preZoomBounds, - zoomManager->currentScale(), - swapMethod); - - if (buffersSwappedPtr && tilesFinished) - *buffersSwappedPtr = true; - if (tilesFinished) { - if (m_scrollState == ScrollingFinishPaint) { - m_scrollState = NotScrolling; - scrolling = false; - } - } - } - if (doZoomPageSwap) { zoomManager->setCurrentScale(scale); - m_glWebViewState->swapPages(); - if (buffersSwappedPtr) - *buffersSwappedPtr = true; + m_state->swapPages(); } - - bool needsRedraw = scrolling || zooming || !tilesFinished; - - // if we don't expect to redraw, unlock the invals - if (!needsRedraw) - m_glWebViewState->unlockBaseLayerUpdate(); + bool needsRedraw = zooming; // if applied invals mark tiles dirty, need to redraw needsRedraw |= tiledPage->updateTileDirtiness(preZoomBounds); - if (needsRedraw) { - // lock and paint what's needed unless we're zooming, since the new - // tiles won't be relevant soon anyway - m_glWebViewState->lockBaseLayerUpdate(); - if (!zooming) - tiledPage->prepare(goingDown, goingLeft, preZoomBounds, - TiledPage::ExpandedBounds); - } + // paint what's needed unless we're zooming, since the new tiles won't + // be relevant soon anyway + if (!zooming) + tiledPage->prepare(goingDown, goingLeft, preZoomBounds, + TiledPage::ExpandedBounds); - XLOG("scrolling %d, zooming %d, tilesFinished %d, needsRedraw %d", - scrolling, zooming, tilesFinished, needsRedraw); + XLOG("scrolling %d, zooming %d, needsRedraw %d", + scrolling, zooming, needsRedraw); // prefetch in the nextTiledPage if unused by zooming (even if not scrolling // since we want the tiles to be ready before they're needed) @@ -288,39 +303,74 @@ bool BaseLayerAndroid::drawBasePictureInGL(SkRect& viewport, float scale, prefetchBasePicture(viewport, scale, nextTiledPage, drawPrefetchPage); } - tiledPage->draw(transparency, preZoomBounds); + tiledPage->prepareForDrawGL(transparency, preZoomBounds); return needsRedraw; } + +void BaseLayerAndroid::drawBasePictureInGL() +{ + m_state->backPage()->drawGL(); + m_state->frontPage()->drawGL(); +} + #endif // USE(ACCELERATED_COMPOSITING) -bool BaseLayerAndroid::drawGL(double currentTime, LayerAndroid* compositedRoot, - IntRect& viewRect, SkRect& visibleRect, float scale, - bool* buffersSwappedPtr) +void BaseLayerAndroid::updateLayerPositions(SkRect& visibleRect) { - bool needsRedraw = false; -#if USE(ACCELERATED_COMPOSITING) + LayerAndroid* compositedRoot = static_cast<LayerAndroid*>(getChild(0)); + TransformationMatrix ident; + compositedRoot->updateFixedLayersPositions(visibleRect); + FloatRect clip(0, 0, content()->width(), content()->height()); + compositedRoot->updateGLPositionsAndScale( + ident, clip, 1, m_state->zoomManager()->layersScale()); + +#ifdef DEBUG + compositedRoot->showLayer(0); + XLOG("We have %d layers, %d textured", + compositedRoot->nbLayers(), + compositedRoot->nbTexturedLayers()); +#endif +} - needsRedraw = drawBasePictureInGL(visibleRect, scale, currentTime, - buffersSwappedPtr); +bool BaseLayerAndroid::prepare(double currentTime, IntRect& viewRect, + SkRect& visibleRect, float scale) +{ + XLOG("preparing BLA %p", this); - if (!needsRedraw) - m_glWebViewState->resetFrameworkInval(); + // base layer is simply drawn in prepare, since there is always a base layer it doesn't matter + bool needsRedraw = prepareBasePictureInGL(visibleRect, scale, currentTime); + LayerAndroid* compositedRoot = static_cast<LayerAndroid*>(getChild(0)); if (compositedRoot) { - SkMatrix matrix; - matrix.setTranslate(viewRect.x(), viewRect.y()); + updateLayerPositions(visibleRect); -#ifdef DEBUG - compositedRoot->showLayer(0); - XLOG("We have %d layers, %d textured", - compositedRoot->nbLayers(), - compositedRoot->nbTexturedLayers()); -#endif + XLOG("preparing BLA %p, root %p", this, compositedRoot); + compositedRoot->prepare(); + } + + return needsRedraw; +} + +bool BaseLayerAndroid::drawGL(IntRect& viewRect, SkRect& visibleRect, + float scale) +{ + XLOG("drawing BLA %p", this); + + // TODO: consider moving drawBackground outside of prepare (into tree manager) + m_state->drawBackground(m_color); + drawBasePictureInGL(); + + bool needsRedraw = false; + +#if USE(ACCELERATED_COMPOSITING) + + LayerAndroid* compositedRoot = static_cast<LayerAndroid*>(getChild(0)); + if (compositedRoot) { + updateLayerPositions(visibleRect); // 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 (compositedRoot->drawGL()) { if (TilesManager::instance()->layerTexturesRemain()) { // only try redrawing for layers if layer textures remain, // otherwise we'll repaint without getting anything done @@ -329,8 +379,6 @@ bool BaseLayerAndroid::drawGL(double currentTime, LayerAndroid* compositedRoot, } } - m_previousVisible = visibleRect; - #endif // USE(ACCELERATED_COMPOSITING) #ifdef DEBUG ClassTracker::instance()->show(); diff --git a/Source/WebCore/platform/graphics/android/BaseLayerAndroid.h b/Source/WebCore/platform/graphics/android/BaseLayerAndroid.h index 20942ec..c5ce52f 100644 --- a/Source/WebCore/platform/graphics/android/BaseLayerAndroid.h +++ b/Source/WebCore/platform/graphics/android/BaseLayerAndroid.h @@ -48,7 +48,6 @@ public: virtual ~BaseLayerAndroid(); #if USE(ACCELERATED_COMPOSITING) - void setGLWebViewState(GLWebViewState* infos) { m_glWebViewState = infos; } void setBackgroundColor(Color& color) { m_color = color; } Color getBackgroundColor() { return m_color; } #endif @@ -60,21 +59,29 @@ public: // we are running in different threads. virtual bool drawCanvas(SkCanvas* canvas); - bool drawGL(double currentTime, LayerAndroid* compositedRoot, IntRect& rect, - SkRect& viewport, float scale, bool* buffersSwappedPtr); + void updateLayerPositions(SkRect& visibleRect); + bool prepare(double currentTime, IntRect& viewRect, + SkRect& visibleRect, float scale); + bool drawGL(IntRect& viewRect, SkRect& visibleRect, float scale); + + // rendering asset management + void swapTiles(); + void setIsDrawing(bool isDrawing); + void setIsPainting(Layer* drawingTree); + void mergeInvalsInto(Layer* replacementTree); + bool isReady(); + private: #if USE(ACCELERATED_COMPOSITING) void prefetchBasePicture(SkRect& viewport, float currentScale, TiledPage* prefetchTiledPage, bool draw); - bool drawBasePictureInGL(SkRect& viewport, float scale, double currentTime, - bool* buffersSwappedPtr); + bool prepareBasePictureInGL(SkRect& viewport, float scale, double currentTime); + void drawBasePictureInGL(); - GLWebViewState* m_glWebViewState; android::Mutex m_drawLock; Color m_color; #endif android::PictureSet m_content; - SkRect m_previousVisible; ScrollState m_scrollState; }; diff --git a/Source/WebCore/platform/graphics/android/BaseTile.cpp b/Source/WebCore/platform/graphics/android/BaseTile.cpp index a331dfc..27bd482 100644 --- a/Source/WebCore/platform/graphics/android/BaseTile.cpp +++ b/Source/WebCore/platform/graphics/android/BaseTile.cpp @@ -204,6 +204,7 @@ void BaseTile::markAsDirty(int unsigned pictureCount, } cliperator.next(); } + if (!intersect) return; @@ -268,7 +269,7 @@ void BaseTile::draw(float transparency, SkRect& rect, float scale) } if (m_frontTexture->readyFor(this)) { - if (isLayerTile()) + if (isLayerTile() && m_painter && m_painter->transform()) TilesManager::instance()->shader()->drawLayerQuad(*m_painter->transform(), rect, m_frontTexture->m_ownTextureId, transparency, true); diff --git a/Source/WebCore/platform/graphics/android/ClassTracker.cpp b/Source/WebCore/platform/graphics/android/ClassTracker.cpp index 92d406c..eb810a8 100644 --- a/Source/WebCore/platform/graphics/android/ClassTracker.cpp +++ b/Source/WebCore/platform/graphics/android/ClassTracker.cpp @@ -27,6 +27,7 @@ #include "ClassTracker.h" #include "LayerAndroid.h" +#include "TilesManager.h" #include <cutils/log.h> #include <wtf/CurrentTime.h> @@ -35,6 +36,9 @@ #undef XLOG #define XLOG(...) android_printLog(ANDROID_LOG_DEBUG, "ClassTracker", __VA_ARGS__) +#define DEBUG_LAYERS +#undef DEBUG_LAYERS + namespace WebCore { ClassTracker* ClassTracker::instance() @@ -66,7 +70,6 @@ void ClassTracker::decrement(String name) m_classes.set(name, value - 1); } - void ClassTracker::add(LayerAndroid* layer) { android::Mutex::Autolock lock(m_lock); @@ -88,6 +91,21 @@ void ClassTracker::show() iter->first.latin1().data(), iter->second); } XLOG("*** %d Layers ***", m_layers.size()); + int nbTextures = 0; + int nbAllocatedTextures = 0; + int nbLayerTextures = 0; + int nbAllocatedLayerTextures = 0; + float textureSize = 256 * 256 * 4 / 1024.0 / 1024.0; + TilesManager::instance()->gatherTexturesNumbers(&nbTextures, &nbAllocatedTextures, + &nbLayerTextures, &nbAllocatedLayerTextures); + XLOG("*** textures: %d/%d (%.2f Mb), layer textures: %d/%d (%.2f Mb) : total used %.2f Mb", + nbAllocatedTextures, nbTextures, + nbAllocatedTextures * textureSize, + nbAllocatedLayerTextures, nbLayerTextures, + nbAllocatedLayerTextures * textureSize, + (nbAllocatedTextures + nbAllocatedLayerTextures) * textureSize); + +#ifdef DEBUG_LAYERS for (unsigned int i = 0; i < m_layers.size(); i++) { LayerAndroid* layer = m_layers[i]; XLOG("[%d/%d] layer %x (%.2f, %.2f) of type %d, refcount(%d) has texture %x has image ref %x (%x) root: %x parent: %x", @@ -98,6 +116,7 @@ void ClassTracker::show() layer->imageTexture(), (LayerAndroid*) layer->getRootLayer(), (LayerAndroid*) layer->getParent()); } +#endif } } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/android/FontAndroid.cpp b/Source/WebCore/platform/graphics/android/FontAndroid.cpp index 81dbdae..0a8c0c1 100644 --- a/Source/WebCore/platform/graphics/android/FontAndroid.cpp +++ b/Source/WebCore/platform/graphics/android/FontAndroid.cpp @@ -98,6 +98,10 @@ static bool setupForText(SkPaint* paint, GraphicsContext* gc, SkLayerDrawLooper* looper = new SkLayerDrawLooper; paint->setLooper(looper)->unref(); + // The layerDrawLooper uses at the root paint to determine the text + // encoding so we need to make sure it is properly configured. + updateForFont(paint, font); + // Specify the behavior of the looper SkLayerDrawLooper::LayerInfo info; info.fPaintBits = SkLayerDrawLooper::kEntirePaint_Bits; diff --git a/Source/WebCore/platform/graphics/android/GLUtils.cpp b/Source/WebCore/platform/graphics/android/GLUtils.cpp index d1fe51a..97a53fe 100644 --- a/Source/WebCore/platform/graphics/android/GLUtils.cpp +++ b/Source/WebCore/platform/graphics/android/GLUtils.cpp @@ -562,6 +562,15 @@ void GLUtils::createTextureFromEGLImage(GLuint texture, EGLImageKHR image, GLint glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter); } +void GLUtils::convertToTransformationMatrix(const float* matrix, TransformationMatrix& transformMatrix) +{ + transformMatrix.setMatrix( + matrix[0], matrix[1], matrix[2], matrix[3], + matrix[4], matrix[5], matrix[6], matrix[7], + matrix[8], matrix[9], matrix[10], matrix[11], + matrix[12], matrix[13], matrix[14], matrix[15]); +} + } // namespace WebCore #endif // USE(ACCELERATED_COMPOSITING) diff --git a/Source/WebCore/platform/graphics/android/GLUtils.h b/Source/WebCore/platform/graphics/android/GLUtils.h index b952513..68acbab 100644 --- a/Source/WebCore/platform/graphics/android/GLUtils.h +++ b/Source/WebCore/platform/graphics/android/GLUtils.h @@ -83,6 +83,7 @@ public: static void updateSurfaceTextureWithBitmap(const TileRenderInfo* , int x, int y, const SkBitmap& bitmap, GLint filter = GL_LINEAR); #endif static void updateSharedSurfaceTextureWithBitmap(const TileRenderInfo* , int x, int y, const SkBitmap& bitmap); + static void convertToTransformationMatrix(const float* matrix, TransformationMatrix& transformMatrix); }; } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/android/GLWebViewState.cpp b/Source/WebCore/platform/graphics/android/GLWebViewState.cpp index fa22593..273c478 100644 --- a/Source/WebCore/platform/graphics/android/GLWebViewState.cpp +++ b/Source/WebCore/platform/graphics/android/GLWebViewState.cpp @@ -37,6 +37,7 @@ #include "SkPath.h" #include "TilesManager.h" #include "TilesTracker.h" +#include "TreeManager.h" #include <wtf/CurrentTime.h> #include <pthread.h> @@ -74,20 +75,16 @@ using namespace android; GLWebViewState::GLWebViewState() : m_zoomManager(this) - , m_paintingBaseLayer(0) - , m_currentBaseLayer(0) - , m_currentBaseLayerRoot(0) , m_currentPictureCounter(0) , m_usePageA(true) , m_frameworkInval(0, 0, 0, 0) , m_frameworkLayersInval(0, 0, 0, 0) - , m_baseLayerUpdate(true) - , m_backgroundColor(SK_ColorWHITE) , m_isScrolling(false) , m_goingDown(true) , m_goingLeft(false) , m_expandedTileBoundsX(0) , m_expandedTileBoundsY(0) + , m_highEndGfx(false) , m_scale(1) , m_layersRenderingMode(kAllTextures) { @@ -111,10 +108,6 @@ GLWebViewState::GLWebViewState() GLWebViewState::~GLWebViewState() { - // Unref the existing tree/PaintedSurfaces - if (m_currentBaseLayerRoot) - TilesManager::instance()->swapLayersTextures(m_currentBaseLayerRoot, 0); - // Take care of the transfer queue such that Tex Gen thread will not stuck TilesManager::instance()->unregisterGLWebViewState(this); @@ -126,12 +119,6 @@ GLWebViewState::~GLWebViewState() // will remove any pending operations, and wait if one is underway). delete m_tiledPageA; delete m_tiledPageB; - SkSafeUnref(m_paintingBaseLayer); - SkSafeUnref(m_currentBaseLayer); - SkSafeUnref(m_currentBaseLayerRoot); - m_paintingBaseLayer = 0; - m_currentBaseLayer = 0; - m_currentBaseLayerRoot = 0; #ifdef DEBUG_COUNT ClassTracker::instance()->decrement("GLWebViewState"); #endif @@ -141,49 +128,19 @@ GLWebViewState::~GLWebViewState() void GLWebViewState::setBaseLayer(BaseLayerAndroid* layer, const SkRegion& inval, bool showVisualIndicator, bool isPictureAfterFirstLayout) { - android::Mutex::Autolock lock(m_baseLayerLock); if (!layer || isPictureAfterFirstLayout) { + // TODO: move this into TreeManager m_tiledPageA->discardTextures(); m_tiledPageB->discardTextures(); } - if (isPictureAfterFirstLayout) { - m_baseLayerUpdate = true; - m_invalidateRegion.setEmpty(); - } - - SkSafeRef(layer); - SkSafeUnref(m_currentBaseLayer); - m_currentBaseLayer = layer; - - // copy content from old composited root to new - LayerAndroid* oldRoot = m_currentBaseLayerRoot; if (layer) { - layer->setGLWebViewState(this); - m_currentBaseLayerRoot = static_cast<LayerAndroid*>(layer->getChild(0)); - SkSafeRef(m_currentBaseLayerRoot); - } else { - m_currentBaseLayerRoot = 0; - } - if (oldRoot != m_currentBaseLayerRoot) - TilesManager::instance()->swapLayersTextures(oldRoot, m_currentBaseLayerRoot); - SkSafeUnref(oldRoot); - - // We only update the base layer if we are not currently - // waiting for a tiledPage to be painted - if (m_baseLayerUpdate) { - SkSafeRef(layer); - SkSafeUnref(m_paintingBaseLayer); - m_paintingBaseLayer = layer; + XLOG("new base layer %p, (inval region empty %d) with child %p", layer, inval.isEmpty(), layer->getChild(0)); + layer->setState(this); + layer->markAsDirty(inval); // TODO: set in webview.cpp } + m_treeManager.updateWithTree(layer, isPictureAfterFirstLayout); m_glExtras.setDrawExtra(0); - // 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) dumpMeasures(); @@ -193,8 +150,10 @@ void GLWebViewState::setBaseLayer(BaseLayerAndroid* layer, const SkRegion& inval TilesManager::instance()->setShowVisualIndicator(showVisualIndicator); } -void GLWebViewState::scrolledLayer(ScrollableLayerAndroid*) +void GLWebViewState::scrollLayer(int layerId, int x, int y) { + m_treeManager.updateScrollableLayer(layerId, x, y); + // TODO: only inval the area of the scrolled layer instead of // doing a fullInval() if (m_layersRenderingMode == kSingleSurfaceRendering) @@ -203,6 +162,12 @@ void GLWebViewState::scrolledLayer(ScrollableLayerAndroid*) void GLWebViewState::invalRegion(const SkRegion& region) { + if (m_layersRenderingMode == kSingleSurfaceRendering) { + // TODO: do the union of both layers tree to compute + //the minimum inval instead of doing a fullInval() + fullInval(); + return; + } SkRegion::Iterator iterator(region); while (!iterator.done()) { SkIRect r = iterator.rect(); @@ -212,59 +177,27 @@ void GLWebViewState::invalRegion(const SkRegion& region) } } -void GLWebViewState::unlockBaseLayerUpdate() { - if (m_baseLayerUpdate) - return; - - m_baseLayerUpdate = true; - android::Mutex::Autolock lock(m_baseLayerLock); - SkSafeRef(m_currentBaseLayer); - SkSafeUnref(m_paintingBaseLayer); - m_paintingBaseLayer = m_currentBaseLayer; - - invalRegion(m_invalidateRegion); - m_invalidateRegion.setEmpty(); -} - void GLWebViewState::inval(const IntRect& rect) { - if (m_baseLayerUpdate) { - // base layer isn't locked, so go ahead and issue the inval to both tiled pages - m_currentPictureCounter++; - if (!rect.isEmpty()) { - // find which tiles fall within the invalRect and mark them as dirty - m_tiledPageA->invalidateRect(rect, m_currentPictureCounter); - m_tiledPageB->invalidateRect(rect, m_currentPictureCounter); - if (m_frameworkInval.isEmpty()) - m_frameworkInval = rect; - else - m_frameworkInval.unite(rect); - XLOG("intermediate invalRect(%d, %d, %d, %d) after unite with rect %d %d %d %d", m_frameworkInval.x(), - m_frameworkInval.y(), m_frameworkInval.width(), m_frameworkInval.height(), - rect.x(), rect.y(), rect.width(), rect.height()); - } - } else { - // base layer is locked, so defer invalidation until unlockBaseLayerUpdate() - m_invalidateRegion.op(rect.x(), rect.y(), rect.maxX(), rect.maxY(), SkRegion::kUnion_Op); + m_currentPictureCounter++; + if (!rect.isEmpty()) { + // find which tiles fall within the invalRect and mark them as dirty + m_tiledPageA->invalidateRect(rect, m_currentPictureCounter); + m_tiledPageB->invalidateRect(rect, m_currentPictureCounter); + if (m_frameworkInval.isEmpty()) + m_frameworkInval = rect; + else + m_frameworkInval.unite(rect); + XLOG("intermediate invalRect(%d, %d, %d, %d) after unite with rect %d %d %d %d", m_frameworkInval.x(), + m_frameworkInval.y(), m_frameworkInval.width(), m_frameworkInval.height(), + rect.x(), rect.y(), rect.width(), rect.height()); } TilesManager::instance()->getProfiler()->nextInval(rect, zoomManager()->currentScale()); } unsigned int GLWebViewState::paintBaseLayerContent(SkCanvas* canvas) { - m_baseLayerLock.lock(); - BaseLayerAndroid* base = m_paintingBaseLayer; - SkSafeRef(base); - 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); + m_treeManager.drawCanvas(canvas, m_layersRenderingMode == kSingleSurfaceRendering); return m_currentPictureCounter; } @@ -296,11 +229,11 @@ void GLWebViewState::swapPages() int GLWebViewState::baseContentWidth() { - return m_paintingBaseLayer ? m_paintingBaseLayer->content()->width() : 0; + return m_treeManager.baseContentWidth(); } int GLWebViewState::baseContentHeight() { - return m_paintingBaseLayer ? m_paintingBaseLayer->content()->height() : 0; + return m_treeManager.baseContentHeight(); } void GLWebViewState::setViewport(SkRect& viewport, float scale) @@ -332,7 +265,7 @@ void GLWebViewState::setViewport(SkRect& viewport, float scale) int viewMaxTileY = static_cast<int>(ceilf((viewport.height()-1) * invTileContentHeight)) + 1; int maxTextureCount = (viewMaxTileX + m_expandedTileBoundsX * 2) * - (viewMaxTileY + m_expandedTileBoundsY * 2) * 2; + (viewMaxTileY + m_expandedTileBoundsY * 2) * (m_highEndGfx ? 4 : 2); TilesManager::instance()->setMaxTextureCount(maxTextureCount); m_tiledPageA->updateBaseTileSize(); @@ -381,41 +314,48 @@ void GLWebViewState::resetLayersDirtyArea() m_frameworkLayersInval.setHeight(0); } -double GLWebViewState::setupDrawing(IntRect& viewRect, SkRect& visibleRect, - IntRect& webViewRect, int titleBarHeight, - IntRect& screenClip, float scale) +void GLWebViewState::drawBackground(Color& backgroundColor) { - int left = viewRect.x(); - int top = viewRect.y(); - int width = viewRect.width(); - int height = viewRect.height(); - if (TilesManager::instance()->invertedScreen()) { - float color = 1.0 - ((((float) m_backgroundColor.red() / 255.0) + - ((float) m_backgroundColor.green() / 255.0) + - ((float) m_backgroundColor.blue() / 255.0)) / 3.0); + float color = 1.0 - ((((float) backgroundColor.red() / 255.0) + + ((float) backgroundColor.green() / 255.0) + + ((float) backgroundColor.blue() / 255.0)) / 3.0); glClearColor(color, color, color, 1); } else { - glClearColor((float)m_backgroundColor.red() / 255.0, - (float)m_backgroundColor.green() / 255.0, - (float)m_backgroundColor.blue() / 255.0, 1); + glClearColor((float)backgroundColor.red() / 255.0, + (float)backgroundColor.green() / 255.0, + (float)backgroundColor.blue() / 255.0, 1); } glClear(GL_COLOR_BUFFER_BIT); +} - glViewport(left, top, width, height); +double GLWebViewState::setupDrawing(IntRect& viewRect, SkRect& visibleRect, + IntRect& webViewRect, int titleBarHeight, + IntRect& screenClip, float scale) +{ + int left = viewRect.x(); + int top = viewRect.y(); + int width = viewRect.width(); + int height = viewRect.height(); ShaderProgram* shader = TilesManager::instance()->shader(); if (shader->program() == -1) { XLOG("Reinit shader"); shader->init(); } + shader->setViewport(visibleRect, scale); shader->setViewRect(viewRect); - shader->setViewport(visibleRect); shader->setWebViewRect(webViewRect); shader->setTitleBarHeight(titleBarHeight); shader->setScreenClip(screenClip); shader->resetBlending(); + shader->calculateAnimationDelta(); + + glViewport(left + shader->getAnimationDeltaX(), + top - shader->getAnimationDeltaY(), + width, height); + double currentTime = WTF::currentTime(); setViewport(visibleRect, scale); @@ -427,7 +367,13 @@ double GLWebViewState::setupDrawing(IntRect& viewRect, SkRect& visibleRect, bool GLWebViewState::setLayersRenderingMode(TexturesResult& nbTexturesNeeded) { bool invalBase = false; - int maxTextures = TilesManager::instance()->maxTextureCount(); + + if (!nbTexturesNeeded.full) + TilesManager::instance()->setMaxLayerTextureCount(0); + else + TilesManager::instance()->setMaxLayerTextureCount((2*nbTexturesNeeded.full)+1); + + int maxTextures = TilesManager::instance()->maxLayerTextureCount(); LayersRenderingMode layersRenderingMode = m_layersRenderingMode; m_layersRenderingMode = kSingleSurfaceRendering; @@ -440,6 +386,9 @@ bool GLWebViewState::setLayersRenderingMode(TexturesResult& nbTexturesNeeded) if (nbTexturesNeeded.full < maxTextures) m_layersRenderingMode = kAllTextures; + if (!maxTextures && !nbTexturesNeeded.full) + m_layersRenderingMode = kAllTextures; + if (m_layersRenderingMode < layersRenderingMode && m_layersRenderingMode != kAllTextures) invalBase = true; @@ -489,7 +438,8 @@ void GLWebViewState::fullInval() bool GLWebViewState::drawGL(IntRect& rect, SkRect& viewport, IntRect* invalRect, IntRect& webViewRect, int titleBarHeight, - IntRect& clip, float scale, bool* buffersSwappedPtr) + IntRect& clip, float scale, + bool* treesSwappedPtr, bool* newTreeHasAnimPtr) { m_scale = scale; TilesManager::instance()->getProfiler()->nextFrame(viewport.fLeft, @@ -503,13 +453,6 @@ bool GLWebViewState::drawGL(IntRect& rect, SkRect& viewport, IntRect* invalRect, TilesManager::instance()->getTilesTracker()->clear(); #endif - m_baseLayerLock.lock(); - BaseLayerAndroid* baseLayer = m_paintingBaseLayer; - SkSafeRef(baseLayer); - m_baseLayerLock.unlock(); - if (!baseLayer) - return false; - float viewWidth = (viewport.fRight - viewport.fLeft) * TILE_PREFETCH_RATIO; float viewHeight = (viewport.fBottom - viewport.fTop) * TILE_PREFETCH_RATIO; bool useMinimalMemory = TilesManager::instance()->useMinimalMemory(); @@ -524,17 +467,8 @@ bool GLWebViewState::drawGL(IntRect& rect, SkRect& viewport, IntRect* invalRect, resetLayersDirtyArea(); - LayerAndroid* compositedRoot = m_currentBaseLayerRoot; - LayerAndroid* paintingBaseLayerRoot = 0; - if (baseLayer && baseLayer->countChildren() >= 1) - paintingBaseLayerRoot = static_cast<LayerAndroid*>(baseLayer->getChild(0)); - // when adding or removing layers, use the the paintingBaseLayer's tree so // that content that moves to the base layer from a layer is synchronized - bool paintingHasLayers = (paintingBaseLayerRoot == 0); - bool currentHasLayers = (m_currentBaseLayerRoot == 0); - if (paintingHasLayers != currentHasLayers) - compositedRoot = paintingBaseLayerRoot; if (scale < MIN_SCALE_WARNING || scale > MAX_SCALE_WARNING) XLOGC("WARNING, scale seems corrupted before update: %e", scale); @@ -547,7 +481,7 @@ bool GLWebViewState::drawGL(IntRect& rect, SkRect& viewport, IntRect* invalRect, // Upload any pending ImageTexture // Return true if we still have some images to upload. // TODO: upload as many textures as possible within a certain time limit - bool ret = ImagesManager::instance()->uploadTextures(); + bool ret = ImagesManager::instance()->prepareTextures(this); if (scale < MIN_SCALE_WARNING || scale > MAX_SCALE_WARNING) XLOGC("WARNING, scale seems corrupted after update: %e", scale); @@ -555,45 +489,27 @@ bool GLWebViewState::drawGL(IntRect& rect, SkRect& viewport, IntRect* invalRect, // gather the textures we can use TilesManager::instance()->gatherLayerTextures(); - // 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; + bool fastSwap = isScrolling() || m_layersRenderingMode == kSingleSurfaceRendering; + ret |= m_treeManager.drawGL(currentTime, rect, viewport, + scale, fastSwap, + treesSwappedPtr, newTreeHasAnimPtr, + &nbTexturesNeeded); + if (!ret) + resetFrameworkInval(); - compositedRoot->computeTexturesAmount(&nbTexturesNeeded); - } + int nbTexturesForImages = ImagesManager::instance()->nbTextures(); + XLOG("*** We have %d textures for images, %d full, %d clipped, total %d / %d", + nbTexturesForImages, nbTexturesNeeded.full, nbTexturesNeeded.clipped, + nbTexturesNeeded.full + nbTexturesForImages, + nbTexturesNeeded.clipped + nbTexturesForImages); + nbTexturesNeeded.full += nbTexturesForImages; + nbTexturesNeeded.clipped += nbTexturesForImages; 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); @@ -601,6 +517,8 @@ bool GLWebViewState::drawGL(IntRect& rect, SkRect& viewport, IntRect* invalRect, glBindBuffer(GL_ARRAY_BUFFER, 0); + // Clean up GL textures for video layer. + TilesManager::instance()->videoLayerManager()->deleteUnusedTextures(); ret |= TilesManager::instance()->invertedScreenSwitch(); if (ret) { @@ -656,7 +574,6 @@ bool GLWebViewState::drawGL(IntRect& rect, SkRect& viewport, IntRect* invalRect, } #endif - SkSafeUnref(baseLayer); #ifdef DEBUG TilesManager::instance()->getTilesTracker()->showTrackTextures(); ImagesManager::instance()->showImages(); diff --git a/Source/WebCore/platform/graphics/android/GLWebViewState.h b/Source/WebCore/platform/graphics/android/GLWebViewState.h index a1adaf1..8d89704 100644 --- a/Source/WebCore/platform/graphics/android/GLWebViewState.h +++ b/Source/WebCore/platform/graphics/android/GLWebViewState.h @@ -36,6 +36,7 @@ #include "SkRect.h" #include "SkRegion.h" #include "TiledPage.h" +#include "TreeManager.h" #include "ZoomManager.h" #include <utils/threads.h> @@ -200,22 +201,21 @@ public: unsigned int currentPictureCounter() const { return m_currentPictureCounter; } - void lockBaseLayerUpdate() { m_baseLayerUpdate = false; } - void unlockBaseLayerUpdate(); - void setIsScrolling(bool isScrolling) { m_isScrolling = isScrolling; } bool isScrolling() { return m_isScrolling; } - double setupDrawing(IntRect& rect, SkRect& viewport, IntRect& webViewRect, - int titleBarHeight, IntRect& screenClip, - float scale); + void drawBackground(Color& backgroundColor); + double setupDrawing(IntRect& viewRect, SkRect& visibleRect, + IntRect& webViewRect, 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); + IntRect& clip, float scale, + bool* treesSwappedPtr, bool* newTreeHasAnimPtr); #ifdef MEASURES_PERF void dumpMeasures(); @@ -234,6 +234,7 @@ public: int expandedTileBoundsX() { return m_expandedTileBoundsX; } int expandedTileBoundsY() { return m_expandedTileBoundsY; } + void setHighEndGfx(bool highEnd) { m_highEndGfx = highEnd; } float scale() { return m_scale; } @@ -247,22 +248,19 @@ public: }; LayersRenderingMode layersRenderingMode() { return m_layersRenderingMode; } - void scrolledLayer(ScrollableLayerAndroid*); + void scrollLayer(int layerId, int x, int y); -private: - void inval(const IntRect& rect); // caller must hold m_baseLayerLock void invalRegion(const SkRegion& region); +private: + void inval(const IntRect& rect); + ZoomManager m_zoomManager; android::Mutex m_tiledPageLock; SkRect m_viewport; SkIRect m_viewportTileBounds; SkIRect m_futureViewportTileBounds; SkIRect m_preZoomBounds; - android::Mutex m_baseLayerLock; - BaseLayerAndroid* m_paintingBaseLayer; - BaseLayerAndroid* m_currentBaseLayer; - LayerAndroid* m_currentBaseLayerRoot; unsigned int m_currentPictureCounter; bool m_usePageA; @@ -272,11 +270,6 @@ private: IntRect m_frameworkInval; IntRect m_frameworkLayersInval; - bool m_baseLayerUpdate; - SkRegion m_invalidateRegion; - - Color m_backgroundColor; - #ifdef MEASURES_PERF unsigned int m_totalTimeCounter; int m_timeCounter; @@ -291,10 +284,12 @@ private: int m_expandedTileBoundsX; int m_expandedTileBoundsY; + bool m_highEndGfx; float m_scale; LayersRenderingMode m_layersRenderingMode; + TreeManager m_treeManager; }; } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/android/GraphicsContextAndroid.cpp b/Source/WebCore/platform/graphics/android/GraphicsContextAndroid.cpp index f647673..a490d5f 100644 --- a/Source/WebCore/platform/graphics/android/GraphicsContextAndroid.cpp +++ b/Source/WebCore/platform/graphics/android/GraphicsContextAndroid.cpp @@ -1207,10 +1207,11 @@ AffineTransform GraphicsContext::getCTM() const void GraphicsContext::setCTM(const AffineTransform& transform) { - if (paintingDisabled()) - return; - - GC2CANVAS(this)->setMatrix(transform); + // The SkPicture mode of Skia does not support SkCanvas::setMatrix(), so we + // can not simply use that method here. We could calculate the transform + // required to achieve the desired matrix and use SkCanvas::concat(), but + // there's currently no need for this. + ASSERT_NOT_REACHED(); } /////////////////////////////////////////////////////////////////////////////// diff --git a/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp b/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp index 3e062f8..6990503 100644 --- a/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp +++ b/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp @@ -119,8 +119,8 @@ GraphicsLayerAndroid::GraphicsLayerAndroid(GraphicsLayerClient* client) : m_needsRepaint(false), m_needsNotifyClient(false), m_haveContents(false), - m_haveImage(false), m_newImage(false), + m_image(0), m_foregroundLayer(0), m_foregroundClipLayer(0) { @@ -132,6 +132,9 @@ GraphicsLayerAndroid::GraphicsLayerAndroid(GraphicsLayerClient* client) : GraphicsLayerAndroid::~GraphicsLayerAndroid() { + if (m_image) + m_image->deref(); + m_contentLayer->unref(); SkSafeUnref(m_foregroundLayer); SkSafeUnref(m_foregroundClipLayer); @@ -331,6 +334,9 @@ void GraphicsLayerAndroid::setSize(const FloatSize& size) void GraphicsLayerAndroid::setBackfaceVisibility(bool b) { + if (b == m_backfaceVisibility) + return; + GraphicsLayer::setBackfaceVisibility(b); m_contentLayer->setBackfaceVisibility(b); askForSync(); @@ -397,7 +403,7 @@ void GraphicsLayerAndroid::setDrawsContent(bool drawsContent) void GraphicsLayerAndroid::setBackgroundColor(const Color& color) { - if (color == m_backgroundColor) + if (color == m_backgroundColor && m_backgroundColorSet) return; LOG("(%x) setBackgroundColor", this); GraphicsLayer::setBackgroundColor(color); @@ -409,6 +415,9 @@ void GraphicsLayerAndroid::setBackgroundColor(const Color& color) void GraphicsLayerAndroid::clearBackgroundColor() { + if (!m_backgroundColorSet) + return; + LOG("(%x) clearBackgroundColor", this); GraphicsLayer::clearBackgroundColor(); askForSync(); @@ -551,7 +560,7 @@ bool GraphicsLayerAndroid::repaint() LOG("(%x) repaint(), gPaused(%d) m_needsRepaint(%d) m_haveContents(%d) ", this, gPaused, m_needsRepaint, m_haveContents); - if (!gPaused && m_haveContents && m_needsRepaint && !m_haveImage) { + if (!gPaused && m_haveContents && m_needsRepaint && !m_image) { // with SkPicture, we request the entire layer's content. IntRect layerBounds(0, 0, m_size.width(), m_size.height()); @@ -602,7 +611,14 @@ bool GraphicsLayerAndroid::repaint() m_foregroundLayer->setPosition(-x, -y); // Set the scrollable bounds of the layer. m_foregroundLayer->setScrollLimits(-x, -y, m_size.width(), m_size.height()); - m_foregroundLayer->markAsDirty(m_dirtyRegion); + + // Invalidate the entire layer for now, as webkit will only send the + // setNeedsDisplayInRect() for the visible (clipped) scrollable area, + // offsetting the invals by the scroll position would not be enough. + // TODO: have webkit send us invals even for non visible area + SkRegion region; + region.setRect(0, 0, contentsRect.width(), contentsRect.height()); + m_foregroundLayer->markAsDirty(region); m_foregroundLayer->needsRepaint(); } else { // If there is no contents clip, we can draw everything into one @@ -633,7 +649,7 @@ bool GraphicsLayerAndroid::repaint() return true; } - if (m_needsRepaint && m_haveImage && m_newImage) { + if (m_needsRepaint && m_image && m_newImage) { // We need to tell the GL thread that we will need to repaint the // texture. Only do so if we effectively have a new image! m_contentLayer->markAsDirty(m_dirtyRegion); @@ -666,7 +682,7 @@ void GraphicsLayerAndroid::setNeedsDisplayInRect(const FloatRect& rect) { // rect is in the render object coordinates - if (!m_haveImage && !drawsContent()) { + if (!m_image && !drawsContent()) { LOG("(%x) setNeedsDisplay(%.2f,%.2f,%.2f,%.2f) doesn't have content, bypass...", this, rect.x(), rect.y(), rect.width(), rect.height()); return; @@ -830,14 +846,23 @@ void GraphicsLayerAndroid::resumeAnimations() void GraphicsLayerAndroid::setContentsToImage(Image* image) { TLOG("(%x) setContentsToImage", this, image); - if (image) { + if (image && image != m_image) { + image->ref(); + if (m_image) + m_image->deref(); + m_image = image; + + SkBitmapRef* bitmap = image->nativeImageForCurrentFrame(); + m_contentLayer->setContentsImage(bitmap); + m_haveContents = true; - m_haveImage = true; m_newImage = true; - m_contentLayer->setContentsImage(image->nativeImageForCurrentFrame()); } - if (m_haveImage && !image) + if (!image && m_image) { m_contentLayer->setContentsImage(0); + m_image->deref(); + m_image = 0; + } setNeedsDisplay(); askForSync(); diff --git a/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.h b/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.h index af8d7ce..358f674 100644 --- a/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.h +++ b/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.h @@ -145,8 +145,8 @@ private: bool m_needsNotifyClient; bool m_haveContents; - bool m_haveImage; bool m_newImage; + Image* m_image; SkRegion m_dirtyRegion; diff --git a/Source/WebCore/platform/graphics/android/ImageTexture.cpp b/Source/WebCore/platform/graphics/android/ImageTexture.cpp index 96f7713..23e3899 100644 --- a/Source/WebCore/platform/graphics/android/ImageTexture.cpp +++ b/Source/WebCore/platform/graphics/android/ImageTexture.cpp @@ -27,8 +27,11 @@ #include "ImageTexture.h" #include "ImagesManager.h" +#include "LayerAndroid.h" #include "SkDevice.h" +#include "SkPicture.h" #include "TilesManager.h" +#include "TiledTexture.h" #include <cutils/log.h> #include <wtf/CurrentTime.h> @@ -51,96 +54,201 @@ namespace WebCore { -ImageTexture::ImageTexture(SkBitmapRef* img) - : m_imageRef(img) - , m_image(0) - , m_textureId(0) - , m_refCount(0) +// CRC computation adapted from Tools/DumpRenderTree/CyclicRedundancyCheck.cpp +static void makeCrcTable(unsigned crcTable[256]) +{ + for (unsigned i = 0; i < 256; i++) { + unsigned c = i; + for (int k = 0; k < 8; k++) { + if (c & 1) + c = -306674912 ^ ((c >> 1) & 0x7fffffff); + else + c = c >> 1; + } + crcTable[i] = c; + } +} + +unsigned computeCrc(uint8_t* buffer, size_t size) +{ + static unsigned crcTable[256]; + static bool crcTableComputed = false; + if (!crcTableComputed) { + makeCrcTable(crcTable); + crcTableComputed = true; + } + + unsigned crc = 0xffffffffL; + for (size_t i = 0; i < size; ++i) + crc = crcTable[(crc ^ buffer[i]) & 0xff] ^ ((crc >> 8) & 0x00ffffffL); + return crc ^ 0xffffffffL; +} + +ImageTexture::ImageTexture(SkBitmap* bmp, unsigned crc) + : m_image(bmp) + , m_texture(0) + , m_layer(0) + , m_picture(0) + , m_crc(crc) { #ifdef DEBUG_COUNT ClassTracker::instance()->increment("ImageTexture"); #endif - if (!m_imageRef) + if (!m_image) return; - SkBitmap* bitmap = &m_imageRef->bitmap(); - m_image = new SkBitmap(); + // NOTE: This constructor is called on the webcore thread + + // Create a picture containing the image (needed for TiledTexture) + m_picture = new SkPicture(); + SkCanvas* pcanvas = m_picture->beginRecording(m_image->width(), m_image->height()); + pcanvas->clear(SkColorSetARGBInline(0, 0, 0, 0)); + pcanvas->drawBitmap(*m_image, 0, 0); + m_picture->endRecording(); +} + +ImageTexture::~ImageTexture() +{ +#ifdef DEBUG_COUNT + ClassTracker::instance()->decrement("ImageTexture"); +#endif + delete m_image; + delete m_texture; + SkSafeUnref(m_picture); +} + +SkBitmap* ImageTexture::convertBitmap(SkBitmap* bitmap) +{ + SkBitmap* img = new SkBitmap(); int w = bitmap->width(); int h = bitmap->height(); - m_image->setConfig(SkBitmap::kARGB_8888_Config, w, h); - m_image->allocPixels(); - SkDevice* device = new SkDevice(NULL, *m_image, false); + + // Create a copy of the image + img->setConfig(SkBitmap::kARGB_8888_Config, w, h); + img->allocPixels(); + SkDevice* device = new SkDevice(NULL, *img, false); SkCanvas canvas; canvas.setDevice(device); device->unref(); SkRect dest; dest.set(0, 0, w, h); - m_image->setIsOpaque(false); - m_image->eraseARGB(0, 0, 0, 0); + img->setIsOpaque(false); + img->eraseARGB(0, 0, 0, 0); canvas.drawBitmapRect(*bitmap, 0, dest); + + return img; } -ImageTexture::~ImageTexture() +unsigned ImageTexture::computeCRC(const SkBitmap* bitmap) { -#ifdef DEBUG_COUNT - ClassTracker::instance()->decrement("ImageTexture"); -#endif - delete m_image; + if (!bitmap) + return 0; + bitmap->lockPixels(); + uint8_t* img = static_cast<uint8_t*>(bitmap->getPixels()); + unsigned crc = computeCrc(img, bitmap->getSize()); + bitmap->unlockPixels(); + return crc; } -void ImageTexture::prepareGL() +bool ImageTexture::equalsCRC(unsigned crc) { - if (m_textureId) - return; - - ImagesManager::instance()->scheduleTextureUpload(this); + return m_crc == crc; } -void ImageTexture::uploadGLTexture() +int ImageTexture::nbTextures() { - if (m_textureId) - return; - - glGenTextures(1, &m_textureId); - GLUtils::createTextureWithBitmap(m_textureId, *m_image); + if (!hasContentToShow()) + return 0; + if (!m_texture) + return 0; + + // 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_texture->nbTextures(visibleArea, 1.0); + XLOG("ImageTexture %p, %d x %d needs %d textures", + this, m_image->width(), m_image->height(), + nbTextures); + return nbTextures; } -void ImageTexture::drawGL(LayerAndroid* layer) +bool ImageTexture::hasContentToShow() { - if (!layer) - return; - if (!m_textureId) - return; + // Don't display 1x1 image -- no need to allocate a full texture for this if (!m_image) - return; + return false; + if (m_image->width() == 1 && m_image->height() == 1) + return false; + return true; +} - SkRect rect; - rect.fLeft = 0; - rect.fTop = 0; - rect.fRight = layer->getSize().width(); - rect.fBottom = layer->getSize().height(); - TilesManager::instance()->shader()->drawLayerQuad(*layer->drawTransform(), - rect, m_textureId, - layer->drawOpacity(), true); +bool ImageTexture::prepareGL(GLWebViewState* state) +{ + if (!hasContentToShow()) + return false; + + if (!m_texture && m_picture) { + m_texture = new TiledTexture(this); + SkRegion region; + region.setRect(0, 0, m_image->width(), m_image->height()); + m_texture->update(region, m_picture); + } + + if (!m_texture) + return false; + + IntRect visibleArea(0, 0, m_image->width(), m_image->height()); + m_texture->prepare(state, 1.0, true, true, visibleArea); + if (m_texture->ready()) { + m_texture->swapTiles(); + return false; + } + return true; } -void ImageTexture::drawCanvas(SkCanvas* canvas, SkRect& rect) +const TransformationMatrix* ImageTexture::transform() { - canvas->drawBitmapRect(*m_image, 0, rect); + if (!m_layer) + return 0; + + FloatPoint p(0, 0); + p = m_layer->drawTransform()->mapPoint(p); + IntRect layerArea = m_layer->unclippedArea(); + 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()); + TransformationMatrix m; + m.scaleNonUniform(scaleW, scaleH); + m_layerMatrix = d.multiply(m); + return &m_layerMatrix; } -void ImageTexture::release() +float ImageTexture::opacity() { - if (m_refCount >= 1) - m_refCount--; - if (!m_refCount) - deleteTexture(); + if (!m_layer) + return 1.0; + return m_layer->drawOpacity(); } -void ImageTexture::deleteTexture() +void ImageTexture::drawGL(LayerAndroid* layer) +{ + if (!layer) + return; + if (!hasContentToShow()) + return; + + // TiledTexture::draw() will call us back to know the + // transform and opacity, so we need to set m_layer + m_layer = layer; + if (m_texture) + m_texture->draw(); + m_layer = 0; +} + +void ImageTexture::drawCanvas(SkCanvas* canvas, SkRect& rect) { - if (m_textureId) - glDeleteTextures(1, &m_textureId); + if (canvas && m_image) + canvas->drawBitmapRect(*m_image, 0, rect); } } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/android/ImageTexture.h b/Source/WebCore/platform/graphics/android/ImageTexture.h index 7f35f06..6c6a075 100644 --- a/Source/WebCore/platform/graphics/android/ImageTexture.h +++ b/Source/WebCore/platform/graphics/android/ImageTexture.h @@ -26,61 +26,81 @@ #ifndef ImageTexture_h #define ImageTexture_h -#include "ClassTracker.h" #include "GLUtils.h" #include "SkBitmap.h" #include "SkBitmapRef.h" +#include "SkPicture.h" #include "SkRefCnt.h" #include "LayerAndroid.h" namespace WebCore { class LayerAndroid; +class TexturesResult; +class TiledTexture; ///////////////////////////////////////////////////////////////////////////////// // Image sharing codepath for layers ///////////////////////////////////////////////////////////////////////////////// // -// We receive an SkBitmapRef on the webcore thread; from this we create -// an ImageTexture instance and keep it in TilesManager in a hashmap -// (see TilesManager::addImage()) +// Layers containing only an image take a slightly different codepath; +// GraphicsLayer::setContentsToImage() is called on the webcore thread, +// passing an Image instance. We get the native image (an SkBitmap) and create +// an ImageTexture instance with it (or increment the refcount of an existing +// instance if the SkBitmap is similar to one already stored in ImagesManager, +// i.e. if two GraphicsLayer share the same image). // -// The ImageTexture will recopy the pointed SkBitmap locally (so we can safely -// use it on the texture generation thread), and just use the SkBitmapRef as a -// key. +// To detect if an image is similar, we compute and use a CRC. Each ImageTexture +// is stored in ImagesManager using its CRC as a hash key. +// Simply comparing the address is not enough -- different image could end up +// at the same address (i.e. the image is deallocated then a new one is +// reallocated at the old address) // -// Layers on the shared image path will ask TilesManager for the corresponding -// ImageTexture, instead of using a PaintedSurface+TiledTexture. -// When the ImageTexture is prepared for the first time, we directly upload -// the bitmap to a texture. +// Each ImageTexture's CRC being unique, LayerAndroid instances simply store that +// and retain/release the corresponding ImageTexture (so that +// queued painting request will work correctly and not crash...). +// LayerAndroid running on the UI thread will get the corresponding +// ImageTexture at draw time. // -// TODO: limit how many ImageTextures can be uploaded in one draw cycle -// TODO: limit the size of ImageTextures (use a TiledTexture when needed) +// ImageTexture recopy the original SkBitmap so that they can safely be used +// on a different thread; it uses TiledTexture to allocate and paint the image, +// so that we can share the same textures and limits as the rest of the layers. // ///////////////////////////////////////////////////////////////////////////////// -class ImageTexture { +class ImageTexture : public SurfacePainter { public: - ImageTexture(SkBitmapRef* img); + ImageTexture(SkBitmap* bmp, unsigned crc); virtual ~ImageTexture(); - void prepareGL(); - void uploadGLTexture(); + bool prepareGL(GLWebViewState*); void drawGL(LayerAndroid* painter); void drawCanvas(SkCanvas*, SkRect&); - void retain() { m_refCount++; } - void release(); - unsigned int refCount() { return m_refCount; } - SkBitmapRef* imageRef() { return m_imageRef; } + bool hasContentToShow(); SkBitmap* bitmap() { return m_image; } + unsigned imageCRC() { return m_crc; } -private: + static SkBitmap* convertBitmap(SkBitmap* bitmap); + + static unsigned computeCRC(const SkBitmap* bitmap); + bool equalsCRC(unsigned crc); + + // methods used by TiledTexture + virtual const TransformationMatrix* transform(); + virtual float opacity(); - void deleteTexture(); + int nbTextures(); + + virtual SurfaceType type() { return SurfacePainter::ImageSurface; } + +private: SkBitmapRef* m_imageRef; SkBitmap* m_image; - GLuint m_textureId; - unsigned int m_refCount; + TiledTexture* m_texture; + LayerAndroid* m_layer; + SkPicture* m_picture; + TransformationMatrix m_layerMatrix; + unsigned m_crc; }; } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/android/ImagesManager.cpp b/Source/WebCore/platform/graphics/android/ImagesManager.cpp index 21f9fe9..65c41d1 100644 --- a/Source/WebCore/platform/graphics/android/ImagesManager.cpp +++ b/Source/WebCore/platform/graphics/android/ImagesManager.cpp @@ -26,6 +26,9 @@ #include "config.h" #include "ImagesManager.h" +#include "SkCanvas.h" +#include "SkDevice.h" +#include "SkRefCnt.h" #include "ImageTexture.h" #include <cutils/log.h> @@ -59,71 +62,88 @@ ImagesManager* ImagesManager::instance() ImagesManager* ImagesManager::gInstance = 0; -void ImagesManager::addImage(SkBitmapRef* imgRef) +ImageTexture* ImagesManager::setImage(SkBitmapRef* imgRef) { if (!imgRef) - return; + return 0; + + SkBitmap* bitmap = &imgRef->bitmap(); + ImageTexture* image = 0; + SkBitmap* img = 0; + unsigned crc = 0; + + img = ImageTexture::convertBitmap(bitmap); + crc = ImageTexture::computeCRC(img); + + { + android::Mutex::Autolock lock(m_imagesLock); + if (m_images.contains(crc)) { + image = m_images.get(crc); + SkSafeRef(image); + return image; + } + } + + // the image is not in the map, we add it + + image = new ImageTexture(img, crc); android::Mutex::Autolock lock(m_imagesLock); - if (!m_images.contains(imgRef)) - m_images.set(imgRef, new ImageTexture(imgRef)); + m_images.set(crc, image); + + return image; } -void ImagesManager::removeImage(SkBitmapRef* imgRef) +ImageTexture* ImagesManager::retainImage(unsigned imgCRC) { + if (!imgCRC) + return 0; + android::Mutex::Autolock lock(m_imagesLock); - if (!m_images.contains(imgRef)) - return; + ImageTexture* image = 0; + if (m_images.contains(imgCRC)) { + image = m_images.get(imgCRC); + SkSafeRef(image); + } + return image; +} - ImageTexture* image = m_images.get(imgRef); - image->release(); +void ImagesManager::releaseImage(unsigned imgCRC) +{ + if (!imgCRC) + return; - if (!image->refCount()) { - m_images.remove(imgRef); - delete image; + android::Mutex::Autolock lock(m_imagesLock); + if (m_images.contains(imgCRC)) { + ImageTexture* image = m_images.get(imgCRC); + if (image->getRefCnt() == 1) + m_images.remove(imgCRC); + SkSafeUnref(image); } } -void ImagesManager::showImages() +int ImagesManager::nbTextures() { - XLOGC("We have %d images", m_images.size()); - HashMap<SkBitmapRef*, ImageTexture*>::iterator end = m_images.end(); + android::Mutex::Autolock lock(m_imagesLock); + HashMap<unsigned, ImageTexture*>::iterator end = m_images.end(); int i = 0; - for (HashMap<SkBitmapRef*, ImageTexture*>::iterator it = m_images.begin(); it != end; ++it) { - XLOGC("Image %x (%d/%d) has %d references", it->first, i, - m_images.size(), it->second->refCount()); + int nb = 0; + for (HashMap<unsigned, ImageTexture*>::iterator it = m_images.begin(); it != end; ++it) { + nb += it->second->nbTextures(); i++; } + return nb; } -ImageTexture* ImagesManager::getTextureForImage(SkBitmapRef* img, bool retain) +bool ImagesManager::prepareTextures(GLWebViewState* state) { + bool ret = false; android::Mutex::Autolock lock(m_imagesLock); - ImageTexture* image = m_images.get(img); - if (retain && image) - image->retain(); - return image; -} - -void ImagesManager::scheduleTextureUpload(ImageTexture* texture) -{ - if (m_imagesToUpload.contains(texture)) - return; - - texture->retain(); - m_imagesToUpload.append(texture); -} - -bool ImagesManager::uploadTextures() -{ - // scheduleUpload and uploadTextures are called on the same thread - if (!m_imagesToUpload.size()) - return false; - ImageTexture* texture = m_imagesToUpload.last(); - texture->uploadGLTexture(); - m_imagesToUpload.removeLast(); - removeImage(texture->imageRef()); - return m_imagesToUpload.size(); + HashMap<unsigned, ImageTexture*>::iterator end = m_images.end(); + for (HashMap<unsigned, ImageTexture*>::iterator it = m_images.begin(); it != end; ++it) { + ret |= it->second->prepareGL(state); + } + return ret; } } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/android/ImagesManager.h b/Source/WebCore/platform/graphics/android/ImagesManager.h index 2fcb9fd..a3ea859 100644 --- a/Source/WebCore/platform/graphics/android/ImagesManager.h +++ b/Source/WebCore/platform/graphics/android/ImagesManager.h @@ -35,17 +35,18 @@ namespace WebCore { class ImageTexture; +class GLWebViewState; class ImagesManager { public: static ImagesManager* instance(); - void addImage(SkBitmapRef* img); - void removeImage(SkBitmapRef* img); - ImageTexture* getTextureForImage(SkBitmapRef* img, bool retain = true); - void showImages(); - void scheduleTextureUpload(ImageTexture* texture); - bool uploadTextures(); + ImageTexture* setImage(SkBitmapRef* imgRef); + ImageTexture* retainImage(unsigned imgCRC); + void releaseImage(unsigned imgCRC); + + bool prepareTextures(GLWebViewState*); + int nbTextures(); private: ImagesManager() {} @@ -53,8 +54,7 @@ private: static ImagesManager* gInstance; android::Mutex m_imagesLock; - HashMap<SkBitmapRef*, ImageTexture*> m_images; - Vector<ImageTexture*> m_imagesToUpload; + HashMap<unsigned, ImageTexture*> m_images; }; } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/android/Layer.cpp b/Source/WebCore/platform/graphics/android/Layer.cpp index f650c52..9280461 100644 --- a/Source/WebCore/platform/graphics/android/Layer.cpp +++ b/Source/WebCore/platform/graphics/android/Layer.cpp @@ -23,6 +23,7 @@ Layer::Layer() { m_shouldInheritFromRootTransform = false; m_hasOverflowChildren = false; + m_state = 0; #ifdef DEBUG_TRACK_NEW_DELETE gLayerAllocCount += 1; @@ -42,6 +43,7 @@ Layer::Layer(const Layer& src) : INHERITED() { m_shouldInheritFromRootTransform = src.m_shouldInheritFromRootTransform; m_hasOverflowChildren = src.m_hasOverflowChildren; + m_state = 0; #ifdef DEBUG_TRACK_NEW_DELETE gLayerAllocCount += 1; @@ -225,3 +227,10 @@ bool Layer::isAncestor(const Layer* possibleAncestor) const { } return false; } + +void Layer::setState(WebCore::GLWebViewState* state) { + m_state = state; + int count = countChildren(); + for (int i = 0; i < count; i++) + m_children[i]->setState(state); +} diff --git a/Source/WebCore/platform/graphics/android/Layer.h b/Source/WebCore/platform/graphics/android/Layer.h index 89e101c..5200a3d 100644 --- a/Source/WebCore/platform/graphics/android/Layer.h +++ b/Source/WebCore/platform/graphics/android/Layer.h @@ -17,17 +17,24 @@ #ifndef Layer_DEFINED #define Layer_DEFINED +#include "TestExport.h" #include "SkRefCnt.h" #include "SkTDArray.h" #include "SkColor.h" #include "SkMatrix.h" #include "SkPoint.h" #include "SkRect.h" +#include "SkRegion.h" #include "SkSize.h" +namespace WebCore { +class IntRect; +class GLWebViewState; +}; + class SkCanvas; -class Layer : public SkRefCnt { +class TEST_EXPORT Layer : public SkRefCnt { public: Layer(); @@ -56,7 +63,42 @@ public: void setMatrix(const SkMatrix& matrix) { m_matrix = matrix; } void setChildrenMatrix(const SkMatrix& matrix) { m_childrenMatrix = matrix; } - // children +// rendering asset management + + // tell rendering assets to update their tile content with most recent painted data + virtual void swapTiles() {} + + // tell rendering assets to use this layer tree for drawing + virtual void setIsDrawing(bool isDrawing) {} + + // take rendering assets from drawing tree, or create if they don't exist + virtual void setIsPainting(Layer* drawingTree) {} + + // if a similar layer exists in the replacement tree, add invals to it + virtual void mergeInvalsInto(Layer* replacementTree) {} + + void markAsDirty(const SkRegion& invalRegion) { + m_dirtyRegion.op(invalRegion, SkRegion::kUnion_Op); + } + + bool isDirty() { + return !m_dirtyRegion.isEmpty(); + } + +// drawing + + virtual bool isReady() { return false; } + + // TODO: clean out several of these, leave them in GLWebViewState + + virtual bool prepare(double currentTime, WebCore::IntRect& viewRect, + SkRect& visibleRect, float scale) { return 0; } + virtual bool drawGL(WebCore::IntRect& viewRect, + SkRect& visibleRect, float scale) { return 0; } + WebCore::GLWebViewState* state() { return m_state; } + void setState(WebCore::GLWebViewState* state); + +// children /** Return the number of layers in our child list. */ @@ -153,6 +195,11 @@ protected: SkTDArray<Layer*> m_children; + // invalidation region + SkRegion m_dirtyRegion; + + WebCore::GLWebViewState* m_state; + typedef SkRefCnt INHERITED; }; diff --git a/Source/WebCore/platform/graphics/android/LayerAndroid.cpp b/Source/WebCore/platform/graphics/android/LayerAndroid.cpp index 12a11bf..962bcdf 100644 --- a/Source/WebCore/platform/graphics/android/LayerAndroid.cpp +++ b/Source/WebCore/platform/graphics/android/LayerAndroid.cpp @@ -149,21 +149,17 @@ LayerAndroid::LayerAndroid(RenderLayer* owner) : Layer(), m_recordingPicture(0), m_uniqueId(++gUniqueId), m_texture(0), - m_imageRef(0), - m_imageTexture(0), + m_imageCRC(0), m_pictureUsed(0), - m_requestSent(false), m_scale(1), m_lastComputeTextureSize(0), m_owningLayer(owner), m_type(LayerAndroid::WebCoreLayer), - m_state(0), m_hasText(true) { m_backgroundColor = 0; m_preserves3D = false; - m_dirty = false; m_iframeOffset.set(0,0); m_dirtyRegion.setEmpty(); #ifdef DEBUG_COUNT @@ -177,17 +173,15 @@ LayerAndroid::LayerAndroid(const LayerAndroid& layer) : Layer(layer), m_isIframe(layer.m_isIframe), m_uniqueId(layer.m_uniqueId), m_texture(0), - m_imageTexture(0), - m_requestSent(false), m_owningLayer(layer.m_owningLayer), m_type(LayerAndroid::UILayer), - m_state(0), m_hasText(true) { m_isFixed = layer.m_isFixed; - m_imageRef = layer.m_imageRef; - if (m_imageRef) - ImagesManager::instance()->addImage(m_imageRef); + m_imageCRC = layer.m_imageCRC; + if (m_imageCRC) + ImagesManager::instance()->retainImage(m_imageCRC); + m_renderLayerPos = layer.m_renderLayerPos; m_transform = layer.m_transform; m_backfaceVisibility = layer.m_backfaceVisibility; @@ -211,7 +205,6 @@ LayerAndroid::LayerAndroid(const LayerAndroid& layer) : Layer(layer), m_anchorPointZ = layer.m_anchorPointZ; m_drawTransform = layer.m_drawTransform; m_childrenTransform = layer.m_childrenTransform; - m_dirty = layer.m_dirty; m_pictureUsed = layer.m_pictureUsed; m_dirtyRegion = layer.m_dirtyRegion; m_scale = layer.m_scale; @@ -222,14 +215,13 @@ LayerAndroid::LayerAndroid(const LayerAndroid& layer) : Layer(layer), KeyframesMap::const_iterator end = layer.m_animations.end(); for (KeyframesMap::const_iterator it = layer.m_animations.begin(); it != end; ++it) { - pair<String, int> key((it->second)->name(), (it->second)->type()); - m_animations.add(key, (it->second)->copy()); + m_animations.add(it->first, it->second); } m_hasText = layer.m_hasText; #ifdef DEBUG_COUNT - ClassTracker::instance()->increment("LayerAndroid - recopy (UI?)"); + ClassTracker::instance()->increment("LayerAndroid - recopy (UI)"); ClassTracker::instance()->add(this); #endif } @@ -256,20 +248,16 @@ LayerAndroid::LayerAndroid(SkPicture* picture) : Layer(), m_isFixed(false), m_isIframe(false), m_recordingPicture(picture), - m_uniqueId(-1), + m_uniqueId(++gUniqueId), m_texture(0), - m_imageRef(0), - m_imageTexture(0), - m_requestSent(false), + m_imageCRC(0), m_scale(1), m_lastComputeTextureSize(0), m_owningLayer(0), m_type(LayerAndroid::NavCacheLayer), - m_state(0), m_hasText(true) { m_backgroundColor = 0; - m_dirty = false; SkSafeRef(m_recordingPicture); m_iframeOffset.set(0,0); m_dirtyRegion.setEmpty(); @@ -281,8 +269,9 @@ LayerAndroid::LayerAndroid(SkPicture* picture) : Layer(), LayerAndroid::~LayerAndroid() { - if (m_imageTexture) - ImagesManager::instance()->removeImage(m_imageTexture->imageRef()); + if (m_imageCRC) + ImagesManager::instance()->releaseImage(m_imageCRC); + SkSafeUnref(m_recordingPicture); m_animations.clear(); #ifdef DEBUG_COUNT @@ -335,7 +324,18 @@ bool LayerAndroid::evaluateAnimations(double time) return hasRunningAnimations || m_hasRunningAnimations; } -void LayerAndroid::addDirtyArea(GLWebViewState* glWebViewState) +void LayerAndroid::initAnimations() { + // tell auto-initializing animations to start now + for (int i = 0; i < countChildren(); i++) + getChild(i)->initAnimations(); + + KeyframesMap::const_iterator localBegin = m_animations.begin(); + KeyframesMap::const_iterator localEnd = m_animations.end(); + for (KeyframesMap::const_iterator localIt = localBegin; localIt != localEnd; ++localIt) + (localIt->second)->suggestBeginTime(WTF::currentTime()); +} + +void LayerAndroid::addDirtyArea() { IntSize layerSize(getSize().width(), getSize().height()); @@ -345,7 +345,7 @@ void LayerAndroid::addDirtyArea(GLWebViewState* glWebViewState) area.intersect(clip); IntRect dirtyArea(area.x(), area.y(), area.width(), area.height()); - glWebViewState->addDirtyArea(dirtyArea); + m_state->addDirtyArea(dirtyArea); } void LayerAndroid::addAnimation(PassRefPtr<AndroidAnimation> prpAnim) @@ -379,7 +379,7 @@ void LayerAndroid::removeAnimationsForKeyframes(const String& name) } for (unsigned int i = 0; i < toDelete.size(); i++) - m_animations.remove(toDelete[i]); + m_animations.remove(toDelete[i]); } // We only use the bounding rect of the layer as mask... @@ -770,16 +770,14 @@ void LayerAndroid::updateGLPositionsAndScale(const TransformationMatrix& parentM void LayerAndroid::setContentsImage(SkBitmapRef* img) { - m_imageRef = img; - if (!img) - return; - - ImagesManager::instance()->addImage(img); + ImageTexture* image = ImagesManager::instance()->setImage(img); + ImagesManager::instance()->releaseImage(m_imageCRC); + m_imageCRC = image ? image->imageCRC() : 0; } bool LayerAndroid::needsTexture() { - return m_imageRef || (prepareContext() + return m_imageCRC || (m_recordingPicture && m_recordingPicture->width() && m_recordingPicture->height()); } @@ -820,6 +818,9 @@ int LayerAndroid::nbTexturedLayers() void LayerAndroid::computeTexturesAmount(TexturesResult* result) { + if (!result) + return; + int count = this->countChildren(); for (int i = 0; i < count; i++) this->getChild(i)->computeTexturesAmount(result); @@ -847,15 +848,17 @@ void LayerAndroid::showLayer(int indent) IntRect visible = visibleArea(); IntRect clip(m_clippingRect.x(), m_clippingRect.y(), m_clippingRect.width(), m_clippingRect.height()); - XLOGC("%s [%d:0x%x] - %s - area (%d, %d, %d, %d) - visible (%d, %d, %d, %d) " - "clip (%d, %d, %d, %d) %s prepareContext(%d), pic w: %d h: %d", + XLOGC("%s [%d:0x%x] - %s %s - area (%d, %d, %d, %d) - visible (%d, %d, %d, %d) " + "clip (%d, %d, %d, %d) %s %s prepareContext(%x), pic w: %d h: %d", spaces, uniqueId(), m_owningLayer, needsTexture() ? "needs a texture" : "no texture", + m_imageCRC ? "has an image" : "no image", 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(), + isFixed() ? "FIXED" : "", + m_recordingPicture, m_recordingPicture ? m_recordingPicture->width() : -1, m_recordingPicture ? m_recordingPicture->height() : -1); @@ -864,33 +867,68 @@ void LayerAndroid::showLayer(int indent) this->getChild(i)->showLayer(indent + 1); } -// We go through our tree, and if we have layer in the new -// tree that is similar, we transfer our texture to it. -// Otherwise, we remove ourselves from the texture so -// that TilesManager::swapLayersTextures() have a chance -// at deallocating the textures (PaintedSurfaces) -void LayerAndroid::assignTextureTo(LayerAndroid* newTree) +void LayerAndroid::swapTiles() { int count = this->countChildren(); for (int i = 0; i < count; i++) - this->getChild(i)->assignTextureTo(newTree); + this->getChild(i)->swapTiles(); - if (newTree) { - LayerAndroid* newLayer = newTree->findById(uniqueId()); - if (newLayer == this) - return; - if (newLayer && m_texture) { - m_texture->replaceLayer(newLayer); - newLayer->m_texture = m_texture; - m_texture = 0; - } - if (!newLayer && m_texture) { - m_texture->removeLayer(this); - m_texture = 0; - } + if (m_texture) + m_texture->swapTiles(); +} + +void LayerAndroid::setIsDrawing(bool isDrawing) +{ + int count = this->countChildren(); + for (int i = 0; i < count; i++) + this->getChild(i)->setIsDrawing(isDrawing); + + if (m_texture) { + m_texture->setDrawingLayer(isDrawing ? this : 0); + m_texture->clearPaintingLayer(); } } +void LayerAndroid::setIsPainting(Layer* drawingTree) +{ + XLOG("setting layer %p as painting, needs texture %d, drawing tree %p", + this, needsTexture(), drawingTree); + int count = this->countChildren(); + for (int i = 0; i < count; i++) + this->getChild(i)->setIsPainting(drawingTree); + + + LayerAndroid* drawingLayer = 0; + if (drawingTree) + drawingLayer = static_cast<LayerAndroid*>(drawingTree)->findById(uniqueId()); + + obtainTextureForPainting(drawingLayer); +} + +void LayerAndroid::mergeInvalsInto(Layer* replacementTree) +{ + int count = this->countChildren(); + for (int i = 0; i < count; i++) + this->getChild(i)->mergeInvalsInto(replacementTree); + + LayerAndroid* replacementLayer = static_cast<LayerAndroid*>(replacementTree)->findById(uniqueId()); + if (replacementLayer) + replacementLayer->markAsDirty(m_dirtyRegion); +} + +bool LayerAndroid::isReady() +{ + int count = countChildren(); + for (int i = 0; i < count; i++) + if (!getChild(i)->isReady()) + return false; + + if (m_texture) + return m_texture->isReady(); + // TODO: image, check if uploaded? + return true; +} + bool LayerAndroid::updateWithTree(LayerAndroid* newTree) { // Disable fast update for now @@ -925,54 +963,48 @@ bool LayerAndroid::updateWithLayer(LayerAndroid* layer) m_opacity = layer->m_opacity; m_transform = layer->m_transform; - if (m_imageRef != layer->m_imageRef) + if (m_imageCRC != layer->m_imageCRC) m_visible = false; if ((m_recordingPicture != layer->m_recordingPicture) - || (m_imageRef != layer->m_imageRef)) + || (m_imageCRC != layer->m_imageCRC)) return true; return false; } -void LayerAndroid::createTexture() +void LayerAndroid::obtainTextureForPainting(LayerAndroid* drawingLayer) { - int count = this->countChildren(); - for (int i = 0; i < count; i++) - this->getChild(i)->createTexture(); - if (!needsTexture()) return; - if (m_imageRef) { - if (!m_imageTexture) { - m_imageTexture = ImagesManager::instance()->getTextureForImage(m_imageRef); - m_dirtyRegion.setEmpty(); - } + if (m_imageCRC) { if (m_texture) { - m_texture->removeLayer(this); + m_texture->setDrawingLayer(0); + m_texture->clearPaintingLayer(); m_texture = 0; } } else { + if (drawingLayer) { + // if a previous tree had the same layer, paint with that painted surface + m_texture = drawingLayer->m_texture; + } + if (!m_texture) - m_texture = new PaintedSurface(this); + m_texture = new PaintedSurface(); // pass the invalidated regions to the PaintedSurface - m_texture->markAsDirty(m_dirtyRegion); - m_dirtyRegion.setEmpty(); + m_texture->setPaintingLayer(this, m_dirtyRegion); } + m_dirtyRegion.setEmpty(); } + static inline bool compareLayerZ(const LayerAndroid* a, const LayerAndroid* b) { return a->zValue() > b->zValue(); } -void LayerAndroid::markAsDirty(const SkRegion& dirtyArea) -{ - m_dirtyRegion.op(dirtyArea, SkRegion::kUnion_Op); -} - // We call this in WebViewCore, when copying the tree of layers. // As we construct a new tree that will be passed on the UI, // we mark the webkit-side tree as having no more dirty region @@ -986,18 +1018,9 @@ 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) +void LayerAndroid::prepare() { - m_state = glWebViewState; + XLOG("LA %p preparing, m_texture %p", this, m_texture); int count = this->countChildren(); if (count > 0) { @@ -1010,14 +1033,11 @@ void LayerAndroid::prepare(GLWebViewState* glWebViewState) // iterate in reverse so top layers get textures first for (int i = count-1; i >= 0; i--) - sublayers[i]->prepare(glWebViewState); + sublayers[i]->prepare(); } if (m_texture) - m_texture->prepare(glWebViewState); - - if (m_imageTexture) - m_imageTexture->prepareGL(); + m_texture->prepare(m_state); } IntRect LayerAndroid::unclippedArea() @@ -1082,15 +1102,14 @@ bool LayerAndroid::drawCanvas(SkCanvas* canvas) // 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); + addDirtyArea(); m_atomicSync.unlock(); return askScreenUpdate; } -bool LayerAndroid::drawGL(GLWebViewState* glWebViewState, SkMatrix& matrix) +bool LayerAndroid::drawGL() { FloatRect clippingRect = TilesManager::instance()->shader()->rectInScreenCoord(m_clippingRect); TilesManager::instance()->shader()->clip(clippingRect); @@ -1099,18 +1118,22 @@ bool LayerAndroid::drawGL(GLWebViewState* glWebViewState, SkMatrix& matrix) bool askScreenUpdate = false; - if (m_texture) - askScreenUpdate |= m_texture->draw(); - - if (m_imageTexture) - m_imageTexture->drawGL(this); + if (m_state->layersRenderingMode() < GLWebViewState::kScrollableAndFixedLayers) { + if (m_texture) + askScreenUpdate |= m_texture->draw(); + if (m_imageCRC) { + ImageTexture* imageTexture = ImagesManager::instance()->retainImage(m_imageCRC); + if (imageTexture) + imageTexture->drawGL(this); + ImagesManager::instance()->releaseImage(m_imageCRC); + } + } // When the layer is dirty, the UI thread should be notified to redraw. - askScreenUpdate |= drawChildrenGL(glWebViewState, matrix); + askScreenUpdate |= drawChildrenGL(); m_atomicSync.lock(); - askScreenUpdate |= m_dirty; if (askScreenUpdate || m_hasRunningAnimations || m_drawTransform.hasPerspective()) - addDirtyArea(glWebViewState); + addDirtyArea(); m_atomicSync.unlock(); return askScreenUpdate; @@ -1136,7 +1159,7 @@ bool LayerAndroid::drawChildrenCanvas(SkCanvas* canvas) return askScreenUpdate; } -bool LayerAndroid::drawChildrenGL(GLWebViewState* glWebViewState, SkMatrix& matrix) +bool LayerAndroid::drawChildrenGL() { bool askScreenUpdate = false; int count = this->countChildren(); @@ -1149,7 +1172,7 @@ bool LayerAndroid::drawChildrenGL(GLWebViewState* glWebViewState, SkMatrix& matr std::stable_sort(sublayers.begin(), sublayers.end(), compareLayerZ); for (int i = 0; i < count; i++) { LayerAndroid* layer = sublayers[i]; - askScreenUpdate |= layer->drawGL(glWebViewState, matrix); + askScreenUpdate |= layer->drawGL(); } } @@ -1201,16 +1224,15 @@ void LayerAndroid::onDraw(SkCanvas* canvas, SkScalar opacity) if (canvasOpacity < 255) canvas->setDrawFilter(new OpacityDrawFilter(canvasOpacity)); - if (m_imageRef) { - if (!m_imageTexture) { - m_imageTexture = ImagesManager::instance()->getTextureForImage(m_imageRef); - m_dirtyRegion.setEmpty(); - } - if (m_imageTexture) { + if (m_imageCRC) { + ImageTexture* imageTexture = ImagesManager::instance()->retainImage(m_imageCRC); + m_dirtyRegion.setEmpty(); + if (imageTexture) { SkRect dest; dest.set(0, 0, getSize().width(), getSize().height()); - m_imageTexture->drawCanvas(canvas, dest); + imageTexture->drawCanvas(canvas, dest); } + ImagesManager::instance()->releaseImage(m_imageCRC); } contentDraw(canvas); } diff --git a/Source/WebCore/platform/graphics/android/LayerAndroid.h b/Source/WebCore/platform/graphics/android/LayerAndroid.h index b536b22..c1f1bc9 100644 --- a/Source/WebCore/platform/graphics/android/LayerAndroid.h +++ b/Source/WebCore/platform/graphics/android/LayerAndroid.h @@ -30,11 +30,9 @@ #include "SkColor.h" #include "SkRegion.h" #include "SkStream.h" -#include "TextureOwner.h" #include "TransformationMatrix.h" #include <wtf/HashMap.h> -#include <wtf/text/StringHash.h> #ifndef BZERO_DEFINED #define BZERO_DEFINED @@ -94,6 +92,7 @@ namespace WebCore { class AndroidAnimation; class BaseTileTexture; +class GLWebViewState; class LayerAndroidFindState; class RenderLayer; class TiledPage; @@ -114,7 +113,7 @@ public: int full; }; -class LayerAndroid : public Layer { +class TEST_EXPORT LayerAndroid : public Layer { public: enum LayerType { UndefinedLayer, WebCoreLayer, UILayer, NavCacheLayer }; @@ -124,7 +123,6 @@ public: virtual ~LayerAndroid(); virtual TiledPage* page() { return 0; } - virtual GLWebViewState* state() { return m_state; } void setBackfaceVisibility(bool value) { m_backfaceVisibility = value; } void setTransform(const TransformationMatrix& matrix) { m_transform = matrix; } @@ -146,22 +144,20 @@ public: // Debug helper methods int nbLayers(); int nbTexturedLayers(); - void showLayer(int indent); + void showLayer(int indent = 0); 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 drawGL(); + bool drawChildrenGL(); virtual bool drawCanvas(SkCanvas*); bool drawChildrenCanvas(SkCanvas*); // prepare layer and its children via reverse-Z, post-order traversal - void prepare(GLWebViewState*); + void prepare(); void updateGLPositionsAndScale(const TransformationMatrix& parentMatrix, const FloatRect& clip, float opacity, float scale); @@ -218,8 +214,9 @@ public: void removeAnimationsForKeyframes(const String& name); bool evaluateAnimations(); bool evaluateAnimations(double time); + void initAnimations(); bool hasAnimations() const; - void addDirtyArea(GLWebViewState*); + void addDirtyArea(); SkPicture* picture() const { return m_recordingPicture; } @@ -264,7 +261,7 @@ public: /** This sets a content image -- calling it means we will use the image directly when drawing the layer instead of using the content painted by WebKit. - Images are handled in TilesManager, as they can be shared + Images are handled in ImagesManager, as they can be shared between layers. */ void setContentsImage(SkBitmapRef* img); @@ -276,9 +273,7 @@ public: void needsRepaint() { m_pictureUsed++; } unsigned int pictureUsed() { return m_pictureUsed; } - void markAsDirty(const SkRegion& dirtyArea); void clearDirtyRegion(); - const SkRegion& dirtyRegion() { return m_dirtyRegion; } void contentDraw(SkCanvas*); @@ -296,8 +291,7 @@ public: friend void android::cleanupImageRefs(LayerAndroid* layer); PaintedSurface* texture() { return m_texture; } - void assignTextureTo(LayerAndroid* newTree); - void createTexture(); + void obtainTextureForPainting(LayerAndroid* drawingLayer); // Update layers using another tree. Only works for basic properties // such as the position, the transform. Return true if anything more @@ -305,13 +299,20 @@ public: bool updateWithTree(LayerAndroid*); virtual bool updateWithLayer(LayerAndroid*); - SkBitmapRef* imageRef() { return m_imageRef; } - ImageTexture* imageTexture() { return m_imageTexture; } int type() { return m_type; } bool hasText() { return m_hasText; } void checkTextPresence(); + void copyAnimationStartTimesRecursive(LayerAndroid* oldTree); + +// rendering asset management + void swapTiles(); + void setIsDrawing(bool isDrawing); + void setIsPainting(Layer* drawingTree); + void mergeInvalsInto(Layer* replacementTree); + bool isReady(); + protected: virtual void onDraw(SkCanvas*, SkScalar opacity); @@ -323,6 +324,7 @@ private: friend class CachedLayer::Debug; // debugging access only #endif + void copyAnimationStartTimes(LayerAndroid* oldLayer); void findInner(FindState&) const; bool prepareContext(bool force = false); void clipInner(SkTDArray<SkRect>* region, const SkRect& local) const; @@ -386,22 +388,13 @@ private: int m_uniqueId; PaintedSurface* m_texture; - SkBitmapRef* m_imageRef; - ImageTexture* m_imageTexture; + unsigned m_imageCRC; - // used to signal that the tile is out-of-date and needs to be redrawn - bool m_dirty; unsigned int m_pictureUsed; - // dirty regions - SkRegion m_dirtyRegion; - // used to signal the framework we need a repaint bool m_hasRunningAnimations; - // painting request sent - bool m_requestSent; - float m_scale; // We try to not always compute the texture size, as this is quite heavy @@ -416,7 +409,6 @@ private: RenderLayer* m_owningLayer; int m_type; - GLWebViewState* m_state; bool m_hasText; diff --git a/Source/WebCore/platform/graphics/android/MediaLayer.cpp b/Source/WebCore/platform/graphics/android/MediaLayer.cpp index 7fa5ac2..12cfe38 100644 --- a/Source/WebCore/platform/graphics/android/MediaLayer.cpp +++ b/Source/WebCore/platform/graphics/android/MediaLayer.cpp @@ -66,9 +66,10 @@ MediaLayer::~MediaLayer() m_mediaTexture->decStrong(this); } -bool MediaLayer::drawGL(GLWebViewState* glWebViewState, SkMatrix& matrix) +bool MediaLayer::drawGL() { - TilesManager::instance()->shader()->clip(drawClip()); + FloatRect clippingRect = TilesManager::instance()->shader()->rectInScreenCoord(drawClip()); + TilesManager::instance()->shader()->clip(clippingRect); // when the plugin gains focus webkit applies an outline to the // widget, which causes the layer to expand to accommodate the @@ -92,7 +93,7 @@ bool MediaLayer::drawGL(GLWebViewState* glWebViewState, SkMatrix& matrix) // draw any content or video if present m_mediaTexture->draw(m, m_drawTransform, mediaBounds); - return drawChildrenGL(glWebViewState, matrix); + return drawChildrenGL(); } ANativeWindow* MediaLayer::acquireNativeWindowForContent() diff --git a/Source/WebCore/platform/graphics/android/MediaLayer.h b/Source/WebCore/platform/graphics/android/MediaLayer.h index ef84abf..b94ec53 100644 --- a/Source/WebCore/platform/graphics/android/MediaLayer.h +++ b/Source/WebCore/platform/graphics/android/MediaLayer.h @@ -36,7 +36,7 @@ public: MediaLayer(const MediaLayer& layer); virtual ~MediaLayer(); - virtual bool drawGL(GLWebViewState*, SkMatrix&); + virtual bool drawGL(); virtual void paintBitmapGL() const { }; virtual bool needsTexture() { return false; } diff --git a/Source/WebCore/platform/graphics/android/PaintTileOperation.cpp b/Source/WebCore/platform/graphics/android/PaintTileOperation.cpp index d9a729a..2d69706 100644 --- a/Source/WebCore/platform/graphics/android/PaintTileOperation.cpp +++ b/Source/WebCore/platform/graphics/android/PaintTileOperation.cpp @@ -25,23 +25,21 @@ #include "config.h" #include "PaintTileOperation.h" +#include "ImageTexture.h" +#include "ImagesManager.h" #include "LayerAndroid.h" #include "PaintedSurface.h" namespace WebCore { -PaintTileOperation::PaintTileOperation(BaseTile* tile, PaintedSurface* surface) +PaintTileOperation::PaintTileOperation(BaseTile* tile, SurfacePainter* surface) : QueuedOperation(QueuedOperation::PaintTile, tile->page()) , m_tile(tile) , m_surface(surface) - , m_layer(0) { if (m_tile) m_tile->setRepaintPending(true); - if (m_surface) - m_layer = surface->layer(); SkSafeRef(m_surface); - SkSafeRef(m_layer); } PaintTileOperation::~PaintTileOperation() @@ -50,8 +48,13 @@ PaintTileOperation::~PaintTileOperation() m_tile->setRepaintPending(false); m_tile = 0; } - SkSafeUnref(m_surface); - SkSafeUnref(m_layer); + + if (m_surface && m_surface->type() == SurfacePainter::ImageSurface) { + ImageTexture* image = static_cast<ImageTexture*>(m_surface); + ImagesManager::instance()->releaseImage(image->imageCRC()); + } else { + SkSafeUnref(m_surface); + } } bool PaintTileOperation::operator==(const QueuedOperation* operation) @@ -99,7 +102,6 @@ int PaintTileOperation::priority() // for base tiles, prioritize based on position if (!m_tile->isLayerTile()) { bool goingDown = m_tile->page()->scrollingDown(); - SkIRect *rect = m_tile->page()->expandedTileBounds(); priority += m_tile->x(); if (goingDown) diff --git a/Source/WebCore/platform/graphics/android/PaintTileOperation.h b/Source/WebCore/platform/graphics/android/PaintTileOperation.h index 65d20f2..bc74d03 100644 --- a/Source/WebCore/platform/graphics/android/PaintTileOperation.h +++ b/Source/WebCore/platform/graphics/android/PaintTileOperation.h @@ -26,16 +26,19 @@ #ifndef PaintTileSetOperation_h #define PaintTileSetOperation_h +#include "BaseTile.h" #include "QueuedOperation.h" +#include "SkRefCnt.h" namespace WebCore { class LayerAndroid; -class PaintedSurface; +class SurfacePainter; +class ImageTexture; class PaintTileOperation : public QueuedOperation { public: - PaintTileOperation(BaseTile* tile, PaintedSurface* surface = 0); + PaintTileOperation(BaseTile* tile, SurfacePainter* surface = 0); virtual ~PaintTileOperation(); virtual bool operator==(const QueuedOperation* operation); virtual void run(); @@ -46,8 +49,7 @@ public: private: BaseTile* m_tile; - PaintedSurface* m_surface; - LayerAndroid* m_layer; + SurfacePainter* m_surface; }; class ScaleFilter : public OperationFilter { diff --git a/Source/WebCore/platform/graphics/android/PaintedSurface.cpp b/Source/WebCore/platform/graphics/android/PaintedSurface.cpp index 939d106..d3c1e15 100644 --- a/Source/WebCore/platform/graphics/android/PaintedSurface.cpp +++ b/Source/WebCore/platform/graphics/android/PaintedSurface.cpp @@ -28,6 +28,7 @@ #include "LayerAndroid.h" +#include "TiledTexture.h" #include "TilesManager.h" #include "SkCanvas.h" #include "SkPicture.h" @@ -57,107 +58,64 @@ namespace WebCore { -PaintedSurface::PaintedSurface(LayerAndroid* layer) - : m_layer(layer) +PaintedSurface::PaintedSurface() + : m_drawingLayer(0) + , m_paintingLayer(0) , m_tiledTexture(0) , m_scale(0) , m_pictureUsed(0) { TilesManager::instance()->addPaintedSurface(this); - SkSafeRef(m_layer); #ifdef DEBUG_COUNT ClassTracker::instance()->increment("PaintedSurface"); #endif m_tiledTexture = new DualTiledTexture(this); - if (layer && layer->picture()) - m_updateManager.updatePicture(layer->picture()); } PaintedSurface::~PaintedSurface() { - XLOG("dtor of %x m_layer: %x", this, m_layer); - android::Mutex::Autolock lock(m_layerLock); - SkSafeUnref(m_layer); #ifdef DEBUG_COUNT ClassTracker::instance()->decrement("PaintedSurface"); #endif delete m_tiledTexture; } -void PaintedSurface::removeLayer() -{ - android::Mutex::Autolock lock(m_layerLock); - if (m_layer) - m_layer->removeTexture(this); - SkSafeUnref(m_layer); - m_layer = 0; -} - -void PaintedSurface::removeLayer(LayerAndroid* layer) -{ - android::Mutex::Autolock lock(m_layerLock); - if (m_layer != layer) - return; - SkSafeUnref(m_layer); - m_layer = 0; -} - -void PaintedSurface::replaceLayer(LayerAndroid* layer) -{ - android::Mutex::Autolock lock(m_layerLock); - if (!layer) - return; - - if (m_layer && layer->uniqueId() != m_layer->uniqueId()) - return; - - SkSafeRef(layer); - SkSafeUnref(m_layer); - m_layer = layer; - if (layer && layer->picture()) - m_updateManager.updatePicture(layer->picture()); -} - void PaintedSurface::prepare(GLWebViewState* state) { - if (!m_layer) - return; + XLOG("PS %p has PL %p, DL %p", this, m_paintingLayer, m_drawingLayer); + LayerAndroid* paintingLayer = m_paintingLayer; + if (!paintingLayer) + paintingLayer = m_drawingLayer; - if (!m_layer->needsTexture()) + if (!paintingLayer) return; bool startFastSwap = false; if (state->isScrolling()) { // when scrolling, block updates and swap tiles as soon as they're ready startFastSwap = true; - } else { - // when not, push updates down to TiledTexture in every prepare - m_updateManager.swap(); - m_tiledTexture->update(m_updateManager.getPaintingInval(), - m_updateManager.getPaintingPicture()); - m_updateManager.clearPaintingInval(); } XLOG("prepare layer %d %x at scale %.2f", - m_layer->uniqueId(), m_layer, - m_layer->getScale()); + paintingLayer->uniqueId(), paintingLayer, + paintingLayer->getScale()); - IntRect visibleArea = computeVisibleArea(m_layer); + IntRect visibleArea = computeVisibleArea(paintingLayer); m_scale = state->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()) + if (m_scale > 1 && !paintingLayer->hasText()) m_scale = 1; - m_tiledTexture->prepare(state, m_scale, m_pictureUsed != m_layer->pictureUsed(), + m_tiledTexture->prepare(state, m_scale, m_pictureUsed != paintingLayer->pictureUsed(), startFastSwap, visibleArea); } bool PaintedSurface::draw() { - if (!m_layer || !m_layer->needsTexture()) + if (!m_drawingLayer || !m_drawingLayer->needsTexture()) return false; bool askRedraw = false; @@ -167,22 +125,38 @@ bool PaintedSurface::draw() return askRedraw; } -void PaintedSurface::markAsDirty(const SkRegion& dirtyArea) +void PaintedSurface::setPaintingLayer(LayerAndroid* layer, const SkRegion& dirtyArea) +{ + m_paintingLayer = layer; + if (m_tiledTexture) + m_tiledTexture->update(dirtyArea, layer->picture()); +} + +bool PaintedSurface::isReady() +{ + if (m_tiledTexture) + return m_tiledTexture->isReady(); + return false; +} + +void PaintedSurface::swapTiles() { - m_updateManager.updateInval(dirtyArea); + if (m_tiledTexture) + m_tiledTexture->swapTiles(); } float PaintedSurface::opacity() { - if (m_layer) - return m_layer->drawOpacity(); + if (m_drawingLayer) + return m_drawingLayer->drawOpacity(); return 1.0; } const TransformationMatrix* PaintedSurface::transform() { - if (!m_layer) + // used exclusively for drawing, so only use m_drawingLayer + if (!m_drawingLayer) return 0; - return m_layer->drawTransform(); + return m_drawingLayer->drawTransform(); } void PaintedSurface::computeTexturesAmount(TexturesResult* result) @@ -190,11 +164,14 @@ void PaintedSurface::computeTexturesAmount(TexturesResult* result) if (!m_tiledTexture) return; - if (!m_layer) + // for now, always done on drawinglayer + LayerAndroid* layer = m_drawingLayer; + + if (!layer) return; - IntRect unclippedArea = m_layer->unclippedArea(); - IntRect clippedVisibleArea = m_layer->visibleArea(); + IntRect unclippedArea = layer->unclippedArea(); + IntRect clippedVisibleArea = layer->visibleArea(); // get two numbers here: // - textures needed for a clipped area // - textures needed for an un-clipped area @@ -202,19 +179,19 @@ void PaintedSurface::computeTexturesAmount(TexturesResult* result) int nbTexturesClipped = m_tiledTexture->nbTextures(clippedVisibleArea, m_scale); // Set kFixedLayers level - if (m_layer->isFixed()) + if (layer->isFixed()) result->fixed += nbTexturesClipped; // Set kScrollableAndFixedLayers level - if (m_layer->contentIsScrollable() - || m_layer->isFixed()) + if (layer->contentIsScrollable() + || layer->isFixed()) result->scrollable += nbTexturesClipped; // Set kClippedTextures level result->clipped += nbTexturesClipped; // Set kAllTextures level - if (m_layer->contentIsScrollable()) + if (layer->contentIsScrollable()) result->full += nbTexturesClipped; else result->full += nbTexturesUnclipped; diff --git a/Source/WebCore/platform/graphics/android/PaintedSurface.h b/Source/WebCore/platform/graphics/android/PaintedSurface.h index 83b2c9b..b8ab7b8 100644 --- a/Source/WebCore/platform/graphics/android/PaintedSurface.h +++ b/Source/WebCore/platform/graphics/android/PaintedSurface.h @@ -32,34 +32,37 @@ #include "LayerAndroid.h" #include "SkRefCnt.h" #include "TextureOwner.h" -#include "TiledTexture.h" #include "TilesManager.h" #include "TilePainter.h" #include "TransformationMatrix.h" -#include "UpdateManager.h" class SkCanvas; class SkRegion; namespace WebCore { -class UpdateManager; +class DualTiledTexture; -class PaintedSurface : public SkRefCnt { +class PaintedSurface : public SurfacePainter { public: - PaintedSurface(LayerAndroid* layer); + PaintedSurface(); virtual ~PaintedSurface(); // PaintedSurface methods - LayerAndroid* layer() { return m_layer; } void prepare(GLWebViewState*); bool draw(); - void markAsDirty(const SkRegion& dirtyArea); bool paint(SkCanvas*); - void removeLayer(); - void removeLayer(LayerAndroid* layer); - void replaceLayer(LayerAndroid* layer); + + void setDrawingLayer(LayerAndroid* layer) { m_drawingLayer = layer; } + LayerAndroid* drawingLayer() { return m_drawingLayer; } + + void setPaintingLayer(LayerAndroid* layer, const SkRegion& dirtyArea); + void clearPaintingLayer() { m_paintingLayer = 0; } + LayerAndroid* paintingLayer() { return m_paintingLayer; } + + void swapTiles(); + bool isReady(); bool owns(BaseTileTexture* texture); @@ -68,16 +71,15 @@ public: // TilePainter methods for TiledTexture virtual const TransformationMatrix* transform(); + virtual float opacity(); // used by TiledTexture float scale() { return m_scale; } - float opacity(); unsigned int pictureUsed() { return m_pictureUsed; } private: - UpdateManager m_updateManager; - - LayerAndroid* m_layer; + LayerAndroid* m_drawingLayer; + LayerAndroid* m_paintingLayer; DualTiledTexture* m_tiledTexture; float m_scale; diff --git a/Source/WebCore/platform/graphics/android/QueuedOperation.h b/Source/WebCore/platform/graphics/android/QueuedOperation.h index a2e49a7..1a83f65 100644 --- a/Source/WebCore/platform/graphics/android/QueuedOperation.h +++ b/Source/WebCore/platform/graphics/android/QueuedOperation.h @@ -26,10 +26,10 @@ #ifndef QueuedOperation_h #define QueuedOperation_h -#include "TiledPage.h" - namespace WebCore { +class TiledPage; + class QueuedOperation { public: enum OperationType { Undefined, PaintTile, PaintLayer, DeleteTexture }; diff --git a/Source/WebCore/platform/graphics/android/ScrollableLayerAndroid.cpp b/Source/WebCore/platform/graphics/android/ScrollableLayerAndroid.cpp index 2643d2c..3c2ced5 100644 --- a/Source/WebCore/platform/graphics/android/ScrollableLayerAndroid.cpp +++ b/Source/WebCore/platform/graphics/android/ScrollableLayerAndroid.cpp @@ -22,9 +22,6 @@ bool ScrollableLayerAndroid::scrollTo(int x, int y) 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 30b5c86..2a6a488 100644 --- a/Source/WebCore/platform/graphics/android/ShaderProgram.cpp +++ b/Source/WebCore/platform/graphics/android/ShaderProgram.cpp @@ -195,6 +195,8 @@ GLuint ShaderProgram::createProgram(const char* pVertexSource, const char* pFrag ShaderProgram::ShaderProgram() : m_blendingEnabled(false) , m_contrast(1) + , m_alphaLayer(false) + , m_currentScale(1.0f) { init(); } @@ -286,13 +288,14 @@ void ShaderProgram::setBlendingState(bool enableBlending) // Drawing ///////////////////////////////////////////////////////////////////////////////////////// -void ShaderProgram::setViewport(SkRect& viewport) +void ShaderProgram::setViewport(SkRect& viewport, float scale) { TransformationMatrix ortho; GLUtils::setOrthographicMatrix(ortho, viewport.fLeft, viewport.fTop, viewport.fRight, viewport.fBottom, -1000, 1000); m_projectionMatrix = ortho; m_viewport = viewport; + m_currentScale = scale; } void ShaderProgram::setProjectionMatrix(SkRect& geometry, GLint projectionMatrixHandle) @@ -302,7 +305,12 @@ void ShaderProgram::setProjectionMatrix(SkRect& geometry, GLint projectionMatrix TransformationMatrix scale; scale.scale3d(geometry.width(), geometry.height(), 1.0); - TransformationMatrix total = m_projectionMatrix * translate * scale; + TransformationMatrix total; + if (!m_alphaLayer) + total = m_projectionMatrix * m_repositionMatrix * m_webViewMatrix + * translate * scale; + else + total = m_projectionMatrix * translate * scale; GLfloat projectionMatrix[16]; GLUtils::toGLMatrix(projectionMatrix, total); @@ -409,7 +417,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); + IntRect rect(0, 0, m_webViewRect.width(), m_webViewRect.height()); + m_documentViewport = m_documentToScreenMatrix.inverse().mapRect(rect); } // This function transform a clip rect extracted from the current layer @@ -559,7 +568,13 @@ void ShaderProgram::drawLayerQuad(const TransformationMatrix& drawMatrix, // move the drawing depending on where the texture is on the layer modifiedDrawMatrix.translate(geometry.fLeft, geometry.fTop); modifiedDrawMatrix.scale3d(geometry.width(), geometry.height(), 1); - TransformationMatrix renderMatrix = m_projectionMatrix * modifiedDrawMatrix; + + TransformationMatrix renderMatrix; + if (!m_alphaLayer) + renderMatrix = m_projectionMatrix * m_repositionMatrix + * m_webViewMatrix * modifiedDrawMatrix; + else + renderMatrix = m_projectionMatrix * modifiedDrawMatrix; GLfloat projectionMatrix[16]; GLUtils::toGLMatrix(projectionMatrix, renderMatrix); @@ -626,6 +641,44 @@ void ShaderProgram::drawVideoLayerQuad(const TransformationMatrix& drawMatrix, glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); } +void ShaderProgram::setWebViewMatrix(const float* matrix, bool alphaLayer) +{ + GLUtils::convertToTransformationMatrix(matrix, m_webViewMatrix); + m_alphaLayer = alphaLayer; +} + +void ShaderProgram::calculateAnimationDelta() +{ + // The matrix contains the scrolling info, so this rect is starting from + // the m_viewport. + // So we just need to map the webview's visible rect using the matrix, + // calculate the difference b/t transformed rect and the webViewRect, + // then we can get the delta x , y caused by the animation. + // Note that the Y is for reporting back to GL viewport, so it is inverted. + // When it is alpha animation, then we rely on the framework implementation + // such that there is no matrix applied in native webkit. + if (!m_alphaLayer) { + FloatRect rect(m_viewport.fLeft * m_currentScale, + m_viewport.fTop * m_currentScale, + m_webViewRect.width(), + m_webViewRect.height()); + rect = m_webViewMatrix.mapRect(rect); + m_animationDelta.setX(rect.x() - m_webViewRect.x() ); + m_animationDelta.setY(rect.y() + rect.height() - m_webViewRect.y() + - m_webViewRect.height() - m_titleBarHeight); + + m_repositionMatrix.makeIdentity(); + m_repositionMatrix.translate3d(-m_webViewRect.x(), -m_webViewRect.y() - m_titleBarHeight, 0); + m_repositionMatrix.translate3d(m_viewport.fLeft * m_currentScale, m_viewport.fTop * m_currentScale, 0); + m_repositionMatrix.translate3d(-m_animationDelta.x(), -m_animationDelta.y(), 0); + } else { + m_animationDelta.setX(0); + m_animationDelta.setY(0); + m_repositionMatrix.makeIdentity(); + } + +} + } // namespace WebCore #endif // USE(ACCELERATED_COMPOSITING) diff --git a/Source/WebCore/platform/graphics/android/ShaderProgram.h b/Source/WebCore/platform/graphics/android/ShaderProgram.h index b309872..9ab7a46 100644 --- a/Source/WebCore/platform/graphics/android/ShaderProgram.h +++ b/Source/WebCore/platform/graphics/android/ShaderProgram.h @@ -36,7 +36,7 @@ public: int program() { return m_program; } // Drawing - void setViewport(SkRect& viewport); + void setViewport(SkRect& viewport, float scale); float zValue(const TransformationMatrix& drawMatrix, float w, float h); // For drawQuad and drawLayerQuad, they can handle 3 cases for now: @@ -88,6 +88,18 @@ public: contrast = MAX_CONTRAST; m_contrast = contrast; } + void setWebViewMatrix(const float* matrix, bool alphaLayer); + + // This delta is the delta from the layout pos and the current animation pos. + // Basically, in terms of layout, the webview is still in the original layout + // pos, as without animation. Such that the viewport and visible rect etc are + // still in that pos, too, except the clipping info. + // Our rendering approach is after applying all the matrix, webView is + // rendered as if it was at the original layout pos, but then offset the + // glViewport to match the animation. + void calculateAnimationDelta(); + int getAnimationDeltaX() { return m_animationDelta.x(); } + int getAnimationDeltaY() { return m_animationDelta.y(); } private: GLuint loadShader(GLenum shaderType, const char* pSource); @@ -158,6 +170,22 @@ private: GLint m_hPosition; GLint m_hPositionInverted; GLint m_hVideoPosition; + + bool m_alphaLayer; + TransformationMatrix m_webViewMatrix; + float m_currentScale; + + // After the webViewTranform, we need to reposition the rect to match our viewport. + // Basically, the webViewTransformMatrix should apply on the screen resolution. + // So we start by doing the scale and translate to get each tile into screen coordinates. + // After applying the webViewTransformMatrix, b/c the way it currently set up + // for scroll and titlebar, we need to offset both of them. + // Finally, map everything back to (-1, 1) by using the m_projectionMatrix. + // TODO: Given that m_webViewMatrix contains most of the tranformation + // information, we should be able to get rid of some parameter we got from + // Java side and simplify our code. + TransformationMatrix m_repositionMatrix; + IntPoint m_animationDelta; }; } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/android/TestExport.h b/Source/WebCore/platform/graphics/android/TestExport.h new file mode 100644 index 0000000..15d7cc3 --- /dev/null +++ b/Source/WebCore/platform/graphics/android/TestExport.h @@ -0,0 +1,32 @@ +/* + * Copyright 2011, 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 TestExport_h +#define TestExport_h + +// classes used outside of the .so, in tests, are declared with this attribute +#define TEST_EXPORT __attribute__((visibility("default"))) + +#endif // #define TestExport_h diff --git a/Source/WebCore/platform/graphics/android/TexturesGenerator.cpp b/Source/WebCore/platform/graphics/android/TexturesGenerator.cpp index 0820688..bccb99b 100644 --- a/Source/WebCore/platform/graphics/android/TexturesGenerator.cpp +++ b/Source/WebCore/platform/graphics/android/TexturesGenerator.cpp @@ -184,11 +184,10 @@ bool TexturesGenerator::threadLoop() m_currentOperation->run(); } + QueuedOperation* oldOperation = m_currentOperation; mRequestedOperationsLock.lock(); - if (m_currentOperation) { - delete m_currentOperation; + if (m_currentOperation) m_currentOperation = 0; - } if (!mRequestedOperations.size()) stop = true; if (m_waitForCompletion) { @@ -197,7 +196,8 @@ bool TexturesGenerator::threadLoop() mRequestedOperationsCond.signal(); } mRequestedOperationsLock.unlock(); - + if (oldOperation) + delete oldOperation; // delete outside lock } XLOG("threadLoop empty"); diff --git a/Source/WebCore/platform/graphics/android/TilePainter.h b/Source/WebCore/platform/graphics/android/TilePainter.h index 91030cb..4d0f5dc 100644 --- a/Source/WebCore/platform/graphics/android/TilePainter.h +++ b/Source/WebCore/platform/graphics/android/TilePainter.h @@ -27,6 +27,7 @@ #define TilePainter_h #include "TransformationMatrix.h" +#include "SkRefCnt.h" class SkCanvas; @@ -41,6 +42,15 @@ public: virtual const TransformationMatrix* transform() { return 0; } }; +class SurfacePainter : public SkRefCnt { +public: + virtual ~SurfacePainter() { } + virtual const TransformationMatrix* transform() { return 0; } + virtual float opacity() { return 1.0; } + enum SurfaceType { PaintedSurface, ImageSurface }; + virtual SurfaceType type() { return PaintedSurface; } +}; + } #endif // TilePainter_h diff --git a/Source/WebCore/platform/graphics/android/TiledPage.cpp b/Source/WebCore/platform/graphics/android/TiledPage.cpp index 3c262d4..31a0593 100644 --- a/Source/WebCore/platform/graphics/android/TiledPage.cpp +++ b/Source/WebCore/platform/graphics/android/TiledPage.cpp @@ -68,6 +68,7 @@ TiledPage::TiledPage(int id, GLWebViewState* state) , m_latestPictureInval(0) , m_prepare(false) , m_isPrefetchPage(false) + , m_willDraw(false) { m_baseTiles = new BaseTile[TilesManager::getMaxTextureAllocation() + 1]; #ifdef DEBUG_COUNT @@ -241,9 +242,6 @@ void TiledPage::prepare(bool goingDown, bool goingLeft, const SkIRect& tileBound int nbTilesWidth = tileBounds.width(); int nbTilesHeight = tileBounds.height(); - int lastTileX = tileBounds.fRight - 1; - int lastTileY = tileBounds.fBottom - 1; - // Expand number of tiles to allow tiles outside of viewport to be prepared for // smoother scrolling. int nTilesToPrepare = nbTilesWidth * nbTilesHeight; @@ -255,26 +253,31 @@ void TiledPage::prepare(bool goingDown, bool goingLeft, const SkIRect& tileBound int expandY = m_glWebViewState->expandedTileBoundsY(); firstTileX -= expandX; - lastTileX += expandX; nbTilesWidth += expandX * 2; firstTileY -= expandY; - lastTileY += expandY; nbTilesHeight += expandY * 2; } - // crop the prepared region to the contents of the base layer - float maxWidthTiles = m_glWebViewState->baseContentWidth() * m_scale / TilesManager::tileWidth(); - float maxHeightTiles = m_glWebViewState->baseContentHeight() * m_scale / TilesManager::tileHeight(); - firstTileX = std::max(0, firstTileX); - firstTileY = std::max(0, firstTileY); - lastTileX = std::min(lastTileX, static_cast<int>(ceilf(maxWidthTiles)) - 1); - lastTileY = std::min(lastTileY, static_cast<int>(ceilf(maxHeightTiles)) - 1); - - m_expandedTileBounds.fLeft = firstTileX; - m_expandedTileBounds.fTop = firstTileY; - m_expandedTileBounds.fRight = lastTileX; - m_expandedTileBounds.fBottom = lastTileY; + // crop the tile bounds in each dimension to the larger of the base layer or viewport + float maxBaseX = m_glWebViewState->baseContentWidth() * m_scale / TilesManager::tileWidth(); + float maxBaseY = m_glWebViewState->baseContentHeight() * m_scale / TilesManager::tileHeight(); + int maxX = std::max(static_cast<int>(ceilf(maxBaseX)), + m_glWebViewState->viewportTileBounds().width()); + int maxY = std::max(static_cast<int>(ceilf(maxBaseY)), + m_glWebViewState->viewportTileBounds().height()); + + // adjust perimeter to not go outside cropped region + if (firstTileX < 0) { + nbTilesWidth += firstTileX; + firstTileX = 0; + } + if (firstTileY < 0) { + nbTilesHeight += firstTileY; + firstTileY = 0; + } + nbTilesWidth = std::min(nbTilesWidth, maxX - firstTileX); + nbTilesHeight = std::min(nbTilesHeight, maxY - firstTileY); // check against corrupted scale values giving bad height/width (use float to avoid overflow) float numTiles = static_cast<float>(nbTilesHeight) * static_cast<float>(nbTilesWidth); @@ -303,7 +306,22 @@ bool TiledPage::hasMissingContent(const SkIRect& tileBounds) return neededTiles > 0; } -bool TiledPage::swapBuffersIfReady(const SkIRect& tileBounds, float scale, SwapMethod swap) +bool TiledPage::isReady(const SkIRect& tileBounds) +{ + int neededTiles = tileBounds.width() * tileBounds.height(); + XLOG("tiled page %p needs %d ready tiles", this, neededTiles); + for (int j = 0; j < m_baseTileSize; j++) { + BaseTile& tile = m_baseTiles[j]; + if (tileBounds.contains(tile.x(), tile.y())) { + if (tile.isTileReady()) + neededTiles--; + } + } + XLOG("tiled page %p still needs %d ready tiles", this, neededTiles); + return neededTiles == 0; +} + +bool TiledPage::swapBuffersIfReady(const SkIRect& tileBounds, float scale) { if (!m_glWebViewState) return false; @@ -316,21 +334,11 @@ bool TiledPage::swapBuffersIfReady(const SkIRect& tileBounds, float scale, SwapM int swaps = 0; bool fullSwap = true; - if (swap == SwapWholePage) { - for (int x = tileBounds.fLeft; x < tileBounds.fRight; x++) { - for (int y = tileBounds.fTop; y < tileBounds.fBottom; y++) { - BaseTile* t = getBaseTile(x, y); - if (!t || !t->isTileReady()) - return false; - } - } - } else { // SwapWhateveryIsReady - for (int x = tileBounds.fLeft; x < tileBounds.fRight; x++) { - for (int y = tileBounds.fTop; y < tileBounds.fBottom; y++) { - BaseTile* t = getBaseTile(x, y); - if (!t || !t->isTileReady()) - fullSwap = false; - } + for (int x = tileBounds.fLeft; x < tileBounds.fRight; x++) { + for (int y = tileBounds.fTop; y < tileBounds.fBottom; y++) { + BaseTile* t = getBaseTile(x, y); + if (!t || !t->isTileReady()) + fullSwap = false; } } @@ -341,15 +349,20 @@ bool TiledPage::swapBuffersIfReady(const SkIRect& tileBounds, float scale, SwapM swaps++; } - XLOG("%p %s swapped %d textures, returning true", - this, (swap == SwapWholePage) ? "whole page" : "greedy swap", swaps); + XLOG("%p greedy swapped %d textures, returning true", this, swaps); return fullSwap; } +void TiledPage::prepareForDrawGL(float transparency, const SkIRect& tileBounds) +{ + m_willDraw = true; + m_transparency = transparency; + m_tileBounds = tileBounds; +} -void TiledPage::draw(float transparency, const SkIRect& tileBounds) +void TiledPage::drawGL() { - if (!m_glWebViewState) + if (!m_glWebViewState || m_transparency == 0 || !m_willDraw) return; const float tileWidth = TilesManager::tileWidth() * m_invScale; @@ -357,7 +370,7 @@ void TiledPage::draw(float transparency, const SkIRect& tileBounds) for (int j = 0; j < m_baseTileSize; j++) { BaseTile& tile = m_baseTiles[j]; - bool tileInView = tileBounds.contains(tile.x(), tile.y()); + bool tileInView = m_tileBounds.contains(tile.x(), tile.y()); if (tileInView) { SkRect rect; rect.fLeft = tile.x() * tileWidth; @@ -365,11 +378,12 @@ void TiledPage::draw(float transparency, const SkIRect& tileBounds) rect.fRight = rect.fLeft + tileWidth; rect.fBottom = rect.fTop + tileHeight; - tile.draw(transparency, rect, m_scale); + tile.draw(m_transparency, rect, m_scale); } TilesManager::instance()->getProfiler()->nextTile(tile, m_invScale, tileInView); } + m_willDraw = false; // don't redraw until re-prepared } bool TiledPage::paint(BaseTile* tile, SkCanvas* canvas, unsigned int* pictureUsed) diff --git a/Source/WebCore/platform/graphics/android/TiledPage.h b/Source/WebCore/platform/graphics/android/TiledPage.h index 960f3d5..791e1f6 100644 --- a/Source/WebCore/platform/graphics/android/TiledPage.h +++ b/Source/WebCore/platform/graphics/android/TiledPage.h @@ -55,10 +55,6 @@ public: ExpandedBounds = 0, VisibleBounds = 1 }; - enum SwapMethod { - SwapWhateverIsReady = 0, - SwapWholePage = 1 - }; TiledPage(int id, GLWebViewState* state); ~TiledPage(); @@ -76,10 +72,14 @@ public: // returns true if the page can't draw the entire region (may still be stale) bool hasMissingContent(const SkIRect& tileBounds); + bool isReady(const SkIRect& tileBounds); + // swap 'buffers' by swapping each modified texture - bool swapBuffersIfReady(const SkIRect& tileBounds, float scale, SwapMethod swap); + bool swapBuffersIfReady(const SkIRect& tileBounds, float scale); + // save the transparency and bounds to be drawn in drawGL() + void prepareForDrawGL(float transparency, const SkIRect& tileBounds); // draw the page on the screen - void draw(float transparency, const SkIRect& tileBounds); + void drawGL(); // TilePainter implementation // used by individual tiles to generate the bitmap for their tile @@ -97,7 +97,6 @@ public: void discardTextures(); void updateBaseTileSize(); bool scrollingDown() { return m_scrollingDown; } - SkIRect* expandedTileBounds() { return &m_expandedTileBounds; } bool isPrefetchPage() { return m_isPrefetchPage; } void setIsPrefetchPage(bool isPrefetch) { m_isPrefetchPage = isPrefetch; } @@ -128,8 +127,12 @@ private: unsigned int m_latestPictureInval; bool m_prepare; bool m_scrollingDown; - SkIRect m_expandedTileBounds; bool m_isPrefetchPage; + + // info saved in prepare, used in drawGL() + bool m_willDraw; + SkIRect m_tileBounds; + float m_transparency; }; } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/android/TiledTexture.cpp b/Source/WebCore/platform/graphics/android/TiledTexture.cpp index e1e5ec9..d538416 100644 --- a/Source/WebCore/platform/graphics/android/TiledTexture.cpp +++ b/Source/WebCore/platform/graphics/android/TiledTexture.cpp @@ -32,6 +32,7 @@ #include "PaintedSurface.h" #include "PaintTileOperation.h" #include "SkCanvas.h" +#include "SkPicture.h" #include <cutils/log.h> #include <wtf/CurrentTime.h> @@ -54,7 +55,17 @@ namespace WebCore { -bool TiledTexture::ready() { +TiledTexture::~TiledTexture() +{ + SkSafeUnref(m_paintingPicture); +#ifdef DEBUG_COUNT + ClassTracker::instance()->decrement("TiledTexture"); +#endif + removeTiles(); +} + +bool TiledTexture::ready() +{ bool tilesAllReady = true; bool tilesVisible = false; for (unsigned int i = 0; i < m_tiles.size(); i++) { @@ -71,10 +82,23 @@ bool TiledTexture::ready() { // in order to unblock the zooming process. // FIXME: have a better system -- maybe keeping the last scale factor // able to fully render everything + XLOG("TT %p, ready %d, visible %d, texturesRemain %d", + this, tilesAllReady, tilesVisible, + TilesManager::instance()->layerTexturesRemain()); + return !TilesManager::instance()->layerTexturesRemain() || !tilesVisible || tilesAllReady; } +void TiledTexture::swapTiles() +{ + int swaps = 0; + for (unsigned int i = 0; i < m_tiles.size(); i++) + if (m_tiles[i]->swapTexturesIfNeeded()) + swaps++; + XLOG("TT %p swapping, swaps = %d", this, swaps); +} + IntRect TiledTexture::computeTilesArea(IntRect& visibleArea, float scale) { IntRect computedArea; @@ -83,6 +107,8 @@ IntRect TiledTexture::computeTilesArea(IntRect& visibleArea, float scale) ceilf(visibleArea.width() * scale), ceilf(visibleArea.height() * scale)); + XLOG("TT %p prepare, scale %f, area %d x %d", this, scale, area.width(), area.height()); + if (area.width() == 0 && area.height() == 0) { computedArea.setWidth(0); computedArea.setHeight(0); @@ -102,15 +128,13 @@ IntRect TiledTexture::computeTilesArea(IntRect& visibleArea, float scale) } void TiledTexture::prepare(GLWebViewState* state, float scale, bool repaint, - bool startFastSwap, IntRect& area) + bool startFastSwap, IntRect& visibleArea) { if (!m_surface) return; - if (!m_surface->layer()) - return; - - m_area = computeTilesArea(area, scale); + // first, how many tiles do we need + m_area = computeTilesArea(visibleArea, scale); if (m_area.isEmpty()) return; @@ -130,31 +154,6 @@ void TiledTexture::prepare(GLWebViewState* state, float scale, bool repaint, m_scale = scale; - // unlock if tiles all ready - bool tilesAllReady = ready(); - - // startFastSwap=true will swap all ready tiles each - // frame until all visible tiles are up to date - if (tilesAllReady) - m_swapWhateverIsReady = false; - else if (startFastSwap) - m_swapWhateverIsReady = true; - - // swap as appropriate - for (unsigned int i = 0; i < m_tiles.size(); i++) { - BaseTile* tile = m_tiles[i]; - if (tilesAllReady || m_swapWhateverIsReady) - tile->swapTexturesIfNeeded(); - } - - if (tilesAllReady) { - m_updateManager.swap(); - m_dirtyRegion.op(m_updateManager.getPaintingInval(), SkRegion::kUnion_Op); - XLOG("TT %p swapping, now painting with picture %p" - this, m_updateManager.getPaintingPicture()); - m_updateManager.clearPaintingInval(); - } - // apply dirty region to affected tiles if (!m_dirtyRegion.isEmpty()) { for (unsigned int i = 0; i < m_tiles.size(); i++) { @@ -179,12 +178,14 @@ void TiledTexture::prepare(GLWebViewState* state, float scale, bool repaint, void TiledTexture::update(const SkRegion& invalRegion, SkPicture* picture) { - XLOG("TT %p, update manager %p updated with picture %p, region empty %d", - this, &m_updateManager, picture, invalRegion.isEmpty()); - // attempt to update inval and picture. these may be deferred below instead - // of used immediately. - m_updateManager.updateInval(invalRegion); - m_updateManager.updatePicture(picture); + XLOG("TT %p update, current region empty %d, new empty %d, painting picture %p", + this, m_dirtyRegion.isEmpty(), invalRegion.isEmpty(), picture); + m_dirtyRegion.op(invalRegion, SkRegion::kUnion_Op); + + android::Mutex::Autolock lock(m_paintingPictureSync); + SkSafeRef(picture); + SkSafeUnref(m_paintingPicture); + m_paintingPicture = picture; } void TiledTexture::prepareTile(bool repaint, int x, int y) @@ -195,7 +196,7 @@ void TiledTexture::prepareTile(bool repaint, int x, int y) m_tiles.append(tile); } - XLOG("preparing tile %p, painter is this %p", tile, this); + XLOG("preparing tile %p at %d, %d, painter is this %p", tile, x, y, this); tile->setContents(this, x, y, m_scale); // TODO: move below (which is largely the same for layers / tiled page) into @@ -203,8 +204,9 @@ void TiledTexture::prepareTile(bool repaint, int x, int y) if (tile->isDirty() || !tile->frontTexture()) tile->reserveTexture(); - LayerAndroid* layer = m_surface->layer(); - if (tile->backTexture() && tile->isDirty() && !tile->isRepaintPending() && layer) { + + bool hasPicture = m_paintingPicture != 0; // safely read on UI thread, since only UI thread writes + if (tile->backTexture() && tile->isDirty() && !tile->isRepaintPending() && hasPicture) { PaintTileOperation *operation = new PaintTileOperation(tile, m_surface); TilesManager::instance()->scheduleOperation(operation); } @@ -222,12 +224,28 @@ BaseTile* TiledTexture::getTile(int x, int y) int TiledTexture::nbTextures(IntRect& area, float scale) { - IntRect computedTilesArea = computeTilesArea(area, scale); - return computedTilesArea.width() * computedTilesArea.height(); + IntRect tileBounds = computeTilesArea(area, scale); + int numberTextures = tileBounds.width() * tileBounds.height(); + + // add the number of dirty tiles in the bounds, as they take up double + // textures for double buffering + for (unsigned int i = 0; i <m_tiles.size(); i++) { + BaseTile* tile = m_tiles[i]; + if (tile->isDirty() + && tile->x() >= tileBounds.x() && tile->x() <= tileBounds.maxX() + && tile->y() >= tileBounds.y() && tile->y() <= tileBounds.maxY()) + numberTextures++; + } + return numberTextures; } bool TiledTexture::draw() { + if (!m_surface) + return true; + + XLOG("TT %p draw", this); + #ifdef DEBUG TilesManager::instance()->getTilesTracker()->trackLayer(); #endif @@ -254,8 +272,8 @@ bool TiledTexture::draw() rect.fTop = tile->y() * tileHeight; rect.fRight = rect.fLeft + tileWidth; rect.fBottom = rect.fTop + tileHeight; - XLOG(" - [%d], { painter %x vs %x }, tile %x %d,%d at scale %.2f vs %.2f [ready: %d] dirty: %d", - i, this, tile->painter(), tile, tile->x(), tile->y(), + XLOG("- [%d], { painter %x vs %x }, tile %x (layer tile: %d) %d,%d at scale %.2f vs %.2f [ready: %d] dirty: %d", + i, this, tile->painter(), tile, tile->isLayerTile(), tile->x(), tile->y(), tile->scale(), m_scale, tile->isTileReady(), tile->isDirty()); tile->draw(m_surface->opacity(), rect, m_scale); #ifdef DEBUG @@ -270,11 +288,29 @@ bool TiledTexture::draw() bool TiledTexture::paint(BaseTile* tile, SkCanvas* canvas, unsigned int* pictureUsed) { - return m_updateManager.paint(tile, canvas, pictureUsed); + m_paintingPictureSync.lock(); + SkPicture* picture = m_paintingPicture; + SkSafeRef(picture); + m_paintingPictureSync.unlock(); + + if (!picture) { + XLOG("TT %p COULDNT PAINT, NO PICTURE", this); + return false; + } + + XLOG("TT %p painting tile %d, %d with picture %p", this, tile->x(), tile->y(), picture); + + canvas->drawPicture(*picture); + + SkSafeUnref(picture); + + return true; } const TransformationMatrix* TiledTexture::transform() { + if (!m_surface) + return 0; return m_surface->transform(); } @@ -304,7 +340,7 @@ bool TiledTexture::owns(BaseTileTexture* texture) return false; } -DualTiledTexture::DualTiledTexture(PaintedSurface* surface) +DualTiledTexture::DualTiledTexture(SurfacePainter* surface) { m_textureA = new TiledTexture(surface); m_textureB = new TiledTexture(surface); @@ -335,8 +371,8 @@ void DualTiledTexture::prepare(GLWebViewState* state, float scale, bool repaint, m_zooming = true; } - XLOG("\n*** %x Drawing with scale %.2f, futureScale: %.2f, zooming: %d", - this, scale, m_futureScale, m_zooming); + XLOG("Preparing DTT %p with scale %.2f, m_scale %.2f, futureScale: %.2f, zooming: %d", + this, scale, m_scale, m_futureScale, m_zooming); if (m_scale > 0) m_frontTexture->prepare(state, m_scale, repaint, startFastSwap, m_preZoomVisibleArea); @@ -345,6 +381,7 @@ void DualTiledTexture::prepare(GLWebViewState* state, float scale, bool repaint, if (m_zooming && m_zoomUpdateTime < WTF::currentTime()) { m_backTexture->prepare(state, m_futureScale, repaint, startFastSwap, visibleArea); if (m_backTexture->ready()) { + m_backTexture->swapTiles(); swap(); m_zooming = false; } @@ -373,6 +410,12 @@ void DualTiledTexture::update(const SkRegion& dirtyArea, SkPicture* picture) m_frontTexture->update(dirtyArea, picture); } +void DualTiledTexture::swapTiles() +{ + m_backTexture->swapTiles(); + m_frontTexture->swapTiles(); +} + bool DualTiledTexture::owns(BaseTileTexture* texture) { bool owns = m_textureA->owns(texture); diff --git a/Source/WebCore/platform/graphics/android/TiledTexture.h b/Source/WebCore/platform/graphics/android/TiledTexture.h index 5a47cd9..444ab14 100644 --- a/Source/WebCore/platform/graphics/android/TiledTexture.h +++ b/Source/WebCore/platform/graphics/android/TiledTexture.h @@ -34,19 +34,16 @@ #include "SkRegion.h" #include "TextureOwner.h" #include "TilePainter.h" -#include "UpdateManager.h" class SkCanvas; namespace WebCore { -class UpdateManager; -class PaintedSurface; - class TiledTexture : public TilePainter { public: - TiledTexture(PaintedSurface* surface) - : m_surface(surface) + TiledTexture(SurfacePainter* surface) + : m_paintingPicture(0) + , m_surface(surface) , m_prevTileX(0) , m_prevTileY(0) , m_scale(1) @@ -57,18 +54,14 @@ public: ClassTracker::instance()->increment("TiledTexture"); #endif } - virtual ~TiledTexture() - { -#ifdef DEBUG_COUNT - ClassTracker::instance()->decrement("TiledTexture"); -#endif - removeTiles(); - }; + + virtual ~TiledTexture(); IntRect computeTilesArea(IntRect& visibleArea, float scale); void prepare(GLWebViewState* state, float scale, bool repaint, bool startFastSwap, IntRect& visibleArea); + void swapTiles(); bool draw(); void prepareTile(bool repaint, int x, int y); @@ -87,16 +80,18 @@ public: float scale() { return m_scale; } bool ready(); - PaintedSurface* surface() { return m_surface; } - int nbTextures(IntRect& area, float scale); private: bool tileIsVisible(BaseTile* tile); - UpdateManager m_updateManager; + // protect m_paintingPicture + // update() on UI thread modifies + // paint() on texture gen thread reads + android::Mutex m_paintingPictureSync; + SkPicture* m_paintingPicture; - PaintedSurface* m_surface; + SurfacePainter* m_surface; Vector<BaseTile*> m_tiles; // tile coordinates in viewport, set in prepare() @@ -113,14 +108,19 @@ private: class DualTiledTexture { public: - DualTiledTexture(PaintedSurface* surface); + DualTiledTexture(SurfacePainter* surface); ~DualTiledTexture(); void prepare(GLWebViewState* state, float scale, bool repaint, bool startFastSwap, IntRect& area); + void swapTiles(); void swap(); bool draw(); void update(const SkRegion& dirtyArea, SkPicture* picture); bool owns(BaseTileTexture* texture); + bool isReady() + { + return !m_zooming && m_frontTexture->ready(); + } int nbTextures(IntRect& area, float scale) { diff --git a/Source/WebCore/platform/graphics/android/TilesManager.cpp b/Source/WebCore/platform/graphics/android/TilesManager.cpp index acfe9e7..30bd8d0 100644 --- a/Source/WebCore/platform/graphics/android/TilesManager.cpp +++ b/Source/WebCore/platform/graphics/android/TilesManager.cpp @@ -69,7 +69,7 @@ // 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. -#define MAX_TEXTURE_ALLOCATION ((6+TILE_PREFETCH_DISTANCE*2)*(5+TILE_PREFETCH_DISTANCE*2)*2) +#define MAX_TEXTURE_ALLOCATION ((6+TILE_PREFETCH_DISTANCE*2)*(5+TILE_PREFETCH_DISTANCE*2)*4) #define TILE_WIDTH 256 #define TILE_HEIGHT 256 #define LAYER_TILE_WIDTH 256 @@ -77,6 +77,8 @@ #define BYTES_PER_PIXEL 4 // 8888 config +#define LAYER_TEXTURES_DESTROY_TIMEOUT 60 // If we do not need layers for 60 seconds, free the textures + namespace WebCore { GLint TilesManager::getMaxTextureSize() @@ -95,12 +97,15 @@ int TilesManager::getMaxTextureAllocation() TilesManager::TilesManager() : m_layerTexturesRemain(true) , m_maxTextureCount(0) + , m_maxLayerTextureCount(0) , m_generatorReady(false) , m_showVisualIndicator(false) , m_invertedScreen(false) , m_invertedScreenSwitch(false) , m_useMinimalMemory(true) , m_drawGLCount(1) + , m_lastTimeLayersUsed(0) + , m_hasLayerTextures(false) { XLOG("TilesManager ctor"); m_textures.reserveCapacity(MAX_TEXTURE_ALLOCATION); @@ -128,9 +133,9 @@ void TilesManager::allocateTiles() nbTexturesAllocated++; } - int nbLayersTexturesToAllocate = m_maxTextureCount - m_tilesTextures.size(); + int nbLayersTexturesToAllocate = m_maxLayerTextureCount - m_tilesTextures.size(); XLOG("%d layers tiles to allocate (%d textures planned)", - nbLayersTexturesToAllocate, m_maxTextureCount); + nbLayersTexturesToAllocate, m_maxLayerTextureCount); int nbLayersTexturesAllocated = 0; for (int i = 0; i < nbLayersTexturesToAllocate; i++) { BaseTileTexture* texture = new BaseTileTexture( @@ -153,7 +158,6 @@ void TilesManager::allocateTiles() void TilesManager::deallocateTextures(bool allTextures) { const unsigned int max = m_textures.size(); - const unsigned int maxLayer = m_tilesTextures.size(); unsigned long long sparedDrawCount = ~0; // by default, spare no textures if (!allTextures) { @@ -165,19 +169,19 @@ void TilesManager::deallocateTextures(bool allTextures) sparedDrawCount = std::max(sparedDrawCount, owner->drawCount()); } } + deallocateTexturesVector(sparedDrawCount, m_textures); + deallocateTexturesVector(sparedDrawCount, m_tilesTextures); +} +void TilesManager::deallocateTexturesVector(unsigned long long sparedDrawCount, + WTF::Vector<BaseTileTexture*>& textures) +{ + const unsigned int max = textures.size(); int dealloc = 0; for (unsigned int i = 0; i < max; i++) { - TextureOwner* owner = m_textures[i]->owner(); + TextureOwner* owner = textures[i]->owner(); if (!owner || owner->drawCount() < sparedDrawCount) { - m_textures[i]->discardGLTexture(); - dealloc++; - } - } - for (unsigned int i = 0; i < maxLayer; i++) { - TextureOwner* owner = m_tilesTextures[i]->owner(); - if (!owner || owner->drawCount() < sparedDrawCount) { - m_tilesTextures[i]->discardGLTexture(); + textures[i]->discardGLTexture(); dealloc++; } } @@ -185,6 +189,23 @@ void TilesManager::deallocateTextures(bool allTextures) dealloc, max, maxLayer); } +void TilesManager::gatherTexturesNumbers(int* nbTextures, int* nbAllocatedTextures, + int* nbLayerTextures, int* nbAllocatedLayerTextures) +{ + *nbTextures = m_textures.size(); + for (unsigned int i = 0; i < m_textures.size(); i++) { + BaseTileTexture* texture = m_textures[i]; + if (texture->m_ownTextureId) + *nbAllocatedTextures += 1; + } + *nbLayerTextures = m_tilesTextures.size(); + for (unsigned int i = 0; i < m_tilesTextures.size(); i++) { + BaseTileTexture* texture = m_tilesTextures[i]; + if (texture->m_ownTextureId) + *nbAllocatedLayerTextures += 1; + } +} + void TilesManager::printTextures() { #ifdef DEBUG @@ -208,21 +229,6 @@ void TilesManager::printTextures() #endif // DEBUG } -void TilesManager::swapLayersTextures(LayerAndroid* oldTree, LayerAndroid* newTree) -{ - if (oldTree) - oldTree->assignTextureTo(newTree); - - if (newTree) - newTree->createTexture(); - - GLWebViewState* oldState = 0; - if (oldTree && !newTree) - oldState = oldTree->state(); - - paintedSurfacesCleanup(oldState); -} - void TilesManager::addPaintedSurface(PaintedSurface* surface) { m_paintedSurfaces.append(surface); @@ -352,6 +358,12 @@ int TilesManager::maxTextureCount() return m_maxTextureCount; } +int TilesManager::maxLayerTextureCount() +{ + android::Mutex::Autolock lock(m_texturesLock); + return m_maxLayerTextureCount; +} + void TilesManager::setMaxTextureCount(int max) { XLOG("setMaxTextureCount: %d (current: %d, total:%d)", @@ -370,6 +382,36 @@ void TilesManager::setMaxTextureCount(int max) allocateTiles(); } +void TilesManager::setMaxLayerTextureCount(int max) +{ + XLOG("setMaxLayerTextureCount: %d (current: %d, total:%d)", + max, m_maxLayerTextureCount, MAX_TEXTURE_ALLOCATION); + if (!max && m_hasLayerTextures) { + double secondsSinceLayersUsed = WTF::currentTime() - m_lastTimeLayersUsed; + if (secondsSinceLayersUsed > LAYER_TEXTURES_DESTROY_TIMEOUT) { + unsigned long long sparedDrawCount = ~0; // by default, spare no textures + deallocateTexturesVector(sparedDrawCount, m_tilesTextures); + m_hasLayerTextures = false; + } + return; + } + m_lastTimeLayersUsed = WTF::currentTime(); + if (m_maxLayerTextureCount == MAX_TEXTURE_ALLOCATION || + max <= m_maxLayerTextureCount) + return; + + android::Mutex::Autolock lock(m_texturesLock); + + if (max < MAX_TEXTURE_ALLOCATION) + m_maxLayerTextureCount = max; + else + m_maxLayerTextureCount = MAX_TEXTURE_ALLOCATION; + + allocateTiles(); + m_hasLayerTextures = true; +} + + float TilesManager::tileWidth() { return TILE_WIDTH; @@ -412,13 +454,24 @@ void TilesManager::paintedSurfacesCleanup(GLWebViewState* state) WTF::Vector<PaintedSurface*> collect; for (unsigned int i = 0; i < m_paintedSurfaces.size(); i++) { PaintedSurface* surface = m_paintedSurfaces[i]; - if (!surface->layer() || (state && surface->layer()->state() == state)) + + Layer* drawing = surface->drawingLayer(); + Layer* painting = surface->paintingLayer(); + + XLOG("considering PS %p, drawing %p, painting %p", surface, drawing, painting); + + bool drawingMatchesState = state && drawing && (drawing->state() == state); + bool paintingMatchesState = state && painting && (painting->state() == state); + + if ((!painting && !drawing) || drawingMatchesState || paintingMatchesState) { + XLOG("trying to remove PS %p, painting %p, drawing %p, DMS %d, PMS %d", + surface, painting, drawing, drawingMatchesState, paintingMatchesState); collect.append(surface); + } } for (unsigned int i = 0; i < collect.size(); i++) { PaintedSurface* surface = collect[i]; m_paintedSurfaces.remove(m_paintedSurfaces.find(surface)); - surface->removeLayer(); SkSafeUnref(surface); } } diff --git a/Source/WebCore/platform/graphics/android/TilesManager.h b/Source/WebCore/platform/graphics/android/TilesManager.h index 8ae9202..9782fbb 100644 --- a/Source/WebCore/platform/graphics/android/TilesManager.h +++ b/Source/WebCore/platform/graphics/android/TilesManager.h @@ -88,6 +88,8 @@ public: void gatherLayerTextures(); void gatherTextures(); bool layerTexturesRemain() { return m_layerTexturesRemain; } + void gatherTexturesNumbers(int* nbTextures, int* nbAllocatedTextures, + int* nbLayerTextures, int* nbAllocatedLayerTextures); BaseTileTexture* getAvailableTexture(BaseTile* owner); @@ -105,12 +107,14 @@ public: void resetTextureUsage(TiledPage* page); int maxTextureCount(); + int maxLayerTextureCount(); void setMaxTextureCount(int max); + void setMaxLayerTextureCount(int max); static float tileWidth(); static float tileHeight(); static float layerTileWidth(); static float layerTileHeight(); - void paintedSurfacesCleanup(GLWebViewState* state); + void paintedSurfacesCleanup(GLWebViewState* state = 0); void unregisterGLWebViewState(GLWebViewState* state); void allocateTiles(); @@ -190,6 +194,11 @@ public: return m_drawGLCount; } + int getPaintedSurfaceCount() + { + return m_paintedSurfaces.size(); + } + private: TilesManager(); @@ -200,6 +209,9 @@ private: m_generatorReadyCond.wait(m_generatorLock); } + void deallocateTexturesVector(unsigned long long sparedDrawCount, + WTF::Vector<BaseTileTexture*>& textures); + Vector<BaseTileTexture*> m_textures; Vector<BaseTileTexture*> m_availableTextures; @@ -210,6 +222,7 @@ private: Vector<PaintedSurface*> m_paintedSurfaces; int m_maxTextureCount; + int m_maxLayerTextureCount; bool m_generatorReady; @@ -235,6 +248,8 @@ private: TilesProfiler m_profiler; TilesTracker m_tilesTracker; unsigned long long m_drawGLCount; + double m_lastTimeLayersUsed; + bool m_hasLayerTextures; }; } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/android/TransferQueue.cpp b/Source/WebCore/platform/graphics/android/TransferQueue.cpp index 5c4f0f3..b20ec7a 100644 --- a/Source/WebCore/platform/graphics/android/TransferQueue.cpp +++ b/Source/WebCore/platform/graphics/android/TransferQueue.cpp @@ -50,7 +50,7 @@ #endif // DEBUG -#define ST_BUFFER_NUMBER 4 +#define ST_BUFFER_NUMBER 6 // Set this to 1 if we would like to take the new GpuUpload approach which // relied on the glCopyTexSubImage2D instead of a glDraw call @@ -297,8 +297,11 @@ void TransferQueue::updateDirtyBaseTiles() BaseTileTexture* destTexture = 0; if (!obsoleteBaseTile) destTexture = m_transferQueue[index].savedBaseTilePtr->backTexture(); - if (m_transferQueue[index].uploadType == GpuUpload) - m_sharedSurfaceTexture->updateTexImage(); + if (m_transferQueue[index].uploadType == GpuUpload) { + status_t result = m_sharedSurfaceTexture->updateTexImage(); + if (result != OK) + XLOGC("unexpected error: updateTexImage return %d", result); + } m_transferQueue[index].savedBaseTilePtr = 0; m_transferQueue[index].status = emptyItem; if (obsoleteBaseTile) { @@ -491,8 +494,11 @@ void TransferQueue::cleanupTransportQueue() // No matter what the current upload type is, as long as there has // been a Surf Tex enqueue operation, this updateTexImage need to // be called to keep things in sync. - if (m_transferQueue[index].uploadType == GpuUpload) - m_sharedSurfaceTexture->updateTexImage(); + if (m_transferQueue[index].uploadType == GpuUpload) { + status_t result = m_sharedSurfaceTexture->updateTexImage(); + if (result != OK) + XLOGC("unexpected error: updateTexImage return %d", result); + } // since tiles in the queue may be from another webview, remove // their textures so that they will be repainted / retransferred diff --git a/Source/WebCore/platform/graphics/android/TreeManager.cpp b/Source/WebCore/platform/graphics/android/TreeManager.cpp new file mode 100644 index 0000000..b7eaacf --- /dev/null +++ b/Source/WebCore/platform/graphics/android/TreeManager.cpp @@ -0,0 +1,331 @@ +/* + * Copyright 2011, 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. + */ + +#include "config.h" +#include "TreeManager.h" + +#include "Layer.h" +#include "BaseLayerAndroid.h" +#include "ScrollableLayerAndroid.h" +#include "TilesManager.h" + +#include <cutils/log.h> +#include <wtf/CurrentTime.h> +#include <wtf/text/CString.h> + +#undef XLOGC +#define XLOGC(...) android_printLog(ANDROID_LOG_DEBUG, "TreeManager", __VA_ARGS__) + +#ifdef DEBUG + +#undef XLOG +#define XLOG(...) android_printLog(ANDROID_LOG_DEBUG, "TreeManager", __VA_ARGS__) + +#else + +#undef XLOG +#define XLOG(...) + +#endif // DEBUG + +namespace WebCore { + +TreeManager::TreeManager() + : m_drawingTree(0) + , m_paintingTree(0) + , m_queuedTree(0) + , m_fastSwapMode(false) +{ +} + +TreeManager::~TreeManager() +{ + clearTrees(); +} + +// the painting tree has finished painting: +// discard the drawing tree +// swap the painting tree in place of the drawing tree +// and start painting the queued tree +void TreeManager::swap() +{ + // swap can't be called unless painting just finished + ASSERT(m_paintingTree); + + android::Mutex::Autolock lock(m_paintSwapLock); + + XLOG("SWAPPING, D %p, P %p, Q %p", m_drawingTree, m_paintingTree, m_queuedTree); + + // if we have a drawing tree, discard it since the painting tree is done + if (m_drawingTree) { + XLOG("destroying drawing tree %p", m_drawingTree); + m_drawingTree->setIsDrawing(false); + SkSafeUnref(m_drawingTree); + } + + // painting tree becomes the drawing tree + XLOG("drawing tree %p", m_paintingTree); + m_paintingTree->setIsDrawing(true); + if (m_paintingTree->countChildren()) + static_cast<LayerAndroid*>(m_paintingTree->getChild(0))->initAnimations(); + + if (m_queuedTree) { + // start painting with the queued tree + XLOG("now painting tree %p", m_queuedTree); + m_queuedTree->setIsPainting(m_paintingTree); + } + m_drawingTree = m_paintingTree; + m_paintingTree = m_queuedTree; + m_queuedTree = 0; + + TilesManager::instance()->paintedSurfacesCleanup(); + + XLOG("SWAPPING COMPLETE, D %p, P %p, Q %p", m_drawingTree, m_paintingTree, m_queuedTree); +} + +// clear all of the content in the three trees held by the tree manager +void TreeManager::clearTrees() +{ + // remove painted surfaces from any tree in this view, and set trees as no + // longer drawing, to clear ptrs from surfaces to layers + GLWebViewState* oldState = 0; + if (m_drawingTree) { + oldState = m_drawingTree->state(); + m_drawingTree->setIsDrawing(false); + } + if (m_paintingTree) { + oldState = m_paintingTree->state(); + m_paintingTree->setIsDrawing(false); + } + + XLOG("TreeManager %p removing PS from state %p", this, oldState); + TilesManager::instance()->paintedSurfacesCleanup(oldState); + + SkSafeUnref(m_drawingTree); + m_drawingTree = 0; + SkSafeUnref(m_paintingTree); + m_paintingTree = 0; + SkSafeUnref(m_queuedTree); + m_queuedTree = 0; +} + +// a new layer tree has arrived, queue it if we're painting something already, +// or start painting it if we aren't +void TreeManager::updateWithTree(Layer* newTree, bool brandNew) +{ + XLOG("updateWithTree - %p, has children %d, has animations %d", + newTree, newTree && newTree->countChildren(), + newTree && newTree->countChildren() + ? static_cast<LayerAndroid*>(newTree->getChild(0))->hasAnimations() : 0); + + // can't have a queued tree unless have a painting tree too + ASSERT(m_paintingTree || !m_queuedTree); + + SkSafeRef(newTree); + + android::Mutex::Autolock lock(m_paintSwapLock); + + if (!newTree || brandNew) { + clearTrees(); + if (brandNew) { + m_paintingTree = newTree; + m_paintingTree->setIsPainting(m_drawingTree); + } + return; + } + + if (m_queuedTree || m_paintingTree) { + // currently painting, so defer this new tree + if (m_queuedTree) { + // have a queued tree, copy over invals so the regions are + // eventually repainted + m_queuedTree->mergeInvalsInto(newTree); + + XLOG("DISCARDING tree - %p, has children %d, has animations %d", + newTree, newTree && newTree->countChildren(), + newTree && newTree->countChildren() + ? static_cast<LayerAndroid*>(newTree->getChild(0))->hasAnimations() : 0); + } + SkSafeUnref(m_queuedTree); + m_queuedTree = newTree; + return; + } + + // don't have painting tree, paint this one! + m_paintingTree = newTree; + m_paintingTree->setIsPainting(m_drawingTree); +} + +void TreeManager::updateScrollableLayerInTree(Layer* tree, int layerId, int x, int y) +{ + LayerAndroid* layer; + if (tree && tree->countChildren()) { + layer = static_cast<LayerAndroid*>(tree->getChild(0))->findById(layerId); + if (layer && layer->contentIsScrollable()) + static_cast<ScrollableLayerAndroid*>(layer)->scrollTo(x, y); + } +} + +void TreeManager::updateScrollableLayer(int layerId, int x, int y) +{ + updateScrollableLayerInTree(m_queuedTree, layerId, x, y); + updateScrollableLayerInTree(m_paintingTree, layerId, x, y); + updateScrollableLayerInTree(m_drawingTree, layerId, x, y); +} + +bool TreeManager::drawGL(double currentTime, IntRect& viewRect, + SkRect& visibleRect, float scale, + bool enterFastSwapMode, bool* treesSwappedPtr, bool* newTreeHasAnimPtr, + TexturesResult* texturesResultPtr) +{ + m_fastSwapMode |= enterFastSwapMode; + + XLOG("drawGL, D %p, P %p, Q %p, fastSwap %d", + m_drawingTree, m_paintingTree, m_queuedTree, m_fastSwapMode); + + bool ret = false; + bool didTreeSwap = false; + if (m_paintingTree) { + XLOG("preparing painting tree %p", m_paintingTree); + + LayerAndroid* laTree = 0; + if (m_paintingTree->countChildren()) { + laTree = static_cast<LayerAndroid*>(m_paintingTree->getChild(0)); + ret |= laTree->evaluateAnimations(currentTime); + } + + ret |= m_paintingTree->prepare(currentTime, viewRect, + visibleRect, scale); + + if (laTree) + laTree->computeTexturesAmount(texturesResultPtr); + + if (/*!m_fastSwapMode && */ m_paintingTree->isReady()) { + XLOG("have painting tree %p ready, swapping!", m_paintingTree); + didTreeSwap = true; + swap(); + if (treesSwappedPtr) + *treesSwappedPtr = true; + if (laTree && newTreeHasAnimPtr) + *newTreeHasAnimPtr = laTree->hasAnimations(); + } + } else if (m_drawingTree) { + XLOG("preparing drawing tree %p", m_drawingTree); + ret |= m_drawingTree->prepare(currentTime, viewRect, + visibleRect, scale); + if (m_drawingTree->countChildren()) { + LayerAndroid* laTree = static_cast<LayerAndroid*>(m_drawingTree->getChild(0)); + laTree->computeTexturesAmount(texturesResultPtr); + } + } + + + if (m_drawingTree) { + bool drawingReady = didTreeSwap || m_drawingTree->isReady(); + + if (didTreeSwap || m_fastSwapMode || (drawingReady && !m_paintingTree)) + m_drawingTree->swapTiles(); + + if (drawingReady) { + // exit fast swap mode, as content is up to date + m_fastSwapMode = false; + } else { + // drawing isn't ready, must redraw + ret = true; + } + + if (m_drawingTree->countChildren()) { + LayerAndroid* laTree = static_cast<LayerAndroid*>(m_drawingTree->getChild(0)); + ret |= laTree->evaluateAnimations(currentTime); + } + XLOG("drawing tree %p", m_drawingTree); + ret |= m_drawingTree->drawGL(viewRect, visibleRect, scale); + } else if (m_paintingTree && m_paintingTree->state()) { + // Dont have a drawing tree, draw white background + Color defaultBackground = Color::white; + m_paintingTree->state()->drawBackground(defaultBackground); + } + + if (m_paintingTree) { + XLOG("still have painting tree %p", m_paintingTree); + return true; + } + + return ret; +} + +int TreeManager::getTotalPaintedSurfaceCount() +{ + return TilesManager::instance()->getPaintedSurfaceCount(); +} + +// draw for base tile - called on TextureGeneration thread +void TreeManager::drawCanvas(SkCanvas* canvas, bool drawLayers) +{ + BaseLayerAndroid* paintingTree = 0; + m_paintSwapLock.lock(); + if (m_paintingTree) + paintingTree = static_cast<BaseLayerAndroid*>(m_paintingTree); + else + paintingTree = static_cast<BaseLayerAndroid*>(m_drawingTree); + SkSafeRef(paintingTree); + m_paintSwapLock.unlock(); + + if (!paintingTree) + return; + + + paintingTree->drawCanvas(canvas); + + if (drawLayers && paintingTree->countChildren()) { + // draw the layers onto the canvas as well + Layer* layers = paintingTree->getChild(0); + static_cast<LayerAndroid*>(layers)->drawCanvas(canvas); + } + + SkSafeUnref(paintingTree); +} + +int TreeManager::baseContentWidth() +{ + if (m_paintingTree) { + return static_cast<BaseLayerAndroid*>(m_paintingTree)->content()->width(); + } else if (m_drawingTree) { + return static_cast<BaseLayerAndroid*>(m_drawingTree)->content()->width(); + } + return 0; +} + +int TreeManager::baseContentHeight() +{ + if (m_paintingTree) { + return static_cast<BaseLayerAndroid*>(m_paintingTree)->content()->height(); + } else if (m_drawingTree) { + return static_cast<BaseLayerAndroid*>(m_drawingTree)->content()->height(); + } + return 0; +} + +} // namespace WebCore diff --git a/Source/WebCore/platform/graphics/android/UpdateManager.h b/Source/WebCore/platform/graphics/android/TreeManager.h index 6254184..83d5300 100644 --- a/Source/WebCore/platform/graphics/android/UpdateManager.h +++ b/Source/WebCore/platform/graphics/android/TreeManager.h @@ -23,65 +23,61 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef UpdateManager_h -#define UpdateManager_h +#ifndef TreeManager_h +#define TreeManager_h +#include "TestExport.h" +#include <utils/threads.h> +#include "PerformanceMonitor.h" + +class Layer; +class SkRect; class SkCanvas; -class SkRegion; namespace WebCore { -class BaseTile; - -// UpdateManager Architecture +class IntRect; +class TexturesResult; -// The UpdateManager is used to defer updates and invalidations to a layer, -// so that the layer can finish painting one version completely without being -// interrupted by new invals/content - -class UpdateManager { +class TEST_EXPORT TreeManager { public: - UpdateManager(); + TreeManager(); - ~UpdateManager(); + ~TreeManager(); - // swap deferred members in place of painting members - void swap(); + void updateWithTree(Layer* tree, bool brandNew); - void updateInval(const SkRegion& invalRegion); + void updateScrollableLayer(int layerId, int x, int y); - void updatePicture(SkPicture* picture); + bool drawGL(double currentTime, IntRect& viewRect, + SkRect& visibleRect, float scale, + bool enterFastSwapMode, bool* treesSwappedPtr, bool* newTreeHasAnimPtr, + TexturesResult* texturesResultPtr); - bool paint(BaseTile* tile, SkCanvas* canvas, unsigned int* pictureUsed); + void drawCanvas(SkCanvas* canvas, bool drawLayers); - void clearPaintingInval(); + // used in debugging (to avoid exporting TilesManager symbols) + static int getTotalPaintedSurfaceCount(); - const SkRegion& getPaintingInval() { - return m_paintingInval; - } - - SkPicture* getPaintingPicture() { - // NOTE: only modified on UI thread, so UI thread access doesn't need mutex - return m_paintingPicture; - } + int baseContentWidth(); + int baseContentHeight(); private: - // protect m_paintingPicture - // swap() on UI thread modifies - // paint() on texture gen thread reads - android::Mutex m_paintingPictureSync; - SkPicture* m_paintingPicture; + static void updateScrollableLayerInTree(Layer* tree, int layerId, int x, int y); + + void swap(); + void clearTrees(); - // inval region to be redrawn with the current paintingPicture - SkRegion m_paintingInval; + android::Mutex m_paintSwapLock; - // most recently received picture, moved into painting on swap() - SkPicture* m_deferredPicture; + Layer* m_drawingTree; + Layer* m_paintingTree; + Layer* m_queuedTree; - // all invals since last swap(), merged with painting inval on swap() - SkRegion m_deferredInval; + bool m_fastSwapMode; + PerformanceMonitor m_perf; }; } // namespace WebCore -#endif //#define UpdateManager_h +#endif //#define TreeManager_h diff --git a/Source/WebCore/platform/graphics/android/UpdateManager.cpp b/Source/WebCore/platform/graphics/android/UpdateManager.cpp deleted file mode 100644 index 1c20f1f..0000000 --- a/Source/WebCore/platform/graphics/android/UpdateManager.cpp +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright 2011, 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. - */ - -#include "config.h" -#include "PaintedSurface.h" - -#include "LayerAndroid.h" -#include "TilesManager.h" -#include "SkCanvas.h" -#include "SkPicture.h" - -#include <cutils/log.h> -#include <wtf/CurrentTime.h> -#include <wtf/text/CString.h> - -#undef XLOGC -#define XLOGC(...) android_printLog(ANDROID_LOG_DEBUG, "UpdateManager", __VA_ARGS__) - -#ifdef DEBUG - -#undef XLOG -#define XLOG(...) android_printLog(ANDROID_LOG_DEBUG, "UpdateManager", __VA_ARGS__) - -#else - -#undef XLOG -#define XLOG(...) - -#endif // DEBUG - -namespace WebCore { - -UpdateManager::UpdateManager() - : m_paintingPicture(0) - , m_deferredPicture(0) -{ -} - -UpdateManager::~UpdateManager() -{ - SkSafeUnref(m_paintingPicture); - SkSafeUnref(m_deferredPicture); -} - -void UpdateManager::swap() -{ - m_paintingInval.op(m_deferredInval, SkRegion::kUnion_Op); - m_deferredInval.setEmpty(); - - android::Mutex::Autolock lock(m_paintingPictureSync); - if (m_deferredPicture) { - XLOG("unlock of updatemanager %p, was painting %p, now painting %p", - this, m_paintingPicture, m_deferredPicture); - SkSafeUnref(m_paintingPicture); - m_paintingPicture = m_deferredPicture; - m_deferredPicture = 0; - } -} - -void UpdateManager::updateInval(const SkRegion& invalRegion) -{ - m_deferredInval.op(invalRegion, SkRegion::kUnion_Op); -} - -void UpdateManager::updatePicture(SkPicture* picture) -{ - SkSafeRef(picture); - SkSafeUnref(m_deferredPicture); - m_deferredPicture = picture; -} - -bool UpdateManager::paint(BaseTile* tile, SkCanvas* canvas, unsigned int* pictureUsed) -{ - m_paintingPictureSync.lock(); - SkPicture* picture = m_paintingPicture; - SkSafeRef(picture); - m_paintingPictureSync.unlock(); - - XLOG("UpdateManager %p painting with picture %p", this, picture); - - if (!picture) - return false; - - canvas->drawPicture(*picture); - - // TODO: visualization layer diagonals - - SkSafeUnref(picture); - return true; -} - - -void UpdateManager::clearPaintingInval() -{ - m_paintingInval.setEmpty(); -} - -} // namespace WebCore diff --git a/Source/WebCore/platform/graphics/android/VideoLayerAndroid.cpp b/Source/WebCore/platform/graphics/android/VideoLayerAndroid.cpp index 9576ed1..482d711 100644 --- a/Source/WebCore/platform/graphics/android/VideoLayerAndroid.cpp +++ b/Source/WebCore/platform/graphics/android/VideoLayerAndroid.cpp @@ -142,7 +142,7 @@ GLuint VideoLayerAndroid::createBackgroundTexture() return texture; } -bool VideoLayerAndroid::drawGL(GLWebViewState* glWebViewState, SkMatrix& matrix) +bool VideoLayerAndroid::drawGL() { // Lazily allocated the textures. if (!m_createdTexture) { @@ -224,7 +224,7 @@ bool VideoLayerAndroid::drawGL(GLWebViewState* glWebViewState, SkMatrix& matrix) } } - return drawChildrenGL(glWebViewState, matrix); + return drawChildrenGL(); } } diff --git a/Source/WebCore/platform/graphics/android/VideoLayerAndroid.h b/Source/WebCore/platform/graphics/android/VideoLayerAndroid.h index abc1c13..8a064bb 100644 --- a/Source/WebCore/platform/graphics/android/VideoLayerAndroid.h +++ b/Source/WebCore/platform/graphics/android/VideoLayerAndroid.h @@ -56,7 +56,7 @@ public: virtual LayerAndroid* copy() const { return new VideoLayerAndroid(*this); } // The following 3 functions are called in UI thread only. - virtual bool drawGL(GLWebViewState*, SkMatrix& matrix); + virtual bool drawGL(); void setSurfaceTexture(sp<SurfaceTexture> texture, int textureName, PlayerState playerState); GLuint createBackgroundTexture(); GLuint createSpinnerOuterTexture(); diff --git a/Source/WebCore/rendering/RenderBlockLineLayout.cpp b/Source/WebCore/rendering/RenderBlockLineLayout.cpp index d4e2aa3..df20063 100644 --- a/Source/WebCore/rendering/RenderBlockLineLayout.cpp +++ b/Source/WebCore/rendering/RenderBlockLineLayout.cpp @@ -812,7 +812,7 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintLogica else { #ifdef ANDROID_LAYOUT // ignore text wrap for textField or menuList - if (doTextWrap && (o->isTextField() || o->isMenuList() || o->isFloating())) + if (doTextWrap && (o->isTextField() || o->isMenuList())) doTextWrap = false; #endif if (o->isFloating()) diff --git a/Source/WebCore/rendering/RenderBox.cpp b/Source/WebCore/rendering/RenderBox.cpp index 80d5699..fb1dd2c 100644 --- a/Source/WebCore/rendering/RenderBox.cpp +++ b/Source/WebCore/rendering/RenderBox.cpp @@ -1562,6 +1562,13 @@ void RenderBox::computeLogicalWidth() // https://bugs.webkit.org/show_bug.cgi?id=46418 if (hasOverrideSize() && parent()->style()->boxOrient() == HORIZONTAL && parent()->isFlexibleBox() && parent()->isFlexingChildren()) { +#if PLATFORM(ANDROID) + // Strangely, the slider is get overrided as width 0 on youtube.com + // The wrong width will cause the touch hit test for the slider failed. + // This WAR should be safe since it is only targeted to slider. + // TODO: root cause this and see if any webkit update fix this. + if (!(isSlider() && overrideSize() == 0)) +#endif setLogicalWidth(overrideSize()); return; } diff --git a/Source/WebCore/rendering/RenderHTMLCanvas.cpp b/Source/WebCore/rendering/RenderHTMLCanvas.cpp index de2a2c1..ada79e9 100644 --- a/Source/WebCore/rendering/RenderHTMLCanvas.cpp +++ b/Source/WebCore/rendering/RenderHTMLCanvas.cpp @@ -47,9 +47,13 @@ RenderHTMLCanvas::RenderHTMLCanvas(HTMLCanvasElement* element) bool RenderHTMLCanvas::requiresLayer() const { +#if PLATFORM(ANDROID) + return true; +#endif + if (RenderReplaced::requiresLayer()) return true; - + HTMLCanvasElement* canvas = static_cast<HTMLCanvasElement*>(node()); return canvas && canvas->renderingContext() && canvas->renderingContext()->isAccelerated(); } diff --git a/Source/WebCore/rendering/RenderLayer.cpp b/Source/WebCore/rendering/RenderLayer.cpp index 904b1b2..cdc4c05 100644 --- a/Source/WebCore/rendering/RenderLayer.cpp +++ b/Source/WebCore/rendering/RenderLayer.cpp @@ -1419,8 +1419,15 @@ void RenderLayer::scrollTo(int x, int y) } // Just schedule a full repaint of our object. +#if ENABLE(ANDROID_OVERFLOW_SCROLL) + // On android, scrollable areas are put on composited layers, so we + // do not need to repaint simply because we are scrolling + if (view && !hasOverflowScroll()) + renderer()->repaintUsingContainer(repaintContainer, rectForRepaint); +#else if (view) renderer()->repaintUsingContainer(repaintContainer, rectForRepaint); +#endif // Schedule the scroll DOM event. renderer()->node()->document()->eventQueue()->enqueueOrDispatchScrollEvent(renderer()->node(), EventQueue::ScrollEventElementTarget); diff --git a/Source/WebCore/rendering/RenderLayerCompositor.cpp b/Source/WebCore/rendering/RenderLayerCompositor.cpp index 4f4f553..06fa0f6 100644 --- a/Source/WebCore/rendering/RenderLayerCompositor.cpp +++ b/Source/WebCore/rendering/RenderLayerCompositor.cpp @@ -650,7 +650,7 @@ bool RenderLayerCompositor::checkForFixedLayers(Vector<RenderLayer*>* list, bool IntRect bounds = aLayer->renderer()->localToAbsoluteQuad( FloatRect(aLayer->localBoundingBox())).enclosingBoundingBox(); if (bounds.contains(currentLayerBounds) - && needsToBeComposited(aLayer)) { + && needsToBeComposited(aLayer) && aLayer->isStackingContext()) { needComposite = false; break; } @@ -724,15 +724,7 @@ void RenderLayerCompositor::computeCompositingRequirements(RenderLayer* layer, O if (layer->isFixed()) compositingState.m_hasFixedElement = true; #endif - -#if ENABLE(ANDROID_OVERFLOW_SCROLL) - // we don't want to signal that the subtree is compositing if the reason - // is because the layer is an overflow layer -- doing so would trigger - // all the above layers to be composited unnecessarily - if (willBeComposited && !layer->hasOverflowScroll() && !layer->isFixed()) { -#else if (willBeComposited) { -#endif // Tell the parent it has compositing descendants. compositingState.m_subtreeIsCompositing = true; // This layer now acts as the ancestor for kids. @@ -764,7 +756,18 @@ void RenderLayerCompositor::computeCompositingRequirements(RenderLayer* layer, O // If we have to make a layer for this child, make one now so we can have a contents layer // (since we need to ensure that the -ve z-order child renders underneath our contents). +#ifdef ANDROID + // Normally we try to reduce the number of layers by not promoting all fixed + // or scrollable elements to their own compositing layer. But in the case that + // we have such an element in the negative z-order, we must make it a layer + // otherwise the content will be painted at a higher z-index. This breaks pages + // that set a large image with a z-index of -1 to implement a background image, + // for example. + bool childRequiresCompositing = childState.m_hasFixedElement || childState.m_hasScrollableElement; + if (!willBeComposited && (childState.m_subtreeIsCompositing || childRequiresCompositing)) { +#else if (!willBeComposited && childState.m_subtreeIsCompositing) { +#endif // make layer compositing layer->setMustOverlapCompositedLayers(true); childState.m_compositingAncestor = layer; @@ -1381,6 +1384,8 @@ bool RenderLayerCompositor::requiresCompositingForAndroidLayers(const RenderLaye if (layer->isFixed()) return true; #endif + if (layer->renderer()->isCanvas()) + return true; return false; } #endif @@ -1573,7 +1578,12 @@ bool RenderLayerCompositor::requiresCompositingForAnimation(RenderObject* render return false; if (AnimationController* animController = renderer->animation()) { +#if PLATFORM(ANDROID) + // android renders an opacity animation much faster if it's composited + return (animController->isRunningAnimationOnRenderer(renderer, CSSPropertyOpacity)) +#else return (animController->isRunningAnimationOnRenderer(renderer, CSSPropertyOpacity) && inCompositingMode()) +#endif || animController->isRunningAnimationOnRenderer(renderer, CSSPropertyWebkitTransform); } return false; diff --git a/Source/WebCore/rendering/svg/SVGInlineTextBox.cpp b/Source/WebCore/rendering/svg/SVGInlineTextBox.cpp index bc550a6..bb34652 100644 --- a/Source/WebCore/rendering/svg/SVGInlineTextBox.cpp +++ b/Source/WebCore/rendering/svg/SVGInlineTextBox.cpp @@ -573,11 +573,18 @@ void SVGInlineTextBox::paintDecorationWithStyle(GraphicsContext* context, ETextD width *= scalingFactor; decorationOrigin.scale(scalingFactor, scalingFactor); +#if PLATFORM(ANDROID) + // Android does not support GraphicsContext::setCTM(). + AffineTransform scaleTransform; + scaleTransform.scale(1 / scalingFactor); + context->concatCTM(scaleTransform); +#else AffineTransform newTransform = context->getCTM(); newTransform.scale(1 / scalingFactor); normalizeTransform(newTransform); context->setCTM(newTransform); +#endif } decorationOrigin.move(0, -scaledFontMetrics.floatAscent() + positionOffsetForDecoration(decoration, scaledFontMetrics, thickness)); @@ -622,6 +629,13 @@ void SVGInlineTextBox::paintTextWithShadows(GraphicsContext* context, RenderStyl AffineTransform originalTransform; if (scalingFactor != 1) { +#if PLATFORM(ANDROID) + // Android does not support GraphicsContext::setCTM(). + context->save(); + AffineTransform scaleTransform; + scaleTransform.scale(1 / scalingFactor); + context->concatCTM(scaleTransform); +#else originalTransform = context->getCTM(); AffineTransform newTransform = originalTransform; @@ -629,12 +643,18 @@ void SVGInlineTextBox::paintTextWithShadows(GraphicsContext* context, RenderStyl normalizeTransform(newTransform); context->setCTM(newTransform); +#endif } scaledFont.drawText(context, textRun, textOrigin + extraOffset, startPosition, endPosition); if (scalingFactor != 1) +#if PLATFORM(ANDROID) + // Android does not support GraphicsContext::setCTM(). + context->restore(); +#else context->setCTM(originalTransform); +#endif restoreGraphicsContextAfterTextPainting(context, textRun); diff --git a/Source/WebCore/tests/Android.mk b/Source/WebCore/tests/Android.mk new file mode 100644 index 0000000..c98a9a3 --- /dev/null +++ b/Source/WebCore/tests/Android.mk @@ -0,0 +1,49 @@ +# Build the unit tests. +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +# Build the unit tests. +test_src_files := \ + TreeManager_test.cpp + +shared_libraries := \ + libcutils \ + libwebcore \ + libskia \ + libstlport + +static_libraries := \ + libgtest \ + libgtest_main + +c_includes := \ + bionic \ + bionic/libstdc++/include \ + external/gtest/include \ + external/stlport/stlport \ + external/skia/include/core \ + external/icu4c/common \ + $(LOCAL_PATH)/../../JavaScriptCore \ + $(LOCAL_PATH)/../../JavaScriptCore/wtf \ + $(LOCAL_PATH)/.. \ + $(LOCAL_PATH)/../platform/graphics \ + $(LOCAL_PATH)/../platform/graphics/transforms \ + $(LOCAL_PATH)/../platform/graphics/android + + # external/webkit/Source/WebCore/platform/graphics/android + +module_tags := eng tests + +$(foreach file,$(test_src_files), \ + $(eval include $(CLEAR_VARS)) \ + $(eval LOCAL_SHARED_LIBRARIES := $(shared_libraries)) \ + $(eval LOCAL_STATIC_LIBRARIES := $(static_libraries)) \ + $(eval LOCAL_C_INCLUDES := $(c_includes)) \ + $(eval LOCAL_SRC_FILES := $(file)) \ + $(eval LOCAL_MODULE := $(notdir $(file:%.cpp=%))) \ + $(eval LOCAL_MODULE_TAGS := $(module_tags)) \ + $(eval include $(BUILD_EXECUTABLE)) \ +) + +# Build the manual test programs. +include $(call all-makefiles-under, $(LOCAL_PATH)) diff --git a/Source/WebCore/tests/TreeManager_test.cpp b/Source/WebCore/tests/TreeManager_test.cpp new file mode 100644 index 0000000..3837627 --- /dev/null +++ b/Source/WebCore/tests/TreeManager_test.cpp @@ -0,0 +1,407 @@ +/* + * Copyright 2011, 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. + */ + +#include "config.h" + +#include <gtest/gtest.h> + +#include "SkRefCnt.h" +#include "TransformationMatrix.h" +#include "IntRect.h" +#include "Layer.h" +#include "LayerAndroid.h" +#include "TreeManager.h" +#include "SkPicture.h" + +#include <cutils/log.h> +#include <wtf/text/CString.h> +#define XLOGC(...) android_printLog(ANDROID_LOG_DEBUG, "TreeManager_test", __VA_ARGS__) + +namespace WebCore { + +// Used for testing simple cases for tree painting, drawing, swapping +class TestLayer : public Layer { +public: + TestLayer() + : m_isDrawing(false) + , m_isPainting(false) + , m_isDonePainting(false) + , m_drawCount(0) + {} + + bool m_isDrawing; + bool m_isPainting; + bool m_isDonePainting; + double m_drawCount; + + bool drawGL(WebCore::IntRect& viewRect, SkRect& visibleRect, float scale) { + m_drawCount++; + return false; + } + + bool isReady() { + return m_isDonePainting; + } + + void setIsDrawing(bool isDrawing) { + m_isDrawing = isDrawing; + if (isDrawing) + m_isPainting = false; + } + + void setIsPainting(Layer* drawingTree) { + m_isPainting = true; + m_isDonePainting = false; + setIsDrawing(false); + } +}; + +// Used for testing complex trees, and painted surfaces +class TestLayerAndroid : public LayerAndroid { +public: + TestLayerAndroid(SkPicture* picture) : LayerAndroid(picture) + , m_isDonePainting(false) + , m_drawCount(0) + {} + + TestLayerAndroid(const TestLayerAndroid& testLayer) : LayerAndroid(testLayer) + , m_isDonePainting(testLayer.m_isDonePainting) + , m_drawCount(testLayer.m_drawCount) + { + XLOGC("copying TLA %p as %p", &testLayer, this); + } + + bool m_isDonePainting; + double m_drawCount; + + bool drawGL(WebCore::IntRect& viewRect, SkRect& visibleRect, float scale) { + m_drawCount++; + return false; + } + + bool isReady() { + return m_isDonePainting; + } + + LayerAndroid* copy() const { return new TestLayerAndroid(*this); } +}; + +class TreeManagerTest : public testing::Test { +protected: + IntRect m_iRect; + SkRect m_sRect; + double m_scale; + + void allocLayerWithPicture(bool useTestLayer, LayerAndroid** layerHandle, SkPicture** pictureHandle) { + SkPicture* p = new SkPicture(); + p->beginRecording(16,16, 0); + p->endRecording(); + + LayerAndroid* l; + if (useTestLayer) + l = new TestLayerAndroid(p); + else + l = new LayerAndroid(p); + l->setSize(16, 16); + SkSafeUnref(p); // layer takes sole ownership of picture + + if (layerHandle) + *layerHandle = l; + if (pictureHandle) + *pictureHandle = p; + } + + bool drawGL(TreeManager& manager, bool* swappedPtr) { + // call draw gl here in one place, so that when its parameters change, + // the tests only have to be updated in one place + return manager.drawGL(0, m_iRect, m_sRect, m_scale, false, swappedPtr, 0); + } + + virtual void SetUp() { + m_iRect = IntRect(0, 0, 1, 1); + m_sRect = SkRect::MakeWH(1, 1); + m_scale = 1.0; + } + virtual void TearDown() { } +}; + +TEST_F(TreeManagerTest, EmptyTree_DoesntRedraw) { + TreeManager manager; + + drawGL(manager, false); +} + +TEST_F(TreeManagerTest, OneLayerTree_SingleTree_SwapCheck) { + TreeManager manager; + TestLayer layer; + + // initialize with tree, should be painting + manager.updateWithTree(&layer, true); + + ASSERT_TRUE(layer.m_isPainting); + ASSERT_FALSE(layer.m_isDrawing); + + // should not call swap, and return true since content isn't done + for (int i = 1; i < 6; i++) { + bool swapped = false; + ASSERT_TRUE(drawGL(manager, &swapped)); + ASSERT_FALSE(swapped); + ASSERT_EQ(layer.m_drawCount, 0); + } + + layer.m_isDonePainting = true; + + // swap content, should return false since no new picture + bool swapped = false; + ASSERT_FALSE(drawGL(manager, &swapped)); + ASSERT_TRUE(swapped); + ASSERT_EQ(layer.m_drawCount, 1); // verify layer drawn +} + +TEST_F(TreeManagerTest, OneLayerTree_SingleTree_RefCountCorrectly) { + TreeManager manager; + TestLayer* layer = new TestLayer(); + ASSERT_EQ(layer->getRefCnt(), 1); + + // initialize with tree, should be painting + manager.updateWithTree(layer, true); + ASSERT_EQ(layer->getRefCnt(), 2); + + layer->m_isDonePainting = true; + ASSERT_FALSE(drawGL(manager, 0)); + + // should be drawing + ASSERT_EQ(layer->getRefCnt(), 2); + + manager.updateWithTree(0, false); + + // layer should be removed + ASSERT_EQ(layer->getRefCnt(), 1); + SkSafeUnref(layer); +} + +TEST_F(TreeManagerTest, OneLayerTree_TwoTreeFlush_PaintDrawRefCheck) { + TreeManager manager; + TestLayer* firstLayer = new TestLayer(); + TestLayer* secondLayer = new TestLayer(); + ASSERT_EQ(firstLayer->getRefCnt(), 1); + ASSERT_EQ(secondLayer->getRefCnt(), 1); + + ///// ENQUEUE 2 TREES + + // first starts painting + manager.updateWithTree(firstLayer, true); + ASSERT_TRUE(firstLayer->m_isPainting); + ASSERT_FALSE(firstLayer->m_isDrawing); + + // second is queued + manager.updateWithTree(secondLayer, false); + ASSERT_FALSE(secondLayer->m_isPainting); + ASSERT_FALSE(secondLayer->m_isDrawing); + + // nothing changes + ASSERT_TRUE(drawGL(manager, 0)); + + ////////// FIRST FINISHES PAINTING, SWAP THE TREES + + firstLayer->m_isDonePainting = true; + bool swapped = false; + ASSERT_TRUE(drawGL(manager, &swapped)); + ASSERT_TRUE(swapped); + + // first is drawing + ASSERT_EQ(firstLayer->m_drawCount, 1); + ASSERT_FALSE(firstLayer->m_isPainting); + ASSERT_TRUE(firstLayer->m_isDrawing); + ASSERT_EQ(firstLayer->getRefCnt(), 2); + + // second is painting (and hasn't drawn) + ASSERT_EQ(secondLayer->m_drawCount, 0); + ASSERT_TRUE(secondLayer->m_isPainting); + ASSERT_FALSE(secondLayer->m_isDrawing); + ASSERT_EQ(secondLayer->getRefCnt(), 2); + + ////////// SECOND FINISHES PAINTING, SWAP AGAIN + + secondLayer->m_isDonePainting = true; + + // draw again, swap, first should be deleted + swapped = false; + ASSERT_FALSE(drawGL(manager, &swapped)); // no painting layer + ASSERT_TRUE(swapped); + + // first layer gone! + ASSERT_EQ(firstLayer->getRefCnt(), 1); + SkSafeUnref(firstLayer); + + // second is drawing + ASSERT_EQ(secondLayer->m_drawCount, 1); + ASSERT_FALSE(secondLayer->m_isPainting); + ASSERT_TRUE(secondLayer->m_isDrawing); + ASSERT_EQ(secondLayer->getRefCnt(), 2); + + ////////// INSERT NULL, BOTH TREES NOW REMOVED + + // insert null tree, which should deref secondLayer immediately + manager.updateWithTree(0, false); + ASSERT_EQ(secondLayer->getRefCnt(), 1); + SkSafeUnref(secondLayer); + + // nothing to draw or swap + swapped = false; + ASSERT_FALSE(drawGL(manager, &swapped)); + ASSERT_FALSE(swapped); +} + +TEST_F(TreeManagerTest, LayerAndroidTree_PictureRefCount) { + RenderLayer* renderLayer = 0; + LayerAndroid* l; + SkPicture* p; + allocLayerWithPicture(false, &l, &p); + ASSERT_TRUE(l->needsTexture()); + SkSafeRef(p); // ref picture locally so it exists after layer (so we can see + // layer derefs it) + + ASSERT_EQ(l->getRefCnt(), 1); + ASSERT_EQ(p->getRefCnt(), 2); + SkSafeUnref(l); + + ASSERT_EQ(p->getRefCnt(), 1); + SkSafeUnref(p); +} + +TEST_F(TreeManagerTest, LayerAndroidTree_PaintTreeWithPictures) { + XLOGC("STARTING PAINT TEST"); + + TreeManager manager; + RenderLayer* renderLayer = 0; + LayerAndroid root(renderLayer); + LayerAndroid* noPaintChild = new LayerAndroid(renderLayer); + root.addChild(noPaintChild); + + root.showLayer(0); + + ASSERT_EQ(noPaintChild->getRefCnt(), 2); + + + LayerAndroid* copy = new LayerAndroid(root); + copy->showLayer(0); + manager.updateWithTree(copy, true); + + + // no painting layer, should swap immediately + bool swapped = false; + ASSERT_FALSE(drawGL(manager, &swapped)); + ASSERT_TRUE(swapped); + + + ////////// add 2 painting layers, push new tree copy into tree manager + + LayerAndroid* paintChildA; + allocLayerWithPicture(true, &paintChildA, 0); + noPaintChild->addChild(paintChildA); + ASSERT_TRUE(paintChildA->needsTexture()); + + LayerAndroid* paintChildB; + allocLayerWithPicture(true, &paintChildB, 0); + noPaintChild->addChild(paintChildB); + ASSERT_TRUE(paintChildB->needsTexture()); + + LayerAndroid* copy1 = new LayerAndroid(root); + copy1->showLayer(0); + manager.updateWithTree(copy1, false); + + swapped = false; + ASSERT_TRUE(drawGL(manager, &swapped)); + ASSERT_FALSE(swapped); // painting layers not ready + + ASSERT_EQ(TreeManager::getTotalPaintedSurfaceCount(), 2); + + ////////// remove painting layer, add new painting layer, push new tree copy into tree manager + + LayerAndroid* paintChildC; + allocLayerWithPicture(true, &paintChildC, 0); + noPaintChild->addChild(paintChildC); + ASSERT_TRUE(paintChildC->needsTexture()); + + paintChildB->detachFromParent(); + ASSERT_EQ(paintChildB->getRefCnt(), 1); + SkSafeUnref(paintChildB); + + LayerAndroid* copy2 = new LayerAndroid(root); + copy2->showLayer(0); + manager.updateWithTree(copy2, false); + + swapped = false; + ASSERT_TRUE(drawGL(manager, &swapped)); + ASSERT_FALSE(swapped); // painting layers not ready + + + ////////// swap layers + + static_cast<TestLayerAndroid*>(copy1->getChild(0)->getChild(0))->m_isDonePainting = true; + static_cast<TestLayerAndroid*>(copy1->getChild(0)->getChild(1))->m_isDonePainting = true; + + XLOGC("painting should be %p, queued %p", copy1, copy2); + swapped = false; + ASSERT_TRUE(drawGL(manager, &swapped)); + ASSERT_TRUE(swapped); // paint complete, new layer tree to paint + XLOGC("drawing should be %p, painting %p", copy1, copy2); + + + ASSERT_EQ(TreeManager::getTotalPaintedSurfaceCount(), 3); + + + ////////// swap layers again + + static_cast<TestLayerAndroid*>(copy2->getChild(0)->getChild(0))->m_isDonePainting = true; + static_cast<TestLayerAndroid*>(copy2->getChild(0)->getChild(1))->m_isDonePainting = true; + + swapped = false; + ASSERT_FALSE(drawGL(manager, &swapped)); + ASSERT_TRUE(swapped); // paint complete, no new layer tree to paint + + ASSERT_EQ(TreeManager::getTotalPaintedSurfaceCount(), 2); + + ////////// remove all painting layers + + paintChildA->detachFromParent(); + SkSafeUnref(paintChildA); + paintChildC->detachFromParent(); + SkSafeUnref(paintChildC); + + + copy = new LayerAndroid(root); + copy->showLayer(0); + manager.updateWithTree(copy, false); + + swapped = false; + ASSERT_FALSE(drawGL(manager, &swapped)); + ASSERT_TRUE(swapped); // paint complete, no new layer tree to paint + + ASSERT_EQ(TreeManager::getTotalPaintedSurfaceCount(), 0); +} + +} // namespace WebCore diff --git a/Source/WebKit/android/WebCoreSupport/CacheResult.cpp b/Source/WebKit/android/WebCoreSupport/CacheResult.cpp index 5309c66..6710e49 100644 --- a/Source/WebKit/android/WebCoreSupport/CacheResult.cpp +++ b/Source/WebKit/android/WebCoreSupport/CacheResult.cpp @@ -134,11 +134,11 @@ bool CacheResult::writeToFile(const String& filePath) const if (!thread) return false; - CacheResult* me = const_cast<CacheResult*>(this); - thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(me, &CacheResult::writeToFileImpl)); - m_filePath = filePath.threadsafeCopy(); m_isAsyncOperationInProgress = true; + + thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(const_cast<CacheResult*>(this), &CacheResult::writeToFileImpl)); + while (m_isAsyncOperationInProgress) m_condition.wait(m_mutex); @@ -213,10 +213,9 @@ HttpResponseHeaders* CacheResult::responseHeaders() const if (!thread) return 0; - CacheResult* me = const_cast<CacheResult*>(this); - thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(me, &CacheResult::responseHeadersImpl)); - m_isAsyncOperationInProgress = true; + thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(const_cast<CacheResult*>(this), &CacheResult::responseHeadersImpl)); + while (m_isAsyncOperationInProgress) m_condition.wait(m_mutex); diff --git a/Source/WebKit/android/jni/CacheManager.cpp b/Source/WebKit/android/jni/CacheManager.cpp index 144b62a..f600d00 100644 --- a/Source/WebKit/android/jni/CacheManager.cpp +++ b/Source/WebKit/android/jni/CacheManager.cpp @@ -90,6 +90,7 @@ static jobject getCacheResult(JNIEnv* env, jobject, jstring url) String urlWtfString = jstringToWtfString(env, url); Vector<char> encodedUrl; base64Encode(urlWtfString.utf8().data(), urlWtfString.length(), encodedUrl, false /*insertLFs*/); + encodedUrl.append('\0'); String filePath = pathByAppendingComponent(getCacheFileBaseDir(env), encodedUrl.data()); if (!result->writeToFile(filePath)) return 0; diff --git a/Source/WebKit/android/jni/ViewStateSerializer.cpp b/Source/WebKit/android/jni/ViewStateSerializer.cpp index 93f4375..6b473f5 100644 --- a/Source/WebKit/android/jni/ViewStateSerializer.cpp +++ b/Source/WebKit/android/jni/ViewStateSerializer.cpp @@ -111,11 +111,6 @@ static BaseLayerAndroid* nativeDeserializeViewState(JNIEnv* env, jobject, jobjec if (childLayer) layer->addChild(childLayer); } - // Now double back and delete any imageRefs - for (int i = 0; i < layer->countChildren(); i++) { - LayerAndroid* childLayer = static_cast<LayerAndroid*>(layer->getChild(i)); - cleanupImageRefs(childLayer); - } delete stream; return layer; } @@ -297,15 +292,16 @@ void serializeLayer(LayerAndroid* layer, SkWStream* stream) stream->writeBool(layer->m_preserves3D); stream->writeScalar(layer->m_anchorPointZ); stream->writeScalar(layer->m_drawOpacity); - bool hasContentsImage = layer->m_imageRef != 0; + bool hasContentsImage = layer->m_imageCRC != 0; stream->writeBool(hasContentsImage); if (hasContentsImage) { SkFlattenableWriteBuffer buffer(1024); buffer.setFlags(SkFlattenableWriteBuffer::kCrossProcess_Flag); ImageTexture* imagetexture = - ImagesManager::instance()->getTextureForImage(layer->m_imageRef, false); + ImagesManager::instance()->retainImage(layer->m_imageCRC); if (imagetexture && imagetexture->bitmap()) imagetexture->bitmap()->flatten(buffer); + ImagesManager::instance()->releaseImage(layer->m_imageCRC); stream->write32(buffer.size()); buffer.writeToStream(stream); } @@ -388,8 +384,7 @@ LayerAndroid* deserializeLayer(SkStream* stream) contentsImage.unflatten(buffer); SkBitmapRef* imageRef = new SkBitmapRef(contentsImage); layer->setContentsImage(imageRef); - // We delay deleting the imageRef until after deserialization to make - // sure we have unique keys + delete imageRef; } bool hasRecordingPicture = stream->readBool(); if (hasRecordingPicture) { @@ -418,17 +413,6 @@ LayerAndroid* deserializeLayer(SkStream* stream) return layer; } -void cleanupImageRefs(LayerAndroid* layer) -{ - if (!layer) - return; - int count = layer->countChildren(); - for (int i = 0; i < count; i++) - cleanupImageRefs(layer->getChild(i)); - if (layer->m_imageRef) - delete layer->m_imageRef; -} - /* * JNI registration */ diff --git a/Source/WebKit/android/jni/WebHistory.cpp b/Source/WebKit/android/jni/WebHistory.cpp index 7ec73a3..aa74b81 100644 --- a/Source/WebKit/android/jni/WebHistory.cpp +++ b/Source/WebKit/android/jni/WebHistory.cpp @@ -490,7 +490,7 @@ static bool read_item_recursive(WebCore::HistoryItem* newItem, // Read the original url // Read the expected length of the string. - int l; + unsigned l; memcpy(&l, data, sizeofUnsigned); // Increment data pointer by the size of an unsigned int. data += sizeofUnsigned; diff --git a/Source/WebKit/android/jni/WebViewCore.cpp b/Source/WebKit/android/jni/WebViewCore.cpp index 7692de1..839c352 100644 --- a/Source/WebKit/android/jni/WebViewCore.cpp +++ b/Source/WebKit/android/jni/WebViewCore.cpp @@ -885,29 +885,37 @@ bool WebViewCore::updateLayers(LayerAndroid* layers) ChromeClientAndroid* chromeC = static_cast<ChromeClientAndroid*>(m_mainFrame->page()->chrome()->client()); GraphicsLayerAndroid* root = static_cast<GraphicsLayerAndroid*>(chromeC->layersSync()); if (root) { - root->notifyClientAnimationStarted(); LayerAndroid* updatedLayer = root->contentLayer(); return layers->updateWithTree(updatedLayer); } return true; } +void WebViewCore::notifyAnimationStarted() +{ + // We notify webkit that the animations have begun + // TODO: handle case where not all have begun + ChromeClientAndroid* chromeC = static_cast<ChromeClientAndroid*>(m_mainFrame->page()->chrome()->client()); + GraphicsLayerAndroid* root = static_cast<GraphicsLayerAndroid*>(chromeC->layersSync()); + if (root) + root->notifyClientAnimationStarted(); + +} + BaseLayerAndroid* WebViewCore::createBaseLayer(SkRegion* region) { BaseLayerAndroid* base = new BaseLayerAndroid(); base->setContent(m_content); - if (!region->isEmpty()) { - m_skipContentDraw = true; - bool layoutSucceeded = layoutIfNeededRecursive(m_mainFrame); - m_skipContentDraw = false; - // Layout only fails if called during a layout. - LOG_ASSERT(layoutSucceeded, "Can never be called recursively"); - } + m_skipContentDraw = true; + bool layoutSucceeded = layoutIfNeededRecursive(m_mainFrame); + m_skipContentDraw = false; + // Layout only fails if called during a layout. + LOG_ASSERT(layoutSucceeded, "Can never be called recursively"); #if USE(ACCELERATED_COMPOSITING) // We set the background color - if (!region->isEmpty() && m_mainFrame && m_mainFrame->document() + if (m_mainFrame && m_mainFrame->document() && m_mainFrame->document()->body()) { Document* document = m_mainFrame->document(); RefPtr<RenderStyle> style = document->styleForElementIgnoringPendingStylesheets(document->body()); @@ -922,7 +930,6 @@ BaseLayerAndroid* WebViewCore::createBaseLayer(SkRegion* region) ChromeClientAndroid* chromeC = static_cast<ChromeClientAndroid*>(m_mainFrame->page()->chrome()->client()); GraphicsLayerAndroid* root = static_cast<GraphicsLayerAndroid*>(chromeC->layersSync()); if (root) { - root->notifyClientAnimationStarted(); LayerAndroid* copyLayer = new LayerAndroid(*root->contentLayer()); base->addChild(copyLayer); copyLayer->unref(); @@ -4106,9 +4113,9 @@ void WebViewCore::addVisitedLink(const UChar* string, int length) m_groupForVisitedLinks->addVisitedLink(string, length); } -static bool UpdateLayers(JNIEnv *env, jobject obj, jint jbaseLayer) +static bool UpdateLayers(JNIEnv *env, jobject obj, jint nativeClass, jint jbaseLayer) { - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); + WebViewCore* viewImpl = (WebViewCore*) nativeClass; BaseLayerAndroid* baseLayer = (BaseLayerAndroid*) jbaseLayer; if (baseLayer) { LayerAndroid* root = static_cast<LayerAndroid*>(baseLayer->getChild(0)); @@ -4118,6 +4125,12 @@ static bool UpdateLayers(JNIEnv *env, jobject obj, jint jbaseLayer) return true; } +static void NotifyAnimationStarted(JNIEnv *env, jobject obj, jint nativeClass) +{ + WebViewCore* viewImpl = (WebViewCore*) nativeClass; + viewImpl->notifyAnimationStarted(); +} + static jint RecordContent(JNIEnv *env, jobject obj, jobject region, jobject pt) { #ifdef ANDROID_INSTRUMENT @@ -4697,8 +4710,10 @@ static JNINativeMethod gJavaWebViewCoreMethods[] = { (void*) UpdateFrameCache }, { "nativeGetContentMinPrefWidth", "()I", (void*) GetContentMinPrefWidth }, - { "nativeUpdateLayers", "(I)Z", + { "nativeUpdateLayers", "(II)Z", (void*) UpdateLayers }, + { "nativeNotifyAnimationStarted", "(I)V", + (void*) NotifyAnimationStarted }, { "nativeRecordContent", "(Landroid/graphics/Region;Landroid/graphics/Point;)I", (void*) RecordContent }, { "setViewportSettingsFromNative", "()V", diff --git a/Source/WebKit/android/jni/WebViewCore.h b/Source/WebKit/android/jni/WebViewCore.h index acde590..a05c3ea 100644 --- a/Source/WebKit/android/jni/WebViewCore.h +++ b/Source/WebKit/android/jni/WebViewCore.h @@ -529,6 +529,7 @@ namespace android { // as we are calling layersSync(). BaseLayerAndroid* createBaseLayer(SkRegion*); bool updateLayers(LayerAndroid*); + void notifyAnimationStarted(); int textWrapWidth() const { return m_textWrapWidth; } float scale() const { return m_scale; } diff --git a/Source/WebKit/android/nav/CacheBuilder.cpp b/Source/WebKit/android/nav/CacheBuilder.cpp index 0c9e85c..940991f 100644 --- a/Source/WebKit/android/nav/CacheBuilder.cpp +++ b/Source/WebKit/android/nav/CacheBuilder.cpp @@ -1161,8 +1161,6 @@ void CacheBuilder::BuildFrame(Frame* root, Frame* frame, absBounds.move(globalOffsetX, globalOffsetY); hasClip = nodeRenderer->hasOverflowClip(); - if (node->hasTagName(HTMLNames::canvasTag)) - mPictureSetDisabled = true; if (checkForPluginViewThatWantsFocus(nodeRenderer)) { bounds = absBounds; isUnclipped = true; @@ -1269,6 +1267,7 @@ void CacheBuilder::BuildFrame(Frame* root, Frame* frame, type = TEXT_INPUT_CACHEDNODETYPE; cachedInput.setFormPointer(area->form()); cachedInput.setIsTextArea(true); + cachedInput.setSpellcheck(area->spellcheck()); exported = area->value().threadsafeCopy(); } else if (node->hasTagName(HTMLNames::aTag)) { const HTMLAnchorElement* anchorNode = diff --git a/Source/WebKit/android/nav/WebView.cpp b/Source/WebKit/android/nav/WebView.cpp index aea28bd..76f0fb8 100644 --- a/Source/WebKit/android/nav/WebView.cpp +++ b/Source/WebKit/android/nav/WebView.cpp @@ -119,7 +119,6 @@ enum DrawExtras { // keep this in sync with WebView.java struct JavaGlue { jweak m_obj; - jmethodID m_calcOurContentVisibleRectF; jmethodID m_overrideLoading; jmethodID m_scrollBy; jmethodID m_sendMoveFocus; @@ -150,14 +149,15 @@ struct JavaGlue { } } m_javaGlue; -WebView(JNIEnv* env, jobject javaWebView, int viewImpl, WTF::String drawableDir) : +WebView(JNIEnv* env, jobject javaWebView, int viewImpl, WTF::String drawableDir, + bool isHighEndGfx) : m_ring((WebViewCore*) viewImpl) + , m_isHighEndGfx(isHighEndGfx) { jclass clazz = env->FindClass("android/webkit/WebView"); // m_javaGlue = new JavaGlue; m_javaGlue.m_obj = env->NewWeakGlobalRef(javaWebView); m_javaGlue.m_scrollBy = GetJMethod(env, clazz, "setContentScrollBy", "(IIZ)Z"); - m_javaGlue.m_calcOurContentVisibleRectF = GetJMethod(env, clazz, "calcOurContentVisibleRectF", "(Landroid/graphics/RectF;)V"); m_javaGlue.m_overrideLoading = GetJMethod(env, clazz, "overrideLoading", "(Ljava/lang/String;)V"); m_javaGlue.m_sendMoveFocus = GetJMethod(env, clazz, "sendMoveFocus", "(II)V"); m_javaGlue.m_sendMoveMouse = GetJMethod(env, clazz, "sendMoveMouse", "(IIII)V"); @@ -172,7 +172,7 @@ WebView(JNIEnv* env, jobject javaWebView, int viewImpl, WTF::String drawableDir) m_javaGlue.m_viewInvalidateRect = GetJMethod(env, clazz, "viewInvalidate", "(IIII)V"); m_javaGlue.m_postInvalidateDelayed = GetJMethod(env, clazz, "viewInvalidateDelayed", "(JIIII)V"); - m_javaGlue.m_pageSwapCallback = GetJMethod(env, clazz, "pageSwapCallback", "()V"); + m_javaGlue.m_pageSwapCallback = GetJMethod(env, clazz, "pageSwapCallback", "(Z)V"); m_javaGlue.m_inFullScreenMode = GetJMethod(env, clazz, "inFullScreenMode", "()Z"); m_javaGlue.m_getTextHandleScale = GetJMethod(env, clazz, "getTextHandleScale", "()F"); env->DeleteLocalRef(clazz); @@ -369,50 +369,29 @@ void scrollRectOnScreen(const IntRect& rect) { if (rect.isEmpty()) return; - SkRect visible = SkRect::MakeEmpty(); - calcOurContentVisibleRect(&visible); int dx = 0; int left = rect.x(); int right = rect.maxX(); - if (left < visible.fLeft) { - dx = left - visible.fLeft; + if (left < m_visibleRect.fLeft) + dx = left - m_visibleRect.fLeft; // Only scroll right if the entire width can fit on screen. - } else if (right > visible.fRight && right - left < visible.width()) { - dx = right - visible.fRight; - } + else if (right > m_visibleRect.fRight + && right - left < m_visibleRect.width()) + dx = right - m_visibleRect.fRight; int dy = 0; int top = rect.y(); int bottom = rect.maxY(); - if (top < visible.fTop) { - dy = top - visible.fTop; + if (top < m_visibleRect.fTop) + dy = top - m_visibleRect.fTop; // Only scroll down if the entire height can fit on screen - } else if (bottom > visible.fBottom && bottom - top < visible.height()) { - dy = bottom - visible.fBottom; - } + else if (bottom > m_visibleRect.fBottom + && bottom - top < m_visibleRect.height()) + dy = bottom - m_visibleRect.fBottom; if ((dx|dy) == 0 || !scrollBy(dx, dy)) return; viewInvalidate(); } -void calcOurContentVisibleRect(SkRect* r) -{ - JNIEnv* env = JSC::Bindings::getJNIEnv(); - AutoJObject javaObject = m_javaGlue.object(env); - if (!javaObject.get()) - return; - jclass rectClass = env->FindClass("android/graphics/RectF"); - jmethodID init = env->GetMethodID(rectClass, "<init>", "(FFFF)V"); - jobject jRect = env->NewObject(rectClass, init, 0, 0, 0, 0); - env->CallVoidMethod(javaObject.get(), m_javaGlue.m_calcOurContentVisibleRectF, jRect); - r->fLeft = env->GetFloatField(jRect, m_javaGlue.m_rectFLeft); - r->fTop = env->GetFloatField(jRect, m_javaGlue.m_rectFTop); - r->fRight = r->fLeft + env->CallFloatMethod(jRect, m_javaGlue.m_rectFWidth); - r->fBottom = r->fTop + env->CallFloatMethod(jRect, m_javaGlue.m_rectFHeight); - env->DeleteLocalRef(rectClass); - env->DeleteLocalRef(jRect); - checkException(env); -} - void resetCursorRing() { m_ringAnimationEnd = 0; @@ -438,9 +417,7 @@ bool drawCursorPreamble(CachedRoot* root) #if USE(ACCELERATED_COMPOSITING) if (node->isInLayer() && root->rootLayer()) { LayerAndroid* layer = root->rootLayer(); - SkRect visible; - calcOurContentVisibleRect(&visible); - layer->updateFixedLayersPositions(visible); + layer->updateFixedLayersPositions(m_visibleRect); layer->updatePositions(); } #endif @@ -469,8 +446,9 @@ void drawCursorPostamble() } } -bool drawGL(WebCore::IntRect& viewRect, WebCore::IntRect* invalRect, WebCore::IntRect& webViewRect, - int titleBarHeight, WebCore::IntRect& clip, float scale, int extras) +bool drawGL(WebCore::IntRect& viewRect, WebCore::IntRect* invalRect, + WebCore::IntRect& webViewRect, int titleBarHeight, + WebCore::IntRect& clip, float scale, int extras) { #if USE(ACCELERATED_COMPOSITING) if (!m_baseLayer || inFullScreenMode()) @@ -478,6 +456,7 @@ bool drawGL(WebCore::IntRect& viewRect, WebCore::IntRect* invalRect, WebCore::In if (!m_glWebViewState) { m_glWebViewState = new GLWebViewState(); + m_glWebViewState->setHighEndGfx(m_isHighEndGfx); m_glWebViewState->glExtras()->setCursorRingExtra(&m_ring); m_glWebViewState->glExtras()->setFindOnPageExtra(&m_findOnPage); if (m_baseLayer->content()) { @@ -521,24 +500,23 @@ bool drawGL(WebCore::IntRect& viewRect, WebCore::IntRect* invalRect, WebCore::In unsigned int pic = m_glWebViewState->currentPictureCounter(); m_glWebViewState->glExtras()->setDrawExtra(extra); - SkRect visibleRect; - calcOurContentVisibleRect(&visibleRect); // Make sure we have valid coordinates. We might not have valid coords // if the zoom manager is still initializing. We will be redrawn // once the correct scale is set - if (!visibleRect.hasValidCoordinates()) + if (!m_visibleRect.hasValidCoordinates()) return false; - bool pagesSwapped = false; - bool ret = m_glWebViewState->drawGL(viewRect, visibleRect, invalRect, + bool treesSwapped = false; + bool newTreeHasAnim = false; + bool ret = m_glWebViewState->drawGL(viewRect, m_visibleRect, invalRect, webViewRect, titleBarHeight, clip, scale, - &pagesSwapped); - if (m_pageSwapCallbackRegistered && pagesSwapped) { + &treesSwapped, &newTreeHasAnim); + if (treesSwapped && (m_pageSwapCallbackRegistered || newTreeHasAnim)) { m_pageSwapCallbackRegistered = false; LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!"); JNIEnv* env = JSC::Bindings::getJNIEnv(); AutoJObject javaObject = m_javaGlue.object(env); if (javaObject.get()) { - env->CallVoidMethod(javaObject.get(), m_javaGlue.m_pageSwapCallback); + env->CallVoidMethod(javaObject.get(), m_javaGlue.m_pageSwapCallback, newTreeHasAnim); checkException(env); } } @@ -597,11 +575,9 @@ PictureSet* draw(SkCanvas* canvas, SkColor bgColor, int extras, bool split) #if USE(ACCELERATED_COMPOSITING) LayerAndroid* compositeLayer = compositeRoot(); if (compositeLayer) { - SkRect visible; - calcOurContentVisibleRect(&visible); // call this to be sure we've adjusted for any scrolling or animations // before we actually draw - compositeLayer->updateFixedLayersPositions(visible); + compositeLayer->updateFixedLayersPositions(m_visibleRect); compositeLayer->updatePositions(); // We have to set the canvas' matrix on the base layer // (to have fixed layers work as intended) @@ -743,12 +719,10 @@ CachedRoot* getFrameCache(FrameCachePermission allowNewer) m_frameCacheUI->setRootLayer(compositeRoot()); #if USE(ACCELERATED_COMPOSITING) if (layerId >= 0) { - SkRect visible; - calcOurContentVisibleRect(&visible); LayerAndroid* layer = const_cast<LayerAndroid*>( m_frameCacheUI->rootLayer()); if (layer) { - layer->updateFixedLayersPositions(visible); + layer->updateFixedLayersPositions(m_visibleRect); layer->updatePositions(); } } @@ -1119,6 +1093,12 @@ int scrollableLayer(int x, int y, SkIRect* layerRect, SkIRect* bounds) return 0; } +void scrollLayer(int layerId, int x, int y) +{ + if (m_glWebViewState) + m_glWebViewState->scrollLayer(layerId, x, y); +} + int getBlockLeftEdge(int x, int y, float scale) { CachedRoot* root = getFrameCache(AllowNewer); @@ -1485,6 +1465,7 @@ void setBaseLayer(BaseLayerAndroid* layer, SkRegion& inval, bool showVisualIndic #if ENABLE(ANDROID_OVERFLOW_SCROLL) if (layer) { + // TODO: the below tree copies are only necessary in software rendering LayerAndroid* newCompositeRoot = static_cast<LayerAndroid*>(layer->getChild(0)); copyScrollPositionRecursive(compositeRoot(), newCompositeRoot); } @@ -1545,6 +1526,10 @@ BaseLayerAndroid* getBaseLayer() { return m_baseLayer; } +void setVisibleRect(SkRect& visibleRect) { + m_visibleRect = visibleRect; +} + bool m_isDrawingPaused; private: // local state for WebView // private to getFrameCache(); other functions operate in a different thread @@ -1567,6 +1552,8 @@ private: // local state for WebView bool m_pageSwapCallbackRegistered; #endif RenderSkinButton* m_buttonSkin; + SkRect m_visibleRect; + bool m_isHighEndGfx; }; // end of WebView class @@ -1578,7 +1565,9 @@ private: // local state for WebView class GLDrawFunctor : Functor { public: GLDrawFunctor(WebView* _wvInstance, - bool(WebView::*_funcPtr)(WebCore::IntRect&, WebCore::IntRect*, WebCore::IntRect&, int, WebCore::IntRect&, jfloat, jint), + bool(WebView::*_funcPtr)(WebCore::IntRect&, WebCore::IntRect*, + WebCore::IntRect&, int, WebCore::IntRect&, + jfloat, jint), WebCore::IntRect _viewRect, float _scale, int _extras) { wvInstance = _wvInstance; funcPtr = _funcPtr; @@ -1603,8 +1592,10 @@ class GLDrawFunctor : Functor { WebCore::IntRect clip(info->clipLeft, info->clipTop, info->clipRight - info->clipLeft, info->clipBottom - info->clipTop); + TilesManager::instance()->shader()->setWebViewMatrix(info->transform, info->isLayer); - bool retVal = (*wvInstance.*funcPtr)(localViewRect, &inval, webViewRect, titlebarHeight, clip, scale, extras); + bool retVal = (*wvInstance.*funcPtr)(localViewRect, &inval, webViewRect, + titlebarHeight, clip, scale, extras); if (retVal) { IntRect finalInval; if (inval.isEmpty()) { @@ -1632,7 +1623,8 @@ class GLDrawFunctor : Functor { } private: WebView* wvInstance; - bool (WebView::*funcPtr)(WebCore::IntRect&, WebCore::IntRect*, WebCore::IntRect&, int, WebCore::IntRect&, float, int); + bool (WebView::*funcPtr)(WebCore::IntRect&, WebCore::IntRect*, + WebCore::IntRect&, int, WebCore::IntRect&, float, int); WebCore::IntRect viewRect; WebCore::IntRect webViewRect; jfloat scale; @@ -1683,10 +1675,11 @@ static void nativeClearCursor(JNIEnv *env, jobject obj) view->clearCursor(); } -static void nativeCreate(JNIEnv *env, jobject obj, int viewImpl, jstring drawableDir) +static void nativeCreate(JNIEnv *env, jobject obj, int viewImpl, + jstring drawableDir, jboolean isHighEndGfx) { WTF::String dir = jstringToWtfString(env, drawableDir); - WebView* webview = new WebView(env, obj, viewImpl, dir); + WebView* webview = new WebView(env, obj, viewImpl, dir, isHighEndGfx); // NEED THIS OR SOMETHING LIKE IT! //Release(obj); } @@ -1816,9 +1809,20 @@ static jobject nativeCursorPosition(JNIEnv *env, jobject obj) static WebCore::IntRect jrect_to_webrect(JNIEnv* env, jobject obj) { - int L, T, R, B; - GraphicsJNI::get_jrect(env, obj, &L, &T, &R, &B); - return WebCore::IntRect(L, T, R - L, B - T); + if (obj) { + int L, T, R, B; + GraphicsJNI::get_jrect(env, obj, &L, &T, &R, &B); + return WebCore::IntRect(L, T, R - L, B - T); + } else + return WebCore::IntRect(); +} + +static SkRect jrectf_to_rect(JNIEnv* env, jobject obj) +{ + SkRect rect = SkRect::MakeEmpty(); + if (obj) + GraphicsJNI::jrectf_to_rect(env, obj, &rect); + return rect; } static bool nativeCursorIntersects(JNIEnv *env, jobject obj, jobject visRect) @@ -1859,56 +1863,49 @@ static void nativeDebugDump(JNIEnv *env, jobject obj) #endif } -static jint nativeDraw(JNIEnv *env, jobject obj, jobject canv, jint color, +static jint nativeDraw(JNIEnv *env, jobject obj, jobject canv, + jobject visible, jint color, jint extras, jboolean split) { SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, canv); - return reinterpret_cast<jint>(GET_NATIVE_VIEW(env, obj)->draw(canvas, color, extras, split)); + WebView* webView = GET_NATIVE_VIEW(env, obj); + SkRect visibleRect = jrectf_to_rect(env, visible); + webView->setVisibleRect(visibleRect); + PictureSet* pictureSet = webView->draw(canvas, color, extras, split); + return reinterpret_cast<jint>(pictureSet); } static jint nativeGetDrawGLFunction(JNIEnv *env, jobject obj, jint nativeView, jobject jrect, jobject jviewrect, + jobject jvisiblerect, jfloat scale, jint extras) { - WebCore::IntRect viewRect; - if (jrect == NULL) { - viewRect = WebCore::IntRect(); - } else { - viewRect = jrect_to_webrect(env, jrect); - } + WebCore::IntRect viewRect = jrect_to_webrect(env, jrect); WebView *wvInstance = (WebView*) nativeView; - GLDrawFunctor* functor = new GLDrawFunctor(wvInstance, &android::WebView::drawGL, - viewRect, scale, extras); + SkRect visibleRect = jrectf_to_rect(env, jvisiblerect); + wvInstance->setVisibleRect(visibleRect); + + GLDrawFunctor* functor = new GLDrawFunctor(wvInstance, + &android::WebView::drawGL, viewRect, scale, extras); wvInstance->setFunctor((Functor*) functor); - WebCore::IntRect webViewRect; - if (jviewrect == NULL) { - webViewRect = WebCore::IntRect(); - } else { - webViewRect = jrect_to_webrect(env, jviewrect); - } + WebCore::IntRect webViewRect = jrect_to_webrect(env, jviewrect); functor->updateViewRect(webViewRect); return (jint)functor; } -static void nativeUpdateDrawGLFunction(JNIEnv *env, jobject obj, jobject jrect, jobject jviewrect) { +static void nativeUpdateDrawGLFunction(JNIEnv *env, jobject obj, jobject jrect, + jobject jviewrect, jobject jvisiblerect) { WebView *wvInstance = GET_NATIVE_VIEW(env, obj); - if (wvInstance != NULL) { + if (wvInstance) { GLDrawFunctor* functor = (GLDrawFunctor*) wvInstance->getFunctor(); - if (functor != NULL) { - WebCore::IntRect viewRect; - if (jrect == NULL) { - viewRect = WebCore::IntRect(); - } else { - viewRect = jrect_to_webrect(env, jrect); - } + if (functor) { + WebCore::IntRect viewRect = jrect_to_webrect(env, jrect); functor->updateRect(viewRect); - WebCore::IntRect webViewRect; - if (jviewrect == NULL) { - webViewRect = WebCore::IntRect(); - } else { - webViewRect = jrect_to_webrect(env, jviewrect); - } + SkRect visibleRect = jrectf_to_rect(env, jvisiblerect); + wvInstance->setVisibleRect(visibleRect); + + WebCore::IntRect webViewRect = jrect_to_webrect(env, jviewrect); functor->updateViewRect(webViewRect); } } @@ -1916,10 +1913,13 @@ static void nativeUpdateDrawGLFunction(JNIEnv *env, jobject obj, jobject jrect, static bool nativeEvaluateLayersAnimations(JNIEnv *env, jobject obj, jint nativeView) { + // only call in software rendering, initialize and evaluate animations #if USE(ACCELERATED_COMPOSITING) LayerAndroid* root = ((WebView*)nativeView)->compositeRoot(); - if (root) + if (root) { + root->initAnimations(); return root->evaluateAnimations(); + } #endif return false; } @@ -2042,7 +2042,7 @@ static jobject nativeFocusCandidateNodeBounds(JNIEnv *env, jobject obj) { const CachedFrame* frame; const CachedNode* node = getFocusCandidate(env, obj, &frame); - WebCore::IntRect bounds = node ? node->bounds(frame) + WebCore::IntRect bounds = node ? node->originalAbsoluteBounds() : 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. @@ -2106,6 +2106,18 @@ static int nativeFocusCandidateType(JNIEnv *env, jobject obj) return input->getType(); } +static int nativeFocusCandidateLayerId(JNIEnv *env, jobject obj) +{ + const CachedFrame* frame = 0; + const CachedNode* node = getFocusNode(env, obj, &frame); + if (!node || !frame) + return -1; + const CachedLayer* layer = frame->layer(node); + if (!layer) + return -1; + return layer->uniqueId(); +} + static bool nativeFocusIsPlugin(JNIEnv *env, jobject obj) { const CachedNode* node = getFocusNode(env, obj); @@ -2669,6 +2681,9 @@ static bool nativeScrollLayer(JNIEnv* env, jobject obj, jint layerId, jint x, { #if ENABLE(ANDROID_OVERFLOW_SCROLL) WebView* view = GET_NATIVE_VIEW(env, obj); + view->scrollLayer(layerId, x, y); + + //TODO: the below only needed for the SW rendering path LayerAndroid* root = view->compositeRoot(); if (!root) return false; @@ -2725,7 +2740,7 @@ static JNINativeMethod gJavaWebViewMethods[] = { (void*) nativeCacheHitNodePointer }, { "nativeClearCursor", "()V", (void*) nativeClearCursor }, - { "nativeCreate", "(ILjava/lang/String;)V", + { "nativeCreate", "(ILjava/lang/String;Z)V", (void*) nativeCreate }, { "nativeCursorFramePointer", "()I", (void*) nativeCursorFramePointer }, @@ -2751,11 +2766,11 @@ static JNINativeMethod gJavaWebViewMethods[] = { (void*) nativeDebugDump }, { "nativeDestroy", "()V", (void*) nativeDestroy }, - { "nativeDraw", "(Landroid/graphics/Canvas;IIZ)I", + { "nativeDraw", "(Landroid/graphics/Canvas;Landroid/graphics/RectF;IIZ)I", (void*) nativeDraw }, - { "nativeGetDrawGLFunction", "(ILandroid/graphics/Rect;Landroid/graphics/Rect;FI)I", + { "nativeGetDrawGLFunction", "(ILandroid/graphics/Rect;Landroid/graphics/Rect;Landroid/graphics/RectF;FI)I", (void*) nativeGetDrawGLFunction }, - { "nativeUpdateDrawGLFunction", "(Landroid/graphics/Rect;Landroid/graphics/Rect;)V", + { "nativeUpdateDrawGLFunction", "(Landroid/graphics/Rect;Landroid/graphics/Rect;Landroid/graphics/RectF;)V", (void*) nativeUpdateDrawGLFunction }, { "nativeDumpDisplayTree", "(Ljava/lang/String;)V", (void*) nativeDumpDisplayTree }, @@ -2801,6 +2816,8 @@ static JNINativeMethod gJavaWebViewMethods[] = { (void*) nativeFocusCandidateTextSize }, { "nativeFocusCandidateType", "()I", (void*) nativeFocusCandidateType }, + { "nativeFocusCandidateLayerId", "()I", + (void*) nativeFocusCandidateLayerId }, { "nativeFocusIsPlugin", "()Z", (void*) nativeFocusIsPlugin }, { "nativeFocusNodeBounds", "()Landroid/graphics/Rect;", |