summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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",