|
1 /* |
|
2 * Copyright 2013 Google Inc. |
|
3 * |
|
4 * Use of this source code is governed by a BSD-style license that can be |
|
5 * found in the LICENSE file. |
|
6 */ |
|
7 |
|
8 #include "SkBitmapDevice.h" |
|
9 #include "SkConfig8888.h" |
|
10 #include "SkDraw.h" |
|
11 #include "SkRasterClip.h" |
|
12 #include "SkShader.h" |
|
13 #include "SkSurface.h" |
|
14 |
|
15 #define CHECK_FOR_ANNOTATION(paint) \ |
|
16 do { if (paint.getAnnotation()) { return; } } while (0) |
|
17 |
|
18 static bool valid_for_bitmap_device(const SkImageInfo& info, |
|
19 SkAlphaType* newAlphaType) { |
|
20 if (info.width() < 0 || info.height() < 0) { |
|
21 return false; |
|
22 } |
|
23 |
|
24 // TODO: can we stop supporting kUnknown in SkBitmkapDevice? |
|
25 if (kUnknown_SkColorType == info.colorType()) { |
|
26 if (newAlphaType) { |
|
27 *newAlphaType = kIgnore_SkAlphaType; |
|
28 } |
|
29 return true; |
|
30 } |
|
31 |
|
32 switch (info.alphaType()) { |
|
33 case kPremul_SkAlphaType: |
|
34 case kOpaque_SkAlphaType: |
|
35 break; |
|
36 default: |
|
37 return false; |
|
38 } |
|
39 |
|
40 SkAlphaType canonicalAlphaType = info.alphaType(); |
|
41 |
|
42 switch (info.colorType()) { |
|
43 case kAlpha_8_SkColorType: |
|
44 break; |
|
45 case kRGB_565_SkColorType: |
|
46 canonicalAlphaType = kOpaque_SkAlphaType; |
|
47 break; |
|
48 case kPMColor_SkColorType: |
|
49 break; |
|
50 default: |
|
51 return false; |
|
52 } |
|
53 |
|
54 if (newAlphaType) { |
|
55 *newAlphaType = canonicalAlphaType; |
|
56 } |
|
57 return true; |
|
58 } |
|
59 |
|
60 SkBitmapDevice::SkBitmapDevice(const SkBitmap& bitmap) : fBitmap(bitmap) { |
|
61 SkASSERT(valid_for_bitmap_device(bitmap.info(), NULL)); |
|
62 } |
|
63 |
|
64 SkBitmapDevice::SkBitmapDevice(const SkBitmap& bitmap, const SkDeviceProperties& deviceProperties) |
|
65 : SkBaseDevice(deviceProperties) |
|
66 , fBitmap(bitmap) |
|
67 { |
|
68 SkASSERT(valid_for_bitmap_device(bitmap.info(), NULL)); |
|
69 } |
|
70 |
|
71 #ifdef SK_SUPPORT_LEGACY_COMPATIBLEDEVICE_CONFIG |
|
72 void SkBitmapDevice::init(SkBitmap::Config config, int width, int height, bool isOpaque) { |
|
73 fBitmap.setConfig(config, width, height, 0, isOpaque ? |
|
74 kOpaque_SkAlphaType : kPremul_SkAlphaType); |
|
75 |
|
76 if (SkBitmap::kNo_Config != config) { |
|
77 if (!fBitmap.allocPixels()) { |
|
78 // indicate failure by zeroing our bitmap |
|
79 fBitmap.setConfig(config, 0, 0, 0, isOpaque ? |
|
80 kOpaque_SkAlphaType : kPremul_SkAlphaType); |
|
81 } else if (!isOpaque) { |
|
82 fBitmap.eraseColor(SK_ColorTRANSPARENT); |
|
83 } |
|
84 } |
|
85 } |
|
86 |
|
87 SkBitmapDevice::SkBitmapDevice(SkBitmap::Config config, int width, int height, bool isOpaque) { |
|
88 this->init(config, width, height, isOpaque); |
|
89 } |
|
90 |
|
91 SkBitmapDevice::SkBitmapDevice(SkBitmap::Config config, int width, int height, bool isOpaque, |
|
92 const SkDeviceProperties& deviceProperties) |
|
93 : SkBaseDevice(deviceProperties) |
|
94 { |
|
95 this->init(config, width, height, isOpaque); |
|
96 } |
|
97 #endif |
|
98 SkBitmapDevice* SkBitmapDevice::Create(const SkImageInfo& origInfo, |
|
99 const SkDeviceProperties* props) { |
|
100 SkImageInfo info = origInfo; |
|
101 if (!valid_for_bitmap_device(info, &info.fAlphaType)) { |
|
102 return NULL; |
|
103 } |
|
104 |
|
105 SkBitmap bitmap; |
|
106 |
|
107 if (kUnknown_SkColorType == info.colorType()) { |
|
108 if (!bitmap.setConfig(info)) { |
|
109 return NULL; |
|
110 } |
|
111 } else { |
|
112 if (!bitmap.allocPixels(info)) { |
|
113 return NULL; |
|
114 } |
|
115 if (!bitmap.info().isOpaque()) { |
|
116 bitmap.eraseColor(SK_ColorTRANSPARENT); |
|
117 } |
|
118 } |
|
119 |
|
120 if (props) { |
|
121 return SkNEW_ARGS(SkBitmapDevice, (bitmap, *props)); |
|
122 } else { |
|
123 return SkNEW_ARGS(SkBitmapDevice, (bitmap)); |
|
124 } |
|
125 } |
|
126 |
|
127 SkImageInfo SkBitmapDevice::imageInfo() const { |
|
128 return fBitmap.info(); |
|
129 } |
|
130 |
|
131 void SkBitmapDevice::replaceBitmapBackendForRasterSurface(const SkBitmap& bm) { |
|
132 SkASSERT(bm.width() == fBitmap.width()); |
|
133 SkASSERT(bm.height() == fBitmap.height()); |
|
134 fBitmap = bm; // intent is to use bm's pixelRef (and rowbytes/config) |
|
135 fBitmap.lockPixels(); |
|
136 } |
|
137 |
|
138 SkBaseDevice* SkBitmapDevice::onCreateDevice(const SkImageInfo& info, Usage usage) { |
|
139 return SkBitmapDevice::Create(info, &this->getDeviceProperties()); |
|
140 } |
|
141 |
|
142 void SkBitmapDevice::lockPixels() { |
|
143 if (fBitmap.lockPixelsAreWritable()) { |
|
144 fBitmap.lockPixels(); |
|
145 } |
|
146 } |
|
147 |
|
148 void SkBitmapDevice::unlockPixels() { |
|
149 if (fBitmap.lockPixelsAreWritable()) { |
|
150 fBitmap.unlockPixels(); |
|
151 } |
|
152 } |
|
153 |
|
154 void SkBitmapDevice::clear(SkColor color) { |
|
155 fBitmap.eraseColor(color); |
|
156 } |
|
157 |
|
158 const SkBitmap& SkBitmapDevice::onAccessBitmap() { |
|
159 return fBitmap; |
|
160 } |
|
161 |
|
162 bool SkBitmapDevice::canHandleImageFilter(const SkImageFilter*) { |
|
163 return false; |
|
164 } |
|
165 |
|
166 bool SkBitmapDevice::filterImage(const SkImageFilter* filter, const SkBitmap& src, |
|
167 const SkImageFilter::Context& ctx, SkBitmap* result, |
|
168 SkIPoint* offset) { |
|
169 return false; |
|
170 } |
|
171 |
|
172 bool SkBitmapDevice::allowImageFilter(const SkImageFilter*) { |
|
173 return true; |
|
174 } |
|
175 |
|
176 bool SkBitmapDevice::onReadPixels(const SkBitmap& bitmap, |
|
177 int x, int y, |
|
178 SkCanvas::Config8888 config8888) { |
|
179 SkASSERT(SkBitmap::kARGB_8888_Config == bitmap.config()); |
|
180 SkASSERT(!bitmap.isNull()); |
|
181 SkASSERT(SkIRect::MakeWH(this->width(), this->height()).contains(SkIRect::MakeXYWH(x, y, |
|
182 bitmap.width(), |
|
183 bitmap.height()))); |
|
184 |
|
185 SkIRect srcRect = SkIRect::MakeXYWH(x, y, bitmap.width(), bitmap.height()); |
|
186 const SkBitmap& src = this->accessBitmap(false); |
|
187 |
|
188 SkBitmap subset; |
|
189 if (!src.extractSubset(&subset, srcRect)) { |
|
190 return false; |
|
191 } |
|
192 if (kPMColor_SkColorType != subset.colorType()) { |
|
193 // It'd be preferable to do this directly to bitmap. |
|
194 subset.copyTo(&subset, kPMColor_SkColorType); |
|
195 } |
|
196 SkAutoLockPixels alp(bitmap); |
|
197 uint32_t* bmpPixels = reinterpret_cast<uint32_t*>(bitmap.getPixels()); |
|
198 SkCopyBitmapToConfig8888(bmpPixels, bitmap.rowBytes(), config8888, subset); |
|
199 return true; |
|
200 } |
|
201 |
|
202 #ifdef SK_SUPPORT_LEGACY_WRITEPIXELSCONFIG |
|
203 void SkBitmapDevice::writePixels(const SkBitmap& bitmap, |
|
204 int x, int y, |
|
205 SkCanvas::Config8888 config8888) { |
|
206 if (bitmap.isNull() || bitmap.getTexture()) { |
|
207 return; |
|
208 } |
|
209 const SkBitmap* sprite = &bitmap; |
|
210 // check whether we have to handle a config8888 that doesn't match SkPMColor |
|
211 if (SkBitmap::kARGB_8888_Config == bitmap.config() && |
|
212 SkCanvas::kNative_Premul_Config8888 != config8888 && |
|
213 kPMColorAlias != config8888) { |
|
214 |
|
215 // We're going to have to convert from a config8888 to the native config |
|
216 // First we clip to the device bounds. |
|
217 SkBitmap dstBmp = this->accessBitmap(true); |
|
218 SkIRect spriteRect = SkIRect::MakeXYWH(x, y, |
|
219 bitmap.width(), bitmap.height()); |
|
220 SkIRect devRect = SkIRect::MakeWH(dstBmp.width(), dstBmp.height()); |
|
221 if (!spriteRect.intersect(devRect)) { |
|
222 return; |
|
223 } |
|
224 |
|
225 // write directly to the device if it has pixels and is SkPMColor |
|
226 bool drawSprite; |
|
227 if (SkBitmap::kARGB_8888_Config == dstBmp.config() && !dstBmp.isNull()) { |
|
228 // we can write directly to the dst when doing the conversion |
|
229 dstBmp.extractSubset(&dstBmp, spriteRect); |
|
230 drawSprite = false; |
|
231 } else { |
|
232 // we convert to a temporary bitmap and draw that as a sprite |
|
233 if (!dstBmp.allocPixels(SkImageInfo::MakeN32Premul(spriteRect.width(), |
|
234 spriteRect.height()))) { |
|
235 return; |
|
236 } |
|
237 drawSprite = true; |
|
238 } |
|
239 |
|
240 // copy pixels to dstBmp and convert from config8888 to native config. |
|
241 SkAutoLockPixels alp(bitmap); |
|
242 uint32_t* srcPixels = bitmap.getAddr32(spriteRect.fLeft - x, |
|
243 spriteRect.fTop - y); |
|
244 SkCopyConfig8888ToBitmap(dstBmp, |
|
245 srcPixels, |
|
246 bitmap.rowBytes(), |
|
247 config8888); |
|
248 |
|
249 if (drawSprite) { |
|
250 // we've clipped the sprite when we made a copy |
|
251 x = spriteRect.fLeft; |
|
252 y = spriteRect.fTop; |
|
253 sprite = &dstBmp; |
|
254 } else { |
|
255 return; |
|
256 } |
|
257 } |
|
258 |
|
259 SkPaint paint; |
|
260 paint.setXfermodeMode(SkXfermode::kSrc_Mode); |
|
261 SkRasterClip clip(SkIRect::MakeWH(fBitmap.width(), fBitmap.height())); |
|
262 SkDraw draw; |
|
263 draw.fRC = &clip; |
|
264 draw.fClip = &clip.bwRgn(); |
|
265 draw.fBitmap = &fBitmap; // canvas should have already called accessBitmap |
|
266 draw.fMatrix = &SkMatrix::I(); |
|
267 this->drawSprite(draw, *sprite, x, y, paint); |
|
268 } |
|
269 #endif |
|
270 |
|
271 void* SkBitmapDevice::onAccessPixels(SkImageInfo* info, size_t* rowBytes) { |
|
272 if (fBitmap.getPixels()) { |
|
273 *info = fBitmap.info(); |
|
274 *rowBytes = fBitmap.rowBytes(); |
|
275 return fBitmap.getPixels(); |
|
276 } |
|
277 return NULL; |
|
278 } |
|
279 |
|
280 static void rect_memcpy(void* dst, size_t dstRB, const void* src, size_t srcRB, size_t bytesPerRow, |
|
281 int rowCount) { |
|
282 SkASSERT(bytesPerRow <= srcRB); |
|
283 SkASSERT(bytesPerRow <= dstRB); |
|
284 for (int i = 0; i < rowCount; ++i) { |
|
285 memcpy(dst, src, bytesPerRow); |
|
286 dst = (char*)dst + dstRB; |
|
287 src = (const char*)src + srcRB; |
|
288 } |
|
289 } |
|
290 |
|
291 static bool info2config8888(const SkImageInfo& info, SkCanvas::Config8888* config) { |
|
292 bool pre; |
|
293 switch (info.alphaType()) { |
|
294 case kPremul_SkAlphaType: |
|
295 case kOpaque_SkAlphaType: |
|
296 pre = true; |
|
297 break; |
|
298 case kUnpremul_SkAlphaType: |
|
299 pre = false; |
|
300 break; |
|
301 default: |
|
302 return false; |
|
303 } |
|
304 switch (info.colorType()) { |
|
305 case kRGBA_8888_SkColorType: |
|
306 *config = pre ? SkCanvas::kRGBA_Premul_Config8888 : SkCanvas::kRGBA_Unpremul_Config8888; |
|
307 return true; |
|
308 case kBGRA_8888_SkColorType: |
|
309 *config = pre ? SkCanvas::kBGRA_Premul_Config8888 : SkCanvas::kBGRA_Unpremul_Config8888; |
|
310 return true; |
|
311 default: |
|
312 return false; |
|
313 } |
|
314 } |
|
315 |
|
316 // TODO: make this guy real, and not rely on legacy config8888 utility |
|
317 #include "SkConfig8888.h" |
|
318 static bool write_pixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes, |
|
319 const SkImageInfo& srcInfo, const void* srcPixels, size_t srcRowBytes) { |
|
320 if (srcInfo.dimensions() != dstInfo.dimensions()) { |
|
321 return false; |
|
322 } |
|
323 if (4 == srcInfo.bytesPerPixel() && 4 == dstInfo.bytesPerPixel()) { |
|
324 SkCanvas::Config8888 srcConfig, dstConfig; |
|
325 if (!info2config8888(srcInfo, &srcConfig) || !info2config8888(dstInfo, &dstConfig)) { |
|
326 return false; |
|
327 } |
|
328 SkConvertConfig8888Pixels((uint32_t*)dstPixels, dstRowBytes, dstConfig, |
|
329 (const uint32_t*)srcPixels, srcRowBytes, srcConfig, |
|
330 srcInfo.width(), srcInfo.height()); |
|
331 return true; |
|
332 } |
|
333 if (srcInfo.colorType() == dstInfo.colorType()) { |
|
334 switch (srcInfo.colorType()) { |
|
335 case kRGB_565_SkColorType: |
|
336 case kAlpha_8_SkColorType: |
|
337 break; |
|
338 case kARGB_4444_SkColorType: |
|
339 if (srcInfo.alphaType() != dstInfo.alphaType()) { |
|
340 return false; |
|
341 } |
|
342 break; |
|
343 default: |
|
344 return false; |
|
345 } |
|
346 rect_memcpy(dstPixels, dstRowBytes, srcPixels, srcRowBytes, |
|
347 srcInfo.width() * srcInfo.bytesPerPixel(), srcInfo.height()); |
|
348 } |
|
349 // TODO: add support for more conversions as needed |
|
350 return false; |
|
351 } |
|
352 |
|
353 bool SkBitmapDevice::onWritePixels(const SkImageInfo& srcInfo, const void* srcPixels, |
|
354 size_t srcRowBytes, int x, int y) { |
|
355 // since we don't stop creating un-pixeled devices yet, check for no pixels here |
|
356 if (NULL == fBitmap.getPixels()) { |
|
357 return false; |
|
358 } |
|
359 |
|
360 SkImageInfo dstInfo = fBitmap.info(); |
|
361 dstInfo.fWidth = srcInfo.width(); |
|
362 dstInfo.fHeight = srcInfo.height(); |
|
363 |
|
364 void* dstPixels = fBitmap.getAddr(x, y); |
|
365 size_t dstRowBytes = fBitmap.rowBytes(); |
|
366 |
|
367 if (write_pixels(dstInfo, dstPixels, dstRowBytes, srcInfo, srcPixels, srcRowBytes)) { |
|
368 fBitmap.notifyPixelsChanged(); |
|
369 return true; |
|
370 } |
|
371 return false; |
|
372 } |
|
373 |
|
374 /////////////////////////////////////////////////////////////////////////////// |
|
375 |
|
376 void SkBitmapDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) { |
|
377 draw.drawPaint(paint); |
|
378 } |
|
379 |
|
380 void SkBitmapDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode, size_t count, |
|
381 const SkPoint pts[], const SkPaint& paint) { |
|
382 CHECK_FOR_ANNOTATION(paint); |
|
383 draw.drawPoints(mode, count, pts, paint); |
|
384 } |
|
385 |
|
386 void SkBitmapDevice::drawRect(const SkDraw& draw, const SkRect& r, const SkPaint& paint) { |
|
387 CHECK_FOR_ANNOTATION(paint); |
|
388 draw.drawRect(r, paint); |
|
389 } |
|
390 |
|
391 void SkBitmapDevice::drawOval(const SkDraw& draw, const SkRect& oval, const SkPaint& paint) { |
|
392 CHECK_FOR_ANNOTATION(paint); |
|
393 |
|
394 SkPath path; |
|
395 path.addOval(oval); |
|
396 // call the VIRTUAL version, so any subclasses who do handle drawPath aren't |
|
397 // required to override drawOval. |
|
398 this->drawPath(draw, path, paint, NULL, true); |
|
399 } |
|
400 |
|
401 void SkBitmapDevice::drawRRect(const SkDraw& draw, const SkRRect& rrect, const SkPaint& paint) { |
|
402 CHECK_FOR_ANNOTATION(paint); |
|
403 |
|
404 #ifdef SK_IGNORE_BLURRED_RRECT_OPT |
|
405 SkPath path; |
|
406 |
|
407 path.addRRect(rrect); |
|
408 // call the VIRTUAL version, so any subclasses who do handle drawPath aren't |
|
409 // required to override drawRRect. |
|
410 this->drawPath(draw, path, paint, NULL, true); |
|
411 #else |
|
412 draw.drawRRect(rrect, paint); |
|
413 #endif |
|
414 } |
|
415 |
|
416 void SkBitmapDevice::drawPath(const SkDraw& draw, const SkPath& path, |
|
417 const SkPaint& paint, const SkMatrix* prePathMatrix, |
|
418 bool pathIsMutable) { |
|
419 CHECK_FOR_ANNOTATION(paint); |
|
420 draw.drawPath(path, paint, prePathMatrix, pathIsMutable); |
|
421 } |
|
422 |
|
423 void SkBitmapDevice::drawBitmap(const SkDraw& draw, const SkBitmap& bitmap, |
|
424 const SkMatrix& matrix, const SkPaint& paint) { |
|
425 draw.drawBitmap(bitmap, matrix, paint); |
|
426 } |
|
427 |
|
428 void SkBitmapDevice::drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap, |
|
429 const SkRect* src, const SkRect& dst, |
|
430 const SkPaint& paint, |
|
431 SkCanvas::DrawBitmapRectFlags flags) { |
|
432 SkMatrix matrix; |
|
433 SkRect bitmapBounds, tmpSrc, tmpDst; |
|
434 SkBitmap tmpBitmap; |
|
435 |
|
436 bitmapBounds.isetWH(bitmap.width(), bitmap.height()); |
|
437 |
|
438 // Compute matrix from the two rectangles |
|
439 if (src) { |
|
440 tmpSrc = *src; |
|
441 } else { |
|
442 tmpSrc = bitmapBounds; |
|
443 } |
|
444 matrix.setRectToRect(tmpSrc, dst, SkMatrix::kFill_ScaleToFit); |
|
445 |
|
446 const SkRect* dstPtr = &dst; |
|
447 const SkBitmap* bitmapPtr = &bitmap; |
|
448 |
|
449 // clip the tmpSrc to the bounds of the bitmap, and recompute dstRect if |
|
450 // needed (if the src was clipped). No check needed if src==null. |
|
451 if (src) { |
|
452 if (!bitmapBounds.contains(*src)) { |
|
453 if (!tmpSrc.intersect(bitmapBounds)) { |
|
454 return; // nothing to draw |
|
455 } |
|
456 // recompute dst, based on the smaller tmpSrc |
|
457 matrix.mapRect(&tmpDst, tmpSrc); |
|
458 dstPtr = &tmpDst; |
|
459 } |
|
460 |
|
461 // since we may need to clamp to the borders of the src rect within |
|
462 // the bitmap, we extract a subset. |
|
463 SkIRect srcIR; |
|
464 tmpSrc.roundOut(&srcIR); |
|
465 if (!bitmap.extractSubset(&tmpBitmap, srcIR)) { |
|
466 return; |
|
467 } |
|
468 bitmapPtr = &tmpBitmap; |
|
469 |
|
470 // Since we did an extract, we need to adjust the matrix accordingly |
|
471 SkScalar dx = 0, dy = 0; |
|
472 if (srcIR.fLeft > 0) { |
|
473 dx = SkIntToScalar(srcIR.fLeft); |
|
474 } |
|
475 if (srcIR.fTop > 0) { |
|
476 dy = SkIntToScalar(srcIR.fTop); |
|
477 } |
|
478 if (dx || dy) { |
|
479 matrix.preTranslate(dx, dy); |
|
480 } |
|
481 |
|
482 SkRect extractedBitmapBounds; |
|
483 extractedBitmapBounds.isetWH(bitmapPtr->width(), bitmapPtr->height()); |
|
484 if (extractedBitmapBounds == tmpSrc) { |
|
485 // no fractional part in src, we can just call drawBitmap |
|
486 goto USE_DRAWBITMAP; |
|
487 } |
|
488 } else { |
|
489 USE_DRAWBITMAP: |
|
490 // We can go faster by just calling drawBitmap, which will concat the |
|
491 // matrix with the CTM, and try to call drawSprite if it can. If not, |
|
492 // it will make a shader and call drawRect, as we do below. |
|
493 this->drawBitmap(draw, *bitmapPtr, matrix, paint); |
|
494 return; |
|
495 } |
|
496 |
|
497 // construct a shader, so we can call drawRect with the dst |
|
498 SkShader* s = SkShader::CreateBitmapShader(*bitmapPtr, |
|
499 SkShader::kClamp_TileMode, |
|
500 SkShader::kClamp_TileMode); |
|
501 if (NULL == s) { |
|
502 return; |
|
503 } |
|
504 s->setLocalMatrix(matrix); |
|
505 |
|
506 SkPaint paintWithShader(paint); |
|
507 paintWithShader.setStyle(SkPaint::kFill_Style); |
|
508 paintWithShader.setShader(s)->unref(); |
|
509 |
|
510 // Call ourself, in case the subclass wanted to share this setup code |
|
511 // but handle the drawRect code themselves. |
|
512 this->drawRect(draw, *dstPtr, paintWithShader); |
|
513 } |
|
514 |
|
515 void SkBitmapDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap, |
|
516 int x, int y, const SkPaint& paint) { |
|
517 draw.drawSprite(bitmap, x, y, paint); |
|
518 } |
|
519 |
|
520 void SkBitmapDevice::drawText(const SkDraw& draw, const void* text, size_t len, |
|
521 SkScalar x, SkScalar y, const SkPaint& paint) { |
|
522 draw.drawText((const char*)text, len, x, y, paint); |
|
523 } |
|
524 |
|
525 void SkBitmapDevice::drawPosText(const SkDraw& draw, const void* text, size_t len, |
|
526 const SkScalar xpos[], SkScalar y, |
|
527 int scalarsPerPos, const SkPaint& paint) { |
|
528 draw.drawPosText((const char*)text, len, xpos, y, scalarsPerPos, paint); |
|
529 } |
|
530 |
|
531 void SkBitmapDevice::drawTextOnPath(const SkDraw& draw, const void* text, |
|
532 size_t len, const SkPath& path, |
|
533 const SkMatrix* matrix, |
|
534 const SkPaint& paint) { |
|
535 draw.drawTextOnPath((const char*)text, len, path, matrix, paint); |
|
536 } |
|
537 |
|
538 void SkBitmapDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode, |
|
539 int vertexCount, |
|
540 const SkPoint verts[], const SkPoint textures[], |
|
541 const SkColor colors[], SkXfermode* xmode, |
|
542 const uint16_t indices[], int indexCount, |
|
543 const SkPaint& paint) { |
|
544 draw.drawVertices(vmode, vertexCount, verts, textures, colors, xmode, |
|
545 indices, indexCount, paint); |
|
546 } |
|
547 |
|
548 void SkBitmapDevice::drawDevice(const SkDraw& draw, SkBaseDevice* device, |
|
549 int x, int y, const SkPaint& paint) { |
|
550 const SkBitmap& src = device->accessBitmap(false); |
|
551 draw.drawSprite(src, x, y, paint); |
|
552 } |
|
553 |
|
554 SkSurface* SkBitmapDevice::newSurface(const SkImageInfo& info) { |
|
555 return SkSurface::NewRaster(info); |
|
556 } |
|
557 |
|
558 const void* SkBitmapDevice::peekPixels(SkImageInfo* info, size_t* rowBytes) { |
|
559 if (fBitmap.getPixels() && fBitmap.asImageInfo(info)) { |
|
560 if (rowBytes) { |
|
561 *rowBytes = fBitmap.rowBytes(); |
|
562 } |
|
563 return fBitmap.getPixels(); |
|
564 } |
|
565 return NULL; |
|
566 } |
|
567 |
|
568 /////////////////////////////////////////////////////////////////////////////// |
|
569 |
|
570 bool SkBitmapDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) { |
|
571 if (!paint.isLCDRenderText() || !paint.isAntiAlias()) { |
|
572 // we're cool with the paint as is |
|
573 return false; |
|
574 } |
|
575 |
|
576 if (SkBitmap::kARGB_8888_Config != fBitmap.config() || |
|
577 paint.getRasterizer() || |
|
578 paint.getPathEffect() || |
|
579 paint.isFakeBoldText() || |
|
580 paint.getStyle() != SkPaint::kFill_Style || |
|
581 !SkXfermode::IsMode(paint.getXfermode(), SkXfermode::kSrcOver_Mode)) { |
|
582 // turn off lcd |
|
583 flags->fFlags = paint.getFlags() & ~SkPaint::kLCDRenderText_Flag; |
|
584 flags->fHinting = paint.getHinting(); |
|
585 return true; |
|
586 } |
|
587 // we're cool with the paint as is |
|
588 return false; |
|
589 } |