// Copyright 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "cc/resources/content_layer_updater.h" #include "base/trace_event/trace_event.h" #include "cc/resources/layer_painter.h" #include "third_party/skia/include/core/SkCanvas.h" #include "third_party/skia/include/core/SkRect.h" #include "third_party/skia/include/core/SkScalar.h" #include "ui/gfx/geometry/rect_conversions.h" #include "ui/gfx/geometry/rect_f.h" #include "ui/gfx/skia_util.h" namespace cc { ContentLayerUpdater::ContentLayerUpdater(scoped_ptr painter, int layer_id) : layer_id_(layer_id), layer_is_opaque_(false), layer_fills_bounds_completely_(false), painter_(painter.Pass()), background_color_(SK_ColorTRANSPARENT) { } ContentLayerUpdater::~ContentLayerUpdater() {} void ContentLayerUpdater::PaintContents(SkCanvas* canvas, const gfx::Size& layer_content_size, const gfx::Rect& paint_rect, float contents_width_scale, float contents_height_scale) { TRACE_EVENT0("cc", "ContentLayerUpdater::PaintContents"); if (!canvas) return; canvas->save(); canvas->translate(SkIntToScalar(-paint_rect.x()), SkIntToScalar(-paint_rect.y())); // The |canvas| backing should be sized to hold the |paint_rect|. DCHECK_EQ(paint_rect.width(), canvas->getBaseLayerSize().width()); DCHECK_EQ(paint_rect.height(), canvas->getBaseLayerSize().height()); const bool is_scaled = contents_width_scale != 1.f || contents_height_scale != 1.f; if (is_scaled && (layer_is_opaque_ || layer_fills_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 paint won't cover it). // // 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. const gfx::Rect layer_content_rect = gfx::Rect(layer_content_size); gfx::Rect deflated_layer_content_rect = layer_content_rect; deflated_layer_content_rect.Inset(0, 0, 1, 1); if (!layer_content_rect.Contains(deflated_layer_content_rect)) { // Drawing at most 1 x 1 x (canvas width + canvas height) texels is 2-3X // faster than clearing, so special case this. DCHECK_LE(paint_rect.right(), layer_content_rect.right()); DCHECK_LE(paint_rect.bottom(), layer_content_rect.bottom()); canvas->save(); canvas->clipRect(gfx::RectToSkRect(layer_content_rect), SkRegion::kReplace_Op); canvas->clipRect(gfx::RectToSkRect(deflated_layer_content_rect), SkRegion::kDifference_Op); canvas->drawColor(background_color_, SkXfermode::kSrc_Mode); canvas->restore(); } } gfx::Rect layer_rect; if (is_scaled) { canvas->scale(SkFloatToScalar(contents_width_scale), SkFloatToScalar(contents_height_scale)); // NOTE: this may go beyond the bounds of the layer, but that shouldn't // cause problems (anything beyond the layer is clipped out). layer_rect = gfx::ScaleToEnclosingRect( paint_rect, 1.f / contents_width_scale, 1.f / contents_height_scale); } else { layer_rect = paint_rect; } SkRect layer_sk_rect = SkRect::MakeXYWH( layer_rect.x(), layer_rect.y(), layer_rect.width(), layer_rect.height()); canvas->clipRect(layer_sk_rect); // If the layer has opaque contents or will fill the bounds completely there // is no need to clear the canvas before painting. if (!layer_is_opaque_ && !layer_fills_bounds_completely_) { TRACE_EVENT0("cc", "Clear"); canvas->drawColor(SK_ColorTRANSPARENT, SkXfermode::kSrc_Mode); } painter_->Paint(canvas, layer_rect); canvas->restore(); paint_rect_ = paint_rect; } void ContentLayerUpdater::SetOpaque(bool opaque) { layer_is_opaque_ = opaque; } void ContentLayerUpdater::SetFillsBoundsCompletely(bool fills_bounds) { layer_fills_bounds_completely_ = fills_bounds; } void ContentLayerUpdater::SetBackgroundColor(SkColor background_color) { background_color_ = background_color; } } // namespace cc