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