1 /*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "jni.h"
18 #include "Canvas.h"
19 #include "GraphicsJNI.h"
20 #include <android_runtime/AndroidRuntime.h>
21
22 #include "SkCanvas.h"
23 #include "SkClipStack.h"
24 #include "SkDevice.h"
25 #include "SkDeque.h"
26 #include "SkDrawFilter.h"
27 #include "SkGraphics.h"
28 #include "SkPorterDuff.h"
29 #include "SkShader.h"
30 #include "SkTArray.h"
31 #include "SkTemplates.h"
32
33 #include "MinikinUtils.h"
34
35 #include "TypefaceImpl.h"
36
37 #include "unicode/ubidi.h"
38 #include "unicode/ushape.h"
39
40 #include <utils/Log.h>
41
42 namespace android {
43
44 // Holds an SkCanvas reference plus additional native data.
45 class SkiaCanvas : public Canvas {
46 public:
47 SkiaCanvas(SkBitmap* bitmap);
48
SkiaCanvas(SkCanvas * canvas)49 SkiaCanvas(SkCanvas* canvas) : mCanvas(canvas) {
50 SkASSERT(canvas);
51 }
52
getSkCanvas()53 virtual SkCanvas* getSkCanvas() {
54 return mCanvas.get();
55 }
56
57 virtual void setBitmap(SkBitmap* bitmap, bool copyState);
58
59 virtual bool isOpaque();
60 virtual int width();
61 virtual int height();
62
63 virtual int getSaveCount() const;
64 virtual int save(SkCanvas::SaveFlags flags);
65 virtual void restore();
66 virtual void restoreToCount(int saveCount);
67
68 virtual int saveLayer(float left, float top, float right, float bottom,
69 const SkPaint* paint, SkCanvas::SaveFlags flags);
70 virtual int saveLayerAlpha(float left, float top, float right, float bottom,
71 int alpha, SkCanvas::SaveFlags flags);
72
73 virtual void getMatrix(SkMatrix* outMatrix) const;
74 virtual void setMatrix(const SkMatrix& matrix);
75 virtual void concat(const SkMatrix& matrix);
76 virtual void rotate(float degrees);
77 virtual void scale(float sx, float sy);
78 virtual void skew(float sx, float sy);
79 virtual void translate(float dx, float dy);
80
81 virtual bool getClipBounds(SkRect* outRect) const;
82 virtual bool quickRejectRect(float left, float top, float right, float bottom) const;
83 virtual bool quickRejectPath(const SkPath& path) const;
84 virtual bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op);
85 virtual bool clipPath(const SkPath* path, SkRegion::Op op);
86 virtual bool clipRegion(const SkRegion* region, SkRegion::Op op);
87
88 virtual SkDrawFilter* getDrawFilter();
89 virtual void setDrawFilter(SkDrawFilter* drawFilter);
90
91 virtual void drawColor(int color, SkXfermode::Mode mode);
92 virtual void drawPaint(const SkPaint& paint);
93
94 virtual void drawPoint(float x, float y, const SkPaint& paint);
95 virtual void drawPoints(const float* points, int count, const SkPaint& paint);
96 virtual void drawLine(float startX, float startY, float stopX, float stopY,
97 const SkPaint& paint);
98 virtual void drawLines(const float* points, int count, const SkPaint& paint);
99 virtual void drawRect(float left, float top, float right, float bottom, const SkPaint& paint);
100 virtual void drawRoundRect(float left, float top, float right, float bottom,
101 float rx, float ry, const SkPaint& paint);
102 virtual void drawCircle(float x, float y, float radius, const SkPaint& paint);
103 virtual void drawOval(float left, float top, float right, float bottom, const SkPaint& paint);
104 virtual void drawArc(float left, float top, float right, float bottom,
105 float startAngle, float sweepAngle, bool useCenter, const SkPaint& paint);
106 virtual void drawPath(const SkPath& path, const SkPaint& paint);
107 virtual void drawVertices(SkCanvas::VertexMode vertexMode, int vertexCount,
108 const float* verts, const float* tex, const int* colors,
109 const uint16_t* indices, int indexCount, const SkPaint& paint);
110
111 virtual void drawBitmap(const SkBitmap& bitmap, float left, float top, const SkPaint* paint);
112 virtual void drawBitmap(const SkBitmap& bitmap, const SkMatrix& matrix, const SkPaint* paint);
113 virtual void drawBitmap(const SkBitmap& bitmap, float srcLeft, float srcTop,
114 float srcRight, float srcBottom, float dstLeft, float dstTop,
115 float dstRight, float dstBottom, const SkPaint* paint);
116 virtual void drawBitmapMesh(const SkBitmap& bitmap, int meshWidth, int meshHeight,
117 const float* vertices, const int* colors, const SkPaint* paint);
118
119 virtual void drawText(const uint16_t* text, const float* positions, int count,
120 const SkPaint& paint, float x, float y,
121 float boundsLeft, float boundsTop, float boundsRight, float boundsBottom);
122 virtual void drawPosText(const uint16_t* text, const float* positions, int count,
123 int posCount, const SkPaint& paint);
124 virtual void drawTextOnPath(const uint16_t* glyphs, int count, const SkPath& path,
125 float hOffset, float vOffset, const SkPaint& paint);
126
drawTextAbsolutePos() const127 virtual bool drawTextAbsolutePos() const { return true; }
128
129 private:
130 struct SaveRec {
131 int saveCount;
132 SkCanvas::SaveFlags saveFlags;
133 };
134
135 void recordPartialSave(SkCanvas::SaveFlags flags);
136 void saveClipsForFrame(SkTArray<SkClipStack::Element>& clips, int frameSaveCount);
137 void applyClips(const SkTArray<SkClipStack::Element>& clips);
138
139 void drawPoints(const float* points, int count, const SkPaint& paint,
140 SkCanvas::PointMode mode);
141 void drawTextDecorations(float x, float y, float length, const SkPaint& paint);
142
143 SkAutoTUnref<SkCanvas> mCanvas;
144 SkAutoTDelete<SkDeque> mSaveStack; // lazily allocated, tracks partial saves.
145 };
146
147 // Construct an SkCanvas from the bitmap.
createCanvas(SkBitmap * bitmap)148 static SkCanvas* createCanvas(SkBitmap* bitmap) {
149 if (bitmap) {
150 return SkNEW_ARGS(SkCanvas, (*bitmap));
151 }
152
153 // Create an empty bitmap device to prevent callers from crashing
154 // if they attempt to draw into this canvas.
155 SkBitmap emptyBitmap;
156 return new SkCanvas(emptyBitmap);
157 }
158
create_canvas(SkBitmap * bitmap)159 Canvas* Canvas::create_canvas(SkBitmap* bitmap) {
160 return new SkiaCanvas(bitmap);
161 }
162
create_canvas(SkCanvas * skiaCanvas)163 Canvas* Canvas::create_canvas(SkCanvas* skiaCanvas) {
164 return new SkiaCanvas(skiaCanvas);
165 }
166
SkiaCanvas(SkBitmap * bitmap)167 SkiaCanvas::SkiaCanvas(SkBitmap* bitmap) {
168 mCanvas.reset(createCanvas(bitmap));
169 }
170
171 // ----------------------------------------------------------------------------
172 // Canvas state operations: Replace Bitmap
173 // ----------------------------------------------------------------------------
174
175 class ClipCopier : public SkCanvas::ClipVisitor {
176 public:
ClipCopier(SkCanvas * dstCanvas)177 ClipCopier(SkCanvas* dstCanvas) : m_dstCanvas(dstCanvas) {}
178
clipRect(const SkRect & rect,SkRegion::Op op,bool antialias)179 virtual void clipRect(const SkRect& rect, SkRegion::Op op, bool antialias) {
180 m_dstCanvas->clipRect(rect, op, antialias);
181 }
clipRRect(const SkRRect & rrect,SkRegion::Op op,bool antialias)182 virtual void clipRRect(const SkRRect& rrect, SkRegion::Op op, bool antialias) {
183 m_dstCanvas->clipRRect(rrect, op, antialias);
184 }
clipPath(const SkPath & path,SkRegion::Op op,bool antialias)185 virtual void clipPath(const SkPath& path, SkRegion::Op op, bool antialias) {
186 m_dstCanvas->clipPath(path, op, antialias);
187 }
188
189 private:
190 SkCanvas* m_dstCanvas;
191 };
192
setBitmap(SkBitmap * bitmap,bool copyState)193 void SkiaCanvas::setBitmap(SkBitmap* bitmap, bool copyState) {
194 SkCanvas* newCanvas = createCanvas(bitmap);
195 SkASSERT(newCanvas);
196
197 if (copyState) {
198 // Copy the canvas matrix & clip state.
199 newCanvas->setMatrix(mCanvas->getTotalMatrix());
200 if (NULL != mCanvas->getDevice() && NULL != newCanvas->getDevice()) {
201 ClipCopier copier(newCanvas);
202 mCanvas->replayClips(&copier);
203 }
204 }
205
206 // unrefs the existing canvas
207 mCanvas.reset(newCanvas);
208
209 // clean up the old save stack
210 mSaveStack.reset(NULL);
211 }
212
213 // ----------------------------------------------------------------------------
214 // Canvas state operations
215 // ----------------------------------------------------------------------------
216
isOpaque()217 bool SkiaCanvas::isOpaque() {
218 return mCanvas->getDevice()->accessBitmap(false).isOpaque();
219 }
220
width()221 int SkiaCanvas::width() {
222 return mCanvas->getBaseLayerSize().width();
223 }
224
height()225 int SkiaCanvas::height() {
226 return mCanvas->getBaseLayerSize().height();
227 }
228
229 // ----------------------------------------------------------------------------
230 // Canvas state operations: Save (layer)
231 // ----------------------------------------------------------------------------
232
getSaveCount() const233 int SkiaCanvas::getSaveCount() const {
234 return mCanvas->getSaveCount();
235 }
236
save(SkCanvas::SaveFlags flags)237 int SkiaCanvas::save(SkCanvas::SaveFlags flags) {
238 int count = mCanvas->save();
239 recordPartialSave(flags);
240 return count;
241 }
242
restore()243 void SkiaCanvas::restore() {
244 const SaveRec* rec = (NULL == mSaveStack.get())
245 ? NULL
246 : static_cast<SaveRec*>(mSaveStack->back());
247 int currentSaveCount = mCanvas->getSaveCount() - 1;
248 SkASSERT(NULL == rec || currentSaveCount >= rec->saveCount);
249
250 if (NULL == rec || rec->saveCount != currentSaveCount) {
251 // Fast path - no record for this frame.
252 mCanvas->restore();
253 return;
254 }
255
256 bool preserveMatrix = !(rec->saveFlags & SkCanvas::kMatrix_SaveFlag);
257 bool preserveClip = !(rec->saveFlags & SkCanvas::kClip_SaveFlag);
258
259 SkMatrix savedMatrix;
260 if (preserveMatrix) {
261 savedMatrix = mCanvas->getTotalMatrix();
262 }
263
264 SkTArray<SkClipStack::Element> savedClips;
265 if (preserveClip) {
266 saveClipsForFrame(savedClips, currentSaveCount);
267 }
268
269 mCanvas->restore();
270
271 if (preserveMatrix) {
272 mCanvas->setMatrix(savedMatrix);
273 }
274
275 if (preserveClip && !savedClips.empty()) {
276 applyClips(savedClips);
277 }
278
279 mSaveStack->pop_back();
280 }
281
restoreToCount(int restoreCount)282 void SkiaCanvas::restoreToCount(int restoreCount) {
283 while (mCanvas->getSaveCount() > restoreCount) {
284 this->restore();
285 }
286 }
287
saveLayer(float left,float top,float right,float bottom,const SkPaint * paint,SkCanvas::SaveFlags flags)288 int SkiaCanvas::saveLayer(float left, float top, float right, float bottom,
289 const SkPaint* paint, SkCanvas::SaveFlags flags) {
290 SkRect bounds = SkRect::MakeLTRB(left, top, right, bottom);
291 int count = mCanvas->saveLayer(&bounds, paint, flags | SkCanvas::kMatrixClip_SaveFlag);
292 recordPartialSave(flags);
293 return count;
294 }
295
saveLayerAlpha(float left,float top,float right,float bottom,int alpha,SkCanvas::SaveFlags flags)296 int SkiaCanvas::saveLayerAlpha(float left, float top, float right, float bottom,
297 int alpha, SkCanvas::SaveFlags flags) {
298 SkRect bounds = SkRect::MakeLTRB(left, top, right, bottom);
299 int count = mCanvas->saveLayerAlpha(&bounds, alpha, flags | SkCanvas::kMatrixClip_SaveFlag);
300 recordPartialSave(flags);
301 return count;
302 }
303
304 // ----------------------------------------------------------------------------
305 // functions to emulate legacy SaveFlags (i.e. independent matrix/clip flags)
306 // ----------------------------------------------------------------------------
307
recordPartialSave(SkCanvas::SaveFlags flags)308 void SkiaCanvas::recordPartialSave(SkCanvas::SaveFlags flags) {
309 // A partial save is a save operation which doesn't capture the full canvas state.
310 // (either kMatrix_SaveFlags or kClip_SaveFlag is missing).
311
312 // Mask-out non canvas state bits.
313 flags = static_cast<SkCanvas::SaveFlags>(flags & SkCanvas::kMatrixClip_SaveFlag);
314
315 if (SkCanvas::kMatrixClip_SaveFlag == flags) {
316 // not a partial save.
317 return;
318 }
319
320 if (NULL == mSaveStack.get()) {
321 mSaveStack.reset(SkNEW_ARGS(SkDeque, (sizeof(struct SaveRec), 8)));
322 }
323
324 SaveRec* rec = static_cast<SaveRec*>(mSaveStack->push_back());
325 // Store the save counter in the SkClipStack domain.
326 // (0-based, equal to the number of save ops on the stack).
327 rec->saveCount = mCanvas->getSaveCount() - 1;
328 rec->saveFlags = flags;
329 }
330
saveClipsForFrame(SkTArray<SkClipStack::Element> & clips,int frameSaveCount)331 void SkiaCanvas::saveClipsForFrame(SkTArray<SkClipStack::Element>& clips, int frameSaveCount) {
332 SkClipStack::Iter clipIterator(*mCanvas->getClipStack(),
333 SkClipStack::Iter::kTop_IterStart);
334 while (const SkClipStack::Element* elem = clipIterator.next()) {
335 if (elem->getSaveCount() < frameSaveCount) {
336 // done with the current frame.
337 break;
338 }
339 SkASSERT(elem->getSaveCount() == frameSaveCount);
340 clips.push_back(*elem);
341 }
342 }
343
applyClips(const SkTArray<SkClipStack::Element> & clips)344 void SkiaCanvas::applyClips(const SkTArray<SkClipStack::Element>& clips) {
345 ClipCopier clipCopier(mCanvas);
346
347 // The clip stack stores clips in device space.
348 SkMatrix origMatrix = mCanvas->getTotalMatrix();
349 mCanvas->resetMatrix();
350
351 // We pushed the clips in reverse order.
352 for (int i = clips.count() - 1; i >= 0; --i) {
353 clips[i].replay(&clipCopier);
354 }
355
356 mCanvas->setMatrix(origMatrix);
357 }
358
359 // ----------------------------------------------------------------------------
360 // Canvas state operations: Matrix
361 // ----------------------------------------------------------------------------
362
getMatrix(SkMatrix * outMatrix) const363 void SkiaCanvas::getMatrix(SkMatrix* outMatrix) const {
364 *outMatrix = mCanvas->getTotalMatrix();
365 }
366
setMatrix(const SkMatrix & matrix)367 void SkiaCanvas::setMatrix(const SkMatrix& matrix) {
368 mCanvas->setMatrix(matrix);
369 }
370
concat(const SkMatrix & matrix)371 void SkiaCanvas::concat(const SkMatrix& matrix) {
372 mCanvas->concat(matrix);
373 }
374
rotate(float degrees)375 void SkiaCanvas::rotate(float degrees) {
376 mCanvas->rotate(degrees);
377 }
378
scale(float sx,float sy)379 void SkiaCanvas::scale(float sx, float sy) {
380 mCanvas->scale(sx, sy);
381 }
382
skew(float sx,float sy)383 void SkiaCanvas::skew(float sx, float sy) {
384 mCanvas->skew(sx, sy);
385 }
386
translate(float dx,float dy)387 void SkiaCanvas::translate(float dx, float dy) {
388 mCanvas->translate(dx, dy);
389 }
390
391 // ----------------------------------------------------------------------------
392 // Canvas state operations: Clips
393 // ----------------------------------------------------------------------------
394
395 // This function is a mirror of SkCanvas::getClipBounds except that it does
396 // not outset the edge of the clip to account for anti-aliasing. There is
397 // a skia bug to investigate pushing this logic into back into skia.
398 // (see https://code.google.com/p/skia/issues/detail?id=1303)
getClipBounds(SkRect * outRect) const399 bool SkiaCanvas::getClipBounds(SkRect* outRect) const {
400 SkIRect ibounds;
401 if (!mCanvas->getClipDeviceBounds(&ibounds)) {
402 return false;
403 }
404
405 SkMatrix inverse;
406 // if we can't invert the CTM, we can't return local clip bounds
407 if (!mCanvas->getTotalMatrix().invert(&inverse)) {
408 if (outRect) {
409 outRect->setEmpty();
410 }
411 return false;
412 }
413
414 if (NULL != outRect) {
415 SkRect r = SkRect::Make(ibounds);
416 inverse.mapRect(outRect, r);
417 }
418 return true;
419 }
420
quickRejectRect(float left,float top,float right,float bottom) const421 bool SkiaCanvas::quickRejectRect(float left, float top, float right, float bottom) const {
422 SkRect bounds = SkRect::MakeLTRB(left, top, right, bottom);
423 return mCanvas->quickReject(bounds);
424 }
425
quickRejectPath(const SkPath & path) const426 bool SkiaCanvas::quickRejectPath(const SkPath& path) const {
427 return mCanvas->quickReject(path);
428 }
429
clipRect(float left,float top,float right,float bottom,SkRegion::Op op)430 bool SkiaCanvas::clipRect(float left, float top, float right, float bottom, SkRegion::Op op) {
431 SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
432 mCanvas->clipRect(rect, op);
433 return mCanvas->isClipEmpty();
434 }
435
clipPath(const SkPath * path,SkRegion::Op op)436 bool SkiaCanvas::clipPath(const SkPath* path, SkRegion::Op op) {
437 mCanvas->clipPath(*path, op);
438 return mCanvas->isClipEmpty();
439 }
440
clipRegion(const SkRegion * region,SkRegion::Op op)441 bool SkiaCanvas::clipRegion(const SkRegion* region, SkRegion::Op op) {
442 SkPath rgnPath;
443 if (region->getBoundaryPath(&rgnPath)) {
444 // The region is specified in device space.
445 SkMatrix savedMatrix = mCanvas->getTotalMatrix();
446 mCanvas->resetMatrix();
447 mCanvas->clipPath(rgnPath, op);
448 mCanvas->setMatrix(savedMatrix);
449 } else {
450 mCanvas->clipRect(SkRect::MakeEmpty(), op);
451 }
452 return mCanvas->isClipEmpty();
453 }
454
455 // ----------------------------------------------------------------------------
456 // Canvas state operations: Filters
457 // ----------------------------------------------------------------------------
458
getDrawFilter()459 SkDrawFilter* SkiaCanvas::getDrawFilter() {
460 return mCanvas->getDrawFilter();
461 }
462
setDrawFilter(SkDrawFilter * drawFilter)463 void SkiaCanvas::setDrawFilter(SkDrawFilter* drawFilter) {
464 mCanvas->setDrawFilter(drawFilter);
465 }
466
467 // ----------------------------------------------------------------------------
468 // Canvas draw operations
469 // ----------------------------------------------------------------------------
470
drawColor(int color,SkXfermode::Mode mode)471 void SkiaCanvas::drawColor(int color, SkXfermode::Mode mode) {
472 mCanvas->drawColor(color, mode);
473 }
474
drawPaint(const SkPaint & paint)475 void SkiaCanvas::drawPaint(const SkPaint& paint) {
476 mCanvas->drawPaint(paint);
477 }
478
479 // ----------------------------------------------------------------------------
480 // Canvas draw operations: Geometry
481 // ----------------------------------------------------------------------------
482
drawPoints(const float * points,int count,const SkPaint & paint,SkCanvas::PointMode mode)483 void SkiaCanvas::drawPoints(const float* points, int count, const SkPaint& paint,
484 SkCanvas::PointMode mode) {
485 // convert the floats into SkPoints
486 count >>= 1; // now it is the number of points
487 SkAutoSTMalloc<32, SkPoint> storage(count);
488 SkPoint* pts = storage.get();
489 for (int i = 0; i < count; i++) {
490 pts[i].set(points[0], points[1]);
491 points += 2;
492 }
493 mCanvas->drawPoints(mode, count, pts, paint);
494 }
495
496
drawPoint(float x,float y,const SkPaint & paint)497 void SkiaCanvas::drawPoint(float x, float y, const SkPaint& paint) {
498 mCanvas->drawPoint(x, y, paint);
499 }
500
drawPoints(const float * points,int count,const SkPaint & paint)501 void SkiaCanvas::drawPoints(const float* points, int count, const SkPaint& paint) {
502 this->drawPoints(points, count, paint, SkCanvas::kPoints_PointMode);
503 }
504
drawLine(float startX,float startY,float stopX,float stopY,const SkPaint & paint)505 void SkiaCanvas::drawLine(float startX, float startY, float stopX, float stopY,
506 const SkPaint& paint) {
507 mCanvas->drawLine(startX, startY, stopX, stopY, paint);
508 }
509
drawLines(const float * points,int count,const SkPaint & paint)510 void SkiaCanvas::drawLines(const float* points, int count, const SkPaint& paint) {
511 this->drawPoints(points, count, paint, SkCanvas::kLines_PointMode);
512 }
513
drawRect(float left,float top,float right,float bottom,const SkPaint & paint)514 void SkiaCanvas::drawRect(float left, float top, float right, float bottom,
515 const SkPaint& paint) {
516 mCanvas->drawRectCoords(left, top, right, bottom, paint);
517
518 }
519
drawRoundRect(float left,float top,float right,float bottom,float rx,float ry,const SkPaint & paint)520 void SkiaCanvas::drawRoundRect(float left, float top, float right, float bottom,
521 float rx, float ry, const SkPaint& paint) {
522 SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
523 mCanvas->drawRoundRect(rect, rx, ry, paint);
524 }
525
drawCircle(float x,float y,float radius,const SkPaint & paint)526 void SkiaCanvas::drawCircle(float x, float y, float radius, const SkPaint& paint) {
527 mCanvas->drawCircle(x, y, radius, paint);
528 }
529
drawOval(float left,float top,float right,float bottom,const SkPaint & paint)530 void SkiaCanvas::drawOval(float left, float top, float right, float bottom, const SkPaint& paint) {
531 SkRect oval = SkRect::MakeLTRB(left, top, right, bottom);
532 mCanvas->drawOval(oval, paint);
533 }
534
drawArc(float left,float top,float right,float bottom,float startAngle,float sweepAngle,bool useCenter,const SkPaint & paint)535 void SkiaCanvas::drawArc(float left, float top, float right, float bottom,
536 float startAngle, float sweepAngle, bool useCenter, const SkPaint& paint) {
537 SkRect arc = SkRect::MakeLTRB(left, top, right, bottom);
538 mCanvas->drawArc(arc, startAngle, sweepAngle, useCenter, paint);
539 }
540
drawPath(const SkPath & path,const SkPaint & paint)541 void SkiaCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
542 mCanvas->drawPath(path, paint);
543 }
544
drawVertices(SkCanvas::VertexMode vertexMode,int vertexCount,const float * verts,const float * texs,const int * colors,const uint16_t * indices,int indexCount,const SkPaint & paint)545 void SkiaCanvas::drawVertices(SkCanvas::VertexMode vertexMode, int vertexCount,
546 const float* verts, const float* texs, const int* colors,
547 const uint16_t* indices, int indexCount, const SkPaint& paint) {
548 #ifndef SK_SCALAR_IS_FLOAT
549 SkDEBUGFAIL("SkScalar must be a float for these conversions to be valid");
550 #endif
551 const int ptCount = vertexCount >> 1;
552 mCanvas->drawVertices(vertexMode, ptCount, (SkPoint*)verts, (SkPoint*)texs,
553 (SkColor*)colors, NULL, indices, indexCount, paint);
554 }
555
556 // ----------------------------------------------------------------------------
557 // Canvas draw operations: Bitmaps
558 // ----------------------------------------------------------------------------
559
drawBitmap(const SkBitmap & bitmap,float left,float top,const SkPaint * paint)560 void SkiaCanvas::drawBitmap(const SkBitmap& bitmap, float left, float top, const SkPaint* paint) {
561 mCanvas->drawBitmap(bitmap, left, top, paint);
562 }
563
drawBitmap(const SkBitmap & bitmap,const SkMatrix & matrix,const SkPaint * paint)564 void SkiaCanvas::drawBitmap(const SkBitmap& bitmap, const SkMatrix& matrix, const SkPaint* paint) {
565 mCanvas->drawBitmapMatrix(bitmap, matrix, paint);
566 }
567
drawBitmap(const SkBitmap & bitmap,float srcLeft,float srcTop,float srcRight,float srcBottom,float dstLeft,float dstTop,float dstRight,float dstBottom,const SkPaint * paint)568 void SkiaCanvas::drawBitmap(const SkBitmap& bitmap, float srcLeft, float srcTop,
569 float srcRight, float srcBottom, float dstLeft, float dstTop,
570 float dstRight, float dstBottom, const SkPaint* paint) {
571 SkRect srcRect = SkRect::MakeLTRB(srcLeft, srcTop, srcRight, srcBottom);
572 SkRect dstRect = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom);
573 mCanvas->drawBitmapRectToRect(bitmap, &srcRect, dstRect, paint);
574 }
575
drawBitmapMesh(const SkBitmap & bitmap,int meshWidth,int meshHeight,const float * vertices,const int * colors,const SkPaint * paint)576 void SkiaCanvas::drawBitmapMesh(const SkBitmap& bitmap, int meshWidth, int meshHeight,
577 const float* vertices, const int* colors, const SkPaint* paint) {
578
579 const int ptCount = (meshWidth + 1) * (meshHeight + 1);
580 const int indexCount = meshWidth * meshHeight * 6;
581
582 /* Our temp storage holds 2 or 3 arrays.
583 texture points [ptCount * sizeof(SkPoint)]
584 optionally vertex points [ptCount * sizeof(SkPoint)] if we need a
585 copy to convert from float to fixed
586 indices [ptCount * sizeof(uint16_t)]
587 */
588 ssize_t storageSize = ptCount * sizeof(SkPoint); // texs[]
589 storageSize += indexCount * sizeof(uint16_t); // indices[]
590
591
592 #ifndef SK_SCALAR_IS_FLOAT
593 SkDEBUGFAIL("SkScalar must be a float for these conversions to be valid");
594 #endif
595 SkAutoMalloc storage(storageSize);
596 SkPoint* texs = (SkPoint*)storage.get();
597 uint16_t* indices = (uint16_t*)(texs + ptCount);
598
599 // cons up texture coordinates and indices
600 {
601 const SkScalar w = SkIntToScalar(bitmap.width());
602 const SkScalar h = SkIntToScalar(bitmap.height());
603 const SkScalar dx = w / meshWidth;
604 const SkScalar dy = h / meshHeight;
605
606 SkPoint* texsPtr = texs;
607 SkScalar y = 0;
608 for (int i = 0; i <= meshHeight; i++) {
609 if (i == meshHeight) {
610 y = h; // to ensure numerically we hit h exactly
611 }
612 SkScalar x = 0;
613 for (int j = 0; j < meshWidth; j++) {
614 texsPtr->set(x, y);
615 texsPtr += 1;
616 x += dx;
617 }
618 texsPtr->set(w, y);
619 texsPtr += 1;
620 y += dy;
621 }
622 SkASSERT(texsPtr - texs == ptCount);
623 }
624
625 // cons up indices
626 {
627 uint16_t* indexPtr = indices;
628 int index = 0;
629 for (int i = 0; i < meshHeight; i++) {
630 for (int j = 0; j < meshWidth; j++) {
631 // lower-left triangle
632 *indexPtr++ = index;
633 *indexPtr++ = index + meshWidth + 1;
634 *indexPtr++ = index + meshWidth + 2;
635 // upper-right triangle
636 *indexPtr++ = index;
637 *indexPtr++ = index + meshWidth + 2;
638 *indexPtr++ = index + 1;
639 // bump to the next cell
640 index += 1;
641 }
642 // bump to the next row
643 index += 1;
644 }
645 SkASSERT(indexPtr - indices == indexCount);
646 SkASSERT((char*)indexPtr - (char*)storage.get() == storageSize);
647 }
648
649 // double-check that we have legal indices
650 #ifdef SK_DEBUG
651 {
652 for (int i = 0; i < indexCount; i++) {
653 SkASSERT((unsigned)indices[i] < (unsigned)ptCount);
654 }
655 }
656 #endif
657
658 // cons-up a shader for the bitmap
659 SkPaint tmpPaint;
660 if (paint) {
661 tmpPaint = *paint;
662 }
663 SkShader* shader = SkShader::CreateBitmapShader(bitmap,
664 SkShader::kClamp_TileMode,
665 SkShader::kClamp_TileMode);
666 SkSafeUnref(tmpPaint.setShader(shader));
667
668 mCanvas->drawVertices(SkCanvas::kTriangles_VertexMode, ptCount, (SkPoint*)vertices,
669 texs, (const SkColor*)colors, NULL, indices,
670 indexCount, tmpPaint);
671 }
672
673 // ----------------------------------------------------------------------------
674 // Canvas draw operations: Text
675 // ----------------------------------------------------------------------------
676
drawText(const uint16_t * text,const float * positions,int count,const SkPaint & paint,float x,float y,float boundsLeft,float boundsTop,float boundsRight,float boundsBottom)677 void SkiaCanvas::drawText(const uint16_t* text, const float* positions, int count,
678 const SkPaint& paint, float x, float y,
679 float boundsLeft, float boundsTop, float boundsRight, float boundsBottom) {
680 // Set align to left for drawing, as we don't want individual
681 // glyphs centered or right-aligned; the offset above takes
682 // care of all alignment.
683 SkPaint paintCopy(paint);
684 paintCopy.setTextAlign(SkPaint::kLeft_Align);
685
686 SK_COMPILE_ASSERT(sizeof(SkPoint) == sizeof(float)*2, SkPoint_is_no_longer_2_floats);
687 mCanvas->drawPosText(text, count << 1, reinterpret_cast<const SkPoint*>(positions), paintCopy);
688 }
689
drawPosText(const uint16_t * text,const float * positions,int count,int posCount,const SkPaint & paint)690 void SkiaCanvas::drawPosText(const uint16_t* text, const float* positions, int count, int posCount,
691 const SkPaint& paint) {
692 SkPoint* posPtr = posCount > 0 ? new SkPoint[posCount] : NULL;
693 int indx;
694 for (indx = 0; indx < posCount; indx++) {
695 posPtr[indx].fX = positions[indx << 1];
696 posPtr[indx].fY = positions[(indx << 1) + 1];
697 }
698
699 SkPaint paintCopy(paint);
700 paintCopy.setTextEncoding(SkPaint::kUTF16_TextEncoding);
701 mCanvas->drawPosText(text, count, posPtr, paintCopy);
702
703 delete[] posPtr;
704 }
705
drawTextOnPath(const uint16_t * glyphs,int count,const SkPath & path,float hOffset,float vOffset,const SkPaint & paint)706 void SkiaCanvas::drawTextOnPath(const uint16_t* glyphs, int count, const SkPath& path,
707 float hOffset, float vOffset, const SkPaint& paint) {
708 mCanvas->drawTextOnPathHV(glyphs, count, path, hOffset, vOffset, paint);
709 }
710
711 } // namespace android
712