1 /* 2 * Copyright 2011 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #include "SkPDFDevice.h" 9 10 #include "SkAnnotation.h" 11 #include "SkColor.h" 12 #include "SkClipStack.h" 13 #include "SkData.h" 14 #include "SkDraw.h" 15 #include "SkFontHost.h" 16 #include "SkGlyphCache.h" 17 #include "SkPaint.h" 18 #include "SkPath.h" 19 #include "SkPathOps.h" 20 #include "SkPDFFont.h" 21 #include "SkPDFFormXObject.h" 22 #include "SkPDFGraphicState.h" 23 #include "SkPDFImage.h" 24 #include "SkPDFResourceDict.h" 25 #include "SkPDFShader.h" 26 #include "SkPDFStream.h" 27 #include "SkPDFTypes.h" 28 #include "SkPDFUtils.h" 29 #include "SkRect.h" 30 #include "SkRRect.h" 31 #include "SkString.h" 32 #include "SkTextFormatParams.h" 33 #include "SkTemplates.h" 34 #include "SkTypefacePriv.h" 35 #include "SkTSet.h" 36 37 #ifdef SK_BUILD_FOR_ANDROID 38 #include "SkTypeface_android.h" 39 40 struct TypefaceFallbackData { 41 SkTypeface* typeface; 42 int lowerBounds; 43 int upperBounds; 44 45 bool operator==(const TypefaceFallbackData& b) const { 46 return typeface == b.typeface && 47 lowerBounds == b.lowerBounds && 48 upperBounds == b.upperBounds; 49 } 50 }; 51 #endif 52 53 #define DPI_FOR_RASTER_SCALE_ONE 72 54 55 // Utility functions 56 57 static void emit_pdf_color(SkColor color, SkWStream* result) { 58 SkASSERT(SkColorGetA(color) == 0xFF); // We handle alpha elsewhere. 59 SkScalar colorMax = SkIntToScalar(0xFF); 60 SkPDFScalar::Append( 61 SkScalarDiv(SkIntToScalar(SkColorGetR(color)), colorMax), result); 62 result->writeText(" "); 63 SkPDFScalar::Append( 64 SkScalarDiv(SkIntToScalar(SkColorGetG(color)), colorMax), result); 65 result->writeText(" "); 66 SkPDFScalar::Append( 67 SkScalarDiv(SkIntToScalar(SkColorGetB(color)), colorMax), result); 68 result->writeText(" "); 69 } 70 71 static SkPaint calculate_text_paint(const SkPaint& paint) { 72 SkPaint result = paint; 73 if (result.isFakeBoldText()) { 74 SkScalar fakeBoldScale = SkScalarInterpFunc(result.getTextSize(), 75 kStdFakeBoldInterpKeys, 76 kStdFakeBoldInterpValues, 77 kStdFakeBoldInterpLength); 78 SkScalar width = SkScalarMul(result.getTextSize(), fakeBoldScale); 79 if (result.getStyle() == SkPaint::kFill_Style) { 80 result.setStyle(SkPaint::kStrokeAndFill_Style); 81 } else { 82 width += result.getStrokeWidth(); 83 } 84 result.setStrokeWidth(width); 85 } 86 return result; 87 } 88 89 // Stolen from measure_text in SkDraw.cpp and then tweaked. 90 static void align_text(SkDrawCacheProc glyphCacheProc, const SkPaint& paint, 91 const uint16_t* glyphs, size_t len, 92 SkScalar* x, SkScalar* y) { 93 if (paint.getTextAlign() == SkPaint::kLeft_Align) { 94 return; 95 } 96 97 SkMatrix ident; 98 ident.reset(); 99 SkAutoGlyphCache autoCache(paint, NULL, &ident); 100 SkGlyphCache* cache = autoCache.getCache(); 101 102 const char* start = reinterpret_cast<const char*>(glyphs); 103 const char* stop = reinterpret_cast<const char*>(glyphs + len); 104 SkFixed xAdv = 0, yAdv = 0; 105 106 // TODO(vandebo): This probably needs to take kerning into account. 107 while (start < stop) { 108 const SkGlyph& glyph = glyphCacheProc(cache, &start, 0, 0); 109 xAdv += glyph.fAdvanceX; 110 yAdv += glyph.fAdvanceY; 111 }; 112 if (paint.getTextAlign() == SkPaint::kLeft_Align) { 113 return; 114 } 115 116 SkScalar xAdj = SkFixedToScalar(xAdv); 117 SkScalar yAdj = SkFixedToScalar(yAdv); 118 if (paint.getTextAlign() == SkPaint::kCenter_Align) { 119 xAdj = SkScalarHalf(xAdj); 120 yAdj = SkScalarHalf(yAdj); 121 } 122 *x = *x - xAdj; 123 *y = *y - yAdj; 124 } 125 126 static int max_glyphid_for_typeface(SkTypeface* typeface) { 127 SkAutoResolveDefaultTypeface autoResolve(typeface); 128 typeface = autoResolve.get(); 129 return typeface->countGlyphs() - 1; 130 } 131 132 typedef SkAutoSTMalloc<128, uint16_t> SkGlyphStorage; 133 134 static int force_glyph_encoding(const SkPaint& paint, const void* text, 135 size_t len, SkGlyphStorage* storage, 136 uint16_t** glyphIDs) { 137 // Make sure we have a glyph id encoding. 138 if (paint.getTextEncoding() != SkPaint::kGlyphID_TextEncoding) { 139 int numGlyphs = paint.textToGlyphs(text, len, NULL); 140 storage->reset(numGlyphs); 141 paint.textToGlyphs(text, len, storage->get()); 142 *glyphIDs = storage->get(); 143 return numGlyphs; 144 } 145 146 // For user supplied glyph ids we need to validate them. 147 SkASSERT((len & 1) == 0); 148 int numGlyphs = SkToInt(len / 2); 149 const uint16_t* input = 150 reinterpret_cast<uint16_t*>(const_cast<void*>((text))); 151 152 int maxGlyphID = max_glyphid_for_typeface(paint.getTypeface()); 153 int validated; 154 for (validated = 0; validated < numGlyphs; ++validated) { 155 if (input[validated] > maxGlyphID) { 156 break; 157 } 158 } 159 if (validated >= numGlyphs) { 160 *glyphIDs = reinterpret_cast<uint16_t*>(const_cast<void*>((text))); 161 return numGlyphs; 162 } 163 164 // Silently drop anything out of range. 165 storage->reset(numGlyphs); 166 if (validated > 0) { 167 memcpy(storage->get(), input, validated * sizeof(uint16_t)); 168 } 169 170 for (int i = validated; i < numGlyphs; ++i) { 171 storage->get()[i] = input[i]; 172 if (input[i] > maxGlyphID) { 173 storage->get()[i] = 0; 174 } 175 } 176 *glyphIDs = storage->get(); 177 return numGlyphs; 178 } 179 180 static void set_text_transform(SkScalar x, SkScalar y, SkScalar textSkewX, 181 SkWStream* content) { 182 // Flip the text about the x-axis to account for origin swap and include 183 // the passed parameters. 184 content->writeText("1 0 "); 185 SkPDFScalar::Append(0 - textSkewX, content); 186 content->writeText(" -1 "); 187 SkPDFScalar::Append(x, content); 188 content->writeText(" "); 189 SkPDFScalar::Append(y, content); 190 content->writeText(" Tm\n"); 191 } 192 193 // It is important to not confuse GraphicStateEntry with SkPDFGraphicState, the 194 // later being our representation of an object in the PDF file. 195 struct GraphicStateEntry { 196 GraphicStateEntry(); 197 198 // Compare the fields we care about when setting up a new content entry. 199 bool compareInitialState(const GraphicStateEntry& b); 200 201 SkMatrix fMatrix; 202 // We can't do set operations on Paths, though PDF natively supports 203 // intersect. If the clip stack does anything other than intersect, 204 // we have to fall back to the region. Treat fClipStack as authoritative. 205 // See http://code.google.com/p/skia/issues/detail?id=221 206 SkClipStack fClipStack; 207 SkRegion fClipRegion; 208 209 // When emitting the content entry, we will ensure the graphic state 210 // is set to these values first. 211 SkColor fColor; 212 SkScalar fTextScaleX; // Zero means we don't care what the value is. 213 SkPaint::Style fTextFill; // Only if TextScaleX is non-zero. 214 int fShaderIndex; 215 int fGraphicStateIndex; 216 217 // We may change the font (i.e. for Type1 support) within a 218 // ContentEntry. This is the one currently in effect, or NULL if none. 219 SkPDFFont* fFont; 220 // In PDF, text size has no default value. It is only valid if fFont is 221 // not NULL. 222 SkScalar fTextSize; 223 }; 224 225 GraphicStateEntry::GraphicStateEntry() : fColor(SK_ColorBLACK), 226 fTextScaleX(SK_Scalar1), 227 fTextFill(SkPaint::kFill_Style), 228 fShaderIndex(-1), 229 fGraphicStateIndex(-1), 230 fFont(NULL), 231 fTextSize(SK_ScalarNaN) { 232 fMatrix.reset(); 233 } 234 235 bool GraphicStateEntry::compareInitialState(const GraphicStateEntry& cur) { 236 return fColor == cur.fColor && 237 fShaderIndex == cur.fShaderIndex && 238 fGraphicStateIndex == cur.fGraphicStateIndex && 239 fMatrix == cur.fMatrix && 240 fClipStack == cur.fClipStack && 241 (fTextScaleX == 0 || 242 (fTextScaleX == cur.fTextScaleX && fTextFill == cur.fTextFill)); 243 } 244 245 class GraphicStackState { 246 public: 247 GraphicStackState(const SkClipStack& existingClipStack, 248 const SkRegion& existingClipRegion, 249 SkWStream* contentStream) 250 : fStackDepth(0), 251 fContentStream(contentStream) { 252 fEntries[0].fClipStack = existingClipStack; 253 fEntries[0].fClipRegion = existingClipRegion; 254 } 255 256 void updateClip(const SkClipStack& clipStack, const SkRegion& clipRegion, 257 const SkPoint& translation); 258 void updateMatrix(const SkMatrix& matrix); 259 void updateDrawingState(const GraphicStateEntry& state); 260 261 void drainStack(); 262 263 private: 264 void push(); 265 void pop(); 266 GraphicStateEntry* currentEntry() { return &fEntries[fStackDepth]; } 267 268 // Conservative limit on save depth, see impl. notes in PDF 1.4 spec. 269 static const int kMaxStackDepth = 12; 270 GraphicStateEntry fEntries[kMaxStackDepth + 1]; 271 int fStackDepth; 272 SkWStream* fContentStream; 273 }; 274 275 void GraphicStackState::drainStack() { 276 while (fStackDepth) { 277 pop(); 278 } 279 } 280 281 void GraphicStackState::push() { 282 SkASSERT(fStackDepth < kMaxStackDepth); 283 fContentStream->writeText("q\n"); 284 fStackDepth++; 285 fEntries[fStackDepth] = fEntries[fStackDepth - 1]; 286 } 287 288 void GraphicStackState::pop() { 289 SkASSERT(fStackDepth > 0); 290 fContentStream->writeText("Q\n"); 291 fStackDepth--; 292 } 293 294 // This function initializes iter to be an iterator on the "stack" argument 295 // and then skips over the leading entries as specified in prefix. It requires 296 // and asserts that "prefix" will be a prefix to "stack." 297 static void skip_clip_stack_prefix(const SkClipStack& prefix, 298 const SkClipStack& stack, 299 SkClipStack::Iter* iter) { 300 SkClipStack::B2TIter prefixIter(prefix); 301 iter->reset(stack, SkClipStack::Iter::kBottom_IterStart); 302 303 const SkClipStack::Element* prefixEntry; 304 const SkClipStack::Element* iterEntry; 305 306 for (prefixEntry = prefixIter.next(); prefixEntry; 307 prefixEntry = prefixIter.next()) { 308 iterEntry = iter->next(); 309 SkASSERT(iterEntry); 310 // Because of SkClipStack does internal intersection, the last clip 311 // entry may differ. 312 if (*prefixEntry != *iterEntry) { 313 SkASSERT(prefixEntry->getOp() == SkRegion::kIntersect_Op); 314 SkASSERT(iterEntry->getOp() == SkRegion::kIntersect_Op); 315 SkASSERT(iterEntry->getType() == prefixEntry->getType()); 316 // back up the iterator by one 317 iter->prev(); 318 prefixEntry = prefixIter.next(); 319 break; 320 } 321 } 322 323 SkASSERT(prefixEntry == NULL); 324 } 325 326 static void emit_clip(SkPath* clipPath, SkRect* clipRect, 327 SkWStream* contentStream) { 328 SkASSERT(clipPath || clipRect); 329 330 SkPath::FillType clipFill; 331 if (clipPath) { 332 SkPDFUtils::EmitPath(*clipPath, SkPaint::kFill_Style, contentStream); 333 clipFill = clipPath->getFillType(); 334 } else { 335 SkPDFUtils::AppendRectangle(*clipRect, contentStream); 336 clipFill = SkPath::kWinding_FillType; 337 } 338 339 NOT_IMPLEMENTED(clipFill == SkPath::kInverseEvenOdd_FillType, false); 340 NOT_IMPLEMENTED(clipFill == SkPath::kInverseWinding_FillType, false); 341 if (clipFill == SkPath::kEvenOdd_FillType) { 342 contentStream->writeText("W* n\n"); 343 } else { 344 contentStream->writeText("W n\n"); 345 } 346 } 347 348 #ifdef SK_PDF_USE_PATHOPS 349 /* Calculate an inverted path's equivalent non-inverted path, given the 350 * canvas bounds. 351 * outPath may alias with invPath (since this is supported by PathOps). 352 */ 353 static bool calculate_inverse_path(const SkRect& bounds, const SkPath& invPath, 354 SkPath* outPath) { 355 SkASSERT(invPath.isInverseFillType()); 356 357 SkPath clipPath; 358 clipPath.addRect(bounds); 359 360 return Op(clipPath, invPath, kIntersect_PathOp, outPath); 361 } 362 363 // Sanity check the numerical values of the SkRegion ops and PathOps ops 364 // enums so region_op_to_pathops_op can do a straight passthrough cast. 365 // If these are failing, it may be necessary to make region_op_to_pathops_op 366 // do more. 367 SK_COMPILE_ASSERT(SkRegion::kDifference_Op == (int)kDifference_PathOp, 368 region_pathop_mismatch); 369 SK_COMPILE_ASSERT(SkRegion::kIntersect_Op == (int)kIntersect_PathOp, 370 region_pathop_mismatch); 371 SK_COMPILE_ASSERT(SkRegion::kUnion_Op == (int)kUnion_PathOp, 372 region_pathop_mismatch); 373 SK_COMPILE_ASSERT(SkRegion::kXOR_Op == (int)kXOR_PathOp, 374 region_pathop_mismatch); 375 SK_COMPILE_ASSERT(SkRegion::kReverseDifference_Op == 376 (int)kReverseDifference_PathOp, 377 region_pathop_mismatch); 378 379 static SkPathOp region_op_to_pathops_op(SkRegion::Op op) { 380 SkASSERT(op >= 0); 381 SkASSERT(op <= SkRegion::kReverseDifference_Op); 382 return (SkPathOp)op; 383 } 384 385 /* Uses Path Ops to calculate a vector SkPath clip from a clip stack. 386 * Returns true if successful, or false if not successful. 387 * If successful, the resulting clip is stored in outClipPath. 388 * If not successful, outClipPath is undefined, and a fallback method 389 * should be used. 390 */ 391 static bool get_clip_stack_path(const SkMatrix& transform, 392 const SkClipStack& clipStack, 393 const SkRegion& clipRegion, 394 SkPath* outClipPath) { 395 outClipPath->reset(); 396 outClipPath->setFillType(SkPath::kInverseWinding_FillType); 397 398 const SkClipStack::Element* clipEntry; 399 SkClipStack::Iter iter; 400 iter.reset(clipStack, SkClipStack::Iter::kBottom_IterStart); 401 for (clipEntry = iter.next(); clipEntry; clipEntry = iter.next()) { 402 SkPath entryPath; 403 if (SkClipStack::Element::kEmpty_Type == clipEntry->getType()) { 404 outClipPath->reset(); 405 outClipPath->setFillType(SkPath::kInverseWinding_FillType); 406 continue; 407 } else { 408 clipEntry->asPath(&entryPath); 409 } 410 entryPath.transform(transform); 411 412 if (SkRegion::kReplace_Op == clipEntry->getOp()) { 413 *outClipPath = entryPath; 414 } else { 415 SkPathOp op = region_op_to_pathops_op(clipEntry->getOp()); 416 if (!Op(*outClipPath, entryPath, op, outClipPath)) { 417 return false; 418 } 419 } 420 } 421 422 if (outClipPath->isInverseFillType()) { 423 // The bounds are slightly outset to ensure this is correct in the 424 // face of floating-point accuracy and possible SkRegion bitmap 425 // approximations. 426 SkRect clipBounds = SkRect::Make(clipRegion.getBounds()); 427 clipBounds.outset(SK_Scalar1, SK_Scalar1); 428 if (!calculate_inverse_path(clipBounds, *outClipPath, outClipPath)) { 429 return false; 430 } 431 } 432 return true; 433 } 434 #endif 435 436 // TODO(vandebo): Take advantage of SkClipStack::getSaveCount(), the PDF 437 // graphic state stack, and the fact that we can know all the clips used 438 // on the page to optimize this. 439 void GraphicStackState::updateClip(const SkClipStack& clipStack, 440 const SkRegion& clipRegion, 441 const SkPoint& translation) { 442 if (clipStack == currentEntry()->fClipStack) { 443 return; 444 } 445 446 while (fStackDepth > 0) { 447 pop(); 448 if (clipStack == currentEntry()->fClipStack) { 449 return; 450 } 451 } 452 push(); 453 454 currentEntry()->fClipStack = clipStack; 455 currentEntry()->fClipRegion = clipRegion; 456 457 SkMatrix transform; 458 transform.setTranslate(translation.fX, translation.fY); 459 460 #ifdef SK_PDF_USE_PATHOPS 461 SkPath clipPath; 462 if (get_clip_stack_path(transform, clipStack, clipRegion, &clipPath)) { 463 emit_clip(&clipPath, NULL, fContentStream); 464 return; 465 } 466 #endif 467 // gsState->initialEntry()->fClipStack/Region specifies the clip that has 468 // already been applied. (If this is a top level device, then it specifies 469 // a clip to the content area. If this is a layer, then it specifies 470 // the clip in effect when the layer was created.) There's no need to 471 // reapply that clip; SKCanvas's SkDrawIter will draw anything outside the 472 // initial clip on the parent layer. (This means there's a bug if the user 473 // expands the clip and then uses any xfer mode that uses dst: 474 // http://code.google.com/p/skia/issues/detail?id=228 ) 475 SkClipStack::Iter iter; 476 skip_clip_stack_prefix(fEntries[0].fClipStack, clipStack, &iter); 477 478 // If the clip stack does anything other than intersect or if it uses 479 // an inverse fill type, we have to fall back to the clip region. 480 bool needRegion = false; 481 const SkClipStack::Element* clipEntry; 482 for (clipEntry = iter.next(); clipEntry; clipEntry = iter.next()) { 483 if (clipEntry->getOp() != SkRegion::kIntersect_Op || 484 clipEntry->isInverseFilled()) { 485 needRegion = true; 486 break; 487 } 488 } 489 490 if (needRegion) { 491 SkPath clipPath; 492 SkAssertResult(clipRegion.getBoundaryPath(&clipPath)); 493 emit_clip(&clipPath, NULL, fContentStream); 494 } else { 495 skip_clip_stack_prefix(fEntries[0].fClipStack, clipStack, &iter); 496 const SkClipStack::Element* clipEntry; 497 for (clipEntry = iter.next(); clipEntry; clipEntry = iter.next()) { 498 SkASSERT(clipEntry->getOp() == SkRegion::kIntersect_Op); 499 switch (clipEntry->getType()) { 500 case SkClipStack::Element::kRect_Type: { 501 SkRect translatedClip; 502 transform.mapRect(&translatedClip, clipEntry->getRect()); 503 emit_clip(NULL, &translatedClip, fContentStream); 504 break; 505 } 506 default: { 507 SkPath translatedPath; 508 clipEntry->asPath(&translatedPath); 509 translatedPath.transform(transform, &translatedPath); 510 emit_clip(&translatedPath, NULL, fContentStream); 511 break; 512 } 513 } 514 } 515 } 516 } 517 518 void GraphicStackState::updateMatrix(const SkMatrix& matrix) { 519 if (matrix == currentEntry()->fMatrix) { 520 return; 521 } 522 523 if (currentEntry()->fMatrix.getType() != SkMatrix::kIdentity_Mask) { 524 SkASSERT(fStackDepth > 0); 525 SkASSERT(fEntries[fStackDepth].fClipStack == 526 fEntries[fStackDepth -1].fClipStack); 527 pop(); 528 529 SkASSERT(currentEntry()->fMatrix.getType() == SkMatrix::kIdentity_Mask); 530 } 531 if (matrix.getType() == SkMatrix::kIdentity_Mask) { 532 return; 533 } 534 535 push(); 536 SkPDFUtils::AppendTransform(matrix, fContentStream); 537 currentEntry()->fMatrix = matrix; 538 } 539 540 void GraphicStackState::updateDrawingState(const GraphicStateEntry& state) { 541 // PDF treats a shader as a color, so we only set one or the other. 542 if (state.fShaderIndex >= 0) { 543 if (state.fShaderIndex != currentEntry()->fShaderIndex) { 544 SkPDFUtils::ApplyPattern(state.fShaderIndex, fContentStream); 545 currentEntry()->fShaderIndex = state.fShaderIndex; 546 } 547 } else { 548 if (state.fColor != currentEntry()->fColor || 549 currentEntry()->fShaderIndex >= 0) { 550 emit_pdf_color(state.fColor, fContentStream); 551 fContentStream->writeText("RG "); 552 emit_pdf_color(state.fColor, fContentStream); 553 fContentStream->writeText("rg\n"); 554 currentEntry()->fColor = state.fColor; 555 currentEntry()->fShaderIndex = -1; 556 } 557 } 558 559 if (state.fGraphicStateIndex != currentEntry()->fGraphicStateIndex) { 560 SkPDFUtils::ApplyGraphicState(state.fGraphicStateIndex, fContentStream); 561 currentEntry()->fGraphicStateIndex = state.fGraphicStateIndex; 562 } 563 564 if (state.fTextScaleX) { 565 if (state.fTextScaleX != currentEntry()->fTextScaleX) { 566 SkScalar pdfScale = SkScalarMul(state.fTextScaleX, 567 SkIntToScalar(100)); 568 SkPDFScalar::Append(pdfScale, fContentStream); 569 fContentStream->writeText(" Tz\n"); 570 currentEntry()->fTextScaleX = state.fTextScaleX; 571 } 572 if (state.fTextFill != currentEntry()->fTextFill) { 573 SK_COMPILE_ASSERT(SkPaint::kFill_Style == 0, enum_must_match_value); 574 SK_COMPILE_ASSERT(SkPaint::kStroke_Style == 1, 575 enum_must_match_value); 576 SK_COMPILE_ASSERT(SkPaint::kStrokeAndFill_Style == 2, 577 enum_must_match_value); 578 fContentStream->writeDecAsText(state.fTextFill); 579 fContentStream->writeText(" Tr\n"); 580 currentEntry()->fTextFill = state.fTextFill; 581 } 582 } 583 } 584 585 SkBaseDevice* SkPDFDevice::onCreateDevice(const SkImageInfo& info, Usage usage) { 586 SkMatrix initialTransform; 587 initialTransform.reset(); 588 SkISize size = SkISize::Make(info.width(), info.height()); 589 return SkNEW_ARGS(SkPDFDevice, (size, size, initialTransform)); 590 } 591 592 593 struct ContentEntry { 594 GraphicStateEntry fState; 595 SkDynamicMemoryWStream fContent; 596 SkAutoTDelete<ContentEntry> fNext; 597 598 // If the stack is too deep we could get Stack Overflow. 599 // So we manually destruct the object. 600 ~ContentEntry() { 601 ContentEntry* val = fNext.detach(); 602 while (val != NULL) { 603 ContentEntry* valNext = val->fNext.detach(); 604 // When the destructor is called, fNext is NULL and exits. 605 delete val; 606 val = valNext; 607 } 608 } 609 }; 610 611 // A helper class to automatically finish a ContentEntry at the end of a 612 // drawing method and maintain the state needed between set up and finish. 613 class ScopedContentEntry { 614 public: 615 ScopedContentEntry(SkPDFDevice* device, const SkDraw& draw, 616 const SkPaint& paint, bool hasText = false) 617 : fDevice(device), 618 fContentEntry(NULL), 619 fXfermode(SkXfermode::kSrcOver_Mode), 620 fDstFormXObject(NULL) { 621 init(draw.fClipStack, *draw.fClip, *draw.fMatrix, paint, hasText); 622 } 623 ScopedContentEntry(SkPDFDevice* device, const SkClipStack* clipStack, 624 const SkRegion& clipRegion, const SkMatrix& matrix, 625 const SkPaint& paint, bool hasText = false) 626 : fDevice(device), 627 fContentEntry(NULL), 628 fXfermode(SkXfermode::kSrcOver_Mode), 629 fDstFormXObject(NULL) { 630 init(clipStack, clipRegion, matrix, paint, hasText); 631 } 632 633 ~ScopedContentEntry() { 634 if (fContentEntry) { 635 SkPath* shape = &fShape; 636 if (shape->isEmpty()) { 637 shape = NULL; 638 } 639 fDevice->finishContentEntry(fXfermode, fDstFormXObject, shape); 640 } 641 SkSafeUnref(fDstFormXObject); 642 } 643 644 ContentEntry* entry() { return fContentEntry; } 645 646 /* Returns true when we explicitly need the shape of the drawing. */ 647 bool needShape() { 648 switch (fXfermode) { 649 case SkXfermode::kClear_Mode: 650 case SkXfermode::kSrc_Mode: 651 case SkXfermode::kSrcIn_Mode: 652 case SkXfermode::kSrcOut_Mode: 653 case SkXfermode::kDstIn_Mode: 654 case SkXfermode::kDstOut_Mode: 655 case SkXfermode::kSrcATop_Mode: 656 case SkXfermode::kDstATop_Mode: 657 case SkXfermode::kModulate_Mode: 658 return true; 659 default: 660 return false; 661 } 662 } 663 664 /* Returns true unless we only need the shape of the drawing. */ 665 bool needSource() { 666 if (fXfermode == SkXfermode::kClear_Mode) { 667 return false; 668 } 669 return true; 670 } 671 672 /* If the shape is different than the alpha component of the content, then 673 * setShape should be called with the shape. In particular, images and 674 * devices have rectangular shape. 675 */ 676 void setShape(const SkPath& shape) { 677 fShape = shape; 678 } 679 680 private: 681 SkPDFDevice* fDevice; 682 ContentEntry* fContentEntry; 683 SkXfermode::Mode fXfermode; 684 SkPDFFormXObject* fDstFormXObject; 685 SkPath fShape; 686 687 void init(const SkClipStack* clipStack, const SkRegion& clipRegion, 688 const SkMatrix& matrix, const SkPaint& paint, bool hasText) { 689 // Shape has to be flatten before we get here. 690 if (matrix.hasPerspective()) { 691 NOT_IMPLEMENTED(!matrix.hasPerspective(), false); 692 return; 693 } 694 if (paint.getXfermode()) { 695 paint.getXfermode()->asMode(&fXfermode); 696 } 697 fContentEntry = fDevice->setUpContentEntry(clipStack, clipRegion, 698 matrix, paint, hasText, 699 &fDstFormXObject); 700 } 701 }; 702 703 //////////////////////////////////////////////////////////////////////////////// 704 705 static inline SkBitmap makeContentBitmap(const SkISize& contentSize, 706 const SkMatrix* initialTransform) { 707 SkImageInfo info; 708 if (initialTransform) { 709 // Compute the size of the drawing area. 710 SkVector drawingSize; 711 SkMatrix inverse; 712 drawingSize.set(SkIntToScalar(contentSize.fWidth), 713 SkIntToScalar(contentSize.fHeight)); 714 if (!initialTransform->invert(&inverse)) { 715 // This shouldn't happen, initial transform should be invertible. 716 SkASSERT(false); 717 inverse.reset(); 718 } 719 inverse.mapVectors(&drawingSize, 1); 720 SkISize size = SkSize::Make(drawingSize.fX, drawingSize.fY).toRound(); 721 info = SkImageInfo::MakeUnknown(abs(size.fWidth), abs(size.fHeight)); 722 } else { 723 info = SkImageInfo::MakeUnknown(abs(contentSize.fWidth), 724 abs(contentSize.fHeight)); 725 } 726 727 SkBitmap bitmap; 728 bitmap.setInfo(info); 729 return bitmap; 730 } 731 732 // TODO(vandebo) change pageSize to SkSize. 733 // TODO: inherit from SkBaseDevice instead of SkBitmapDevice 734 SkPDFDevice::SkPDFDevice(const SkISize& pageSize, const SkISize& contentSize, 735 const SkMatrix& initialTransform) 736 : SkBitmapDevice(makeContentBitmap(contentSize, &initialTransform)), 737 fPageSize(pageSize), 738 fContentSize(contentSize), 739 fLastContentEntry(NULL), 740 fLastMarginContentEntry(NULL), 741 fClipStack(NULL), 742 fEncoder(NULL), 743 fRasterDpi(72.0f) { 744 // Just report that PDF does not supports perspective in the 745 // initial transform. 746 NOT_IMPLEMENTED(initialTransform.hasPerspective(), true); 747 748 // Skia generally uses the top left as the origin but PDF natively has the 749 // origin at the bottom left. This matrix corrects for that. But that only 750 // needs to be done once, we don't do it when layering. 751 fInitialTransform.setTranslate(0, SkIntToScalar(pageSize.fHeight)); 752 fInitialTransform.preScale(SK_Scalar1, -SK_Scalar1); 753 fInitialTransform.preConcat(initialTransform); 754 755 SkIRect existingClip = SkIRect::MakeWH(this->width(), this->height()); 756 fExistingClipRegion.setRect(existingClip); 757 758 this->init(); 759 } 760 761 // TODO(vandebo) change layerSize to SkSize. 762 SkPDFDevice::SkPDFDevice(const SkISize& layerSize, 763 const SkClipStack& existingClipStack, 764 const SkRegion& existingClipRegion) 765 : SkBitmapDevice(makeContentBitmap(layerSize, NULL)), 766 fPageSize(layerSize), 767 fContentSize(layerSize), 768 fExistingClipStack(existingClipStack), 769 fExistingClipRegion(existingClipRegion), 770 fLastContentEntry(NULL), 771 fLastMarginContentEntry(NULL), 772 fClipStack(NULL), 773 fEncoder(NULL), 774 fRasterDpi(72.0f) { 775 fInitialTransform.reset(); 776 this->init(); 777 } 778 779 SkPDFDevice::~SkPDFDevice() { 780 this->cleanUp(true); 781 } 782 783 void SkPDFDevice::init() { 784 fAnnotations = NULL; 785 fResourceDict = NULL; 786 fContentEntries.free(); 787 fLastContentEntry = NULL; 788 fMarginContentEntries.free(); 789 fLastMarginContentEntry = NULL; 790 fDrawingArea = kContent_DrawingArea; 791 if (fFontGlyphUsage.get() == NULL) { 792 fFontGlyphUsage.reset(new SkPDFGlyphSetMap()); 793 } 794 } 795 796 void SkPDFDevice::cleanUp(bool clearFontUsage) { 797 fGraphicStateResources.unrefAll(); 798 fXObjectResources.unrefAll(); 799 fFontResources.unrefAll(); 800 fShaderResources.unrefAll(); 801 SkSafeUnref(fAnnotations); 802 SkSafeUnref(fResourceDict); 803 fNamedDestinations.deleteAll(); 804 805 if (clearFontUsage) { 806 fFontGlyphUsage->reset(); 807 } 808 } 809 810 void SkPDFDevice::clear(SkColor color) { 811 this->cleanUp(true); 812 this->init(); 813 814 SkPaint paint; 815 paint.setColor(color); 816 paint.setStyle(SkPaint::kFill_Style); 817 SkMatrix identity; 818 identity.reset(); 819 ScopedContentEntry content(this, &fExistingClipStack, fExistingClipRegion, 820 identity, paint); 821 internalDrawPaint(paint, content.entry()); 822 } 823 824 void SkPDFDevice::drawPaint(const SkDraw& d, const SkPaint& paint) { 825 SkPaint newPaint = paint; 826 newPaint.setStyle(SkPaint::kFill_Style); 827 ScopedContentEntry content(this, d, newPaint); 828 internalDrawPaint(newPaint, content.entry()); 829 } 830 831 void SkPDFDevice::internalDrawPaint(const SkPaint& paint, 832 ContentEntry* contentEntry) { 833 if (!contentEntry) { 834 return; 835 } 836 SkRect bbox = SkRect::MakeWH(SkIntToScalar(this->width()), 837 SkIntToScalar(this->height())); 838 SkMatrix inverse; 839 if (!contentEntry->fState.fMatrix.invert(&inverse)) { 840 return; 841 } 842 inverse.mapRect(&bbox); 843 844 SkPDFUtils::AppendRectangle(bbox, &contentEntry->fContent); 845 SkPDFUtils::PaintPath(paint.getStyle(), SkPath::kWinding_FillType, 846 &contentEntry->fContent); 847 } 848 849 void SkPDFDevice::drawPoints(const SkDraw& d, SkCanvas::PointMode mode, 850 size_t count, const SkPoint* points, 851 const SkPaint& passedPaint) { 852 if (count == 0) { 853 return; 854 } 855 856 if (handlePointAnnotation(points, count, *d.fMatrix, passedPaint)) { 857 return; 858 } 859 860 // SkDraw::drawPoints converts to multiple calls to fDevice->drawPath. 861 // We only use this when there's a path effect because of the overhead 862 // of multiple calls to setUpContentEntry it causes. 863 if (passedPaint.getPathEffect()) { 864 if (d.fClip->isEmpty()) { 865 return; 866 } 867 SkDraw pointDraw(d); 868 pointDraw.fDevice = this; 869 pointDraw.drawPoints(mode, count, points, passedPaint, true); 870 return; 871 } 872 873 const SkPaint* paint = &passedPaint; 874 SkPaint modifiedPaint; 875 876 if (mode == SkCanvas::kPoints_PointMode && 877 paint->getStrokeCap() != SkPaint::kRound_Cap) { 878 modifiedPaint = *paint; 879 paint = &modifiedPaint; 880 if (paint->getStrokeWidth()) { 881 // PDF won't draw a single point with square/butt caps because the 882 // orientation is ambiguous. Draw a rectangle instead. 883 modifiedPaint.setStyle(SkPaint::kFill_Style); 884 SkScalar strokeWidth = paint->getStrokeWidth(); 885 SkScalar halfStroke = SkScalarHalf(strokeWidth); 886 for (size_t i = 0; i < count; i++) { 887 SkRect r = SkRect::MakeXYWH(points[i].fX, points[i].fY, 0, 0); 888 r.inset(-halfStroke, -halfStroke); 889 drawRect(d, r, modifiedPaint); 890 } 891 return; 892 } else { 893 modifiedPaint.setStrokeCap(SkPaint::kRound_Cap); 894 } 895 } 896 897 ScopedContentEntry content(this, d, *paint); 898 if (!content.entry()) { 899 return; 900 } 901 902 switch (mode) { 903 case SkCanvas::kPolygon_PointMode: 904 SkPDFUtils::MoveTo(points[0].fX, points[0].fY, 905 &content.entry()->fContent); 906 for (size_t i = 1; i < count; i++) { 907 SkPDFUtils::AppendLine(points[i].fX, points[i].fY, 908 &content.entry()->fContent); 909 } 910 SkPDFUtils::StrokePath(&content.entry()->fContent); 911 break; 912 case SkCanvas::kLines_PointMode: 913 for (size_t i = 0; i < count/2; i++) { 914 SkPDFUtils::MoveTo(points[i * 2].fX, points[i * 2].fY, 915 &content.entry()->fContent); 916 SkPDFUtils::AppendLine(points[i * 2 + 1].fX, 917 points[i * 2 + 1].fY, 918 &content.entry()->fContent); 919 SkPDFUtils::StrokePath(&content.entry()->fContent); 920 } 921 break; 922 case SkCanvas::kPoints_PointMode: 923 SkASSERT(paint->getStrokeCap() == SkPaint::kRound_Cap); 924 for (size_t i = 0; i < count; i++) { 925 SkPDFUtils::MoveTo(points[i].fX, points[i].fY, 926 &content.entry()->fContent); 927 SkPDFUtils::ClosePath(&content.entry()->fContent); 928 SkPDFUtils::StrokePath(&content.entry()->fContent); 929 } 930 break; 931 default: 932 SkASSERT(false); 933 } 934 } 935 936 void SkPDFDevice::drawRect(const SkDraw& d, const SkRect& rect, 937 const SkPaint& paint) { 938 SkRect r = rect; 939 r.sort(); 940 941 if (paint.getPathEffect()) { 942 if (d.fClip->isEmpty()) { 943 return; 944 } 945 SkPath path; 946 path.addRect(r); 947 drawPath(d, path, paint, NULL, true); 948 return; 949 } 950 951 if (handleRectAnnotation(r, *d.fMatrix, paint)) { 952 return; 953 } 954 955 ScopedContentEntry content(this, d, paint); 956 if (!content.entry()) { 957 return; 958 } 959 SkPDFUtils::AppendRectangle(r, &content.entry()->fContent); 960 SkPDFUtils::PaintPath(paint.getStyle(), SkPath::kWinding_FillType, 961 &content.entry()->fContent); 962 } 963 964 void SkPDFDevice::drawRRect(const SkDraw& draw, const SkRRect& rrect, 965 const SkPaint& paint) { 966 SkPath path; 967 path.addRRect(rrect); 968 this->drawPath(draw, path, paint, NULL, true); 969 } 970 971 void SkPDFDevice::drawPath(const SkDraw& d, const SkPath& origPath, 972 const SkPaint& paint, const SkMatrix* prePathMatrix, 973 bool pathIsMutable) { 974 SkPath modifiedPath; 975 SkPath* pathPtr = const_cast<SkPath*>(&origPath); 976 977 SkMatrix matrix = *d.fMatrix; 978 if (prePathMatrix) { 979 if (paint.getPathEffect() || paint.getStyle() != SkPaint::kFill_Style) { 980 if (!pathIsMutable) { 981 pathPtr = &modifiedPath; 982 pathIsMutable = true; 983 } 984 origPath.transform(*prePathMatrix, pathPtr); 985 } else { 986 matrix.preConcat(*prePathMatrix); 987 } 988 } 989 990 if (paint.getPathEffect()) { 991 if (d.fClip->isEmpty()) { 992 return; 993 } 994 if (!pathIsMutable) { 995 pathPtr = &modifiedPath; 996 pathIsMutable = true; 997 } 998 bool fill = paint.getFillPath(origPath, pathPtr); 999 1000 SkPaint noEffectPaint(paint); 1001 noEffectPaint.setPathEffect(NULL); 1002 if (fill) { 1003 noEffectPaint.setStyle(SkPaint::kFill_Style); 1004 } else { 1005 noEffectPaint.setStyle(SkPaint::kStroke_Style); 1006 noEffectPaint.setStrokeWidth(0); 1007 } 1008 drawPath(d, *pathPtr, noEffectPaint, NULL, true); 1009 return; 1010 } 1011 1012 #ifdef SK_PDF_USE_PATHOPS 1013 if (handleInversePath(d, origPath, paint, pathIsMutable, prePathMatrix)) { 1014 return; 1015 } 1016 #endif 1017 1018 if (handleRectAnnotation(pathPtr->getBounds(), matrix, paint)) { 1019 return; 1020 } 1021 1022 ScopedContentEntry content(this, d.fClipStack, *d.fClip, matrix, paint); 1023 if (!content.entry()) { 1024 return; 1025 } 1026 SkPDFUtils::EmitPath(*pathPtr, paint.getStyle(), 1027 &content.entry()->fContent); 1028 SkPDFUtils::PaintPath(paint.getStyle(), pathPtr->getFillType(), 1029 &content.entry()->fContent); 1030 } 1031 1032 void SkPDFDevice::drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap, 1033 const SkRect* src, const SkRect& dst, 1034 const SkPaint& paint, 1035 SkCanvas::DrawBitmapRectFlags flags) { 1036 // TODO: this code path must be updated to respect the flags parameter 1037 SkMatrix matrix; 1038 SkRect bitmapBounds, tmpSrc, tmpDst; 1039 SkBitmap tmpBitmap; 1040 1041 bitmapBounds.isetWH(bitmap.width(), bitmap.height()); 1042 1043 // Compute matrix from the two rectangles 1044 if (src) { 1045 tmpSrc = *src; 1046 } else { 1047 tmpSrc = bitmapBounds; 1048 } 1049 matrix.setRectToRect(tmpSrc, dst, SkMatrix::kFill_ScaleToFit); 1050 1051 const SkBitmap* bitmapPtr = &bitmap; 1052 1053 // clip the tmpSrc to the bounds of the bitmap, and recompute dstRect if 1054 // needed (if the src was clipped). No check needed if src==null. 1055 if (src) { 1056 if (!bitmapBounds.contains(*src)) { 1057 if (!tmpSrc.intersect(bitmapBounds)) { 1058 return; // nothing to draw 1059 } 1060 // recompute dst, based on the smaller tmpSrc 1061 matrix.mapRect(&tmpDst, tmpSrc); 1062 } 1063 1064 // since we may need to clamp to the borders of the src rect within 1065 // the bitmap, we extract a subset. 1066 // TODO: make sure this is handled in drawBitmap and remove from here. 1067 SkIRect srcIR; 1068 tmpSrc.roundOut(&srcIR); 1069 if (!bitmap.extractSubset(&tmpBitmap, srcIR)) { 1070 return; 1071 } 1072 bitmapPtr = &tmpBitmap; 1073 1074 // Since we did an extract, we need to adjust the matrix accordingly 1075 SkScalar dx = 0, dy = 0; 1076 if (srcIR.fLeft > 0) { 1077 dx = SkIntToScalar(srcIR.fLeft); 1078 } 1079 if (srcIR.fTop > 0) { 1080 dy = SkIntToScalar(srcIR.fTop); 1081 } 1082 if (dx || dy) { 1083 matrix.preTranslate(dx, dy); 1084 } 1085 } 1086 this->drawBitmap(draw, *bitmapPtr, matrix, paint); 1087 } 1088 1089 void SkPDFDevice::drawBitmap(const SkDraw& d, const SkBitmap& bitmap, 1090 const SkMatrix& matrix, const SkPaint& paint) { 1091 if (d.fClip->isEmpty()) { 1092 return; 1093 } 1094 1095 SkMatrix transform = matrix; 1096 transform.postConcat(*d.fMatrix); 1097 this->internalDrawBitmap(transform, d.fClipStack, *d.fClip, bitmap, NULL, 1098 paint); 1099 } 1100 1101 void SkPDFDevice::drawSprite(const SkDraw& d, const SkBitmap& bitmap, 1102 int x, int y, const SkPaint& paint) { 1103 if (d.fClip->isEmpty()) { 1104 return; 1105 } 1106 1107 SkMatrix matrix; 1108 matrix.setTranslate(SkIntToScalar(x), SkIntToScalar(y)); 1109 this->internalDrawBitmap(matrix, d.fClipStack, *d.fClip, bitmap, NULL, 1110 paint); 1111 } 1112 1113 void SkPDFDevice::drawText(const SkDraw& d, const void* text, size_t len, 1114 SkScalar x, SkScalar y, const SkPaint& paint) { 1115 NOT_IMPLEMENTED(paint.getMaskFilter() != NULL, false); 1116 if (paint.getMaskFilter() != NULL) { 1117 // Don't pretend we support drawing MaskFilters, it makes for artifacts 1118 // making text unreadable (e.g. same text twice when using CSS shadows). 1119 return; 1120 } 1121 SkPaint textPaint = calculate_text_paint(paint); 1122 ScopedContentEntry content(this, d, textPaint, true); 1123 if (!content.entry()) { 1124 return; 1125 } 1126 1127 SkGlyphStorage storage(0); 1128 uint16_t* glyphIDs = NULL; 1129 int numGlyphs = force_glyph_encoding(paint, text, len, &storage, &glyphIDs); 1130 textPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); 1131 1132 SkDrawCacheProc glyphCacheProc = textPaint.getDrawCacheProc(); 1133 align_text(glyphCacheProc, textPaint, glyphIDs, numGlyphs, &x, &y); 1134 content.entry()->fContent.writeText("BT\n"); 1135 set_text_transform(x, y, textPaint.getTextSkewX(), 1136 &content.entry()->fContent); 1137 int consumedGlyphCount = 0; 1138 while (numGlyphs > consumedGlyphCount) { 1139 updateFont(textPaint, glyphIDs[consumedGlyphCount], content.entry()); 1140 SkPDFFont* font = content.entry()->fState.fFont; 1141 int availableGlyphs = 1142 font->glyphsToPDFFontEncoding(glyphIDs + consumedGlyphCount, 1143 numGlyphs - consumedGlyphCount); 1144 fFontGlyphUsage->noteGlyphUsage(font, glyphIDs + consumedGlyphCount, 1145 availableGlyphs); 1146 SkString encodedString = 1147 SkPDFString::FormatString(glyphIDs + consumedGlyphCount, 1148 availableGlyphs, font->multiByteGlyphs()); 1149 content.entry()->fContent.writeText(encodedString.c_str()); 1150 consumedGlyphCount += availableGlyphs; 1151 content.entry()->fContent.writeText(" Tj\n"); 1152 } 1153 content.entry()->fContent.writeText("ET\n"); 1154 } 1155 1156 void SkPDFDevice::drawPosText(const SkDraw& d, const void* text, size_t len, 1157 const SkScalar pos[], SkScalar constY, 1158 int scalarsPerPos, const SkPaint& paint) { 1159 NOT_IMPLEMENTED(paint.getMaskFilter() != NULL, false); 1160 if (paint.getMaskFilter() != NULL) { 1161 // Don't pretend we support drawing MaskFilters, it makes for artifacts 1162 // making text unreadable (e.g. same text twice when using CSS shadows). 1163 return; 1164 } 1165 SkASSERT(1 == scalarsPerPos || 2 == scalarsPerPos); 1166 SkPaint textPaint = calculate_text_paint(paint); 1167 ScopedContentEntry content(this, d, textPaint, true); 1168 if (!content.entry()) { 1169 return; 1170 } 1171 1172 #ifdef SK_BUILD_FOR_ANDROID 1173 /* 1174 * In the case that we have enabled fallback fonts on Android we need to 1175 * take the following steps to ensure that the PDF draws all characters, 1176 * regardless of their underlying font file, correctly. 1177 * 1178 * 1. Convert input into GlyphID encoding if it currently is not 1179 * 2. Iterate over the glyphIDs and identify the actual typeface that each 1180 * glyph resolves to 1181 * 3. Iterate over those typefaces and recursively call this function with 1182 * only the glyphs (and their positions) that the typeface is capable of 1183 * resolving. 1184 */ 1185 if (paint.getPaintOptionsAndroid().isUsingFontFallbacks()) { 1186 uint16_t* glyphIDs = NULL; 1187 SkGlyphStorage tmpStorage(0); 1188 size_t numGlyphs = 0; 1189 1190 // convert to glyphIDs 1191 if (paint.getTextEncoding() == SkPaint::kGlyphID_TextEncoding) { 1192 numGlyphs = len / 2; 1193 glyphIDs = reinterpret_cast<uint16_t*>(const_cast<void*>(text)); 1194 } else { 1195 numGlyphs = paint.textToGlyphs(text, len, NULL); 1196 tmpStorage.reset(numGlyphs); 1197 paint.textToGlyphs(text, len, tmpStorage.get()); 1198 glyphIDs = tmpStorage.get(); 1199 } 1200 1201 // if no typeface is provided in the paint get the default 1202 SkAutoTUnref<SkTypeface> origFace(SkSafeRef(paint.getTypeface())); 1203 if (NULL == origFace.get()) { 1204 origFace.reset(SkTypeface::RefDefault()); 1205 } 1206 const uint16_t origGlyphCount = origFace->countGlyphs(); 1207 1208 // keep a list of the already visited typefaces and some data about them 1209 SkTDArray<TypefaceFallbackData> visitedTypefaces; 1210 1211 // find all the typefaces needed to resolve this run of text 1212 bool usesOriginalTypeface = false; 1213 for (uint16_t x = 0; x < numGlyphs; ++x) { 1214 // optimization that checks to see if original typeface can resolve 1215 // the glyph 1216 if (glyphIDs[x] < origGlyphCount) { 1217 usesOriginalTypeface = true; 1218 continue; 1219 } 1220 1221 // find the fallback typeface that supports this glyph 1222 TypefaceFallbackData data; 1223 data.typeface = 1224 SkGetTypefaceForGlyphID(glyphIDs[x], origFace.get(), 1225 paint.getPaintOptionsAndroid(), 1226 &data.lowerBounds, 1227 &data.upperBounds); 1228 // add the typeface and its data if we don't have it 1229 if (data.typeface && !visitedTypefaces.contains(data)) { 1230 visitedTypefaces.push(data); 1231 } 1232 } 1233 1234 // if the original font was used then add it to the list as well 1235 if (usesOriginalTypeface) { 1236 TypefaceFallbackData* data = visitedTypefaces.push(); 1237 data->typeface = origFace.get(); 1238 data->lowerBounds = 0; 1239 data->upperBounds = origGlyphCount; 1240 } 1241 1242 // keep a scratch glyph and pos storage 1243 SkAutoTMalloc<SkScalar> posStorage(len * scalarsPerPos); 1244 SkScalar* tmpPos = posStorage.get(); 1245 SkGlyphStorage glyphStorage(numGlyphs); 1246 uint16_t* tmpGlyphIDs = glyphStorage.get(); 1247 1248 // loop through all the valid typefaces, trim the glyphs to only those 1249 // resolved by the typeface, and then draw that run of glyphs 1250 for (int x = 0; x < visitedTypefaces.count(); ++x) { 1251 const TypefaceFallbackData& data = visitedTypefaces[x]; 1252 1253 int tmpGlyphCount = 0; 1254 for (uint16_t y = 0; y < numGlyphs; ++y) { 1255 if (glyphIDs[y] >= data.lowerBounds && 1256 glyphIDs[y] < data.upperBounds) { 1257 tmpGlyphIDs[tmpGlyphCount] = glyphIDs[y] - data.lowerBounds; 1258 memcpy(&(tmpPos[tmpGlyphCount * scalarsPerPos]), 1259 &(pos[y * scalarsPerPos]), 1260 scalarsPerPos * sizeof(SkScalar)); 1261 tmpGlyphCount++; 1262 } 1263 } 1264 1265 // recursively call this function with the right typeface 1266 SkPaint tmpPaint = paint; 1267 tmpPaint.setTypeface(data.typeface); 1268 tmpPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); 1269 1270 // turn off fallback chaining 1271 SkPaintOptionsAndroid paintOpts = tmpPaint.getPaintOptionsAndroid(); 1272 paintOpts.setUseFontFallbacks(false); 1273 tmpPaint.setPaintOptionsAndroid(paintOpts); 1274 1275 this->drawPosText(d, tmpGlyphIDs, tmpGlyphCount * 2, tmpPos, constY, 1276 scalarsPerPos, tmpPaint); 1277 } 1278 return; 1279 } 1280 #endif 1281 1282 SkGlyphStorage storage(0); 1283 uint16_t* glyphIDs = NULL; 1284 size_t numGlyphs = force_glyph_encoding(paint, text, len, &storage, 1285 &glyphIDs); 1286 textPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); 1287 1288 SkDrawCacheProc glyphCacheProc = textPaint.getDrawCacheProc(); 1289 content.entry()->fContent.writeText("BT\n"); 1290 updateFont(textPaint, glyphIDs[0], content.entry()); 1291 for (size_t i = 0; i < numGlyphs; i++) { 1292 SkPDFFont* font = content.entry()->fState.fFont; 1293 uint16_t encodedValue = glyphIDs[i]; 1294 if (font->glyphsToPDFFontEncoding(&encodedValue, 1) != 1) { 1295 updateFont(textPaint, glyphIDs[i], content.entry()); 1296 i--; 1297 continue; 1298 } 1299 fFontGlyphUsage->noteGlyphUsage(font, &encodedValue, 1); 1300 SkScalar x = pos[i * scalarsPerPos]; 1301 SkScalar y = scalarsPerPos == 1 ? constY : pos[i * scalarsPerPos + 1]; 1302 align_text(glyphCacheProc, textPaint, glyphIDs + i, 1, &x, &y); 1303 set_text_transform(x, y, textPaint.getTextSkewX(), 1304 &content.entry()->fContent); 1305 SkString encodedString = 1306 SkPDFString::FormatString(&encodedValue, 1, 1307 font->multiByteGlyphs()); 1308 content.entry()->fContent.writeText(encodedString.c_str()); 1309 content.entry()->fContent.writeText(" Tj\n"); 1310 } 1311 content.entry()->fContent.writeText("ET\n"); 1312 } 1313 1314 void SkPDFDevice::drawTextOnPath(const SkDraw& d, const void* text, size_t len, 1315 const SkPath& path, const SkMatrix* matrix, 1316 const SkPaint& paint) { 1317 if (d.fClip->isEmpty()) { 1318 return; 1319 } 1320 d.drawTextOnPath((const char*)text, len, path, matrix, paint); 1321 } 1322 1323 void SkPDFDevice::drawVertices(const SkDraw& d, SkCanvas::VertexMode, 1324 int vertexCount, const SkPoint verts[], 1325 const SkPoint texs[], const SkColor colors[], 1326 SkXfermode* xmode, const uint16_t indices[], 1327 int indexCount, const SkPaint& paint) { 1328 if (d.fClip->isEmpty()) { 1329 return; 1330 } 1331 // TODO: implement drawVertices 1332 } 1333 1334 void SkPDFDevice::drawDevice(const SkDraw& d, SkBaseDevice* device, 1335 int x, int y, const SkPaint& paint) { 1336 // our onCreateDevice() always creates SkPDFDevice subclasses. 1337 SkPDFDevice* pdfDevice = static_cast<SkPDFDevice*>(device); 1338 if (pdfDevice->isContentEmpty()) { 1339 return; 1340 } 1341 1342 SkMatrix matrix; 1343 matrix.setTranslate(SkIntToScalar(x), SkIntToScalar(y)); 1344 ScopedContentEntry content(this, d.fClipStack, *d.fClip, matrix, paint); 1345 if (!content.entry()) { 1346 return; 1347 } 1348 if (content.needShape()) { 1349 SkPath shape; 1350 shape.addRect(SkRect::MakeXYWH(SkIntToScalar(x), SkIntToScalar(y), 1351 SkIntToScalar(device->width()), 1352 SkIntToScalar(device->height()))); 1353 content.setShape(shape); 1354 } 1355 if (!content.needSource()) { 1356 return; 1357 } 1358 1359 SkAutoTUnref<SkPDFFormXObject> xObject(new SkPDFFormXObject(pdfDevice)); 1360 SkPDFUtils::DrawFormXObject(this->addXObjectResource(xObject.get()), 1361 &content.entry()->fContent); 1362 1363 // Merge glyph sets from the drawn device. 1364 fFontGlyphUsage->merge(pdfDevice->getFontGlyphUsage()); 1365 } 1366 1367 void SkPDFDevice::onAttachToCanvas(SkCanvas* canvas) { 1368 INHERITED::onAttachToCanvas(canvas); 1369 1370 // Canvas promises that this ptr is valid until onDetachFromCanvas is called 1371 fClipStack = canvas->getClipStack(); 1372 } 1373 1374 void SkPDFDevice::onDetachFromCanvas() { 1375 INHERITED::onDetachFromCanvas(); 1376 1377 fClipStack = NULL; 1378 } 1379 1380 ContentEntry* SkPDFDevice::getLastContentEntry() { 1381 if (fDrawingArea == kContent_DrawingArea) { 1382 return fLastContentEntry; 1383 } else { 1384 return fLastMarginContentEntry; 1385 } 1386 } 1387 1388 SkAutoTDelete<ContentEntry>* SkPDFDevice::getContentEntries() { 1389 if (fDrawingArea == kContent_DrawingArea) { 1390 return &fContentEntries; 1391 } else { 1392 return &fMarginContentEntries; 1393 } 1394 } 1395 1396 void SkPDFDevice::setLastContentEntry(ContentEntry* contentEntry) { 1397 if (fDrawingArea == kContent_DrawingArea) { 1398 fLastContentEntry = contentEntry; 1399 } else { 1400 fLastMarginContentEntry = contentEntry; 1401 } 1402 } 1403 1404 void SkPDFDevice::setDrawingArea(DrawingArea drawingArea) { 1405 // A ScopedContentEntry only exists during the course of a draw call, so 1406 // this can't be called while a ScopedContentEntry exists. 1407 fDrawingArea = drawingArea; 1408 } 1409 1410 SkPDFResourceDict* SkPDFDevice::getResourceDict() { 1411 if (NULL == fResourceDict) { 1412 fResourceDict = SkNEW(SkPDFResourceDict); 1413 1414 if (fGraphicStateResources.count()) { 1415 for (int i = 0; i < fGraphicStateResources.count(); i++) { 1416 fResourceDict->insertResourceAsReference( 1417 SkPDFResourceDict::kExtGState_ResourceType, 1418 i, fGraphicStateResources[i]); 1419 } 1420 } 1421 1422 if (fXObjectResources.count()) { 1423 for (int i = 0; i < fXObjectResources.count(); i++) { 1424 fResourceDict->insertResourceAsReference( 1425 SkPDFResourceDict::kXObject_ResourceType, 1426 i, fXObjectResources[i]); 1427 } 1428 } 1429 1430 if (fFontResources.count()) { 1431 for (int i = 0; i < fFontResources.count(); i++) { 1432 fResourceDict->insertResourceAsReference( 1433 SkPDFResourceDict::kFont_ResourceType, 1434 i, fFontResources[i]); 1435 } 1436 } 1437 1438 if (fShaderResources.count()) { 1439 SkAutoTUnref<SkPDFDict> patterns(new SkPDFDict()); 1440 for (int i = 0; i < fShaderResources.count(); i++) { 1441 fResourceDict->insertResourceAsReference( 1442 SkPDFResourceDict::kPattern_ResourceType, 1443 i, fShaderResources[i]); 1444 } 1445 } 1446 } 1447 return fResourceDict; 1448 } 1449 1450 const SkTDArray<SkPDFFont*>& SkPDFDevice::getFontResources() const { 1451 return fFontResources; 1452 } 1453 1454 SkPDFArray* SkPDFDevice::copyMediaBox() const { 1455 // should this be a singleton? 1456 SkAutoTUnref<SkPDFInt> zero(SkNEW_ARGS(SkPDFInt, (0))); 1457 1458 SkPDFArray* mediaBox = SkNEW(SkPDFArray); 1459 mediaBox->reserve(4); 1460 mediaBox->append(zero.get()); 1461 mediaBox->append(zero.get()); 1462 mediaBox->appendInt(fPageSize.fWidth); 1463 mediaBox->appendInt(fPageSize.fHeight); 1464 return mediaBox; 1465 } 1466 1467 SkStream* SkPDFDevice::content() const { 1468 SkMemoryStream* result = new SkMemoryStream; 1469 result->setData(this->copyContentToData())->unref(); 1470 return result; 1471 } 1472 1473 void SkPDFDevice::copyContentEntriesToData(ContentEntry* entry, 1474 SkWStream* data) const { 1475 // TODO(ctguil): For margins, I'm not sure fExistingClipStack/Region is the 1476 // right thing to pass here. 1477 GraphicStackState gsState(fExistingClipStack, fExistingClipRegion, data); 1478 while (entry != NULL) { 1479 SkPoint translation; 1480 translation.iset(this->getOrigin()); 1481 translation.negate(); 1482 gsState.updateClip(entry->fState.fClipStack, entry->fState.fClipRegion, 1483 translation); 1484 gsState.updateMatrix(entry->fState.fMatrix); 1485 gsState.updateDrawingState(entry->fState); 1486 1487 SkAutoDataUnref copy(entry->fContent.copyToData()); 1488 data->write(copy->data(), copy->size()); 1489 entry = entry->fNext.get(); 1490 } 1491 gsState.drainStack(); 1492 } 1493 1494 SkData* SkPDFDevice::copyContentToData() const { 1495 SkDynamicMemoryWStream data; 1496 if (fInitialTransform.getType() != SkMatrix::kIdentity_Mask) { 1497 SkPDFUtils::AppendTransform(fInitialTransform, &data); 1498 } 1499 1500 // TODO(aayushkumar): Apply clip along the margins. Currently, webkit 1501 // colors the contentArea white before it starts drawing into it and 1502 // that currently acts as our clip. 1503 // Also, think about adding a transform here (or assume that the values 1504 // sent across account for that) 1505 SkPDFDevice::copyContentEntriesToData(fMarginContentEntries.get(), &data); 1506 1507 // If the content area is the entire page, then we don't need to clip 1508 // the content area (PDF area clips to the page size). Otherwise, 1509 // we have to clip to the content area; we've already applied the 1510 // initial transform, so just clip to the device size. 1511 if (fPageSize != fContentSize) { 1512 SkRect r = SkRect::MakeWH(SkIntToScalar(this->width()), 1513 SkIntToScalar(this->height())); 1514 emit_clip(NULL, &r, &data); 1515 } 1516 1517 SkPDFDevice::copyContentEntriesToData(fContentEntries.get(), &data); 1518 1519 // potentially we could cache this SkData, and only rebuild it if we 1520 // see that our state has changed. 1521 return data.copyToData(); 1522 } 1523 1524 #ifdef SK_PDF_USE_PATHOPS 1525 /* Draws an inverse filled path by using Path Ops to compute the positive 1526 * inverse using the current clip as the inverse bounds. 1527 * Return true if this was an inverse path and was properly handled, 1528 * otherwise returns false and the normal drawing routine should continue, 1529 * either as a (incorrect) fallback or because the path was not inverse 1530 * in the first place. 1531 */ 1532 bool SkPDFDevice::handleInversePath(const SkDraw& d, const SkPath& origPath, 1533 const SkPaint& paint, bool pathIsMutable, 1534 const SkMatrix* prePathMatrix) { 1535 if (!origPath.isInverseFillType()) { 1536 return false; 1537 } 1538 1539 if (d.fClip->isEmpty()) { 1540 return false; 1541 } 1542 1543 SkPath modifiedPath; 1544 SkPath* pathPtr = const_cast<SkPath*>(&origPath); 1545 SkPaint noInversePaint(paint); 1546 1547 // Merge stroking operations into final path. 1548 if (SkPaint::kStroke_Style == paint.getStyle() || 1549 SkPaint::kStrokeAndFill_Style == paint.getStyle()) { 1550 bool doFillPath = paint.getFillPath(origPath, &modifiedPath); 1551 if (doFillPath) { 1552 noInversePaint.setStyle(SkPaint::kFill_Style); 1553 noInversePaint.setStrokeWidth(0); 1554 pathPtr = &modifiedPath; 1555 } else { 1556 // To be consistent with the raster output, hairline strokes 1557 // are rendered as non-inverted. 1558 modifiedPath.toggleInverseFillType(); 1559 drawPath(d, modifiedPath, paint, NULL, true); 1560 return true; 1561 } 1562 } 1563 1564 // Get bounds of clip in current transform space 1565 // (clip bounds are given in device space). 1566 SkRect bounds; 1567 SkMatrix transformInverse; 1568 SkMatrix totalMatrix = *d.fMatrix; 1569 if (prePathMatrix) { 1570 totalMatrix.preConcat(*prePathMatrix); 1571 } 1572 if (!totalMatrix.invert(&transformInverse)) { 1573 return false; 1574 } 1575 bounds.set(d.fClip->getBounds()); 1576 transformInverse.mapRect(&bounds); 1577 1578 // Extend the bounds by the line width (plus some padding) 1579 // so the edge doesn't cause a visible stroke. 1580 bounds.outset(paint.getStrokeWidth() + SK_Scalar1, 1581 paint.getStrokeWidth() + SK_Scalar1); 1582 1583 if (!calculate_inverse_path(bounds, *pathPtr, &modifiedPath)) { 1584 return false; 1585 } 1586 1587 drawPath(d, modifiedPath, noInversePaint, prePathMatrix, true); 1588 return true; 1589 } 1590 #endif 1591 1592 bool SkPDFDevice::handleRectAnnotation(const SkRect& r, const SkMatrix& matrix, 1593 const SkPaint& p) { 1594 SkAnnotation* annotationInfo = p.getAnnotation(); 1595 if (!annotationInfo) { 1596 return false; 1597 } 1598 SkData* urlData = annotationInfo->find(SkAnnotationKeys::URL_Key()); 1599 if (urlData) { 1600 handleLinkToURL(urlData, r, matrix); 1601 return p.getAnnotation() != NULL; 1602 } 1603 SkData* linkToName = annotationInfo->find( 1604 SkAnnotationKeys::Link_Named_Dest_Key()); 1605 if (linkToName) { 1606 handleLinkToNamedDest(linkToName, r, matrix); 1607 return p.getAnnotation() != NULL; 1608 } 1609 return false; 1610 } 1611 1612 bool SkPDFDevice::handlePointAnnotation(const SkPoint* points, size_t count, 1613 const SkMatrix& matrix, 1614 const SkPaint& paint) { 1615 SkAnnotation* annotationInfo = paint.getAnnotation(); 1616 if (!annotationInfo) { 1617 return false; 1618 } 1619 SkData* nameData = annotationInfo->find( 1620 SkAnnotationKeys::Define_Named_Dest_Key()); 1621 if (nameData) { 1622 for (size_t i = 0; i < count; i++) { 1623 defineNamedDestination(nameData, points[i], matrix); 1624 } 1625 return paint.getAnnotation() != NULL; 1626 } 1627 return false; 1628 } 1629 1630 SkPDFDict* SkPDFDevice::createLinkAnnotation(const SkRect& r, 1631 const SkMatrix& matrix) { 1632 SkMatrix transform = matrix; 1633 transform.postConcat(fInitialTransform); 1634 SkRect translatedRect; 1635 transform.mapRect(&translatedRect, r); 1636 1637 if (NULL == fAnnotations) { 1638 fAnnotations = SkNEW(SkPDFArray); 1639 } 1640 SkPDFDict* annotation(SkNEW_ARGS(SkPDFDict, ("Annot"))); 1641 annotation->insertName("Subtype", "Link"); 1642 fAnnotations->append(annotation); 1643 1644 SkAutoTUnref<SkPDFArray> border(SkNEW(SkPDFArray)); 1645 border->reserve(3); 1646 border->appendInt(0); // Horizontal corner radius. 1647 border->appendInt(0); // Vertical corner radius. 1648 border->appendInt(0); // Width, 0 = no border. 1649 annotation->insert("Border", border.get()); 1650 1651 SkAutoTUnref<SkPDFArray> rect(SkNEW(SkPDFArray)); 1652 rect->reserve(4); 1653 rect->appendScalar(translatedRect.fLeft); 1654 rect->appendScalar(translatedRect.fTop); 1655 rect->appendScalar(translatedRect.fRight); 1656 rect->appendScalar(translatedRect.fBottom); 1657 annotation->insert("Rect", rect.get()); 1658 1659 return annotation; 1660 } 1661 1662 void SkPDFDevice::handleLinkToURL(SkData* urlData, const SkRect& r, 1663 const SkMatrix& matrix) { 1664 SkAutoTUnref<SkPDFDict> annotation(createLinkAnnotation(r, matrix)); 1665 1666 SkString url(static_cast<const char *>(urlData->data()), 1667 urlData->size() - 1); 1668 SkAutoTUnref<SkPDFDict> action(SkNEW_ARGS(SkPDFDict, ("Action"))); 1669 action->insertName("S", "URI"); 1670 action->insert("URI", SkNEW_ARGS(SkPDFString, (url)))->unref(); 1671 annotation->insert("A", action.get()); 1672 } 1673 1674 void SkPDFDevice::handleLinkToNamedDest(SkData* nameData, const SkRect& r, 1675 const SkMatrix& matrix) { 1676 SkAutoTUnref<SkPDFDict> annotation(createLinkAnnotation(r, matrix)); 1677 SkString name(static_cast<const char *>(nameData->data()), 1678 nameData->size() - 1); 1679 annotation->insert("Dest", SkNEW_ARGS(SkPDFName, (name)))->unref(); 1680 } 1681 1682 struct NamedDestination { 1683 const SkData* nameData; 1684 SkPoint point; 1685 1686 NamedDestination(const SkData* nameData, const SkPoint& point) 1687 : nameData(nameData), point(point) { 1688 nameData->ref(); 1689 } 1690 1691 ~NamedDestination() { 1692 nameData->unref(); 1693 } 1694 }; 1695 1696 void SkPDFDevice::defineNamedDestination(SkData* nameData, const SkPoint& point, 1697 const SkMatrix& matrix) { 1698 SkMatrix transform = matrix; 1699 transform.postConcat(fInitialTransform); 1700 SkPoint translatedPoint; 1701 transform.mapXY(point.x(), point.y(), &translatedPoint); 1702 fNamedDestinations.push( 1703 SkNEW_ARGS(NamedDestination, (nameData, translatedPoint))); 1704 } 1705 1706 void SkPDFDevice::appendDestinations(SkPDFDict* dict, SkPDFObject* page) { 1707 int nDest = fNamedDestinations.count(); 1708 for (int i = 0; i < nDest; i++) { 1709 NamedDestination* dest = fNamedDestinations[i]; 1710 SkAutoTUnref<SkPDFArray> pdfDest(SkNEW(SkPDFArray)); 1711 pdfDest->reserve(5); 1712 pdfDest->append(SkNEW_ARGS(SkPDFObjRef, (page)))->unref(); 1713 pdfDest->appendName("XYZ"); 1714 pdfDest->appendScalar(dest->point.x()); 1715 pdfDest->appendScalar(dest->point.y()); 1716 pdfDest->appendInt(0); // Leave zoom unchanged 1717 dict->insert(static_cast<const char *>(dest->nameData->data()), 1718 pdfDest); 1719 } 1720 } 1721 1722 SkPDFFormXObject* SkPDFDevice::createFormXObjectFromDevice() { 1723 SkPDFFormXObject* xobject = SkNEW_ARGS(SkPDFFormXObject, (this)); 1724 // We always draw the form xobjects that we create back into the device, so 1725 // we simply preserve the font usage instead of pulling it out and merging 1726 // it back in later. 1727 cleanUp(false); // Reset this device to have no content. 1728 init(); 1729 return xobject; 1730 } 1731 1732 void SkPDFDevice::drawFormXObjectWithMask(int xObjectIndex, 1733 SkPDFFormXObject* mask, 1734 const SkClipStack* clipStack, 1735 const SkRegion& clipRegion, 1736 SkXfermode::Mode mode, 1737 bool invertClip) { 1738 if (clipRegion.isEmpty() && !invertClip) { 1739 return; 1740 } 1741 1742 SkAutoTUnref<SkPDFGraphicState> sMaskGS( 1743 SkPDFGraphicState::GetSMaskGraphicState( 1744 mask, invertClip, SkPDFGraphicState::kAlpha_SMaskMode)); 1745 1746 SkMatrix identity; 1747 identity.reset(); 1748 SkPaint paint; 1749 paint.setXfermodeMode(mode); 1750 ScopedContentEntry content(this, clipStack, clipRegion, identity, paint); 1751 if (!content.entry()) { 1752 return; 1753 } 1754 SkPDFUtils::ApplyGraphicState(addGraphicStateResource(sMaskGS.get()), 1755 &content.entry()->fContent); 1756 SkPDFUtils::DrawFormXObject(xObjectIndex, &content.entry()->fContent); 1757 1758 sMaskGS.reset(SkPDFGraphicState::GetNoSMaskGraphicState()); 1759 SkPDFUtils::ApplyGraphicState(addGraphicStateResource(sMaskGS.get()), 1760 &content.entry()->fContent); 1761 } 1762 1763 ContentEntry* SkPDFDevice::setUpContentEntry(const SkClipStack* clipStack, 1764 const SkRegion& clipRegion, 1765 const SkMatrix& matrix, 1766 const SkPaint& paint, 1767 bool hasText, 1768 SkPDFFormXObject** dst) { 1769 *dst = NULL; 1770 if (clipRegion.isEmpty()) { 1771 return NULL; 1772 } 1773 1774 // The clip stack can come from an SkDraw where it is technically optional. 1775 SkClipStack synthesizedClipStack; 1776 if (clipStack == NULL) { 1777 if (clipRegion == fExistingClipRegion) { 1778 clipStack = &fExistingClipStack; 1779 } else { 1780 // GraphicStackState::updateClip expects the clip stack to have 1781 // fExistingClip as a prefix, so start there, then set the clip 1782 // to the passed region. 1783 synthesizedClipStack = fExistingClipStack; 1784 SkPath clipPath; 1785 clipRegion.getBoundaryPath(&clipPath); 1786 synthesizedClipStack.clipDevPath(clipPath, SkRegion::kReplace_Op, 1787 false); 1788 clipStack = &synthesizedClipStack; 1789 } 1790 } 1791 1792 SkXfermode::Mode xfermode = SkXfermode::kSrcOver_Mode; 1793 if (paint.getXfermode()) { 1794 paint.getXfermode()->asMode(&xfermode); 1795 } 1796 1797 // For the following modes, we want to handle source and destination 1798 // separately, so make an object of what's already there. 1799 if (xfermode == SkXfermode::kClear_Mode || 1800 xfermode == SkXfermode::kSrc_Mode || 1801 xfermode == SkXfermode::kSrcIn_Mode || 1802 xfermode == SkXfermode::kDstIn_Mode || 1803 xfermode == SkXfermode::kSrcOut_Mode || 1804 xfermode == SkXfermode::kDstOut_Mode || 1805 xfermode == SkXfermode::kSrcATop_Mode || 1806 xfermode == SkXfermode::kDstATop_Mode || 1807 xfermode == SkXfermode::kModulate_Mode) { 1808 if (!isContentEmpty()) { 1809 *dst = createFormXObjectFromDevice(); 1810 SkASSERT(isContentEmpty()); 1811 } else if (xfermode != SkXfermode::kSrc_Mode && 1812 xfermode != SkXfermode::kSrcOut_Mode) { 1813 // Except for Src and SrcOut, if there isn't anything already there, 1814 // then we're done. 1815 return NULL; 1816 } 1817 } 1818 // TODO(vandebo): Figure out how/if we can handle the following modes: 1819 // Xor, Plus. 1820 1821 // Dst xfer mode doesn't draw source at all. 1822 if (xfermode == SkXfermode::kDst_Mode) { 1823 return NULL; 1824 } 1825 1826 ContentEntry* entry; 1827 SkAutoTDelete<ContentEntry> newEntry; 1828 1829 ContentEntry* lastContentEntry = getLastContentEntry(); 1830 if (lastContentEntry && lastContentEntry->fContent.getOffset() == 0) { 1831 entry = lastContentEntry; 1832 } else { 1833 newEntry.reset(new ContentEntry); 1834 entry = newEntry.get(); 1835 } 1836 1837 populateGraphicStateEntryFromPaint(matrix, *clipStack, clipRegion, paint, 1838 hasText, &entry->fState); 1839 if (lastContentEntry && xfermode != SkXfermode::kDstOver_Mode && 1840 entry->fState.compareInitialState(lastContentEntry->fState)) { 1841 return lastContentEntry; 1842 } 1843 1844 SkAutoTDelete<ContentEntry>* contentEntries = getContentEntries(); 1845 if (!lastContentEntry) { 1846 contentEntries->reset(entry); 1847 setLastContentEntry(entry); 1848 } else if (xfermode == SkXfermode::kDstOver_Mode) { 1849 entry->fNext.reset(contentEntries->detach()); 1850 contentEntries->reset(entry); 1851 } else { 1852 lastContentEntry->fNext.reset(entry); 1853 setLastContentEntry(entry); 1854 } 1855 newEntry.detach(); 1856 return entry; 1857 } 1858 1859 void SkPDFDevice::finishContentEntry(SkXfermode::Mode xfermode, 1860 SkPDFFormXObject* dst, 1861 SkPath* shape) { 1862 if (xfermode != SkXfermode::kClear_Mode && 1863 xfermode != SkXfermode::kSrc_Mode && 1864 xfermode != SkXfermode::kDstOver_Mode && 1865 xfermode != SkXfermode::kSrcIn_Mode && 1866 xfermode != SkXfermode::kDstIn_Mode && 1867 xfermode != SkXfermode::kSrcOut_Mode && 1868 xfermode != SkXfermode::kDstOut_Mode && 1869 xfermode != SkXfermode::kSrcATop_Mode && 1870 xfermode != SkXfermode::kDstATop_Mode && 1871 xfermode != SkXfermode::kModulate_Mode) { 1872 SkASSERT(!dst); 1873 return; 1874 } 1875 if (xfermode == SkXfermode::kDstOver_Mode) { 1876 SkASSERT(!dst); 1877 ContentEntry* firstContentEntry = getContentEntries()->get(); 1878 if (firstContentEntry->fContent.getOffset() == 0) { 1879 // For DstOver, an empty content entry was inserted before the rest 1880 // of the content entries. If nothing was drawn, it needs to be 1881 // removed. 1882 SkAutoTDelete<ContentEntry>* contentEntries = getContentEntries(); 1883 contentEntries->reset(firstContentEntry->fNext.detach()); 1884 } 1885 return; 1886 } 1887 if (!dst) { 1888 SkASSERT(xfermode == SkXfermode::kSrc_Mode || 1889 xfermode == SkXfermode::kSrcOut_Mode); 1890 return; 1891 } 1892 1893 ContentEntry* contentEntries = getContentEntries()->get(); 1894 SkASSERT(dst); 1895 SkASSERT(!contentEntries->fNext.get()); 1896 // Changing the current content into a form-xobject will destroy the clip 1897 // objects which is fine since the xobject will already be clipped. However 1898 // if source has shape, we need to clip it too, so a copy of the clip is 1899 // saved. 1900 SkClipStack clipStack = contentEntries->fState.fClipStack; 1901 SkRegion clipRegion = contentEntries->fState.fClipRegion; 1902 1903 SkMatrix identity; 1904 identity.reset(); 1905 SkPaint stockPaint; 1906 1907 SkAutoTUnref<SkPDFFormXObject> srcFormXObject; 1908 if (isContentEmpty()) { 1909 // If nothing was drawn and there's no shape, then the draw was a 1910 // no-op, but dst needs to be restored for that to be true. 1911 // If there is shape, then an empty source with Src, SrcIn, SrcOut, 1912 // DstIn, DstAtop or Modulate reduces to Clear and DstOut or SrcAtop 1913 // reduces to Dst. 1914 if (shape == NULL || xfermode == SkXfermode::kDstOut_Mode || 1915 xfermode == SkXfermode::kSrcATop_Mode) { 1916 ScopedContentEntry content(this, &fExistingClipStack, 1917 fExistingClipRegion, identity, 1918 stockPaint); 1919 SkPDFUtils::DrawFormXObject(this->addXObjectResource(dst), 1920 &content.entry()->fContent); 1921 return; 1922 } else { 1923 xfermode = SkXfermode::kClear_Mode; 1924 } 1925 } else { 1926 SkASSERT(!fContentEntries->fNext.get()); 1927 srcFormXObject.reset(createFormXObjectFromDevice()); 1928 } 1929 1930 // TODO(vandebo) srcFormXObject may contain alpha, but here we want it 1931 // without alpha. 1932 if (xfermode == SkXfermode::kSrcATop_Mode) { 1933 // TODO(vandebo): In order to properly support SrcATop we have to track 1934 // the shape of what's been drawn at all times. It's the intersection of 1935 // the non-transparent parts of the device and the outlines (shape) of 1936 // all images and devices drawn. 1937 drawFormXObjectWithMask(addXObjectResource(srcFormXObject.get()), dst, 1938 &fExistingClipStack, fExistingClipRegion, 1939 SkXfermode::kSrcOver_Mode, true); 1940 } else { 1941 SkAutoTUnref<SkPDFFormXObject> dstMaskStorage; 1942 SkPDFFormXObject* dstMask = srcFormXObject.get(); 1943 if (shape != NULL) { 1944 // Draw shape into a form-xobject. 1945 SkDraw d; 1946 d.fMatrix = &identity; 1947 d.fClip = &clipRegion; 1948 d.fClipStack = &clipStack; 1949 SkPaint filledPaint; 1950 filledPaint.setColor(SK_ColorBLACK); 1951 filledPaint.setStyle(SkPaint::kFill_Style); 1952 this->drawPath(d, *shape, filledPaint, NULL, true); 1953 1954 dstMaskStorage.reset(createFormXObjectFromDevice()); 1955 dstMask = dstMaskStorage.get(); 1956 } 1957 drawFormXObjectWithMask(addXObjectResource(dst), dstMask, 1958 &fExistingClipStack, fExistingClipRegion, 1959 SkXfermode::kSrcOver_Mode, true); 1960 } 1961 1962 if (xfermode == SkXfermode::kClear_Mode) { 1963 return; 1964 } else if (xfermode == SkXfermode::kSrc_Mode || 1965 xfermode == SkXfermode::kDstATop_Mode) { 1966 ScopedContentEntry content(this, &fExistingClipStack, 1967 fExistingClipRegion, identity, stockPaint); 1968 if (content.entry()) { 1969 SkPDFUtils::DrawFormXObject( 1970 this->addXObjectResource(srcFormXObject.get()), 1971 &content.entry()->fContent); 1972 } 1973 if (xfermode == SkXfermode::kSrc_Mode) { 1974 return; 1975 } 1976 } else if (xfermode == SkXfermode::kSrcATop_Mode) { 1977 ScopedContentEntry content(this, &fExistingClipStack, 1978 fExistingClipRegion, identity, stockPaint); 1979 if (content.entry()) { 1980 SkPDFUtils::DrawFormXObject(this->addXObjectResource(dst), 1981 &content.entry()->fContent); 1982 } 1983 } 1984 1985 SkASSERT(xfermode == SkXfermode::kSrcIn_Mode || 1986 xfermode == SkXfermode::kDstIn_Mode || 1987 xfermode == SkXfermode::kSrcOut_Mode || 1988 xfermode == SkXfermode::kDstOut_Mode || 1989 xfermode == SkXfermode::kSrcATop_Mode || 1990 xfermode == SkXfermode::kDstATop_Mode || 1991 xfermode == SkXfermode::kModulate_Mode); 1992 1993 if (xfermode == SkXfermode::kSrcIn_Mode || 1994 xfermode == SkXfermode::kSrcOut_Mode || 1995 xfermode == SkXfermode::kSrcATop_Mode) { 1996 drawFormXObjectWithMask(addXObjectResource(srcFormXObject.get()), dst, 1997 &fExistingClipStack, fExistingClipRegion, 1998 SkXfermode::kSrcOver_Mode, 1999 xfermode == SkXfermode::kSrcOut_Mode); 2000 } else { 2001 SkXfermode::Mode mode = SkXfermode::kSrcOver_Mode; 2002 if (xfermode == SkXfermode::kModulate_Mode) { 2003 drawFormXObjectWithMask(addXObjectResource(srcFormXObject.get()), 2004 dst, &fExistingClipStack, 2005 fExistingClipRegion, 2006 SkXfermode::kSrcOver_Mode, false); 2007 mode = SkXfermode::kMultiply_Mode; 2008 } 2009 drawFormXObjectWithMask(addXObjectResource(dst), srcFormXObject.get(), 2010 &fExistingClipStack, fExistingClipRegion, mode, 2011 xfermode == SkXfermode::kDstOut_Mode); 2012 } 2013 } 2014 2015 bool SkPDFDevice::isContentEmpty() { 2016 ContentEntry* contentEntries = getContentEntries()->get(); 2017 if (!contentEntries || contentEntries->fContent.getOffset() == 0) { 2018 SkASSERT(!contentEntries || !contentEntries->fNext.get()); 2019 return true; 2020 } 2021 return false; 2022 } 2023 2024 void SkPDFDevice::populateGraphicStateEntryFromPaint( 2025 const SkMatrix& matrix, 2026 const SkClipStack& clipStack, 2027 const SkRegion& clipRegion, 2028 const SkPaint& paint, 2029 bool hasText, 2030 GraphicStateEntry* entry) { 2031 NOT_IMPLEMENTED(paint.getPathEffect() != NULL, false); 2032 NOT_IMPLEMENTED(paint.getMaskFilter() != NULL, false); 2033 NOT_IMPLEMENTED(paint.getColorFilter() != NULL, false); 2034 2035 entry->fMatrix = matrix; 2036 entry->fClipStack = clipStack; 2037 entry->fClipRegion = clipRegion; 2038 entry->fColor = SkColorSetA(paint.getColor(), 0xFF); 2039 entry->fShaderIndex = -1; 2040 2041 // PDF treats a shader as a color, so we only set one or the other. 2042 SkAutoTUnref<SkPDFObject> pdfShader; 2043 const SkShader* shader = paint.getShader(); 2044 SkColor color = paint.getColor(); 2045 if (shader) { 2046 // PDF positions patterns relative to the initial transform, so 2047 // we need to apply the current transform to the shader parameters. 2048 SkMatrix transform = matrix; 2049 transform.postConcat(fInitialTransform); 2050 2051 // PDF doesn't support kClamp_TileMode, so we simulate it by making 2052 // a pattern the size of the current clip. 2053 SkIRect bounds = clipRegion.getBounds(); 2054 2055 // We need to apply the initial transform to bounds in order to get 2056 // bounds in a consistent coordinate system. 2057 SkRect boundsTemp; 2058 boundsTemp.set(bounds); 2059 fInitialTransform.mapRect(&boundsTemp); 2060 boundsTemp.roundOut(&bounds); 2061 2062 pdfShader.reset(SkPDFShader::GetPDFShader(*shader, transform, bounds)); 2063 2064 if (pdfShader.get()) { 2065 // pdfShader has been canonicalized so we can directly compare 2066 // pointers. 2067 int resourceIndex = fShaderResources.find(pdfShader.get()); 2068 if (resourceIndex < 0) { 2069 resourceIndex = fShaderResources.count(); 2070 fShaderResources.push(pdfShader.get()); 2071 pdfShader.get()->ref(); 2072 } 2073 entry->fShaderIndex = resourceIndex; 2074 } else { 2075 // A color shader is treated as an invalid shader so we don't have 2076 // to set a shader just for a color. 2077 SkShader::GradientInfo gradientInfo; 2078 SkColor gradientColor; 2079 gradientInfo.fColors = &gradientColor; 2080 gradientInfo.fColorOffsets = NULL; 2081 gradientInfo.fColorCount = 1; 2082 if (shader->asAGradient(&gradientInfo) == 2083 SkShader::kColor_GradientType) { 2084 entry->fColor = SkColorSetA(gradientColor, 0xFF); 2085 color = gradientColor; 2086 } 2087 } 2088 } 2089 2090 SkAutoTUnref<SkPDFGraphicState> newGraphicState; 2091 if (color == paint.getColor()) { 2092 newGraphicState.reset( 2093 SkPDFGraphicState::GetGraphicStateForPaint(paint)); 2094 } else { 2095 SkPaint newPaint = paint; 2096 newPaint.setColor(color); 2097 newGraphicState.reset( 2098 SkPDFGraphicState::GetGraphicStateForPaint(newPaint)); 2099 } 2100 int resourceIndex = addGraphicStateResource(newGraphicState.get()); 2101 entry->fGraphicStateIndex = resourceIndex; 2102 2103 if (hasText) { 2104 entry->fTextScaleX = paint.getTextScaleX(); 2105 entry->fTextFill = paint.getStyle(); 2106 } else { 2107 entry->fTextScaleX = 0; 2108 } 2109 } 2110 2111 int SkPDFDevice::addGraphicStateResource(SkPDFGraphicState* gs) { 2112 // Assumes that gs has been canonicalized (so we can directly compare 2113 // pointers). 2114 int result = fGraphicStateResources.find(gs); 2115 if (result < 0) { 2116 result = fGraphicStateResources.count(); 2117 fGraphicStateResources.push(gs); 2118 gs->ref(); 2119 } 2120 return result; 2121 } 2122 2123 int SkPDFDevice::addXObjectResource(SkPDFObject* xObject) { 2124 // Assumes that xobject has been canonicalized (so we can directly compare 2125 // pointers). 2126 int result = fXObjectResources.find(xObject); 2127 if (result < 0) { 2128 result = fXObjectResources.count(); 2129 fXObjectResources.push(xObject); 2130 xObject->ref(); 2131 } 2132 return result; 2133 } 2134 2135 void SkPDFDevice::updateFont(const SkPaint& paint, uint16_t glyphID, 2136 ContentEntry* contentEntry) { 2137 SkTypeface* typeface = paint.getTypeface(); 2138 if (contentEntry->fState.fFont == NULL || 2139 contentEntry->fState.fTextSize != paint.getTextSize() || 2140 !contentEntry->fState.fFont->hasGlyph(glyphID)) { 2141 int fontIndex = getFontResourceIndex(typeface, glyphID); 2142 contentEntry->fContent.writeText("/"); 2143 contentEntry->fContent.writeText(SkPDFResourceDict::getResourceName( 2144 SkPDFResourceDict::kFont_ResourceType, 2145 fontIndex).c_str()); 2146 contentEntry->fContent.writeText(" "); 2147 SkPDFScalar::Append(paint.getTextSize(), &contentEntry->fContent); 2148 contentEntry->fContent.writeText(" Tf\n"); 2149 contentEntry->fState.fFont = fFontResources[fontIndex]; 2150 } 2151 } 2152 2153 int SkPDFDevice::getFontResourceIndex(SkTypeface* typeface, uint16_t glyphID) { 2154 SkAutoTUnref<SkPDFFont> newFont(SkPDFFont::GetFontResource(typeface, 2155 glyphID)); 2156 int resourceIndex = fFontResources.find(newFont.get()); 2157 if (resourceIndex < 0) { 2158 resourceIndex = fFontResources.count(); 2159 fFontResources.push(newFont.get()); 2160 newFont.get()->ref(); 2161 } 2162 return resourceIndex; 2163 } 2164 2165 void SkPDFDevice::internalDrawBitmap(const SkMatrix& origMatrix, 2166 const SkClipStack* clipStack, 2167 const SkRegion& origClipRegion, 2168 const SkBitmap& origBitmap, 2169 const SkIRect* srcRect, 2170 const SkPaint& paint) { 2171 SkMatrix matrix = origMatrix; 2172 SkRegion perspectiveBounds; 2173 const SkRegion* clipRegion = &origClipRegion; 2174 SkBitmap perspectiveBitmap; 2175 const SkBitmap* bitmap = &origBitmap; 2176 SkBitmap tmpSubsetBitmap; 2177 2178 // Rasterize the bitmap using perspective in a new bitmap. 2179 if (origMatrix.hasPerspective()) { 2180 if (fRasterDpi == 0) { 2181 return; 2182 } 2183 SkBitmap* subsetBitmap; 2184 if (srcRect) { 2185 if (!origBitmap.extractSubset(&tmpSubsetBitmap, *srcRect)) { 2186 return; 2187 } 2188 subsetBitmap = &tmpSubsetBitmap; 2189 } else { 2190 subsetBitmap = &tmpSubsetBitmap; 2191 *subsetBitmap = origBitmap; 2192 } 2193 srcRect = NULL; 2194 2195 // Transform the bitmap in the new space, without taking into 2196 // account the initial transform. 2197 SkPath perspectiveOutline; 2198 perspectiveOutline.addRect( 2199 SkRect::MakeWH(SkIntToScalar(subsetBitmap->width()), 2200 SkIntToScalar(subsetBitmap->height()))); 2201 perspectiveOutline.transform(origMatrix); 2202 2203 // TODO(edisonn): perf - use current clip too. 2204 // Retrieve the bounds of the new shape. 2205 SkRect bounds = perspectiveOutline.getBounds(); 2206 2207 // Transform the bitmap in the new space, taking into 2208 // account the initial transform. 2209 SkMatrix total = origMatrix; 2210 total.postConcat(fInitialTransform); 2211 total.postScale(SkIntToScalar(fRasterDpi) / 2212 SkIntToScalar(DPI_FOR_RASTER_SCALE_ONE), 2213 SkIntToScalar(fRasterDpi) / 2214 SkIntToScalar(DPI_FOR_RASTER_SCALE_ONE)); 2215 SkPath physicalPerspectiveOutline; 2216 physicalPerspectiveOutline.addRect( 2217 SkRect::MakeWH(SkIntToScalar(subsetBitmap->width()), 2218 SkIntToScalar(subsetBitmap->height()))); 2219 physicalPerspectiveOutline.transform(total); 2220 2221 SkScalar scaleX = physicalPerspectiveOutline.getBounds().width() / 2222 bounds.width(); 2223 SkScalar scaleY = physicalPerspectiveOutline.getBounds().height() / 2224 bounds.height(); 2225 2226 // TODO(edisonn): A better approach would be to use a bitmap shader 2227 // (in clamp mode) and draw a rect over the entire bounding box. Then 2228 // intersect perspectiveOutline to the clip. That will avoid introducing 2229 // alpha to the image while still giving good behavior at the edge of 2230 // the image. Avoiding alpha will reduce the pdf size and generation 2231 // CPU time some. 2232 2233 const int w = SkScalarCeilToInt(physicalPerspectiveOutline.getBounds().width()); 2234 const int h = SkScalarCeilToInt(physicalPerspectiveOutline.getBounds().height()); 2235 if (!perspectiveBitmap.allocPixels(SkImageInfo::MakeN32Premul(w, h))) { 2236 return; 2237 } 2238 perspectiveBitmap.eraseColor(SK_ColorTRANSPARENT); 2239 2240 SkBitmapDevice device(perspectiveBitmap); 2241 SkCanvas canvas(&device); 2242 2243 SkScalar deltaX = bounds.left(); 2244 SkScalar deltaY = bounds.top(); 2245 2246 SkMatrix offsetMatrix = origMatrix; 2247 offsetMatrix.postTranslate(-deltaX, -deltaY); 2248 offsetMatrix.postScale(scaleX, scaleY); 2249 2250 // Translate the draw in the new canvas, so we perfectly fit the 2251 // shape in the bitmap. 2252 canvas.setMatrix(offsetMatrix); 2253 2254 canvas.drawBitmap(*subsetBitmap, SkIntToScalar(0), SkIntToScalar(0)); 2255 2256 // Make sure the final bits are in the bitmap. 2257 canvas.flush(); 2258 2259 // In the new space, we use the identity matrix translated 2260 // and scaled to reflect DPI. 2261 matrix.setScale(1 / scaleX, 1 / scaleY); 2262 matrix.postTranslate(deltaX, deltaY); 2263 2264 perspectiveBounds.setRect( 2265 SkIRect::MakeXYWH(SkScalarFloorToInt(bounds.x()), 2266 SkScalarFloorToInt(bounds.y()), 2267 SkScalarCeilToInt(bounds.width()), 2268 SkScalarCeilToInt(bounds.height()))); 2269 clipRegion = &perspectiveBounds; 2270 srcRect = NULL; 2271 bitmap = &perspectiveBitmap; 2272 } 2273 2274 SkMatrix scaled; 2275 // Adjust for origin flip. 2276 scaled.setScale(SK_Scalar1, -SK_Scalar1); 2277 scaled.postTranslate(0, SK_Scalar1); 2278 // Scale the image up from 1x1 to WxH. 2279 SkIRect subset = SkIRect::MakeWH(bitmap->width(), bitmap->height()); 2280 scaled.postScale(SkIntToScalar(subset.width()), 2281 SkIntToScalar(subset.height())); 2282 scaled.postConcat(matrix); 2283 ScopedContentEntry content(this, clipStack, *clipRegion, scaled, paint); 2284 if (!content.entry() || (srcRect && !subset.intersect(*srcRect))) { 2285 return; 2286 } 2287 if (content.needShape()) { 2288 SkPath shape; 2289 shape.addRect(SkRect::MakeWH(SkIntToScalar(subset.width()), 2290 SkIntToScalar( subset.height()))); 2291 shape.transform(matrix); 2292 content.setShape(shape); 2293 } 2294 if (!content.needSource()) { 2295 return; 2296 } 2297 2298 SkAutoTUnref<SkPDFImage> image( 2299 SkPDFImage::CreateImage(*bitmap, subset, fEncoder)); 2300 if (!image) { 2301 return; 2302 } 2303 2304 SkPDFUtils::DrawFormXObject(this->addXObjectResource(image.get()), 2305 &content.entry()->fContent); 2306 } 2307 2308 bool SkPDFDevice::allowImageFilter(const SkImageFilter*) { 2309 return false; 2310 } 2311