SkiaCanvas.cpp revision eecff56fed5dd5206acfbc5007b4912081b36d3b
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 "Canvas.h" 18 19#include <SkCanvas.h> 20#include <SkClipStack.h> 21#include <SkDevice.h> 22#include <SkDeque.h> 23#include <SkDrawFilter.h> 24#include <SkGraphics.h> 25#include <SkShader.h> 26#include <SkTArray.h> 27#include <SkTLazy.h> 28#include <SkTemplates.h> 29 30#include <memory> 31 32namespace android { 33 34// Holds an SkCanvas reference plus additional native data. 35class SkiaCanvas : public Canvas { 36public: 37 explicit SkiaCanvas(const SkBitmap& bitmap); 38 39 /** 40 * Create a new SkiaCanvas. 41 * 42 * @param canvas SkCanvas to handle calls made to this SkiaCanvas. Must 43 * not be NULL. This constructor will ref() the SkCanvas, and unref() 44 * it in its destructor. 45 */ 46 explicit SkiaCanvas(SkCanvas* canvas) : mCanvas(canvas) { 47 SkASSERT(canvas); 48 canvas->ref(); 49 } 50 51 virtual SkCanvas* asSkCanvas() override { 52 return mCanvas.get(); 53 } 54 55 virtual void setBitmap(const SkBitmap& bitmap) override; 56 57 virtual bool isOpaque() override; 58 virtual int width() override; 59 virtual int height() override; 60 61 virtual void setHighContrastText(bool highContrastText) override { 62 mHighContrastText = highContrastText; 63 } 64 virtual bool isHighContrastText() override { return mHighContrastText; } 65 66 virtual int getSaveCount() const override; 67 virtual int save(SaveFlags::Flags flags) override; 68 virtual void restore() override; 69 virtual void restoreToCount(int saveCount) override; 70 71 virtual int saveLayer(float left, float top, float right, float bottom, 72 const SkPaint* paint, SaveFlags::Flags flags) override; 73 virtual int saveLayerAlpha(float left, float top, float right, float bottom, 74 int alpha, SaveFlags::Flags flags) override; 75 76 virtual void getMatrix(SkMatrix* outMatrix) const override; 77 virtual void setMatrix(const SkMatrix& matrix) override; 78 virtual void concat(const SkMatrix& matrix) override; 79 virtual void rotate(float degrees) override; 80 virtual void scale(float sx, float sy) override; 81 virtual void skew(float sx, float sy) override; 82 virtual void translate(float dx, float dy) override; 83 84 virtual bool getClipBounds(SkRect* outRect) const override; 85 virtual bool quickRejectRect(float left, float top, float right, float bottom) const override; 86 virtual bool quickRejectPath(const SkPath& path) const override; 87 virtual bool clipRect(float left, float top, float right, float bottom, 88 SkRegion::Op op) override; 89 virtual bool clipPath(const SkPath* path, SkRegion::Op op) override; 90 virtual bool clipRegion(const SkRegion* region, SkRegion::Op op) override; 91 92 virtual SkDrawFilter* getDrawFilter() override; 93 virtual void setDrawFilter(SkDrawFilter* drawFilter) override; 94 95 virtual void drawColor(int color, SkXfermode::Mode mode) override; 96 virtual void drawPaint(const SkPaint& paint) override; 97 98 virtual void drawPoint(float x, float y, const SkPaint& paint) override; 99 virtual void drawPoints(const float* points, int count, const SkPaint& paint) override; 100 virtual void drawLine(float startX, float startY, float stopX, float stopY, 101 const SkPaint& paint) override; 102 virtual void drawLines(const float* points, int count, const SkPaint& paint) override; 103 virtual void drawRect(float left, float top, float right, float bottom, 104 const SkPaint& paint) override; 105 virtual void drawRegion(const SkRegion& region, const SkPaint& paint) override; 106 virtual void drawRoundRect(float left, float top, float right, float bottom, 107 float rx, float ry, const SkPaint& paint) override; 108 virtual void drawCircle(float x, float y, float radius, const SkPaint& paint) override; 109 virtual void drawOval(float left, float top, float right, float bottom, 110 const SkPaint& paint) override; 111 virtual void drawArc(float left, float top, float right, float bottom, 112 float startAngle, float sweepAngle, bool useCenter, const SkPaint& paint) override; 113 virtual void drawPath(const SkPath& path, const SkPaint& paint) override; 114 virtual void drawVertices(SkCanvas::VertexMode vertexMode, int vertexCount, 115 const float* verts, const float* tex, const int* colors, 116 const uint16_t* indices, int indexCount, const SkPaint& paint) override; 117 118 virtual void drawBitmap(const SkBitmap& bitmap, float left, float top, 119 const SkPaint* paint) override; 120 virtual void drawBitmap(const SkBitmap& bitmap, const SkMatrix& matrix, 121 const SkPaint* paint) override; 122 virtual void drawBitmap(const SkBitmap& bitmap, float srcLeft, float srcTop, 123 float srcRight, float srcBottom, float dstLeft, float dstTop, 124 float dstRight, float dstBottom, const SkPaint* paint) override; 125 virtual void drawBitmapMesh(const SkBitmap& bitmap, int meshWidth, int meshHeight, 126 const float* vertices, const int* colors, const SkPaint* paint) override; 127 virtual void drawNinePatch(const SkBitmap& bitmap, const android::Res_png_9patch& chunk, 128 float dstLeft, float dstTop, float dstRight, float dstBottom, 129 const SkPaint* paint) override; 130 131 virtual void drawText(const uint16_t* text, const float* positions, int count, 132 const SkPaint& paint, float x, float y, 133 float boundsLeft, float boundsTop, float boundsRight, float boundsBottom, 134 float totalAdvance) override; 135 virtual void drawTextOnPath(const uint16_t* glyphs, int count, const SkPath& path, 136 float hOffset, float vOffset, const SkPaint& paint) override; 137 138 virtual bool drawTextAbsolutePos() const override { return true; } 139 140private: 141 struct SaveRec { 142 int saveCount; 143 SaveFlags::Flags saveFlags; 144 }; 145 146 bool mHighContrastText = false; 147 148 void recordPartialSave(SaveFlags::Flags flags); 149 void saveClipsForFrame(SkTArray<SkClipStack::Element>& clips, int frameSaveCount); 150 void applyClips(const SkTArray<SkClipStack::Element>& clips); 151 152 void drawPoints(const float* points, int count, const SkPaint& paint, 153 SkCanvas::PointMode mode); 154 155 SkAutoTUnref<SkCanvas> mCanvas; 156 std::unique_ptr<SkDeque> mSaveStack; // lazily allocated, tracks partial saves. 157}; 158 159Canvas* Canvas::create_canvas(const SkBitmap& bitmap) { 160 return new SkiaCanvas(bitmap); 161} 162 163Canvas* Canvas::create_canvas(SkCanvas* skiaCanvas) { 164 return new SkiaCanvas(skiaCanvas); 165} 166 167SkiaCanvas::SkiaCanvas(const SkBitmap& bitmap) { 168 mCanvas.reset(new SkCanvas(bitmap)); 169} 170 171// ---------------------------------------------------------------------------- 172// Canvas state operations: Replace Bitmap 173// ---------------------------------------------------------------------------- 174 175class ClipCopier : public SkCanvas::ClipVisitor { 176public: 177 ClipCopier(SkCanvas* dstCanvas) : m_dstCanvas(dstCanvas) {} 178 179 virtual void clipRect(const SkRect& rect, SkRegion::Op op, bool antialias) { 180 m_dstCanvas->clipRect(rect, op, antialias); 181 } 182 virtual void clipRRect(const SkRRect& rrect, SkRegion::Op op, bool antialias) { 183 m_dstCanvas->clipRRect(rrect, op, antialias); 184 } 185 virtual void clipPath(const SkPath& path, SkRegion::Op op, bool antialias) { 186 m_dstCanvas->clipPath(path, op, antialias); 187 } 188 189private: 190 SkCanvas* m_dstCanvas; 191}; 192 193void SkiaCanvas::setBitmap(const SkBitmap& bitmap) { 194 SkCanvas* newCanvas = new SkCanvas(bitmap); 195 196 if (!bitmap.isNull()) { 197 // Copy the canvas matrix & clip state. 198 newCanvas->setMatrix(mCanvas->getTotalMatrix()); 199 200 ClipCopier copier(newCanvas); 201 mCanvas->replayClips(&copier); 202 } 203 204 // unrefs the existing canvas 205 mCanvas.reset(newCanvas); 206 207 // clean up the old save stack 208 mSaveStack.reset(NULL); 209} 210 211// ---------------------------------------------------------------------------- 212// Canvas state operations 213// ---------------------------------------------------------------------------- 214 215bool SkiaCanvas::isOpaque() { 216 return mCanvas->imageInfo().isOpaque(); 217} 218 219int SkiaCanvas::width() { 220 return mCanvas->imageInfo().width(); 221} 222 223int SkiaCanvas::height() { 224 return mCanvas->imageInfo().height(); 225} 226 227// ---------------------------------------------------------------------------- 228// Canvas state operations: Save (layer) 229// ---------------------------------------------------------------------------- 230 231int SkiaCanvas::getSaveCount() const { 232 return mCanvas->getSaveCount(); 233} 234 235int SkiaCanvas::save(SaveFlags::Flags flags) { 236 int count = mCanvas->save(); 237 recordPartialSave(flags); 238 return count; 239} 240 241// The SkiaCanvas::restore operation layers on the capability to preserve 242// either (or both) the matrix and/or clip state after a SkCanvas::restore 243// operation. It does this by explicitly saving off the clip & matrix state 244// when requested and playing it back after the SkCanvas::restore. 245void SkiaCanvas::restore() { 246 const SaveRec* rec = (NULL == mSaveStack.get()) 247 ? NULL 248 : static_cast<SaveRec*>(mSaveStack->back()); 249 int currentSaveCount = mCanvas->getSaveCount(); 250 SkASSERT(NULL == rec || currentSaveCount >= rec->saveCount); 251 252 if (NULL == rec || rec->saveCount != currentSaveCount) { 253 // Fast path - no record for this frame. 254 mCanvas->restore(); 255 return; 256 } 257 258 bool preserveMatrix = !(rec->saveFlags & SaveFlags::Matrix); 259 bool preserveClip = !(rec->saveFlags & SaveFlags::Clip); 260 261 SkMatrix savedMatrix; 262 if (preserveMatrix) { 263 savedMatrix = mCanvas->getTotalMatrix(); 264 } 265 266 SkTArray<SkClipStack::Element> savedClips; 267 int topClipStackFrame = mCanvas->getClipStack()->getSaveCount(); 268 if (preserveClip) { 269 saveClipsForFrame(savedClips, topClipStackFrame); 270 } 271 272 mCanvas->restore(); 273 274 if (preserveMatrix) { 275 mCanvas->setMatrix(savedMatrix); 276 } 277 278 if (preserveClip && !savedClips.empty() && 279 topClipStackFrame != mCanvas->getClipStack()->getSaveCount()) { 280 // Only reapply the saved clips if the top clip stack frame was actually 281 // popped by restore(). If it wasn't, it means it doesn't belong to the 282 // restored canvas frame (SkCanvas lazy save/restore kicked in). 283 applyClips(savedClips); 284 } 285 286 mSaveStack->pop_back(); 287} 288 289void SkiaCanvas::restoreToCount(int restoreCount) { 290 while (mCanvas->getSaveCount() > restoreCount) { 291 this->restore(); 292 } 293} 294 295static inline SkCanvas::SaveLayerFlags layerFlags(SaveFlags::Flags flags) { 296 SkCanvas::SaveLayerFlags layerFlags = 0; 297 298 if (!(flags & SaveFlags::HasAlphaLayer)) { 299 layerFlags |= SkCanvas::kIsOpaque_SaveLayerFlag; 300 } 301 302 if (!(flags & SaveFlags::ClipToLayer)) { 303 layerFlags |= SkCanvas::kDontClipToLayer_Legacy_SaveLayerFlag; 304 } 305 306 return layerFlags; 307} 308 309int SkiaCanvas::saveLayer(float left, float top, float right, float bottom, 310 const SkPaint* paint, SaveFlags::Flags flags) { 311 const SkRect bounds = SkRect::MakeLTRB(left, top, right, bottom); 312 const SkCanvas::SaveLayerRec rec(&bounds, paint, layerFlags(flags)); 313 314 int count = mCanvas->saveLayer(rec); 315 recordPartialSave(flags); 316 return count; 317} 318 319int SkiaCanvas::saveLayerAlpha(float left, float top, float right, float bottom, 320 int alpha, SaveFlags::Flags flags) { 321 SkTLazy<SkPaint> alphaPaint; 322 if (static_cast<unsigned>(alpha) < 0xFF) { 323 alphaPaint.init()->setAlpha(alpha); 324 } 325 326 return this->saveLayer(left, top, right, bottom, alphaPaint.getMaybeNull(), 327 flags); 328} 329 330// ---------------------------------------------------------------------------- 331// functions to emulate legacy SaveFlags (i.e. independent matrix/clip flags) 332// ---------------------------------------------------------------------------- 333 334void SkiaCanvas::recordPartialSave(SaveFlags::Flags flags) { 335 // A partial save is a save operation which doesn't capture the full canvas state. 336 // (either SaveFlags::Matrix or SaveFlags::Clip is missing). 337 338 // Mask-out non canvas state bits. 339 flags &= SaveFlags::MatrixClip; 340 341 if (flags == SaveFlags::MatrixClip) { 342 // not a partial save. 343 return; 344 } 345 346 if (NULL == mSaveStack.get()) { 347 mSaveStack.reset(new SkDeque(sizeof(struct SaveRec), 8)); 348 } 349 350 SaveRec* rec = static_cast<SaveRec*>(mSaveStack->push_back()); 351 rec->saveCount = mCanvas->getSaveCount(); 352 rec->saveFlags = flags; 353} 354 355void SkiaCanvas::saveClipsForFrame(SkTArray<SkClipStack::Element>& clips, 356 int saveCountToBackup) { 357 // Each SkClipStack::Element stores the index of the canvas save 358 // with which it is associated. Backup only those Elements that 359 // are associated with 'saveCountToBackup' 360 SkClipStack::Iter clipIterator(*mCanvas->getClipStack(), 361 SkClipStack::Iter::kTop_IterStart); 362 while (const SkClipStack::Element* elem = clipIterator.prev()) { 363 if (elem->getSaveCount() < saveCountToBackup) { 364 // done with the target save count. 365 break; 366 } 367 SkASSERT(elem->getSaveCount() == saveCountToBackup); 368 clips.push_back(*elem); 369 } 370} 371 372void SkiaCanvas::applyClips(const SkTArray<SkClipStack::Element>& clips) { 373 ClipCopier clipCopier(mCanvas); 374 375 // The clip stack stores clips in device space. 376 SkMatrix origMatrix = mCanvas->getTotalMatrix(); 377 mCanvas->resetMatrix(); 378 379 // We pushed the clips in reverse order. 380 for (int i = clips.count() - 1; i >= 0; --i) { 381 clips[i].replay(&clipCopier); 382 } 383 384 mCanvas->setMatrix(origMatrix); 385} 386 387// ---------------------------------------------------------------------------- 388// Canvas state operations: Matrix 389// ---------------------------------------------------------------------------- 390 391void SkiaCanvas::getMatrix(SkMatrix* outMatrix) const { 392 *outMatrix = mCanvas->getTotalMatrix(); 393} 394 395void SkiaCanvas::setMatrix(const SkMatrix& matrix) { 396 mCanvas->setMatrix(matrix); 397} 398 399void SkiaCanvas::concat(const SkMatrix& matrix) { 400 mCanvas->concat(matrix); 401} 402 403void SkiaCanvas::rotate(float degrees) { 404 mCanvas->rotate(degrees); 405} 406 407void SkiaCanvas::scale(float sx, float sy) { 408 mCanvas->scale(sx, sy); 409} 410 411void SkiaCanvas::skew(float sx, float sy) { 412 mCanvas->skew(sx, sy); 413} 414 415void SkiaCanvas::translate(float dx, float dy) { 416 mCanvas->translate(dx, dy); 417} 418 419// ---------------------------------------------------------------------------- 420// Canvas state operations: Clips 421// ---------------------------------------------------------------------------- 422 423// This function is a mirror of SkCanvas::getClipBounds except that it does 424// not outset the edge of the clip to account for anti-aliasing. There is 425// a skia bug to investigate pushing this logic into back into skia. 426// (see https://code.google.com/p/skia/issues/detail?id=1303) 427bool SkiaCanvas::getClipBounds(SkRect* outRect) const { 428 SkIRect ibounds; 429 if (!mCanvas->getClipDeviceBounds(&ibounds)) { 430 return false; 431 } 432 433 SkMatrix inverse; 434 // if we can't invert the CTM, we can't return local clip bounds 435 if (!mCanvas->getTotalMatrix().invert(&inverse)) { 436 if (outRect) { 437 outRect->setEmpty(); 438 } 439 return false; 440 } 441 442 if (NULL != outRect) { 443 SkRect r = SkRect::Make(ibounds); 444 inverse.mapRect(outRect, r); 445 } 446 return true; 447} 448 449bool SkiaCanvas::quickRejectRect(float left, float top, float right, float bottom) const { 450 SkRect bounds = SkRect::MakeLTRB(left, top, right, bottom); 451 return mCanvas->quickReject(bounds); 452} 453 454bool SkiaCanvas::quickRejectPath(const SkPath& path) const { 455 return mCanvas->quickReject(path); 456} 457 458bool SkiaCanvas::clipRect(float left, float top, float right, float bottom, SkRegion::Op op) { 459 SkRect rect = SkRect::MakeLTRB(left, top, right, bottom); 460 mCanvas->clipRect(rect, op); 461 return !mCanvas->isClipEmpty(); 462} 463 464bool SkiaCanvas::clipPath(const SkPath* path, SkRegion::Op op) { 465 mCanvas->clipPath(*path, op); 466 return !mCanvas->isClipEmpty(); 467} 468 469bool SkiaCanvas::clipRegion(const SkRegion* region, SkRegion::Op op) { 470 SkPath rgnPath; 471 if (region->getBoundaryPath(&rgnPath)) { 472 // The region is specified in device space. 473 SkMatrix savedMatrix = mCanvas->getTotalMatrix(); 474 mCanvas->resetMatrix(); 475 mCanvas->clipPath(rgnPath, op); 476 mCanvas->setMatrix(savedMatrix); 477 } else { 478 mCanvas->clipRect(SkRect::MakeEmpty(), op); 479 } 480 return !mCanvas->isClipEmpty(); 481} 482 483// ---------------------------------------------------------------------------- 484// Canvas state operations: Filters 485// ---------------------------------------------------------------------------- 486 487SkDrawFilter* SkiaCanvas::getDrawFilter() { 488 return mCanvas->getDrawFilter(); 489} 490 491void SkiaCanvas::setDrawFilter(SkDrawFilter* drawFilter) { 492 mCanvas->setDrawFilter(drawFilter); 493} 494 495// ---------------------------------------------------------------------------- 496// Canvas draw operations 497// ---------------------------------------------------------------------------- 498 499void SkiaCanvas::drawColor(int color, SkXfermode::Mode mode) { 500 mCanvas->drawColor(color, mode); 501} 502 503void SkiaCanvas::drawPaint(const SkPaint& paint) { 504 mCanvas->drawPaint(paint); 505} 506 507// ---------------------------------------------------------------------------- 508// Canvas draw operations: Geometry 509// ---------------------------------------------------------------------------- 510 511void SkiaCanvas::drawPoints(const float* points, int count, const SkPaint& paint, 512 SkCanvas::PointMode mode) { 513 // convert the floats into SkPoints 514 count >>= 1; // now it is the number of points 515 std::unique_ptr<SkPoint[]> pts(new SkPoint[count]); 516 for (int i = 0; i < count; i++) { 517 pts[i].set(points[0], points[1]); 518 points += 2; 519 } 520 mCanvas->drawPoints(mode, count, pts.get(), paint); 521} 522 523 524void SkiaCanvas::drawPoint(float x, float y, const SkPaint& paint) { 525 mCanvas->drawPoint(x, y, paint); 526} 527 528void SkiaCanvas::drawPoints(const float* points, int count, const SkPaint& paint) { 529 this->drawPoints(points, count, paint, SkCanvas::kPoints_PointMode); 530} 531 532void SkiaCanvas::drawLine(float startX, float startY, float stopX, float stopY, 533 const SkPaint& paint) { 534 mCanvas->drawLine(startX, startY, stopX, stopY, paint); 535} 536 537void SkiaCanvas::drawLines(const float* points, int count, const SkPaint& paint) { 538 this->drawPoints(points, count, paint, SkCanvas::kLines_PointMode); 539} 540 541void SkiaCanvas::drawRect(float left, float top, float right, float bottom, 542 const SkPaint& paint) { 543 mCanvas->drawRectCoords(left, top, right, bottom, paint); 544 545} 546 547void SkiaCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) { 548 SkRegion::Iterator it(region); 549 while (!it.done()) { 550 mCanvas->drawRect(SkRect::Make(it.rect()), paint); 551 it.next(); 552 } 553} 554 555void SkiaCanvas::drawRoundRect(float left, float top, float right, float bottom, 556 float rx, float ry, const SkPaint& paint) { 557 SkRect rect = SkRect::MakeLTRB(left, top, right, bottom); 558 mCanvas->drawRoundRect(rect, rx, ry, paint); 559} 560 561void SkiaCanvas::drawCircle(float x, float y, float radius, const SkPaint& paint) { 562 mCanvas->drawCircle(x, y, radius, paint); 563} 564 565void SkiaCanvas::drawOval(float left, float top, float right, float bottom, const SkPaint& paint) { 566 SkRect oval = SkRect::MakeLTRB(left, top, right, bottom); 567 mCanvas->drawOval(oval, paint); 568} 569 570void SkiaCanvas::drawArc(float left, float top, float right, float bottom, 571 float startAngle, float sweepAngle, bool useCenter, const SkPaint& paint) { 572 SkRect arc = SkRect::MakeLTRB(left, top, right, bottom); 573 mCanvas->drawArc(arc, startAngle, sweepAngle, useCenter, paint); 574} 575 576void SkiaCanvas::drawPath(const SkPath& path, const SkPaint& paint) { 577 mCanvas->drawPath(path, paint); 578} 579 580void SkiaCanvas::drawVertices(SkCanvas::VertexMode vertexMode, int vertexCount, 581 const float* verts, const float* texs, const int* colors, 582 const uint16_t* indices, int indexCount, const SkPaint& paint) { 583#ifndef SK_SCALAR_IS_FLOAT 584 SkDEBUGFAIL("SkScalar must be a float for these conversions to be valid"); 585#endif 586 const int ptCount = vertexCount >> 1; 587 mCanvas->drawVertices(vertexMode, ptCount, (SkPoint*)verts, (SkPoint*)texs, 588 (SkColor*)colors, NULL, indices, indexCount, paint); 589} 590 591// ---------------------------------------------------------------------------- 592// Canvas draw operations: Bitmaps 593// ---------------------------------------------------------------------------- 594 595void SkiaCanvas::drawBitmap(const SkBitmap& bitmap, float left, float top, const SkPaint* paint) { 596 mCanvas->drawBitmap(bitmap, left, top, paint); 597} 598 599void SkiaCanvas::drawBitmap(const SkBitmap& bitmap, const SkMatrix& matrix, const SkPaint* paint) { 600 SkAutoCanvasRestore acr(mCanvas, true); 601 mCanvas->concat(matrix); 602 mCanvas->drawBitmap(bitmap, 0, 0, paint); 603} 604 605void SkiaCanvas::drawBitmap(const SkBitmap& bitmap, float srcLeft, float srcTop, 606 float srcRight, float srcBottom, float dstLeft, float dstTop, 607 float dstRight, float dstBottom, const SkPaint* paint) { 608 SkRect srcRect = SkRect::MakeLTRB(srcLeft, srcTop, srcRight, srcBottom); 609 SkRect dstRect = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom); 610 mCanvas->drawBitmapRect(bitmap, srcRect, dstRect, paint); 611} 612 613void SkiaCanvas::drawBitmapMesh(const SkBitmap& bitmap, int meshWidth, int meshHeight, 614 const float* vertices, const int* colors, const SkPaint* paint) { 615 616 const int ptCount = (meshWidth + 1) * (meshHeight + 1); 617 const int indexCount = meshWidth * meshHeight * 6; 618 619 /* Our temp storage holds 2 or 3 arrays. 620 texture points [ptCount * sizeof(SkPoint)] 621 optionally vertex points [ptCount * sizeof(SkPoint)] if we need a 622 copy to convert from float to fixed 623 indices [ptCount * sizeof(uint16_t)] 624 */ 625 ssize_t storageSize = ptCount * sizeof(SkPoint); // texs[] 626 storageSize += indexCount * sizeof(uint16_t); // indices[] 627 628 629#ifndef SK_SCALAR_IS_FLOAT 630 SkDEBUGFAIL("SkScalar must be a float for these conversions to be valid"); 631#endif 632 std::unique_ptr<char[]> storage(new char[storageSize]); 633 SkPoint* texs = (SkPoint*)storage.get(); 634 uint16_t* indices = (uint16_t*)(texs + ptCount); 635 636 // cons up texture coordinates and indices 637 { 638 const SkScalar w = SkIntToScalar(bitmap.width()); 639 const SkScalar h = SkIntToScalar(bitmap.height()); 640 const SkScalar dx = w / meshWidth; 641 const SkScalar dy = h / meshHeight; 642 643 SkPoint* texsPtr = texs; 644 SkScalar y = 0; 645 for (int i = 0; i <= meshHeight; i++) { 646 if (i == meshHeight) { 647 y = h; // to ensure numerically we hit h exactly 648 } 649 SkScalar x = 0; 650 for (int j = 0; j < meshWidth; j++) { 651 texsPtr->set(x, y); 652 texsPtr += 1; 653 x += dx; 654 } 655 texsPtr->set(w, y); 656 texsPtr += 1; 657 y += dy; 658 } 659 SkASSERT(texsPtr - texs == ptCount); 660 } 661 662 // cons up indices 663 { 664 uint16_t* indexPtr = indices; 665 int index = 0; 666 for (int i = 0; i < meshHeight; i++) { 667 for (int j = 0; j < meshWidth; j++) { 668 // lower-left triangle 669 *indexPtr++ = index; 670 *indexPtr++ = index + meshWidth + 1; 671 *indexPtr++ = index + meshWidth + 2; 672 // upper-right triangle 673 *indexPtr++ = index; 674 *indexPtr++ = index + meshWidth + 2; 675 *indexPtr++ = index + 1; 676 // bump to the next cell 677 index += 1; 678 } 679 // bump to the next row 680 index += 1; 681 } 682 SkASSERT(indexPtr - indices == indexCount); 683 SkASSERT((char*)indexPtr - (char*)storage.get() == storageSize); 684 } 685 686 // double-check that we have legal indices 687#ifdef SK_DEBUG 688 { 689 for (int i = 0; i < indexCount; i++) { 690 SkASSERT((unsigned)indices[i] < (unsigned)ptCount); 691 } 692 } 693#endif 694 695 // cons-up a shader for the bitmap 696 SkPaint tmpPaint; 697 if (paint) { 698 tmpPaint = *paint; 699 } 700 SkShader* shader = SkShader::CreateBitmapShader(bitmap, 701 SkShader::kClamp_TileMode, 702 SkShader::kClamp_TileMode); 703 SkSafeUnref(tmpPaint.setShader(shader)); 704 705 mCanvas->drawVertices(SkCanvas::kTriangles_VertexMode, ptCount, (SkPoint*)vertices, 706 texs, (const SkColor*)colors, NULL, indices, 707 indexCount, tmpPaint); 708} 709 710void SkiaCanvas::drawNinePatch(const SkBitmap& bitmap, const Res_png_9patch& chunk, 711 float dstLeft, float dstTop, float dstRight, float dstBottom, const SkPaint* paint) { 712 SkRect bounds = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom); 713 NinePatch::Draw(mCanvas, bounds, bitmap, chunk, paint, nullptr); 714} 715 716// ---------------------------------------------------------------------------- 717// Canvas draw operations: Text 718// ---------------------------------------------------------------------------- 719 720void SkiaCanvas::drawText(const uint16_t* text, const float* positions, int count, 721 const SkPaint& paint, float x, float y, 722 float boundsLeft, float boundsTop, float boundsRight, float boundsBottom, 723 float totalAdvance) { 724 // Set align to left for drawing, as we don't want individual 725 // glyphs centered or right-aligned; the offset above takes 726 // care of all alignment. 727 SkPaint paintCopy(paint); 728 paintCopy.setTextAlign(SkPaint::kLeft_Align); 729 730 static_assert(sizeof(SkPoint) == sizeof(float)*2, "SkPoint is no longer two floats"); 731 mCanvas->drawPosText(text, count << 1, reinterpret_cast<const SkPoint*>(positions), paintCopy); 732 drawTextDecorations(x, y, totalAdvance, paint); 733} 734 735void SkiaCanvas::drawTextOnPath(const uint16_t* glyphs, int count, const SkPath& path, 736 float hOffset, float vOffset, const SkPaint& paint) { 737 mCanvas->drawTextOnPathHV(glyphs, count << 1, path, hOffset, vOffset, paint); 738} 739 740} // namespace android 741