Home | History | Annotate | Download | only in output
      1 // Copyright 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "cc/output/software_renderer.h"
      6 
      7 #include "base/debug/trace_event.h"
      8 #include "cc/base/math_util.h"
      9 #include "cc/output/compositor_frame.h"
     10 #include "cc/output/compositor_frame_ack.h"
     11 #include "cc/output/compositor_frame_metadata.h"
     12 #include "cc/output/copy_output_request.h"
     13 #include "cc/output/output_surface.h"
     14 #include "cc/output/render_surface_filters.h"
     15 #include "cc/output/software_output_device.h"
     16 #include "cc/quads/checkerboard_draw_quad.h"
     17 #include "cc/quads/debug_border_draw_quad.h"
     18 #include "cc/quads/picture_draw_quad.h"
     19 #include "cc/quads/render_pass_draw_quad.h"
     20 #include "cc/quads/solid_color_draw_quad.h"
     21 #include "cc/quads/texture_draw_quad.h"
     22 #include "cc/quads/tile_draw_quad.h"
     23 #include "skia/ext/opacity_draw_filter.h"
     24 #include "third_party/skia/include/core/SkCanvas.h"
     25 #include "third_party/skia/include/core/SkColor.h"
     26 #include "third_party/skia/include/core/SkImageFilter.h"
     27 #include "third_party/skia/include/core/SkMatrix.h"
     28 #include "third_party/skia/include/core/SkShader.h"
     29 #include "third_party/skia/include/effects/SkLayerRasterizer.h"
     30 #include "ui/gfx/rect_conversions.h"
     31 #include "ui/gfx/skia_util.h"
     32 #include "ui/gfx/transform.h"
     33 
     34 namespace cc {
     35 
     36 namespace {
     37 
     38 static inline bool IsScalarNearlyInteger(SkScalar scalar) {
     39   return SkScalarNearlyZero(scalar - SkScalarRound(scalar));
     40 }
     41 
     42 bool IsScaleAndIntegerTranslate(const SkMatrix& matrix) {
     43   return IsScalarNearlyInteger(matrix[SkMatrix::kMTransX]) &&
     44          IsScalarNearlyInteger(matrix[SkMatrix::kMTransY]) &&
     45          SkScalarNearlyZero(matrix[SkMatrix::kMSkewX]) &&
     46          SkScalarNearlyZero(matrix[SkMatrix::kMSkewY]) &&
     47          SkScalarNearlyZero(matrix[SkMatrix::kMPersp0]) &&
     48          SkScalarNearlyZero(matrix[SkMatrix::kMPersp1]) &&
     49          SkScalarNearlyZero(matrix[SkMatrix::kMPersp2] - 1.0f);
     50 }
     51 
     52 static SkShader::TileMode WrapModeToTileMode(GLint wrap_mode) {
     53   switch (wrap_mode) {
     54     case GL_REPEAT:
     55       return SkShader::kRepeat_TileMode;
     56     case GL_CLAMP_TO_EDGE:
     57       return SkShader::kClamp_TileMode;
     58   }
     59   NOTREACHED();
     60   return SkShader::kClamp_TileMode;
     61 }
     62 
     63 }  // anonymous namespace
     64 
     65 scoped_ptr<SoftwareRenderer> SoftwareRenderer::Create(
     66     RendererClient* client,
     67     const LayerTreeSettings* settings,
     68     OutputSurface* output_surface,
     69     ResourceProvider* resource_provider) {
     70   return make_scoped_ptr(new SoftwareRenderer(
     71       client, settings, output_surface, resource_provider));
     72 }
     73 
     74 SoftwareRenderer::SoftwareRenderer(RendererClient* client,
     75                                    const LayerTreeSettings* settings,
     76                                    OutputSurface* output_surface,
     77                                    ResourceProvider* resource_provider)
     78     : DirectRenderer(client, settings, output_surface, resource_provider),
     79       visible_(true),
     80       is_scissor_enabled_(false),
     81       is_backbuffer_discarded_(false),
     82       output_device_(output_surface->software_device()),
     83       current_canvas_(NULL) {
     84   if (resource_provider_) {
     85     capabilities_.max_texture_size = resource_provider_->max_texture_size();
     86     capabilities_.best_texture_format =
     87         resource_provider_->best_texture_format();
     88   }
     89   // The updater can access bitmaps while the SoftwareRenderer is using them.
     90   capabilities_.allow_partial_texture_updates = true;
     91   capabilities_.using_partial_swap = true;
     92 
     93   capabilities_.using_map_image = settings_->use_map_image;
     94   capabilities_.using_shared_memory_resources = true;
     95 }
     96 
     97 SoftwareRenderer::~SoftwareRenderer() {}
     98 
     99 const RendererCapabilitiesImpl& SoftwareRenderer::Capabilities() const {
    100   return capabilities_;
    101 }
    102 
    103 void SoftwareRenderer::BeginDrawingFrame(DrawingFrame* frame) {
    104   TRACE_EVENT0("cc", "SoftwareRenderer::BeginDrawingFrame");
    105   root_canvas_ = output_device_->BeginPaint(
    106       gfx::ToEnclosingRect(frame->root_damage_rect));
    107 }
    108 
    109 void SoftwareRenderer::FinishDrawingFrame(DrawingFrame* frame) {
    110   TRACE_EVENT0("cc", "SoftwareRenderer::FinishDrawingFrame");
    111   current_framebuffer_lock_.reset();
    112   current_canvas_ = NULL;
    113   root_canvas_ = NULL;
    114 
    115   current_frame_data_.reset(new SoftwareFrameData);
    116   output_device_->EndPaint(current_frame_data_.get());
    117 }
    118 
    119 void SoftwareRenderer::SwapBuffers(const CompositorFrameMetadata& metadata) {
    120   CompositorFrame compositor_frame;
    121   compositor_frame.metadata = metadata;
    122   compositor_frame.software_frame_data = current_frame_data_.Pass();
    123   output_surface_->SwapBuffers(&compositor_frame);
    124 }
    125 
    126 void SoftwareRenderer::ReceiveSwapBuffersAck(const CompositorFrameAck& ack) {
    127   output_device_->ReclaimSoftwareFrame(ack.last_software_frame_id);
    128 }
    129 
    130 bool SoftwareRenderer::FlippedFramebuffer() const {
    131   return false;
    132 }
    133 
    134 void SoftwareRenderer::EnsureScissorTestEnabled() {
    135   is_scissor_enabled_ = true;
    136   SetClipRect(scissor_rect_);
    137 }
    138 
    139 void SoftwareRenderer::EnsureScissorTestDisabled() {
    140   // There is no explicit notion of enabling/disabling scissoring in software
    141   // rendering, but the underlying effect we want is to clear any existing
    142   // clipRect on the current SkCanvas. This is done by setting clipRect to
    143   // the viewport's dimensions.
    144   is_scissor_enabled_ = false;
    145   SkBaseDevice* device = current_canvas_->getDevice();
    146   SetClipRect(gfx::Rect(device->width(), device->height()));
    147 }
    148 
    149 void SoftwareRenderer::Finish() {}
    150 
    151 void SoftwareRenderer::BindFramebufferToOutputSurface(DrawingFrame* frame) {
    152   DCHECK(!output_surface_->HasExternalStencilTest());
    153   current_framebuffer_lock_.reset();
    154   current_canvas_ = root_canvas_;
    155 }
    156 
    157 bool SoftwareRenderer::BindFramebufferToTexture(
    158     DrawingFrame* frame,
    159     const ScopedResource* texture,
    160     gfx::Rect target_rect) {
    161   current_framebuffer_lock_.reset();
    162   current_framebuffer_lock_ = make_scoped_ptr(
    163       new ResourceProvider::ScopedWriteLockSoftware(
    164           resource_provider_, texture->id()));
    165   current_canvas_ = current_framebuffer_lock_->sk_canvas();
    166   InitializeViewport(frame,
    167                      target_rect,
    168                      gfx::Rect(target_rect.size()),
    169                      target_rect.size());
    170   return true;
    171 }
    172 
    173 void SoftwareRenderer::SetScissorTestRect(gfx::Rect scissor_rect) {
    174   is_scissor_enabled_ = true;
    175   scissor_rect_ = scissor_rect;
    176   SetClipRect(scissor_rect);
    177 }
    178 
    179 void SoftwareRenderer::SetClipRect(gfx::Rect rect) {
    180   // Skia applies the current matrix to clip rects so we reset it temporary.
    181   SkMatrix current_matrix = current_canvas_->getTotalMatrix();
    182   current_canvas_->resetMatrix();
    183   current_canvas_->clipRect(gfx::RectToSkRect(rect), SkRegion::kReplace_Op);
    184   current_canvas_->setMatrix(current_matrix);
    185 }
    186 
    187 void SoftwareRenderer::ClearCanvas(SkColor color) {
    188   // SkCanvas::clear doesn't respect the current clipping region
    189   // so we SkCanvas::drawColor instead if scissoring is active.
    190   if (is_scissor_enabled_)
    191     current_canvas_->drawColor(color, SkXfermode::kSrc_Mode);
    192   else
    193     current_canvas_->clear(color);
    194 }
    195 
    196 void SoftwareRenderer::DiscardPixels(bool has_external_stencil_test,
    197                                      bool draw_rect_covers_full_surface) {}
    198 
    199 void SoftwareRenderer::ClearFramebuffer(DrawingFrame* frame,
    200                                         bool has_external_stencil_test) {
    201   if (frame->current_render_pass->has_transparent_background) {
    202     ClearCanvas(SkColorSetARGB(0, 0, 0, 0));
    203   } else {
    204 #ifndef NDEBUG
    205     // On DEBUG builds, opaque render passes are cleared to blue
    206     // to easily see regions that were not drawn on the screen.
    207     ClearCanvas(SkColorSetARGB(255, 0, 0, 255));
    208 #endif
    209   }
    210 }
    211 
    212 void SoftwareRenderer::SetDrawViewport(gfx::Rect window_space_viewport) {}
    213 
    214 bool SoftwareRenderer::IsSoftwareResource(
    215     ResourceProvider::ResourceId resource_id) const {
    216   switch (resource_provider_->GetResourceType(resource_id)) {
    217     case ResourceProvider::GLTexture:
    218       return false;
    219     case ResourceProvider::Bitmap:
    220       return true;
    221     case ResourceProvider::InvalidType:
    222       break;
    223   }
    224 
    225   LOG(FATAL) << "Invalid resource type.";
    226   return false;
    227 }
    228 
    229 void SoftwareRenderer::DoDrawQuad(DrawingFrame* frame, const DrawQuad* quad) {
    230   TRACE_EVENT0("cc", "SoftwareRenderer::DoDrawQuad");
    231   gfx::Transform quad_rect_matrix;
    232   QuadRectTransform(&quad_rect_matrix, quad->quadTransform(), quad->rect);
    233   gfx::Transform contents_device_transform =
    234       frame->window_matrix * frame->projection_matrix * quad_rect_matrix;
    235   contents_device_transform.FlattenTo2d();
    236   SkMatrix sk_device_matrix;
    237   gfx::TransformToFlattenedSkMatrix(contents_device_transform,
    238                                     &sk_device_matrix);
    239   current_canvas_->setMatrix(sk_device_matrix);
    240 
    241   current_paint_.reset();
    242   if (!IsScaleAndIntegerTranslate(sk_device_matrix)) {
    243     // TODO(danakj): Until we can enable AA only on exterior edges of the
    244     // layer, disable AA if any interior edges are present. crbug.com/248175
    245     bool all_four_edges_are_exterior = quad->IsTopEdge() &&
    246                                        quad->IsLeftEdge() &&
    247                                        quad->IsBottomEdge() &&
    248                                        quad->IsRightEdge();
    249     if (settings_->allow_antialiasing && all_four_edges_are_exterior)
    250       current_paint_.setAntiAlias(true);
    251     current_paint_.setFilterBitmap(true);
    252   }
    253 
    254   if (quad->ShouldDrawWithBlending()) {
    255     current_paint_.setAlpha(quad->opacity() * 255);
    256     current_paint_.setXfermodeMode(SkXfermode::kSrcOver_Mode);
    257   } else {
    258     current_paint_.setXfermodeMode(SkXfermode::kSrc_Mode);
    259   }
    260 
    261   switch (quad->material) {
    262     case DrawQuad::CHECKERBOARD:
    263       DrawCheckerboardQuad(frame, CheckerboardDrawQuad::MaterialCast(quad));
    264       break;
    265     case DrawQuad::DEBUG_BORDER:
    266       DrawDebugBorderQuad(frame, DebugBorderDrawQuad::MaterialCast(quad));
    267       break;
    268     case DrawQuad::PICTURE_CONTENT:
    269       DrawPictureQuad(frame, PictureDrawQuad::MaterialCast(quad));
    270       break;
    271     case DrawQuad::RENDER_PASS:
    272       DrawRenderPassQuad(frame, RenderPassDrawQuad::MaterialCast(quad));
    273       break;
    274     case DrawQuad::SOLID_COLOR:
    275       DrawSolidColorQuad(frame, SolidColorDrawQuad::MaterialCast(quad));
    276       break;
    277     case DrawQuad::TEXTURE_CONTENT:
    278       DrawTextureQuad(frame, TextureDrawQuad::MaterialCast(quad));
    279       break;
    280     case DrawQuad::TILED_CONTENT:
    281       DrawTileQuad(frame, TileDrawQuad::MaterialCast(quad));
    282       break;
    283     case DrawQuad::INVALID:
    284     case DrawQuad::IO_SURFACE_CONTENT:
    285     case DrawQuad::YUV_VIDEO_CONTENT:
    286     case DrawQuad::STREAM_VIDEO_CONTENT:
    287       DrawUnsupportedQuad(frame, quad);
    288       NOTREACHED();
    289       break;
    290   }
    291 
    292   current_canvas_->resetMatrix();
    293 }
    294 
    295 void SoftwareRenderer::DrawCheckerboardQuad(const DrawingFrame* frame,
    296                                             const CheckerboardDrawQuad* quad) {
    297   gfx::RectF visible_quad_vertex_rect = MathUtil::ScaleRectProportional(
    298       QuadVertexRect(), quad->rect, quad->visible_rect);
    299   current_paint_.setColor(quad->color);
    300   current_paint_.setAlpha(quad->opacity() * SkColorGetA(quad->color));
    301   current_canvas_->drawRect(gfx::RectFToSkRect(visible_quad_vertex_rect),
    302                             current_paint_);
    303 }
    304 
    305 void SoftwareRenderer::DrawDebugBorderQuad(const DrawingFrame* frame,
    306                                            const DebugBorderDrawQuad* quad) {
    307   // We need to apply the matrix manually to have pixel-sized stroke width.
    308   SkPoint vertices[4];
    309   gfx::RectFToSkRect(QuadVertexRect()).toQuad(vertices);
    310   SkPoint transformed_vertices[4];
    311   current_canvas_->getTotalMatrix().mapPoints(transformed_vertices,
    312                                               vertices,
    313                                               4);
    314   current_canvas_->resetMatrix();
    315 
    316   current_paint_.setColor(quad->color);
    317   current_paint_.setAlpha(quad->opacity() * SkColorGetA(quad->color));
    318   current_paint_.setStyle(SkPaint::kStroke_Style);
    319   current_paint_.setStrokeWidth(quad->width);
    320   current_canvas_->drawPoints(SkCanvas::kPolygon_PointMode,
    321                               4, transformed_vertices, current_paint_);
    322 }
    323 
    324 void SoftwareRenderer::DrawPictureQuad(const DrawingFrame* frame,
    325                                        const PictureDrawQuad* quad) {
    326   SkMatrix content_matrix;
    327   content_matrix.setRectToRect(
    328       gfx::RectFToSkRect(quad->tex_coord_rect),
    329       gfx::RectFToSkRect(QuadVertexRect()),
    330       SkMatrix::kFill_ScaleToFit);
    331   current_canvas_->concat(content_matrix);
    332 
    333   // TODO(aelias): This isn't correct in all cases. We should detect these
    334   // cases and fall back to a persistent bitmap backing
    335   // (http://crbug.com/280374).
    336   skia::RefPtr<SkDrawFilter> opacity_filter =
    337       skia::AdoptRef(new skia::OpacityDrawFilter(
    338           quad->opacity(), frame->disable_picture_quad_image_filtering));
    339   DCHECK(!current_canvas_->getDrawFilter());
    340   current_canvas_->setDrawFilter(opacity_filter.get());
    341 
    342   TRACE_EVENT0("cc",
    343                "SoftwareRenderer::DrawPictureQuad");
    344   quad->picture_pile->RasterDirect(
    345       current_canvas_, quad->content_rect, quad->contents_scale, NULL);
    346 
    347   current_canvas_->setDrawFilter(NULL);
    348 }
    349 
    350 void SoftwareRenderer::DrawSolidColorQuad(const DrawingFrame* frame,
    351                                           const SolidColorDrawQuad* quad) {
    352   gfx::RectF visible_quad_vertex_rect = MathUtil::ScaleRectProportional(
    353       QuadVertexRect(), quad->rect, quad->visible_rect);
    354   current_paint_.setColor(quad->color);
    355   current_paint_.setAlpha(quad->opacity() * SkColorGetA(quad->color));
    356   current_canvas_->drawRect(gfx::RectFToSkRect(visible_quad_vertex_rect),
    357                             current_paint_);
    358 }
    359 
    360 void SoftwareRenderer::DrawTextureQuad(const DrawingFrame* frame,
    361                                        const TextureDrawQuad* quad) {
    362   if (!IsSoftwareResource(quad->resource_id)) {
    363     DrawUnsupportedQuad(frame, quad);
    364     return;
    365   }
    366 
    367   // TODO(skaslev): Add support for non-premultiplied alpha.
    368   ResourceProvider::ScopedReadLockSoftware lock(resource_provider_,
    369                                                 quad->resource_id);
    370   const SkBitmap* bitmap = lock.sk_bitmap();
    371   gfx::RectF uv_rect = gfx::ScaleRect(gfx::BoundingRect(quad->uv_top_left,
    372                                                         quad->uv_bottom_right),
    373                                       bitmap->width(),
    374                                       bitmap->height());
    375   gfx::RectF visible_uv_rect =
    376       MathUtil::ScaleRectProportional(uv_rect, quad->rect, quad->visible_rect);
    377   SkRect sk_uv_rect = gfx::RectFToSkRect(visible_uv_rect);
    378   gfx::RectF visible_quad_vertex_rect = MathUtil::ScaleRectProportional(
    379       QuadVertexRect(), quad->rect, quad->visible_rect);
    380   SkRect quad_rect = gfx::RectFToSkRect(visible_quad_vertex_rect);
    381 
    382   if (quad->flipped)
    383     current_canvas_->scale(1, -1);
    384 
    385   bool blend_background = quad->background_color != SK_ColorTRANSPARENT &&
    386                           !bitmap->isOpaque();
    387   bool needs_layer = blend_background && (current_paint_.getAlpha() != 0xFF);
    388   if (needs_layer) {
    389     current_canvas_->saveLayerAlpha(&quad_rect, current_paint_.getAlpha());
    390     current_paint_.setAlpha(0xFF);
    391   }
    392   if (blend_background) {
    393     SkPaint background_paint;
    394     background_paint.setColor(quad->background_color);
    395     current_canvas_->drawRect(quad_rect, background_paint);
    396   }
    397   SkShader::TileMode tile_mode = WrapModeToTileMode(lock.wrap_mode());
    398   if (tile_mode != SkShader::kClamp_TileMode) {
    399     SkMatrix matrix;
    400     matrix.setRectToRect(sk_uv_rect, quad_rect, SkMatrix::kFill_ScaleToFit);
    401     skia::RefPtr<SkShader> shader = skia::AdoptRef(
    402         SkShader::CreateBitmapShader(*bitmap, tile_mode, tile_mode));
    403     shader->setLocalMatrix(matrix);
    404     SkPaint paint;
    405     paint.setStyle(SkPaint::kFill_Style);
    406     paint.setShader(shader.get());
    407     current_canvas_->drawRect(quad_rect, paint);
    408   } else {
    409     current_canvas_->drawBitmapRectToRect(*bitmap,
    410                                           &sk_uv_rect,
    411                                           quad_rect,
    412                                           &current_paint_);
    413   }
    414 
    415   if (needs_layer)
    416     current_canvas_->restore();
    417 }
    418 
    419 void SoftwareRenderer::DrawTileQuad(const DrawingFrame* frame,
    420                                     const TileDrawQuad* quad) {
    421   DCHECK(!output_surface_->ForcedDrawToSoftwareDevice());
    422   DCHECK(IsSoftwareResource(quad->resource_id));
    423 
    424   ResourceProvider::ScopedReadLockSoftware lock(resource_provider_,
    425                                                 quad->resource_id);
    426   DCHECK_EQ(GL_CLAMP_TO_EDGE, lock.wrap_mode());
    427 
    428   gfx::RectF visible_tex_coord_rect = MathUtil::ScaleRectProportional(
    429       quad->tex_coord_rect, quad->rect, quad->visible_rect);
    430   gfx::RectF visible_quad_vertex_rect = MathUtil::ScaleRectProportional(
    431       QuadVertexRect(), quad->rect, quad->visible_rect);
    432 
    433   SkRect uv_rect = gfx::RectFToSkRect(visible_tex_coord_rect);
    434   current_paint_.setFilterBitmap(true);
    435   current_canvas_->drawBitmapRectToRect(
    436       *lock.sk_bitmap(),
    437       &uv_rect,
    438       gfx::RectFToSkRect(visible_quad_vertex_rect),
    439       &current_paint_);
    440 }
    441 
    442 void SoftwareRenderer::DrawRenderPassQuad(const DrawingFrame* frame,
    443                                           const RenderPassDrawQuad* quad) {
    444   ScopedResource* content_texture =
    445       render_pass_textures_.get(quad->render_pass_id);
    446   if (!content_texture || !content_texture->id())
    447     return;
    448 
    449   DCHECK(IsSoftwareResource(content_texture->id()));
    450   ResourceProvider::ScopedReadLockSoftware lock(resource_provider_,
    451                                                 content_texture->id());
    452   SkShader::TileMode content_tile_mode = WrapModeToTileMode(lock.wrap_mode());
    453 
    454   SkRect dest_rect = gfx::RectFToSkRect(QuadVertexRect());
    455   SkRect dest_visible_rect = gfx::RectFToSkRect(MathUtil::ScaleRectProportional(
    456       QuadVertexRect(), quad->rect, quad->visible_rect));
    457   SkRect content_rect = SkRect::MakeWH(quad->rect.width(), quad->rect.height());
    458 
    459   SkMatrix content_mat;
    460   content_mat.setRectToRect(content_rect, dest_rect,
    461                             SkMatrix::kFill_ScaleToFit);
    462 
    463   const SkBitmap* content = lock.sk_bitmap();
    464 
    465   SkBitmap filter_bitmap;
    466   if (!quad->filters.IsEmpty()) {
    467     skia::RefPtr<SkImageFilter> filter = RenderSurfaceFilters::BuildImageFilter(
    468         quad->filters, content_texture->size());
    469     // TODO(ajuma): In addition origin translation, the canvas should also be
    470     // scaled to accomodate device pixel ratio and pinch zoom. See
    471     // crbug.com/281516 and crbug.com/281518.
    472     // TODO(ajuma): Apply the filter in the same pass as the content where
    473     // possible (e.g. when there's no origin offset). See crbug.com/308201.
    474     if (filter) {
    475       bool is_opaque = false;
    476       skia::RefPtr<SkBaseDevice> device =
    477           skia::AdoptRef(new SkBitmapDevice(SkBitmap::kARGB_8888_Config,
    478                                             content_texture->size().width(),
    479                                             content_texture->size().height(),
    480                                             is_opaque));
    481       SkCanvas canvas(device.get());
    482       SkPaint paint;
    483       paint.setImageFilter(filter.get());
    484       canvas.clear(SK_ColorTRANSPARENT);
    485       canvas.translate(SkIntToScalar(-quad->rect.origin().x()),
    486                        SkIntToScalar(-quad->rect.origin().y()));
    487       canvas.drawSprite(*content, 0, 0, &paint);
    488       bool will_change_pixels = false;
    489       filter_bitmap = device->accessBitmap(will_change_pixels);
    490     }
    491   }
    492 
    493   skia::RefPtr<SkShader> shader;
    494   if (filter_bitmap.isNull()) {
    495     shader = skia::AdoptRef(SkShader::CreateBitmapShader(
    496         *content, content_tile_mode, content_tile_mode));
    497   } else {
    498     shader = skia::AdoptRef(SkShader::CreateBitmapShader(
    499         filter_bitmap, content_tile_mode, content_tile_mode));
    500   }
    501   shader->setLocalMatrix(content_mat);
    502   current_paint_.setShader(shader.get());
    503 
    504   if (quad->mask_resource_id) {
    505     ResourceProvider::ScopedReadLockSoftware mask_lock(resource_provider_,
    506                                                        quad->mask_resource_id);
    507     SkShader::TileMode mask_tile_mode = WrapModeToTileMode(
    508         mask_lock.wrap_mode());
    509 
    510     const SkBitmap* mask = mask_lock.sk_bitmap();
    511 
    512     SkRect mask_rect = SkRect::MakeXYWH(
    513         quad->mask_uv_rect.x() * mask->width(),
    514         quad->mask_uv_rect.y() * mask->height(),
    515         quad->mask_uv_rect.width() * mask->width(),
    516         quad->mask_uv_rect.height() * mask->height());
    517 
    518     SkMatrix mask_mat;
    519     mask_mat.setRectToRect(mask_rect, dest_rect, SkMatrix::kFill_ScaleToFit);
    520 
    521     skia::RefPtr<SkShader> mask_shader = skia::AdoptRef(
    522         SkShader::CreateBitmapShader(*mask, mask_tile_mode, mask_tile_mode));
    523     mask_shader->setLocalMatrix(mask_mat);
    524 
    525     SkPaint mask_paint;
    526     mask_paint.setShader(mask_shader.get());
    527 
    528     skia::RefPtr<SkLayerRasterizer> mask_rasterizer =
    529         skia::AdoptRef(new SkLayerRasterizer);
    530     mask_rasterizer->addLayer(mask_paint);
    531 
    532     current_paint_.setRasterizer(mask_rasterizer.get());
    533     current_canvas_->drawRect(dest_visible_rect, current_paint_);
    534   } else {
    535     // TODO(skaslev): Apply background filters and blend with content
    536     current_canvas_->drawRect(dest_visible_rect, current_paint_);
    537   }
    538 }
    539 
    540 void SoftwareRenderer::DrawUnsupportedQuad(const DrawingFrame* frame,
    541                                            const DrawQuad* quad) {
    542 #ifdef NDEBUG
    543   current_paint_.setColor(SK_ColorWHITE);
    544 #else
    545   current_paint_.setColor(SK_ColorMAGENTA);
    546 #endif
    547   current_paint_.setAlpha(quad->opacity() * 255);
    548   current_canvas_->drawRect(gfx::RectFToSkRect(QuadVertexRect()),
    549                             current_paint_);
    550 }
    551 
    552 void SoftwareRenderer::CopyCurrentRenderPassToBitmap(
    553     DrawingFrame* frame,
    554     scoped_ptr<CopyOutputRequest> request) {
    555   gfx::Rect copy_rect = frame->current_render_pass->output_rect;
    556   if (request->has_area())
    557     copy_rect.Intersect(request->area());
    558   gfx::Rect window_copy_rect = MoveFromDrawToWindowSpace(copy_rect);
    559 
    560   scoped_ptr<SkBitmap> bitmap(new SkBitmap);
    561   bitmap->setConfig(SkBitmap::kARGB_8888_Config,
    562                     window_copy_rect.width(),
    563                     window_copy_rect.height());
    564   current_canvas_->readPixels(
    565       bitmap.get(), window_copy_rect.x(), window_copy_rect.y());
    566 
    567   request->SendBitmapResult(bitmap.Pass());
    568 }
    569 
    570 void SoftwareRenderer::DiscardBackbuffer() {
    571   if (is_backbuffer_discarded_)
    572     return;
    573 
    574   output_surface_->DiscardBackbuffer();
    575 
    576   is_backbuffer_discarded_ = true;
    577 
    578   // Damage tracker needs a full reset every time framebuffer is discarded.
    579   client_->SetFullRootLayerDamage();
    580 }
    581 
    582 void SoftwareRenderer::EnsureBackbuffer() {
    583   if (!is_backbuffer_discarded_)
    584     return;
    585 
    586   output_surface_->EnsureBackbuffer();
    587   is_backbuffer_discarded_ = false;
    588 }
    589 
    590 void SoftwareRenderer::GetFramebufferPixels(void* pixels, gfx::Rect rect) {
    591   TRACE_EVENT0("cc", "SoftwareRenderer::GetFramebufferPixels");
    592   SkBitmap subset_bitmap;
    593   rect += current_viewport_rect_.OffsetFromOrigin();
    594   output_device_->CopyToBitmap(rect, &subset_bitmap);
    595   subset_bitmap.copyPixelsTo(pixels,
    596                              4 * rect.width() * rect.height(),
    597                              4 * rect.width());
    598 }
    599 
    600 void SoftwareRenderer::SetVisible(bool visible) {
    601   if (visible_ == visible)
    602     return;
    603   visible_ = visible;
    604 
    605   if (visible_)
    606     EnsureBackbuffer();
    607   else
    608     DiscardBackbuffer();
    609 }
    610 
    611 }  // namespace cc
    612