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