Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / cc / resources / picture_pile_impl.cc
index b88a439..de25c04 100644 (file)
@@ -9,28 +9,13 @@
 #include "cc/base/region.h"
 #include "cc/debug/debug_colors.h"
 #include "cc/resources/picture_pile_impl.h"
-#include "cc/resources/raster_worker_pool.h"
 #include "skia/ext/analysis_canvas.h"
 #include "third_party/skia/include/core/SkCanvas.h"
-#include "third_party/skia/include/core/SkSize.h"
-#include "ui/gfx/rect_conversions.h"
-#include "ui/gfx/size_conversions.h"
-#include "ui/gfx/skia_util.h"
+#include "third_party/skia/include/core/SkPictureRecorder.h"
+#include "ui/gfx/geometry/rect_conversions.h"
 
 namespace cc {
 
-PicturePileImpl::ClonesForDrawing::ClonesForDrawing(
-    const PicturePileImpl* pile, int num_threads) {
-  for (int i = 0; i < num_threads; i++) {
-    scoped_refptr<PicturePileImpl> clone =
-        PicturePileImpl::CreateCloneForDrawing(pile, i);
-    clones_.push_back(clone);
-  }
-}
-
-PicturePileImpl::ClonesForDrawing::~ClonesForDrawing() {
-}
-
 scoped_refptr<PicturePileImpl> PicturePileImpl::Create() {
   return make_scoped_refptr(new PicturePileImpl);
 }
@@ -40,122 +25,140 @@ scoped_refptr<PicturePileImpl> PicturePileImpl::CreateFromOther(
   return make_scoped_refptr(new PicturePileImpl(other));
 }
 
-scoped_refptr<PicturePileImpl> PicturePileImpl::CreateCloneForDrawing(
-    const PicturePileImpl* other, unsigned thread_index) {
-  return make_scoped_refptr(new PicturePileImpl(other, thread_index));
-}
-
 PicturePileImpl::PicturePileImpl()
-    : clones_for_drawing_(ClonesForDrawing(this, 0)) {
+    : background_color_(SK_ColorTRANSPARENT),
+      contents_opaque_(false),
+      contents_fill_bounds_completely_(false),
+      is_solid_color_(false),
+      solid_color_(SK_ColorTRANSPARENT),
+      has_any_recordings_(false),
+      is_mask_(false),
+      clear_canvas_with_debug_color_(false),
+      min_contents_scale_(0.f),
+      slow_down_raster_scale_factor_for_debug_(0),
+      likely_to_be_used_for_transform_animation_(false) {
 }
 
 PicturePileImpl::PicturePileImpl(const PicturePileBase* other)
-    : PicturePileBase(other),
-      clones_for_drawing_(ClonesForDrawing(
-                              this, RasterWorkerPool::GetNumRasterThreads())) {
-}
-
-PicturePileImpl::PicturePileImpl(
-    const PicturePileImpl* other, unsigned thread_index)
-    : PicturePileBase(other, thread_index),
-      clones_for_drawing_(ClonesForDrawing(this, 0)) {
+    : picture_map_(other->picture_map_),
+      tiling_(other->tiling_),
+      background_color_(other->background_color_),
+      contents_opaque_(other->contents_opaque_),
+      contents_fill_bounds_completely_(other->contents_fill_bounds_completely_),
+      is_solid_color_(other->is_solid_color_),
+      solid_color_(other->solid_color_),
+      recorded_viewport_(other->recorded_viewport_),
+      has_any_recordings_(other->has_any_recordings_),
+      is_mask_(other->is_mask_),
+      clear_canvas_with_debug_color_(other->clear_canvas_with_debug_color_),
+      min_contents_scale_(other->min_contents_scale_),
+      slow_down_raster_scale_factor_for_debug_(
+          other->slow_down_raster_scale_factor_for_debug_),
+      likely_to_be_used_for_transform_animation_(false) {
 }
 
 PicturePileImpl::~PicturePileImpl() {
 }
 
-PicturePileImpl* PicturePileImpl::GetCloneForDrawingOnThread(
-    unsigned thread_index) const {
-  CHECK_GT(clones_for_drawing_.clones_.size(), thread_index);
-  return clones_for_drawing_.clones_[thread_index].get();
-}
-
-void PicturePileImpl::RasterDirect(
-    SkCanvas* canvas,
-    const gfx::Rect& canvas_rect,
-    float contents_scale,
-    RenderingStatsInstrumentation* rendering_stats_instrumentation) {
+void PicturePileImpl::RasterDirect(SkCanvas* canvas,
+                                   const gfx::Rect& canvas_rect,
+                                   float contents_scale) const {
   RasterCommon(canvas,
                NULL,
                canvas_rect,
                contents_scale,
-               rendering_stats_instrumentation,
                false);
 }
 
-void PicturePileImpl::RasterForAnalysis(
-    skia::AnalysisCanvas* canvas,
-    const gfx::Rect& canvas_rect,
-    float contents_scale,
-    RenderingStatsInstrumentation* stats_instrumentation) {
-  RasterCommon(
-      canvas, canvas, canvas_rect, contents_scale, stats_instrumentation, true);
+void PicturePileImpl::RasterForAnalysis(skia::AnalysisCanvas* canvas,
+                                        const gfx::Rect& canvas_rect,
+                                        float contents_scale) const {
+  RasterCommon(canvas, canvas, canvas_rect, contents_scale, true);
 }
 
-void PicturePileImpl::RasterToBitmap(
-    SkCanvas* canvas,
-    const gfx::Rect& canvas_rect,
-    float contents_scale,
-    RenderingStatsInstrumentation* rendering_stats_instrumentation) {
+void PicturePileImpl::PlaybackToCanvas(SkCanvas* canvas,
+                                       const gfx::Rect& canvas_rect,
+                                       float contents_scale) const {
+  canvas->discard();
   if (clear_canvas_with_debug_color_) {
-    // Any non-painted areas will be left in this color.
+    // Any non-painted areas in the content bounds will be left in this color.
     canvas->clear(DebugColors::NonPaintedFillColor());
   }
 
   // If this picture has opaque contents, it is guaranteeing that it will
   // draw an opaque rect the size of the layer.  If it is not, then we must
   // clear this canvas ourselves.
-  if (!contents_opaque_) {
-    // Clearing is about ~4x faster than drawing a rect even if the content
-    // isn't covering a majority of the canvas.
-    canvas->clear(SK_ColorTRANSPARENT);
-  } else {
-    // Even if it is opaque, on any rasterizations that touch the edge of the
+  if (contents_opaque_ || contents_fill_bounds_completely_) {
+    // Even if completely covered, for rasterizations that touch the edge of the
     // layer, we also need to raster the background color underneath the last
     // texel (since the recording won't cover it) and outside the last texel
     // (due to linear filtering when using this texture).
-    gfx::SizeF total_content_size = gfx::ScaleSize(tiling_.total_size(),
-                                                   contents_scale);
-    gfx::Rect content_rect(gfx::ToCeiledSize(total_content_size));
+    gfx::Rect content_tiling_rect = gfx::ToEnclosingRect(
+        gfx::ScaleRect(gfx::Rect(tiling_.tiling_size()), contents_scale));
 
     // The final texel of content may only be partially covered by a
     // rasterization; this rect represents the content rect that is fully
     // covered by content.
-    gfx::Rect deflated_content_rect = content_rect;
-    deflated_content_rect.Inset(0, 0, 1, 1);
-    if (!deflated_content_rect.Contains(canvas_rect)) {
+    gfx::Rect deflated_content_tiling_rect = content_tiling_rect;
+    deflated_content_tiling_rect.Inset(0, 0, 1, 1);
+    if (!deflated_content_tiling_rect.Contains(canvas_rect)) {
+      if (clear_canvas_with_debug_color_) {
+        // Any non-painted areas outside of the content bounds are left in
+        // this color.  If this is seen then it means that cc neglected to
+        // rerasterize a tile that used to intersect with the content rect
+        // after the content bounds grew.
+        canvas->save();
+        canvas->translate(-canvas_rect.x(), -canvas_rect.y());
+        canvas->clipRect(gfx::RectToSkRect(content_tiling_rect),
+                         SkRegion::kDifference_Op);
+        canvas->drawColor(DebugColors::MissingResizeInvalidations(),
+                          SkXfermode::kSrc_Mode);
+        canvas->restore();
+      }
+
       // Drawing at most 2 x 2 x (canvas width + canvas height) texels is 2-3X
       // faster than clearing, so special case this.
       canvas->save();
       canvas->translate(-canvas_rect.x(), -canvas_rect.y());
-      gfx::Rect inflated_content_rect = content_rect;
-      inflated_content_rect.Inset(0, 0, -1, -1);
-      canvas->clipRect(gfx::RectToSkRect(inflated_content_rect),
+      gfx::Rect inflated_content_tiling_rect = content_tiling_rect;
+      inflated_content_tiling_rect.Inset(0, 0, -1, -1);
+      canvas->clipRect(gfx::RectToSkRect(inflated_content_tiling_rect),
                        SkRegion::kReplace_Op);
-      canvas->clipRect(gfx::RectToSkRect(deflated_content_rect),
+      canvas->clipRect(gfx::RectToSkRect(deflated_content_tiling_rect),
                        SkRegion::kDifference_Op);
       canvas->drawColor(background_color_, SkXfermode::kSrc_Mode);
       canvas->restore();
     }
+  } else {
+    TRACE_EVENT_INSTANT0("cc", "SkCanvas::clear", TRACE_EVENT_SCOPE_THREAD);
+    // Clearing is about ~4x faster than drawing a rect even if the content
+    // isn't covering a majority of the canvas.
+    canvas->clear(SK_ColorTRANSPARENT);
   }
 
   RasterCommon(canvas,
                NULL,
                canvas_rect,
                contents_scale,
-               rendering_stats_instrumentation,
                false);
 }
 
 void PicturePileImpl::CoalesceRasters(const gfx::Rect& canvas_rect,
                                       const gfx::Rect& content_rect,
                                       float contents_scale,
-                                      PictureRegionMap* results) {
+                                      PictureRegionMap* results) const {
   DCHECK(results);
   // Rasterize the collection of relevant picture piles.
   gfx::Rect layer_rect = gfx::ScaleToEnclosingRect(
       content_rect, 1.f / contents_scale);
 
+  // Make sure pictures don't overlap by keeping track of previous right/bottom.
+  int min_content_left = -1;
+  int min_content_top = -1;
+  int last_row_index = -1;
+  int last_col_index = -1;
+  gfx::Rect last_content_rect;
+
   // Coalesce rasters of the same picture into different rects:
   //  - Compute the clip of each of the pile chunks,
   //  - Subtract it from the canvas rect to get difference region
@@ -170,13 +173,15 @@ void PicturePileImpl::CoalesceRasters(const gfx::Rect& canvas_rect,
   // that and subtract chunk rects to get the region that we need to subtract
   // from the canvas. Then, we can use clipRect with difference op to subtract
   // each rect in the region.
-  for (TilingData::Iterator tile_iter(&tiling_, layer_rect);
-       tile_iter; ++tile_iter) {
-    PictureMap::iterator map_iter = picture_map_.find(tile_iter.index());
+  bool include_borders = true;
+  for (TilingData::Iterator tile_iter(&tiling_, layer_rect, include_borders);
+       tile_iter;
+       ++tile_iter) {
+    PictureMap::const_iterator map_iter = picture_map_.find(tile_iter.index());
     if (map_iter == picture_map_.end())
       continue;
-    PictureInfo& info = map_iter->second;
-    Picture* picture = info.GetPicture();
+    const PictureInfo& info = map_iter->second;
+    const Picture* picture = info.GetPicture();
     if (!picture)
       continue;
 
@@ -193,16 +198,43 @@ void PicturePileImpl::CoalesceRasters(const gfx::Rect& canvas_rect,
                                     << "Contents scale: " << contents_scale;
     content_clip.Intersect(canvas_rect);
 
+    // Make sure iterator goes top->bottom.
+    DCHECK_GE(tile_iter.index_y(), last_row_index);
+    if (tile_iter.index_y() > last_row_index) {
+      // First tile in a new row.
+      min_content_left = content_clip.x();
+      min_content_top = last_content_rect.bottom();
+    } else {
+      // Make sure iterator goes left->right.
+      DCHECK_GT(tile_iter.index_x(), last_col_index);
+      min_content_left = last_content_rect.right();
+      min_content_top = last_content_rect.y();
+    }
+
+    last_col_index = tile_iter.index_x();
+    last_row_index = tile_iter.index_y();
+
+    // Only inset if the content_clip is less than then previous min.
+    int inset_left = std::max(0, min_content_left - content_clip.x());
+    int inset_top = std::max(0, min_content_top - content_clip.y());
+    content_clip.Inset(inset_left, inset_top, 0, 0);
+
     PictureRegionMap::iterator it = results->find(picture);
+    Region* clip_region;
     if (it == results->end()) {
-      Region& region = (*results)[picture];
-      region = content_rect;
-      region.Subtract(content_clip);
-      continue;
+      // The clip for a set of coalesced pictures starts out clipping the entire
+      // canvas.  Each picture added to the set must subtract its own bounds
+      // from the clip region, poking a hole so that the picture is unclipped.
+      clip_region = &(*results)[picture];
+      *clip_region = canvas_rect;
+    } else {
+      clip_region = &it->second;
     }
 
-    Region& region = it->second;
-    region.Subtract(content_clip);
+    DCHECK(clip_region->Contains(content_clip))
+        << "Content clips should not overlap.";
+    clip_region->Subtract(content_clip);
+    last_content_rect = content_clip;
   }
 }
 
@@ -211,23 +243,20 @@ void PicturePileImpl::RasterCommon(
     SkDrawPictureCallback* callback,
     const gfx::Rect& canvas_rect,
     float contents_scale,
-    RenderingStatsInstrumentation* rendering_stats_instrumentation,
-    bool is_analysis) {
+    bool is_analysis) const {
   DCHECK(contents_scale >= min_contents_scale_);
 
   canvas->translate(-canvas_rect.x(), -canvas_rect.y());
-  gfx::SizeF total_content_size = gfx::ScaleSize(tiling_.total_size(),
-                                                 contents_scale);
-  gfx::Rect total_content_rect(gfx::ToCeiledSize(total_content_size));
-  gfx::Rect content_rect = total_content_rect;
-  content_rect.Intersect(canvas_rect);
+  gfx::Rect content_tiling_rect = gfx::ToEnclosingRect(
+      gfx::ScaleRect(gfx::Rect(tiling_.tiling_size()), contents_scale));
+  content_tiling_rect.Intersect(canvas_rect);
 
-  canvas->clipRect(gfx::RectToSkRect(content_rect),
+  canvas->clipRect(gfx::RectToSkRect(content_tiling_rect),
                    SkRegion::kIntersect_Op);
 
   PictureRegionMap picture_region_map;
   CoalesceRasters(
-      canvas_rect, content_rect, contents_scale, &picture_region_map);
+      canvas_rect, content_tiling_rect, contents_scale, &picture_region_map);
 
 #ifndef NDEBUG
   Region total_clip;
@@ -238,44 +267,21 @@ void PicturePileImpl::RasterCommon(
   for (PictureRegionMap::iterator it = picture_region_map.begin();
        it != picture_region_map.end();
        ++it) {
-    Picture* picture = it->first;
+    const Picture* picture = it->first;
     Region negated_clip_region = it->second;
 
 #ifndef NDEBUG
-    Region positive_clip = content_rect;
+    Region positive_clip = content_tiling_rect;
     positive_clip.Subtract(negated_clip_region);
+    // Make sure we never rasterize the same region twice.
+    DCHECK(!total_clip.Intersects(positive_clip));
     total_clip.Union(positive_clip);
 #endif  // NDEBUG
 
-    base::TimeDelta best_duration =
-        base::TimeDelta::FromInternalValue(std::numeric_limits<int64>::max());
     int repeat_count = std::max(1, slow_down_raster_scale_factor_for_debug_);
-    int rasterized_pixel_count = 0;
 
-    for (int j = 0; j < repeat_count; ++j) {
-      base::TimeTicks start_time;
-      if (rendering_stats_instrumentation)
-        start_time = rendering_stats_instrumentation->StartRecording();
-
-      rasterized_pixel_count = picture->Raster(
-          canvas, callback, negated_clip_region, contents_scale);
-
-      if (rendering_stats_instrumentation) {
-        base::TimeDelta duration =
-            rendering_stats_instrumentation->EndRecording(start_time);
-        best_duration = std::min(best_duration, duration);
-      }
-    }
-
-    if (rendering_stats_instrumentation) {
-      if (is_analysis) {
-        rendering_stats_instrumentation->AddAnalysis(best_duration,
-                                                     rasterized_pixel_count);
-      } else {
-        rendering_stats_instrumentation->AddRaster(best_duration,
-                                                   rasterized_pixel_count);
-      }
-    }
+    for (int j = 0; j < repeat_count; ++j)
+      picture->Raster(canvas, callback, negated_clip_region, contents_scale);
   }
 
 #ifndef NDEBUG
@@ -294,61 +300,106 @@ void PicturePileImpl::RasterCommon(
 skia::RefPtr<SkPicture> PicturePileImpl::GetFlattenedPicture() {
   TRACE_EVENT0("cc", "PicturePileImpl::GetFlattenedPicture");
 
-  gfx::Rect layer_rect(tiling_.total_size());
-  skia::RefPtr<SkPicture> picture = skia::AdoptRef(new SkPicture);
-  if (layer_rect.IsEmpty())
-    return picture;
-
-  SkCanvas* canvas = picture->beginRecording(
-      layer_rect.width(),
-      layer_rect.height(),
-      SkPicture::kUsePathBoundsForClip_RecordingFlag);
-
-  RasterToBitmap(canvas, layer_rect, 1.0, NULL);
-  picture->endRecording();
+  gfx::Rect tiling_rect(tiling_.tiling_size());
+  SkPictureRecorder recorder;
+  SkCanvas* canvas =
+      recorder.beginRecording(tiling_rect.width(), tiling_rect.height());
+  if (!tiling_rect.IsEmpty())
+    PlaybackToCanvas(canvas, tiling_rect, 1.0);
+  skia::RefPtr<SkPicture> picture = skia::AdoptRef(recorder.endRecording());
 
   return picture;
 }
 
-void PicturePileImpl::AnalyzeInRect(
+void PicturePileImpl::PerformSolidColorAnalysis(
     const gfx::Rect& content_rect,
     float contents_scale,
-    PicturePileImpl::Analysis* analysis) {
-  AnalyzeInRect(content_rect, contents_scale, analysis, NULL);
-}
-
-void PicturePileImpl::AnalyzeInRect(
-    const gfx::Rect& content_rect,
-    float contents_scale,
-    PicturePileImpl::Analysis* analysis,
-    RenderingStatsInstrumentation* stats_instrumentation) {
+    RasterSource::SolidColorAnalysis* analysis) const {
   DCHECK(analysis);
-  TRACE_EVENT0("cc", "PicturePileImpl::AnalyzeInRect");
+  TRACE_EVENT0("cc", "PicturePileImpl::PerformSolidColorAnalysis");
 
   gfx::Rect layer_rect = gfx::ScaleToEnclosingRect(
       content_rect, 1.0f / contents_scale);
 
-  layer_rect.Intersect(gfx::Rect(tiling_.total_size()));
+  layer_rect.Intersect(gfx::Rect(tiling_.tiling_size()));
 
-  SkBitmap empty_bitmap;
-  empty_bitmap.setConfig(SkBitmap::kNo_Config,
-                         layer_rect.width(),
-                         layer_rect.height());
-  skia::AnalysisDevice device(empty_bitmap);
-  skia::AnalysisCanvas canvas(&device);
+  skia::AnalysisCanvas canvas(layer_rect.width(), layer_rect.height());
 
-  RasterForAnalysis(&canvas, layer_rect, 1.0f, stats_instrumentation);
+  RasterForAnalysis(&canvas, layer_rect, 1.0f);
 
   analysis->is_solid_color = canvas.GetColorIfSolid(&analysis->solid_color);
-  analysis->has_text = canvas.HasText();
 }
 
-PicturePileImpl::Analysis::Analysis()
-    : is_solid_color(false),
-      has_text(false) {
+void PicturePileImpl::GatherPixelRefs(
+    const gfx::Rect& content_rect,
+    float contents_scale,
+    std::vector<SkPixelRef*>* pixel_refs) const {
+  DCHECK_EQ(0u, pixel_refs->size());
+  for (PixelRefIterator iter(content_rect, contents_scale, this); iter;
+       ++iter) {
+    pixel_refs->push_back(*iter);
+  }
+}
+
+bool PicturePileImpl::CoversRect(const gfx::Rect& content_rect,
+                                 float contents_scale) const {
+  if (tiling_.tiling_size().IsEmpty())
+    return false;
+  gfx::Rect layer_rect =
+      gfx::ScaleToEnclosingRect(content_rect, 1.f / contents_scale);
+  layer_rect.Intersect(gfx::Rect(tiling_.tiling_size()));
+
+  // Common case inside of viewport to avoid the slower map lookups.
+  if (recorded_viewport_.Contains(layer_rect)) {
+    // Sanity check that there are no false positives in recorded_viewport_.
+    DCHECK(CanRasterSlowTileCheck(layer_rect));
+    return true;
+  }
+
+  return CanRasterSlowTileCheck(layer_rect);
+}
+
+gfx::Rect PicturePileImpl::PaddedRect(const PictureMapKey& key) const {
+  gfx::Rect padded_rect = tiling_.TileBounds(key.first, key.second);
+  padded_rect.Inset(-buffer_pixels(), -buffer_pixels(), -buffer_pixels(),
+                    -buffer_pixels());
+  return padded_rect;
+}
+
+bool PicturePileImpl::CanRasterSlowTileCheck(
+    const gfx::Rect& layer_rect) const {
+  bool include_borders = false;
+  for (TilingData::Iterator tile_iter(&tiling_, layer_rect, include_borders);
+       tile_iter; ++tile_iter) {
+    PictureMap::const_iterator map_iter = picture_map_.find(tile_iter.index());
+    if (map_iter == picture_map_.end())
+      return false;
+    if (!map_iter->second.GetPicture())
+      return false;
+  }
+  return true;
 }
 
-PicturePileImpl::Analysis::~Analysis() {
+bool PicturePileImpl::SuitableForDistanceFieldText() const {
+  return likely_to_be_used_for_transform_animation_;
+}
+
+void PicturePileImpl::AsValueInto(base::debug::TracedValue* pictures) const {
+  gfx::Rect tiling_rect(tiling_.tiling_size());
+  std::set<const void*> appended_pictures;
+  bool include_borders = true;
+  for (TilingData::Iterator tile_iter(&tiling_, tiling_rect, include_borders);
+       tile_iter; ++tile_iter) {
+    PictureMap::const_iterator map_iter = picture_map_.find(tile_iter.index());
+    if (map_iter == picture_map_.end())
+      continue;
+
+    const Picture* picture = map_iter->second.GetPicture();
+    if (picture && (appended_pictures.count(picture) == 0)) {
+      appended_pictures.insert(picture);
+      TracedValue::AppendIDRef(picture, pictures);
+    }
+  }
 }
 
 PicturePileImpl::PixelRefIterator::PixelRefIterator(
@@ -356,9 +407,11 @@ PicturePileImpl::PixelRefIterator::PixelRefIterator(
     float contents_scale,
     const PicturePileImpl* picture_pile)
     : picture_pile_(picture_pile),
-      layer_rect_(gfx::ScaleToEnclosingRect(
-          content_rect, 1.f / contents_scale)),
-      tile_iterator_(&picture_pile_->tiling_, layer_rect_) {
+      layer_rect_(
+          gfx::ScaleToEnclosingRect(content_rect, 1.f / contents_scale)),
+      tile_iterator_(&picture_pile_->tiling_,
+                     layer_rect_,
+                     false /* include_borders */) {
   // Early out if there isn't a single tile.
   if (!tile_iterator_)
     return;
@@ -400,12 +453,11 @@ void PicturePileImpl::PixelRefIterator::AdvanceToTilePictureWithPixelRefs() {
 }
 
 void PicturePileImpl::DidBeginTracing() {
-  gfx::Rect layer_rect(tiling_.total_size());
-  std::set<void*> processed_pictures;
+  std::set<const void*> processed_pictures;
   for (PictureMap::iterator it = picture_map_.begin();
        it != picture_map_.end();
        ++it) {
-    Picture* picture = it->second.GetPicture();
+    const Picture* picture = it->second.GetPicture();
     if (picture && (processed_pictures.count(picture) == 0)) {
       picture->EmitTraceSnapshot();
       processed_pictures.insert(picture);