diff options
author | mad@google.com <mad@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-06-10 21:41:54 +0000 |
---|---|---|
committer | mad@google.com <mad@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-06-10 21:41:54 +0000 |
commit | 87ef8484fbd915ac4e527fb566422002f4d612ab (patch) | |
tree | e6180d206b0723ab073985ec5f2016a14f459127 /chrome/browser | |
parent | 9aefecc973faa549046389937bd526f00fb26b5f (diff) | |
download | chromium_src-87ef8484fbd915ac4e527fb566422002f4d612ab.zip chromium_src-87ef8484fbd915ac4e527fb566422002f4d612ab.tar.gz chromium_src-87ef8484fbd915ac4e527fb566422002f4d612ab.tar.bz2 |
To help resolve the performance issue introduced when enabling the resize corner, we now keep all non-intersecting rects separately and send an array of invalidation bitmaps via IPC as opposed to a single unionized rect :-)
Review URL: http://codereview.chromium.org/108040
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@18090 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
-rw-r--r-- | chrome/browser/renderer_host/backing_store.h | 14 | ||||
-rw-r--r-- | chrome/browser/renderer_host/backing_store_mac.cc | 18 | ||||
-rw-r--r-- | chrome/browser/renderer_host/backing_store_manager.cc | 12 | ||||
-rw-r--r-- | chrome/browser/renderer_host/backing_store_manager.h | 1 | ||||
-rw-r--r-- | chrome/browser/renderer_host/backing_store_win.cc | 43 | ||||
-rw-r--r-- | chrome/browser/renderer_host/backing_store_x.cc | 114 | ||||
-rw-r--r-- | chrome/browser/renderer_host/render_widget_host.cc | 92 | ||||
-rw-r--r-- | chrome/browser/renderer_host/render_widget_host.h | 7 | ||||
-rw-r--r-- | chrome/browser/views/frame/browser_view.cc | 10 |
9 files changed, 221 insertions, 90 deletions
diff --git a/chrome/browser/renderer_host/backing_store.h b/chrome/browser/renderer_host/backing_store.h index 5d817d0..5bb3945 100644 --- a/chrome/browser/renderer_host/backing_store.h +++ b/chrome/browser/renderer_host/backing_store.h @@ -63,9 +63,12 @@ class BackingStore { #endif // Paints the bitmap from the renderer onto the backing store. + // bitmap_rect is the rect of the whole bitmap, and paint_rect + // is a sub-rect of bitmap that we want to draw. void PaintRect(base::ProcessHandle process, TransportDIB* bitmap, - const gfx::Rect& bitmap_rect); + const gfx::Rect& bitmap_rect, + const gfx::Rect& paint_rect); // Scrolls the given rect in the backing store, replacing the given region // identified by |bitmap_rect| by the bitmap in the file identified by the @@ -95,8 +98,11 @@ class BackingStore { #elif defined(OS_LINUX) // Paints the bitmap from the renderer onto the backing store without // using Xrender to composite the pixmaps. + // bitmap_rect is the rect of the whole bitmap, and paint_rect + // is a sub-rect of bitmap that we want to draw. void PaintRectWithoutXrender(TransportDIB* bitmap, - const gfx::Rect& bitmap_rect); + const gfx::Rect& bitmap_rect, + const gfx::Rect& paint_rect); // This is the connection to the X server where this backing store will be // displayed. @@ -119,6 +125,10 @@ class BackingStore { void* pixmap_gc_; #endif + // Sanity checks on the size of the rects to draw so that we don't allocate + // enourmous pixmaps. + static int kMaxBitmapLengthAllowed; + DISALLOW_COPY_AND_ASSIGN(BackingStore); }; diff --git a/chrome/browser/renderer_host/backing_store_mac.cc b/chrome/browser/renderer_host/backing_store_mac.cc index 569e3f6..8983208 100644 --- a/chrome/browser/renderer_host/backing_store_mac.cc +++ b/chrome/browser/renderer_host/backing_store_mac.cc @@ -21,14 +21,24 @@ BackingStore::~BackingStore() { void BackingStore::PaintRect(base::ProcessHandle process, TransportDIB* bitmap, - const gfx::Rect& bitmap_rect) { + const gfx::Rect& bitmap_rect, + const gfx::Rect& paint_rect) { + DCHECK(bitmap_rect.Contains(paint_rect) && + paint_rect.x() < kMaxBitmapLengthAllowed && + paint_rect.y() < kMaxBitmapLengthAllowed); SkBitmap skbitmap; skbitmap.setConfig(SkBitmap::kARGB_8888_Config, bitmap_rect.width(), bitmap_rect.height(), 4 * bitmap_rect.width()); skbitmap.setPixels(bitmap->memory()); - - canvas_.drawBitmap(skbitmap, bitmap_rect.x(), bitmap_rect.y()); + SkIRect src_rect; + src_rect.set(paint_rect.x(), paint_rect.y(), + paint_rect.right(), paint_rect.bottom()); + src_rect.offset(-bitmap_rect.x(), -bitmap_rect.y()); + SkRect dst_rect; + dst_rect.iset(paint_rect.x(), paint_rect.y(), + paint_rect.right(), paint_rect.bottom()); + canvas_.drawBitmapRect(skbitmap, &src_rect, dst_rect); } void BackingStore::ScrollRect(base::ProcessHandle process, @@ -118,6 +128,6 @@ void BackingStore::ScrollRect(base::ProcessHandle process, } // Now paint the new bitmap data. - PaintRect(process, bitmap, bitmap_rect); + PaintRect(process, bitmap, bitmap_rect, bitmap_rect); return; } diff --git a/chrome/browser/renderer_host/backing_store_manager.cc b/chrome/browser/renderer_host/backing_store_manager.cc index 3ff2e76..eb3600e 100644 --- a/chrome/browser/renderer_host/backing_store_manager.cc +++ b/chrome/browser/renderer_host/backing_store_manager.cc @@ -49,6 +49,11 @@ BackingStore* CreateBackingStore(RenderWidgetHost* host, } // namespace +// Assume that somewhere along the line, someone will do width * height * 4 +// with signed numbers. If the maximum value is 2**31, then 2**31 / 4 = +// 2**29 and floor(sqrt(2**29)) = 23170. +int BackingStore::kMaxBitmapLengthAllowed = 23170; + // BackingStoreManager --------------------------------------------------------- // static @@ -74,13 +79,14 @@ BackingStore* BackingStoreManager::PrepareBackingStore( base::ProcessHandle process_handle, TransportDIB* bitmap, const gfx::Rect& bitmap_rect, + const gfx::Rect& paint_rect, bool* needs_full_paint) { BackingStore* backing_store = GetBackingStore(host, backing_store_size); if (!backing_store) { // We need to get Webkit to generate a new paint here, as we // don't have a previous snapshot. - if (bitmap_rect.size() != backing_store_size || - bitmap_rect.x() != 0 || bitmap_rect.y() != 0) { + if (paint_rect.size() != backing_store_size || + paint_rect.x() != 0 || paint_rect.y() != 0) { DCHECK(needs_full_paint != NULL); *needs_full_paint = true; } @@ -88,7 +94,7 @@ BackingStore* BackingStoreManager::PrepareBackingStore( } DCHECK(backing_store != NULL); - backing_store->PaintRect(process_handle, bitmap, bitmap_rect); + backing_store->PaintRect(process_handle, bitmap, bitmap_rect, paint_rect); return backing_store; } diff --git a/chrome/browser/renderer_host/backing_store_manager.h b/chrome/browser/renderer_host/backing_store_manager.h index 5b929f6..d273c17 100644 --- a/chrome/browser/renderer_host/backing_store_manager.h +++ b/chrome/browser/renderer_host/backing_store_manager.h @@ -49,6 +49,7 @@ class BackingStoreManager { base::ProcessHandle process_handle, TransportDIB* bitmap, const gfx::Rect& bitmap_rect, + const gfx::Rect& paint_rect, bool* needs_full_paint); // Returns a matching backing store for the host. diff --git a/chrome/browser/renderer_host/backing_store_win.cc b/chrome/browser/renderer_host/backing_store_win.cc index 1241e42..edb861d 100644 --- a/chrome/browser/renderer_host/backing_store_win.cc +++ b/chrome/browser/renderer_host/backing_store_win.cc @@ -54,7 +54,11 @@ BackingStore::~BackingStore() { void BackingStore::PaintRect(base::ProcessHandle process, TransportDIB* bitmap, - const gfx::Rect& bitmap_rect) { + const gfx::Rect& bitmap_rect, + const gfx::Rect& paint_rect) { + DCHECK(bitmap_rect.Contains(paint_rect) && + paint_rect.x() < kMaxBitmapLengthAllowed && + paint_rect.y() < kMaxBitmapLengthAllowed); if (!backing_store_dib_) { backing_store_dib_ = CreateDIB(hdc_, size_.width(), size_.height(), color_depth_); @@ -67,16 +71,33 @@ void BackingStore::PaintRect(base::ProcessHandle process, BITMAPINFOHEADER hdr; gfx::CreateBitmapHeader(bitmap_rect.width(), bitmap_rect.height(), &hdr); - // Account for a bitmap_rect that exceeds the bounds of our view + // Account for a paint_rect that exceeds the bounds of our view. gfx::Rect view_rect(0, 0, size_.width(), size_.height()); - gfx::Rect paint_rect = view_rect.Intersect(bitmap_rect); - - int rv = StretchDIBits(hdc_, - paint_rect.x(), paint_rect.y(), - paint_rect.width(), paint_rect.height(), - 0, 0, // source x,y. - paint_rect.width(), paint_rect.height(), - bitmap->memory(), + gfx::Rect paint_view_rect = view_rect.Intersect(paint_rect); + + // CreateBitmapHeader specifies a negative height, + // so the y destination is from the bottom. + int source_x = paint_view_rect.x() - bitmap_rect.x(); + int source_y = bitmap_rect.bottom() - paint_view_rect.bottom(); + int source_height = paint_view_rect.height(); + int destination_y = paint_view_rect.y(); + int destination_height = paint_view_rect.height(); + if (source_y == 0 && source_x == 0 && + paint_view_rect.height() != bitmap_rect.height()) { + // StretchDIBits has a bug where it won't take the proper source + // rect if it starts at (0, 0) in the source but not in the destination, + // so we must use a mirror blit trick as proposed here: + // http://wiki.allegro.cc/index.php?title=StretchDIBits + destination_y += destination_height - 1; + destination_height = -destination_height; + source_y = bitmap_rect.height() - paint_view_rect.y() + 1; + source_height = -source_height; + } + + int rv = StretchDIBits(hdc_, paint_view_rect.x(), destination_y, + paint_view_rect.width(), destination_height, + source_x, source_y, paint_view_rect.width(), + source_height, bitmap->memory(), reinterpret_cast<BITMAPINFO*>(&hdr), DIB_RGB_COLORS, SRCCOPY); DCHECK(rv != GDI_ERROR); @@ -97,5 +118,5 @@ void BackingStore::ScrollRect(base::ProcessHandle process, // We expect that damaged_rect should equal bitmap_rect. DCHECK(gfx::Rect(damaged_rect) == bitmap_rect); - PaintRect(process, bitmap, bitmap_rect); + PaintRect(process, bitmap, bitmap_rect, bitmap_rect); } diff --git a/chrome/browser/renderer_host/backing_store_x.cc b/chrome/browser/renderer_host/backing_store_x.cc index 6cb7c91..ff7a489 100644 --- a/chrome/browser/renderer_host/backing_store_x.cc +++ b/chrome/browser/renderer_host/backing_store_x.cc @@ -77,17 +77,20 @@ BackingStore::~BackingStore() { } void BackingStore::PaintRectWithoutXrender(TransportDIB* bitmap, - const gfx::Rect &bitmap_rect) { - const int width = bitmap_rect.width(); - const int height = bitmap_rect.height(); - Pixmap pixmap = XCreatePixmap(display_, root_window_, width, height, - visual_depth_); - + const gfx::Rect& bitmap_rect, + const gfx::Rect& paint_rect) { + const int paint_width = paint_rect.width(); + const int paint_height = paint_rect.height(); + Pixmap pixmap = XCreatePixmap(display_, root_window_, paint_width, + paint_height, visual_depth_); + + const int bitmap_width = bitmap_rect.width(); + const int bitmap_height = bitmap_rect.height(); XImage image; memset(&image, 0, sizeof(image)); - image.width = width; - image.height = height; + image.width = bitmap_width; + image.height = bitmap_height; image.format = ZPixmap; image.byte_order = LSBFirst; image.bitmap_unit = 8; @@ -96,16 +99,18 @@ void BackingStore::PaintRectWithoutXrender(TransportDIB* bitmap, image.green_mask = 0xff00; image.blue_mask = 0xff0000; + const int x_offset = paint_rect.x() - bitmap_rect.x(); + const int y_offset = paint_rect.y() - bitmap_rect.y(); if (pixmap_bpp_ == 32) { // If the X server depth is already 32-bits, then our job is easy. image.depth = visual_depth_; image.bits_per_pixel = 32; - image.bytes_per_line = width * 4; + image.bytes_per_line = bitmap_width * 4; image.data = static_cast<char*>(bitmap->memory()); XPutImage(display_, pixmap, static_cast<GC>(pixmap_gc_), &image, - 0, 0 /* source x, y */, 0, 0 /* dest x, y */, - width, height); + x_offset, y_offset /* source x, y */, 0, 0 /* dest x, y */, + paint_width, paint_height); } else if (pixmap_bpp_ == 24) { // In this case we just need to strip the alpha channel out of each // pixel. This is the case which covers VNC servers since they don't @@ -114,52 +119,68 @@ void BackingStore::PaintRectWithoutXrender(TransportDIB* bitmap, // It's possible to use some fancy SSE tricks here, but since this is the // slow path anyway, we do it slowly. - uint8_t* bitmap24 = static_cast<uint8_t*>(malloc(3 * width * height)); + uint8_t* bitmap24 = static_cast<uint8_t*>(malloc(3 * paint_width * + paint_height)); if (!bitmap24) return; const uint32_t* bitmap_in = static_cast<const uint32_t*>(bitmap->memory()); - for (int y = 0; y < height; ++y) { - for (int x = 0; x < width; ++x) { + const int x_limit = paint_rect.right() - bitmap_rect.x(); + const int y_limit = paint_rect.bottom() - bitmap_rect.y(); + const int row_length = bitmap_width; + bitmap_in += row_length * y_offset; + for (int y = y_offset; y < y_limit; ++y) { + bitmap_in += x_offset; + for (int x = x_offset; x < x_limit; ++x) { const uint32_t pixel = *(bitmap_in++); bitmap24[0] = (pixel >> 16) & 0xff; bitmap24[1] = (pixel >> 8) & 0xff; bitmap24[2] = pixel & 0xff; bitmap24 += 3; } + bitmap_in += row_length - x_limit; } + image.width = paint_width; + image.height = paint_height; image.depth = visual_depth_; image.bits_per_pixel = 24; - image.bytes_per_line = width * 3; + image.bytes_per_line = paint_width * 3; image.data = reinterpret_cast<char*>(bitmap24); XPutImage(display_, pixmap, static_cast<GC>(pixmap_gc_), &image, 0, 0 /* source x, y */, 0, 0 /* dest x, y */, - width, height); + paint_width, paint_height); free(bitmap24); } else if (pixmap_bpp_ == 16) { // Some folks have VNC setups which still use 16-bit visuals and VNC // doesn't include Xrender. - uint16_t* bitmap16 = static_cast<uint16_t*>(malloc(2 * width * height)); + uint16_t* bitmap16 = static_cast<uint16_t*>(malloc(2 * paint_width * + paint_height)); if (!bitmap16) return; uint16_t* const orig_bitmap16 = bitmap16; const uint32_t* bitmap_in = static_cast<const uint32_t*>(bitmap->memory()); - for (int y = 0; y < height; ++y) { - for (int x = 0; x < width; ++x) { + const int x_limit = paint_rect.right() - bitmap_rect.x(); + const int y_limit = paint_rect.bottom() - bitmap_rect.y(); + const int row_length = bitmap_width; + bitmap_in += row_length * y_offset; + for (int y = y_offset; y < y_limit; ++y) { + bitmap_in += x_offset; + for (int x = x_offset; x < x_limit; ++x) { const uint32_t pixel = *(bitmap_in++); uint16_t out_pixel = ((pixel >> 8) & 0xf800) | ((pixel >> 5) & 0x07e0) | ((pixel >> 3) & 0x001f); *(bitmap16++) = out_pixel; } + bitmap_in += row_length - x_limit; } image.depth = visual_depth_; image.bits_per_pixel = 16; - image.bytes_per_line = width * 2; + image.bytes_per_line = paint_width * 2; image.data = reinterpret_cast<char*>(orig_bitmap16); image.red_mask = 0xf800; @@ -168,7 +189,7 @@ void BackingStore::PaintRectWithoutXrender(TransportDIB* bitmap, XPutImage(display_, pixmap, static_cast<GC>(pixmap_gc_), &image, 0, 0 /* source x, y */, 0, 0 /* dest x, y */, - width, height); + paint_width, paint_height); free(orig_bitmap16); } else { CHECK(false) << "Sorry, we don't support your visual depth without " @@ -178,31 +199,31 @@ void BackingStore::PaintRectWithoutXrender(TransportDIB* bitmap, XCopyArea(display_, pixmap /* source */, pixmap_ /* target */, static_cast<GC>(pixmap_gc_), - 0, 0 /* source x, y */, bitmap_rect.width(), bitmap_rect.height(), - bitmap_rect.x(), bitmap_rect.y() /* dest x, y */); + 0, 0 /* source x, y */, paint_width, paint_height, + paint_rect.x(), paint_rect.y() /* dest x, y */); XFreePixmap(display_, pixmap); } void BackingStore::PaintRect(base::ProcessHandle process, TransportDIB* bitmap, - const gfx::Rect& bitmap_rect) { + const gfx::Rect& bitmap_rect, + const gfx::Rect& paint_rect) { + DCHECK(bitmap_rect.Contains(paint_rect)); if (!display_) return; if (bitmap_rect.IsEmpty()) return; - const int width = bitmap_rect.width(); - const int height = bitmap_rect.height(); - // Assume that somewhere along the line, someone will do width * height * 4 - // with signed numbers. If the maximum value is 2**31, then 2**31 / 4 = - // 2**29 and floor(sqrt(2**29)) = 23170. - if (width > 23170 || height > 23170) + const int paint_width = paint_rect.width(); + const int paint_height = paint_rect.height(); + if (paint_width > kMaxBitmapLengthAllowed || + paint_width > kMaxBitmapLengthAllowed) return; if (!use_render_) - return PaintRectWithoutXrender(bitmap, bitmap_rect); + return PaintRectWithoutXrender(bitmap, bitmap_rect, paint_rect); Picture picture; Pixmap pixmap; @@ -221,8 +242,11 @@ void BackingStore::PaintRect(base::ProcessHandle process, // difference between the |data| pointer and the address of the mapping in // |shminfo|. Since both are NULL, the offset will be calculated to be 0, // which is correct for us. - pixmap = XShmCreatePixmap(display_, root_window_, NULL, &shminfo, width, - height, 32); + pixmap = XShmCreatePixmap(display_, root_window_, NULL, &shminfo, + bitmap_rect.width(), bitmap_rect.height(), 32); + // Since we use the whole source bitmap, we must offset the source. + src_x = paint_rect.x() - bitmap_rect.x(); + src_y = paint_rect.y() - bitmap_rect.y(); } else { // No shared memory support, we have to copy the bitmap contents to the X // server. Xlib wraps the underlying PutImage call behind several layers of @@ -231,34 +255,36 @@ void BackingStore::PaintRect(base::ProcessHandle process, XImage image; memset(&image, 0, sizeof(image)); - image.width = width; - image.height = height; + image.width = paint_width; + image.height = paint_height; image.depth = 32; image.bits_per_pixel = 32; image.format = ZPixmap; image.byte_order = LSBFirst; image.bitmap_unit = 8; image.bitmap_bit_order = LSBFirst; - image.bytes_per_line = width * 4; + image.bytes_per_line = paint_width * 4; image.red_mask = 0xff; image.green_mask = 0xff00; image.blue_mask = 0xff0000; + // TODO(agl): check if we can make this more efficient. image.data = static_cast<char*>(bitmap->memory()); - pixmap = XCreatePixmap(display_, root_window_, width, height, 32); + pixmap = XCreatePixmap(display_, root_window_, paint_width, paint_height, + 32); GC gc = XCreateGC(display_, pixmap, 0, NULL); - XPutImage(display_, pixmap, gc, &image, - 0, 0 /* source x, y */, 0, 0 /* dest x, y */, - width, height); + XPutImage(display_, pixmap, gc, &image, paint_rect.x() - bitmap_rect.x(), + paint_rect.y() - bitmap_rect.y() /* source x, y */, + 0, 0 /* dest x, y */, paint_width, paint_height); XFreeGC(display_, gc); } picture = x11_util::CreatePictureFromSkiaPixmap(display_, pixmap); XRenderComposite(display_, PictOpSrc, picture /* source */, 0 /* mask */, - picture_ /* dest */, 0, 0 /* source x, y */, + picture_ /* dest */, src_x, src_y /* source x, y */, 0, 0 /* mask x, y */, - bitmap_rect.x(), bitmap_rect.y() /* target x, y */, - width, height); + paint_rect.x(), paint_rect.y() /* target x, y */, + paint_width, paint_height); // In the case of shared memory, we wait for the composite to complete so that // we are sure that the X server has finished reading. @@ -305,7 +331,7 @@ void BackingStore::ScrollRect(base::ProcessHandle process, } } - PaintRect(process, bitmap, bitmap_rect); + PaintRect(process, bitmap, bitmap_rect, bitmap_rect); } void BackingStore::ShowRect(const gfx::Rect& rect, XID target) { diff --git a/chrome/browser/renderer_host/render_widget_host.cc b/chrome/browser/renderer_host/render_widget_host.cc index fb6303b..95e7cf3 100644 --- a/chrome/browser/renderer_host/render_widget_host.cc +++ b/chrome/browser/renderer_host/render_widget_host.cc @@ -14,6 +14,7 @@ #include "chrome/browser/renderer_host/render_widget_host_view.h" #include "chrome/common/notification_service.h" #include "chrome/common/render_messages.h" +#include "skia/ext/platform_canvas.h" #include "views/view.h" #include "webkit/glue/webcursor.h" #include "webkit/glue/webtextdirection.h" @@ -41,6 +42,32 @@ static const int kPaintMsgTimeoutMS = 40; // How long to wait before we consider a renderer hung. static const int kHungRendererDelayMs = 20000; +// Helper function to confirm if a set of rects completely cover a given area. +// The caller already know that all the rects are contained within the area, +// and they shold not overlap either, so all we need to do is compare the areas. +static bool CoversArea(const std::vector<gfx::Rect>& rects, + const gfx::Size& size) { +#ifndef NDEBUG + // Make sure there are no overlapping rects. That would make the + // test below irrelevant. We only do it in the debug build since + // this case "should" be covered in the renderer. + gfx::Rect view_rect(size.width(), size.height()); + size_t last_index = rects.size() - 1; + for (size_t i = 0; i < last_index; ++i) { + DCHECK(view_rect.Contains(rects[i])); + for (size_t j = i + 1; i < rects.size(); ++i) + DCHECK(!rects[i].Intersects(rects[j])); + } + DCHECK(view_rect.Contains(rects[last_index])); +#endif + int target_area = size.height() * size.width(); + int covered_area = 0; + for (size_t i = 0; i < rects.size(); ++i) { + covered_area += rects[i].height() * rects[i].width(); + } + return covered_area < target_area; +} + /////////////////////////////////////////////////////////////////////////////// // RenderWidgetHost @@ -498,18 +525,19 @@ void RenderWidgetHost::OnMsgPaintRect( DCHECK(!params.bitmap_rect.IsEmpty()); DCHECK(!params.view_size.IsEmpty()); - const size_t size = params.bitmap_rect.height() * - params.bitmap_rect.width() * 4; TransportDIB* dib = process_->GetTransportDIB(params.bitmap); if (dib) { + const size_t size = params.bitmap_rect.height() * + skia::PlatformCanvas::StrideForWidth(params.bitmap_rect.width()); if (dib->size() < size) { DLOG(WARNING) << "Transport DIB too small for given rectangle"; process()->ReceivedBadMessage(ViewHostMsg_PaintRect__ID); } else { - // Paint the backing store. This will update it with the renderer-supplied - // bits. The view will read out of the backing store later to actually - // draw to the screen. - PaintBackingStoreRect(dib, params.bitmap_rect, params.view_size); + // Paint the backing store. This will update it with the + // renderer-supplied bits. The view will read out of the backing + // store later to actually draw to the screen. + PaintBackingStoreRects(dib, params.bitmap_rect, params.paint_rects, + params.view_size); } } @@ -529,7 +557,12 @@ void RenderWidgetHost::OnMsgPaintRect( if (view_) { view_->MovePluginWindows(params.plugin_window_moves); view_being_painted_ = true; - view_->DidPaintRect(params.bitmap_rect); + if (params.paint_rects.empty()) { + view_->DidPaintRect(params.bitmap_rect); + } else { + for (size_t i = 0; i < params.paint_rects.size(); ++i) + view_->DidPaintRect(params.paint_rects[i]); + } view_being_painted_ = false; } @@ -620,7 +653,7 @@ void RenderWidgetHost::OnMsgInputEventAck(const IPC::Message& message) { } if (WebInputEvent::isKeyboardEventType(type)) { - if (key_queue_.size() == 0) { + if (key_queue_.empty()) { LOG(ERROR) << "Got a KeyEvent back from the renderer but we " << "don't seem to have sent it to the renderer!"; } else if (key_queue_.front().type != type) { @@ -688,9 +721,10 @@ void RenderWidgetHost::OnMsgShowPopup(const IPC::Message& message) { #endif } -void RenderWidgetHost::PaintBackingStoreRect(TransportDIB* bitmap, - const gfx::Rect& bitmap_rect, - const gfx::Size& view_size) { +void RenderWidgetHost::PaintBackingStoreRects( + TransportDIB* bitmap, const gfx::Rect& bitmap_rect, + const std::vector<gfx::Rect>& paint_rects, + const gfx::Size& view_size) { // The view may be destroyed already. if (!view_) return; @@ -704,12 +738,36 @@ void RenderWidgetHost::PaintBackingStoreRect(TransportDIB* bitmap, } bool needs_full_paint = false; - BackingStore* backing_store = - BackingStoreManager::PrepareBackingStore(this, view_size, - process_->process().handle(), - bitmap, bitmap_rect, - &needs_full_paint); - DCHECK(backing_store != NULL); + base::ProcessHandle process_handle = process_->process().handle(); + if (paint_rects.empty()) { + BackingStore* backing_store = + BackingStoreManager::PrepareBackingStore(this, view_size, + process_handle, bitmap, bitmap_rect, bitmap_rect, + &needs_full_paint); + DCHECK(backing_store != NULL); + } else { + bool checked_coverage = false; + // TODO(agl): Reduce the number of X server round trips on Linux. + for (size_t i = 0; i < paint_rects.size(); ++i) { + BackingStore* backing_store = + BackingStoreManager::PrepareBackingStore(this, view_size, + process_handle, bitmap, bitmap_rect, paint_rects[i], + &needs_full_paint); + DCHECK(backing_store != NULL); + if (needs_full_paint) { + // We should not need a full paint more than once for a given view size + DCHECK(!checked_coverage); + checked_coverage = true; + + // Before we ask for a full repaint, we check if we already have a + // full coverage of the view size in out list of paint_rects + if (CoversArea(paint_rects, view_size)) + break; + needs_full_paint = false; + } + } + } + if (needs_full_paint) { repaint_start_time_ = TimeTicks::Now(); repaint_ack_pending_ = true; diff --git a/chrome/browser/renderer_host/render_widget_host.h b/chrome/browser/renderer_host/render_widget_host.h index 8ac2376..886bd2c 100644 --- a/chrome/browser/renderer_host/render_widget_host.h +++ b/chrome/browser/renderer_host/render_widget_host.h @@ -328,9 +328,10 @@ class RenderWidgetHost : public IPC::Channel::Listener { void OnMsgShowPopup(const IPC::Message& message); // Paints the given bitmap to the current backing store at the given location. - void PaintBackingStoreRect(TransportDIB* dib, - const gfx::Rect& bitmap_rect, - const gfx::Size& view_size); + void PaintBackingStoreRects(TransportDIB* bitmap, + const gfx::Rect& bitmap_rect, + const std::vector<gfx::Rect>& paint_rects, + const gfx::Size& view_size); // Scrolls the given |clip_rect| in the backing by the given dx/dy amount. The // |dib| and its corresponding location |bitmap_rect| in the backing store diff --git a/chrome/browser/views/frame/browser_view.cc b/chrome/browser/views/frame/browser_view.cc index 2665610..2a6ea40 100644 --- a/chrome/browser/views/frame/browser_view.cc +++ b/chrome/browser/views/frame/browser_view.cc @@ -134,11 +134,8 @@ class ResizeCorner : public views::View { } static gfx::Size GetSize() { - // This is disabled until we find what makes us slower when we let - // WebKit know that we have a resizer rect... - // return gfx::Size(views::NativeScrollBar::GetVerticalScrollBarWidth(), - // views::NativeScrollBar::GetHorizontalScrollBarHeight()); - return gfx::Size(); + return gfx::Size(views::NativeScrollBar::GetVerticalScrollBarWidth(), + views::NativeScrollBar::GetHorizontalScrollBarHeight()); } virtual gfx::Size GetPreferredSize() { @@ -1329,7 +1326,8 @@ void BrowserView::Init() { #if defined(OS_WIN) SetProp(GetWidget()->GetNativeView(), kBrowserViewKey, this); #else - g_object_set_data(G_OBJECT(GetWidget()->GetNativeView()), kBrowserViewKey, this); + g_object_set_data(G_OBJECT(GetWidget()->GetNativeView()), kBrowserViewKey, + this); #endif // Start a hung plugin window detector for this browser object (as long as |