summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRussell Brenner <russellbrenner@google.com>2011-09-22 16:54:49 -0700
committerRussell Brenner <russellbrenner@google.com>2011-09-26 16:49:28 -0700
commitb4bf6cc925ee7af6187a0f0124cbc5ef85828c8d (patch)
tree86bbc0b27718a40378d9987808a9f48eac648378
parent573d2754446fc611151ef424b4b87a525bcd006d (diff)
downloadexternal_webkit-b4bf6cc925ee7af6187a0f0124cbc5ef85828c8d.zip
external_webkit-b4bf6cc925ee7af6187a0f0124cbc5ef85828c8d.tar.gz
external_webkit-b4bf6cc925ee7af6187a0f0124cbc5ef85828c8d.tar.bz2
Limit the number of buckets in a PictureSet
Added MAX_BUCKET_COUNT_X and _Y so that absurdly large pages, such as those in LayoutTests, don't run out of memory due to millions of buckets. Renamed checkDimensions() to setDimensions() and made inval an optional parameter so that it can be used more generally within PictureSet to adjust settings. Bug: 5300146 Change-Id: Ic6c2dc97085ef38d5782aa005b71a6797d165e24
-rw-r--r--Source/WebKit/android/jni/PictureSet.cpp72
-rw-r--r--Source/WebKit/android/jni/PictureSet.h5
-rw-r--r--Source/WebKit/android/jni/WebViewCore.cpp2
3 files changed, 45 insertions, 34 deletions
diff --git a/Source/WebKit/android/jni/PictureSet.cpp b/Source/WebKit/android/jni/PictureSet.cpp
index f61e0f1..233a4c9 100644
--- a/Source/WebKit/android/jni/PictureSet.cpp
+++ b/Source/WebKit/android/jni/PictureSet.cpp
@@ -44,6 +44,8 @@
#define MAX_ADDITIONAL_PICTURES 32
#define BUCKET_SIZE 256
+#define MAX_BUCKET_COUNT_X 16
+#define MAX_BUCKET_COUNT_Y 64
#include <wtf/CurrentTime.h>
@@ -65,6 +67,8 @@
#endif // DEBUG
+#define MAX(a,b) ((a)<(b)?(b):(a))
+
#if PICTURE_SET_DEBUG
class MeasureStream : public SkWStream {
public:
@@ -81,7 +85,7 @@ namespace android {
PictureSet::PictureSet()
{
- mWidth = mHeight = 0;
+ setDimensions(0, 0);
mBaseArea = mAdditionalArea = 0;
}
@@ -89,11 +93,10 @@ PictureSet::PictureSet(SkPicture* picture)
{
mBaseArea = mAdditionalArea = 0;
if (!picture) {
- mWidth = mHeight = 0;
+ setDimensions(0, 0);
return;
}
- mWidth = picture->width();
- mHeight = picture->height();
+ setDimensions(picture->width(), picture->height());
mBaseArea = mWidth * mHeight;
#ifdef FAST_PICTURESET
SkIRect area;
@@ -183,6 +186,7 @@ Bucket* PictureSet::getBucket(int x, int y)
BucketPosition position(x+1, y+1);
if (!mBuckets.contains(position)) {
+ XLOGC("PictureSet::getBucket(%d, %d) adding new bucket", x, y);
Bucket* bucket = new Bucket();
mBuckets.add(position, bucket);
}
@@ -229,7 +233,7 @@ void PictureSet::addToBucket(Bucket* bucket, int dx, int dy, SkIRect& rect)
// 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 * BUCKET_SIZE * BUCKET_SIZE)
+ if (rect.width() * rect.height() > MAX_ADDITIONAL_AREA * mBucketSizeX * mBucketSizeY)
resetBase = true;
// let's gather all the BucketPicture intersecting with the new invalidated
@@ -251,7 +255,7 @@ void PictureSet::addToBucket(Bucket* bucket, int dx, int dy, SkIRect& rect)
// 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() < BUCKET_SIZE || current->mArea.height() < BUCKET_SIZE)) {
+ && (current->mArea.width() < mBucketSizeX || current->mArea.height() < mBucketSizeY)) {
remove = true;
}
@@ -301,18 +305,16 @@ void PictureSet::addToBucket(Bucket* bucket, int dx, int dy, SkIRect& rect)
void PictureSet::gatherBucketsForArea(WTF::Vector<Bucket*>& list, const SkIRect& rect)
{
- int maxSize = BUCKET_SIZE;
-
XLOG("\n--- gatherBucketsForArea for rect %d, %d, %d, %d (%d x %d)",
rect.fLeft, rect.fTop, rect.fRight, rect.fBottom,
rect.width(), rect.height());
int x = rect.fLeft;
int y = rect.fTop;
- int firstTileX = rect.fLeft / maxSize;
- int firstTileY = rect.fTop / maxSize;
- int lastTileX = rect.fRight / maxSize;
- int lastTileY = rect.fBottom / maxSize;
+ 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++) {
@@ -333,15 +335,13 @@ void PictureSet::splitAdd(const SkIRect& rect)
rect.fLeft, rect.fTop, rect.fRight, rect.fBottom,
rect.width(), rect.height());
- int maxSize = BUCKET_SIZE;
-
// TODO: reuse gatherBucketsForArea() (change Bucket to be a class)
int x = rect.fLeft;
int y = rect.fTop;
- int firstTileX = rect.fLeft / maxSize;
- int firstTileY = rect.fTop / maxSize;
- int lastTileX = rect.fRight / maxSize;
- int lastTileY = rect.fBottom / maxSize;
+ int firstTileX = rect.fLeft / mBucketSizeX;
+ int firstTileY = rect.fTop / mBucketSizeY;
+ int lastTileX = rect.fRight / mBucketSizeX;
+ int lastTileY = rect.fBottom / mBucketSizeY;
XLOG("--- firstTile(%d, %d) lastTile(%d, %d)",
firstTileX, firstTileY,
@@ -354,12 +354,12 @@ void PictureSet::splitAdd(const SkIRect& rect)
continue;
SkIRect newRect;
- int deltaX = i * maxSize;
- int deltaY = j * maxSize;
+ 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 % maxSize : maxSize;
- int bottom = (j == lastTileY) ? rect.fBottom % maxSize : maxSize;
+ 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);
@@ -558,22 +558,30 @@ void PictureSet::add(const SkRegion& area, SkPicture* picture,
}
#endif // FAST_PICTURESET
-void PictureSet::checkDimensions(int width, int height, SkRegion* inval)
+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);
- if (mWidth == width && height > mHeight) { // only grew vertically
- SkIRect rect;
- rect.set(0, mHeight, width, height);
- inval->op(rect, SkRegion::kUnion_Op);
- } else {
- clear(); // if both width/height changed, clear the old cache
- inval->setRect(0, 0, width, height);
+ 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 {
+ inval->setRect(0, 0, width, height);
+ }
}
+ clear(); // clear the old cache
mWidth = width;
mHeight = height;
+#ifdef FAST_PICTURESET
+ mBucketSizeX = MAX(BUCKET_SIZE, (width + MAX_BUCKET_COUNT_X - 1) / MAX_BUCKET_COUNT_X);
+ mBucketSizeY = MAX(BUCKET_SIZE, (height + MAX_BUCKET_COUNT_Y - 1) / MAX_BUCKET_COUNT_Y);
+ XLOGC("mBucketSizeX=%d mBucketSizeY=%d", mBucketSizeX, mBucketSizeY);
+#endif
}
void PictureSet::clear()
@@ -600,6 +608,7 @@ void PictureSet::clear()
mPictures.clear();
#endif // FAST_PICTURESET
mWidth = mHeight = 0;
+ mBucketSizeX = mBucketSizeY = 0;
}
bool PictureSet::draw(SkCanvas* canvas)
@@ -890,8 +899,7 @@ void PictureSet::set(const PictureSet& src)
{
DBG_SET_LOGD("start %p src=%p", this, &src);
clear();
- mWidth = src.mWidth;
- mHeight = src.mHeight;
+ setDimensions(src.mWidth, src.mHeight);
#ifdef FAST_PICTURESET
XLOG("\n--- set picture ---");
for (BucketMap::const_iterator iter = src.mBuckets.begin();
diff --git a/Source/WebKit/android/jni/PictureSet.h b/Source/WebKit/android/jni/PictureSet.h
index 1ca4580..57ae83a 100644
--- a/Source/WebKit/android/jni/PictureSet.h
+++ b/Source/WebKit/android/jni/PictureSet.h
@@ -87,7 +87,7 @@ namespace android {
uint32_t elapsed, bool split);
// Update mWidth/mHeight, and adds any additional inval region
- void checkDimensions(int width, int height, SkRegion* inval);
+ void setDimensions(int width, int height, SkRegion* inval = 0);
void clear();
bool draw(SkCanvas* );
static PictureSet* GetNativePictureSet(JNIEnv* env, jobject jpic);
@@ -113,9 +113,12 @@ namespace android {
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;
#else
struct Pictures {
SkRegion mArea;
diff --git a/Source/WebKit/android/jni/WebViewCore.cpp b/Source/WebKit/android/jni/WebViewCore.cpp
index 24266f6..26c73b2 100644
--- a/Source/WebKit/android/jni/WebViewCore.cpp
+++ b/Source/WebKit/android/jni/WebViewCore.cpp
@@ -686,7 +686,7 @@ void WebViewCore::recordPictureSet(PictureSet* content)
if (cacheBuilder().pictureSetDisabled())
content->clear();
- content->checkDimensions(width, height, &m_addInval);
+ content->setDimensions(width, height, &m_addInval);
// Add the current inval rects to the PictureSet, and rebuild it.
content->add(m_addInval, 0, 0, false);