blob: ba343841d760117ab6bd4fa7c6657b6aefdacf3a [file] [log] [blame]
Derek Sollenberger8872b382014-06-23 14:13:53 -04001/*
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
Derek Sollenbergerc1908132016-07-15 10:28:16 -040017#include "SkiaCanvas.h"
Derek Sollenberger8872b382014-06-23 14:13:53 -040018
Derek Sollenbergerc1908132016-07-15 10:28:16 -040019#include "CanvasProperty.h"
Matt Sarett7de73852016-10-25 18:36:39 -040020#include "NinePatchUtils.h"
Derek Sollenbergerc1908132016-07-15 10:28:16 -040021#include "VectorDrawable.h"
sergeyvaed7f582016-10-14 16:30:21 -070022#include "hwui/Bitmap.h"
Yuqian Liafc221492016-07-18 13:07:42 -040023#include "hwui/MinikinUtils.h"
Ben Wagner0ed10be2018-06-28 17:08:16 -040024#include "hwui/PaintFilter.h"
Stan Iliev021693b2016-10-17 16:26:15 -040025#include "pipeline/skia/AnimatedDrawables.h"
Derek Sollenbergerc1908132016-07-15 10:28:16 -040026
Leon Scroggins III671cce22018-01-14 16:52:17 -050027#include <SkAnimatedImage.h>
Matt Sarettd0814db2017-04-13 09:33:18 -040028#include <SkCanvasStateUtils.h>
Derek Sollenbergerfb0c8fc2017-07-26 13:53:27 -040029#include <SkColorFilter.h>
John Reck849911a2015-01-20 07:51:14 -080030#include <SkDeque.h>
John Reck1bcacfd2017-11-03 10:12:19 -070031#include <SkDrawable.h>
Mike Reed1c79eab2018-11-21 11:01:57 -050032#include <SkFont.h>
John Reck849911a2015-01-20 07:51:14 -080033#include <SkGraphics.h>
Derek Sollenberger6f485562015-07-30 10:00:39 -040034#include <SkImage.h>
Matt Sarett62feb3a2016-09-20 10:34:11 -040035#include <SkImagePriv.h>
Leon Scroggins III671cce22018-01-14 16:52:17 -050036#include <SkPicture.h>
Yuqian Liafc221492016-07-18 13:07:42 -040037#include <SkRSXform.h>
John Reck849911a2015-01-20 07:51:14 -080038#include <SkShader.h>
John Reck849911a2015-01-20 07:51:14 -080039#include <SkTemplates.h>
Stan Ilievf50806a2016-10-24 10:40:39 -040040#include <SkTextBlob.h>
Derek Sollenberger8872b382014-06-23 14:13:53 -040041
Ben Wagner60126ef2015-08-07 12:13:48 -040042#include <memory>
Ben Wagner0ed10be2018-06-28 17:08:16 -040043#include <optional>
44#include <utility>
Ben Wagner60126ef2015-08-07 12:13:48 -040045
Derek Sollenberger8872b382014-06-23 14:13:53 -040046namespace android {
47
Stan Ilievf50806a2016-10-24 10:40:39 -040048using uirenderer::PaintUtils;
49
John Reckc1b33d62015-04-22 09:04:45 -070050Canvas* Canvas::create_canvas(const SkBitmap& bitmap) {
Derek Sollenberger8872b382014-06-23 14:13:53 -040051 return new SkiaCanvas(bitmap);
52}
53
Derek Sollenbergerfa3e3402017-08-04 08:35:10 -040054Canvas* Canvas::create_canvas(SkCanvas* skiaCanvas) {
55 return new SkiaCanvas(skiaCanvas);
Derek Sollenberger8872b382014-06-23 14:13:53 -040056}
57
Stan Ilievf50806a2016-10-24 10:40:39 -040058SkiaCanvas::SkiaCanvas() {}
59
Derek Sollenbergerfa3e3402017-08-04 08:35:10 -040060SkiaCanvas::SkiaCanvas(SkCanvas* canvas) : mCanvas(canvas) {}
Stan Ilievf50806a2016-10-24 10:40:39 -040061
John Reckc1b33d62015-04-22 09:04:45 -070062SkiaCanvas::SkiaCanvas(const SkBitmap& bitmap) {
Derek Sollenbergerd01b5912018-10-19 15:55:33 -040063 mCanvasOwned = std::unique_ptr<SkCanvas>(new SkCanvas(bitmap));
64 mCanvas = mCanvasOwned.get();
Derek Sollenberger8872b382014-06-23 14:13:53 -040065}
66
Stan Iliev021693b2016-10-17 16:26:15 -040067SkiaCanvas::~SkiaCanvas() {}
68
Derek Sollenbergerc1908132016-07-15 10:28:16 -040069void SkiaCanvas::reset(SkCanvas* skiaCanvas) {
Mike Reed6acfe162016-11-18 17:21:09 -050070 if (mCanvas != skiaCanvas) {
71 mCanvas = skiaCanvas;
72 mCanvasOwned.reset();
73 }
Derek Sollenbergerc1908132016-07-15 10:28:16 -040074 mSaveStack.reset(nullptr);
Derek Sollenbergerc1908132016-07-15 10:28:16 -040075}
76
Derek Sollenberger8872b382014-06-23 14:13:53 -040077// ----------------------------------------------------------------------------
78// Canvas state operations: Replace Bitmap
79// ----------------------------------------------------------------------------
80
John Reckc1b33d62015-04-22 09:04:45 -070081void SkiaCanvas::setBitmap(const SkBitmap& bitmap) {
Tony Mantler4f641d12017-03-14 22:36:14 +000082 // deletes the previously owned canvas (if any)
Derek Sollenbergerd01b5912018-10-19 15:55:33 -040083 mCanvasOwned.reset(new SkCanvas(bitmap));
84 mCanvas = mCanvasOwned.get();
Tony Mantler4f641d12017-03-14 22:36:14 +000085
Derek Sollenberger8872b382014-06-23 14:13:53 -040086 // clean up the old save stack
Stan Ilievf50806a2016-10-24 10:40:39 -040087 mSaveStack.reset(nullptr);
Derek Sollenberger8872b382014-06-23 14:13:53 -040088}
89
90// ----------------------------------------------------------------------------
91// Canvas state operations
92// ----------------------------------------------------------------------------
93
94bool SkiaCanvas::isOpaque() {
Leon Scroggins IIIf35b9892015-07-31 10:38:40 -040095 return mCanvas->imageInfo().isOpaque();
Derek Sollenberger8872b382014-06-23 14:13:53 -040096}
97
98int SkiaCanvas::width() {
Leon Scroggins IIIf35b9892015-07-31 10:38:40 -040099 return mCanvas->imageInfo().width();
Derek Sollenberger8872b382014-06-23 14:13:53 -0400100}
101
102int SkiaCanvas::height() {
Leon Scroggins IIIf35b9892015-07-31 10:38:40 -0400103 return mCanvas->imageInfo().height();
Derek Sollenberger8872b382014-06-23 14:13:53 -0400104}
105
106// ----------------------------------------------------------------------------
107// Canvas state operations: Save (layer)
108// ----------------------------------------------------------------------------
109
110int SkiaCanvas::getSaveCount() const {
111 return mCanvas->getSaveCount();
112}
113
Florin Malitaeecff562015-12-21 10:43:01 -0500114int SkiaCanvas::save(SaveFlags::Flags flags) {
Derek Sollenberger8872b382014-06-23 14:13:53 -0400115 int count = mCanvas->save();
116 recordPartialSave(flags);
117 return count;
118}
119
Florin Malita5e271402015-11-04 14:36:02 -0500120// The SkiaCanvas::restore operation layers on the capability to preserve
121// either (or both) the matrix and/or clip state after a SkCanvas::restore
122// operation. It does this by explicitly saving off the clip & matrix state
123// when requested and playing it back after the SkCanvas::restore.
Derek Sollenberger8872b382014-06-23 14:13:53 -0400124void SkiaCanvas::restore() {
Stan Ilievf50806a2016-10-24 10:40:39 -0400125 const auto* rec = this->currentSaveRec();
126 if (!rec) {
Derek Sollenberger8872b382014-06-23 14:13:53 -0400127 // Fast path - no record for this frame.
128 mCanvas->restore();
129 return;
130 }
131
Florin Malitaeecff562015-12-21 10:43:01 -0500132 bool preserveMatrix = !(rec->saveFlags & SaveFlags::Matrix);
John Reck1bcacfd2017-11-03 10:12:19 -0700133 bool preserveClip = !(rec->saveFlags & SaveFlags::Clip);
Derek Sollenberger8872b382014-06-23 14:13:53 -0400134
135 SkMatrix savedMatrix;
136 if (preserveMatrix) {
137 savedMatrix = mCanvas->getTotalMatrix();
138 }
139
Stan Ilievf50806a2016-10-24 10:40:39 -0400140 const size_t clipIndex = rec->clipIndex;
Derek Sollenberger8872b382014-06-23 14:13:53 -0400141
142 mCanvas->restore();
Stan Ilievf50806a2016-10-24 10:40:39 -0400143 mSaveStack->pop_back();
Derek Sollenberger8872b382014-06-23 14:13:53 -0400144
145 if (preserveMatrix) {
146 mCanvas->setMatrix(savedMatrix);
147 }
148
Stan Ilievf50806a2016-10-24 10:40:39 -0400149 if (preserveClip) {
150 this->applyPersistentClips(clipIndex);
Derek Sollenberger8872b382014-06-23 14:13:53 -0400151 }
Derek Sollenberger8872b382014-06-23 14:13:53 -0400152}
153
154void SkiaCanvas::restoreToCount(int restoreCount) {
155 while (mCanvas->getSaveCount() > restoreCount) {
156 this->restore();
157 }
158}
159
Florin Malitaeecff562015-12-21 10:43:01 -0500160static inline SkCanvas::SaveLayerFlags layerFlags(SaveFlags::Flags flags) {
161 SkCanvas::SaveLayerFlags layerFlags = 0;
162
Florin Malitaeecff562015-12-21 10:43:01 -0500163 if (!(flags & SaveFlags::ClipToLayer)) {
164 layerFlags |= SkCanvas::kDontClipToLayer_Legacy_SaveLayerFlag;
165 }
166
167 return layerFlags;
168}
169
John Reck1bcacfd2017-11-03 10:12:19 -0700170int SkiaCanvas::saveLayer(float left, float top, float right, float bottom, const SkPaint* paint,
171 SaveFlags::Flags flags) {
Florin Malitaeecff562015-12-21 10:43:01 -0500172 const SkRect bounds = SkRect::MakeLTRB(left, top, right, bottom);
Derek Sollenbergerb8201192017-01-09 16:11:59 -0500173 const SkCanvas::SaveLayerRec rec(&bounds, paint, layerFlags(flags));
Florin Malitaeecff562015-12-21 10:43:01 -0500174
Stan Iliev68885e32016-12-14 11:18:34 -0500175 return mCanvas->saveLayer(rec);
Derek Sollenberger8872b382014-06-23 14:13:53 -0400176}
177
John Reck1bcacfd2017-11-03 10:12:19 -0700178int SkiaCanvas::saveLayerAlpha(float left, float top, float right, float bottom, int alpha,
179 SaveFlags::Flags flags) {
Florin Malitaeecff562015-12-21 10:43:01 -0500180 if (static_cast<unsigned>(alpha) < 0xFF) {
Yuqian Lifd92ee42016-04-27 17:03:38 -0400181 SkPaint alphaPaint;
182 alphaPaint.setAlpha(alpha);
183 return this->saveLayer(left, top, right, bottom, &alphaPaint, flags);
Florin Malitaeecff562015-12-21 10:43:01 -0500184 }
Yuqian Lifd92ee42016-04-27 17:03:38 -0400185 return this->saveLayer(left, top, right, bottom, nullptr, flags);
Derek Sollenberger8872b382014-06-23 14:13:53 -0400186}
187
Stan Ilievf50806a2016-10-24 10:40:39 -0400188class SkiaCanvas::Clip {
189public:
Mike Reed6e49c9f2016-12-02 15:36:59 -0500190 Clip(const SkRect& rect, SkClipOp op, const SkMatrix& m)
John Reck1bcacfd2017-11-03 10:12:19 -0700191 : mType(Type::Rect), mOp(op), mMatrix(m), mRRect(SkRRect::MakeRect(rect)) {}
Mike Reed6e49c9f2016-12-02 15:36:59 -0500192 Clip(const SkRRect& rrect, SkClipOp op, const SkMatrix& m)
John Reck1bcacfd2017-11-03 10:12:19 -0700193 : mType(Type::RRect), mOp(op), mMatrix(m), mRRect(rrect) {}
Mike Reed6e49c9f2016-12-02 15:36:59 -0500194 Clip(const SkPath& path, SkClipOp op, const SkMatrix& m)
Ben Wagner0ed10be2018-06-28 17:08:16 -0400195 : mType(Type::Path), mOp(op), mMatrix(m), mPath(std::in_place, path) {}
Stan Ilievf50806a2016-10-24 10:40:39 -0400196
197 void apply(SkCanvas* canvas) const {
198 canvas->setMatrix(mMatrix);
199 switch (mType) {
John Reck1bcacfd2017-11-03 10:12:19 -0700200 case Type::Rect:
201 canvas->clipRect(mRRect.rect(), mOp);
202 break;
203 case Type::RRect:
204 canvas->clipRRect(mRRect, mOp);
205 break;
206 case Type::Path:
Ben Wagner0ed10be2018-06-28 17:08:16 -0400207 canvas->clipPath(mPath.value(), mOp);
John Reck1bcacfd2017-11-03 10:12:19 -0700208 break;
Stan Ilievf50806a2016-10-24 10:40:39 -0400209 }
210 }
211
212private:
213 enum class Type {
214 Rect,
215 RRect,
216 Path,
217 };
218
John Reck1bcacfd2017-11-03 10:12:19 -0700219 Type mType;
220 SkClipOp mOp;
221 SkMatrix mMatrix;
Stan Ilievf50806a2016-10-24 10:40:39 -0400222
223 // These are logically a union (tracked separately due to non-POD path).
Ben Wagner0ed10be2018-06-28 17:08:16 -0400224 std::optional<SkPath> mPath;
John Reck1bcacfd2017-11-03 10:12:19 -0700225 SkRRect mRRect;
Stan Ilievf50806a2016-10-24 10:40:39 -0400226};
227
228const SkiaCanvas::SaveRec* SkiaCanvas::currentSaveRec() const {
John Reck1bcacfd2017-11-03 10:12:19 -0700229 const SaveRec* rec = mSaveStack ? static_cast<const SaveRec*>(mSaveStack->back()) : nullptr;
Stan Ilievf50806a2016-10-24 10:40:39 -0400230 int currentSaveCount = mCanvas->getSaveCount();
231 SkASSERT(!rec || currentSaveCount >= rec->saveCount);
232
233 return (rec && rec->saveCount == currentSaveCount) ? rec : nullptr;
234}
235
Derek Sollenberger8872b382014-06-23 14:13:53 -0400236// ----------------------------------------------------------------------------
237// functions to emulate legacy SaveFlags (i.e. independent matrix/clip flags)
238// ----------------------------------------------------------------------------
239
Florin Malitaeecff562015-12-21 10:43:01 -0500240void SkiaCanvas::recordPartialSave(SaveFlags::Flags flags) {
Derek Sollenberger8872b382014-06-23 14:13:53 -0400241 // A partial save is a save operation which doesn't capture the full canvas state.
Florin Malitaeecff562015-12-21 10:43:01 -0500242 // (either SaveFlags::Matrix or SaveFlags::Clip is missing).
Derek Sollenberger8872b382014-06-23 14:13:53 -0400243
244 // Mask-out non canvas state bits.
Florin Malitaeecff562015-12-21 10:43:01 -0500245 flags &= SaveFlags::MatrixClip;
Derek Sollenberger8872b382014-06-23 14:13:53 -0400246
Florin Malitaeecff562015-12-21 10:43:01 -0500247 if (flags == SaveFlags::MatrixClip) {
Derek Sollenberger8872b382014-06-23 14:13:53 -0400248 // not a partial save.
249 return;
250 }
251
Stan Ilievf50806a2016-10-24 10:40:39 -0400252 if (!mSaveStack) {
Ben Wagnerd1cbc162015-08-19 12:45:09 -0400253 mSaveStack.reset(new SkDeque(sizeof(struct SaveRec), 8));
Derek Sollenberger8872b382014-06-23 14:13:53 -0400254 }
255
256 SaveRec* rec = static_cast<SaveRec*>(mSaveStack->push_back());
Florin Malita5e271402015-11-04 14:36:02 -0500257 rec->saveCount = mCanvas->getSaveCount();
Derek Sollenberger8872b382014-06-23 14:13:53 -0400258 rec->saveFlags = flags;
Stan Ilievf50806a2016-10-24 10:40:39 -0400259 rec->clipIndex = mClipStack.size();
Derek Sollenberger8872b382014-06-23 14:13:53 -0400260}
261
Stan Ilievf50806a2016-10-24 10:40:39 -0400262template <typename T>
Mike Reed6e49c9f2016-12-02 15:36:59 -0500263void SkiaCanvas::recordClip(const T& clip, SkClipOp op) {
Stan Ilievf50806a2016-10-24 10:40:39 -0400264 // Only need tracking when in a partial save frame which
265 // doesn't restore the clip.
266 const SaveRec* rec = this->currentSaveRec();
267 if (rec && !(rec->saveFlags & SaveFlags::Clip)) {
268 mClipStack.emplace_back(clip, op, mCanvas->getTotalMatrix());
Derek Sollenberger8872b382014-06-23 14:13:53 -0400269 }
270}
271
Stan Ilievf50806a2016-10-24 10:40:39 -0400272// Applies and optionally removes all clips >= index.
273void SkiaCanvas::applyPersistentClips(size_t clipStartIndex) {
274 SkASSERT(clipStartIndex <= mClipStack.size());
275 const auto begin = mClipStack.cbegin() + clipStartIndex;
276 const auto end = mClipStack.cend();
Derek Sollenberger8872b382014-06-23 14:13:53 -0400277
Stan Ilievf50806a2016-10-24 10:40:39 -0400278 // Clip application mutates the CTM.
279 const SkMatrix saveMatrix = mCanvas->getTotalMatrix();
Derek Sollenberger8872b382014-06-23 14:13:53 -0400280
Stan Ilievf50806a2016-10-24 10:40:39 -0400281 for (auto clip = begin; clip != end; ++clip) {
Mike Reed6acfe162016-11-18 17:21:09 -0500282 clip->apply(mCanvas);
Derek Sollenberger8872b382014-06-23 14:13:53 -0400283 }
284
Stan Ilievf50806a2016-10-24 10:40:39 -0400285 mCanvas->setMatrix(saveMatrix);
286
287 // If the current/post-restore save rec is also persisting clips, we
288 // leave them on the stack to be reapplied part of the next restore().
289 // Otherwise we're done and just pop them.
290 const auto* rec = this->currentSaveRec();
291 if (!rec || (rec->saveFlags & SaveFlags::Clip)) {
292 mClipStack.erase(begin, end);
293 }
Derek Sollenberger8872b382014-06-23 14:13:53 -0400294}
295
296// ----------------------------------------------------------------------------
297// Canvas state operations: Matrix
298// ----------------------------------------------------------------------------
299
300void SkiaCanvas::getMatrix(SkMatrix* outMatrix) const {
301 *outMatrix = mCanvas->getTotalMatrix();
302}
303
304void SkiaCanvas::setMatrix(const SkMatrix& matrix) {
305 mCanvas->setMatrix(matrix);
306}
307
308void SkiaCanvas::concat(const SkMatrix& matrix) {
309 mCanvas->concat(matrix);
310}
311
312void SkiaCanvas::rotate(float degrees) {
313 mCanvas->rotate(degrees);
314}
315
316void SkiaCanvas::scale(float sx, float sy) {
317 mCanvas->scale(sx, sy);
318}
319
320void SkiaCanvas::skew(float sx, float sy) {
321 mCanvas->skew(sx, sy);
322}
323
324void SkiaCanvas::translate(float dx, float dy) {
325 mCanvas->translate(dx, dy);
326}
327
328// ----------------------------------------------------------------------------
329// Canvas state operations: Clips
330// ----------------------------------------------------------------------------
331
332// This function is a mirror of SkCanvas::getClipBounds except that it does
333// not outset the edge of the clip to account for anti-aliasing. There is
334// a skia bug to investigate pushing this logic into back into skia.
335// (see https://code.google.com/p/skia/issues/detail?id=1303)
336bool SkiaCanvas::getClipBounds(SkRect* outRect) const {
337 SkIRect ibounds;
Mike Reed5e438982017-01-25 08:23:25 -0500338 if (!mCanvas->getDeviceClipBounds(&ibounds)) {
Derek Sollenberger8872b382014-06-23 14:13:53 -0400339 return false;
340 }
341
342 SkMatrix inverse;
343 // if we can't invert the CTM, we can't return local clip bounds
344 if (!mCanvas->getTotalMatrix().invert(&inverse)) {
345 if (outRect) {
346 outRect->setEmpty();
347 }
348 return false;
349 }
350
351 if (NULL != outRect) {
352 SkRect r = SkRect::Make(ibounds);
353 inverse.mapRect(outRect, r);
354 }
355 return true;
356}
357
358bool SkiaCanvas::quickRejectRect(float left, float top, float right, float bottom) const {
359 SkRect bounds = SkRect::MakeLTRB(left, top, right, bottom);
360 return mCanvas->quickReject(bounds);
361}
362
363bool SkiaCanvas::quickRejectPath(const SkPath& path) const {
364 return mCanvas->quickReject(path);
365}
366
Mike Reed6e49c9f2016-12-02 15:36:59 -0500367bool SkiaCanvas::clipRect(float left, float top, float right, float bottom, SkClipOp op) {
Derek Sollenberger8872b382014-06-23 14:13:53 -0400368 SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
Stan Ilievf50806a2016-10-24 10:40:39 -0400369 this->recordClip(rect, op);
Derek Sollenberger8872b382014-06-23 14:13:53 -0400370 mCanvas->clipRect(rect, op);
Chris Craik5ec6a282015-06-23 15:42:12 -0700371 return !mCanvas->isClipEmpty();
Derek Sollenberger8872b382014-06-23 14:13:53 -0400372}
373
Mike Reed6e49c9f2016-12-02 15:36:59 -0500374bool SkiaCanvas::clipPath(const SkPath* path, SkClipOp op) {
Derek Sollenbergerf7d98f42017-04-17 11:27:36 -0400375 this->recordClip(*path, op);
376 mCanvas->clipPath(*path, op);
Chris Craik5ec6a282015-06-23 15:42:12 -0700377 return !mCanvas->isClipEmpty();
Derek Sollenberger8872b382014-06-23 14:13:53 -0400378}
379
Derek Sollenberger8872b382014-06-23 14:13:53 -0400380// ----------------------------------------------------------------------------
381// Canvas state operations: Filters
382// ----------------------------------------------------------------------------
383
Ben Wagner0ed10be2018-06-28 17:08:16 -0400384PaintFilter* SkiaCanvas::getPaintFilter() {
385 return mPaintFilter.get();
Derek Sollenbergeracb40992014-07-21 15:22:10 -0400386}
387
Ben Wagner0ed10be2018-06-28 17:08:16 -0400388void SkiaCanvas::setPaintFilter(sk_sp<PaintFilter> paintFilter) {
389 mPaintFilter = std::move(paintFilter);
Derek Sollenberger8872b382014-06-23 14:13:53 -0400390}
391
392// ----------------------------------------------------------------------------
Matt Sarettd0814db2017-04-13 09:33:18 -0400393// Canvas state operations: Capture
394// ----------------------------------------------------------------------------
395
396SkCanvasState* SkiaCanvas::captureCanvasState() const {
397 SkCanvas* canvas = mCanvas;
398 if (mCanvasOwned) {
399 // Important to use the underlying SkCanvas, not the wrapper.
400 canvas = mCanvasOwned.get();
401 }
402
403 // Workarounds for http://crbug.com/271096: SW draw only supports
404 // translate & scale transforms, and a simple rectangular clip.
405 // (This also avoids significant wasted time in calling
406 // SkCanvasStateUtils::CaptureCanvasState when the clip is complex).
John Reck1bcacfd2017-11-03 10:12:19 -0700407 if (!canvas->isClipRect() || (canvas->getTotalMatrix().getType() &
408 ~(SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask))) {
409 return nullptr;
Matt Sarettd0814db2017-04-13 09:33:18 -0400410 }
411
412 return SkCanvasStateUtils::CaptureCanvasState(canvas);
413}
414
415// ----------------------------------------------------------------------------
Derek Sollenberger8872b382014-06-23 14:13:53 -0400416// Canvas draw operations
417// ----------------------------------------------------------------------------
418
Mike Reed260ab722016-10-07 15:59:20 -0400419void SkiaCanvas::drawColor(int color, SkBlendMode mode) {
Derek Sollenberger8872b382014-06-23 14:13:53 -0400420 mCanvas->drawColor(color, mode);
421}
422
Ben Wagner0ed10be2018-06-28 17:08:16 -0400423SkiaCanvas::PaintCoW&& SkiaCanvas::filterPaint(PaintCoW&& paint) const {
424 if (mPaintFilter) {
425 mPaintFilter->filter(&paint.writeable());
426 }
427 return std::move(paint);
428}
429
Derek Sollenbergeracb40992014-07-21 15:22:10 -0400430void SkiaCanvas::drawPaint(const SkPaint& paint) {
Ben Wagner0ed10be2018-06-28 17:08:16 -0400431 mCanvas->drawPaint(*filterPaint(paint));
Derek Sollenberger8872b382014-06-23 14:13:53 -0400432}
433
434// ----------------------------------------------------------------------------
435// Canvas draw operations: Geometry
436// ----------------------------------------------------------------------------
437
Derek Sollenbergeracb40992014-07-21 15:22:10 -0400438void SkiaCanvas::drawPoints(const float* points, int count, const SkPaint& paint,
Derek Sollenberger8872b382014-06-23 14:13:53 -0400439 SkCanvas::PointMode mode) {
Derek Sollenberger792fb322017-03-03 14:02:09 -0500440 if (CC_UNLIKELY(count < 2 || paint.nothingToDraw())) return;
Derek Sollenberger8872b382014-06-23 14:13:53 -0400441 // convert the floats into SkPoints
John Reck1bcacfd2017-11-03 10:12:19 -0700442 count >>= 1; // now it is the number of points
Ben Wagner6bbf68d2015-08-19 11:26:06 -0400443 std::unique_ptr<SkPoint[]> pts(new SkPoint[count]);
Derek Sollenberger8872b382014-06-23 14:13:53 -0400444 for (int i = 0; i < count; i++) {
445 pts[i].set(points[0], points[1]);
446 points += 2;
447 }
Ben Wagner0ed10be2018-06-28 17:08:16 -0400448 mCanvas->drawPoints(mode, count, pts.get(), *filterPaint(paint));
Derek Sollenberger8872b382014-06-23 14:13:53 -0400449}
450
Derek Sollenbergeracb40992014-07-21 15:22:10 -0400451void SkiaCanvas::drawPoint(float x, float y, const SkPaint& paint) {
Ben Wagner0ed10be2018-06-28 17:08:16 -0400452 mCanvas->drawPoint(x, y, *filterPaint(paint));
Derek Sollenberger8872b382014-06-23 14:13:53 -0400453}
454
Derek Sollenbergeracb40992014-07-21 15:22:10 -0400455void SkiaCanvas::drawPoints(const float* points, int count, const SkPaint& paint) {
Ben Wagner0ed10be2018-06-28 17:08:16 -0400456 this->drawPoints(points, count, *filterPaint(paint), SkCanvas::kPoints_PointMode);
Derek Sollenberger8872b382014-06-23 14:13:53 -0400457}
458
459void SkiaCanvas::drawLine(float startX, float startY, float stopX, float stopY,
Derek Sollenbergeracb40992014-07-21 15:22:10 -0400460 const SkPaint& paint) {
Ben Wagner0ed10be2018-06-28 17:08:16 -0400461 mCanvas->drawLine(startX, startY, stopX, stopY, *filterPaint(paint));
Derek Sollenberger8872b382014-06-23 14:13:53 -0400462}
463
Derek Sollenbergeracb40992014-07-21 15:22:10 -0400464void SkiaCanvas::drawLines(const float* points, int count, const SkPaint& paint) {
Derek Sollenberger792fb322017-03-03 14:02:09 -0500465 if (CC_UNLIKELY(count < 4 || paint.nothingToDraw())) return;
Ben Wagner0ed10be2018-06-28 17:08:16 -0400466 this->drawPoints(points, count, *filterPaint(paint), SkCanvas::kLines_PointMode);
Derek Sollenberger8872b382014-06-23 14:13:53 -0400467}
468
John Reck1bcacfd2017-11-03 10:12:19 -0700469void SkiaCanvas::drawRect(float left, float top, float right, float bottom, const SkPaint& paint) {
Derek Sollenberger792fb322017-03-03 14:02:09 -0500470 if (CC_UNLIKELY(paint.nothingToDraw())) return;
Ben Wagner0ed10be2018-06-28 17:08:16 -0400471 mCanvas->drawRect({left, top, right, bottom}, *filterPaint(paint));
Derek Sollenberger8872b382014-06-23 14:13:53 -0400472}
473
Derek Sollenberger94394b32015-07-10 09:58:41 -0400474void SkiaCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
Derek Sollenberger792fb322017-03-03 14:02:09 -0500475 if (CC_UNLIKELY(paint.nothingToDraw())) return;
Ben Wagner0ed10be2018-06-28 17:08:16 -0400476 mCanvas->drawRegion(region, *filterPaint(paint));
Derek Sollenberger94394b32015-07-10 09:58:41 -0400477}
478
John Reck1bcacfd2017-11-03 10:12:19 -0700479void SkiaCanvas::drawRoundRect(float left, float top, float right, float bottom, float rx, float ry,
480 const SkPaint& paint) {
Derek Sollenberger792fb322017-03-03 14:02:09 -0500481 if (CC_UNLIKELY(paint.nothingToDraw())) return;
Derek Sollenberger8872b382014-06-23 14:13:53 -0400482 SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
Ben Wagner0ed10be2018-06-28 17:08:16 -0400483 mCanvas->drawRoundRect(rect, rx, ry, *filterPaint(paint));
Derek Sollenberger8872b382014-06-23 14:13:53 -0400484}
485
Nader Jawadadfe1d92018-09-27 12:27:36 -0700486void SkiaCanvas::drawDoubleRoundRect(const SkRRect& outer, const SkRRect& inner,
487 const SkPaint& paint) {
488 mCanvas->drawDRRect(outer, inner, *filterPaint(paint));
489}
490
Derek Sollenbergeracb40992014-07-21 15:22:10 -0400491void SkiaCanvas::drawCircle(float x, float y, float radius, const SkPaint& paint) {
Derek Sollenberger792fb322017-03-03 14:02:09 -0500492 if (CC_UNLIKELY(radius <= 0 || paint.nothingToDraw())) return;
Ben Wagner0ed10be2018-06-28 17:08:16 -0400493 mCanvas->drawCircle(x, y, radius, *filterPaint(paint));
Derek Sollenberger8872b382014-06-23 14:13:53 -0400494}
495
Derek Sollenbergeracb40992014-07-21 15:22:10 -0400496void SkiaCanvas::drawOval(float left, float top, float right, float bottom, const SkPaint& paint) {
Derek Sollenberger792fb322017-03-03 14:02:09 -0500497 if (CC_UNLIKELY(paint.nothingToDraw())) return;
Derek Sollenberger8872b382014-06-23 14:13:53 -0400498 SkRect oval = SkRect::MakeLTRB(left, top, right, bottom);
Ben Wagner0ed10be2018-06-28 17:08:16 -0400499 mCanvas->drawOval(oval, *filterPaint(paint));
Derek Sollenberger8872b382014-06-23 14:13:53 -0400500}
501
John Reck1bcacfd2017-11-03 10:12:19 -0700502void SkiaCanvas::drawArc(float left, float top, float right, float bottom, float startAngle,
503 float sweepAngle, bool useCenter, const SkPaint& paint) {
Derek Sollenberger792fb322017-03-03 14:02:09 -0500504 if (CC_UNLIKELY(paint.nothingToDraw())) return;
Derek Sollenberger8872b382014-06-23 14:13:53 -0400505 SkRect arc = SkRect::MakeLTRB(left, top, right, bottom);
Derek Sollenbergeref3b2182017-11-06 13:55:59 -0500506 if (fabs(sweepAngle) >= 360.0f) {
Ben Wagner0ed10be2018-06-28 17:08:16 -0400507 mCanvas->drawOval(arc, *filterPaint(paint));
Derek Sollenbergeref3b2182017-11-06 13:55:59 -0500508 } else {
Ben Wagner0ed10be2018-06-28 17:08:16 -0400509 mCanvas->drawArc(arc, startAngle, sweepAngle, useCenter, *filterPaint(paint));
Derek Sollenbergeref3b2182017-11-06 13:55:59 -0500510 }
Derek Sollenberger8872b382014-06-23 14:13:53 -0400511}
512
Derek Sollenbergeracb40992014-07-21 15:22:10 -0400513void SkiaCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
Derek Sollenberger792fb322017-03-03 14:02:09 -0500514 if (CC_UNLIKELY(paint.nothingToDraw())) return;
Stan Iliev6dcfdec2017-08-15 16:42:05 -0400515 if (CC_UNLIKELY(path.isEmpty() && (!path.isInverseFillType()))) {
516 return;
517 }
Ben Wagner0ed10be2018-06-28 17:08:16 -0400518 mCanvas->drawPath(path, *filterPaint(paint));
Derek Sollenberger8872b382014-06-23 14:13:53 -0400519}
520
Mike Reed826deef2017-04-04 15:32:04 -0400521void SkiaCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint) {
Ben Wagner0ed10be2018-06-28 17:08:16 -0400522 mCanvas->drawVertices(vertices, mode, *filterPaint(paint));
Derek Sollenberger8872b382014-06-23 14:13:53 -0400523}
524
525// ----------------------------------------------------------------------------
526// Canvas draw operations: Bitmaps
527// ----------------------------------------------------------------------------
528
Derek Sollenbergerfb0c8fc2017-07-26 13:53:27 -0400529void SkiaCanvas::drawBitmap(Bitmap& bitmap, float left, float top, const SkPaint* paint) {
Derek Sollenbergerd01b5912018-10-19 15:55:33 -0400530 mCanvas->drawImage(bitmap.makeImage(), left, top, filterPaint(paint));
Derek Sollenbergerfb0c8fc2017-07-26 13:53:27 -0400531}
532
533void SkiaCanvas::drawBitmap(Bitmap& bitmap, const SkMatrix& matrix, const SkPaint* paint) {
Mike Reed6acfe162016-11-18 17:21:09 -0500534 SkAutoCanvasRestore acr(mCanvas, true);
Mike Reed70ffbf92014-12-08 17:03:30 -0500535 mCanvas->concat(matrix);
Derek Sollenbergerd01b5912018-10-19 15:55:33 -0400536 mCanvas->drawImage(bitmap.makeImage(), 0, 0, filterPaint(paint));
Derek Sollenberger8872b382014-06-23 14:13:53 -0400537}
538
John Reck1bcacfd2017-11-03 10:12:19 -0700539void SkiaCanvas::drawBitmap(Bitmap& bitmap, float srcLeft, float srcTop, float srcRight,
540 float srcBottom, float dstLeft, float dstTop, float dstRight,
541 float dstBottom, const SkPaint* paint) {
Derek Sollenberger8872b382014-06-23 14:13:53 -0400542 SkRect srcRect = SkRect::MakeLTRB(srcLeft, srcTop, srcRight, srcBottom);
543 SkRect dstRect = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom);
Derek Sollenbergerfb0c8fc2017-07-26 13:53:27 -0400544
Derek Sollenbergerd01b5912018-10-19 15:55:33 -0400545 mCanvas->drawImageRect(bitmap.makeImage(), srcRect, dstRect, filterPaint(paint),
John Reck1bcacfd2017-11-03 10:12:19 -0700546 SkCanvas::kFast_SrcRectConstraint);
Derek Sollenberger8872b382014-06-23 14:13:53 -0400547}
548
Derek Sollenbergerfb0c8fc2017-07-26 13:53:27 -0400549void SkiaCanvas::drawBitmapMesh(Bitmap& bitmap, int meshWidth, int meshHeight,
John Reck1bcacfd2017-11-03 10:12:19 -0700550 const float* vertices, const int* colors, const SkPaint* paint) {
Derek Sollenberger8872b382014-06-23 14:13:53 -0400551 const int ptCount = (meshWidth + 1) * (meshHeight + 1);
552 const int indexCount = meshWidth * meshHeight * 6;
Mike Reed871cd2d2017-03-17 10:15:52 -0400553 uint32_t flags = SkVertices::kHasTexCoords_BuilderFlag;
554 if (colors) {
555 flags |= SkVertices::kHasColors_BuilderFlag;
556 }
Mike Reed826deef2017-04-04 15:32:04 -0400557 SkVertices::Builder builder(SkVertices::kTriangles_VertexMode, ptCount, indexCount, flags);
Mike Reed871cd2d2017-03-17 10:15:52 -0400558 memcpy(builder.positions(), vertices, ptCount * sizeof(SkPoint));
559 if (colors) {
560 memcpy(builder.colors(), colors, ptCount * sizeof(SkColor));
561 }
562 SkPoint* texs = builder.texCoords();
563 uint16_t* indices = builder.indices();
Derek Sollenberger8872b382014-06-23 14:13:53 -0400564
565 // cons up texture coordinates and indices
566 {
Derek Sollenbergerfb0c8fc2017-07-26 13:53:27 -0400567 const SkScalar w = SkIntToScalar(bitmap.width());
568 const SkScalar h = SkIntToScalar(bitmap.height());
Derek Sollenberger8872b382014-06-23 14:13:53 -0400569 const SkScalar dx = w / meshWidth;
570 const SkScalar dy = h / meshHeight;
571
572 SkPoint* texsPtr = texs;
573 SkScalar y = 0;
574 for (int i = 0; i <= meshHeight; i++) {
575 if (i == meshHeight) {
576 y = h; // to ensure numerically we hit h exactly
577 }
578 SkScalar x = 0;
579 for (int j = 0; j < meshWidth; j++) {
580 texsPtr->set(x, y);
581 texsPtr += 1;
582 x += dx;
583 }
584 texsPtr->set(w, y);
585 texsPtr += 1;
586 y += dy;
587 }
588 SkASSERT(texsPtr - texs == ptCount);
589 }
590
591 // cons up indices
592 {
593 uint16_t* indexPtr = indices;
594 int index = 0;
595 for (int i = 0; i < meshHeight; i++) {
596 for (int j = 0; j < meshWidth; j++) {
597 // lower-left triangle
598 *indexPtr++ = index;
599 *indexPtr++ = index + meshWidth + 1;
600 *indexPtr++ = index + meshWidth + 2;
601 // upper-right triangle
602 *indexPtr++ = index;
603 *indexPtr++ = index + meshWidth + 2;
604 *indexPtr++ = index + 1;
605 // bump to the next cell
606 index += 1;
607 }
608 // bump to the next row
609 index += 1;
610 }
611 SkASSERT(indexPtr - indices == indexCount);
Derek Sollenberger8872b382014-06-23 14:13:53 -0400612 }
613
John Reck1bcacfd2017-11-03 10:12:19 -0700614// double-check that we have legal indices
Derek Sollenberger8872b382014-06-23 14:13:53 -0400615#ifdef SK_DEBUG
616 {
617 for (int i = 0; i < indexCount; i++) {
618 SkASSERT((unsigned)indices[i] < (unsigned)ptCount);
619 }
620 }
621#endif
622
623 // cons-up a shader for the bitmap
Ben Wagner0ed10be2018-06-28 17:08:16 -0400624 PaintCoW paintCoW(paint);
625 SkPaint& tmpPaint = paintCoW.writeable();
Stan Ilievf50806a2016-10-24 10:40:39 -0400626
Derek Sollenbergerd01b5912018-10-19 15:55:33 -0400627 sk_sp<SkImage> image = bitmap.makeImage();
John Reck1bcacfd2017-11-03 10:12:19 -0700628 sk_sp<SkShader> shader =
629 image->makeShader(SkShader::kClamp_TileMode, SkShader::kClamp_TileMode);
Ben Wagner0ed10be2018-06-28 17:08:16 -0400630 tmpPaint.setShader(std::move(shader));
Derek Sollenberger8872b382014-06-23 14:13:53 -0400631
Ben Wagner0ed10be2018-06-28 17:08:16 -0400632 mCanvas->drawVertices(builder.detach(), SkBlendMode::kModulate,
633 *filterPaint(std::move(paintCoW)));
Derek Sollenberger8872b382014-06-23 14:13:53 -0400634}
635
John Reck1bcacfd2017-11-03 10:12:19 -0700636void SkiaCanvas::drawNinePatch(Bitmap& bitmap, const Res_png_9patch& chunk, float dstLeft,
637 float dstTop, float dstRight, float dstBottom,
638 const SkPaint* paint) {
Stan Ilievf50806a2016-10-24 10:40:39 -0400639 SkCanvas::Lattice lattice;
Derek Sollenbergerfb0c8fc2017-07-26 13:53:27 -0400640 NinePatchUtils::SetLatticeDivs(&lattice, chunk, bitmap.width(), bitmap.height());
Stan Ilievf50806a2016-10-24 10:40:39 -0400641
Stan Ilieve12d7312017-12-04 14:48:27 -0500642 lattice.fRectTypes = nullptr;
643 lattice.fColors = nullptr;
Stan Ilievf50806a2016-10-24 10:40:39 -0400644 int numFlags = 0;
Stan Iliev021693b2016-10-17 16:26:15 -0400645 if (chunk.numColors > 0 && chunk.numColors == NinePatchUtils::NumDistinctRects(lattice)) {
Stan Ilievf50806a2016-10-24 10:40:39 -0400646 // We can expect the framework to give us a color for every distinct rect.
647 // Skia requires a flag for every rect.
648 numFlags = (lattice.fXCount + 1) * (lattice.fYCount + 1);
649 }
650
Stan Ilieve12d7312017-12-04 14:48:27 -0500651 SkAutoSTMalloc<25, SkCanvas::Lattice::RectType> flags(numFlags);
652 SkAutoSTMalloc<25, SkColor> colors(numFlags);
Stan Ilievf50806a2016-10-24 10:40:39 -0400653 if (numFlags > 0) {
Stan Ilieve12d7312017-12-04 14:48:27 -0500654 NinePatchUtils::SetLatticeFlags(&lattice, flags.get(), numFlags, chunk, colors.get());
Stan Ilievf50806a2016-10-24 10:40:39 -0400655 }
656
657 lattice.fBounds = nullptr;
658 SkRect dst = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom);
Derek Sollenbergerfb0c8fc2017-07-26 13:53:27 -0400659
Derek Sollenbergerd01b5912018-10-19 15:55:33 -0400660 mCanvas->drawImageLattice(bitmap.makeImage().get(), lattice, dst, filterPaint(paint));
Derek Sollenbergeredca3202015-07-10 13:56:39 -0400661}
662
Derek Sollenberger2d142132018-01-22 10:25:26 -0500663double SkiaCanvas::drawAnimatedImage(AnimatedImageDrawable* imgDrawable) {
664 return imgDrawable->drawStaging(mCanvas);
Leon Scroggins III671cce22018-01-14 16:52:17 -0500665}
666
Doris Liu766431a2016-02-04 22:17:11 +0000667void SkiaCanvas::drawVectorDrawable(VectorDrawableRoot* vectorDrawable) {
Doris Liu1d8e1942016-03-02 15:16:28 -0800668 vectorDrawable->drawStaging(this);
Doris Liu766431a2016-02-04 22:17:11 +0000669}
670
Derek Sollenberger8872b382014-06-23 14:13:53 -0400671// ----------------------------------------------------------------------------
672// Canvas draw operations: Text
673// ----------------------------------------------------------------------------
674
Stan Iliev0b58d992017-03-30 18:22:27 -0400675void SkiaCanvas::drawGlyphs(ReadGlyphFunc glyphFunc, int count, const SkPaint& paint, float x,
John Reck1bcacfd2017-11-03 10:12:19 -0700676 float y, float boundsLeft, float boundsTop, float boundsRight,
677 float boundsBottom, float totalAdvance) {
Stan Iliev0b58d992017-03-30 18:22:27 -0400678 if (count <= 0 || paint.nothingToDraw()) return;
Mike Reed1c79eab2018-11-21 11:01:57 -0500679 SkFont font = SkFont::LEGACY_ExtractFromPaint(paint);
Stan Ilievf50806a2016-10-24 10:40:39 -0400680 SkPaint paintCopy(paint);
Ben Wagner0ed10be2018-06-28 17:08:16 -0400681 if (mPaintFilter) {
682 mPaintFilter->filter(&paintCopy);
683 }
Stan Ilieva39b7742017-11-29 13:15:45 -0500684 SkASSERT(paintCopy.getTextEncoding() == SkPaint::kGlyphID_TextEncoding);
Stan Iliev7717e222018-02-05 18:04:11 -0500685 // Stroke with a hairline is drawn on HW with a fill style for compatibility with Android O and
686 // older.
John Recke170fb62018-05-07 08:12:07 -0700687 if (!mCanvasOwned && sApiLevel <= 27 && paintCopy.getStrokeWidth() <= 0 &&
688 paintCopy.getStyle() == SkPaint::kStroke_Style) {
Stan Iliev7717e222018-02-05 18:04:11 -0500689 paintCopy.setStyle(SkPaint::kFill_Style);
690 }
Stan Ilievf50806a2016-10-24 10:40:39 -0400691
John Reck1bcacfd2017-11-03 10:12:19 -0700692 SkRect bounds =
693 SkRect::MakeLTRB(boundsLeft + x, boundsTop + y, boundsRight + x, boundsBottom + y);
Stan Ilievf50806a2016-10-24 10:40:39 -0400694
695 SkTextBlobBuilder builder;
Mike Reed1c79eab2018-11-21 11:01:57 -0500696 const SkTextBlobBuilder::RunBuffer& buffer = builder.allocRunPos(font, count, &bounds);
Stan Iliev0b58d992017-03-30 18:22:27 -0400697 glyphFunc(buffer.glyphs, buffer.pos);
Stan Ilievf50806a2016-10-24 10:40:39 -0400698
699 sk_sp<SkTextBlob> textBlob(builder.make());
700 mCanvas->drawTextBlob(textBlob, 0, 0, paintCopy);
701 drawTextDecorations(x, y, totalAdvance, paintCopy);
Derek Sollenberger8872b382014-06-23 14:13:53 -0400702}
703
Yuqian Liafc221492016-07-18 13:07:42 -0400704void SkiaCanvas::drawLayoutOnPath(const minikin::Layout& layout, float hOffset, float vOffset,
John Reck1bcacfd2017-11-03 10:12:19 -0700705 const SkPaint& paint, const SkPath& path, size_t start,
706 size_t end) {
Derek Sollenberger415a74b2018-03-14 15:03:13 -0400707 SkPaint paintCopy(paint);
Ben Wagner0ed10be2018-06-28 17:08:16 -0400708 if (mPaintFilter) {
709 mPaintFilter->filter(&paintCopy);
710 }
Derek Sollenberger415a74b2018-03-14 15:03:13 -0400711 SkASSERT(paintCopy.getTextEncoding() == SkPaint::kGlyphID_TextEncoding);
712
Yuqian Liafc221492016-07-18 13:07:42 -0400713 const int N = end - start;
Derek Sollenbergere547dd02016-11-09 11:55:59 -0500714 SkAutoSTMalloc<1024, uint8_t> storage(N * (sizeof(uint16_t) + sizeof(SkRSXform)));
Yuqian Liafc221492016-07-18 13:07:42 -0400715 SkRSXform* xform = (SkRSXform*)storage.get();
716 uint16_t* glyphs = (uint16_t*)(xform + N);
717 SkPathMeasure meas(path, false);
718
719 for (size_t i = start; i < end; i++) {
720 glyphs[i - start] = layout.getGlyphId(i);
Stan Ilievc6c96dd2018-01-10 16:06:04 -0500721 float halfWidth = layout.getCharAdvance(i) * 0.5f;
722 float x = hOffset + layout.getX(i) + halfWidth;
Yuqian Liafc221492016-07-18 13:07:42 -0400723 float y = vOffset + layout.getY(i);
724
725 SkPoint pos;
726 SkVector tan;
727 if (!meas.getPosTan(x, &pos, &tan)) {
728 pos.set(x, y);
729 tan.set(1, 0);
730 }
731 xform[i - start].fSCos = tan.x();
732 xform[i - start].fSSin = tan.y();
Stan Ilievc6c96dd2018-01-10 16:06:04 -0500733 xform[i - start].fTx = pos.x() - tan.y() * y - halfWidth * tan.x();
734 xform[i - start].fTy = pos.y() + tan.x() * y - halfWidth * tan.y();
Yuqian Liafc221492016-07-18 13:07:42 -0400735 }
736
Derek Sollenberger415a74b2018-03-14 15:03:13 -0400737 this->asSkCanvas()->drawTextRSXform(glyphs, sizeof(uint16_t) * N, xform, nullptr, paintCopy);
Derek Sollenberger8872b382014-06-23 14:13:53 -0400738}
739
Derek Sollenberger6f485562015-07-30 10:00:39 -0400740// ----------------------------------------------------------------------------
741// Canvas draw operations: Animations
742// ----------------------------------------------------------------------------
743
Derek Sollenberger6f485562015-07-30 10:00:39 -0400744void SkiaCanvas::drawRoundRect(uirenderer::CanvasPropertyPrimitive* left,
John Reck1bcacfd2017-11-03 10:12:19 -0700745 uirenderer::CanvasPropertyPrimitive* top,
746 uirenderer::CanvasPropertyPrimitive* right,
747 uirenderer::CanvasPropertyPrimitive* bottom,
748 uirenderer::CanvasPropertyPrimitive* rx,
749 uirenderer::CanvasPropertyPrimitive* ry,
750 uirenderer::CanvasPropertyPaint* paint) {
Stan Iliev021693b2016-10-17 16:26:15 -0400751 sk_sp<uirenderer::skiapipeline::AnimatedRoundRect> drawable(
John Reck1bcacfd2017-11-03 10:12:19 -0700752 new uirenderer::skiapipeline::AnimatedRoundRect(left, top, right, bottom, rx, ry,
753 paint));
Derek Sollenberger6f485562015-07-30 10:00:39 -0400754 mCanvas->drawDrawable(drawable.get());
755}
756
John Reck1bcacfd2017-11-03 10:12:19 -0700757void SkiaCanvas::drawCircle(uirenderer::CanvasPropertyPrimitive* x,
758 uirenderer::CanvasPropertyPrimitive* y,
759 uirenderer::CanvasPropertyPrimitive* radius,
760 uirenderer::CanvasPropertyPaint* paint) {
761 sk_sp<uirenderer::skiapipeline::AnimatedCircle> drawable(
762 new uirenderer::skiapipeline::AnimatedCircle(x, y, radius, paint));
Derek Sollenberger6f485562015-07-30 10:00:39 -0400763 mCanvas->drawDrawable(drawable.get());
764}
765
766// ----------------------------------------------------------------------------
767// Canvas draw operations: View System
768// ----------------------------------------------------------------------------
769
Stan Ilievf50806a2016-10-24 10:40:39 -0400770void SkiaCanvas::drawLayer(uirenderer::DeferredLayerUpdater* layerUpdater) {
Derek Sollenbergerc1908132016-07-15 10:28:16 -0400771 LOG_ALWAYS_FATAL("SkiaCanvas can't directly draw Layers");
772}
Derek Sollenberger6f485562015-07-30 10:00:39 -0400773
Derek Sollenbergerc1908132016-07-15 10:28:16 -0400774void SkiaCanvas::drawRenderNode(uirenderer::RenderNode* renderNode) {
775 LOG_ALWAYS_FATAL("SkiaCanvas can't directly draw RenderNodes");
776}
Derek Sollenberger6f485562015-07-30 10:00:39 -0400777
John Reckcd1c3eb2016-04-14 10:38:54 -0700778void SkiaCanvas::callDrawGLFunction(Functor* functor,
John Reck1bcacfd2017-11-03 10:12:19 -0700779 uirenderer::GlFunctorLifecycleListener* listener) {
Derek Sollenbergerc1908132016-07-15 10:28:16 -0400780 LOG_ALWAYS_FATAL("SkiaCanvas can't directly draw GL Content");
781}
Derek Sollenberger6f485562015-07-30 10:00:39 -0400782
John Reck1bcacfd2017-11-03 10:12:19 -0700783} // namespace android