Home | History | Annotate | Download | only in ext
      1 // Copyright 2013 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 "skia/ext/lazy_pixel_ref_utils.h"
      6 
      7 #include <algorithm>
      8 
      9 #include "skia/ext/lazy_pixel_ref.h"
     10 #include "third_party/skia/include/core/SkBitmapDevice.h"
     11 #include "third_party/skia/include/core/SkCanvas.h"
     12 #include "third_party/skia/include/core/SkData.h"
     13 #include "third_party/skia/include/core/SkDraw.h"
     14 #include "third_party/skia/include/core/SkPixelRef.h"
     15 #include "third_party/skia/include/core/SkRRect.h"
     16 #include "third_party/skia/include/core/SkRect.h"
     17 #include "third_party/skia/include/core/SkShader.h"
     18 #include "third_party/skia/src/core/SkRasterClip.h"
     19 
     20 namespace skia {
     21 
     22 namespace {
     23 
     24 // URI label for a lazily decoded SkPixelRef.
     25 const char kLabelLazyDecoded[] = "lazy";
     26 
     27 class LazyPixelRefSet {
     28  public:
     29   LazyPixelRefSet(
     30       std::vector<LazyPixelRefUtils::PositionLazyPixelRef>* pixel_refs)
     31       : pixel_refs_(pixel_refs) {}
     32 
     33   void Add(SkPixelRef* pixel_ref, const SkRect& rect) {
     34     // Only save lazy pixel refs.
     35     if (pixel_ref->getURI() &&
     36         !strcmp(pixel_ref->getURI(), kLabelLazyDecoded)) {
     37       LazyPixelRefUtils::PositionLazyPixelRef position_pixel_ref;
     38       position_pixel_ref.lazy_pixel_ref =
     39           static_cast<skia::LazyPixelRef*>(pixel_ref);
     40       position_pixel_ref.pixel_ref_rect = rect;
     41       pixel_refs_->push_back(position_pixel_ref);
     42     }
     43   }
     44 
     45  private:
     46   std::vector<LazyPixelRefUtils::PositionLazyPixelRef>* pixel_refs_;
     47 };
     48 
     49 class GatherPixelRefDevice : public SkBitmapDevice {
     50  public:
     51   GatherPixelRefDevice(const SkBitmap& bm, LazyPixelRefSet* lazy_pixel_ref_set)
     52       : SkBitmapDevice(bm), lazy_pixel_ref_set_(lazy_pixel_ref_set) {}
     53 
     54   virtual void clear(SkColor color) SK_OVERRIDE {}
     55   virtual void writePixels(const SkBitmap& bitmap,
     56                            int x,
     57                            int y,
     58                            SkCanvas::Config8888 config8888) SK_OVERRIDE {}
     59 
     60   virtual void drawPaint(const SkDraw& draw, const SkPaint& paint) SK_OVERRIDE {
     61     SkBitmap bitmap;
     62     if (GetBitmapFromPaint(paint, &bitmap)) {
     63       SkRect clip_rect = SkRect::Make(draw.fRC->getBounds());
     64       AddBitmap(bitmap, clip_rect);
     65     }
     66   }
     67 
     68   virtual void drawPoints(const SkDraw& draw,
     69                           SkCanvas::PointMode mode,
     70                           size_t count,
     71                           const SkPoint points[],
     72                           const SkPaint& paint) SK_OVERRIDE {
     73     SkBitmap bitmap;
     74     if (!GetBitmapFromPaint(paint, &bitmap))
     75       return;
     76 
     77     if (count == 0)
     78       return;
     79 
     80     SkPoint min_point = points[0];
     81     SkPoint max_point = points[0];
     82     for (size_t i = 1; i < count; ++i) {
     83       const SkPoint& point = points[i];
     84       min_point.set(std::min(min_point.x(), point.x()),
     85                     std::min(min_point.y(), point.y()));
     86       max_point.set(std::max(max_point.x(), point.x()),
     87                     std::max(max_point.y(), point.y()));
     88     }
     89 
     90     SkRect bounds = SkRect::MakeLTRB(
     91         min_point.x(), min_point.y(), max_point.x(), max_point.y());
     92 
     93     GatherPixelRefDevice::drawRect(draw, bounds, paint);
     94   }
     95   virtual void drawRect(const SkDraw& draw,
     96                         const SkRect& rect,
     97                         const SkPaint& paint) SK_OVERRIDE {
     98     SkBitmap bitmap;
     99     if (GetBitmapFromPaint(paint, &bitmap)) {
    100       SkRect mapped_rect;
    101       draw.fMatrix->mapRect(&mapped_rect, rect);
    102       mapped_rect.intersect(SkRect::Make(draw.fRC->getBounds()));
    103       AddBitmap(bitmap, mapped_rect);
    104     }
    105   }
    106   virtual void drawOval(const SkDraw& draw,
    107                         const SkRect& rect,
    108                         const SkPaint& paint) SK_OVERRIDE {
    109     GatherPixelRefDevice::drawRect(draw, rect, paint);
    110   }
    111   virtual void drawRRect(const SkDraw& draw,
    112                          const SkRRect& rect,
    113                          const SkPaint& paint) SK_OVERRIDE {
    114     GatherPixelRefDevice::drawRect(draw, rect.rect(), paint);
    115   }
    116   virtual void drawPath(const SkDraw& draw,
    117                         const SkPath& path,
    118                         const SkPaint& paint,
    119                         const SkMatrix* pre_path_matrix,
    120                         bool path_is_mutable) SK_OVERRIDE {
    121     SkBitmap bitmap;
    122     if (!GetBitmapFromPaint(paint, &bitmap))
    123       return;
    124 
    125     SkRect path_bounds = path.getBounds();
    126     SkRect final_rect;
    127     if (pre_path_matrix != NULL)
    128       pre_path_matrix->mapRect(&final_rect, path_bounds);
    129     else
    130       final_rect = path_bounds;
    131 
    132     GatherPixelRefDevice::drawRect(draw, final_rect, paint);
    133   }
    134   virtual void drawBitmap(const SkDraw& draw,
    135                           const SkBitmap& bitmap,
    136                           const SkMatrix& matrix,
    137                           const SkPaint& paint) SK_OVERRIDE {
    138     SkMatrix total_matrix;
    139     total_matrix.setConcat(*draw.fMatrix, matrix);
    140 
    141     SkRect bitmap_rect = SkRect::MakeWH(bitmap.width(), bitmap.height());
    142     SkRect mapped_rect;
    143     total_matrix.mapRect(&mapped_rect, bitmap_rect);
    144     AddBitmap(bitmap, mapped_rect);
    145 
    146     SkBitmap paint_bitmap;
    147     if (GetBitmapFromPaint(paint, &paint_bitmap))
    148       AddBitmap(paint_bitmap, mapped_rect);
    149   }
    150   virtual void drawBitmapRect(const SkDraw& draw,
    151                               const SkBitmap& bitmap,
    152                               const SkRect* src_or_null,
    153                               const SkRect& dst,
    154                               const SkPaint& paint,
    155                               SkCanvas::DrawBitmapRectFlags flags) SK_OVERRIDE {
    156     SkRect bitmap_rect = SkRect::MakeWH(bitmap.width(), bitmap.height());
    157     SkMatrix matrix;
    158     matrix.setRectToRect(bitmap_rect, dst, SkMatrix::kFill_ScaleToFit);
    159     GatherPixelRefDevice::drawBitmap(draw, bitmap, matrix, paint);
    160   }
    161   virtual void drawSprite(const SkDraw& draw,
    162                           const SkBitmap& bitmap,
    163                           int x,
    164                           int y,
    165                           const SkPaint& paint) SK_OVERRIDE {
    166     // Sprites aren't affected by current matrix, so we can't reuse drawRect.
    167     SkMatrix matrix;
    168     matrix.setTranslate(x, y);
    169 
    170     SkRect bitmap_rect = SkRect::MakeWH(bitmap.width(), bitmap.height());
    171     SkRect mapped_rect;
    172     matrix.mapRect(&mapped_rect, bitmap_rect);
    173 
    174     AddBitmap(bitmap, mapped_rect);
    175     SkBitmap paint_bitmap;
    176     if (GetBitmapFromPaint(paint, &paint_bitmap))
    177       AddBitmap(paint_bitmap, mapped_rect);
    178   }
    179   virtual void drawText(const SkDraw& draw,
    180                         const void* text,
    181                         size_t len,
    182                         SkScalar x,
    183                         SkScalar y,
    184                         const SkPaint& paint) SK_OVERRIDE {
    185     SkBitmap bitmap;
    186     if (!GetBitmapFromPaint(paint, &bitmap))
    187       return;
    188 
    189     // Math is borrowed from SkBBoxRecord
    190     SkRect bounds;
    191     paint.measureText(text, len, &bounds);
    192     SkPaint::FontMetrics metrics;
    193     paint.getFontMetrics(&metrics);
    194 
    195     if (paint.isVerticalText()) {
    196       SkScalar h = bounds.fBottom - bounds.fTop;
    197       if (paint.getTextAlign() == SkPaint::kCenter_Align) {
    198         bounds.fTop -= h / 2;
    199         bounds.fBottom -= h / 2;
    200       }
    201       bounds.fBottom += metrics.fBottom;
    202       bounds.fTop += metrics.fTop;
    203     } else {
    204       SkScalar w = bounds.fRight - bounds.fLeft;
    205       if (paint.getTextAlign() == SkPaint::kCenter_Align) {
    206         bounds.fLeft -= w / 2;
    207         bounds.fRight -= w / 2;
    208       } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
    209         bounds.fLeft -= w;
    210         bounds.fRight -= w;
    211       }
    212       bounds.fTop = metrics.fTop;
    213       bounds.fBottom = metrics.fBottom;
    214     }
    215 
    216     SkScalar pad = (metrics.fBottom - metrics.fTop) / 2;
    217     bounds.fLeft -= pad;
    218     bounds.fRight += pad;
    219     bounds.fLeft += x;
    220     bounds.fRight += x;
    221     bounds.fTop += y;
    222     bounds.fBottom += y;
    223 
    224     GatherPixelRefDevice::drawRect(draw, bounds, paint);
    225   }
    226   virtual void drawPosText(const SkDraw& draw,
    227                            const void* text,
    228                            size_t len,
    229                            const SkScalar pos[],
    230                            SkScalar const_y,
    231                            int scalars_per_pos,
    232                            const SkPaint& paint) SK_OVERRIDE {
    233     SkBitmap bitmap;
    234     if (!GetBitmapFromPaint(paint, &bitmap))
    235       return;
    236 
    237     if (len == 0)
    238       return;
    239 
    240     // Similar to SkDraw asserts.
    241     SkASSERT(scalars_per_pos == 1 || scalars_per_pos == 2);
    242 
    243     SkPoint min_point;
    244     SkPoint max_point;
    245     if (scalars_per_pos == 1) {
    246       min_point.set(pos[0], const_y);
    247       max_point.set(pos[0], const_y);
    248     } else if (scalars_per_pos == 2) {
    249       min_point.set(pos[0], const_y + pos[1]);
    250       max_point.set(pos[0], const_y + pos[1]);
    251     }
    252 
    253     for (size_t i = 0; i < len; ++i) {
    254       SkScalar x = pos[i * scalars_per_pos];
    255       SkScalar y = const_y;
    256       if (scalars_per_pos == 2)
    257         y += pos[i * scalars_per_pos + 1];
    258 
    259       min_point.set(std::min(x, min_point.x()), std::min(y, min_point.y()));
    260       max_point.set(std::max(x, max_point.x()), std::max(y, max_point.y()));
    261     }
    262 
    263     SkRect bounds = SkRect::MakeLTRB(
    264         min_point.x(), min_point.y(), max_point.x(), max_point.y());
    265 
    266     // Math is borrowed from SkBBoxRecord
    267     SkPaint::FontMetrics metrics;
    268     paint.getFontMetrics(&metrics);
    269 
    270     bounds.fTop += metrics.fTop;
    271     bounds.fBottom += metrics.fBottom;
    272 
    273     SkScalar pad = (metrics.fTop - metrics.fBottom) / 2;
    274     bounds.fLeft += pad;
    275     bounds.fRight -= pad;
    276 
    277     GatherPixelRefDevice::drawRect(draw, bounds, paint);
    278   }
    279   virtual void drawTextOnPath(const SkDraw& draw,
    280                               const void* text,
    281                               size_t len,
    282                               const SkPath& path,
    283                               const SkMatrix* matrix,
    284                               const SkPaint& paint) SK_OVERRIDE {
    285     SkBitmap bitmap;
    286     if (!GetBitmapFromPaint(paint, &bitmap))
    287       return;
    288 
    289     // Math is borrowed from SkBBoxRecord
    290     SkRect bounds = path.getBounds();
    291     SkPaint::FontMetrics metrics;
    292     paint.getFontMetrics(&metrics);
    293 
    294     SkScalar pad = metrics.fTop;
    295     bounds.fLeft += pad;
    296     bounds.fRight -= pad;
    297     bounds.fTop += pad;
    298     bounds.fBottom -= pad;
    299 
    300     GatherPixelRefDevice::drawRect(draw, bounds, paint);
    301   }
    302   virtual void drawVertices(const SkDraw& draw,
    303                             SkCanvas::VertexMode,
    304                             int vertex_count,
    305                             const SkPoint verts[],
    306                             const SkPoint texs[],
    307                             const SkColor colors[],
    308                             SkXfermode* xmode,
    309                             const uint16_t indices[],
    310                             int index_count,
    311                             const SkPaint& paint) SK_OVERRIDE {
    312     GatherPixelRefDevice::drawPoints(
    313         draw, SkCanvas::kPolygon_PointMode, vertex_count, verts, paint);
    314   }
    315   virtual void drawDevice(const SkDraw&,
    316                           SkBaseDevice*,
    317                           int x,
    318                           int y,
    319                           const SkPaint&) SK_OVERRIDE {}
    320 
    321  protected:
    322   virtual bool onReadPixels(const SkBitmap& bitmap,
    323                             int x,
    324                             int y,
    325                             SkCanvas::Config8888 config8888) SK_OVERRIDE {
    326     return false;
    327   }
    328 
    329  private:
    330   LazyPixelRefSet* lazy_pixel_ref_set_;
    331 
    332   void AddBitmap(const SkBitmap& bm, const SkRect& rect) {
    333     SkRect canvas_rect = SkRect::MakeWH(width(), height());
    334     SkRect paint_rect = SkRect::MakeEmpty();
    335     paint_rect.intersect(rect, canvas_rect);
    336     lazy_pixel_ref_set_->Add(bm.pixelRef(), paint_rect);
    337   }
    338 
    339   bool GetBitmapFromPaint(const SkPaint& paint, SkBitmap* bm) {
    340     SkShader* shader = paint.getShader();
    341     if (shader) {
    342       // Check whether the shader is a gradient in order to prevent generation
    343       // of bitmaps from gradient shaders, which implement asABitmap.
    344       if (SkShader::kNone_GradientType == shader->asAGradient(NULL))
    345         return shader->asABitmap(bm, NULL, NULL);
    346     }
    347     return false;
    348   }
    349 };
    350 
    351 class NoSaveLayerCanvas : public SkCanvas {
    352  public:
    353   NoSaveLayerCanvas(SkBaseDevice* device) : INHERITED(device) {}
    354 
    355   // Turn saveLayer() into save() for speed, should not affect correctness.
    356   virtual int saveLayer(const SkRect* bounds,
    357                         const SkPaint* paint,
    358                         SaveFlags flags) SK_OVERRIDE {
    359 
    360     // Like SkPictureRecord, we don't want to create layers, but we do need
    361     // to respect the save and (possibly) its rect-clip.
    362     int count = this->INHERITED::save(flags);
    363     if (bounds) {
    364       this->INHERITED::clipRectBounds(bounds, flags, NULL);
    365     }
    366     return count;
    367   }
    368 
    369   // Disable aa for speed.
    370   virtual bool clipRect(const SkRect& rect, SkRegion::Op op, bool doAA)
    371       SK_OVERRIDE {
    372     return this->INHERITED::clipRect(rect, op, false);
    373   }
    374 
    375   virtual bool clipPath(const SkPath& path, SkRegion::Op op, bool doAA)
    376       SK_OVERRIDE {
    377     return this->updateClipConservativelyUsingBounds(
    378         path.getBounds(), op, path.isInverseFillType());
    379   }
    380   virtual bool clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA)
    381       SK_OVERRIDE {
    382     return this->updateClipConservativelyUsingBounds(
    383         rrect.getBounds(), op, false);
    384   }
    385 
    386  private:
    387   typedef SkCanvas INHERITED;
    388 };
    389 
    390 }  // namespace
    391 
    392 void LazyPixelRefUtils::GatherPixelRefs(
    393     SkPicture* picture,
    394     std::vector<PositionLazyPixelRef>* lazy_pixel_refs) {
    395   lazy_pixel_refs->clear();
    396   LazyPixelRefSet pixel_ref_set(lazy_pixel_refs);
    397 
    398   SkBitmap empty_bitmap;
    399   empty_bitmap.setConfig(
    400       SkBitmap::kNo_Config, picture->width(), picture->height());
    401 
    402   GatherPixelRefDevice device(empty_bitmap, &pixel_ref_set);
    403   NoSaveLayerCanvas canvas(&device);
    404 
    405   canvas.clipRect(SkRect::MakeWH(picture->width(), picture->height()),
    406                   SkRegion::kIntersect_Op,
    407                   false);
    408   canvas.drawPicture(*picture);
    409 }
    410 
    411 }  // namespace skia
    412