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