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