SkiaCanvas.cpp revision 62feb3a0b4690144a067080ab17beae160ea6320
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 "SkiaCanvas.h"
18
19#include "CanvasProperty.h"
20#include "VectorDrawable.h"
21#include "hwui/MinikinUtils.h"
22
23#include <SkDrawable.h>
24#include <SkDevice.h>
25#include <SkDeque.h>
26#include <SkDrawFilter.h>
27#include <SkGraphics.h>
28#include <SkImage.h>
29#include <SkImagePriv.h>
30#include <SkRSXform.h>
31#include <SkShader.h>
32#include <SkTemplates.h>
33
34#include <memory>
35
36namespace android {
37
38Canvas* Canvas::create_canvas(const SkBitmap& bitmap) {
39    return new SkiaCanvas(bitmap);
40}
41
42Canvas* Canvas::create_canvas(SkCanvas* skiaCanvas) {
43    return new SkiaCanvas(skiaCanvas);
44}
45
46SkiaCanvas::SkiaCanvas(const SkBitmap& bitmap) {
47    mCanvas.reset(new SkCanvas(bitmap));
48}
49
50void SkiaCanvas::reset(SkCanvas* skiaCanvas) {
51    mCanvas.reset(SkRef(skiaCanvas));
52    mSaveStack.reset(nullptr);
53    mHighContrastText = false;
54}
55
56// ----------------------------------------------------------------------------
57// Canvas state operations: Replace Bitmap
58// ----------------------------------------------------------------------------
59
60class ClipCopier : public SkCanvas::ClipVisitor {
61public:
62    explicit ClipCopier(SkCanvas* dstCanvas) : m_dstCanvas(dstCanvas) {}
63
64    virtual void clipRect(const SkRect& rect, SkRegion::Op op, bool antialias) {
65        m_dstCanvas->clipRect(rect, op, antialias);
66    }
67    virtual void clipRRect(const SkRRect& rrect, SkRegion::Op op, bool antialias) {
68        m_dstCanvas->clipRRect(rrect, op, antialias);
69    }
70    virtual void clipPath(const SkPath& path, SkRegion::Op op, bool antialias) {
71        m_dstCanvas->clipPath(path, op, antialias);
72    }
73
74private:
75    SkCanvas* m_dstCanvas;
76};
77
78void SkiaCanvas::setBitmap(const SkBitmap& bitmap) {
79    sk_sp<SkCanvas> newCanvas(new SkCanvas(bitmap));
80
81    if (!bitmap.isNull()) {
82        // Copy the canvas matrix & clip state.
83        newCanvas->setMatrix(mCanvas->getTotalMatrix());
84
85        ClipCopier copier(newCanvas.get());
86        mCanvas->replayClips(&copier);
87    }
88
89    // unrefs the existing canvas
90    mCanvas = std::move(newCanvas);
91
92    // clean up the old save stack
93    mSaveStack.reset(NULL);
94}
95
96// ----------------------------------------------------------------------------
97// Canvas state operations
98// ----------------------------------------------------------------------------
99
100bool SkiaCanvas::isOpaque() {
101    return mCanvas->imageInfo().isOpaque();
102}
103
104int SkiaCanvas::width() {
105    return mCanvas->imageInfo().width();
106}
107
108int SkiaCanvas::height() {
109    return mCanvas->imageInfo().height();
110}
111
112// ----------------------------------------------------------------------------
113// Canvas state operations: Save (layer)
114// ----------------------------------------------------------------------------
115
116int SkiaCanvas::getSaveCount() const {
117    return mCanvas->getSaveCount();
118}
119
120int SkiaCanvas::save(SaveFlags::Flags flags) {
121    int count = mCanvas->save();
122    recordPartialSave(flags);
123    return count;
124}
125
126// The SkiaCanvas::restore operation layers on the capability to preserve
127// either (or both) the matrix and/or clip state after a SkCanvas::restore
128// operation. It does this by explicitly saving off the clip & matrix state
129// when requested and playing it back after the SkCanvas::restore.
130void SkiaCanvas::restore() {
131    const SaveRec* rec = (NULL == mSaveStack.get())
132            ? NULL
133            : static_cast<SaveRec*>(mSaveStack->back());
134    int currentSaveCount = mCanvas->getSaveCount();
135    SkASSERT(NULL == rec || currentSaveCount >= rec->saveCount);
136
137    if (NULL == rec || rec->saveCount != currentSaveCount) {
138        // Fast path - no record for this frame.
139        mCanvas->restore();
140        return;
141    }
142
143    bool preserveMatrix = !(rec->saveFlags & SaveFlags::Matrix);
144    bool preserveClip   = !(rec->saveFlags & SaveFlags::Clip);
145
146    SkMatrix savedMatrix;
147    if (preserveMatrix) {
148        savedMatrix = mCanvas->getTotalMatrix();
149    }
150
151    SkTArray<SkClipStack::Element> savedClips;
152    int topClipStackFrame = mCanvas->getClipStack()->getSaveCount();
153    if (preserveClip) {
154        saveClipsForFrame(savedClips, topClipStackFrame);
155    }
156
157    mCanvas->restore();
158
159    if (preserveMatrix) {
160        mCanvas->setMatrix(savedMatrix);
161    }
162
163    if (preserveClip && !savedClips.empty() &&
164        topClipStackFrame != mCanvas->getClipStack()->getSaveCount()) {
165        // Only reapply the saved clips if the top clip stack frame was actually
166        // popped by restore().  If it wasn't, it means it doesn't belong to the
167        // restored canvas frame (SkCanvas lazy save/restore kicked in).
168        applyClips(savedClips);
169    }
170
171    mSaveStack->pop_back();
172}
173
174void SkiaCanvas::restoreToCount(int restoreCount) {
175    while (mCanvas->getSaveCount() > restoreCount) {
176        this->restore();
177    }
178}
179
180static inline SkCanvas::SaveLayerFlags layerFlags(SaveFlags::Flags flags) {
181    SkCanvas::SaveLayerFlags layerFlags = 0;
182
183    if (!(flags & SaveFlags::HasAlphaLayer)) {
184        layerFlags |= SkCanvas::kIsOpaque_SaveLayerFlag;
185    }
186
187    if (!(flags & SaveFlags::ClipToLayer)) {
188        layerFlags |= SkCanvas::kDontClipToLayer_Legacy_SaveLayerFlag;
189    }
190
191    return layerFlags;
192}
193
194int SkiaCanvas::saveLayer(float left, float top, float right, float bottom,
195            const SkPaint* paint, SaveFlags::Flags flags) {
196    const SkRect bounds = SkRect::MakeLTRB(left, top, right, bottom);
197    const SkCanvas::SaveLayerRec rec(&bounds, paint, layerFlags(flags));
198
199    int count = mCanvas->saveLayer(rec);
200    recordPartialSave(flags);
201    return count;
202}
203
204int SkiaCanvas::saveLayerAlpha(float left, float top, float right, float bottom,
205        int alpha, SaveFlags::Flags flags) {
206    if (static_cast<unsigned>(alpha) < 0xFF) {
207        SkPaint alphaPaint;
208        alphaPaint.setAlpha(alpha);
209        return this->saveLayer(left, top, right, bottom, &alphaPaint, flags);
210    }
211    return this->saveLayer(left, top, right, bottom, nullptr, flags);
212}
213
214// ----------------------------------------------------------------------------
215// functions to emulate legacy SaveFlags (i.e. independent matrix/clip flags)
216// ----------------------------------------------------------------------------
217
218void SkiaCanvas::recordPartialSave(SaveFlags::Flags flags) {
219    // A partial save is a save operation which doesn't capture the full canvas state.
220    // (either SaveFlags::Matrix or SaveFlags::Clip is missing).
221
222    // Mask-out non canvas state bits.
223    flags &= SaveFlags::MatrixClip;
224
225    if (flags == SaveFlags::MatrixClip) {
226        // not a partial save.
227        return;
228    }
229
230    if (NULL == mSaveStack.get()) {
231        mSaveStack.reset(new SkDeque(sizeof(struct SaveRec), 8));
232    }
233
234    SaveRec* rec = static_cast<SaveRec*>(mSaveStack->push_back());
235    rec->saveCount = mCanvas->getSaveCount();
236    rec->saveFlags = flags;
237}
238
239void SkiaCanvas::saveClipsForFrame(SkTArray<SkClipStack::Element>& clips,
240                                   int saveCountToBackup) {
241    // Each SkClipStack::Element stores the index of the canvas save
242    // with which it is associated. Backup only those Elements that
243    // are associated with 'saveCountToBackup'
244    SkClipStack::Iter clipIterator(*mCanvas->getClipStack(),
245                                   SkClipStack::Iter::kTop_IterStart);
246    while (const SkClipStack::Element* elem = clipIterator.prev()) {
247        if (elem->getSaveCount() < saveCountToBackup) {
248            // done with the target save count.
249            break;
250        }
251        SkASSERT(elem->getSaveCount() == saveCountToBackup);
252        clips.push_back(*elem);
253    }
254}
255
256void SkiaCanvas::applyClips(const SkTArray<SkClipStack::Element>& clips) {
257    ClipCopier clipCopier(mCanvas.get());
258
259    // The clip stack stores clips in device space.
260    SkMatrix origMatrix = mCanvas->getTotalMatrix();
261    mCanvas->resetMatrix();
262
263    // We pushed the clips in reverse order.
264    for (int i = clips.count() - 1; i >= 0; --i) {
265        clips[i].replay(&clipCopier);
266    }
267
268    mCanvas->setMatrix(origMatrix);
269}
270
271// ----------------------------------------------------------------------------
272// Canvas state operations: Matrix
273// ----------------------------------------------------------------------------
274
275void SkiaCanvas::getMatrix(SkMatrix* outMatrix) const {
276    *outMatrix = mCanvas->getTotalMatrix();
277}
278
279void SkiaCanvas::setMatrix(const SkMatrix& matrix) {
280    mCanvas->setMatrix(matrix);
281}
282
283void SkiaCanvas::concat(const SkMatrix& matrix) {
284    mCanvas->concat(matrix);
285}
286
287void SkiaCanvas::rotate(float degrees) {
288    mCanvas->rotate(degrees);
289}
290
291void SkiaCanvas::scale(float sx, float sy) {
292    mCanvas->scale(sx, sy);
293}
294
295void SkiaCanvas::skew(float sx, float sy) {
296    mCanvas->skew(sx, sy);
297}
298
299void SkiaCanvas::translate(float dx, float dy) {
300    mCanvas->translate(dx, dy);
301}
302
303// ----------------------------------------------------------------------------
304// Canvas state operations: Clips
305// ----------------------------------------------------------------------------
306
307// This function is a mirror of SkCanvas::getClipBounds except that it does
308// not outset the edge of the clip to account for anti-aliasing. There is
309// a skia bug to investigate pushing this logic into back into skia.
310// (see https://code.google.com/p/skia/issues/detail?id=1303)
311bool SkiaCanvas::getClipBounds(SkRect* outRect) const {
312    SkIRect ibounds;
313    if (!mCanvas->getClipDeviceBounds(&ibounds)) {
314        return false;
315    }
316
317    SkMatrix inverse;
318    // if we can't invert the CTM, we can't return local clip bounds
319    if (!mCanvas->getTotalMatrix().invert(&inverse)) {
320        if (outRect) {
321            outRect->setEmpty();
322        }
323        return false;
324    }
325
326    if (NULL != outRect) {
327        SkRect r = SkRect::Make(ibounds);
328        inverse.mapRect(outRect, r);
329    }
330    return true;
331}
332
333bool SkiaCanvas::quickRejectRect(float left, float top, float right, float bottom) const {
334    SkRect bounds = SkRect::MakeLTRB(left, top, right, bottom);
335    return mCanvas->quickReject(bounds);
336}
337
338bool SkiaCanvas::quickRejectPath(const SkPath& path) const {
339    return mCanvas->quickReject(path);
340}
341
342bool SkiaCanvas::clipRect(float left, float top, float right, float bottom, SkRegion::Op op) {
343    SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
344    mCanvas->clipRect(rect, op);
345    return !mCanvas->isClipEmpty();
346}
347
348bool SkiaCanvas::clipPath(const SkPath* path, SkRegion::Op op) {
349    SkRRect roundRect;
350    if (path->isRRect(&roundRect)) {
351        mCanvas->clipRRect(roundRect, op);
352    } else {
353        mCanvas->clipPath(*path, op);
354    }
355    return !mCanvas->isClipEmpty();
356}
357
358bool SkiaCanvas::clipRegion(const SkRegion* region, SkRegion::Op op) {
359    SkPath rgnPath;
360    if (region->getBoundaryPath(&rgnPath)) {
361        // The region is specified in device space.
362        SkMatrix savedMatrix = mCanvas->getTotalMatrix();
363        mCanvas->resetMatrix();
364        mCanvas->clipPath(rgnPath, op);
365        mCanvas->setMatrix(savedMatrix);
366    } else {
367        mCanvas->clipRect(SkRect::MakeEmpty(), op);
368    }
369    return !mCanvas->isClipEmpty();
370}
371
372// ----------------------------------------------------------------------------
373// Canvas state operations: Filters
374// ----------------------------------------------------------------------------
375
376SkDrawFilter* SkiaCanvas::getDrawFilter() {
377    return mCanvas->getDrawFilter();
378}
379
380void SkiaCanvas::setDrawFilter(SkDrawFilter* drawFilter) {
381    mCanvas->setDrawFilter(drawFilter);
382}
383
384// ----------------------------------------------------------------------------
385// Canvas draw operations
386// ----------------------------------------------------------------------------
387
388void SkiaCanvas::drawColor(int color, SkXfermode::Mode mode) {
389    mCanvas->drawColor(color, mode);
390}
391
392void SkiaCanvas::drawPaint(const SkPaint& paint) {
393    mCanvas->drawPaint(paint);
394}
395
396// ----------------------------------------------------------------------------
397// Canvas draw operations: Geometry
398// ----------------------------------------------------------------------------
399
400void SkiaCanvas::drawPoints(const float* points, int count, const SkPaint& paint,
401                            SkCanvas::PointMode mode) {
402    // convert the floats into SkPoints
403    count >>= 1;    // now it is the number of points
404    std::unique_ptr<SkPoint[]> pts(new SkPoint[count]);
405    for (int i = 0; i < count; i++) {
406        pts[i].set(points[0], points[1]);
407        points += 2;
408    }
409    mCanvas->drawPoints(mode, count, pts.get(), paint);
410}
411
412
413void SkiaCanvas::drawPoint(float x, float y, const SkPaint& paint) {
414    mCanvas->drawPoint(x, y, paint);
415}
416
417void SkiaCanvas::drawPoints(const float* points, int count, const SkPaint& paint) {
418    this->drawPoints(points, count, paint, SkCanvas::kPoints_PointMode);
419}
420
421void SkiaCanvas::drawLine(float startX, float startY, float stopX, float stopY,
422                          const SkPaint& paint) {
423    mCanvas->drawLine(startX, startY, stopX, stopY, paint);
424}
425
426void SkiaCanvas::drawLines(const float* points, int count, const SkPaint& paint) {
427    this->drawPoints(points, count, paint, SkCanvas::kLines_PointMode);
428}
429
430void SkiaCanvas::drawRect(float left, float top, float right, float bottom,
431        const SkPaint& paint) {
432    mCanvas->drawRectCoords(left, top, right, bottom, paint);
433
434}
435
436void SkiaCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
437    SkRegion::Iterator it(region);
438    while (!it.done()) {
439        mCanvas->drawRect(SkRect::Make(it.rect()), paint);
440        it.next();
441    }
442}
443
444void SkiaCanvas::drawRoundRect(float left, float top, float right, float bottom,
445        float rx, float ry, const SkPaint& paint) {
446    SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
447    mCanvas->drawRoundRect(rect, rx, ry, paint);
448}
449
450void SkiaCanvas::drawCircle(float x, float y, float radius, const SkPaint& paint) {
451    mCanvas->drawCircle(x, y, radius, paint);
452}
453
454void SkiaCanvas::drawOval(float left, float top, float right, float bottom, const SkPaint& paint) {
455    SkRect oval = SkRect::MakeLTRB(left, top, right, bottom);
456    mCanvas->drawOval(oval, paint);
457}
458
459void SkiaCanvas::drawArc(float left, float top, float right, float bottom,
460        float startAngle, float sweepAngle, bool useCenter, const SkPaint& paint) {
461    SkRect arc = SkRect::MakeLTRB(left, top, right, bottom);
462    mCanvas->drawArc(arc, startAngle, sweepAngle, useCenter, paint);
463}
464
465void SkiaCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
466    SkRect rect;
467    SkRRect roundRect;
468    if (path.isOval(&rect)) {
469        mCanvas->drawOval(rect, paint);
470    } else if (path.isRRect(&roundRect)) {
471        mCanvas->drawRRect(roundRect, paint);
472    } else {
473        mCanvas->drawPath(path, paint);
474    }
475}
476
477void SkiaCanvas::drawVertices(SkCanvas::VertexMode vertexMode, int vertexCount,
478                              const float* verts, const float* texs, const int* colors,
479                              const uint16_t* indices, int indexCount, const SkPaint& paint) {
480#ifndef SK_SCALAR_IS_FLOAT
481    SkDEBUGFAIL("SkScalar must be a float for these conversions to be valid");
482#endif
483    const int ptCount = vertexCount >> 1;
484    mCanvas->drawVertices(vertexMode, ptCount, (SkPoint*)verts, (SkPoint*)texs,
485                          (SkColor*)colors, NULL, indices, indexCount, paint);
486}
487
488// ----------------------------------------------------------------------------
489// Canvas draw operations: Bitmaps
490// ----------------------------------------------------------------------------
491
492void SkiaCanvas::drawBitmap(const SkBitmap& bitmap, float left, float top, const SkPaint* paint) {
493    mCanvas->drawBitmap(bitmap, left, top, paint);
494}
495
496void SkiaCanvas::drawBitmap(const SkBitmap& bitmap, const SkMatrix& matrix, const SkPaint* paint) {
497    SkAutoCanvasRestore acr(mCanvas.get(), true);
498    mCanvas->concat(matrix);
499    mCanvas->drawBitmap(bitmap, 0, 0, paint);
500}
501
502void SkiaCanvas::drawBitmap(const SkBitmap& bitmap, float srcLeft, float srcTop,
503                            float srcRight, float srcBottom, float dstLeft, float dstTop,
504                            float dstRight, float dstBottom, const SkPaint* paint) {
505    SkRect srcRect = SkRect::MakeLTRB(srcLeft, srcTop, srcRight, srcBottom);
506    SkRect dstRect = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom);
507    mCanvas->drawBitmapRect(bitmap, srcRect, dstRect, paint);
508}
509
510void SkiaCanvas::drawBitmapMesh(const SkBitmap& bitmap, int meshWidth, int meshHeight,
511        const float* vertices, const int* colors, const SkPaint* paint) {
512
513    const int ptCount = (meshWidth + 1) * (meshHeight + 1);
514    const int indexCount = meshWidth * meshHeight * 6;
515
516    /*  Our temp storage holds 2 or 3 arrays.
517        texture points [ptCount * sizeof(SkPoint)]
518        optionally vertex points [ptCount * sizeof(SkPoint)] if we need a
519            copy to convert from float to fixed
520        indices [ptCount * sizeof(uint16_t)]
521    */
522    ssize_t storageSize = ptCount * sizeof(SkPoint); // texs[]
523    storageSize += indexCount * sizeof(uint16_t);  // indices[]
524
525
526#ifndef SK_SCALAR_IS_FLOAT
527    SkDEBUGFAIL("SkScalar must be a float for these conversions to be valid");
528#endif
529    std::unique_ptr<char[]> storage(new char[storageSize]);
530    SkPoint* texs = (SkPoint*)storage.get();
531    uint16_t* indices = (uint16_t*)(texs + ptCount);
532
533    // cons up texture coordinates and indices
534    {
535        const SkScalar w = SkIntToScalar(bitmap.width());
536        const SkScalar h = SkIntToScalar(bitmap.height());
537        const SkScalar dx = w / meshWidth;
538        const SkScalar dy = h / meshHeight;
539
540        SkPoint* texsPtr = texs;
541        SkScalar y = 0;
542        for (int i = 0; i <= meshHeight; i++) {
543            if (i == meshHeight) {
544                y = h;  // to ensure numerically we hit h exactly
545            }
546            SkScalar x = 0;
547            for (int j = 0; j < meshWidth; j++) {
548                texsPtr->set(x, y);
549                texsPtr += 1;
550                x += dx;
551            }
552            texsPtr->set(w, y);
553            texsPtr += 1;
554            y += dy;
555        }
556        SkASSERT(texsPtr - texs == ptCount);
557    }
558
559    // cons up indices
560    {
561        uint16_t* indexPtr = indices;
562        int index = 0;
563        for (int i = 0; i < meshHeight; i++) {
564            for (int j = 0; j < meshWidth; j++) {
565                // lower-left triangle
566                *indexPtr++ = index;
567                *indexPtr++ = index + meshWidth + 1;
568                *indexPtr++ = index + meshWidth + 2;
569                // upper-right triangle
570                *indexPtr++ = index;
571                *indexPtr++ = index + meshWidth + 2;
572                *indexPtr++ = index + 1;
573                // bump to the next cell
574                index += 1;
575            }
576            // bump to the next row
577            index += 1;
578        }
579        SkASSERT(indexPtr - indices == indexCount);
580        SkASSERT((char*)indexPtr - (char*)storage.get() == storageSize);
581    }
582
583    // double-check that we have legal indices
584#ifdef SK_DEBUG
585    {
586        for (int i = 0; i < indexCount; i++) {
587            SkASSERT((unsigned)indices[i] < (unsigned)ptCount);
588        }
589    }
590#endif
591
592    // cons-up a shader for the bitmap
593    SkPaint tmpPaint;
594    if (paint) {
595        tmpPaint = *paint;
596    }
597    sk_sp<SkShader> shader = SkMakeBitmapShader(bitmap,
598                                                SkShader::kClamp_TileMode,
599                                                SkShader::kClamp_TileMode,
600                                                nullptr,
601                                                kNever_SkCopyPixelsMode,
602                                                nullptr);
603    tmpPaint.setShader(std::move(shader));
604
605    mCanvas->drawVertices(SkCanvas::kTriangles_VertexMode, ptCount, (SkPoint*)vertices,
606                         texs, (const SkColor*)colors, NULL, indices,
607                         indexCount, tmpPaint);
608}
609
610void SkiaCanvas::drawNinePatch(const SkBitmap& bitmap, const Res_png_9patch& chunk,
611        float dstLeft, float dstTop, float dstRight, float dstBottom, const SkPaint* paint) {
612    SkRect bounds = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom);
613    NinePatch::Draw(mCanvas.get(), bounds, bitmap, chunk, paint, nullptr);
614}
615
616void SkiaCanvas::drawVectorDrawable(VectorDrawableRoot* vectorDrawable) {
617    vectorDrawable->drawStaging(this);
618}
619
620// ----------------------------------------------------------------------------
621// Canvas draw operations: Text
622// ----------------------------------------------------------------------------
623
624void SkiaCanvas::drawGlyphs(const uint16_t* text, const float* positions, int count,
625        const SkPaint& paint, float x, float y,
626        float boundsLeft, float boundsTop, float boundsRight, float boundsBottom,
627        float totalAdvance) {
628    static_assert(sizeof(SkPoint) == sizeof(float)*2, "SkPoint is no longer two floats");
629    mCanvas->drawPosText(text, count << 1, reinterpret_cast<const SkPoint*>(positions), paint);
630    drawTextDecorations(x, y, totalAdvance, paint);
631}
632
633void SkiaCanvas::drawLayoutOnPath(const minikin::Layout& layout, float hOffset, float vOffset,
634        const SkPaint& paint, const SkPath& path, size_t start, size_t end) {
635    const int N = end - start;
636    SkAutoSMalloc<1024> storage(N * (sizeof(uint16_t) + sizeof(SkRSXform)));
637    SkRSXform* xform = (SkRSXform*)storage.get();
638    uint16_t* glyphs = (uint16_t*)(xform + N);
639    SkPathMeasure meas(path, false);
640
641    for (size_t i = start; i < end; i++) {
642        glyphs[i - start] = layout.getGlyphId(i);
643        float x = hOffset + layout.getX(i);
644        float y = vOffset + layout.getY(i);
645
646        SkPoint pos;
647        SkVector tan;
648        if (!meas.getPosTan(x, &pos, &tan)) {
649            pos.set(x, y);
650            tan.set(1, 0);
651        }
652        xform[i - start].fSCos = tan.x();
653        xform[i - start].fSSin = tan.y();
654        xform[i - start].fTx   = pos.x() - tan.y() * y;
655        xform[i - start].fTy   = pos.y() + tan.x() * y;
656    }
657
658    this->asSkCanvas()->drawTextRSXform(glyphs, sizeof(uint16_t) * N, xform, nullptr, paint);
659}
660
661// ----------------------------------------------------------------------------
662// Canvas draw operations: Animations
663// ----------------------------------------------------------------------------
664
665class AnimatedRoundRect : public SkDrawable {
666 public:
667    AnimatedRoundRect(uirenderer::CanvasPropertyPrimitive* left,
668            uirenderer::CanvasPropertyPrimitive* top, uirenderer::CanvasPropertyPrimitive* right,
669            uirenderer::CanvasPropertyPrimitive* bottom, uirenderer::CanvasPropertyPrimitive* rx,
670            uirenderer::CanvasPropertyPrimitive* ry, uirenderer::CanvasPropertyPaint* p) :
671            mLeft(left), mTop(top), mRight(right), mBottom(bottom), mRx(rx), mRy(ry), mPaint(p) {}
672
673 protected:
674     virtual SkRect onGetBounds() override {
675         return SkRect::MakeLTRB(mLeft->value, mTop->value, mRight->value, mBottom->value);
676     }
677     virtual void onDraw(SkCanvas* canvas) override {
678         SkRect rect = SkRect::MakeLTRB(mLeft->value, mTop->value, mRight->value, mBottom->value);
679         canvas->drawRoundRect(rect, mRx->value, mRy->value, mPaint->value);
680     }
681
682 private:
683    sp<uirenderer::CanvasPropertyPrimitive> mLeft;
684    sp<uirenderer::CanvasPropertyPrimitive> mTop;
685    sp<uirenderer::CanvasPropertyPrimitive> mRight;
686    sp<uirenderer::CanvasPropertyPrimitive> mBottom;
687    sp<uirenderer::CanvasPropertyPrimitive> mRx;
688    sp<uirenderer::CanvasPropertyPrimitive> mRy;
689    sp<uirenderer::CanvasPropertyPaint> mPaint;
690};
691
692class AnimatedCircle : public SkDrawable {
693 public:
694    AnimatedCircle(uirenderer::CanvasPropertyPrimitive* x, uirenderer::CanvasPropertyPrimitive* y,
695            uirenderer::CanvasPropertyPrimitive* radius, uirenderer::CanvasPropertyPaint* paint) :
696            mX(x), mY(y), mRadius(radius), mPaint(paint) {}
697
698 protected:
699     virtual SkRect onGetBounds() override {
700         const float x = mX->value;
701         const float y = mY->value;
702         const float radius = mRadius->value;
703         return SkRect::MakeLTRB(x - radius, y - radius, x + radius, y + radius);
704     }
705     virtual void onDraw(SkCanvas* canvas) override {
706         canvas->drawCircle(mX->value, mY->value, mRadius->value, mPaint->value);
707     }
708
709 private:
710    sp<uirenderer::CanvasPropertyPrimitive> mX;
711    sp<uirenderer::CanvasPropertyPrimitive> mY;
712    sp<uirenderer::CanvasPropertyPrimitive> mRadius;
713    sp<uirenderer::CanvasPropertyPaint> mPaint;
714};
715
716void SkiaCanvas::drawRoundRect(uirenderer::CanvasPropertyPrimitive* left,
717        uirenderer::CanvasPropertyPrimitive* top, uirenderer::CanvasPropertyPrimitive* right,
718        uirenderer::CanvasPropertyPrimitive* bottom, uirenderer::CanvasPropertyPrimitive* rx,
719        uirenderer::CanvasPropertyPrimitive* ry, uirenderer::CanvasPropertyPaint* paint) {
720    sk_sp<AnimatedRoundRect> drawable(
721            new AnimatedRoundRect(left, top, right, bottom, rx, ry, paint));
722    mCanvas->drawDrawable(drawable.get());
723}
724
725void SkiaCanvas::drawCircle(uirenderer::CanvasPropertyPrimitive* x, uirenderer::CanvasPropertyPrimitive* y,
726        uirenderer::CanvasPropertyPrimitive* radius, uirenderer::CanvasPropertyPaint* paint) {
727    sk_sp<AnimatedCircle> drawable(new AnimatedCircle(x, y, radius, paint));
728    mCanvas->drawDrawable(drawable.get());
729}
730
731// ----------------------------------------------------------------------------
732// Canvas draw operations: View System
733// ----------------------------------------------------------------------------
734
735void SkiaCanvas::drawLayer(uirenderer::DeferredLayerUpdater* layer) {
736    LOG_ALWAYS_FATAL("SkiaCanvas can't directly draw Layers");
737}
738
739void SkiaCanvas::drawRenderNode(uirenderer::RenderNode* renderNode) {
740    LOG_ALWAYS_FATAL("SkiaCanvas can't directly draw RenderNodes");
741}
742
743void SkiaCanvas::callDrawGLFunction(Functor* functor,
744        uirenderer::GlFunctorLifecycleListener* listener) {
745    LOG_ALWAYS_FATAL("SkiaCanvas can't directly draw GL Content");
746}
747
748} // namespace android
749