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