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