summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohn Reck <jreck@google.com>2012-04-27 08:13:38 -0700
committerJohn Reck <jreck@google.com>2012-05-02 16:13:16 -0700
commite859a34171f2a36877d95197d118d962078f8aa0 (patch)
tree3c8b592536fa193bcb468c03e5f318c7d0edcf8e
parent8a3e157baecb453158df1f7bc81bfb4704448b2e (diff)
downloadexternal_webkit-e859a34171f2a36877d95197d118d962078f8aa0.zip
external_webkit-e859a34171f2a36877d95197d118d962078f8aa0.tar.gz
external_webkit-e859a34171f2a36877d95197d118d962078f8aa0.tar.bz2
Rewrite PictureSet with TURBO!
This changes how partial invals are done by adding a hybrid mode. What we used to do is generate a SkPicture for the new area. This SkPicture would possibly be larger than the actual inval, depending on various merge rules (more SkPictures == slower to draw a tile) The new code rewrites PictureSet entirely, preserving many of the old rules but cleans up the code and adds the concept of a "PrerenderedInval". This is a partial inval that WebKit has rasterized. By having WebKit produce both a SkPicture and a SkBitmap, we avoid needing to play back the picture and avoid overdrawing. We take this SkBitmap, and simply update the front textures with it. This gives us full partial invals through the entire system without hitting any driver bugs, and with minimal copies. And while the SkPicture may be larger than the inval, the SkBitmap that is rasterized is not - it matches the area webkit has said is dirty. Change-Id: Ieb7ecc9db0d4f679102fda004a43399f9b319ebc
-rw-r--r--Source/WebCore/Android.mk2
-rw-r--r--Source/WebCore/platform/android/ScrollViewAndroid.cpp8
-rw-r--r--Source/WebCore/platform/android/WidgetAndroid.cpp4
-rw-r--r--Source/WebCore/platform/graphics/android/layers/LayerAndroid.cpp15
-rw-r--r--Source/WebCore/platform/graphics/android/layers/LayerAndroid.h3
-rw-r--r--Source/WebCore/platform/graphics/android/layers/LayerContent.h7
-rw-r--r--Source/WebCore/platform/graphics/android/layers/PicturePileLayerContent.cpp41
-rw-r--r--Source/WebCore/platform/graphics/android/layers/PicturePileLayerContent.h (renamed from Source/WebCore/platform/graphics/android/layers/PictureSetLayerContent.h)22
-rw-r--r--Source/WebCore/platform/graphics/android/layers/PictureSetLayerContent.cpp41
-rw-r--r--Source/WebCore/platform/graphics/android/layers/PrerenderedInval.h58
-rw-r--r--Source/WebCore/platform/graphics/android/rendering/BaseRenderer.cpp24
-rw-r--r--Source/WebCore/platform/graphics/android/rendering/BaseRenderer.h4
-rw-r--r--Source/WebCore/platform/graphics/android/rendering/GLUtils.cpp31
-rw-r--r--Source/WebCore/platform/graphics/android/rendering/GLUtils.h6
-rw-r--r--Source/WebCore/platform/graphics/android/rendering/GaneshRenderer.cpp10
-rw-r--r--Source/WebCore/platform/graphics/android/rendering/GaneshRenderer.h1
-rw-r--r--Source/WebCore/platform/graphics/android/rendering/RasterRenderer.cpp14
-rw-r--r--Source/WebCore/platform/graphics/android/rendering/Surface.cpp98
-rw-r--r--Source/WebCore/platform/graphics/android/rendering/Surface.h4
-rw-r--r--Source/WebCore/platform/graphics/android/rendering/SurfaceBacking.cpp6
-rw-r--r--Source/WebCore/platform/graphics/android/rendering/SurfaceBacking.h8
-rw-r--r--Source/WebCore/platform/graphics/android/rendering/SurfaceCollection.cpp10
-rw-r--r--Source/WebCore/platform/graphics/android/rendering/Tile.cpp87
-rw-r--r--Source/WebCore/platform/graphics/android/rendering/Tile.h2
-rw-r--r--Source/WebCore/platform/graphics/android/rendering/TileGrid.cpp27
-rw-r--r--Source/WebCore/platform/graphics/android/rendering/TileGrid.h10
-rw-r--r--Source/WebCore/platform/graphics/android/rendering/TilePainter.h2
-rw-r--r--Source/WebCore/platform/graphics/android/rendering/TilesManager.cpp4
-rw-r--r--Source/WebCore/platform/graphics/android/rendering/TilesManager.h4
-rw-r--r--Source/WebCore/platform/graphics/android/rendering/TransferQueue.cpp34
-rw-r--r--Source/WebCore/platform/graphics/android/rendering/TransferQueue.h1
-rw-r--r--Source/WebKit/Android.mk2
-rw-r--r--Source/WebKit/android/AndroidLog.h7
-rw-r--r--Source/WebKit/android/jni/PicturePile.cpp309
-rw-r--r--Source/WebKit/android/jni/PicturePile.h121
-rw-r--r--Source/WebKit/android/jni/PictureSet.cpp1244
-rw-r--r--Source/WebKit/android/jni/PictureSet.h152
-rw-r--r--Source/WebKit/android/jni/ViewStateSerializer.cpp1
-rw-r--r--Source/WebKit/android/jni/WebCoreViewBridge.h2
-rw-r--r--Source/WebKit/android/jni/WebViewCore.cpp248
-rw-r--r--Source/WebKit/android/jni/WebViewCore.h18
-rw-r--r--Source/WebKit/android/nav/WebView.cpp35
42 files changed, 850 insertions, 1877 deletions
diff --git a/Source/WebCore/Android.mk b/Source/WebCore/Android.mk
index 794a4a8..742fade 100644
--- a/Source/WebCore/Android.mk
+++ b/Source/WebCore/Android.mk
@@ -670,7 +670,7 @@ LOCAL_SRC_FILES := $(LOCAL_SRC_FILES) \
platform/graphics/android/layers/MediaLayer.cpp \
platform/graphics/android/layers/MediaTexture.cpp \
platform/graphics/android/layers/PictureLayerContent.cpp \
- platform/graphics/android/layers/PictureSetLayerContent.cpp \
+ platform/graphics/android/layers/PicturePileLayerContent.cpp \
platform/graphics/android/layers/ScrollableLayerAndroid.cpp \
platform/graphics/android/layers/VideoLayerAndroid.cpp \
platform/graphics/android/layers/VideoLayerManager.cpp \
diff --git a/Source/WebCore/platform/android/ScrollViewAndroid.cpp b/Source/WebCore/platform/android/ScrollViewAndroid.cpp
index ecaa2b5..cc1c09e 100644
--- a/Source/WebCore/platform/android/ScrollViewAndroid.cpp
+++ b/Source/WebCore/platform/android/ScrollViewAndroid.cpp
@@ -103,13 +103,7 @@ void ScrollView::platformOffscreenContentRectangle(const IntRect& vis, const Int
android::WebViewCore* core = android::WebViewCore::getWebViewCore(this);
if (!core) // SVG does not instantiate webviewcore
return; // and doesn't need to record drawing offscreen
- SkRegion rectRgn = SkRegion(rect);
- rectRgn.op(vis, SkRegion::kDifference_Op);
- SkRegion::Iterator iter(rectRgn);
- for (; !iter.done(); iter.next()) {
- const SkIRect& diff = iter.rect();
- core->offInvalidate(diff);
- }
+ core->offInvalidate(rect);
}
#endif
diff --git a/Source/WebCore/platform/android/WidgetAndroid.cpp b/Source/WebCore/platform/android/WidgetAndroid.cpp
index 0f7758d..6858f29 100644
--- a/Source/WebCore/platform/android/WidgetAndroid.cpp
+++ b/Source/WebCore/platform/android/WidgetAndroid.cpp
@@ -59,10 +59,6 @@ void Widget::setFocus(bool focused)
void Widget::paint(GraphicsContext* ctx, const IntRect& r)
{
- // FIXME: in what case, will this be called for the top frame?
- if (!platformWidget())
- return;
- platformWidget()->draw(ctx, r);
}
void Widget::releasePlatformWidget()
diff --git a/Source/WebCore/platform/graphics/android/layers/LayerAndroid.cpp b/Source/WebCore/platform/graphics/android/layers/LayerAndroid.cpp
index 69c597f..535d211 100644
--- a/Source/WebCore/platform/graphics/android/layers/LayerAndroid.cpp
+++ b/Source/WebCore/platform/graphics/android/layers/LayerAndroid.cpp
@@ -20,6 +20,7 @@
#include "MediaLayer.h"
#include "ParseCanvas.h"
#include "PictureLayerContent.h"
+#include "PrerenderedInval.h"
#include "SkBitmapRef.h"
#include "SkDrawFilter.h"
#include "SkPaint.h"
@@ -524,6 +525,20 @@ void LayerAndroid::setContent(LayerContent* content)
m_content = content;
}
+bool LayerAndroid::canUpdateWithBlit()
+{
+ if (!m_content || !m_scale)
+ return false;
+ PrerenderedInval* prerendered = m_content->prerenderForRect(m_dirtyRegion.getBounds());
+ if (!prerendered)
+ return false;
+ // Check that the scales are "close enough" to produce the same rects
+ FloatRect screenArea = prerendered->screenArea;
+ screenArea.scale(1 / m_scale);
+ IntRect enclosingDocArea = enclosingIntRect(screenArea);
+ return enclosingDocArea == prerendered->area;
+}
+
bool LayerAndroid::needsTexture()
{
return m_content && !m_content->isEmpty();
diff --git a/Source/WebCore/platform/graphics/android/layers/LayerAndroid.h b/Source/WebCore/platform/graphics/android/layers/LayerAndroid.h
index 4f94698..ca833f7 100644
--- a/Source/WebCore/platform/graphics/android/layers/LayerAndroid.h
+++ b/Source/WebCore/platform/graphics/android/layers/LayerAndroid.h
@@ -185,6 +185,9 @@ public:
LayerContent* content() { return m_content; }
void setContent(LayerContent* content);
+ // Check to see if the dirty area of this layer can be updated with a blit
+ // from the prerender instead of needing to generate tiles from the LayerContent
+ bool canUpdateWithBlit();
void addAnimation(PassRefPtr<AndroidAnimation> anim);
void removeAnimationsForProperty(AnimatedPropertyID property);
diff --git a/Source/WebCore/platform/graphics/android/layers/LayerContent.h b/Source/WebCore/platform/graphics/android/layers/LayerContent.h
index 97bc32a..2cd90a90 100644
--- a/Source/WebCore/platform/graphics/android/layers/LayerContent.h
+++ b/Source/WebCore/platform/graphics/android/layers/LayerContent.h
@@ -26,6 +26,7 @@
#ifndef LayerContent_h
#define LayerContent_h
+#include "IntRect.h"
#include "SkRefCnt.h"
#include <utils/threads.h>
@@ -35,14 +36,18 @@ class SkWStream;
namespace WebCore {
+class PrerenderedInval;
+
class LayerContent : public SkRefCnt {
public:
virtual int width() = 0;
virtual int height() = 0;
- virtual bool isEmpty() = 0;
+ virtual bool isEmpty() { return !width() || !height(); }
virtual void checkForOptimisations() = 0;
virtual bool hasText() = 0;
virtual void draw(SkCanvas* canvas) = 0;
+ virtual PrerenderedInval* prerenderForRect(const IntRect& dirty) { return 0; }
+ virtual void clearPrerenders() { };
virtual void serialize(SkWStream* stream) = 0;
diff --git a/Source/WebCore/platform/graphics/android/layers/PicturePileLayerContent.cpp b/Source/WebCore/platform/graphics/android/layers/PicturePileLayerContent.cpp
new file mode 100644
index 0000000..b648e72
--- /dev/null
+++ b/Source/WebCore/platform/graphics/android/layers/PicturePileLayerContent.cpp
@@ -0,0 +1,41 @@
+#include "config.h"
+#include "PicturePileLayerContent.h"
+
+#include "SkCanvas.h"
+#include "SkPicture.h"
+
+namespace WebCore {
+
+PicturePileLayerContent::PicturePileLayerContent(const PicturePile& picturePile)
+ : m_picturePile(picturePile)
+{
+}
+
+void PicturePileLayerContent::draw(SkCanvas* canvas)
+{
+ android::Mutex::Autolock lock(m_drawLock);
+ m_picturePile.draw(canvas);
+}
+
+void PicturePileLayerContent::serialize(SkWStream* stream)
+{
+ if (!stream)
+ return;
+ SkPicture picture;
+ draw(picture.beginRecording(width(), height(),
+ SkPicture::kUsePathBoundsForClip_RecordingFlag));
+ picture.endRecording();
+ picture.serialize(stream);
+}
+
+PrerenderedInval* PicturePileLayerContent::prerenderForRect(const IntRect& dirty)
+{
+ return m_picturePile.prerenderedInvalForArea(dirty);
+}
+
+void PicturePileLayerContent::clearPrerenders()
+{
+ m_picturePile.clearPrerenders();
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/android/layers/PictureSetLayerContent.h b/Source/WebCore/platform/graphics/android/layers/PicturePileLayerContent.h
index 61fc3f4..4216617 100644
--- a/Source/WebCore/platform/graphics/android/layers/PictureSetLayerContent.h
+++ b/Source/WebCore/platform/graphics/android/layers/PicturePileLayerContent.h
@@ -23,31 +23,31 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef PictureSetLayerContent_h
-#define PictureSetLayerContent_h
+#ifndef PicturePileLayerContent_h
+#define PicturePileLayerContent_h
#include "LayerContent.h"
-#include "PictureSet.h"
+#include "PicturePile.h"
namespace WebCore {
-class PictureSetLayerContent : public LayerContent {
+class PicturePileLayerContent : public LayerContent {
public:
- PictureSetLayerContent(const android::PictureSet& pictureSet);
- ~PictureSetLayerContent();
+ PicturePileLayerContent(const PicturePile& picturePile);
- virtual int width() { return m_pictureSet.width(); }
- virtual int height() { return m_pictureSet.height(); }
- virtual bool isEmpty() { return m_pictureSet.isEmpty(); }
+ virtual int width() { return m_picturePile.size().width(); }
+ virtual int height() { return m_picturePile.size().height(); }
virtual void checkForOptimisations() {}
virtual bool hasText() { return true; }
virtual void draw(SkCanvas* canvas);
virtual void serialize(SkWStream* stream);
+ virtual PrerenderedInval* prerenderForRect(const IntRect& dirty);
+ virtual void clearPrerenders();
private:
- android::PictureSet m_pictureSet;
+ PicturePile m_picturePile;
};
} // WebCore
-#endif // PictureLayerContent_h
+#endif // PicturePileLayerContent_h
diff --git a/Source/WebCore/platform/graphics/android/layers/PictureSetLayerContent.cpp b/Source/WebCore/platform/graphics/android/layers/PictureSetLayerContent.cpp
deleted file mode 100644
index 8b72b0a..0000000
--- a/Source/WebCore/platform/graphics/android/layers/PictureSetLayerContent.cpp
+++ /dev/null
@@ -1,41 +0,0 @@
-#include "config.h"
-#include "PictureSetLayerContent.h"
-
-#include "SkCanvas.h"
-#include "SkPicture.h"
-
-namespace WebCore {
-
-PictureSetLayerContent::PictureSetLayerContent(const android::PictureSet& pictureSet)
-{
- m_pictureSet.set(pictureSet);
-}
-
-PictureSetLayerContent::~PictureSetLayerContent()
-{
- m_pictureSet.clear();
-}
-
-void PictureSetLayerContent::draw(SkCanvas* canvas)
-{
- if (m_pictureSet.isEmpty())
- return;
-
- android::Mutex::Autolock lock(m_drawLock);
- SkRect r = SkRect::MakeWH(width(), height());
- canvas->clipRect(r);
- m_pictureSet.draw(canvas);
-}
-
-void PictureSetLayerContent::serialize(SkWStream* stream)
-{
- if (!stream)
- return;
- SkPicture picture;
- draw(picture.beginRecording(m_pictureSet.width(), m_pictureSet.height(),
- SkPicture::kUsePathBoundsForClip_RecordingFlag));
- picture.endRecording();
- picture.serialize(stream);
-}
-
-} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/android/layers/PrerenderedInval.h b/Source/WebCore/platform/graphics/android/layers/PrerenderedInval.h
new file mode 100644
index 0000000..91f385d
--- /dev/null
+++ b/Source/WebCore/platform/graphics/android/layers/PrerenderedInval.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2012, The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef PrerenderedInval_h
+#define PrerenderedInval_h
+
+#include "IntRect.h"
+#include "SkBitmap.h"
+
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/ThreadSafeRefCounted.h>
+
+namespace WebCore {
+
+class PrerenderedInval : public ThreadSafeRefCounted<PrerenderedInval> {
+ WTF_MAKE_NONCOPYABLE(PrerenderedInval);
+public:
+ SkBitmap bitmap;
+ IntRect area;
+ IntRect screenArea;
+
+ static PassRefPtr<PrerenderedInval> create(const IntRect& ir)
+ {
+ return adoptRef(new PrerenderedInval(ir));
+ }
+
+private:
+ PrerenderedInval(const IntRect& ir)
+ : area(ir)
+ {}
+};
+
+} // namespace WebCore
+
+#endif // PrerenderedInval_h
diff --git a/Source/WebCore/platform/graphics/android/rendering/BaseRenderer.cpp b/Source/WebCore/platform/graphics/android/rendering/BaseRenderer.cpp
index 8bb1755..6f679da 100644
--- a/Source/WebCore/platform/graphics/android/rendering/BaseRenderer.cpp
+++ b/Source/WebCore/platform/graphics/android/rendering/BaseRenderer.cpp
@@ -109,7 +109,6 @@ void BaseRenderer::renderTiledContent(TileRenderInfo& renderInfo)
before = currentTimeMS();
}
- setupPartialInval(renderInfo, &canvas);
canvas.translate(-renderInfo.x * tileSize.width(), -renderInfo.y * tileSize.height());
canvas.scale(renderInfo.scale, renderInfo.scale);
renderInfo.tilePainter->paint(&canvas);
@@ -127,25 +126,10 @@ void BaseRenderer::renderTiledContent(TileRenderInfo& renderInfo)
// only color the invalidated area
SkPaint paint;
paint.setARGB(color, 0, 255, 0);
- if (renderInfo.invalRect)
- canvas.drawIRect(*renderInfo.invalRect, paint);
- else {
- SkIRect rect;
- rect.set(0, 0, tileSize.width(), tileSize.height());
- canvas.drawIRect(rect, paint);
- }
-
- if (renderInfo.invalRect) {
- // if partial inval...
- int x = renderInfo.invalRect->fLeft;
- int y = renderInfo.invalRect->fTop;
- int w = renderInfo.invalRect->width();
- int h = renderInfo.invalRect->height();
-
- paint.setARGB(128, 255, 255, 0);
- canvas.drawLine(x, y, x + w, y + h, paint);
- canvas.drawLine(x, y + h, x + w, y, paint);
- }
+ SkIRect rect;
+ rect.set(0, 0, tileSize.width(), tileSize.height());
+ canvas.drawIRect(rect, paint);
+
drawTileInfo(&canvas, renderInfo, updateCount, after - before);
// paint the tile boundaries
diff --git a/Source/WebCore/platform/graphics/android/rendering/BaseRenderer.h b/Source/WebCore/platform/graphics/android/rendering/BaseRenderer.h
index f225871..b25a50e 100644
--- a/Source/WebCore/platform/graphics/android/rendering/BaseRenderer.h
+++ b/Source/WebCore/platform/graphics/android/rendering/BaseRenderer.h
@@ -49,9 +49,6 @@ struct TileRenderInfo {
// current scale factor
float scale;
- // inval rectangle with coordinates in the tile's coordinate space
- SkIRect* invalRect;
-
// the expected size of the tile
SkSize tileSize;
@@ -89,7 +86,6 @@ public:
protected:
virtual void setupCanvas(const TileRenderInfo& renderInfo, SkCanvas* canvas) = 0;
- virtual void setupPartialInval(const TileRenderInfo& renderInfo, SkCanvas* canvas) {}
virtual void renderingComplete(const TileRenderInfo& renderInfo, SkCanvas* canvas) = 0;
virtual void checkForPureColor(TileRenderInfo& renderInfo, SkCanvas* canvas) = 0;
diff --git a/Source/WebCore/platform/graphics/android/rendering/GLUtils.cpp b/Source/WebCore/platform/graphics/android/rendering/GLUtils.cpp
index 7206c98..32f353c 100644
--- a/Source/WebCore/platform/graphics/android/rendering/GLUtils.cpp
+++ b/Source/WebCore/platform/graphics/android/rendering/GLUtils.cpp
@@ -418,10 +418,6 @@ bool GLUtils::skipTransferForPureColor(const TileRenderInfo* renderInfo,
bool skipTransfer = false;
Tile* tilePtr = renderInfo->baseTile;
- // TODO: use pure color for partial invals as well
- if (renderInfo->invalRect)
- return false;
-
if (tilePtr) {
TileTexture* tileTexture = tilePtr->backTexture();
// Check the bitmap, and make everything ready here.
@@ -611,6 +607,33 @@ void GLUtils::clearBackgroundIfOpaque(const Color* backgroundColor)
}
}
+bool GLUtils::deepCopyBitmapSubset(const SkBitmap& sourceBitmap,
+ SkBitmap& subset, int leftOffset, int topOffset)
+{
+ sourceBitmap.lockPixels();
+ subset.lockPixels();
+ char* srcPixels = (char*) sourceBitmap.getPixels();
+ char* dstPixels = (char*) subset.getPixels();
+ if (!dstPixels || !srcPixels || !subset.lockPixelsAreWritable()) {
+ ALOGD("no pixels :( %p, %p (writable=%d)", srcPixels, dstPixels,
+ subset.lockPixelsAreWritable());
+ subset.unlockPixels();
+ sourceBitmap.unlockPixels();
+ return false;
+ }
+ int srcRowSize = sourceBitmap.rowBytes();
+ int destRowSize = subset.rowBytes();
+ for (int i = 0; i < subset.height(); i++) {
+ int srcOffset = (i + topOffset) * srcRowSize;
+ srcOffset += (leftOffset * sourceBitmap.bytesPerPixel());
+ int dstOffset = i * destRowSize;
+ memcpy(dstPixels + dstOffset, srcPixels + srcOffset, destRowSize);
+ }
+ subset.unlockPixels();
+ sourceBitmap.unlockPixels();
+ return true;
+}
+
} // namespace WebCore
#endif // USE(ACCELERATED_COMPOSITING)
diff --git a/Source/WebCore/platform/graphics/android/rendering/GLUtils.h b/Source/WebCore/platform/graphics/android/rendering/GLUtils.h
index a235458..1b69d6c 100644
--- a/Source/WebCore/platform/graphics/android/rendering/GLUtils.h
+++ b/Source/WebCore/platform/graphics/android/rendering/GLUtils.h
@@ -29,6 +29,7 @@
#if USE(ACCELERATED_COMPOSITING)
#include "Color.h"
+#include "IntRect.h"
#include "SkBitmap.h"
#include "SkMatrix.h"
#include "TransformationMatrix.h"
@@ -73,7 +74,8 @@ public:
static GLuint createTileGLTexture(int width, int height);
static void createTextureWithBitmap(GLuint texture, const SkBitmap& bitmap, GLint filter = GL_LINEAR);
- static void updateTextureWithBitmap(GLuint texture, const SkBitmap& bitmap, const IntRect&, GLint filter = GL_LINEAR);
+ static void updateTextureWithBitmap(GLuint texture, const SkBitmap& bitmap,
+ const IntRect& inval = IntRect(), GLint filter = GL_LINEAR);
static void createEGLImageFromTexture(GLuint texture, EGLImageKHR* image);
static void createTextureFromEGLImage(GLuint texture, EGLImageKHR image, GLint filter = GL_LINEAR);
@@ -82,6 +84,8 @@ public:
static bool updateSharedSurfaceTextureWithBitmap(ANativeWindow* anw, const SkBitmap& bitmap);
static void convertToTransformationMatrix(const float* matrix, TransformationMatrix& transformMatrix);
+ static bool deepCopyBitmapSubset(const SkBitmap& sourceBitmap,
+ SkBitmap& subset, int left, int top);
static bool isPureColorBitmap(const SkBitmap& bitmap, Color& pureColor);
static bool skipTransferForPureColor(const TileRenderInfo* renderInfo,
const SkBitmap& bitmap);
diff --git a/Source/WebCore/platform/graphics/android/rendering/GaneshRenderer.cpp b/Source/WebCore/platform/graphics/android/rendering/GaneshRenderer.cpp
index 208adb6..d779af4 100644
--- a/Source/WebCore/platform/graphics/android/rendering/GaneshRenderer.cpp
+++ b/Source/WebCore/platform/graphics/android/rendering/GaneshRenderer.cpp
@@ -84,16 +84,6 @@ void GaneshRenderer::setupCanvas(const TileRenderInfo& renderInfo, SkCanvas* can
canvas->setDevice(device);
}
-void GaneshRenderer::setupPartialInval(const TileRenderInfo& renderInfo, SkCanvas* canvas)
-{
- // set the clip to our invalRect
- SkRect clipRect = SkRect::MakeLTRB(renderInfo.invalRect->fLeft,
- renderInfo.invalRect->fTop,
- renderInfo.invalRect->fRight,
- renderInfo.invalRect->fBottom);
- canvas->clipRect(clipRect);
-}
-
void GaneshRenderer::renderingComplete(const TileRenderInfo& renderInfo, SkCanvas* canvas)
{
ALOGV("rendered to tile (%d,%d)", renderInfo.x, renderInfo.y);
diff --git a/Source/WebCore/platform/graphics/android/rendering/GaneshRenderer.h b/Source/WebCore/platform/graphics/android/rendering/GaneshRenderer.h
index d7eda24..cdd9f3e 100644
--- a/Source/WebCore/platform/graphics/android/rendering/GaneshRenderer.h
+++ b/Source/WebCore/platform/graphics/android/rendering/GaneshRenderer.h
@@ -47,7 +47,6 @@ public:
protected:
virtual void setupCanvas(const TileRenderInfo& renderInfo, SkCanvas* canvas);
- virtual void setupPartialInval(const TileRenderInfo& renderInfo, SkCanvas* canvas);
virtual void renderingComplete(const TileRenderInfo& renderInfo, SkCanvas* canvas);
virtual void checkForPureColor(TileRenderInfo& renderInfo, SkCanvas* canvas) {
renderInfo.isPureColor = false;
diff --git a/Source/WebCore/platform/graphics/android/rendering/RasterRenderer.cpp b/Source/WebCore/platform/graphics/android/rendering/RasterRenderer.cpp
index b880eef..47e5c17 100644
--- a/Source/WebCore/platform/graphics/android/rendering/RasterRenderer.cpp
+++ b/Source/WebCore/platform/graphics/android/rendering/RasterRenderer.cpp
@@ -80,7 +80,7 @@ void RasterRenderer::setupCanvas(const TileRenderInfo& renderInfo, SkCanvas* can
ALOGV("setupCanvas use background on Base Layer %x", background->rgb());
g_bitmap->setIsOpaque(!background->hasAlpha());
g_bitmap->eraseARGB(background->alpha(), background->red(),
- background->green(), background->blue());
+ background->green(), background->blue());
}
SkDevice* device = new SkDevice(*g_bitmap);
@@ -88,15 +88,6 @@ void RasterRenderer::setupCanvas(const TileRenderInfo& renderInfo, SkCanvas* can
canvas->setDevice(device);
device->unref();
-
- // If we have a partially painted bitmap
- if (renderInfo.invalRect) {
- SkRect clipRect = SkRect::MakeWH(renderInfo.invalRect->width(),
- renderInfo.invalRect->height());
- // ensure the canvas origin is translated to the coordinates of our inval rect
- canvas->clipRect(clipRect);
- canvas->translate(-renderInfo.invalRect->fLeft, -renderInfo.invalRect->fTop);
- }
}
void RasterRenderer::renderingComplete(const TileRenderInfo& renderInfo, SkCanvas* canvas)
@@ -107,7 +98,8 @@ void RasterRenderer::renderingComplete(const TileRenderInfo& renderInfo, SkCanva
void RasterRenderer::checkForPureColor(TileRenderInfo& renderInfo, SkCanvas* canvas)
{
- renderInfo.isPureColor = GLUtils::isPureColorBitmap(*g_bitmap, renderInfo.pureColor);
+ const SkBitmap& bitmap = canvas->getDevice()->accessBitmap(false);
+ renderInfo.isPureColor = GLUtils::isPureColorBitmap(bitmap, renderInfo.pureColor);
}
} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/android/rendering/Surface.cpp b/Source/WebCore/platform/graphics/android/rendering/Surface.cpp
index 13c7d27..652c165 100644
--- a/Source/WebCore/platform/graphics/android/rendering/Surface.cpp
+++ b/Source/WebCore/platform/graphics/android/rendering/Surface.cpp
@@ -33,9 +33,13 @@
#include "BaseLayerAndroid.h"
#include "ClassTracker.h"
#include "LayerAndroid.h"
+#include "LayerContent.h"
#include "GLWebViewState.h"
+#include "PrerenderedInval.h"
#include "SkCanvas.h"
#include "SurfaceBacking.h"
+#include "Tile.h"
+#include "TileTexture.h"
#include "TilesManager.h"
#include <wtf/text/CString.h>
@@ -181,7 +185,7 @@ bool Surface::useAggressiveRendering()
|| !m_background.hasAlpha());
}
-void Surface::prepareGL(bool layerTilesDisabled)
+void Surface::prepareGL(bool layerTilesDisabled, bool updateWithBlit)
{
bool tilesDisabled = layerTilesDisabled && !isBase();
if (!m_surfaceBacking) {
@@ -210,8 +214,15 @@ void Surface::prepareGL(bool layerTilesDisabled)
fullArea.x(), fullArea.y(), fullArea.width(), fullArea.height());
m_surfaceBacking->prepareGL(getFirstLayer()->state(), allowZoom,
- prepareArea, fullArea,
- this, useAggressiveRendering());
+ prepareArea, fullArea,
+ this, useAggressiveRendering(), updateWithBlit);
+ if (updateWithBlit) {
+ for (size_t i = 0; i < m_layers.size(); i++) {
+ LayerContent* content = m_layers[i]->content();
+ if (content)
+ content->clearPrerenders();
+ }
+ }
}
}
@@ -273,7 +284,28 @@ bool Surface::isMissingContent()
return m_surfaceBacking->isMissingContent();
}
-IntRect Surface::computePrepareArea() {
+bool Surface::canUpdateWithBlit()
+{
+ // If we don't have a texture, we have nothing to update and thus can take
+ // the fast path
+ if (!needsTexture())
+ return true;
+ // If we have a surface backing that isn't ready, we can't update with a blit
+ // If it is ready, then check to see if it is dirty. We can only call isDirty()
+ // if isReady() returns true
+ if (!m_surfaceBacking)
+ return false;
+ if (!m_surfaceBacking->isReady())
+ return false;
+ if (!m_surfaceBacking->isDirty())
+ return true;
+ if (!singleLayer())
+ return false;
+ return getFirstLayer()->canUpdateWithBlit();
+}
+
+IntRect Surface::computePrepareArea()
+{
IntRect area;
if (!getFirstLayer()->contentIsScrollable()
@@ -285,9 +317,8 @@ IntRect Surface::computePrepareArea() {
double total = ((double) area.width()) * ((double) area.height());
if (total > MAX_UNCLIPPED_AREA)
area = visibleArea();
- } else {
+ } else
area = visibleArea();
- }
return area;
}
@@ -355,6 +386,61 @@ Color* Surface::background()
return &m_background;
}
+bool Surface::blitFromContents(Tile* tile)
+{
+ if (!singleLayer() || !tile || !getFirstLayer() || !getFirstLayer()->content())
+ return false;
+
+ LayerContent* content = getFirstLayer()->content();
+ // Extract the dirty rect from the region. Note that this is *NOT* constrained
+ // to this tile
+ IntRect dirtyRect = tile->dirtyArea().getBounds();
+ PrerenderedInval* prerenderedInval = content->prerenderForRect(dirtyRect);
+ if (!prerenderedInval || prerenderedInval->bitmap.isNull())
+ return false;
+ SkBitmap sourceBitmap = prerenderedInval->bitmap;
+ // Calculate the screen rect that is dirty, then intersect it with the
+ // tile's screen rect so that we end up with the pixels we need to blit
+ FloatRect screenDirty = dirtyRect;
+ screenDirty.scale(tile->scale());
+ IntRect enclosingScreenDirty = enclosingIntRect(screenDirty);
+ IntRect tileRect = IntRect(tile->x() * TilesManager::tileWidth(),
+ tile->y() * TilesManager::tileHeight(),
+ TilesManager::tileWidth(),
+ TilesManager::tileHeight());
+ enclosingScreenDirty.intersect(tileRect);
+ if (enclosingScreenDirty.isEmpty())
+ return false;
+ // Make sure the screen area we want to blit is contained by the
+ // prerendered screen area
+ if (!prerenderedInval->screenArea.contains(enclosingScreenDirty)) {
+ ALOGD("prerendered->screenArea " INT_RECT_FORMAT " doesn't contain "
+ "enclosingScreenDirty " INT_RECT_FORMAT,
+ INT_RECT_ARGS(prerenderedInval->screenArea),
+ INT_RECT_ARGS(enclosingScreenDirty));
+ return false;
+ }
+ IntPoint origin = prerenderedInval->screenArea.location();
+ SkBitmap subset;
+ subset.setConfig(sourceBitmap.config(), enclosingScreenDirty.width(),
+ enclosingScreenDirty.height());
+ subset.allocPixels();
+
+ int topOffset = enclosingScreenDirty.y() - prerenderedInval->screenArea.y();
+ int leftOffset = enclosingScreenDirty.x() - prerenderedInval->screenArea.x();
+ if (!GLUtils::deepCopyBitmapSubset(sourceBitmap, subset, leftOffset, topOffset))
+ return false;
+ // Now upload
+ SkIRect textureInval = SkIRect::MakeXYWH(enclosingScreenDirty.x() - tileRect.x(),
+ enclosingScreenDirty.y() - tileRect.y(),
+ enclosingScreenDirty.width(),
+ enclosingScreenDirty.height());
+ GLUtils::updateTextureWithBitmap(tile->frontTexture()->m_ownTextureId,
+ subset, textureInval);
+ tile->onBlitUpdate();
+ return true;
+}
+
const TransformationMatrix* Surface::drawTransform()
{
// single layer surfaces query the layer's draw transform, while multi-layer
diff --git a/Source/WebCore/platform/graphics/android/rendering/Surface.h b/Source/WebCore/platform/graphics/android/rendering/Surface.h
index 0fced47..dc46fcf 100644
--- a/Source/WebCore/platform/graphics/android/rendering/Surface.h
+++ b/Source/WebCore/platform/graphics/android/rendering/Surface.h
@@ -49,11 +49,12 @@ public:
bool tryUpdateSurface(Surface* oldSurface);
void addLayer(LayerAndroid* layer, const TransformationMatrix& transform);
- void prepareGL(bool layerTilesDisabled);
+ void prepareGL(bool layerTilesDisabled, bool updateWithBlit);
bool drawGL(bool layerTilesDisabled);
void swapTiles();
bool isReady();
bool isMissingContent();
+ bool canUpdateWithBlit();
void computeTexturesAmount(TexturesResult* result);
@@ -66,6 +67,7 @@ public:
virtual bool paint(SkCanvas* canvas);
virtual float opacity();
virtual Color* background();
+ virtual bool blitFromContents(Tile* tile);
private:
IntRect computePrepareArea();
diff --git a/Source/WebCore/platform/graphics/android/rendering/SurfaceBacking.cpp b/Source/WebCore/platform/graphics/android/rendering/SurfaceBacking.cpp
index f43472e..957aa63 100644
--- a/Source/WebCore/platform/graphics/android/rendering/SurfaceBacking.cpp
+++ b/Source/WebCore/platform/graphics/android/rendering/SurfaceBacking.cpp
@@ -57,7 +57,8 @@ SurfaceBacking::~SurfaceBacking()
void SurfaceBacking::prepareGL(GLWebViewState* state, bool allowZoom,
const IntRect& prepareArea, const IntRect& unclippedArea,
- TilePainter* painter, bool aggressiveRendering)
+ TilePainter* painter, bool aggressiveRendering,
+ bool updateWithBlit)
{
float scale = state->scale();
if (scale > 1 && !allowZoom)
@@ -113,7 +114,8 @@ void SurfaceBacking::prepareGL(GLWebViewState* state, bool allowZoom,
// if the front grid hasn't already prepared, or needs to prepare
// expanded bounds do so now
m_frontTileGrid->prepareGL(state, m_scale,
- prepareArea, unclippedArea, painter, prepareRegionFlags, false);
+ prepareArea, unclippedArea, painter,
+ prepareRegionFlags, false, updateWithBlit);
}
if (aggressiveRendering) {
// prepare low res content
diff --git a/Source/WebCore/platform/graphics/android/rendering/SurfaceBacking.h b/Source/WebCore/platform/graphics/android/rendering/SurfaceBacking.h
index 61e3336..08cfc7c 100644
--- a/Source/WebCore/platform/graphics/android/rendering/SurfaceBacking.h
+++ b/Source/WebCore/platform/graphics/android/rendering/SurfaceBacking.h
@@ -42,7 +42,8 @@ public:
~SurfaceBacking();
void prepareGL(GLWebViewState* state, bool allowZoom,
const IntRect& prepareArea, const IntRect& unclippedArea,
- TilePainter* painter, bool aggressiveRendering);
+ TilePainter* painter, bool aggressiveRendering,
+ bool updateWithBlit);
void swapTiles();
void drawGL(const IntRect& visibleArea, float opacity,
const TransformationMatrix* transform, bool aggressiveRendering,
@@ -59,6 +60,11 @@ public:
return !m_zooming && m_frontTileGrid->isReady() && m_scale > 0;
}
+ bool isDirty()
+ {
+ return m_frontTileGrid->isDirty();
+ }
+
bool isMissingContent()
{
return m_zooming || m_frontTileGrid->isMissingContent();
diff --git a/Source/WebCore/platform/graphics/android/rendering/SurfaceCollection.cpp b/Source/WebCore/platform/graphics/android/rendering/SurfaceCollection.cpp
index 24e196b..cf59044 100644
--- a/Source/WebCore/platform/graphics/android/rendering/SurfaceCollection.cpp
+++ b/Source/WebCore/platform/graphics/android/rendering/SurfaceCollection.cpp
@@ -88,8 +88,16 @@ void SurfaceCollection::prepareGL(const SkRect& visibleRect)
updateLayerPositions(visibleRect);
bool layerTilesDisabled = m_compositedRoot->state()->layersRenderingMode()
> GLWebViewState::kClippedTextures;
+ bool updateWithBlit = true;
+ if (!layerTilesDisabled) {
+ for (unsigned int i = 0; i < m_surfaces.size(); i++) {
+ updateWithBlit &= m_surfaces[i]->canUpdateWithBlit();
+ if (!updateWithBlit)
+ break;
+ }
+ }
for (unsigned int i = 0; i < m_surfaces.size(); i++)
- m_surfaces[i]->prepareGL(layerTilesDisabled);
+ m_surfaces[i]->prepareGL(layerTilesDisabled, updateWithBlit);
}
static inline bool compareSurfaceZ(const Surface* a, const Surface* b)
diff --git a/Source/WebCore/platform/graphics/android/rendering/Tile.cpp b/Source/WebCore/platform/graphics/android/rendering/Tile.cpp
index 2ee45b0..3af05f4 100644
--- a/Source/WebCore/platform/graphics/android/rendering/Tile.cpp
+++ b/Source/WebCore/platform/graphics/android/rendering/Tile.cpp
@@ -327,75 +327,7 @@ void Tile::paintBitmap(TilePainter* painter)
const float tileWidth = renderInfo.tileSize.width();
const float tileHeight = renderInfo.tileSize.height();
- SkRegion::Iterator cliperator(dirtyArea);
-
- bool fullRepaint = false;
-
- if (m_fullRepaint
- || textureInfo->m_width != tileWidth
- || textureInfo->m_height != tileHeight) {
- fullRepaint = true;
- }
-
- // For now, only do full repaint
- fullRepaint = true;
-
- if (!fullRepaint) {
- // compute the partial inval area
- SkIRect totalRect;
- totalRect.set(0, 0, 0, 0);
- float tileSurface = tileWidth * tileHeight;
- float tileSurfaceCap = MAX_INVAL_AREA * tileSurface;
-
- // We join all the invals in the same tile for now
- while (!fullRepaint && !cliperator.done()) {
- SkRect realTileRect;
- SkRect dirtyRect;
- dirtyRect.set(cliperator.rect());
- bool intersect = intersectWithRect(x, y, tileWidth, tileHeight,
- scale, dirtyRect, realTileRect);
- if (intersect) {
- // initialize finalRealRect to the rounded values of realTileRect
- SkIRect finalRealRect;
- realTileRect.roundOut(&finalRealRect);
-
- // stash the int values of the current width and height
- const int iWidth = finalRealRect.width();
- const int iHeight = finalRealRect.height();
-
- if (iWidth == tileWidth || iHeight == tileHeight) {
- fullRepaint = true;
- break;
- }
-
- // translate the rect into tile space coordinates
- finalRealRect.fLeft = finalRealRect.fLeft % static_cast<int>(tileWidth);
- finalRealRect.fTop = finalRealRect.fTop % static_cast<int>(tileHeight);
- finalRealRect.fRight = finalRealRect.fLeft + iWidth;
- finalRealRect.fBottom = finalRealRect.fTop + iHeight;
- totalRect.join(finalRealRect);
- float repaintSurface = totalRect.width() * totalRect.height();
-
- if (repaintSurface > tileSurfaceCap) {
- fullRepaint = true;
- break;
- }
- }
-
- cliperator.next();
- }
-
- if (!fullRepaint) {
- renderInfo.invalRect = &totalRect;
- m_renderer->renderTiledContent(renderInfo);
- }
- }
-
- // Do a full repaint if needed
- if (fullRepaint) {
- renderInfo.invalRect = 0;
- m_renderer->renderTiledContent(renderInfo);
- }
+ m_renderer->renderTiledContent(renderInfo);
m_atomicSync.lock();
@@ -410,13 +342,7 @@ void Tile::paintBitmap(TilePainter* painter)
if (m_scale != scale)
m_dirty = true;
- if (fullRepaint)
- m_dirtyArea.setEmpty();
- else
- m_dirtyArea.op(dirtyArea, SkRegion::kDifference_Op);
-
- if (!m_dirtyArea.isEmpty())
- m_dirty = true;
+ m_dirtyArea.setEmpty();
ALOGV("painted tile %p (%d, %d), texture %p, dirty=%d", this, x, y, texture, m_dirty);
@@ -498,6 +424,15 @@ void Tile::backTextureTransferFail() {
// whether validatePaint is called before or after, it won't do anything
}
+void Tile::onBlitUpdate()
+{
+ // The front texture was directly updated with a blit, so mark this as clean
+ android::AutoMutex lock(m_atomicSync);
+ m_dirty = false;
+ m_dirtyArea.setEmpty();
+ m_state = Tile::UpToDate;
+}
+
void Tile::validatePaint() {
// ONLY CALL while m_atomicSync is locked (at the end of paintBitmap())
diff --git a/Source/WebCore/platform/graphics/android/rendering/Tile.h b/Source/WebCore/platform/graphics/android/rendering/Tile.h
index c115f1c..9697b61 100644
--- a/Source/WebCore/platform/graphics/android/rendering/Tile.h
+++ b/Source/WebCore/platform/graphics/android/rendering/Tile.h
@@ -116,6 +116,7 @@ public:
void markAsDirty(const SkRegion& dirtyArea);
bool isDirty();
+ const SkRegion& dirtyArea() { return m_dirtyArea; }
virtual bool isRepaintPending();
void setRepaintPending(bool pending);
float scale() const { return m_scale; }
@@ -133,6 +134,7 @@ public:
bool swapTexturesIfNeeded();
void backTextureTransfer();
void backTextureTransferFail();
+ void onBlitUpdate();
// TextureOwner implementation
virtual bool removeTexture(TileTexture* texture);
diff --git a/Source/WebCore/platform/graphics/android/rendering/TileGrid.cpp b/Source/WebCore/platform/graphics/android/rendering/TileGrid.cpp
index 8bf033e..bee42ae 100644
--- a/Source/WebCore/platform/graphics/android/rendering/TileGrid.cpp
+++ b/Source/WebCore/platform/graphics/android/rendering/TileGrid.cpp
@@ -34,6 +34,7 @@
#include "GLWebViewState.h"
#include "PaintTileOperation.h"
#include "Tile.h"
+#include "TileTexture.h"
#include "TilesManager.h"
#include <wtf/CurrentTime.h>
@@ -113,7 +114,7 @@ IntRect TileGrid::computeTilesArea(const IntRect& contentArea, float scale)
ceilf(contentArea.width() * scale),
ceilf(contentArea.height() * scale));
- ALOGV("TG %p prepare, scale %f, area %d x %d", this, scale, area.width(), area.height());
+ ALOGV("TG prepare, scale %f, area %d x %d", scale, area.width(), area.height());
if (area.width() == 0 && area.height() == 0) {
computedArea.setWidth(0);
@@ -135,7 +136,8 @@ IntRect TileGrid::computeTilesArea(const IntRect& contentArea, float scale)
void TileGrid::prepareGL(GLWebViewState* state, float scale,
const IntRect& prepareArea, const IntRect& unclippedArea,
- TilePainter* painter, int regionFlags, bool isLowResPrefetch)
+ TilePainter* painter, int regionFlags, bool isLowResPrefetch,
+ bool updateWithBlit)
{
// first, how many tiles do we need
m_area = computeTilesArea(prepareArea, scale);
@@ -181,11 +183,11 @@ void TileGrid::prepareGL(GLWebViewState* state, float scale,
if (goingDown) {
for (int j = 0; j < m_area.height(); j++)
prepareTile(m_area.x() + i, m_area.y() + j,
- painter, state, isLowResPrefetch, false);
+ painter, state, isLowResPrefetch, false, updateWithBlit);
} else {
for (int j = m_area.height() - 1; j >= 0; j--)
prepareTile(m_area.x() + i, m_area.y() + j,
- painter, state, isLowResPrefetch, false);
+ painter, state, isLowResPrefetch, false, updateWithBlit);
}
}
}
@@ -207,7 +209,7 @@ void TileGrid::prepareGL(GLWebViewState* state, float scale,
for (int i = expandedArea.x(); i < expandedArea.maxX(); i++)
for (int j = expandedArea.y(); j < expandedArea.maxY(); j++)
if (!m_area.contains(i, j))
- prepareTile(i, j, painter, state, isLowResPrefetch, true);
+ prepareTile(i, j, painter, state, isLowResPrefetch, true, updateWithBlit);
}
}
@@ -219,7 +221,8 @@ void TileGrid::markAsDirty(const SkRegion& invalRegion)
}
void TileGrid::prepareTile(int x, int y, TilePainter* painter,
- GLWebViewState* state, bool isLowResPrefetch, bool isExpandPrefetch)
+ GLWebViewState* state, bool isLowResPrefetch,
+ bool isExpandPrefetch, bool shouldTryUpdateWithBlit)
{
Tile* tile = getTile(x, y);
if (!tile) {
@@ -232,6 +235,9 @@ void TileGrid::prepareTile(int x, int y, TilePainter* painter,
tile->setContents(x, y, m_scale, isExpandPrefetch);
+ if (shouldTryUpdateWithBlit && tryBlitFromContents(tile, painter))
+ return;
+
if (tile->isDirty() || !tile->frontTexture())
tile->reserveTexture();
@@ -243,6 +249,15 @@ void TileGrid::prepareTile(int x, int y, TilePainter* painter,
}
}
+bool TileGrid::tryBlitFromContents(Tile* tile, TilePainter* painter)
+{
+ return tile->frontTexture()
+ && !tile->frontTexture()->isPureColor()
+ && tile->frontTexture()->m_ownTextureId
+ && !tile->isRepaintPending()
+ && painter->blitFromContents(tile);
+}
+
Tile* TileGrid::getTile(int x, int y)
{
for (unsigned int i = 0; i <m_tiles.size(); i++) {
diff --git a/Source/WebCore/platform/graphics/android/rendering/TileGrid.h b/Source/WebCore/platform/graphics/android/rendering/TileGrid.h
index 2483e0e..e412979 100644
--- a/Source/WebCore/platform/graphics/android/rendering/TileGrid.h
+++ b/Source/WebCore/platform/graphics/android/rendering/TileGrid.h
@@ -51,13 +51,11 @@ public:
void prepareGL(GLWebViewState* state, float scale,
const IntRect& prepareArea, const IntRect& unclippedArea,
TilePainter* painter, int regionFlags = StandardRegion,
- bool isLowResPrefetch = false);
+ bool isLowResPrefetch = false, bool updateWithBlit = false);
void swapTiles();
void drawGL(const IntRect& visibleArea, float opacity,
const TransformationMatrix* transform, const Color* background = 0);
- void prepareTile(int x, int y, TilePainter* painter,
- GLWebViewState* state, bool isLowResPrefetch, bool isExpandPrefetch);
void markAsDirty(const SkRegion& dirtyArea);
Tile* getTile(int x, int y);
@@ -67,11 +65,17 @@ public:
bool isReady();
bool isMissingContent();
+ bool isDirty() { return !m_dirtyRegion.isEmpty(); }
int nbTextures(IntRect& area, float scale);
private:
+ void prepareTile(int x, int y, TilePainter* painter,
+ GLWebViewState* state, bool isLowResPrefetch,
+ bool isExpandPrefetch, bool shouldTryUpdateWithBlit);
void drawMissingRegion(const SkRegion& region, float opacity, const Color* tileBackground);
+ bool tryBlitFromContents(Tile* tile, TilePainter* painter);
+
WTF::Vector<Tile*> m_tiles;
IntRect m_area;
diff --git a/Source/WebCore/platform/graphics/android/rendering/TilePainter.h b/Source/WebCore/platform/graphics/android/rendering/TilePainter.h
index 53dfadc..901db66 100644
--- a/Source/WebCore/platform/graphics/android/rendering/TilePainter.h
+++ b/Source/WebCore/platform/graphics/android/rendering/TilePainter.h
@@ -34,6 +34,7 @@ class SkCanvas;
namespace WebCore {
class Color;
+class Tile;
class TilePainter : public SkRefCnt {
// TODO: investigate webkit threadsafe ref counting
@@ -44,6 +45,7 @@ public:
enum SurfaceType { Painted, Image };
virtual SurfaceType type() { return Painted; }
virtual Color* background() { return 0; }
+ virtual bool blitFromContents(Tile* tile) { return false; }
unsigned int getUpdateCount() { return m_updateCount; }
void setUpdateCount(unsigned int updateCount) { m_updateCount = updateCount; }
diff --git a/Source/WebCore/platform/graphics/android/rendering/TilesManager.cpp b/Source/WebCore/platform/graphics/android/rendering/TilesManager.cpp
index 5693d28..6e22d25 100644
--- a/Source/WebCore/platform/graphics/android/rendering/TilesManager.cpp
+++ b/Source/WebCore/platform/graphics/android/rendering/TilesManager.cpp
@@ -471,12 +471,12 @@ bool TilesManager::updateContextIfChanged()
return changed;
}
-float TilesManager::tileWidth()
+int TilesManager::tileWidth()
{
return TILE_WIDTH;
}
-float TilesManager::tileHeight()
+int TilesManager::tileHeight()
{
return TILE_HEIGHT;
}
diff --git a/Source/WebCore/platform/graphics/android/rendering/TilesManager.h b/Source/WebCore/platform/graphics/android/rendering/TilesManager.h
index 834f36d..295acf6 100644
--- a/Source/WebCore/platform/graphics/android/rendering/TilesManager.h
+++ b/Source/WebCore/platform/graphics/android/rendering/TilesManager.h
@@ -87,8 +87,8 @@ public:
int currentLayerTextureCount();
void setCurrentTextureCount(int newTextureCount);
void setCurrentLayerTextureCount(int newTextureCount);
- static float tileWidth();
- static float tileHeight();
+ static int tileWidth();
+ static int tileHeight();
void allocateTextures();
diff --git a/Source/WebCore/platform/graphics/android/rendering/TransferQueue.cpp b/Source/WebCore/platform/graphics/android/rendering/TransferQueue.cpp
index df5ba6e..2316014 100644
--- a/Source/WebCore/platform/graphics/android/rendering/TransferQueue.cpp
+++ b/Source/WebCore/platform/graphics/android/rendering/TransferQueue.cpp
@@ -166,34 +166,14 @@ void TransferQueue::blitTileFromQueue(GLuint fboID, TileTexture* destTex,
int textureWidth = destTex->getSize().width();
int textureHeight = destTex->getSize().height();
- IntRect inval = m_transferQueue[index].invalRect;
- bool partialInval = !inval.isEmpty();
-
- if (partialInval && frontTex) {
- // recopy the previous texture to the new one, as
- // the partial update will not cover the entire texture
- glFramebufferTexture2D(GL_FRAMEBUFFER,
- GL_COLOR_ATTACHMENT0,
- GL_TEXTURE_2D,
- frontTex->m_ownTextureId,
- 0);
- glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0,
- textureWidth, textureHeight);
- }
-
glFramebufferTexture2D(GL_FRAMEBUFFER,
GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D,
srcTexId,
0);
- if (!partialInval) {
- glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0,
- textureWidth, textureHeight);
- } else {
- glCopyTexSubImage2D(GL_TEXTURE_2D, 0, inval.x(), inval.y(), 0, 0,
- inval.width(), inval.height());
- }
+ glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0,
+ textureWidth, textureHeight);
#else
// Then set up the FBO and copy the SurfTex content in.
@@ -412,8 +392,7 @@ void TransferQueue::updateDirtyTiles()
if (m_transferQueue[index].uploadType == CpuUpload) {
// Here we just need to upload the bitmap content to the GL Texture
GLUtils::updateTextureWithBitmap(destTexture->m_ownTextureId,
- *m_transferQueue[index].bitmap,
- m_transferQueue[index].invalRect);
+ *m_transferQueue[index].bitmap);
} else {
if (!usedFboForUpload) {
saveGLState();
@@ -517,13 +496,6 @@ void TransferQueue::addItemCommon(const TileRenderInfo* renderInfo,
data->uploadType = type;
IntRect inval(0, 0, 0, 0);
- if (renderInfo->invalRect) {
- inval.setX(renderInfo->invalRect->fLeft);
- inval.setY(renderInfo->invalRect->fTop);
- inval.setWidth(renderInfo->invalRect->width());
- inval.setHeight(renderInfo->invalRect->height());
- }
- data->invalRect = inval;
}
// Note that there should be lock/unlock around this function call.
diff --git a/Source/WebCore/platform/graphics/android/rendering/TransferQueue.h b/Source/WebCore/platform/graphics/android/rendering/TransferQueue.h
index fe58336..b8563e3 100644
--- a/Source/WebCore/platform/graphics/android/rendering/TransferQueue.h
+++ b/Source/WebCore/platform/graphics/android/rendering/TransferQueue.h
@@ -91,7 +91,6 @@ public:
TransferItemStatus status;
Tile* savedTilePtr;
TileTexture* savedTileTexturePtr;
- IntRect invalRect;
TextureUploadType uploadType;
// This is only useful in Cpu upload code path, so it will be dynamically
// lazily allocated.
diff --git a/Source/WebKit/Android.mk b/Source/WebKit/Android.mk
index 67da200..c3e9798 100644
--- a/Source/WebKit/Android.mk
+++ b/Source/WebKit/Android.mk
@@ -65,7 +65,7 @@ LOCAL_SRC_FILES += \
android/jni/JavaSharedClient.cpp \
android/jni/MIMETypeRegistry.cpp \
android/jni/MockGeolocation.cpp \
- android/jni/PictureSet.cpp \
+ android/jni/PicturePile.cpp \
android/jni/WebCoreFrameBridge.cpp \
android/jni/WebCoreJni.cpp \
android/jni/WebFrameView.cpp \
diff --git a/Source/WebKit/android/AndroidLog.h b/Source/WebKit/android/AndroidLog.h
index e483169..f034d35 100644
--- a/Source/WebKit/android/AndroidLog.h
+++ b/Source/WebKit/android/AndroidLog.h
@@ -53,7 +53,12 @@ extern FILE* gRenderTreeFile;
#define DISPLAY_TREE_LOG_FILE "/sdcard/displayTree.txt"
#define LAYERS_TREE_LOG_FILE "/sdcard/layersTree.plist"
-#define TRACE_METHOD() ScopedTrace __st(ATRACE_TAG_WEBVIEW, __func__);
+#define FLOAT_RECT_FORMAT "[x=%.2f,y=%.2f,w=%.2f,h=%.2f]"
+#define FLOAT_RECT_ARGS(fr) fr.x(), fr.y(), fr.width(), fr.height()
+#define INT_RECT_FORMAT "[x=%d,y=%d,w=%d,h=%d]"
+#define INT_RECT_ARGS(ir) ir.x(), ir.y(), ir.width(), ir.height()
+
+#define TRACE_METHOD() android::ScopedTrace __st(ATRACE_TAG_WEBVIEW, __func__);
#define TIME_METHOD() MethodTimer __method_timer(__func__)
class MethodTimer {
diff --git a/Source/WebKit/android/jni/PicturePile.cpp b/Source/WebKit/android/jni/PicturePile.cpp
new file mode 100644
index 0000000..9ca3588
--- /dev/null
+++ b/Source/WebKit/android/jni/PicturePile.cpp
@@ -0,0 +1,309 @@
+/*
+ * Copyright 2012, The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define LOG_TAG "PicturePile"
+#define LOG_NDEBUG 1
+
+#include "config.h"
+#include "PicturePile.h"
+
+#include "AndroidLog.h"
+#include "FloatRect.h"
+#include "GraphicsContext.h"
+#include "PlatformGraphicsContextSkia.h"
+#include "SkCanvas.h"
+#include "SkNWayCanvas.h"
+#include "SkPicture.h"
+#include "SkPixelRef.h"
+#include "SkRect.h"
+#include "SkRegion.h"
+
+#define ENABLE_PRERENDERED_INVALS true
+#define MAX_OVERLAP_COUNT 2
+#define MAX_OVERLAP_AREA .7
+
+namespace WebCore {
+
+static SkIRect toSkIRect(const IntRect& rect) {
+ return SkIRect::MakeXYWH(rect.x(), rect.y(), rect.width(), rect.height());
+}
+
+static IntRect extractClipBounds(SkCanvas* canvas, const IntSize& size) {
+ SkRect clip;
+ canvas->getClipBounds(&clip);
+ clip.intersect(0, 0, size.width(), size.height());
+ return enclosingIntRect(clip);
+}
+
+PicturePile::PicturePile(const PicturePile& other)
+ : m_size(other.m_size)
+ , m_pile(other.m_pile)
+ , m_webkitInvals(other.m_webkitInvals)
+{
+}
+
+PicturePile::PicturePile(SkPicture* picture)
+{
+ m_size = IntSize(picture->width(), picture->height());
+ PictureContainer pc(IntRect(0, 0, m_size.width(), m_size.height()));
+ pc.picture = picture;
+ pc.dirty = false;
+ m_pile.append(pc);
+}
+
+void PicturePile::draw(SkCanvas* canvas)
+{
+ /* Loop down recursively, subtracting the previous clip from the SkRegion,
+ * stopping when the SkRegion is empty. This will still draw back-to-front,
+ * but it will clip out anything obscured. For performance reasons we use
+ * the rect bounds of the SkRegion for the clip, so this still can't be
+ * used for translucent surfaces
+ */
+ TRACE_METHOD();
+ IntRect clipBounds = extractClipBounds(canvas, m_size);
+ SkRegion clipRegion(toSkIRect(clipBounds));
+ drawWithClipRecursive(canvas, clipRegion, m_pile.size() - 1);
+}
+
+void PicturePile::clearPrerenders()
+{
+ for (size_t i = 0; i < m_pile.size(); i++)
+ m_pile[i].prerendered.clear();
+}
+
+void PicturePile::drawWithClipRecursive(SkCanvas* canvas, SkRegion& clipRegion,
+ int index)
+{
+ // TODO: Add some debug visualizations of this
+ if (index < 0 || clipRegion.isEmpty())
+ return;
+ PictureContainer& pc = m_pile[index];
+ IntRect intersection = clipRegion.getBounds();
+ intersection.intersect(pc.area);
+ if (pc.picture && !intersection.isEmpty()) {
+ clipRegion.op(intersection, SkRegion::kDifference_Op);
+ drawWithClipRecursive(canvas, clipRegion, index - 1);
+ int saved = canvas->save();
+ canvas->clipRect(intersection);
+ canvas->translate(pc.area.x(), pc.area.y());
+ canvas->drawPicture(*pc.picture);
+ canvas->restoreToCount(saved);
+ } else
+ drawWithClipRecursive(canvas, clipRegion, index - 1);
+}
+
+// Used by WebViewCore
+void PicturePile::invalidate(const IntRect& dirtyRect)
+{
+ // This will typically happen if the document has been resized but we haven't
+ // drawn yet. As the first draw after a size change will do a full inval anyway,
+ // don't bother tracking individual rects
+ // TODO: Instead of clipping here, we should take the invals as given
+ // and when the size changes just inval the deltas. This prevents a full
+ // redraw for a page that grows
+ IntRect inval = dirtyRect;
+ inval.intersect(IntRect(0, 0, m_size.width(), m_size.height()));
+ if (inval.isEmpty()) {
+ ALOGV("Rejecting inval " INT_RECT_FORMAT, INT_RECT_ARGS(dirtyRect));
+ return;
+ }
+ // TODO: Support multiple non-intersecting webkit invals
+ if (m_webkitInvals.size())
+ m_webkitInvals[0].unite(inval);
+ else
+ m_webkitInvals.append(inval);
+}
+
+void PicturePile::setSize(const IntSize& size)
+{
+ if (m_size == size)
+ return;
+ m_size = size;
+ // TODO: See above about just adding invals for new content
+ m_pile.clear();
+ m_webkitInvals.clear();
+ IntRect area(0, 0, size.width(), size.height());
+ m_webkitInvals.append(area);
+ m_pile.append(area);
+}
+
+void PicturePile::updatePicturesIfNeeded(PicturePainter* painter)
+{
+ applyWebkitInvals();
+ for (size_t i = 0; i < m_pile.size(); i++) {
+ PictureContainer& pc = m_pile[i];
+ if (pc.dirty)
+ updatePicture(painter, pc);
+ }
+}
+
+void PicturePile::updatePicture(PicturePainter* painter, PictureContainer& pc)
+{
+ /* The ref counting here is a bit unusual. What happens is begin/end recording
+ * will ref/unref the recording canvas. However, 'canvas' might be pointing
+ * at an SkNWayCanvas instead of the recording canvas, which needs to be
+ * unref'd. Thus what we do is ref the recording canvas so that we can
+ * always unref whatever canvas we have at the end.
+ */
+ TRACE_METHOD();
+ SkPicture* picture = new SkPicture();
+ SkCanvas* canvas = picture->beginRecording(pc.area.width(), pc.area.height(),
+ SkPicture::kUsePathBoundsForClip_RecordingFlag);
+ SkSafeRef(canvas);
+ canvas->translate(-pc.area.x(), -pc.area.y());
+ IntRect drawArea = pc.area;
+ if (pc.prerendered.get()) {
+ SkCanvas* prerender = painter->createPrerenderCanvas(pc.prerendered.get());
+ if (!prerender) {
+ ALOGV("Failed to create prerendered for " INT_RECT_FORMAT,
+ INT_RECT_ARGS(pc.prerendered->area));
+ pc.prerendered.clear();
+ } else {
+ drawArea.unite(pc.prerendered->area);
+ SkNWayCanvas* nwayCanvas = new SkNWayCanvas(drawArea.width(), drawArea.height());
+ nwayCanvas->addCanvas(canvas);
+ nwayCanvas->addCanvas(prerender);
+ SkSafeUnref(canvas);
+ SkSafeUnref(prerender);
+ canvas = nwayCanvas;
+ }
+ }
+ WebCore::PlatformGraphicsContextSkia pgc(canvas);
+ WebCore::GraphicsContext gc(&pgc);
+ ALOGV("painting picture: " INT_RECT_FORMAT, INT_RECT_ARGS(drawArea));
+ painter->paintContents(&gc, drawArea);
+ SkSafeUnref(canvas);
+ picture->endRecording();
+
+ SkSafeUnref(pc.picture);
+ pc.picture = picture;
+ pc.dirty = false;
+}
+
+void PicturePile::reset()
+{
+ m_size = IntSize(0,0);
+ m_pile.clear();
+ m_webkitInvals.clear();
+}
+
+void PicturePile::applyWebkitInvals()
+{
+ m_dirtyRegion.setEmpty();
+ if (!m_webkitInvals.size())
+ return;
+ // Build the invals (TODO: Support multiple inval regions)
+ IntRect inval = m_webkitInvals[0];
+ m_dirtyRegion.setRect(toSkIRect(inval));
+ for (size_t i = 1; i < m_webkitInvals.size(); i++) {
+ inval.unite(m_webkitInvals[i]);
+ m_dirtyRegion.op(toSkIRect(m_webkitInvals[i]), SkRegion::kUnion_Op);
+ }
+ m_webkitInvals.clear();
+ ALOGV("Webkit inval: " INT_RECT_FORMAT, INT_RECT_ARGS(inval));
+ if (inval.isEmpty())
+ return;
+
+ // Find the overlaps
+ Vector<int> overlaps;
+ for (size_t i = 0; i < m_pile.size(); i++) {
+ PictureContainer& pc = m_pile[i];
+ if (pc.area.contains(inval)) {
+ if (pc.dirty) {
+ ALOGV("Found already dirty intersection");
+ return;
+ }
+ if (pc.area == inval) {
+ appendToPile(inval);
+ return;
+ }
+ // Don't count the base surface as an overlap
+ if (pc.area.size() != m_size)
+ overlaps.append(i);
+ } else if (pc.area.intersects(inval))
+ overlaps.append(i);
+ }
+
+ if (overlaps.size() >= MAX_OVERLAP_COUNT) {
+ ALOGV("Exceeds overlap count");
+ IntRect overlap = inval;
+ for (int i = (int) overlaps.size() - 1; i >= 0; i--) {
+ overlap.unite(m_pile[overlaps[i]].area);
+ m_pile.remove(overlaps[i]);
+ }
+ float overlapArea = overlap.width() * overlap.height();
+ float totalArea = m_size.width() * m_size.height();
+ if (overlapArea / totalArea > MAX_OVERLAP_AREA)
+ overlap = IntRect(0, 0, m_size.width(), m_size.height());
+ appendToPile(overlap, inval);
+ return;
+ }
+
+ // Append!
+ appendToPile(inval);
+}
+
+void PicturePile::appendToPile(const IntRect& inval, const IntRect& originalInval)
+{
+ ALOGV("Adding inval " INT_RECT_FORMAT " for original inval " INT_RECT_FORMAT,
+ INT_RECT_ARGS(inval), INT_RECT_ARGS(originalInval));
+ // Remove any entries this obscures
+ for (int i = (int) m_pile.size() - 1; i >= 0; i--) {
+ if (inval.contains(m_pile[i].area))
+ m_pile.remove(i);
+ }
+ PictureContainer container(inval);
+ if (ENABLE_PRERENDERED_INVALS) {
+ container.prerendered = PrerenderedInval::create(originalInval.isEmpty()
+ ? inval : originalInval);
+ }
+ m_pile.append(container);
+}
+
+PrerenderedInval* PicturePile::prerenderedInvalForArea(const IntRect& area)
+{
+ ALOGV("Checking for prerendered inval for area " INT_RECT_FORMAT,
+ INT_RECT_ARGS(area));
+ for (int i = (int) m_pile.size() - 1; i >= 0; i--) {
+ if (m_pile[i].area.intersects(area)) {
+ RefPtr<PrerenderedInval> inval = m_pile[i].prerendered;
+ if (inval.get() && inval->area.contains(area)) {
+ ALOGV("Returning prerendered %p for area " INT_RECT_FORMAT,
+ m_pile[i].prerendered.get(), INT_RECT_ARGS(area));
+ return inval.get();
+ }
+ if (inval.get()) {
+ ALOGV("Prerendered area doesn't contain requested area; prerendered="
+ INT_RECT_FORMAT, INT_RECT_ARGS(inval->area));
+ } else
+ ALOGV("No prerendered in intersection");
+ return 0;
+ }
+ }
+ ALOGV("No containers found");
+ return 0;
+}
+
+} // namespace WebCore
diff --git a/Source/WebKit/android/jni/PicturePile.h b/Source/WebKit/android/jni/PicturePile.h
new file mode 100644
index 0000000..b28a792
--- /dev/null
+++ b/Source/WebKit/android/jni/PicturePile.h
@@ -0,0 +1,121 @@
+/*
+ * Copyright 2012, The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef PicturePile_h
+#define PicturePile_h
+
+#include "IntRect.h"
+#include "IntSize.h"
+#include "PrerenderedInval.h"
+#include "SkBitmap.h"
+#include "SkRegion.h"
+#include "SkRefCnt.h"
+
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/ThreadSafeRefCounted.h>
+#include <wtf/Vector.h>
+
+class SkPicture;
+class SkCanvas;
+
+namespace WebCore {
+
+class GraphicsContext;
+
+class PicturePainter {
+public:
+ virtual void paintContents(GraphicsContext* gc, IntRect& dirty) = 0;
+ virtual SkCanvas* createPrerenderCanvas(PrerenderedInval* prerendered)
+ {
+ return 0;
+ }
+ virtual ~PicturePainter() {}
+};
+
+class PictureContainer {
+public:
+ SkPicture* picture;
+ IntRect area;
+ bool dirty;
+ RefPtr<PrerenderedInval> prerendered;
+
+ PictureContainer(const IntRect& area)
+ : picture(0)
+ , area(area)
+ , dirty(true)
+ {}
+
+ PictureContainer(const PictureContainer& other)
+ : picture(other.picture)
+ , area(other.area)
+ , dirty(other.dirty)
+ , prerendered(other.prerendered)
+ {
+ SkSafeRef(picture);
+ }
+
+ ~PictureContainer()
+ {
+ SkSafeUnref(picture);
+ }
+};
+
+class PicturePile {
+public:
+ PicturePile() {}
+ PicturePile(const PicturePile& other);
+ PicturePile(SkPicture* picture);
+
+ const IntSize& size() { return m_size; }
+
+ void clearPrerenders();
+
+ // used by PicturePileLayerContents
+ void draw(SkCanvas* canvas);
+
+ // Used by WebViewCore
+ void invalidate(const IntRect& dirtyRect);
+ void setSize(const IntSize& size);
+ void updatePicturesIfNeeded(PicturePainter* painter);
+ void reset();
+ SkRegion& dirtyRegion() { return m_dirtyRegion; }
+ PrerenderedInval* prerenderedInvalForArea(const IntRect& area);
+
+private:
+ void applyWebkitInvals();
+ void updatePicture(PicturePainter* painter, PictureContainer& container);
+ void appendToPile(const IntRect& inval, const IntRect& originalInval = IntRect());
+ void drawWithClipRecursive(SkCanvas* canvas, SkRegion& clipRegion, int index);
+
+ IntSize m_size;
+ Vector<PictureContainer> m_pile;
+ Vector<IntRect> m_webkitInvals;
+ SkRegion m_dirtyRegion;
+};
+
+} // namespace android
+
+#endif // PicturePile_h
diff --git a/Source/WebKit/android/jni/PictureSet.cpp b/Source/WebKit/android/jni/PictureSet.cpp
deleted file mode 100644
index 8beb0ef..0000000
--- a/Source/WebKit/android/jni/PictureSet.cpp
+++ /dev/null
@@ -1,1244 +0,0 @@
-/*
- * Copyright 2008, 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.
- */
-
-#define LOG_TAG "PictureSet"
-#define LOG_NDEBUG 1
-
-#include "config.h"
-#include "PictureSet.h"
-
-#include "AndroidLog.h"
-#include "android_graphics.h"
-#include "SkBounder.h"
-#include "SkCanvas.h"
-#include "SkPicture.h"
-#include "SkRect.h"
-#include "SkRegion.h"
-#include "SkStream.h"
-
-#include "PlatformGraphicsContext.h"
-
-#define MAX_DRAW_TIME 100
-#define MIN_SPLITTABLE 400
-#define MAX_ADDITIONAL_AREA 0.65
-#define MAX_ADDITIONAL_PICTURES 32
-
-#define BUCKET_SIZE 1024
-#define MAX_BUCKET_COUNT_X 16
-#define MAX_BUCKET_COUNT_Y 64
-
-#if PICTURE_SET_DEBUG
-class MeasureStream : public SkWStream {
-public:
- MeasureStream() : mTotal(0) {}
- virtual bool write(const void* , size_t size) {
- mTotal += size;
- return true;
- }
- size_t mTotal;
-};
-#endif
-
-namespace android {
-
-PictureSet::PictureSet() :
-#ifdef FAST_PICTURESET
- mBucketSizeX(BUCKET_SIZE), mBucketSizeY(BUCKET_SIZE),
- mBucketCountX(0), mBucketCountY(0),
-#endif
- mHeight(0), mWidth(0)
-{
- setDimensions(0, 0);
- mBaseArea = mAdditionalArea = 0;
-}
-
-PictureSet::PictureSet(SkPicture* picture) :
-#ifdef FAST_PICTURESET
- mBucketSizeX(BUCKET_SIZE), mBucketSizeY(BUCKET_SIZE),
- mBucketCountX(0), mBucketCountY(0),
-#endif
- mHeight(0), mWidth(0)
-{
- mBaseArea = mAdditionalArea = 0;
- if (!picture) {
- setDimensions(0, 0);
- return;
- }
- setDimensions(picture->width(), picture->height());
- mBaseArea = mWidth * mHeight;
-#ifdef FAST_PICTURESET
- SkIRect area;
- area.set(0, 0, mWidth, mHeight);
- splitAdd(area);
- WTF::Vector<Bucket*>* buckets = bucketsToUpdate();
- for (unsigned int i = 0; i < buckets->size(); i++) {
- Bucket* bucket = (*buckets)[i];
- for (unsigned int j = 0; j < bucket->size(); j++) {
- BucketPicture& bucketPicture = (*bucket)[j];
- const SkIRect& inval = bucketPicture.mRealArea;
- SkPicture *splitPicture = new SkPicture();
- SkCanvas *canvas = splitPicture->beginRecording(
- inval.width(), inval.height(),
- SkPicture::kUsePathBoundsForClip_RecordingFlag);
- canvas->translate(-inval.fLeft, -inval.fTop);
- picture->draw(canvas);
- splitPicture->endRecording();
- SkSafeUnref(bucketPicture.mPicture);
- bucketPicture.mPicture = splitPicture;
- }
- }
- buckets->clear();
-#else
- Pictures pictureAndBounds;
- pictureAndBounds.mPicture = picture;
- SkSafeRef(pictureAndBounds.mPicture);
- pictureAndBounds.mEmpty = false;
- pictureAndBounds.mArea.set(0, 0, mWidth, mHeight);
- pictureAndBounds.mSplit = false;
- pictureAndBounds.mBase = true;
- pictureAndBounds.mElapsed = 0;
- pictureAndBounds.mWroteElapsed = false;
- mPictures.append(pictureAndBounds);
-#endif // FAST_PICTURESET
-}
-
-PictureSet::~PictureSet()
-{
- clear();
-}
-
-#ifdef FAST_PICTURESET
-#else
-void PictureSet::add(const Pictures* temp)
-{
- Pictures pictureAndBounds = *temp;
- SkSafeRef(pictureAndBounds.mPicture);
-#ifdef CONTEXT_RECORDING
- SkSafeRef(pictureAndBounds.mGraphicsOperationCollection);
-#endif
- pictureAndBounds.mWroteElapsed = false;
- mPictures.append(pictureAndBounds);
-}
-#endif // FAST_PICTURESET
-
-void PictureSet::add(const SkRegion& area, uint32_t elapsed, bool split)
-{
- if (area.isRect()) {
-#ifdef FAST_PICTURESET
- splitAdd(area.getBounds());
-#else
- add(area.getBounds(), elapsed, split, false);
-#endif // FAST_PICTURESET
- } else {
- SkRegion::Iterator cliperator(area);
- while (!cliperator.done()) {
- SkIRect ir = cliperator.rect();
-#ifdef FAST_PICTURESET
- splitAdd(ir);
-#else
- add(ir, elapsed, split, false);
-#endif // FAST_PICTURESET
- cliperator.next();
- }
- }
-}
-
-#ifdef FAST_PICTURESET
-
-Bucket* PictureSet::getBucket(int x, int y)
-{
- // only create buckets for valid, positive coordinates, ignore and return
- // NULL otherwise
- if (x < 0 || y < 0)
- return 0;
-
- BucketPosition position(x+1, y+1);
- if (!mBuckets.contains(position)) {
- ALOGV("PictureSet::getBucket(%d, %d) adding new bucket", x, y);
- Bucket* bucket = new Bucket();
- mBuckets.add(position, bucket);
- }
- return mBuckets.get(position);
-}
-
-void PictureSet::displayBucket(Bucket* bucket)
-{
- BucketPicture* first = bucket->begin();
- BucketPicture* last = bucket->end();
- for (BucketPicture* current = first; current != last; current++) {
- ALOGD("- in %x, bucketPicture %d,%d,%d,%d - %dx%d, picture: %x, base: %x",
- bucket,
- current->mArea.fLeft,
- current->mArea.fTop,
- current->mArea.fRight,
- current->mArea.fBottom,
- current->mArea.width(),
- current->mArea.height(),
- current->mPicture,
- current->mBase);
- }
-}
-
-void PictureSet::displayBuckets()
-{
- ALOGD("\n\n****** DISPLAY BUCKETS ON PictureSet %x ******", this);
- for (BucketMap::iterator iter = mBuckets.begin(); iter != mBuckets.end(); ++iter) {
- ALOGD("\n*** Bucket %x for %d, %d", iter->second, iter->first.first, iter->first.second);
- displayBucket(iter->second);
- }
- ALOGD("\n****** END OF DISPLAY BUCKETS ******\n\n");
-}
-
-// When we receive an inval in a Bucket, we try to see if we intersect with
-// existing invals/pictures in the Bucket.
-void PictureSet::addToBucket(Bucket* bucket, int dx, int dy, SkIRect& rect)
-{
- bool resetBase = false;
-
- SkIRect totalArea = rect;
- BucketPicture* first = bucket->begin();
- BucketPicture* last = bucket->end();
-
- // If the inval covers a large area of the base inval, let's repaint the
- // entire bucket.
- if (rect.width() * rect.height() > MAX_ADDITIONAL_AREA * mBucketSizeX * mBucketSizeY)
- resetBase = true;
-
- // let's gather all the BucketPicture intersecting with the new invalidated
- // area, collect their area and remove their picture
- for (BucketPicture* current = first; current != last; current++) {
- bool remove = resetBase;
- bool intersect = false;
-
- if (!remove)
- intersect = SkIRect::Intersects(current->mArea, rect);
- // If the current picture is not a base, and we intersect, remove it
- if (!remove && !current->mBase && intersect)
- remove = true;
- // If the current picture is a base, check if the new inval completely
- // contains the base, and if so remove it.
- if (!remove && current->mBase && rect.contains(current->mArea))
- remove = true;
- // If the current picture is a base and it intersects,
- // also check that it fully covers the bucket -- otherwise,
- // let's aggregate it with the new inval.
- if (!remove && current->mBase && intersect
- && (current->mArea.width() < mBucketSizeX || current->mArea.height() < mBucketSizeY)) {
- remove = true;
- }
-
- if (remove) {
- totalArea.join(current->mArea);
- current->mBase = false;
- current->mArea.setEmpty();
- SkSafeUnref(current->mPicture);
- current->mPicture = 0;
- }
- }
-
- // Now, let's add the new BucketPicture to the list, with the correct
- // area that needs to be repainted
- SkRegion region;
- SkIRect area = totalArea;
- area.offset(dx, dy);
- BucketPicture picture = { 0, totalArea, area, false };
-
- bucket->append(picture);
-
- first = bucket->begin();
- last = bucket->end();
-
- bool clearUp = false;
- if (last - first > MAX_ADDITIONAL_PICTURES) {
- // too many pictures in the bucket, let's collapse
- clearUp = true;
- }
-
- float bucketBaseArea = 0;
- float bucketAdditionalArea = 0;
- for (BucketPicture* current = first; current != last; current++) {
- float area = current->mArea.width() * current->mArea.height();
- if (current->mBase)
- bucketBaseArea += area;
- else
- bucketAdditionalArea += area;
- }
-
- if (bucketBaseArea > 0 && bucketBaseArea * MAX_ADDITIONAL_AREA <= bucketAdditionalArea) {
- // additional area too large, not worth maintaining
- clearUp = true;
- }
-
- // To clear things up, we just need to mark the pictures' area as empty
- // We only keep the base surface.
- if (clearUp) {
- for (BucketPicture* current = first; current != last; current++) {
- if (!current->mBase)
- current->mArea.setEmpty();
- SkSafeUnref(current->mPicture);
- current->mPicture = 0;
- }
- }
-
- // let's do a pass to collapse out empty areas
- BucketPicture* writer = first;
- for (BucketPicture* current = first; current != last; current++) {
- if (current && current->mArea.isEmpty())
- continue;
- *writer++ = *current;
- }
-
- bucket->shrink(writer - first);
-
- // let's recompute the bases
- first = bucket->begin();
- last = bucket->end();
- SkRegion drawn;
- drawn.setEmpty();
- for (BucketPicture* current = first; current != last; current++) {
- if (drawn.contains(current->mArea) == false) {
- current->mBase = true;
- }
- drawn.op(current->mArea, SkRegion::kUnion_Op);
- }
-}
-
-void PictureSet::gatherBucketsForArea(WTF::Vector<Bucket*>& list, const SkIRect& rect)
-{
- ALOGV("\n--- gatherBucketsForArea for rect %d, %d, %d, %d (%d x %d)",
- rect.fLeft, rect.fTop, rect.fRight, rect.fBottom,
- rect.width(), rect.height());
-
- if (!mBucketSizeX || !mBucketSizeY) {
- ALOGD("PictureSet::gatherBucketsForArea() called with bad bucket size: x=%d y=%d",
- mBucketSizeX, mBucketSizeY);
- return;
- }
-
- int x = rect.fLeft;
- int y = rect.fTop;
- int firstTileX = rect.fLeft / mBucketSizeX;
- int firstTileY = rect.fTop / mBucketSizeY;
- int lastTileX = rect.fRight / mBucketSizeX;
- int lastTileY = rect.fBottom / mBucketSizeY;
-
- for (int i = firstTileX; i <= lastTileX; i++) {
- for (int j = firstTileY; j <= lastTileY; j++) {
- Bucket* bucket = getBucket(i, j);
- ALOGV("gather bucket %x for %d, %d", bucket, i+1, j+1);
- if (bucket)
- list.append(bucket);
- }
- }
-}
-
-// When we receive a new inval rect, we first find the Buckets that intersect
-// with it; then we split the original inval into a serie of invals (one for
-// each Bucket we intersect with). We then send that inval to the Bucket.
-void PictureSet::splitAdd(const SkIRect& rect)
-{
- ALOGV("\n--- splitAdd for rect %d, %d, %d, %d (%d x %d)",
- rect.fLeft, rect.fTop, rect.fRight, rect.fBottom,
- rect.width(), rect.height());
-
- if (!mBucketSizeX || !mBucketSizeY) {
- ALOGD("PictureSet::splitAdd() called with bad bucket size: x=%d y=%d",
- mBucketSizeX, mBucketSizeY);
- return;
- }
-
- // TODO: reuse gatherBucketsForArea() (change Bucket to be a class)
- int x = rect.fLeft;
- int y = rect.fTop;
- int firstTileX = rect.fLeft / mBucketSizeX;
- int firstTileY = rect.fTop / mBucketSizeY;
- int lastTileX = rect.fRight / mBucketSizeX;
- int lastTileY = rect.fBottom / mBucketSizeY;
-
- ALOGV("--- firstTile(%d, %d) lastTile(%d, %d)",
- firstTileX, firstTileY,
- lastTileX, lastTileY);
-
- for (int i = firstTileX; i <= lastTileX; i++) {
- for (int j = firstTileY; j <= lastTileY; j++) {
- Bucket* bucket = getBucket(i, j);
- if (!bucket)
- continue;
-
- SkIRect newRect;
- int deltaX = i * mBucketSizeX;
- int deltaY = j * mBucketSizeY;
- int left = (i == firstTileX) ? rect.fLeft - deltaX : 0;
- int top = (j == firstTileY) ? rect.fTop - deltaY : 0;
- int right = (i == lastTileX) ? rect.fRight % mBucketSizeX : mBucketSizeX;
- int bottom = (j == lastTileY) ? rect.fBottom % mBucketSizeY : mBucketSizeY;
-
- newRect.set(left, top, right, bottom);
- addToBucket(bucket, deltaX, deltaY, newRect);
- mUpdatedBuckets.append(bucket);
- }
- }
-
- ALOGV("--- splitAdd DONE\n");
-}
-
-#endif // FAST_PICTURESET
-
-// This function is used to maintain the list of Pictures.
-// Pictures contain an SkPicture covering a specific area; some
-// Pictures are "base" Pictures -- i.e. there is no Pictures
-// underneath them.
-// The idea here is to keep a balance between the number of Pictures
-// we have (more Pictures slow us down) and the area of Pictures that
-// need to be repainted (obviously, smaller areas are better).
-// To do so, we try to not update/repaint the base pictures -- by
-// construction, they usually cover a large area (the entire page).
-// We only reset a base picture if the new invalidated area entirely
-// contains it.
-// Most of the time we thus work on smaller pictures on top of the
-// base ones; We compute the total area of all pictures intersecting
-// with the passed invalidated area (as they would need to be invalidated),
-// and use that as the basis for the correct area we want to invalidate
-// (we then can simply delete the pictures we intersect with).
-// In addition, we do a couple of things to limit the total number of pictures
-// we keep in the list:
-// - if the total area of additional textures reach 65% of the base pictures,
-// we delete the additional pictures and mark the base pictures as
-// needing a full repaint
-// - we limit the number of pictures to 32 -- above that, we do the same
-// things (deleting additional pictures + full repaint of base pictures)
-#ifdef FAST_PICTURESET
-#else
-void PictureSet::add(const SkIRect& area, uint32_t elapsed, bool split, bool empty)
-{
- bool checkForNewBases = false;
-
- Pictures* first = mPictures.begin();
- Pictures* last = mPictures.end();
-#ifdef DEBUG
- ALOGV("--- before adding the new inval ---");
- for (Pictures* working = mPictures.begin(); working != mPictures.end(); working++) {
- SkIRect currentArea = working->mArea;
- ALOGV("picture %d (%d, %d, %d, %d - %d x %d) base: %c",
- working - first,
- currentArea.fLeft, currentArea.fTop, currentArea.fRight, currentArea.fBottom,
- currentArea.width(), currentArea.height(),
- working->mBase ? 'Y' : 'N');
- }
- ALOGV("----------------------------------");
-#endif
-
- // let's gather all the Pictures intersecting with the new invalidated
- // area, collect their area and remove their picture
- SkIRect totalArea = area;
- for (Pictures* working = first; working != last; working++) {
- SkIRect inval = area;
- bool remove = false;
- if (!working->mBase && SkIRect::Intersects(working->mArea, inval))
- remove = true;
- if (working->mBase) {
- SkIRect baseArea = working->mArea;
- if (area.contains(baseArea)) {
- remove = true;
- checkForNewBases = true;
- }
- }
-
- if (remove) {
- SkIRect currentArea = working->mArea;
- if (working->mBase)
- mBaseArea -= currentArea.width() * currentArea.height();
- else
- mAdditionalArea -= currentArea.width() * currentArea.height();
-
- totalArea.join(currentArea);
- ALOGV("picture %d (%d, %d, %d, %d - %d x %d) intersects with the new inval area (%d, %d, %d, %d - %d x %d)",
- working - first,
- currentArea.fLeft, currentArea.fTop, currentArea.fRight, currentArea.fBottom,
- currentArea.width(), currentArea.height(),
- inval.fLeft, inval.fTop, inval.fRight, inval.fBottom,
- inval.width(), inval.height());
- working->mArea.setEmpty();
- SkSafeUnref(working->mPicture);
- working->mPicture = 0;
-#ifdef CONTEXT_RECORDING
- SkSafeUnref(working->mGraphicsOperationCollection);
- working->mGraphicsOperationCollection = 0;
-#endif
- }
- }
-
- // Now we can add the new Picture to the list, with the correct area
- // that need to be repainted
- Pictures pictureAndBounds = {totalArea, 0,
-#ifdef CONTEXT_RECORDING
- 0,
-#endif
- totalArea, elapsed, split, false, false, empty};
-
-#ifdef FAST_PICTURESET
- if (mPictures.size() == 0)
- checkForNewBases = true;
-#endif
-
- if (!size()) {
- pictureAndBounds.mBase = true;
- mBaseArea = totalArea.width() * totalArea.height();
- mAdditionalArea = 0;
- mPictures.append(pictureAndBounds);
- return;
- }
- mPictures.append(pictureAndBounds);
- mAdditionalArea += totalArea.width() * totalArea.height();
- last = mPictures.end();
- first = mPictures.begin();
-
- // Then, let's see if we have to clear up the pictures in order to keep
- // the total number of pictures under our limit
- bool clearUp = false;
- if (last - first > MAX_ADDITIONAL_PICTURES) {
- ALOGV("--- too many pictures, only keeping the bases : %d", last - first);
- clearUp = true;
- }
-
- if (!clearUp) {
- if (mBaseArea > 0 && mBaseArea * MAX_ADDITIONAL_AREA <= mAdditionalArea) {
- ALOGV("+++ the sum of the additional area is > %.2f\% of the base Area (%.2f (%.2f) <= %.2f",
- MAX_ADDITIONAL_AREA * 100, mBaseArea * 0.65, mBaseArea, mAdditionalArea);
- clearUp = true;
- }
- }
-
- if (clearUp) {
- for (Pictures* working = mPictures.begin(); working != mPictures.end(); working++) {
- if (!working->mBase)
- working->mArea.setEmpty();
- SkSafeUnref(working->mPicture);
- working->mPicture = 0;
-#ifdef CONTEXT_RECORDING
- SkSafeUnref(working->mGraphicsOperationCollection);
- working->mGraphicsOperationCollection = 0;
-#endif
- }
- }
-
-#ifdef DEBUG
- ALOGV("--- after adding the new inval, but before collapsing ---");
- for (Pictures* working = mPictures.begin(); working != mPictures.end(); working++) {
- SkIRect currentArea = working->mArea;
- ALOGV("picture %d (%d, %d, %d, %d - %d x %d) base: %c",
- working - first,
- currentArea.fLeft, currentArea.fTop, currentArea.fRight, currentArea.fBottom,
- currentArea.width(), currentArea.height(),
- working->mBase ? 'Y' : 'N');
- }
- ALOGV("----------------------------------");
- ALOGV("let's collapse...");
-#endif
-
- // Finally, let's do a pass to collapse out empty regions
- Pictures* writer = first;
- for (Pictures* working = first; working != last; working++) {
- if (working && working->mArea.isEmpty())
- continue;
- *writer++ = *working;
- }
- ALOGV("shiking of %d elements", writer - first);
- mPictures.shrink(writer - first);
-
-#ifdef DEBUG
- ALOGV("--- after adding the new inval ---");
- for (Pictures* working = mPictures.begin(); working != mPictures.end(); working++) {
- SkIRect currentArea = working->mArea;
- ALOGV("picture %d (%d, %d, %d, %d - %d x %d) base: %c picture %x",
- working - first,
- currentArea.fLeft, currentArea.fTop, currentArea.fRight, currentArea.fBottom,
- currentArea.width(), currentArea.height(),
- working->mBase ? 'Y' : 'N', working->mPicture);
- }
- ALOGV("----------------------------------");
-#endif
-
- // Base pictures might have been removed/added -- let's recompute them
- SkRegion drawn;
- if (checkForNewBases) {
- drawn.setEmpty();
- Pictures* last = mPictures.end();
- ALOGV("checkForNewBases...");
- for (Pictures* working = mPictures.begin(); working != last; working++) {
- SkRegion area;
- area.setRect(working->mArea);
- const SkIRect& a = area.getBounds();
- if (drawn.contains(working->mArea) == false) {
- working->mBase = true;
- float area = a.width() * a.height();
- mBaseArea += area;
- mAdditionalArea -= area;
- }
- drawn.op(working->mArea, SkRegion::kUnion_Op);
- }
- }
-
-#ifdef DEBUG
- ALOGV("--- after checking for bases ---");
- for (Pictures* working = mPictures.begin(); working != mPictures.end(); working++) {
- SkIRect currentArea = working->mArea;
- ALOGV("picture %d (%d, %d, %d, %d - %d x %d) base: %c picture %x",
- working - first,
- currentArea.fLeft, currentArea.fTop, currentArea.fRight, currentArea.fBottom,
- currentArea.width(), currentArea.height(),
- working->mBase ? 'Y' : 'N', working->mPicture);
- }
- ALOGV("----------------------------------");
-#endif
-}
-#endif // FAST_PICTURESET
-
-void PictureSet::setDimensions(int width, int height, SkRegion* inval)
-{
- // Note that setDimensions() may be called by our ctor and should behave accordingly
- if (mWidth == width && mHeight == height)
- return;
- DBG_SET_LOGD("%p old:(w=%d,h=%d) new:(w=%d,h=%d)", this,
- mWidth, mHeight, width, height);
- bool clearCache = false;
- if (inval) {
- if (mWidth == width && height > mHeight) { // only grew vertically
- SkIRect rect;
- rect.set(0, mHeight, width, height);
- inval->op(rect, SkRegion::kUnion_Op);
- } else {
- clearCache = true;
- inval->setRect(0, 0, width, height);
- }
- }
-#ifdef FAST_PICTURESET
- // First figure out how large each bucket would be if we used all of the buckets
- int tmpSizeX = (width + MAX_BUCKET_COUNT_X - 1) / MAX_BUCKET_COUNT_X;
- int tmpSizeY = (height + MAX_BUCKET_COUNT_Y - 1) / MAX_BUCKET_COUNT_Y;
-
- // Then round the bucket size up to the nearest chunk
- int bucketSizeX = ((tmpSizeX - 1) / BUCKET_SIZE + 1) * BUCKET_SIZE;
- int bucketSizeY = ((tmpSizeY - 1) / BUCKET_SIZE + 1) * BUCKET_SIZE;
-
- int bucketCountX = (width + bucketSizeX - 1) / bucketSizeX;
- int bucketCountY = (height + bucketSizeY - 1) / bucketSizeY;
-
- // Clear the cache if the horizontal bucket count changed or the vertical
- // count shrank
- if (bucketCountX != mBucketCountX || bucketCountY < mBucketCountY)
- clearCache = true;
-
- // Or if the bucket size changed
- if (bucketSizeX != mBucketSizeX || bucketSizeY != mBucketSizeY)
- clearCache = true;
-
- ALOGV("old width=%d height=%d bucketSizeX=%d bucketSizeY=%d bucketCountX=%d bucketCountY=%d clearCache=%d",
- mWidth, mHeight, mBucketSizeX, mBucketSizeY, mBucketCountX, mBucketCountY, clearCache);
- ALOGV("new width=%d height=%d bucketSizeX=%d bucketSizeY=%d bucketCountX=%d bucketCountY=%d clearCache=%d",
- width, height, bucketSizeX, bucketSizeY, bucketCountX, bucketCountY, clearCache);
-#endif
- if (clearCache)
- clear();
- mWidth = width;
- mHeight = height;
-#ifdef FAST_PICTURESET
- mBucketSizeX = bucketSizeX;
- mBucketSizeY = bucketSizeY;
- mBucketCountX = bucketCountX;
- mBucketCountY = bucketCountY;
-#endif
-}
-
-void PictureSet::clear()
-{
- DBG_SET_LOG("");
-#ifdef FAST_PICTURESET
- for (BucketMap::iterator iter = mBuckets.begin(); iter != mBuckets.end(); ++iter) {
- Bucket* bucket = iter->second;
- BucketPicture* first = bucket->begin();
- BucketPicture* last = bucket->end();
- for (BucketPicture* current = first; current != last; current++) {
- SkSafeUnref(current->mPicture);
- current->mPicture = 0;
- }
- bucket->clear();
- }
- mBuckets.clear();
- mBucketSizeX = mBucketSizeY = BUCKET_SIZE;
-#else
- Pictures* last = mPictures.end();
- for (Pictures* working = mPictures.begin(); working != last; working++) {
- working->mArea.setEmpty();
- SkSafeUnref(working->mPicture);
-#ifdef CONTEXT_RECORDING
- SkSafeUnref(working->mGraphicsOperationCollection);
-#endif
- }
- mPictures.clear();
-#endif // FAST_PICTURESET
- mWidth = mHeight = 0;
-}
-
-uint32_t getThreadMsec()
-{
-#if defined(HAVE_POSIX_CLOCKS)
- struct timespec tm;
-
- clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tm);
- return tm.tv_sec * 1000LL + tm.tv_nsec / 1000000;
-#else
- struct timeval now;
- struct timezone zone;
-
- gettimeofday(&now, &zone);
- return now.tv_sec * 1000LL + now.tv_usec / 1000;
-#endif
-}
-
-bool PictureSet::draw(SkCanvas* canvas)
-{
-#ifdef FAST_PICTURESET
- ALOGV("PictureSet %x draw on canvas %x", this, canvas);
- SkRect bounds;
- if (canvas->getClipBounds(&bounds) == false)
- return false;
- SkIRect irect;
- bounds.roundOut(&irect);
-
- WTF::Vector<Bucket*> list;
- gatherBucketsForArea(list, irect);
-
- ALOGV("PictureSet draw on canvas %x, we have %d buckets", canvas, list.size());
- for (unsigned int i = 0; i < list.size(); i++) {
- Bucket* bucket = list[i];
- ALOGV("We paint using bucket %x with %d pictures", bucket, bucket->size());
- for (unsigned int j = 0; j < bucket->size(); j++) {
- BucketPicture& picture = bucket->at(j);
- if (!picture.mPicture)
- continue;
- int saved = canvas->save();
- SkRect pathBounds;
- pathBounds.set(picture.mRealArea);
- ALOGV("[%d/%d] draw on canvas with clip %d, %d, %d, %d - %d x %d",
- j, bucket->size(),
- picture.mRealArea.fLeft,
- picture.mRealArea.fTop,
- picture.mRealArea.fRight,
- picture.mRealArea.fBottom,
- picture.mRealArea.width(),
- picture.mRealArea.height());
- canvas->clipRect(pathBounds);
- canvas->translate(pathBounds.fLeft, pathBounds.fTop);
- canvas->save();
- canvas->drawPicture(*picture.mPicture);
- canvas->restoreToCount(saved);
- }
- }
- return false;
-
-#else
-
- validate(__FUNCTION__);
- Pictures* first = mPictures.begin();
- Pictures* last = mPictures.end();
- Pictures* working;
- SkRect bounds;
- if (canvas->getClipBounds(&bounds) == false)
- return false;
- SkIRect irect;
- bounds.roundOut(&irect);
- if (!irect.intersect(0, 0, width(), height()))
- return false;
- for (working = last; working != first; ) {
- --working;
- if (working->mArea.contains(irect)) {
-#if PICTURE_SET_DEBUG
- const SkIRect& b = working->mArea;
- DBG_SET_LOGD("contains working->mArea={%d,%d,%d,%d}"
- " irect={%d,%d,%d,%d}", b.fLeft, b.fTop, b.fRight, b.fBottom,
- irect.fLeft, irect.fTop, irect.fRight, irect.fBottom);
-#endif
- first = working;
- break;
- }
- }
- DBG_SET_LOGD("%p first=%d last=%d", this, first - mPictures.begin(),
- last - mPictures.begin());
- uint32_t maxElapsed = 0;
- for (working = first; working != last; working++) {
- SkRegion area;
- area.setRect(working->mArea);
- if (area.quickReject(irect)) {
-#if PICTURE_SET_DEBUG
- const SkIRect& b = area.getBounds();
- DBG_SET_LOGD("[%d] %p quickReject working->mArea={%d,%d,%d,%d}"
- " irect={%d,%d,%d,%d}", working - first, working,
- b.fLeft, b.fTop, b.fRight, b.fBottom,
- irect.fLeft, irect.fTop, irect.fRight, irect.fBottom);
-#endif
- working->mElapsed = 0;
- continue;
- }
- int saved = canvas->save();
- SkRect pathBounds;
- if (area.isComplex()) {
- SkPath pathClip;
- area.getBoundaryPath(&pathClip);
- canvas->clipPath(pathClip);
- pathBounds = pathClip.getBounds();
- } else {
- pathBounds.set(area.getBounds());
- canvas->clipRect(pathBounds);
- }
- canvas->translate(pathBounds.fLeft, pathBounds.fTop);
- canvas->save();
- uint32_t startTime = getThreadMsec();
-
-#ifdef CONTEXT_RECORDING
- WebCore::PlatformGraphicsContextSkia context(canvas);
- working->mGraphicsOperationCollection->apply(&context);
-#else
- canvas->drawPicture(*working->mPicture);
-#endif
-
- size_t elapsed = working->mElapsed = getThreadMsec() - startTime;
- working->mWroteElapsed = true;
- if (maxElapsed < elapsed && (pathBounds.width() >= MIN_SPLITTABLE ||
- pathBounds.height() >= MIN_SPLITTABLE))
- maxElapsed = elapsed;
- canvas->restoreToCount(saved);
-#define DRAW_TEST_IMAGE 01
-#if DRAW_TEST_IMAGE && PICTURE_SET_DEBUG
- SkColor color = 0x3f000000 | (0xffffff & (unsigned) working);
- canvas->drawColor(color);
- SkPaint paint;
- color ^= 0x00ffffff;
- paint.setColor(color);
- char location[256];
- for (int x = area.getBounds().fLeft & ~0x3f;
- x < area.getBounds().fRight; x += 0x40) {
- for (int y = area.getBounds().fTop & ~0x3f;
- y < area.getBounds().fBottom; y += 0x40) {
- int len = snprintf(location, sizeof(location) - 1, "(%d,%d)", x, y);
- canvas->drawText(location, len, x, y, paint);
- }
- }
-#endif
- DBG_SET_LOGD("[%d] %p working->mArea={%d,%d,%d,%d} elapsed=%d base=%s",
- working - first, working,
- area.getBounds().fLeft, area.getBounds().fTop,
- area.getBounds().fRight, area.getBounds().fBottom,
- working->mElapsed, working->mBase ? "true" : "false");
- }
- // dump(__FUNCTION__);
- return maxElapsed >= MAX_DRAW_TIME;
-#endif // FAST_PICTURESET
-}
-
-void PictureSet::dump(const char* label) const
-{
-#if PICTURE_SET_DUMP
- DBG_SET_LOGD("%p %s (%d) (w=%d,h=%d)", this, label, mPictures.size(),
- mWidth, mHeight);
- const Pictures* last = mPictures.end();
- for (const Pictures* working = mPictures.begin(); working != last; working++) {
- const SkIRect& bounds = working->mArea.getBounds();
- const SkIRect& unsplit = working->mUnsplit;
- MeasureStream measure;
- if (working->mPicture != NULL)
- working->mPicture->serialize(&measure);
- ALOGD(" [%d]"
- " mArea.bounds={%d,%d,r=%d,b=%d}"
- " mPicture=%p"
- " mUnsplit={%d,%d,r=%d,b=%d}"
- " mElapsed=%d"
- " mSplit=%s"
- " mWroteElapsed=%s"
- " mBase=%s"
- " pict-size=%d",
- working - mPictures.begin(),
- bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom,
- working->mPicture,
- unsplit.fLeft, unsplit.fTop, unsplit.fRight, unsplit.fBottom,
- working->mElapsed, working->mSplit ? "true" : "false",
- working->mWroteElapsed ? "true" : "false",
- working->mBase ? "true" : "false",
- measure.mTotal);
- }
-#endif
-}
-
-class IsEmptyBounder : public SkBounder {
- virtual bool onIRect(const SkIRect& rect) {
- return false;
- }
-};
-
-class IsEmptyCanvas : public SkCanvas {
-public:
- IsEmptyCanvas(SkBounder* bounder, SkPicture* picture) :
- mPicture(picture), mEmpty(true) {
- setBounder(bounder);
- }
-
- void notEmpty() {
- mEmpty = false;
- mPicture->abortPlayback();
- }
-
- virtual bool clipPath(const SkPath&, SkRegion::Op) {
- // this can be expensive to actually do, and doesn't affect the
- // question of emptiness, so we make it a no-op
- return true;
- }
-
- virtual void commonDrawBitmap(const SkBitmap& bitmap, const SkIRect* rect,
- const SkMatrix& , const SkPaint& ) {
- if (bitmap.width() <= 1 || bitmap.height() <= 1)
- return;
- DBG_SET_LOGD("abort {%d,%d}", bitmap.width(), bitmap.height());
- notEmpty();
- }
-
- virtual void drawPaint(const SkPaint& paint) {
- }
-
- virtual void drawPath(const SkPath& , const SkPaint& paint) {
- DBG_SET_LOG("abort");
- notEmpty();
- }
-
- virtual void drawPoints(PointMode , size_t , const SkPoint [],
- const SkPaint& paint) {
- }
-
- virtual void drawRect(const SkRect& , const SkPaint& paint) {
- // wait for visual content
- if (paint.getColor() != SK_ColorWHITE)
- notEmpty();
- }
-
- virtual void drawSprite(const SkBitmap& , int , int ,
- const SkPaint* paint = NULL) {
- DBG_SET_LOG("abort");
- notEmpty();
- }
-
- virtual void drawText(const void* , size_t byteLength, SkScalar ,
- SkScalar , const SkPaint& paint) {
- DBG_SET_LOGD("abort %d", byteLength);
- notEmpty();
- }
-
- virtual void drawPosText(const void* , size_t byteLength,
- const SkPoint [], const SkPaint& paint) {
- DBG_SET_LOGD("abort %d", byteLength);
- notEmpty();
- }
-
- virtual void drawPosTextH(const void* , size_t byteLength,
- const SkScalar [], SkScalar ,
- const SkPaint& paint) {
- DBG_SET_LOGD("abort %d", byteLength);
- notEmpty();
- }
-
- virtual void drawTextOnPath(const void* , size_t byteLength,
- const SkPath& , const SkMatrix* ,
- const SkPaint& paint) {
- DBG_SET_LOGD("abort %d", byteLength);
- notEmpty();
- }
-
- virtual void drawPicture(SkPicture& picture) {
- SkCanvas::drawPicture(picture);
- }
-
- SkPicture* mPicture;
- bool mEmpty;
-};
-
-bool PictureSet::emptyPicture(SkPicture* picture) const
-{
- IsEmptyBounder isEmptyBounder;
- IsEmptyCanvas checker(&isEmptyBounder, picture);
- SkBitmap bitmap;
- bitmap.setConfig(SkBitmap::kARGB_8888_Config, mWidth, mHeight);
- checker.setBitmapDevice(bitmap);
- checker.drawPicture(*picture);
- return checker.mEmpty;
-}
-
-bool PictureSet::isEmpty() const
-{
-#ifdef FAST_PICTURESET
- // For now, just assume the pictureset is *not* empty
- // if the hashmap contains something
- for (BucketMap::const_iterator iter = mBuckets.begin(); iter != mBuckets.end(); ++iter) {
- if (iter->second->size() > 0)
- return false;
- }
- return true;
-#else
- const Pictures* last = mPictures.end();
- for (const Pictures* working = mPictures.begin(); working != last; working++) {
- if (!working->mEmpty)
- return false;
- }
- return true;
-#endif // FAST_PICTURESET
-}
-
-void PictureSet::set(const PictureSet& src)
-{
- DBG_SET_LOGD("start %p src=%p", this, &src);
- clear();
- setDimensions(src.mWidth, src.mHeight);
-#ifdef FAST_PICTURESET
- ALOGV("\n--- set picture ---");
- for (BucketMap::const_iterator iter = src.mBuckets.begin();
- iter != src.mBuckets.end(); ++iter) {
- Bucket* sourceBucket = iter->second;
- Bucket* targetBucket = getBucket(iter->first.first-1, iter->first.second-1);
- BucketPicture* first = sourceBucket->begin();
- BucketPicture* last = sourceBucket->end();
- ALOGV("set from bucket %x (%d, %d), %d pictures", sourceBucket,
- iter->first.first, iter->first.second, sourceBucket->size());
- for (BucketPicture* current = first; current != last; current++) {
- ALOGV("set picture %x from bucket %x in bucket %x (%d, %d)",
- current->mPicture, sourceBucket, targetBucket,
- iter->first.first, iter->first.second);
- SkSafeRef(current->mPicture);
- BucketPicture picture = { current->mPicture, current->mArea,
- current->mRealArea, current->mBase };
- targetBucket->append(picture);
- }
- }
- ALOGV("--- DONE set picture ---\n");
-#else
- const Pictures* last = src.mPictures.end();
- for (const Pictures* working = src.mPictures.begin(); working != last; working++)
- add(working);
- // dump(__FUNCTION__);
- validate(__FUNCTION__);
- DBG_SET_LOG("end");
-#endif // FAST_PICTURESET
-}
-
-#ifdef FAST_PICTURESET
-#else
-
-void PictureSet::setDrawTimes(const PictureSet& src)
-{
- validate(__FUNCTION__);
- if (mWidth != src.mWidth || mHeight != src.mHeight)
- return;
- Pictures* last = mPictures.end();
- Pictures* working = mPictures.begin();
- if (working == last)
- return;
- const Pictures* srcLast = src.mPictures.end();
- const Pictures* srcWorking = src.mPictures.begin();
- for (; srcWorking != srcLast; srcWorking++) {
- if (srcWorking->mWroteElapsed == false)
- continue;
- while ((srcWorking->mArea != working->mArea ||
- srcWorking->mPicture != working->mPicture)) {
- if (++working == last)
- return;
- }
- DBG_SET_LOGD("%p [%d] [%d] {%d,%d,r=%d,b=%d} working->mElapsed=%d <- %d",
- this, working - mPictures.begin(), srcWorking - src.mPictures.begin(),
- working->mArea.fLeft, working->mArea.fTop,
- working->mArea.fRight, working->mArea.fBottom,
- working->mElapsed, srcWorking->mElapsed);
- working->mElapsed = srcWorking->mElapsed;
- }
-}
-
-void PictureSet::setPicture(size_t i, SkPicture* p)
-{
- SkSafeUnref(mPictures[i].mPicture);
- mPictures[i].mPicture = p;
- mPictures[i].mEmpty = emptyPicture(p);
-}
-
-#ifdef CONTEXT_RECORDING
-void PictureSet::setGraphicsOperationCollection(size_t i, WebCore::GraphicsOperationCollection* p)
-{
- SkSafeUnref(mPictures[i].mGraphicsOperationCollection);
- mPictures[i].mGraphicsOperationCollection = p;
-}
-#endif
-
-void PictureSet::split(PictureSet* out) const
-{
- dump(__FUNCTION__);
- DBG_SET_LOGD("%p", this);
- SkIRect totalBounds;
- out->mWidth = mWidth;
- out->mHeight = mHeight;
- totalBounds.set(0, 0, mWidth, mHeight);
- SkRegion* total = new SkRegion(totalBounds);
- const Pictures* last = mPictures.end();
- const Pictures* working;
- uint32_t balance = 0;
- int multiUnsplitFastPictures = 0; // > 1 has more than 1
- for (working = mPictures.begin(); working != last; working++) {
- if (working->mElapsed >= MAX_DRAW_TIME || working->mSplit)
- continue;
- if (++multiUnsplitFastPictures > 1)
- break;
- }
- for (working = mPictures.begin(); working != last; working++) {
- uint32_t elapsed = working->mElapsed;
- if (elapsed < MAX_DRAW_TIME) {
- bool split = working->mSplit;
- DBG_SET_LOGD("elapsed=%d working=%p total->getBounds()="
- "{%d,%d,r=%d,b=%d} split=%s", elapsed, working,
- total->getBounds().fLeft, total->getBounds().fTop,
- total->getBounds().fRight, total->getBounds().fBottom,
- split ? "true" : "false");
- if (multiUnsplitFastPictures <= 1 || split) {
- total->op(working->mArea, SkRegion::kDifference_Op);
- out->add(working->mArea, elapsed, split,
- working->mEmpty);
- } else if (balance < elapsed)
- balance = elapsed;
- continue;
- }
- total->op(working->mArea, SkRegion::kDifference_Op);
- const SkIRect& bounds = working->mArea;
- int width = bounds.width();
- int height = bounds.height();
- int across = 1;
- int down = 1;
- while (height >= MIN_SPLITTABLE || width >= MIN_SPLITTABLE) {
- if (height >= width) {
- height >>= 1;
- down <<= 1;
- } else {
- width >>= 1;
- across <<= 1 ;
- }
- if ((elapsed >>= 1) < MAX_DRAW_TIME)
- break;
- }
- width = bounds.width();
- height = bounds.height();
- int top = bounds.fTop;
- for (int indexY = 0; indexY < down; ) {
- int bottom = bounds.fTop + height * ++indexY / down;
- int left = bounds.fLeft;
- for (int indexX = 0; indexX < across; ) {
- int right = bounds.fLeft + width * ++indexX / across;
- SkIRect cBounds;
- cBounds.set(left, top, right, bottom);
- out->add(cBounds, elapsed, true,
- (across | down) != 1 ? false : working->mEmpty);
- left = right;
- }
- top = bottom;
- }
- }
- DBG_SET_LOGD("%p w=%d h=%d total->isEmpty()=%s multiUnsplitFastPictures=%d",
- this, mWidth, mHeight, total->isEmpty() ? "true" : "false",
- multiUnsplitFastPictures);
- if (!total->isEmpty() && multiUnsplitFastPictures > 1)
- out->add(*total, balance, false);
- delete total;
- validate(__FUNCTION__);
- out->dump("split-out");
-}
-
-#endif // FAST_PICTURESET
-
-bool PictureSet::validate(const char* funct) const
-{
-#ifdef FAST_PICTURESET
- return true;
-#else
- bool valid = true;
-#if PICTURE_SET_VALIDATE
- SkRegion all;
- const Pictures* first = mPictures.begin();
- for (const Pictures* working = mPictures.end(); working != first; ) {
- --working;
- const SkPicture* pict = working->mPicture;
- const SkRegion& area = working->mArea;
- const SkIRect& bounds = area.getBounds();
- bool localValid = false;
- if (working->mUnsplit.isEmpty())
- ALOGD("%s working->mUnsplit.isEmpty()", funct);
- else if (working->mUnsplit.contains(bounds) == false)
- ALOGD("%s working->mUnsplit.contains(bounds) == false", funct);
- else if (working->mElapsed >= 1000)
- ALOGD("%s working->mElapsed >= 1000", funct);
- else if ((working->mSplit & 0xfe) != 0)
- ALOGD("%s (working->mSplit & 0xfe) != 0", funct);
- else if ((working->mWroteElapsed & 0xfe) != 0)
- ALOGD("%s (working->mWroteElapsed & 0xfe) != 0", funct);
- else if (pict != NULL) {
- int pictWidth = pict->width();
- int pictHeight = pict->height();
- if (pictWidth < bounds.width())
- ALOGD("%s pictWidth=%d < bounds.width()=%d", funct, pictWidth, bounds.width());
- else if (pictHeight < bounds.height())
- ALOGD("%s pictHeight=%d < bounds.height()=%d", funct, pictHeight, bounds.height());
- else if (working->mArea.isEmpty())
- ALOGD("%s working->mArea.isEmpty()", funct);
- else
- localValid = true;
- } else
- localValid = true;
- working->mArea.validate();
- if (localValid == false) {
- if (all.contains(area) == true)
- ALOGD("%s all.contains(area) == true", funct);
- else
- localValid = true;
- }
- valid &= localValid;
- all.op(area, SkRegion::kUnion_Op);
- }
- const SkIRect& allBounds = all.getBounds();
- if (valid) {
- valid = false;
- if (allBounds.width() != mWidth)
- ALOGD("%s allBounds.width()=%d != mWidth=%d", funct, allBounds.width(), mWidth);
- else if (allBounds.height() != mHeight)
- ALOGD("%s allBounds.height()=%d != mHeight=%d", funct, allBounds.height(), mHeight);
- else
- valid = true;
- }
- while (valid == false)
- ;
-#endif
- return valid;
-#endif // FAST_PICTURESET
-}
-
-} /* namespace android */
diff --git a/Source/WebKit/android/jni/PictureSet.h b/Source/WebKit/android/jni/PictureSet.h
deleted file mode 100644
index 1e639da..0000000
--- a/Source/WebKit/android/jni/PictureSet.h
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * Copyright 2008, 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 PictureSet_h
-#define PictureSet_h
-
-#define PICTURE_SET_DUMP 0
-#define PICTURE_SET_DEBUG 0
-#define PICTURE_SET_VALIDATE 0
-
-#if PICTURE_SET_DEBUG
-#define DBG_SET_LOG(message) ALOGD("%s %s", __FUNCTION__, message)
-#define DBG_SET_LOGD(format, ...) ALOGD("%s " format, __FUNCTION__, __VA_ARGS__)
-#define DEBUG_SET_UI_LOGD(...) ALOGD(__VA_ARGS__)
-#else
-#define DBG_SET_LOG(message) ((void)0)
-#define DBG_SET_LOGD(format, ...) ((void)0)
-#define DEBUG_SET_UI_LOGD(...) ((void)0)
-#endif
-
-#include "jni.h"
-#include "SkRegion.h"
-#include <wtf/Vector.h>
-#include <wtf/HashMap.h>
-
-#include "GraphicsOperationCollection.h"
-
-// #define FAST_PICTURESET // use a hierarchy of pictures
-// #define CONTEXT_RECORDING // use the new PlatformGraphicsContextRecording
-
-class SkCanvas;
-class SkPicture;
-class SkIRect;
-
-namespace android {
-
-#ifdef FAST_PICTURESET
- struct BucketPicture {
- SkPicture* mPicture;
- SkIRect mArea;
- SkIRect mRealArea;
- bool mBase;
- };
-
- typedef std::pair<int, int> BucketPosition;
- typedef WTF::Vector<BucketPicture> Bucket;
- typedef WTF::HashMap<BucketPosition , Bucket* > BucketMap;
-#endif
-
- class PictureSet {
- public:
- PictureSet();
- PictureSet(const PictureSet& src) { set(src); }
- PictureSet(SkPicture* picture);
- virtual ~PictureSet();
-
-#ifdef FAST_PICTURESET
- void displayBucket(Bucket* bucket);
- void displayBuckets();
- WTF::Vector<Bucket*>* bucketsToUpdate() { return &mUpdatedBuckets; }
- Bucket* getBucket(int x, int y);
- void addToBucket(Bucket* bucket, int dx, int dy, SkIRect& rect);
- void gatherBucketsForArea(WTF::Vector<Bucket*>& list, const SkIRect& rect);
- void splitAdd(const SkIRect& rect);
-#endif
-
- void add(const SkRegion& area, uint32_t elapsed, bool split);
-
- // Update mWidth/mHeight, and adds any additional inval region
- void setDimensions(int width, int height, SkRegion* inval = 0);
- void clear();
- bool draw(SkCanvas* );
- static PictureSet* GetNativePictureSet(JNIEnv* env, jobject jpic);
- int height() const { return mHeight; }
- bool isEmpty() const; // returns true if empty or only trivial content
- void set(const PictureSet& );
-
-#ifdef FAST_PICTURESET
-#else
- void add(const SkIRect& area, uint32_t elapsed, bool split, bool empty);
- const SkIRect& bounds(size_t i) const {
- return mPictures[i].mArea; }
- void setPicture(size_t i, SkPicture* p);
-#ifdef CONTEXT_RECORDING
- void setGraphicsOperationCollection(size_t i, WebCore::GraphicsOperationCollection* p);
-#endif
- void setDrawTimes(const PictureSet& );
- size_t size() const { return mPictures.size(); }
- void split(PictureSet* result) const;
- bool upToDate(size_t i) const { return mPictures[i].mPicture != NULL; }
-#endif
- int width() const { return mWidth; }
- void dump(const char* label) const;
- bool validate(const char* label) const;
- private:
- bool emptyPicture(SkPicture* ) const; // true if no text, images, paths
-
-#ifdef FAST_PICTURESET
- BucketMap mBuckets;
- WTF::Vector<Bucket*> mUpdatedBuckets;
- int mBucketSizeX;
- int mBucketSizeY;
- int mBucketCountX;
- int mBucketCountY;
-#else
-
- struct Pictures {
- SkIRect mArea;
- SkPicture* mPicture;
-#ifdef CONTEXT_RECORDING
- WebCore::GraphicsOperationCollection* mGraphicsOperationCollection;
-#endif
- SkIRect mUnsplit;
- uint32_t mElapsed;
- bool mSplit : 8;
- bool mWroteElapsed : 8;
- bool mBase : 8; // true if nothing is drawn underneath this
- bool mEmpty : 8; // true if the picture only draws white
- };
- void add(const Pictures* temp);
- WTF::Vector<Pictures> mPictures;
-#endif
- float mBaseArea;
- float mAdditionalArea;
- int mHeight;
- int mWidth;
- };
-}
-
-#endif
diff --git a/Source/WebKit/android/jni/ViewStateSerializer.cpp b/Source/WebKit/android/jni/ViewStateSerializer.cpp
index 5f2480a..02ddca6 100644
--- a/Source/WebKit/android/jni/ViewStateSerializer.cpp
+++ b/Source/WebKit/android/jni/ViewStateSerializer.cpp
@@ -38,7 +38,6 @@
#include "LayerAndroid.h"
#include "LayerContent.h"
#include "PictureLayerContent.h"
-#include "PictureSet.h"
#include "ScrollableLayerAndroid.h"
#include "SkFlattenable.h"
#include "SkPicture.h"
diff --git a/Source/WebKit/android/jni/WebCoreViewBridge.h b/Source/WebKit/android/jni/WebCoreViewBridge.h
index b04a0f9..cca4ca5 100644
--- a/Source/WebKit/android/jni/WebCoreViewBridge.h
+++ b/Source/WebKit/android/jni/WebCoreViewBridge.h
@@ -48,7 +48,7 @@ public:
virtual ~WebCoreViewBridge() { }
- virtual void draw(WebCore::GraphicsContext* ctx,
+ virtual void draw(WebCore::GraphicsContext* ctx,
const WebCore::IntRect& rect) = 0;
const WebCore::IntRect& getBounds() const
diff --git a/Source/WebKit/android/jni/WebViewCore.cpp b/Source/WebKit/android/jni/WebViewCore.cpp
index e0379a8..4e6ffc6 100644
--- a/Source/WebKit/android/jni/WebViewCore.cpp
+++ b/Source/WebKit/android/jni/WebViewCore.cpp
@@ -89,7 +89,7 @@
#include "Page.h"
#include "PageGroup.h"
#include "PictureLayerContent.h"
-#include "PictureSetLayerContent.h"
+#include "PicturePileLayerContent.h"
#include "PlatformKeyboardEvent.h"
#include "PlatformString.h"
#include "PluginWidgetAndroid.h"
@@ -169,17 +169,6 @@ FILE* gRenderTreeFile = 0;
#include "RenderLayerCompositor.h"
#endif
-// In some cases, too many invalidations passed to the UI will slow us down.
-// Limit ourselves to 32 rectangles, past this just send the area bounds to the UI.
-// see WebViewCore::recordPictureSet().
-#define MAX_INVALIDATIONS 32
-
-/* We pass this flag when recording the actual content, so that we don't spend
- time actually regionizing complex path clips, when all we really want to do
- is record them.
- */
-#define PICT_RECORD_FLAGS SkPicture::kUsePathBoundsForClip_RecordingFlag
-
////////////////////////////////////////////////////////////////////////////////////////////////
namespace android {
@@ -430,7 +419,6 @@ WebViewCore::WebViewCore(JNIEnv* env, jobject javaWebViewCore, WebCore::Frame* m
, m_scrollOffsetX(0)
, m_scrollOffsetY(0)
, m_mousePos(WebCore::IntPoint(0,0))
- , m_progressDone(false)
, m_screenWidth(320)
, m_screenHeight(240)
, m_textWrapWidth(320)
@@ -610,18 +598,8 @@ static bool layoutIfNeededRecursive(WebCore::Frame* f)
WebCore::FrameView* v = f->view();
if (!v)
return true;
-
- if (v->needsLayout())
- v->layout(f->tree()->parent());
-
- WebCore::Frame* child = f->tree()->firstChild();
- bool success = true;
- while (child) {
- success &= layoutIfNeededRecursive(child);
- child = child->tree()->nextSibling();
- }
-
- return success && !v->needsLayout();
+ v->updateLayoutAndStyleIfNeededRecursive();
+ return !v->needsLayout();
}
WebCore::Node* WebViewCore::currentFocus()
@@ -629,19 +607,16 @@ WebCore::Node* WebViewCore::currentFocus()
return focusedFrame()->document()->focusedNode();
}
-void WebViewCore::recordPictureSet(PictureSet* content)
+void WebViewCore::recordPicturePile()
{
TRACE_METHOD();
// if there is no document yet, just return
if (!m_mainFrame->document()) {
- DBG_SET_LOG("!m_mainFrame->document()");
- return;
- }
- if (m_addInval.isEmpty()) {
- DBG_SET_LOG("m_addInval.isEmpty()");
+ ALOGV("!m_mainFrame->document()");
return;
}
+
// Call layout to ensure that the contentWidth and contentHeight are correct
// it's fine for layout to gather invalidates, but defeat sending a message
// back to java to call webkitDraw, since we're already in the middle of
@@ -704,6 +679,8 @@ void WebViewCore::recordPictureSet(PictureSet* content)
// If the new total is larger than the content, resize the view to include
// all the content.
if (!contentRect.contains(total)) {
+ // TODO: Does this ever happen? Is this needed now that we don't flatten
+ // frames?
// Resize the view to change the overflow clip.
view->resize(total.fRight, total.fBottom);
@@ -723,51 +700,15 @@ void WebViewCore::recordPictureSet(PictureSet* content)
height = view->contentsHeight();
}
-#if USE(ACCELERATED_COMPOSITING)
- // The invals are not always correct when the content size has changed. For
- // now, let's just reset the inval so that it invalidates the entire content
- // -- the pictureset will be fully repainted, tiles will be marked dirty and
- // will have to be repainted.
-
- // FIXME: the webkit invals ought to have been enough...
- if (content->width() != width || content->height() != height) {
- SkIRect r;
- r.fLeft = 0;
- r.fTop = 0;
- r.fRight = width;
- r.fBottom = height;
- m_addInval.setRect(r);
- }
-#endif
-
- content->setDimensions(width, height, &m_addInval);
+ m_content.setSize(IntSize(width, height));
- // Add the current inval rects to the PictureSet, and rebuild it.
- content->add(m_addInval, 0, false);
-
- // If we have too many invalidations, just get the area bounds
- SkRegion::Iterator iterator(m_addInval);
- int nbInvals = 0;
- while (!iterator.done()) {
- iterator.next();
- nbInvals++;
- if (nbInvals > MAX_INVALIDATIONS)
- break;
- }
- if (nbInvals > MAX_INVALIDATIONS) {
- SkIRect r = m_addInval.getBounds();
- m_addInval.setRect(r);
- }
// Rebuild the pictureset (webkit repaint)
- rebuildPictureSet(content);
+ m_content.updatePicturesIfNeeded(this);
}
void WebViewCore::clearContent()
{
- DBG_SET_LOG("");
- m_content.clear();
- m_addInval.setEmpty();
- m_rebuildInval.setEmpty();
+ m_content.reset();
updateLocale();
}
@@ -778,86 +719,51 @@ bool WebViewCore::focusBoundsChanged()
return result;
}
-SkPicture* WebViewCore::rebuildPicture(const SkIRect& inval)
+void WebViewCore::paintContents(WebCore::GraphicsContext* gc, WebCore::IntRect& dirty)
{
WebCore::FrameView* view = m_mainFrame->view();
- int width = view->contentsWidth();
- int height = view->contentsHeight();
- SkPicture* picture = new SkPicture();
- SkAutoPictureRecord arp(picture, width, height, PICT_RECORD_FLAGS);
- SkAutoMemoryUsageProbe mup(__FUNCTION__);
- SkCanvas* recordingCanvas = arp.getRecordingCanvas();
- WebCore::PlatformGraphicsContextSkia pgc(recordingCanvas);
- WebCore::GraphicsContext gc(&pgc);
IntPoint origin = view->minimumScrollPosition();
- WebCore::IntRect drawArea(inval.fLeft + origin.x(), inval.fTop + origin.y(),
- inval.width(), inval.height());
- recordingCanvas->translate(-drawArea.x(), -drawArea.y());
- recordingCanvas->save();
- view->platformWidget()->draw(&gc, drawArea);
- m_rebuildInval.op(inval, SkRegion::kUnion_Op);
- DBG_SET_LOGD("m_rebuildInval={%d,%d,r=%d,b=%d}",
- m_rebuildInval.getBounds().fLeft, m_rebuildInval.getBounds().fTop,
- m_rebuildInval.getBounds().fRight, m_rebuildInval.getBounds().fBottom);
-
- return picture;
+ IntRect drawArea = dirty;
+ gc->translate(-origin.x(), -origin.y());
+ drawArea.move(origin.x(), origin.y());
+ view->platformWidget()->draw(gc, drawArea);
}
-#ifdef CONTEXT_RECORDING
-GraphicsOperationCollection* WebViewCore::rebuildGraphicsOperationCollection(const SkIRect& inval)
+SkCanvas* WebViewCore::createPrerenderCanvas(PrerenderedInval* prerendered)
{
- WebCore::FrameView* view = m_mainFrame->view();
- int width = view->contentsWidth();
- int height = view->contentsHeight();
-
- IntPoint origin = view->minimumScrollPosition();
- WebCore::IntRect drawArea(inval.fLeft + origin.x(), inval.fTop + origin.y(),
- inval.width(), inval.height());
-
- AutoGraphicsOperationCollection autoPicture(drawArea);
- view->platformWidget()->draw(autoPicture.context(), drawArea);
-
- m_rebuildInval.op(inval, SkRegion::kUnion_Op);
-
- SkSafeRef(autoPicture.picture());
- return autoPicture.picture();
-}
-#endif
-
-void WebViewCore::rebuildPictureSet(PictureSet* pictureSet)
-{
-#ifdef FAST_PICTURESET
- WTF::Vector<Bucket*>* buckets = pictureSet->bucketsToUpdate();
-
- for (unsigned int i = 0; i < buckets->size(); i++) {
- Bucket* bucket = (*buckets)[i];
- for (unsigned int j = 0; j < bucket->size(); j++) {
- BucketPicture& bucketPicture = (*bucket)[j];
- const SkIRect& inval = bucketPicture.mRealArea;
- SkPicture* picture = rebuildPicture(inval);
- SkSafeUnref(bucketPicture.mPicture);
- bucketPicture.mPicture = picture;
- }
- }
- buckets->clear();
-#else
- size_t size = pictureSet->size();
- for (size_t index = 0; index < size; index++) {
- if (pictureSet->upToDate(index))
- continue;
- const SkIRect& inval = pictureSet->bounds(index);
- DBG_SET_LOGD("pictSet=%p [%d] {%d,%d,w=%d,h=%d}", pictureSet, index,
- inval.fLeft, inval.fTop, inval.width(), inval.height());
- pictureSet->setPicture(index, rebuildPicture(inval));
-#ifdef CONTEXT_RECORDING
- pictureSet->setGraphicsOperationCollection(index,
- rebuildGraphicsOperationCollection(inval));
-#endif
+ IntRect screen(m_scrollOffsetX, m_scrollOffsetY, m_screenWidth, m_screenHeight);
+ if (prerendered->area.isEmpty() || !prerendered->area.intersects(screen))
+ return 0;
+ FloatRect scaledArea = prerendered->area;
+ scaledArea.scale(m_scale);
+ IntRect enclosingScaledArea = enclosingIntRect(scaledArea);
+ if (enclosingScaledArea.isEmpty())
+ return 0;
+ prerendered->screenArea = enclosingScaledArea;
+ FloatRect enclosingDocArea(enclosingScaledArea);
+ enclosingDocArea.scale(1 / m_scale);
+ prerendered->area = enclosingIntRect(enclosingDocArea);
+ if (prerendered->area.isEmpty())
+ return 0;
+ // TODO: We need a better heuristic for this. We should change this to:
+ // 1) Limit by area, not width/height (as we care more about the RAM than size)
+ // 2) Clip by the screen, but "round out" to make sure we cover partially
+ // visible tiles
+ int maxWidth = ceilf(m_screenWidth * m_scale);
+ int maxHeight = ceilf(m_screenHeight * m_scale);
+ if (enclosingScaledArea.width() <= maxWidth
+ && enclosingScaledArea.height() <= maxHeight) {
+ prerendered->bitmap.setConfig(SkBitmap::kARGB_8888_Config,
+ enclosingScaledArea.width(),
+ enclosingScaledArea.height());
+ prerendered->bitmap.allocPixels();
+ SkCanvas* bitmapCanvas = new SkCanvas(prerendered->bitmap);
+ bitmapCanvas->scale(m_scale, m_scale);
+ bitmapCanvas->translate(-enclosingDocArea.x(), -enclosingDocArea.y());
+ return bitmapCanvas;
}
-
- pictureSet->validate(__FUNCTION__);
-#endif
+ return 0;
}
void WebViewCore::notifyAnimationStarted()
@@ -896,7 +802,8 @@ BaseLayerAndroid* WebViewCore::createBaseLayer()
bodyHasFixedBackgroundImage = style->hasFixedBackgroundImage();
}
- PictureSetLayerContent* content = new PictureSetLayerContent(m_content);
+ PicturePileLayerContent* content = new PicturePileLayerContent(m_content);
+ m_content.clearPrerenders();
BaseLayerAndroid* realBase = 0;
LayerAndroid* base = 0;
@@ -952,46 +859,22 @@ BaseLayerAndroid* WebViewCore::createBaseLayer()
BaseLayerAndroid* WebViewCore::recordContent(SkIPoint* point)
{
- // If there is a pending style recalculation, just return.
- if (m_mainFrame->document()->isPendingStyleRecalc()) {
- DBG_SET_LOG("recordContent: pending style recalc, ignoring.");
- return 0;
- }
- float progress = (float) m_mainFrame->page()->progress()->estimatedProgress();
- m_progressDone = progress <= 0.0f || progress >= 1.0f;
- recordPictureSet(&m_content);
- if (!m_progressDone && m_content.isEmpty()) {
- DBG_SET_LOGD("empty (progress=%g)", progress);
- return 0;
- }
+ recordPicturePile();
BaseLayerAndroid* baseLayer = createBaseLayer();
- baseLayer->markAsDirty(m_addInval);
- m_addInval.setEmpty();
+ baseLayer->markAsDirty(m_content.dirtyRegion());
+ m_content.dirtyRegion().setEmpty();
#if USE(ACCELERATED_COMPOSITING)
#else
baseLayer->markAsDirty(m_rebuildInval);
#endif
- m_rebuildInval.setEmpty();
- point->fX = m_content.width();
- point->fY = m_content.height();
+ point->fX = m_content.size().width();
+ point->fY = m_content.size().height();
return baseLayer;
}
-void WebViewCore::splitContent(PictureSet* content)
-{
-#ifdef FAST_PICTURESET
-#else
- bool layoutSucceeded = layoutIfNeededRecursive(m_mainFrame);
- ALOG_ASSERT(layoutSucceeded, "Can never be called recursively");
- content->split(&m_content);
- rebuildPictureSet(&m_content);
- content->set(m_content);
-#endif // FAST_PICTURESET
-}
-
void WebViewCore::scrollTo(int x, int y, bool animate)
{
ALOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
@@ -1041,14 +924,10 @@ void WebViewCore::contentDraw()
void WebViewCore::contentInvalidate(const WebCore::IntRect &r)
{
- DBG_SET_LOGD("rect={%d,%d,w=%d,h=%d}", r.x(), r.y(), r.width(), r.height());
- SkIRect rect(r);
- if (!rect.intersect(0, 0, INT_MAX, INT_MAX))
- return;
- m_addInval.op(rect, SkRegion::kUnion_Op);
- DBG_SET_LOGD("m_addInval={%d,%d,r=%d,b=%d}",
- m_addInval.getBounds().fLeft, m_addInval.getBounds().fTop,
- m_addInval.getBounds().fRight, m_addInval.getBounds().fBottom);
+ IntPoint origin = m_mainFrame->view()->minimumScrollPosition();
+ IntRect dirty = r;
+ dirty.move(-origin.x(), -origin.y());
+ m_content.invalidate(dirty);
if (!m_skipContentDraw)
contentDraw();
}
@@ -4560,13 +4439,6 @@ static jint RecordContent(JNIEnv* env, jobject obj, jint nativeClass, jobject pt
return reinterpret_cast<jint>(result);
}
-static void SplitContent(JNIEnv* env, jobject obj, jint nativeClass,
- jint content)
-{
- WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
- viewImpl->splitContent(reinterpret_cast<PictureSet*>(content));
-}
-
static void SendListBoxChoice(JNIEnv* env, jobject obj, jint nativeClass,
jint choice)
{
@@ -5074,8 +4946,6 @@ static JNINativeMethod gJavaWebViewCoreMethods[] = {
(void*) RecordContent },
{ "setViewportSettingsFromNative", "(I)V",
(void*) SetViewportSettingsFromNative },
- { "nativeSplitContent", "(II)V",
- (void*) SplitContent },
{ "nativeSetBackgroundColor", "(II)V",
(void*) SetBackgroundColor },
{ "nativeRegisterURLSchemeAsLocal", "(ILjava/lang/String;)V",
diff --git a/Source/WebKit/android/jni/WebViewCore.h b/Source/WebKit/android/jni/WebViewCore.h
index 3e1dbab..8dc1d07 100644
--- a/Source/WebKit/android/jni/WebViewCore.h
+++ b/Source/WebKit/android/jni/WebViewCore.h
@@ -31,7 +31,7 @@
#include "FileChooser.h"
#include "FocusDirection.h"
#include "HitTestResult.h"
-#include "PictureSet.h"
+#include "PicturePile.h"
#include "PlatformGraphicsContext.h"
#include "Position.h"
#include "ScrollTypes.h"
@@ -121,7 +121,7 @@ namespace android {
};
// one instance of WebViewCore per page for calling into Java's WebViewCore
- class WebViewCore : public WebCoreRefObject {
+ class WebViewCore : public WebCoreRefObject, public WebCore::PicturePainter {
public:
/**
* Initialize the native WebViewCore with a JNI environment, a Java
@@ -526,9 +526,6 @@ namespace android {
WebCore::Frame* mainFrame() const { return m_mainFrame; }
WebCore::Frame* focusedFrame() const;
- // utility to split slow parts of the picture set
- void splitContent(PictureSet*);
-
void notifyWebAppCanBeInstalled();
void deleteText(int startX, int startY, int endX, int endY);
@@ -625,13 +622,13 @@ namespace android {
WebCore::Node* currentFocus();
// Create a set of pictures to represent the drawn DOM, driven by
// the invalidated region and the time required to draw (used to draw)
- void recordPictureSet(PictureSet* master);
+ void recordPicturePile();
- SkPicture* rebuildPicture(const SkIRect& inval);
+ virtual void paintContents(WebCore::GraphicsContext* gc, WebCore::IntRect& dirty);
+ virtual SkCanvas* createPrerenderCanvas(WebCore::PrerenderedInval* prerendered);
#ifdef CONTEXT_RECORDING
WebCore::GraphicsOperationCollection* rebuildGraphicsOperationCollection(const SkIRect& inval);
#endif
- void rebuildPictureSet(PictureSet* );
void sendNotifyProgressFinished();
/*
* Handle a mouse click, either from a touch or trackball press.
@@ -750,9 +747,7 @@ namespace android {
struct TextFieldInitDataGlue* m_textFieldInitDataGlue;
WebCore::Frame* m_mainFrame;
WebCoreReply* m_popupReply;
- PictureSet m_content; // the set of pictures to draw
- SkRegion m_addInval; // the accumulated inval region (not yet drawn)
- SkRegion m_rebuildInval; // the accumulated region for rebuilt pictures
+ WebCore::PicturePile m_content; // the set of pictures to draw
// Used in passToJS to avoid updating the UI text field until after the
// key event has been processed.
bool m_blockTextfieldUpdates;
@@ -766,7 +761,6 @@ namespace android {
int m_scrollOffsetX; // webview.java's current scroll in X
int m_scrollOffsetY; // webview.java's current scroll in Y
WebCore::IntPoint m_mousePos;
- bool m_progressDone;
int m_screenWidth; // width of the visible rect in document coordinates
int m_screenHeight;// height of the visible rect in document coordinates
int m_textWrapWidth;
diff --git a/Source/WebKit/android/nav/WebView.cpp b/Source/WebKit/android/nav/WebView.cpp
index 51ffdfe..9d4d7a4 100644
--- a/Source/WebKit/android/nav/WebView.cpp
+++ b/Source/WebKit/android/nav/WebView.cpp
@@ -293,12 +293,11 @@ int drawGL(WebCore::IntRect& viewRect, WebCore::IntRect* invalRect,
return 0;
}
-PictureSet* draw(SkCanvas* canvas, SkColor bgColor, DrawExtras extras, bool split)
+void draw(SkCanvas* canvas, SkColor bgColor, DrawExtras extras)
{
- PictureSet* ret = 0;
if (!m_baseLayer) {
canvas->drawColor(bgColor);
- return ret;
+ return;
}
// draw the content of the base layer first
@@ -327,8 +326,6 @@ PictureSet* draw(SkCanvas* canvas, SkColor bgColor, DrawExtras extras, bool spli
m_baseLayer->setMatrix(canvas->getTotalMatrix());
canvas->resetMatrix();
m_baseLayer->draw(canvas, getDrawExtra(extras));
-
- return ret;
}
int getScaledMaxXScroll()
@@ -543,14 +540,6 @@ bool setBaseLayer(BaseLayerAndroid* newBaseLayer, bool showVisualIndicator,
return queueFull;
}
-void replaceBaseContent(PictureSet* set)
-{
- if (!m_baseLayer)
- return;
- // TODO: remove the split picture codepath
- delete set;
-}
-
void copyBaseContentToPicture(SkPicture* picture)
{
if (!m_baseLayer)
@@ -805,16 +794,14 @@ static SkRect jrectf_to_rect(JNIEnv* env, jobject obj)
return rect;
}
-static jint nativeDraw(JNIEnv *env, jobject obj, jobject canv,
+static void nativeDraw(JNIEnv *env, jobject obj, jobject canv,
jobject visible, jint color,
- jint extras, jboolean split) {
+ jint extras) {
SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, canv);
WebView* webView = GET_NATIVE_VIEW(env, obj);
SkRect visibleRect = jrectf_to_rect(env, visible);
webView->setVisibleRect(visibleRect);
- PictureSet* pictureSet = webView->draw(canvas, color,
- static_cast<WebView::DrawExtras>(extras), split);
- return reinterpret_cast<jint>(pictureSet);
+ webView->draw(canvas, color, static_cast<WebView::DrawExtras>(extras));
}
static jint nativeCreateDrawGLFunction(JNIEnv *env, jobject obj, jint nativeView,
@@ -898,12 +885,6 @@ static BaseLayerAndroid* nativeGetBaseLayer(JNIEnv *env, jobject obj)
return GET_NATIVE_VIEW(env, obj)->getBaseLayer();
}
-static void nativeReplaceBaseContent(JNIEnv *env, jobject obj, jint content)
-{
- PictureSet* set = reinterpret_cast<PictureSet*>(content);
- GET_NATIVE_VIEW(env, obj)->replaceBaseContent(set);
-}
-
static void nativeCopyBaseContentToPicture(JNIEnv *env, jobject obj, jobject pict)
{
SkPicture* picture = GraphicsJNI::getNativePicture(env, pict);
@@ -1110,7 +1091,7 @@ static void nativeDumpDisplayTree(JNIEnv* env, jobject jwebview, jstring jurl)
SkDumpCanvas canvas(&dumper);
// this will playback the picture into the canvas, which will
// spew its contents to the dumper
- view->draw(&canvas, 0, WebView::DrawExtrasNone, false);
+ view->draw(&canvas, 0, WebView::DrawExtrasNone);
// we're done with the file now
fwrite("\n", 1, 1, file);
fclose(file);
@@ -1249,7 +1230,7 @@ static JNINativeMethod gJavaWebViewMethods[] = {
(void*) nativeCreate },
{ "nativeDestroy", "()V",
(void*) nativeDestroy },
- { "nativeDraw", "(Landroid/graphics/Canvas;Landroid/graphics/RectF;IIZ)I",
+ { "nativeDraw", "(Landroid/graphics/Canvas;Landroid/graphics/RectF;II)V",
(void*) nativeDraw },
{ "nativeCreateDrawGLFunction", "(ILandroid/graphics/Rect;Landroid/graphics/Rect;Landroid/graphics/RectF;FI)I",
(void*) nativeCreateDrawGLFunction },
@@ -1271,8 +1252,6 @@ static JNINativeMethod gJavaWebViewMethods[] = {
(void*) nativeSetBaseLayer },
{ "nativeGetBaseLayer", "()I",
(void*) nativeGetBaseLayer },
- { "nativeReplaceBaseContent", "(I)V",
- (void*) nativeReplaceBaseContent },
{ "nativeCopyBaseContentToPicture", "(Landroid/graphics/Picture;)V",
(void*) nativeCopyBaseContentToPicture },
{ "nativeHasContent", "()Z",