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