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 20namespace skia { 21 22namespace { 23 24// URI label for a lazily decoded SkPixelRef. 25const char kLabelLazyDecoded[] = "lazy"; 26 27class 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 49class 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 351class 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 392void 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