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 18namespace skia { 19 20namespace { 21 22// URI label for a lazily decoded SkPixelRef. 23const char kLabelLazyDecoded[] = "lazy"; 24 25class 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 47class 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 349class 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 390void 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