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