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