SkiaCanvas.cpp revision 82d3b17f6dff9372ec531d90b5d9180671e0ee2c
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 "NinePatchUtils.h" 21#include "VectorDrawable.h" 22#include "hwui/Bitmap.h" 23#include "hwui/MinikinUtils.h" 24#include "pipeline/skia/AnimatedDrawables.h" 25 26#include <SkDrawable.h> 27#include <SkDeque.h> 28#include <SkDrawFilter.h> 29#include <SkGraphics.h> 30#include <SkImage.h> 31#include <SkImagePriv.h> 32#include <SkRSXform.h> 33#include <SkShader.h> 34#include <SkTemplates.h> 35#include <SkTextBlob.h> 36 37#include <memory> 38 39namespace android { 40 41using uirenderer::PaintUtils; 42 43Canvas* Canvas::create_canvas(const SkBitmap& bitmap) { 44 return new SkiaCanvas(bitmap); 45} 46 47Canvas* Canvas::create_canvas(SkCanvas* skiaCanvas) { 48 return new SkiaCanvas(skiaCanvas); 49} 50 51SkiaCanvas::SkiaCanvas() {} 52 53SkiaCanvas::SkiaCanvas(SkCanvas* canvas) 54 : mCanvas(canvas) {} 55 56SkiaCanvas::SkiaCanvas(const SkBitmap& bitmap) { 57 mCanvasOwned = std::unique_ptr<SkCanvas>(new SkCanvas(bitmap)); 58 mCanvas = mCanvasOwned.get(); 59} 60 61SkiaCanvas::~SkiaCanvas() {} 62 63void SkiaCanvas::reset(SkCanvas* skiaCanvas) { 64 if (mCanvas != skiaCanvas) { 65 mCanvas = skiaCanvas; 66 mCanvasOwned.reset(); 67 } 68 mSaveStack.reset(nullptr); 69 mHighContrastText = false; 70} 71 72// ---------------------------------------------------------------------------- 73// Canvas state operations: Replace Bitmap 74// ---------------------------------------------------------------------------- 75 76void SkiaCanvas::setBitmap(const SkBitmap& bitmap) { 77 SkCanvas* newCanvas = new SkCanvas(bitmap); 78 79 if (!bitmap.isNull()) { 80 // Copy the canvas matrix & clip state. 81 newCanvas->setMatrix(mCanvas->getTotalMatrix()); 82 83 SkRegion rgn; 84 mCanvas->temporary_internal_getRgnClip(&rgn); 85 newCanvas->clipRegion(rgn, SkClipOp::kIntersect); 86 } 87 88 // deletes the previously owned canvas (if any) 89 mCanvasOwned = std::unique_ptr<SkCanvas>(newCanvas); 90 mCanvas = newCanvas; 91 92 // clean up the old save stack 93 mSaveStack.reset(nullptr); 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 auto* rec = this->currentSaveRec(); 132 if (!rec) { 133 // Fast path - no record for this frame. 134 mCanvas->restore(); 135 return; 136 } 137 138 bool preserveMatrix = !(rec->saveFlags & SaveFlags::Matrix); 139 bool preserveClip = !(rec->saveFlags & SaveFlags::Clip); 140 141 SkMatrix savedMatrix; 142 if (preserveMatrix) { 143 savedMatrix = mCanvas->getTotalMatrix(); 144 } 145 146 const size_t clipIndex = rec->clipIndex; 147 148 mCanvas->restore(); 149 mSaveStack->pop_back(); 150 151 if (preserveMatrix) { 152 mCanvas->setMatrix(savedMatrix); 153 } 154 155 if (preserveClip) { 156 this->applyPersistentClips(clipIndex); 157 } 158} 159 160void SkiaCanvas::restoreToCount(int restoreCount) { 161 while (mCanvas->getSaveCount() > restoreCount) { 162 this->restore(); 163 } 164} 165 166static inline SkCanvas::SaveLayerFlags layerFlags(SaveFlags::Flags flags) { 167 SkCanvas::SaveLayerFlags layerFlags = 0; 168 169 // We intentionally ignore the SaveFlags::HasAlphaLayer and 170 // SkCanvas::kIsOpaque_SaveLayerFlag flags because HWUI ignores it 171 // and our Android client may use it incorrectly. 172 // In Skia, this flag is purely for performance optimization. 173 174 if (!(flags & SaveFlags::ClipToLayer)) { 175 layerFlags |= SkCanvas::kDontClipToLayer_Legacy_SaveLayerFlag; 176 } 177 178 return layerFlags; 179} 180 181int SkiaCanvas::saveLayer(float left, float top, float right, float bottom, 182 const SkPaint* paint, SaveFlags::Flags flags) { 183 const SkRect bounds = SkRect::MakeLTRB(left, top, right, bottom); 184 const SkCanvas::SaveLayerRec rec(&bounds, paint, layerFlags(flags)); 185 186 return mCanvas->saveLayer(rec); 187} 188 189int SkiaCanvas::saveLayerAlpha(float left, float top, float right, float bottom, 190 int alpha, SaveFlags::Flags flags) { 191 if (static_cast<unsigned>(alpha) < 0xFF) { 192 SkPaint alphaPaint; 193 alphaPaint.setAlpha(alpha); 194 return this->saveLayer(left, top, right, bottom, &alphaPaint, flags); 195 } 196 return this->saveLayer(left, top, right, bottom, nullptr, flags); 197} 198 199class SkiaCanvas::Clip { 200public: 201 Clip(const SkRect& rect, SkClipOp op, const SkMatrix& m) 202 : mType(Type::Rect), mOp(op), mMatrix(m), mRRect(SkRRect::MakeRect(rect)) {} 203 Clip(const SkRRect& rrect, SkClipOp op, const SkMatrix& m) 204 : mType(Type::RRect), mOp(op), mMatrix(m), mRRect(rrect) {} 205 Clip(const SkPath& path, SkClipOp op, const SkMatrix& m) 206 : mType(Type::Path), mOp(op), mMatrix(m), mPath(&path) {} 207 208 void apply(SkCanvas* canvas) const { 209 canvas->setMatrix(mMatrix); 210 switch (mType) { 211 case Type::Rect: 212 canvas->clipRect(mRRect.rect(), mOp); 213 break; 214 case Type::RRect: 215 canvas->clipRRect(mRRect, mOp); 216 break; 217 case Type::Path: 218 canvas->clipPath(*mPath.get(), mOp); 219 break; 220 } 221 } 222 223private: 224 enum class Type { 225 Rect, 226 RRect, 227 Path, 228 }; 229 230 Type mType; 231 SkClipOp mOp; 232 SkMatrix mMatrix; 233 234 // These are logically a union (tracked separately due to non-POD path). 235 SkTLazy<SkPath> mPath; 236 SkRRect mRRect; 237}; 238 239const SkiaCanvas::SaveRec* SkiaCanvas::currentSaveRec() const { 240 const SaveRec* rec = mSaveStack 241 ? static_cast<const SaveRec*>(mSaveStack->back()) 242 : nullptr; 243 int currentSaveCount = mCanvas->getSaveCount(); 244 SkASSERT(!rec || currentSaveCount >= rec->saveCount); 245 246 return (rec && rec->saveCount == currentSaveCount) ? rec : nullptr; 247} 248 249// ---------------------------------------------------------------------------- 250// functions to emulate legacy SaveFlags (i.e. independent matrix/clip flags) 251// ---------------------------------------------------------------------------- 252 253void SkiaCanvas::recordPartialSave(SaveFlags::Flags flags) { 254 // A partial save is a save operation which doesn't capture the full canvas state. 255 // (either SaveFlags::Matrix or SaveFlags::Clip is missing). 256 257 // Mask-out non canvas state bits. 258 flags &= SaveFlags::MatrixClip; 259 260 if (flags == SaveFlags::MatrixClip) { 261 // not a partial save. 262 return; 263 } 264 265 if (!mSaveStack) { 266 mSaveStack.reset(new SkDeque(sizeof(struct SaveRec), 8)); 267 } 268 269 SaveRec* rec = static_cast<SaveRec*>(mSaveStack->push_back()); 270 rec->saveCount = mCanvas->getSaveCount(); 271 rec->saveFlags = flags; 272 rec->clipIndex = mClipStack.size(); 273} 274 275template <typename T> 276void SkiaCanvas::recordClip(const T& clip, SkClipOp op) { 277 // Only need tracking when in a partial save frame which 278 // doesn't restore the clip. 279 const SaveRec* rec = this->currentSaveRec(); 280 if (rec && !(rec->saveFlags & SaveFlags::Clip)) { 281 mClipStack.emplace_back(clip, op, mCanvas->getTotalMatrix()); 282 } 283} 284 285// Applies and optionally removes all clips >= index. 286void SkiaCanvas::applyPersistentClips(size_t clipStartIndex) { 287 SkASSERT(clipStartIndex <= mClipStack.size()); 288 const auto begin = mClipStack.cbegin() + clipStartIndex; 289 const auto end = mClipStack.cend(); 290 291 // Clip application mutates the CTM. 292 const SkMatrix saveMatrix = mCanvas->getTotalMatrix(); 293 294 for (auto clip = begin; clip != end; ++clip) { 295 clip->apply(mCanvas); 296 } 297 298 mCanvas->setMatrix(saveMatrix); 299 300 // If the current/post-restore save rec is also persisting clips, we 301 // leave them on the stack to be reapplied part of the next restore(). 302 // Otherwise we're done and just pop them. 303 const auto* rec = this->currentSaveRec(); 304 if (!rec || (rec->saveFlags & SaveFlags::Clip)) { 305 mClipStack.erase(begin, end); 306 } 307} 308 309// ---------------------------------------------------------------------------- 310// Canvas state operations: Matrix 311// ---------------------------------------------------------------------------- 312 313void SkiaCanvas::getMatrix(SkMatrix* outMatrix) const { 314 *outMatrix = mCanvas->getTotalMatrix(); 315} 316 317void SkiaCanvas::setMatrix(const SkMatrix& matrix) { 318 mCanvas->setMatrix(matrix); 319} 320 321void SkiaCanvas::concat(const SkMatrix& matrix) { 322 mCanvas->concat(matrix); 323} 324 325void SkiaCanvas::rotate(float degrees) { 326 mCanvas->rotate(degrees); 327} 328 329void SkiaCanvas::scale(float sx, float sy) { 330 mCanvas->scale(sx, sy); 331} 332 333void SkiaCanvas::skew(float sx, float sy) { 334 mCanvas->skew(sx, sy); 335} 336 337void SkiaCanvas::translate(float dx, float dy) { 338 mCanvas->translate(dx, dy); 339} 340 341// ---------------------------------------------------------------------------- 342// Canvas state operations: Clips 343// ---------------------------------------------------------------------------- 344 345// This function is a mirror of SkCanvas::getClipBounds except that it does 346// not outset the edge of the clip to account for anti-aliasing. There is 347// a skia bug to investigate pushing this logic into back into skia. 348// (see https://code.google.com/p/skia/issues/detail?id=1303) 349bool SkiaCanvas::getClipBounds(SkRect* outRect) const { 350 SkIRect ibounds; 351 if (!mCanvas->getDeviceClipBounds(&ibounds)) { 352 return false; 353 } 354 355 SkMatrix inverse; 356 // if we can't invert the CTM, we can't return local clip bounds 357 if (!mCanvas->getTotalMatrix().invert(&inverse)) { 358 if (outRect) { 359 outRect->setEmpty(); 360 } 361 return false; 362 } 363 364 if (NULL != outRect) { 365 SkRect r = SkRect::Make(ibounds); 366 inverse.mapRect(outRect, r); 367 } 368 return true; 369} 370 371bool SkiaCanvas::quickRejectRect(float left, float top, float right, float bottom) const { 372 SkRect bounds = SkRect::MakeLTRB(left, top, right, bottom); 373 return mCanvas->quickReject(bounds); 374} 375 376bool SkiaCanvas::quickRejectPath(const SkPath& path) const { 377 return mCanvas->quickReject(path); 378} 379 380bool SkiaCanvas::clipRect(float left, float top, float right, float bottom, SkClipOp op) { 381 SkRect rect = SkRect::MakeLTRB(left, top, right, bottom); 382 this->recordClip(rect, op); 383 mCanvas->clipRect(rect, op); 384 return !mCanvas->isClipEmpty(); 385} 386 387bool SkiaCanvas::clipPath(const SkPath* path, SkClipOp op) { 388 SkRRect roundRect; 389 if (path->isRRect(&roundRect)) { 390 this->recordClip(roundRect, op); 391 mCanvas->clipRRect(roundRect, op); 392 } else { 393 this->recordClip(*path, op); 394 mCanvas->clipPath(*path, op); 395 } 396 return !mCanvas->isClipEmpty(); 397} 398 399// ---------------------------------------------------------------------------- 400// Canvas state operations: Filters 401// ---------------------------------------------------------------------------- 402 403SkDrawFilter* SkiaCanvas::getDrawFilter() { 404 return mCanvas->getDrawFilter(); 405} 406 407void SkiaCanvas::setDrawFilter(SkDrawFilter* drawFilter) { 408 mCanvas->setDrawFilter(drawFilter); 409} 410 411// ---------------------------------------------------------------------------- 412// Canvas draw operations 413// ---------------------------------------------------------------------------- 414 415void SkiaCanvas::drawColor(int color, SkBlendMode mode) { 416 mCanvas->drawColor(color, mode); 417} 418 419void SkiaCanvas::drawPaint(const SkPaint& paint) { 420 mCanvas->drawPaint(paint); 421} 422 423// ---------------------------------------------------------------------------- 424// Canvas draw operations: Geometry 425// ---------------------------------------------------------------------------- 426 427void SkiaCanvas::drawPoints(const float* points, int count, const SkPaint& paint, 428 SkCanvas::PointMode mode) { 429 if (CC_UNLIKELY(count < 2 || PaintUtils::paintWillNotDraw(paint))) return; 430 // convert the floats into SkPoints 431 count >>= 1; // now it is the number of points 432 std::unique_ptr<SkPoint[]> pts(new SkPoint[count]); 433 for (int i = 0; i < count; i++) { 434 pts[i].set(points[0], points[1]); 435 points += 2; 436 } 437 mCanvas->drawPoints(mode, count, pts.get(), paint); 438} 439 440 441void SkiaCanvas::drawPoint(float x, float y, const SkPaint& paint) { 442 mCanvas->drawPoint(x, y, paint); 443} 444 445void SkiaCanvas::drawPoints(const float* points, int count, const SkPaint& paint) { 446 this->drawPoints(points, count, paint, SkCanvas::kPoints_PointMode); 447} 448 449void SkiaCanvas::drawLine(float startX, float startY, float stopX, float stopY, 450 const SkPaint& paint) { 451 mCanvas->drawLine(startX, startY, stopX, stopY, paint); 452} 453 454void SkiaCanvas::drawLines(const float* points, int count, const SkPaint& paint) { 455 if (CC_UNLIKELY(count < 4 || PaintUtils::paintWillNotDraw(paint))) return; 456 this->drawPoints(points, count, paint, SkCanvas::kLines_PointMode); 457} 458 459void SkiaCanvas::drawRect(float left, float top, float right, float bottom, 460 const SkPaint& paint) { 461 if (CC_UNLIKELY(PaintUtils::paintWillNotDraw(paint))) return; 462 mCanvas->drawRectCoords(left, top, right, bottom, paint); 463 464} 465 466void SkiaCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) { 467 if (CC_UNLIKELY(PaintUtils::paintWillNotDraw(paint))) return; 468 mCanvas->drawRegion(region, paint); 469} 470 471void SkiaCanvas::drawRoundRect(float left, float top, float right, float bottom, 472 float rx, float ry, const SkPaint& paint) { 473 if (CC_UNLIKELY(PaintUtils::paintWillNotDraw(paint))) return; 474 SkRect rect = SkRect::MakeLTRB(left, top, right, bottom); 475 mCanvas->drawRoundRect(rect, rx, ry, paint); 476} 477 478void SkiaCanvas::drawCircle(float x, float y, float radius, const SkPaint& paint) { 479 if (CC_UNLIKELY(radius <= 0 || PaintUtils::paintWillNotDraw(paint))) return; 480 mCanvas->drawCircle(x, y, radius, paint); 481} 482 483void SkiaCanvas::drawOval(float left, float top, float right, float bottom, const SkPaint& paint) { 484 if (CC_UNLIKELY(PaintUtils::paintWillNotDraw(paint))) return; 485 SkRect oval = SkRect::MakeLTRB(left, top, right, bottom); 486 mCanvas->drawOval(oval, paint); 487} 488 489void SkiaCanvas::drawArc(float left, float top, float right, float bottom, 490 float startAngle, float sweepAngle, bool useCenter, const SkPaint& paint) { 491 if (CC_UNLIKELY(PaintUtils::paintWillNotDraw(paint))) return; 492 SkRect arc = SkRect::MakeLTRB(left, top, right, bottom); 493 mCanvas->drawArc(arc, startAngle, sweepAngle, useCenter, paint); 494} 495 496void SkiaCanvas::drawPath(const SkPath& path, const SkPaint& paint) { 497 if (CC_UNLIKELY(PaintUtils::paintWillNotDraw(paint))) return; 498 SkRect rect; 499 SkRRect roundRect; 500 if (path.isOval(&rect)) { 501 mCanvas->drawOval(rect, paint); 502 } else if (path.isRRect(&roundRect)) { 503 mCanvas->drawRRect(roundRect, paint); 504 } else { 505 mCanvas->drawPath(path, paint); 506 } 507} 508 509void SkiaCanvas::drawVertices(SkCanvas::VertexMode vertexMode, int vertexCount, 510 const float* verts, const float* texs, const int* colors, 511 const uint16_t* indices, int indexCount, const SkPaint& paint) { 512#ifndef SK_SCALAR_IS_FLOAT 513 SkDEBUGFAIL("SkScalar must be a float for these conversions to be valid"); 514#endif 515 const int ptCount = vertexCount >> 1; 516 mCanvas->drawVertices(vertexMode, ptCount, (SkPoint*)verts, (SkPoint*)texs, 517 (SkColor*)colors, indices, indexCount, paint); 518} 519 520// ---------------------------------------------------------------------------- 521// Canvas draw operations: Bitmaps 522// ---------------------------------------------------------------------------- 523 524void SkiaCanvas::drawBitmap(Bitmap& bitmap, float left, float top, const SkPaint* paint) { 525 SkBitmap skBitmap; 526 bitmap.getSkBitmap(&skBitmap); 527 mCanvas->drawBitmap(skBitmap, left, top, paint); 528} 529 530void SkiaCanvas::drawBitmap(Bitmap& hwuiBitmap, const SkMatrix& matrix, const SkPaint* paint) { 531 SkBitmap bitmap; 532 hwuiBitmap.getSkBitmap(&bitmap); 533 SkAutoCanvasRestore acr(mCanvas, true); 534 mCanvas->concat(matrix); 535 mCanvas->drawBitmap(bitmap, 0, 0, paint); 536} 537 538void SkiaCanvas::drawBitmap(Bitmap& hwuiBitmap, float srcLeft, float srcTop, 539 float srcRight, float srcBottom, float dstLeft, float dstTop, 540 float dstRight, float dstBottom, const SkPaint* paint) { 541 SkBitmap bitmap; 542 hwuiBitmap.getSkBitmap(&bitmap); 543 SkRect srcRect = SkRect::MakeLTRB(srcLeft, srcTop, srcRight, srcBottom); 544 SkRect dstRect = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom); 545 mCanvas->drawBitmapRect(bitmap, srcRect, dstRect, paint); 546} 547 548void SkiaCanvas::drawBitmapMesh(Bitmap& hwuiBitmap, int meshWidth, int meshHeight, 549 const float* vertices, const int* colors, const SkPaint* paint) { 550 SkBitmap bitmap; 551 hwuiBitmap.getSkBitmap(&bitmap); 552 const int ptCount = (meshWidth + 1) * (meshHeight + 1); 553 const int indexCount = meshWidth * meshHeight * 6; 554 555 /* Our temp storage holds 2 or 3 arrays. 556 texture points [ptCount * sizeof(SkPoint)] 557 optionally vertex points [ptCount * sizeof(SkPoint)] if we need a 558 copy to convert from float to fixed 559 indices [ptCount * sizeof(uint16_t)] 560 */ 561 ssize_t storageSize = ptCount * sizeof(SkPoint); // texs[] 562 storageSize += indexCount * sizeof(uint16_t); // indices[] 563 564 565#ifndef SK_SCALAR_IS_FLOAT 566 SkDEBUGFAIL("SkScalar must be a float for these conversions to be valid"); 567#endif 568 std::unique_ptr<char[]> storage(new char[storageSize]); 569 SkPoint* texs = (SkPoint*)storage.get(); 570 uint16_t* indices = (uint16_t*)(texs + ptCount); 571 572 // cons up texture coordinates and indices 573 { 574 const SkScalar w = SkIntToScalar(bitmap.width()); 575 const SkScalar h = SkIntToScalar(bitmap.height()); 576 const SkScalar dx = w / meshWidth; 577 const SkScalar dy = h / meshHeight; 578 579 SkPoint* texsPtr = texs; 580 SkScalar y = 0; 581 for (int i = 0; i <= meshHeight; i++) { 582 if (i == meshHeight) { 583 y = h; // to ensure numerically we hit h exactly 584 } 585 SkScalar x = 0; 586 for (int j = 0; j < meshWidth; j++) { 587 texsPtr->set(x, y); 588 texsPtr += 1; 589 x += dx; 590 } 591 texsPtr->set(w, y); 592 texsPtr += 1; 593 y += dy; 594 } 595 SkASSERT(texsPtr - texs == ptCount); 596 } 597 598 // cons up indices 599 { 600 uint16_t* indexPtr = indices; 601 int index = 0; 602 for (int i = 0; i < meshHeight; i++) { 603 for (int j = 0; j < meshWidth; j++) { 604 // lower-left triangle 605 *indexPtr++ = index; 606 *indexPtr++ = index + meshWidth + 1; 607 *indexPtr++ = index + meshWidth + 2; 608 // upper-right triangle 609 *indexPtr++ = index; 610 *indexPtr++ = index + meshWidth + 2; 611 *indexPtr++ = index + 1; 612 // bump to the next cell 613 index += 1; 614 } 615 // bump to the next row 616 index += 1; 617 } 618 SkASSERT(indexPtr - indices == indexCount); 619 SkASSERT((char*)indexPtr - (char*)storage.get() == storageSize); 620 } 621 622 // double-check that we have legal indices 623#ifdef SK_DEBUG 624 { 625 for (int i = 0; i < indexCount; i++) { 626 SkASSERT((unsigned)indices[i] < (unsigned)ptCount); 627 } 628 } 629#endif 630 631 // cons-up a shader for the bitmap 632 SkPaint tmpPaint; 633 if (paint) { 634 tmpPaint = *paint; 635 } 636 637 sk_sp<SkImage> image = SkMakeImageFromRasterBitmap(bitmap, kNever_SkCopyPixelsMode); 638 tmpPaint.setShader(image->makeShader(SkShader::kClamp_TileMode, SkShader::kClamp_TileMode)); 639 640 mCanvas->drawVertices(SkCanvas::kTriangles_VertexMode, ptCount, (SkPoint*)vertices, 641 texs, (const SkColor*)colors, indices, 642 indexCount, tmpPaint); 643} 644 645void SkiaCanvas::drawNinePatch(Bitmap& hwuiBitmap, const Res_png_9patch& chunk, 646 float dstLeft, float dstTop, float dstRight, float dstBottom, const SkPaint* paint) { 647 648 SkBitmap bitmap; 649 hwuiBitmap.getSkBitmap(&bitmap); 650 651 SkCanvas::Lattice lattice; 652 NinePatchUtils::SetLatticeDivs(&lattice, chunk, bitmap.width(), bitmap.height()); 653 654 lattice.fFlags = nullptr; 655 int numFlags = 0; 656 if (chunk.numColors > 0 && chunk.numColors == NinePatchUtils::NumDistinctRects(lattice)) { 657 // We can expect the framework to give us a color for every distinct rect. 658 // Skia requires a flag for every rect. 659 numFlags = (lattice.fXCount + 1) * (lattice.fYCount + 1); 660 } 661 662 SkAutoSTMalloc<25, SkCanvas::Lattice::Flags> flags(numFlags); 663 if (numFlags > 0) { 664 NinePatchUtils::SetLatticeFlags(&lattice, flags.get(), numFlags, chunk); 665 } 666 667 lattice.fBounds = nullptr; 668 SkRect dst = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom); 669 mCanvas->drawBitmapLattice(bitmap, lattice, dst, paint); 670} 671 672void SkiaCanvas::drawVectorDrawable(VectorDrawableRoot* vectorDrawable) { 673 vectorDrawable->drawStaging(this); 674} 675 676// ---------------------------------------------------------------------------- 677// Canvas draw operations: Text 678// ---------------------------------------------------------------------------- 679 680void SkiaCanvas::drawGlyphs(const uint16_t* text, const float* positions, int count, 681 const SkPaint& paint, float x, float y, 682 float boundsLeft, float boundsTop, float boundsRight, float boundsBottom, 683 float totalAdvance) { 684 if (!text || !positions || count <= 0 || PaintUtils::paintWillNotDrawText(paint)) return; 685 // Set align to left for drawing, as we don't want individual 686 // glyphs centered or right-aligned; the offset above takes 687 // care of all alignment. 688 SkPaint paintCopy(paint); 689 paintCopy.setTextAlign(SkPaint::kLeft_Align); 690 691 SkRect bounds = SkRect::MakeLTRB(boundsLeft + x, boundsTop + y, 692 boundsRight + x, boundsBottom + y); 693 694 SkTextBlobBuilder builder; 695 const SkTextBlobBuilder::RunBuffer& buffer = builder.allocRunPos(paintCopy, count, &bounds); 696 // TODO: we could reduce the number of memcpy's if the this were exposed further up 697 // in the architecture. 698 memcpy(buffer.glyphs, text, count * sizeof(uint16_t)); 699 memcpy(buffer.pos, positions, (count << 1) * sizeof(float)); 700 701 sk_sp<SkTextBlob> textBlob(builder.make()); 702 mCanvas->drawTextBlob(textBlob, 0, 0, paintCopy); 703 drawTextDecorations(x, y, totalAdvance, paintCopy); 704} 705 706void SkiaCanvas::drawLayoutOnPath(const minikin::Layout& layout, float hOffset, float vOffset, 707 const SkPaint& paint, const SkPath& path, size_t start, size_t end) { 708 const int N = end - start; 709 SkAutoSTMalloc<1024, uint8_t> storage(N * (sizeof(uint16_t) + sizeof(SkRSXform))); 710 SkRSXform* xform = (SkRSXform*)storage.get(); 711 uint16_t* glyphs = (uint16_t*)(xform + N); 712 SkPathMeasure meas(path, false); 713 714 for (size_t i = start; i < end; i++) { 715 glyphs[i - start] = layout.getGlyphId(i); 716 float x = hOffset + layout.getX(i); 717 float y = vOffset + layout.getY(i); 718 719 SkPoint pos; 720 SkVector tan; 721 if (!meas.getPosTan(x, &pos, &tan)) { 722 pos.set(x, y); 723 tan.set(1, 0); 724 } 725 xform[i - start].fSCos = tan.x(); 726 xform[i - start].fSSin = tan.y(); 727 xform[i - start].fTx = pos.x() - tan.y() * y; 728 xform[i - start].fTy = pos.y() + tan.x() * y; 729 } 730 731 this->asSkCanvas()->drawTextRSXform(glyphs, sizeof(uint16_t) * N, xform, nullptr, paint); 732} 733 734// ---------------------------------------------------------------------------- 735// Canvas draw operations: Animations 736// ---------------------------------------------------------------------------- 737 738void SkiaCanvas::drawRoundRect(uirenderer::CanvasPropertyPrimitive* left, 739 uirenderer::CanvasPropertyPrimitive* top, uirenderer::CanvasPropertyPrimitive* right, 740 uirenderer::CanvasPropertyPrimitive* bottom, uirenderer::CanvasPropertyPrimitive* rx, 741 uirenderer::CanvasPropertyPrimitive* ry, uirenderer::CanvasPropertyPaint* paint) { 742 sk_sp<uirenderer::skiapipeline::AnimatedRoundRect> drawable( 743 new uirenderer::skiapipeline::AnimatedRoundRect(left, top, right, bottom, rx, ry, paint)); 744 mCanvas->drawDrawable(drawable.get()); 745} 746 747void SkiaCanvas::drawCircle(uirenderer::CanvasPropertyPrimitive* x, uirenderer::CanvasPropertyPrimitive* y, 748 uirenderer::CanvasPropertyPrimitive* radius, uirenderer::CanvasPropertyPaint* paint) { 749 sk_sp<uirenderer::skiapipeline::AnimatedCircle> drawable(new uirenderer::skiapipeline::AnimatedCircle(x, y, radius, paint)); 750 mCanvas->drawDrawable(drawable.get()); 751} 752 753// ---------------------------------------------------------------------------- 754// Canvas draw operations: View System 755// ---------------------------------------------------------------------------- 756 757void SkiaCanvas::drawLayer(uirenderer::DeferredLayerUpdater* layerUpdater) { 758 LOG_ALWAYS_FATAL("SkiaCanvas can't directly draw Layers"); 759} 760 761void SkiaCanvas::drawRenderNode(uirenderer::RenderNode* renderNode) { 762 LOG_ALWAYS_FATAL("SkiaCanvas can't directly draw RenderNodes"); 763} 764 765void SkiaCanvas::callDrawGLFunction(Functor* functor, 766 uirenderer::GlFunctorLifecycleListener* listener) { 767 LOG_ALWAYS_FATAL("SkiaCanvas can't directly draw GL Content"); 768} 769 770} // namespace android 771