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