Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(5)

Side by Side Diff: chrome/renderer/render_widget.cc

Issue 108040: Send array of paint rects and bitmaps as opposed to a Union (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 11 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/renderer/render_widget.h" 5 #include "chrome/renderer/render_widget.h"
6 6
7 #include "base/gfx/point.h" 7 #include "base/gfx/point.h"
8 #include "base/gfx/size.h" 8 #include "base/gfx/size.h"
9 #include "base/logging.h" 9 #include "base/logging.h"
10 #include "base/message_loop.h" 10 #include "base/message_loop.h"
(...skipping 14 matching lines...) Expand all
25 #endif // defined(OS_POSIX) 25 #endif // defined(OS_POSIX)
26 26
27 #include "webkit/glue/webtextdirection.h" 27 #include "webkit/glue/webtextdirection.h"
28 #include "webkit/glue/webwidget.h" 28 #include "webkit/glue/webwidget.h"
29 29
30 using WebKit::WebInputEvent; 30 using WebKit::WebInputEvent;
31 using WebKit::WebRect; 31 using WebKit::WebRect;
32 using WebKit::WebScreenInfo; 32 using WebKit::WebScreenInfo;
33 using WebKit::WebSize; 33 using WebKit::WebSize;
34 34
35 namespace {
36
37 // A helper class to manage access to the RenderWidget::paint_rects vector.
38 class PaintRegion {
39 public:
40 explicit PaintRegion(std::vector<gfx::Rect>* rects)
41 : rects_(*rects),
42 coalesce_(false) {
43 }
44
45 gfx::Rect GetBoundingRect() const {
46 gfx::Rect bounding_rect;
47 for (size_t i = 0; i < rects_.size(); ++i)
48 bounding_rect = bounding_rect.Union(rects_[i]);
49 return bounding_rect;
50 }
51
52 void Add(gfx::Rect rect) {
53 if (rect.IsEmpty())
54 return;
55
56 if (rects_.size() >= kNumRectsThreshold) {
57 coalesce_ = true;
58 for (size_t i = rects_.size() - 1; i > 0; --i) {
59 rects_[0] = rects_[0].Union(rects_[i]);
60 rects_.pop_back();
61 }
62 }
63
64 if (coalesce_) {
65 DCHECK(rects_.size() == 1);
66 rects_[0] = rects_[0].Union(rect);
67 } else {
68 // Look for all rects that would intersect with this new
69 // rect, union them and remove them from the list so that we
70 // have only one rect for any pixel in the invalidation.
71 std::vector<gfx::Rect>::iterator it = rects_.begin();
72 while (it != rects_.end()) {
73 if (rect.Intersects(*it)) {
74 rect = rect.Union(*it);
75 rects_.erase(it);
76 // We must go back to the beginning since some rects we previously
77 // checked might now intersects with the union of the two rects,
78 // even though they didn't intersect with them individually.
79 it = rects_.begin();
80 } else {
81 ++it;
82 }
83 }
84 rects_.push_back(rect);
85 }
86 }
87
88 void Clip(const gfx::Rect& clip_rect) {
89 std::vector<gfx::Rect>::iterator it = rects_.begin();
90 while (it != rects_.end()) {
91 if (!clip_rect.Contains(*it))
92 *it = clip_rect.Intersect(*it);
93 ++it;
94 }
95 }
96
97 bool Intersects(const gfx::Rect& rect) const {
98 for (size_t i = 0; i < rects_.size(); ++i) {
99 if (rects_[i].Intersects(rect))
100 return true;
101 }
102 return false;
103 }
104
105 private:
106 std::vector<gfx::Rect>& rects_;
107 bool coalesce_;
108 static const size_t kNumRectsThreshold;
109 };
110 // We use a threshold for the number of rects because in many cases as
111 // described here:
112 // http://my.opera.com/desktopteam/blog/2008/03/28/painting-performance-fixes
113 // we get diminishing returns from using more sub-rectangles, it becomes more
114 // efficient to Union the rects. The nubmer 25 is also used in WebKit for
115 // deferred paints in the FrameView. It was chosen here based on some
116 // manual experiments using the benchmark from the article sited above.
117 const size_t PaintRegion::kNumRectsThreshold = 25;
118
119 } // namespace
120
35 RenderWidget::RenderWidget(RenderThreadBase* render_thread, bool activatable) 121 RenderWidget::RenderWidget(RenderThreadBase* render_thread, bool activatable)
36 : routing_id_(MSG_ROUTING_NONE), 122 : routing_id_(MSG_ROUTING_NONE),
37 webwidget_(NULL), 123 webwidget_(NULL),
38 opener_id_(MSG_ROUTING_NONE), 124 opener_id_(MSG_ROUTING_NONE),
39 render_thread_(render_thread), 125 render_thread_(render_thread),
40 host_window_(NULL), 126 host_window_(NULL),
41 current_paint_buf_(NULL), 127 current_paint_buf_(NULL),
42 current_scroll_buf_(NULL), 128 current_scroll_buf_(NULL),
43 next_paint_flags_(0), 129 next_paint_flags_(0),
44 paint_reply_pending_(false), 130 paint_reply_pending_(false),
(...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after
193 size_ = new_size; 279 size_ = new_size;
194 280
195 // We should not be sent a Resize message if we have not ACK'd the previous 281 // We should not be sent a Resize message if we have not ACK'd the previous
196 DCHECK(!next_paint_is_resize_ack()); 282 DCHECK(!next_paint_is_resize_ack());
197 283
198 // When resizing, we want to wait to paint before ACK'ing the resize. This 284 // When resizing, we want to wait to paint before ACK'ing the resize. This
199 // ensures that we only resize as fast as we can paint. We only need to send 285 // ensures that we only resize as fast as we can paint. We only need to send
200 // an ACK if we are resized to a non-empty rect. 286 // an ACK if we are resized to a non-empty rect.
201 webwidget_->Resize(new_size); 287 webwidget_->Resize(new_size);
202 if (!new_size.IsEmpty()) { 288 if (!new_size.IsEmpty()) {
203 DCHECK(!paint_rect_.IsEmpty()); 289 DCHECK(!paint_rects_.empty());
204 290
205 // This should have caused an invalidation of the entire view. The damaged 291 // This should have caused an invalidation of the entire view. The damaged
206 // rect could be larger than new_size if we are being made smaller. 292 // rect could be larger than new_size if we are being made smaller.
207 DCHECK_GE(paint_rect_.width(), new_size.width()); 293 DCHECK_GE(PaintRegion(&paint_rects_).GetBoundingRect().width(),
208 DCHECK_GE(paint_rect_.height(), new_size.height()); 294 new_size.width());
209 295 DCHECK_GE(PaintRegion(&paint_rects_).GetBoundingRect().height(),
296 new_size.height());
210 // We will send the Resize_ACK flag once we paint again. 297 // We will send the Resize_ACK flag once we paint again.
211 set_next_paint_is_resize_ack(); 298 set_next_paint_is_resize_ack();
212 } 299 }
213 } 300 }
214 301
215 void RenderWidget::OnWasHidden() { 302 void RenderWidget::OnWasHidden() {
216 // Go into a mode where we stop generating paint and scrolling events. 303 // Go into a mode where we stop generating paint and scrolling events.
217 is_hidden_ = true; 304 is_hidden_ = true;
218 } 305 }
219 306
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after
307 } 394 }
308 } 395 }
309 396
310 void RenderWidget::ClearFocus() { 397 void RenderWidget::ClearFocus() {
311 // We may have got the focus from the browser before this gets processed, in 398 // We may have got the focus from the browser before this gets processed, in
312 // which case we do not want to unfocus ourself. 399 // which case we do not want to unfocus ourself.
313 if (!has_focus_ && webwidget_) 400 if (!has_focus_ && webwidget_)
314 webwidget_->SetFocus(false); 401 webwidget_->SetFocus(false);
315 } 402 }
316 403
317 void RenderWidget::PaintRect(const gfx::Rect& rect, 404 void RenderWidget::PaintThisRect(const gfx::Rect& rect,
318 skia::PlatformCanvas* canvas) { 405 skia::PlatformCanvas* canvas) {
319 406 // Make sure we don't erase previous rects in the canvas
320 // Bring the canvas into the coordinate system of the paint rect. 407 SkRect clip_rect;
321 canvas->translate(static_cast<SkScalar>(-rect.x()), 408 clip_rect.iset(rect.x(), rect.y(), rect.right(), rect.bottom());
322 static_cast<SkScalar>(-rect.y())); 409 canvas->clipRect(clip_rect, SkRegion::kReplace_Op);
323 410
324 // If there is a custom background, tile it. 411 // If there is a custom background, tile it.
325 if (!background_.empty()) { 412 if (!background_.empty()) {
326 SkPaint paint; 413 SkPaint paint;
327 SkShader* shader = SkShader::CreateBitmapShader(background_, 414 SkShader* shader = SkShader::CreateBitmapShader(background_,
328 SkShader::kRepeat_TileMode, 415 SkShader::kRepeat_TileMode,
329 SkShader::kRepeat_TileMode); 416 SkShader::kRepeat_TileMode);
330 paint.setShader(shader)->unref(); 417 paint.setShader(shader)->unref();
331 paint.setPorterDuffXfermode(SkPorterDuff::kSrcOver_Mode); 418 paint.setPorterDuffXfermode(SkPorterDuff::kSrcOver_Mode);
332 canvas->drawPaint(paint); 419 canvas->drawPaint(paint);
333 } 420 }
334 421
335 webwidget_->Paint(canvas, rect); 422 webwidget_->Paint(canvas, rect);
423 }
424
425 void RenderWidget::PaintRect(const gfx::Rect& rect,
426 skia::PlatformCanvas* canvas) {
427 // Bring the canvas into the coordinate system of the paint rect.
428 canvas->translate(static_cast<SkScalar>(-rect.x()),
429 static_cast<SkScalar>(-rect.y()));
430 PaintThisRect(rect, canvas);
336 431
337 // Flush to underlying bitmap. TODO(darin): is this needed? 432 // Flush to underlying bitmap. TODO(darin): is this needed?
338 canvas->getTopPlatformDevice().accessBitmap(false); 433 canvas->getTopPlatformDevice().accessBitmap(false);
339 434
340 // Let the subclass observe this paint operations. 435 // Let the subclass observe this paint operation.
436 DidPaint();
437 }
438
439 void RenderWidget::PaintRects(const std::vector<gfx::Rect>& rects,
440 skia::PlatformCanvas* canvas) {
441 for (size_t i = 0; i < rects.size(); ++i)
442 PaintThisRect(rects[i], canvas);
443
444 // Flush to underlying bitmap. TODO(darin): is this needed?
445 canvas->getTopPlatformDevice().accessBitmap(false);
446
447 // Let the subclass observe these paint operations.
341 DidPaint(); 448 DidPaint();
342 } 449 }
343 450
344 void RenderWidget::DoDeferredPaint() { 451 void RenderWidget::DoDeferredPaint() {
345 if (!webwidget_ || paint_reply_pending() || paint_rect_.IsEmpty()) 452 if (!webwidget_ || paint_reply_pending() || paint_rects_.empty())
346 return; 453 return;
347 454
348 // When we are hidden, we want to suppress painting, but we still need to 455 // When we are hidden, we want to suppress painting, but we still need to
349 // mark this DoDeferredPaint as complete. 456 // mark this DoDeferredPaint as complete.
350 if (is_hidden_ || size_.IsEmpty()) { 457 if (is_hidden_ || size_.IsEmpty()) {
351 paint_rect_ = gfx::Rect(); 458 paint_rects_.clear();
352 needs_repainting_on_restore_ = true; 459 needs_repainting_on_restore_ = true;
353 return; 460 return;
354 } 461 }
355 462
356 // Layout may generate more invalidation... 463 // Layout may generate more invalidation...
357 webwidget_->Layout(); 464 webwidget_->Layout();
358 465
359 // OK, save the current paint_rect to a local since painting may cause more 466 // OK, save the current paint_rect to a local since painting may cause more
360 // invalidation. Some WebCore rendering objects only layout when painted. 467 // invalidation. Some WebCore rendering objects only layout when painted.
361 gfx::Rect damaged_rect = paint_rect_; 468 std::vector<gfx::Rect> paint_rects = paint_rects_;
362 paint_rect_ = gfx::Rect(); 469 paint_rects_.clear();
363 470
364 // Compute a buffer for painting and cache it. 471 // Compute a buffer for painting and cache it.
472 DCHECK(!current_paint_buf_);
473
474 // we use the whole view size as opposed to damaged rect size we have a pool
475 // of paint buffers anyway, and this size has surely been used at least once
476 // to paint the whole view... And it also prevents, somehow, an intermittent
477 // bug we get when painting the sub-rectangles with StretchDIBits on Windows.
478 gfx::Rect bitmap_rect = gfx::Rect(gfx::Point(0, 0), size_);
365 skia::PlatformCanvas* canvas = 479 skia::PlatformCanvas* canvas =
366 RenderProcess::current()->GetDrawingCanvas(&current_paint_buf_, 480 RenderProcess::current()->GetDrawingCanvas(&current_paint_buf_,
367 damaged_rect); 481 bitmap_rect);
368 if (!canvas) { 482 if (!canvas) {
369 NOTREACHED(); 483 NOTREACHED();
370 return; 484 return;
371 } 485 }
372 486
373 PaintRect(damaged_rect, canvas); 487 // We must make sure all our paint rects are within the bitmap bounds.
488 PaintRegion(&paint_rects).Clip(bitmap_rect);
489 PaintRects(paint_rects, canvas);
374 490
375 ViewHostMsg_PaintRect_Params params; 491 ViewHostMsg_PaintRect_Params params;
376 params.bitmap_rect = damaged_rect; 492 params.bitmap = current_paint_buf_->id();
493 params.bitmap_rect = bitmap_rect;
494 params.paint_rects = paint_rects;
377 params.view_size = size_; 495 params.view_size = size_;
378 params.plugin_window_moves = plugin_window_moves_; 496 params.plugin_window_moves = plugin_window_moves_;
379 params.flags = next_paint_flags_; 497 params.flags = next_paint_flags_;
380 params.bitmap = current_paint_buf_->id();
381 498
382 delete canvas; 499 delete canvas;
383 500
384 plugin_window_moves_.clear(); 501 plugin_window_moves_.clear();
385 502
386 paint_reply_pending_ = true; 503 paint_reply_pending_ = true;
387 Send(new ViewHostMsg_PaintRect(routing_id_, params)); 504 Send(new ViewHostMsg_PaintRect(routing_id_, params));
388 next_paint_flags_ = 0; 505 next_paint_flags_ = 0;
389 506
390 UpdateIME(); 507 UpdateIME();
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
473 /////////////////////////////////////////////////////////////////////////////// 590 ///////////////////////////////////////////////////////////////////////////////
474 // WebWidgetDelegate 591 // WebWidgetDelegate
475 592
476 gfx::NativeViewId RenderWidget::GetContainingView(WebWidget* webwidget) { 593 gfx::NativeViewId RenderWidget::GetContainingView(WebWidget* webwidget) {
477 return host_window_; 594 return host_window_;
478 } 595 }
479 596
480 void RenderWidget::DidInvalidateRect(WebWidget* webwidget, 597 void RenderWidget::DidInvalidateRect(WebWidget* webwidget,
481 const WebRect& rect) { 598 const WebRect& rect) {
482 // We only want one pending DoDeferredPaint call at any time... 599 // We only want one pending DoDeferredPaint call at any time...
483 bool paint_pending = !paint_rect_.IsEmpty(); 600 bool paint_pending = !paint_rects_.empty();
484 601
485 // If this invalidate overlaps with a pending scroll, then we have to 602 // If this invalidate overlaps with a pending scroll, then we have to
486 // downgrade to invalidating the scroll rect. 603 // downgrade to invalidating the scroll rect.
604 PaintRegion rect_vector(&paint_rects_);
487 if (gfx::Rect(rect).Intersects(scroll_rect_)) { 605 if (gfx::Rect(rect).Intersects(scroll_rect_)) {
488 paint_rect_ = paint_rect_.Union(scroll_rect_); 606 rect_vector.Add(scroll_rect_);
489 scroll_rect_ = gfx::Rect(); 607 scroll_rect_ = gfx::Rect();
490 } 608 }
491 609
492 gfx::Rect view_rect(0, 0, size_.width(), size_.height()); 610 // We don't need to intersect with the view rect here since we have to
493 // TODO(iyengar) Investigate why we have painting issues when 611 // do it later on in case the view rect changes between invalidations.
494 // we ignore invalid regions outside the view. 612 rect_vector.Add(rect);
495 // Ignore invalidates that occur outside the bounds of the view
496 // TODO(darin): maybe this should move into the paint code?
497 // paint_rect_ = view_rect.Intersect(paint_rect_.Union(rect));
498 paint_rect_ = paint_rect_.Union(view_rect.Intersect(rect));
499 613
500 if (paint_rect_.IsEmpty() || paint_reply_pending() || paint_pending) 614 if (paint_rects_.empty() || paint_reply_pending() || paint_pending)
501 return; 615 return;
502 616
503 // Perform painting asynchronously. This serves two purposes: 617 // Perform painting asynchronously. This serves two purposes:
504 // 1) Ensures that we call WebView::Paint without a bunch of other junk 618 // 1) Ensures that we call WebView::Paint without a bunch of other junk
505 // on the call stack. 619 // on the call stack.
506 // 2) Allows us to collect more damage rects before painting to help coalesce 620 // 2) Allows us to collect more damage rects before painting to help coalesce
507 // the work that we will need to do. 621 // the work that we will need to do.
508 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod( 622 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
509 this, &RenderWidget::DoDeferredPaint)); 623 this, &RenderWidget::DoDeferredPaint));
510 } 624 }
511 625
512 void RenderWidget::DidScrollRect(WebWidget* webwidget, int dx, int dy, 626 void RenderWidget::DidScrollRect(WebWidget* webwidget, int dx, int dy,
513 const WebRect& clip_rect) { 627 const WebRect& clip_rect) {
514 if (dx != 0 && dy != 0) { 628 if (dx != 0 && dy != 0) {
515 // We only support scrolling along one axis at a time. 629 // We only support scrolling along one axis at a time.
516 DidScrollRect(webwidget, 0, dy, clip_rect); 630 DidScrollRect(webwidget, 0, dy, clip_rect);
517 dy = 0; 631 dy = 0;
518 } 632 }
519 633
520 bool intersects_with_painting = paint_rect_.Intersects(clip_rect); 634 bool intersects_with_painting =
635 PaintRegion(&paint_rects_).Intersects(clip_rect);
521 636
522 // If we already have a pending scroll operation or if this scroll operation 637 // If we already have a pending scroll operation or if this scroll operation
523 // intersects the existing paint region, then just failover to invalidating. 638 // intersects the existing paint region, then just failover to invalidating.
524 if (!scroll_rect_.IsEmpty() || intersects_with_painting) { 639 if (!scroll_rect_.IsEmpty() || intersects_with_painting) {
525 if (!intersects_with_painting && scroll_rect_ == gfx::Rect(clip_rect)) { 640 if (!intersects_with_painting && scroll_rect_ == gfx::Rect(clip_rect)) {
526 // OK, we can just update the scroll delta (requires same scrolling axis) 641 // OK, we can just update the scroll delta (requires same scrolling axis)
527 if (!dx && !scroll_delta_.x()) { 642 if (!dx && !scroll_delta_.x()) {
528 scroll_delta_.set_y(scroll_delta_.y() + dy); 643 scroll_delta_.set_y(scroll_delta_.y() + dy);
529 return; 644 return;
530 } 645 }
(...skipping 310 matching lines...) Expand 10 before | Expand all | Expand 10 after
841 if (i == plugin_window_moves_.size()) 956 if (i == plugin_window_moves_.size())
842 plugin_window_moves_.push_back(move); 957 plugin_window_moves_.push_back(move);
843 } 958 }
844 959
845 WebScreenInfo RenderWidget::GetScreenInfo(WebWidget* webwidget) { 960 WebScreenInfo RenderWidget::GetScreenInfo(WebWidget* webwidget) {
846 WebScreenInfo results; 961 WebScreenInfo results;
847 RenderThread::current()->Send( 962 RenderThread::current()->Send(
848 new ViewHostMsg_GetScreenInfo(host_window_, &results)); 963 new ViewHostMsg_GetScreenInfo(host_window_, &results));
849 return results; 964 return results;
850 } 965 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698