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