SkPDFDevice.cpp revision 13d14a9dbd2cf0a9654045cc967e92626690631a
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Copyright (C) 2011 Google Inc. 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Licensed under the Apache License, Version 2.0 (the "License"); 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * you may not use this file except in compliance with the License. 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * You may obtain a copy of the License at 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 8cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * http://www.apache.org/licenses/LICENSE-2.0 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 10868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) * Unless required by applicable law or agreed to in writing, software 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * distributed under the License is distributed on an "AS IS" BASIS, 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * See the License for the specific language governing permissions and 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * limitations under the License. 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "SkPDFDevice.h" 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "SkColor.h" 20cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "SkClipStack.h" 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "SkDraw.h" 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "SkGlyphCache.h" 235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "SkPaint.h" 245c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "SkPath.h" 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "SkPDFFont.h" 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "SkPDFFormXObject.h" 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "SkPDFGraphicState.h" 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "SkPDFImage.h" 29cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "SkPDFShader.h" 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "SkPDFStream.h" 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "SkPDFTypes.h" 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "SkPDFUtils.h" 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "SkRect.h" 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "SkString.h" 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "SkTextFormatParams.h" 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "SkTypeface.h" 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "SkTypes.h" 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Utility functions 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void emit_pdf_color(SkColor color, SkWStream* result) { 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkASSERT(SkColorGetA(color) == 0xFF); // We handle alpha elsewhere. 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkScalar colorMax = SkIntToScalar(0xFF); 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkPDFScalar::Append( 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkScalarDiv(SkIntToScalar(SkColorGetR(color)), colorMax), result); 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) result->writeText(" "); 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkPDFScalar::Append( 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkScalarDiv(SkIntToScalar(SkColorGetG(color)), colorMax), result); 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) result->writeText(" "); 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkPDFScalar::Append( 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkScalarDiv(SkIntToScalar(SkColorGetB(color)), colorMax), result); 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) result->writeText(" "); 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static SkPaint calculate_text_paint(const SkPaint& paint) { 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkPaint result = paint; 57f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (result.isFakeBoldText()) { 58f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) SkScalar fakeBoldScale = SkScalarInterpFunc(result.getTextSize(), 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kStdFakeBoldInterpKeys, 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kStdFakeBoldInterpValues, 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kStdFakeBoldInterpLength); 62f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) SkScalar width = SkScalarMul(result.getTextSize(), fakeBoldScale); 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (result.getStyle() == SkPaint::kFill_Style) 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) result.setStyle(SkPaint::kStrokeAndFill_Style); 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) width += result.getStrokeWidth(); 675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) result.setStrokeWidth(width); 685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 695c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return result; 705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Stolen from measure_text in SkDraw.cpp and then tweaked. 73cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)static void align_text(SkDrawCacheProc glyphCacheProc, const SkPaint& paint, 74cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const uint16_t* glyphs, size_t len, SkScalar* x, 75cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) SkScalar* y, SkScalar* width) { 76cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (paint.getTextAlign() == SkPaint::kLeft_Align && width == NULL) 77cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return; 78cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 79cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) SkMatrix ident; 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ident.reset(); 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkAutoGlyphCache autoCache(paint, &ident); 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkGlyphCache* cache = autoCache.getCache(); 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* start = (char*)glyphs; 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* stop = (char*)(glyphs + len); 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkFixed xAdv = 0, yAdv = 0; 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(vandebo) This probably needs to take kerning into account. 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (start < stop) { 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const SkGlyph& glyph = glyphCacheProc(cache, &start, 0, 0); 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) xAdv += glyph.fAdvanceX; 925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) yAdv += glyph.fAdvanceY; 93cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) }; 94cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (width) 95cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) *width = SkFixedToScalar(xAdv); 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (paint.getTextAlign() == SkPaint::kLeft_Align) 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkScalar xAdj = SkFixedToScalar(xAdv); 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkScalar yAdj = SkFixedToScalar(yAdv); 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (paint.getTextAlign() == SkPaint::kCenter_Align) { 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) xAdj = SkScalarHalf(xAdj); 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) yAdj = SkScalarHalf(yAdj); 104cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 105cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) *x = *x - xAdj; 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *y = *y - yAdj; 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void set_text_transform(SkScalar x, SkScalar y, SkScalar textSkewX, 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkWStream* content) { 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Flip the text about the x-axis to account for origin swap and include 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the passed parameters. 1135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) content->writeText("1 0 "); 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkPDFScalar::Append(0 - textSkewX, content); 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content->writeText(" -1 "); 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkPDFScalar::Append(x, content); 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content->writeText(" "); 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkPDFScalar::Append(y, content); 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content->writeText(" Tm\n"); 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// It is important to not confuse GraphicStateEntry with SkPDFGraphicState, the 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// later being our representation of an object in the PDF file. 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct GraphicStateEntry { 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GraphicStateEntry(); 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Compare the fields we care about when setting up a new content entry. 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool compareInitialState(const GraphicStateEntry& b); 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkMatrix fMatrix; 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We can't do set operations on Paths, though PDF natively supports 132a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // intersect. If the clip stack does anything other than intersect, 133a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // we have to fall back to the region. Treat fClipStack as authoritative. 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // See http://code.google.com/p/skia/issues/detail?id=221 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkClipStack fClipStack; 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkRegion fClipRegion; 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // When emitting the content entry, we will ensure the graphic state 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // is set to these values first. 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkColor fColor; 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkScalar fTextScaleX; // Zero means we don't care what the value is. 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkPaint::Style fTextFill; // Only if TextScaleX is non-zero. 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int fShaderIndex; 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int fGraphicStateIndex; 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We may change the font (i.e. for Type1 support) within a 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // ContentEntry. This is the one currently in effect, or NULL if none. 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkPDFFont* fFont; 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // In PDF, text size has no default value. It is only valid if fFont is 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // not NULL. 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkScalar fTextSize; 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)GraphicStateEntry::GraphicStateEntry() : fColor(SK_ColorBLACK), 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fTextScaleX(SK_Scalar1), 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fTextFill(SkPaint::kFill_Style), 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fShaderIndex(-1), 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fGraphicStateIndex(-1), 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fFont(NULL), 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fTextSize(SK_ScalarNaN) { 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fMatrix.reset(); 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool GraphicStateEntry::compareInitialState(const GraphicStateEntry& b) { 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return fColor == b.fColor && 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fShaderIndex == b.fShaderIndex && 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fGraphicStateIndex == b.fGraphicStateIndex && 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fMatrix == b.fMatrix && 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fClipStack == b.fClipStack && 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (fTextScaleX == 0 || 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) b.fTextScaleX == 0 || 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (fTextScaleX == b.fTextScaleX && fTextFill == b.fTextFill)); 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class GraphicStackState { 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)public: 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GraphicStackState(const SkClipStack& existingClipStack, 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const SkRegion& existingClipRegion, 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkWStream* contentStream) 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : fStackDepth(0), 1815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) fContentStream(contentStream) { 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fEntries[0].fClipStack = existingClipStack; 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fEntries[0].fClipRegion = existingClipRegion; 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void updateClip(const SkClipStack& clipStack, const SkRegion& clipRegion, 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const SkIPoint& translation); 1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) void updateMatrix(const SkMatrix& matrix); 1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) void updateDrawingState(const GraphicStateEntry& state); 1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void drainStack(); 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)private: 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void push(); 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void pop(); 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GraphicStateEntry* currentEntry() { return &fEntries[fStackDepth]; } 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Conservative limit on save depth, see impl. notes in PDF 1.4 spec. 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const int kMaxStackDepth = 12; 200010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) GraphicStateEntry fEntries[kMaxStackDepth + 1]; 201010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) int fStackDepth; 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkWStream* fContentStream; 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GraphicStackState::drainStack() { 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (fStackDepth) { 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pop(); 2085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 2095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 2105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GraphicStackState::push() { 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkASSERT(fStackDepth < kMaxStackDepth); 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fContentStream->writeText("q\n"); 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fStackDepth++; 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fEntries[fStackDepth] = fEntries[fStackDepth - 1]; 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GraphicStackState::pop() { 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkASSERT(fStackDepth > 0); 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fContentStream->writeText("Q\n"); 2215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) fStackDepth--; 2225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 2235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// This function initializes iter to be an interator on the "stack" argument 2255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// and then skips over the leading entries as specified in prefix. It requires 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// and asserts that "prefix" will be a prefix to "stack." 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void skip_clip_stack_prefix(const SkClipStack& prefix, 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const SkClipStack& stack, 229cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) SkClipStack::B2FIter* iter) { 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkClipStack::B2FIter prefixIter(prefix); 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) iter->reset(stack); 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const SkClipStack::B2FIter::Clip* prefixEntry; 234cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const SkClipStack::B2FIter::Clip* iterEntry; 235c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 236c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) for (prefixEntry = prefixIter.next(); prefixEntry; 237c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) prefixEntry = prefixIter.next()) { 238c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) iterEntry = iter->next(); 239cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) SkASSERT(iterEntry); 240c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) SkASSERT(*prefixEntry == *iterEntry); 241c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 242c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 243c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) SkASSERT(prefixEntry == NULL); 244c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 245c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 246c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)static void emit_clip(SkPath* clipPath, SkRect* clipRect, 247c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) SkWStream* contentStream) { 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkASSERT(clipPath || clipRect); 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkPath::FillType clipFill; 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (clipPath) { 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkPDFUtils::EmitPath(*clipPath, contentStream); 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) clipFill = clipPath->getFillType(); 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (clipRect) { 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkPDFUtils::AppendRectangle(*clipRect, contentStream); 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) clipFill = SkPath::kWinding_FillType; 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOT_IMPLEMENTED(clipFill == SkPath::kInverseEvenOdd_FillType, false); 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOT_IMPLEMENTED(clipFill == SkPath::kInverseWinding_FillType, false); 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (clipFill == SkPath::kEvenOdd_FillType) { 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) contentStream->writeText("W* n\n"); 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) contentStream->writeText("W n\n"); 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(vandebo) Take advantage of SkClipStack::getSaveCount(), the PDF 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// graphic state stack, and the fact that we can know all the clips used 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// on the page to optimize this. 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GraphicStackState::updateClip(const SkClipStack& clipStack, 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const SkRegion& clipRegion, 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const SkIPoint& translation) { 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (clipStack == currentEntry()->fClipStack) { 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (fStackDepth > 0) { 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pop(); 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (clipStack == currentEntry()->fClipStack) { 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 284f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) push(); 285f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 286f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // gsState->initialEntry()->fClipStack/Region specifies the clip that has 287f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // already been applied. (If this is a top level device, then it specifies 288f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // a clip to the content area. If this is a layer, then it specifies 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the clip in effect when the layer was created.) There's no need to 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // reapply that clip; SKCanvas's SkDrawIter will draw anything outside the 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // initial clip on the parent layer. (This means there's a bug if the user 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // expands the clip and then uses any xfer mode that uses dst: 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // http://code.google.com/p/skia/issues/detail?id=228 ) 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkClipStack::B2FIter iter; 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) skip_clip_stack_prefix(fEntries[0].fClipStack, clipStack, &iter); 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If the clip stack does anything other than intersect or if it uses 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // an inverse fill type, we have to fall back to the clip region. 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool needRegion = false; 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const SkClipStack::B2FIter::Clip* clipEntry; 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (clipEntry = iter.next(); clipEntry; clipEntry = iter.next()) { 3025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (clipEntry->fOp != SkRegion::kIntersect_Op || 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (clipEntry->fPath && clipEntry->fPath->isInverseFillType())) { 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) needRegion = true; 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (needRegion) { 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkPath clipPath; 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkAssertResult(clipRegion.getBoundaryPath(&clipPath)); 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) emit_clip(&clipPath, NULL, fContentStream); 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) skip_clip_stack_prefix(fEntries[0].fClipStack, clipStack, &iter); 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkMatrix transform; 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) transform.setTranslate(translation.fX, translation.fY); 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const SkClipStack::B2FIter::Clip* clipEntry; 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (clipEntry = iter.next(); clipEntry; clipEntry = iter.next()) { 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkASSERT(clipEntry->fOp == SkRegion::kIntersect_Op); 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (clipEntry->fRect) { 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkRect translatedClip; 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) transform.mapRect(&translatedClip, *clipEntry->fRect); 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) emit_clip(NULL, &translatedClip, fContentStream); 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (clipEntry->fPath) { 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkPath translatedPath; 326cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) clipEntry->fPath->transform(transform, &translatedPath); 327cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) emit_clip(&translatedPath, NULL, fContentStream); 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkASSERT(false); 3305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 33123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) } 33223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) } 33323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) currentEntry()->fClipStack = clipStack; 3345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) currentEntry()->fClipRegion = clipRegion; 3355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 3365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 3375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GraphicStackState::updateMatrix(const SkMatrix& matrix) { 3385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (matrix == currentEntry()->fMatrix) { 3395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return; 3405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 3415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (currentEntry()->fMatrix.getType() != SkMatrix::kIdentity_Mask) { 3435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) SkASSERT(fStackDepth > 0); 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkASSERT(fEntries[fStackDepth].fClipStack == 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fEntries[fStackDepth -1].fClipStack); 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pop(); 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkASSERT(currentEntry()->fMatrix.getType() == SkMatrix::kIdentity_Mask); 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (matrix.getType() == SkMatrix::kIdentity_Mask) { 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) push(); 3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkPDFUtils::AppendTransform(matrix, fContentStream); 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) currentEntry()->fMatrix = matrix; 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GraphicStackState::updateDrawingState(const GraphicStateEntry& state) { 3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // PDF treats a shader as a color, so we only set one or the other. 3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (state.fShaderIndex >= 0) { 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (state.fShaderIndex != currentEntry()->fShaderIndex) { 3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fContentStream->writeText("/Pattern CS /Pattern cs /P"); 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fContentStream->writeDecAsText(state.fShaderIndex); 3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fContentStream->writeText(" SCN /P"); 3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fContentStream->writeDecAsText(state.fShaderIndex); 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fContentStream->writeText(" scn\n"); 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) currentEntry()->fShaderIndex = state.fShaderIndex; 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (state.fColor != currentEntry()->fColor || 3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) currentEntry()->fShaderIndex >= 0) { 3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) emit_pdf_color(state.fColor, fContentStream); 3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fContentStream->writeText("RG "); 3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) emit_pdf_color(state.fColor, fContentStream); 3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fContentStream->writeText("rg\n"); 3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) currentEntry()->fColor = state.fColor; 3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) currentEntry()->fShaderIndex = -1; 3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (state.fGraphicStateIndex != currentEntry()->fGraphicStateIndex) { 3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkPDFUtils::ApplyGraphicState(state.fGraphicStateIndex, fContentStream); 3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) currentEntry()->fGraphicStateIndex = state.fGraphicStateIndex; 3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (state.fTextScaleX) { 3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (state.fTextScaleX != currentEntry()->fTextScaleX) { 3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkScalar pdfScale = SkScalarMul(state.fTextScaleX, 3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkIntToScalar(100)); 3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkPDFScalar::Append(pdfScale, fContentStream); 3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fContentStream->writeText(" Tz\n"); 393010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) currentEntry()->fTextScaleX = state.fTextScaleX; 3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (state.fTextFill != currentEntry()->fTextFill) { 3965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) SK_COMPILE_ASSERT(SkPaint::kFill_Style == 0, enum_must_match_value); 3975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) SK_COMPILE_ASSERT(SkPaint::kStroke_Style == 1, 3985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) enum_must_match_value); 3995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) SK_COMPILE_ASSERT(SkPaint::kStrokeAndFill_Style == 2, 4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) enum_must_match_value); 4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fContentStream->writeDecAsText(state.fTextFill); 4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fContentStream->writeText(" Tr\n"); 4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) currentEntry()->fTextFill = state.fTextFill; 4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 407a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 408a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)struct ContentEntry { 409a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) GraphicStateEntry fState; 410a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) SkDynamicMemoryWStream fContent; 411a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) SkTScopedPtr<ContentEntry> fNext; 412a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}; 413a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 414a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// A helper class to automatically finish a ContentEntry at the end of a 4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// drawing method and maintain the state needed between set up and finish. 416a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)class ScopedContentEntry { 417a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)public: 418a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) ScopedContentEntry(SkPDFDevice* device, const SkDraw& draw, 419a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const SkPaint& paint, bool hasText = false) 420a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) : fDevice(device), 4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fContentEntry(NULL), 4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fXfermode(SkXfermode::kSrcOver_Mode) { 423a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) init(draw.fClipStack, *draw.fClip, *draw.fMatrix, paint, hasText); 424a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ScopedContentEntry(SkPDFDevice* device, const SkClipStack* clipStack, 4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const SkRegion& clipRegion, const SkMatrix& matrix, 4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const SkPaint& paint, bool hasText = false) 428a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) : fDevice(device), 429a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) fContentEntry(NULL), 430a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) fXfermode(SkXfermode::kSrcOver_Mode) { 431a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) init(clipStack, clipRegion, matrix, paint, hasText); 432a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 433a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 434a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) ~ScopedContentEntry() { 435a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (fContentEntry) { 436a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) fDevice->finishContentEntry(fXfermode, fDstFormXObject.get()); 437a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 438a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 439a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 440a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) ContentEntry* entry() { return fContentEntry; } 4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)private: 4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkPDFDevice* fDevice; 443a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) ContentEntry* fContentEntry; 444a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) SkXfermode::Mode fXfermode; 445a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) SkRefPtr<SkPDFFormXObject> fDstFormXObject; 446a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 447a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) void init(const SkClipStack* clipStack, const SkRegion& clipRegion, 448a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const SkMatrix& matrix, const SkPaint& paint, bool hasText) { 449a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (paint.getXfermode()) { 450a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) paint.getXfermode()->asMode(&fXfermode); 4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 452a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) fContentEntry = fDevice->setUpContentEntry(clipStack, clipRegion, 453a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) matrix, paint, hasText, 454a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) &fDstFormXObject); 455a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 456a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}; 457a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 458a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)//////////////////////////////////////////////////////////////////////////////// 459a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 460a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)SkDevice* SkPDFDeviceFactory::newDevice(SkCanvas* c, SkBitmap::Config config, 461a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) int width, int height, bool isOpaque, 4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool isForLayer) { 4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkMatrix initialTransform; 464a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) initialTransform.reset(); 465a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) SkISize size = SkISize::Make(width, height); 466a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (isForLayer) { 467a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return SkNEW_ARGS(SkPDFDevice, (size, c->getTotalClipStack(), 468a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) c->getTotalClip())); 4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return SkNEW_ARGS(SkPDFDevice, (size, size, initialTransform)); 4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static inline SkBitmap makeContentBitmap(const SkISize& contentSize, 4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const SkMatrix* initialTransform) { 4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkBitmap bitmap; 4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (initialTransform) { 4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Compute the size of the drawing area. 4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkVector drawingSize; 4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkMatrix inverse; 481cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) drawingSize.set(contentSize.fWidth, contentSize.fHeight); 482cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) initialTransform->invert(&inverse); 483cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) inverse.mapVectors(&drawingSize, 1); 484cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) SkISize size = SkSize::Make(drawingSize.fX, drawingSize.fY).toRound(); 485cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) bitmap.setConfig(SkBitmap::kNo_Config, abs(size.fWidth), 486cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) abs(size.fHeight)); 4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bitmap.setConfig(SkBitmap::kNo_Config, abs(contentSize.fWidth), 4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) abs(contentSize.fHeight)); 490cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 491cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 492cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return bitmap; 4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 494cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 495cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)SkPDFDevice::SkPDFDevice(const SkISize& pageSize, const SkISize& contentSize, 4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const SkMatrix& initialTransform) 4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : SkDevice(NULL, makeContentBitmap(contentSize, &initialTransform), false), 4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fPageSize(pageSize), 4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fContentSize(contentSize), 5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fLastContentEntry(NULL) { 501cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // Skia generally uses the top left as the origin but PDF natively has the 502cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // origin at the bottom left. This matrix corrects for that. But that only 503cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // needs to be done once, we don't do it when layering. 504cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) fInitialTransform.setTranslate(0, pageSize.fHeight); 505cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) fInitialTransform.preScale(1, -1); 506cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) fInitialTransform.preConcat(initialTransform); 507cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 508cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) SkIRect existingClip = SkIRect::MakeWH(this->width(), this->height()); 509cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) fExistingClipStack.clipDevRect(existingClip); 510cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) fExistingClipRegion.setRect(existingClip); 511cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 512cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) this->init(); 513cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 514cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 515cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)SkPDFDevice::SkPDFDevice(const SkISize& layerSize, 516cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const SkClipStack& existingClipStack, 517cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const SkRegion& existingClipRegion) 518cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) : SkDevice(NULL, makeContentBitmap(layerSize, NULL), false), 519cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) fPageSize(layerSize), 520cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) fContentSize(layerSize), 5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fExistingClipStack(existingClipStack), 5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fExistingClipRegion(existingClipRegion), 523cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) fLastContentEntry(NULL) { 524cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) fInitialTransform.reset(); 525cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) this->init(); 526cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 527cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 528cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)SkPDFDevice::~SkPDFDevice() { 529cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) this->cleanUp(); 530cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 531cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 532cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void SkPDFDevice::init() { 533cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) fResourceDict = NULL; 534cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) fContentEntries.reset(); 535cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) fLastContentEntry = NULL; 536cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 537cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 538cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)SkDeviceFactory* SkPDFDevice::onNewDeviceFactory() { 5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return SkNEW(SkPDFDeviceFactory); 5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 542cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void SkPDFDevice::cleanUp() { 5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fGraphicStateResources.unrefAll(); 5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fXObjectResources.unrefAll(); 5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fFontResources.unrefAll(); 5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fShaderResources.unrefAll(); 5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SkPDFDevice::clear(SkColor color) { 550010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) this->cleanUp(); 551010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) this->init(); 552010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkPaint paint; 5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) paint.setColor(color); 5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) paint.setStyle(SkPaint::kFill_Style); 5565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) SkMatrix identity; 5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) identity.reset(); 5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ScopedContentEntry content(this, &fExistingClipStack, fExistingClipRegion, 5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) identity, paint); 5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) internalDrawPaint(paint, content.entry()); 5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SkPDFDevice::drawPaint(const SkDraw& d, const SkPaint& paint) { 564cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) SkPaint newPaint = paint; 5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) newPaint.setStyle(SkPaint::kFill_Style); 5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ScopedContentEntry content(this, d, newPaint); 5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) internalDrawPaint(newPaint, content.entry()); 5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 5705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void SkPDFDevice::internalDrawPaint(const SkPaint& paint, 5715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ContentEntry* contentEntry) { 5725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (!contentEntry) { 5735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return; 5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkRect bbox = SkRect::MakeWH(SkIntToScalar(this->width()), 5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkIntToScalar(this->height())); 5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkMatrix totalTransform = fInitialTransform; 5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) totalTransform.preConcat(contentEntry->fState.fMatrix); 5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkMatrix inverse; 5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) inverse.reset(); 5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) totalTransform.invert(&inverse); 5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) inverse.mapRect(&bbox); 5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkPDFUtils::AppendRectangle(bbox, &contentEntry->fContent); 5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkPDFUtils::PaintPath(paint.getStyle(), SkPath::kWinding_FillType, 5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &contentEntry->fContent); 5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SkPDFDevice::drawPoints(const SkDraw& d, SkCanvas::PointMode mode, 5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t count, const SkPoint* points, 5912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const SkPaint& passedPaint) { 5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (count == 0) { 5932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // SkDraw::drawPoints converts to multiple calls to fDevice->drawPath. 5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We only use this when there's a path effect because of the overhead 5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // of multiple calls to setUpContentEntry it causes. 599cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (passedPaint.getPathEffect()) { 600cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (d.fClip->isEmpty()) { 601cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return; 602cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 603cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) SkDraw pointDraw(d); 604cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) pointDraw.fDevice = this; 605cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) pointDraw.drawPoints(mode, count, points, passedPaint, true); 606cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return; 607cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 608cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 609cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const SkPaint* paint = &passedPaint; 610cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) SkPaint modifiedPaint; 611cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 612cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (mode == SkCanvas::kPoints_PointMode && 613cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) paint->getStrokeCap() != SkPaint::kRound_Cap) { 614cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) modifiedPaint = *paint; 615cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) paint = &modifiedPaint; 616cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (paint->getStrokeWidth()) { 617cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // PDF won't draw a single point with square/butt caps because the 618cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // orientation is ambiguous. Draw a rectangle instead. 619cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) modifiedPaint.setStyle(SkPaint::kFill_Style); 620cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) SkScalar strokeWidth = paint->getStrokeWidth(); 621cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) SkScalar halfStroke = SkScalarHalf(strokeWidth); 622cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) for (size_t i = 0; i < count; i++) { 623cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) SkRect r = SkRect::MakeXYWH(points[i].fX, points[i].fY, 0, 0); 624cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) r.inset(-halfStroke, -halfStroke); 625cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) drawRect(d, r, modifiedPaint); 6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 627 return; 628 } else { 629 modifiedPaint.setStrokeCap(SkPaint::kRound_Cap); 630 } 631 } 632 633 ScopedContentEntry content(this, d, *paint); 634 if (!content.entry()) { 635 return; 636 } 637 638 switch (mode) { 639 case SkCanvas::kPolygon_PointMode: 640 SkPDFUtils::MoveTo(points[0].fX, points[0].fY, 641 &content.entry()->fContent); 642 for (size_t i = 1; i < count; i++) { 643 SkPDFUtils::AppendLine(points[i].fX, points[i].fY, 644 &content.entry()->fContent); 645 } 646 SkPDFUtils::StrokePath(&content.entry()->fContent); 647 break; 648 case SkCanvas::kLines_PointMode: 649 for (size_t i = 0; i < count/2; i++) { 650 SkPDFUtils::MoveTo(points[i * 2].fX, points[i * 2].fY, 651 &content.entry()->fContent); 652 SkPDFUtils::AppendLine(points[i * 2 + 1].fX, 653 points[i * 2 + 1].fY, 654 &content.entry()->fContent); 655 SkPDFUtils::StrokePath(&content.entry()->fContent); 656 } 657 break; 658 case SkCanvas::kPoints_PointMode: 659 SkASSERT(paint->getStrokeCap() == SkPaint::kRound_Cap); 660 for (size_t i = 0; i < count; i++) { 661 SkPDFUtils::MoveTo(points[i].fX, points[i].fY, 662 &content.entry()->fContent); 663 SkPDFUtils::ClosePath(&content.entry()->fContent); 664 SkPDFUtils::StrokePath(&content.entry()->fContent); 665 } 666 break; 667 default: 668 SkASSERT(false); 669 } 670} 671 672void SkPDFDevice::drawRect(const SkDraw& d, const SkRect& r, 673 const SkPaint& paint) { 674 if (paint.getPathEffect()) { 675 if (d.fClip->isEmpty()) { 676 return; 677 } 678 SkPath path; 679 path.addRect(r); 680 drawPath(d, path, paint, NULL, true); 681 return; 682 } 683 684 ScopedContentEntry content(this, d, paint); 685 if (!content.entry()) { 686 return; 687 } 688 SkPDFUtils::AppendRectangle(r, &content.entry()->fContent); 689 SkPDFUtils::PaintPath(paint.getStyle(), SkPath::kWinding_FillType, 690 &content.entry()->fContent); 691} 692 693void SkPDFDevice::drawPath(const SkDraw& d, const SkPath& origPath, 694 const SkPaint& paint, const SkMatrix* prePathMatrix, 695 bool pathIsMutable) { 696 SkPath modifiedPath; 697 SkPath* pathPtr = const_cast<SkPath*>(&origPath); 698 699 SkMatrix matrix = *d.fMatrix; 700 if (prePathMatrix) { 701 if (paint.getPathEffect() || paint.getStyle() != SkPaint::kFill_Style) { 702 if (!pathIsMutable) { 703 pathPtr = &modifiedPath; 704 pathIsMutable = true; 705 } 706 origPath.transform(*prePathMatrix, pathPtr); 707 } else { 708 if (!matrix.preConcat(*prePathMatrix)) { 709 return; 710 } 711 } 712 } 713 714 if (paint.getPathEffect()) { 715 if (d.fClip->isEmpty()) { 716 return; 717 } 718 if (!pathIsMutable) { 719 pathPtr = &modifiedPath; 720 pathIsMutable = true; 721 } 722 bool fill = paint.getFillPath(origPath, pathPtr); 723 724 SkPaint noEffectPaint(paint); 725 noEffectPaint.setPathEffect(NULL); 726 if (fill) { 727 noEffectPaint.setStyle(SkPaint::kFill_Style); 728 } else { 729 noEffectPaint.setStyle(SkPaint::kStroke_Style); 730 noEffectPaint.setStrokeWidth(0); 731 } 732 drawPath(d, *pathPtr, noEffectPaint, NULL, true); 733 return; 734 } 735 736 ScopedContentEntry content(this, d, paint); 737 if (!content.entry()) { 738 return; 739 } 740 SkPDFUtils::EmitPath(*pathPtr, &content.entry()->fContent); 741 SkPDFUtils::PaintPath(paint.getStyle(), pathPtr->getFillType(), 742 &content.entry()->fContent); 743} 744 745void SkPDFDevice::drawBitmap(const SkDraw& d, const SkBitmap& bitmap, 746 const SkIRect* srcRect, const SkMatrix& matrix, 747 const SkPaint& paint) { 748 if (d.fClip->isEmpty()) { 749 return; 750 } 751 752 SkMatrix transform = matrix; 753 transform.postConcat(*d.fMatrix); 754 internalDrawBitmap(transform, d.fClipStack, *d.fClip, bitmap, srcRect, 755 paint); 756} 757 758void SkPDFDevice::drawSprite(const SkDraw& d, const SkBitmap& bitmap, 759 int x, int y, const SkPaint& paint) { 760 if (d.fClip->isEmpty()) { 761 return; 762 } 763 764 SkMatrix matrix; 765 matrix.setTranslate(SkIntToScalar(x), SkIntToScalar(y)); 766 internalDrawBitmap(matrix, d.fClipStack, *d.fClip, bitmap, NULL, paint); 767} 768 769void SkPDFDevice::drawText(const SkDraw& d, const void* text, size_t len, 770 SkScalar x, SkScalar y, const SkPaint& paint) { 771 SkPaint textPaint = calculate_text_paint(paint); 772 ScopedContentEntry content(this, d, textPaint, true); 773 if (!content.entry()) { 774 return; 775 } 776 777 // We want the text in glyph id encoding and a writable buffer, so we end 778 // up making a copy either way. 779 size_t numGlyphs = paint.textToGlyphs(text, len, NULL); 780 uint16_t* glyphIDs = 781 (uint16_t*)sk_malloc_flags(numGlyphs * 2, 782 SK_MALLOC_TEMP | SK_MALLOC_THROW); 783 SkAutoFree autoFreeGlyphIDs(glyphIDs); 784 if (paint.getTextEncoding() != SkPaint::kGlyphID_TextEncoding) { 785 paint.textToGlyphs(text, len, glyphIDs); 786 textPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); 787 } else { 788 SkASSERT((len & 1) == 0); 789 SkASSERT(len / 2 == numGlyphs); 790 memcpy(glyphIDs, text, len); 791 } 792 793 SkScalar width; 794 SkScalar* widthPtr = NULL; 795 if (textPaint.isUnderlineText() || textPaint.isStrikeThruText()) 796 widthPtr = &width; 797 798 SkDrawCacheProc glyphCacheProc = textPaint.getDrawCacheProc(); 799 align_text(glyphCacheProc, textPaint, glyphIDs, numGlyphs, &x, &y, 800 widthPtr); 801 content.entry()->fContent.writeText("BT\n"); 802 set_text_transform(x, y, textPaint.getTextSkewX(), 803 &content.entry()->fContent); 804 size_t consumedGlyphCount = 0; 805 while (numGlyphs > consumedGlyphCount) { 806 updateFont(textPaint, glyphIDs[consumedGlyphCount], content.entry()); 807 SkPDFFont* font = content.entry()->fState.fFont; 808 size_t availableGlyphs = 809 font->glyphsToPDFFontEncoding(glyphIDs + consumedGlyphCount, 810 numGlyphs - consumedGlyphCount); 811 SkString encodedString = 812 SkPDFString::formatString(glyphIDs + consumedGlyphCount, 813 availableGlyphs, font->multiByteGlyphs()); 814 content.entry()->fContent.writeText(encodedString.c_str()); 815 consumedGlyphCount += availableGlyphs; 816 content.entry()->fContent.writeText(" Tj\n"); 817 } 818 content.entry()->fContent.writeText("ET\n"); 819 820 // Draw underline and/or strikethrough if the paint has them. 821 // drawPosText() and drawTextOnPath() don't draw underline or strikethrough 822 // because the raster versions don't. Use paint instead of textPaint 823 // because we may have changed strokeWidth to do fakeBold text. 824 if (paint.isUnderlineText() || paint.isStrikeThruText()) { 825 SkScalar textSize = paint.getTextSize(); 826 SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness); 827 828 if (paint.isUnderlineText()) { 829 SkScalar top = SkScalarMulAdd(textSize, kStdUnderline_Offset, y); 830 SkRect r = SkRect::MakeXYWH(x, top - height, width, height); 831 drawRect(d, r, paint); 832 } 833 if (paint.isStrikeThruText()) { 834 SkScalar top = SkScalarMulAdd(textSize, kStdStrikeThru_Offset, y); 835 SkRect r = SkRect::MakeXYWH(x, top - height, width, height); 836 drawRect(d, r, paint); 837 } 838 } 839} 840 841void SkPDFDevice::drawPosText(const SkDraw& d, const void* text, size_t len, 842 const SkScalar pos[], SkScalar constY, 843 int scalarsPerPos, const SkPaint& paint) { 844 SkASSERT(1 == scalarsPerPos || 2 == scalarsPerPos); 845 SkPaint textPaint = calculate_text_paint(paint); 846 ScopedContentEntry content(this, d, textPaint, true); 847 if (!content.entry()) { 848 return; 849 } 850 851 // Make sure we have a glyph id encoding. 852 SkAutoFree glyphStorage; 853 uint16_t* glyphIDs; 854 size_t numGlyphs; 855 if (paint.getTextEncoding() != SkPaint::kGlyphID_TextEncoding) { 856 numGlyphs = paint.textToGlyphs(text, len, NULL); 857 glyphIDs = (uint16_t*)sk_malloc_flags(numGlyphs * 2, 858 SK_MALLOC_TEMP | SK_MALLOC_THROW); 859 glyphStorage.set(glyphIDs); 860 paint.textToGlyphs(text, len, glyphIDs); 861 textPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); 862 } else { 863 SkASSERT((len & 1) == 0); 864 numGlyphs = len / 2; 865 glyphIDs = (uint16_t*)text; 866 } 867 868 SkDrawCacheProc glyphCacheProc = textPaint.getDrawCacheProc(); 869 content.entry()->fContent.writeText("BT\n"); 870 updateFont(textPaint, glyphIDs[0], content.entry()); 871 for (size_t i = 0; i < numGlyphs; i++) { 872 SkPDFFont* font = content.entry()->fState.fFont; 873 uint16_t encodedValue = glyphIDs[i]; 874 if (font->glyphsToPDFFontEncoding(&encodedValue, 1) != 1) { 875 updateFont(textPaint, glyphIDs[i], content.entry()); 876 i--; 877 continue; 878 } 879 SkScalar x = pos[i * scalarsPerPos]; 880 SkScalar y = scalarsPerPos == 1 ? constY : pos[i * scalarsPerPos + 1]; 881 align_text(glyphCacheProc, textPaint, glyphIDs + i, 1, &x, &y, NULL); 882 set_text_transform(x, y, textPaint.getTextSkewX(), 883 &content.entry()->fContent); 884 SkString encodedString = 885 SkPDFString::formatString(&encodedValue, 1, 886 font->multiByteGlyphs()); 887 content.entry()->fContent.writeText(encodedString.c_str()); 888 content.entry()->fContent.writeText(" Tj\n"); 889 } 890 content.entry()->fContent.writeText("ET\n"); 891} 892 893void SkPDFDevice::drawTextOnPath(const SkDraw& d, const void* text, size_t len, 894 const SkPath& path, const SkMatrix* matrix, 895 const SkPaint& paint) { 896 if (d.fClip->isEmpty()) { 897 return; 898 } 899 NOT_IMPLEMENTED("drawTextOnPath", true); 900} 901 902void SkPDFDevice::drawVertices(const SkDraw& d, SkCanvas::VertexMode, 903 int vertexCount, const SkPoint verts[], 904 const SkPoint texs[], const SkColor colors[], 905 SkXfermode* xmode, const uint16_t indices[], 906 int indexCount, const SkPaint& paint) { 907 if (d.fClip->isEmpty()) { 908 return; 909 } 910 NOT_IMPLEMENTED("drawVerticies", true); 911} 912 913void SkPDFDevice::drawDevice(const SkDraw& d, SkDevice* device, int x, int y, 914 const SkPaint& paint) { 915 if ((device->getDeviceCapabilities() & kVector_Capability) == 0) { 916 // If we somehow get a raster device, do what our parent would do. 917 SkDevice::drawDevice(d, device, x, y, paint); 918 return; 919 } 920 921 // Assume that a vector capable device means that it's a PDF Device. 922 SkPDFDevice* pdfDevice = static_cast<SkPDFDevice*>(device); 923 if (pdfDevice->isContentEmpty()) { 924 return; 925 } 926 927 SkMatrix matrix; 928 matrix.setTranslate(SkIntToScalar(x), SkIntToScalar(y)); 929 ScopedContentEntry content(this, d.fClipStack, *d.fClip, matrix, paint); 930 if (!content.entry()) { 931 return; 932 } 933 934 SkPDFFormXObject* xobject = new SkPDFFormXObject(pdfDevice); 935 fXObjectResources.push(xobject); // Transfer reference. 936 SkPDFUtils::DrawFormXObject(fXObjectResources.count() - 1, 937 &content.entry()->fContent); 938} 939 940const SkRefPtr<SkPDFDict>& SkPDFDevice::getResourceDict() { 941 if (fResourceDict.get() == NULL) { 942 fResourceDict = new SkPDFDict; 943 fResourceDict->unref(); // SkRefPtr and new both took a reference. 944 945 if (fGraphicStateResources.count()) { 946 SkRefPtr<SkPDFDict> extGState = new SkPDFDict(); 947 extGState->unref(); // SkRefPtr and new both took a reference. 948 for (int i = 0; i < fGraphicStateResources.count(); i++) { 949 SkString nameString("G"); 950 nameString.appendS32(i); 951 extGState->insert( 952 nameString.c_str(), 953 new SkPDFObjRef(fGraphicStateResources[i]))->unref(); 954 } 955 fResourceDict->insert("ExtGState", extGState.get()); 956 } 957 958 if (fXObjectResources.count()) { 959 SkRefPtr<SkPDFDict> xObjects = new SkPDFDict(); 960 xObjects->unref(); // SkRefPtr and new both took a reference. 961 for (int i = 0; i < fXObjectResources.count(); i++) { 962 SkString nameString("X"); 963 nameString.appendS32(i); 964 xObjects->insert( 965 nameString.c_str(), 966 new SkPDFObjRef(fXObjectResources[i]))->unref(); 967 } 968 fResourceDict->insert("XObject", xObjects.get()); 969 } 970 971 if (fFontResources.count()) { 972 SkRefPtr<SkPDFDict> fonts = new SkPDFDict(); 973 fonts->unref(); // SkRefPtr and new both took a reference. 974 for (int i = 0; i < fFontResources.count(); i++) { 975 SkString nameString("F"); 976 nameString.appendS32(i); 977 fonts->insert(nameString.c_str(), 978 new SkPDFObjRef(fFontResources[i]))->unref(); 979 } 980 fResourceDict->insert("Font", fonts.get()); 981 } 982 983 if (fShaderResources.count()) { 984 SkRefPtr<SkPDFDict> patterns = new SkPDFDict(); 985 patterns->unref(); // SkRefPtr and new both took a reference. 986 for (int i = 0; i < fShaderResources.count(); i++) { 987 SkString nameString("P"); 988 nameString.appendS32(i); 989 patterns->insert(nameString.c_str(), 990 new SkPDFObjRef(fShaderResources[i]))->unref(); 991 } 992 fResourceDict->insert("Pattern", patterns.get()); 993 } 994 995 // For compatibility, add all proc sets (only used for output to PS 996 // devices). 997 const char procs[][7] = {"PDF", "Text", "ImageB", "ImageC", "ImageI"}; 998 SkRefPtr<SkPDFArray> procSets = new SkPDFArray(); 999 procSets->unref(); // SkRefPtr and new both took a reference. 1000 procSets->reserve(SK_ARRAY_COUNT(procs)); 1001 for (size_t i = 0; i < SK_ARRAY_COUNT(procs); i++) 1002 procSets->append(new SkPDFName(procs[i]))->unref(); 1003 fResourceDict->insert("ProcSet", procSets.get()); 1004 } 1005 return fResourceDict; 1006} 1007 1008void SkPDFDevice::getResources(SkTDArray<SkPDFObject*>* resourceList) const { 1009 resourceList->setReserve(resourceList->count() + 1010 fGraphicStateResources.count() + 1011 fXObjectResources.count() + 1012 fFontResources.count() + 1013 fShaderResources.count()); 1014 for (int i = 0; i < fGraphicStateResources.count(); i++) { 1015 resourceList->push(fGraphicStateResources[i]); 1016 fGraphicStateResources[i]->ref(); 1017 fGraphicStateResources[i]->getResources(resourceList); 1018 } 1019 for (int i = 0; i < fXObjectResources.count(); i++) { 1020 resourceList->push(fXObjectResources[i]); 1021 fXObjectResources[i]->ref(); 1022 fXObjectResources[i]->getResources(resourceList); 1023 } 1024 for (int i = 0; i < fFontResources.count(); i++) { 1025 resourceList->push(fFontResources[i]); 1026 fFontResources[i]->ref(); 1027 fFontResources[i]->getResources(resourceList); 1028 } 1029 for (int i = 0; i < fShaderResources.count(); i++) { 1030 resourceList->push(fShaderResources[i]); 1031 fShaderResources[i]->ref(); 1032 fShaderResources[i]->getResources(resourceList); 1033 } 1034} 1035 1036SkRefPtr<SkPDFArray> SkPDFDevice::getMediaBox() const { 1037 SkRefPtr<SkPDFInt> zero = new SkPDFInt(0); 1038 zero->unref(); // SkRefPtr and new both took a reference. 1039 1040 SkRefPtr<SkPDFArray> mediaBox = new SkPDFArray(); 1041 mediaBox->unref(); // SkRefPtr and new both took a reference. 1042 mediaBox->reserve(4); 1043 mediaBox->append(zero.get()); 1044 mediaBox->append(zero.get()); 1045 mediaBox->append(new SkPDFInt(fPageSize.fWidth))->unref(); 1046 mediaBox->append(new SkPDFInt(fPageSize.fHeight))->unref(); 1047 return mediaBox; 1048} 1049 1050SkStream* SkPDFDevice::content() const { 1051 SkDynamicMemoryWStream data; 1052 if (fInitialTransform.getType() != SkMatrix::kIdentity_Mask) { 1053 SkPDFUtils::AppendTransform(fInitialTransform, &data); 1054 } 1055 // If the content area is the entire page, then we don't need to clip 1056 // the content area (PDF area clips to the page size). Otherwise, 1057 // we have to clip to the content area; we've already applied the 1058 // initial transform, so just clip to the device size. 1059 if (fPageSize != fContentSize) { 1060 SkRect r = SkRect::MakeWH(this->width(), this->height()); 1061 emit_clip(NULL, &r, &data); 1062 } 1063 1064 GraphicStackState gsState(fExistingClipStack, fExistingClipRegion, &data); 1065 for (ContentEntry* entry = fContentEntries.get(); 1066 entry != NULL; 1067 entry = entry->fNext.get()) { 1068 SkIPoint translation = this->getOrigin(); 1069 translation.negate(); 1070 gsState.updateClip(entry->fState.fClipStack, entry->fState.fClipRegion, 1071 translation); 1072 gsState.updateMatrix(entry->fState.fMatrix); 1073 gsState.updateDrawingState(entry->fState); 1074 data.write(entry->fContent.getStream(), entry->fContent.getOffset()); 1075 } 1076 gsState.drainStack(); 1077 1078 SkMemoryStream* result = new SkMemoryStream; 1079 result->setMemoryOwned(data.detach(), data.getOffset()); 1080 return result; 1081} 1082 1083void SkPDFDevice::createFormXObjectFromDevice( 1084 SkRefPtr<SkPDFFormXObject>* xobject) { 1085 *xobject = new SkPDFFormXObject(this); 1086 (*xobject)->unref(); // SkRefPtr and new both took a reference. 1087 cleanUp(); // Reset this device to have no content. 1088 init(); 1089} 1090 1091void SkPDFDevice::clearClipFromContent(const SkClipStack* clipStack, 1092 const SkRegion& clipRegion) { 1093 if (clipRegion.isEmpty() || isContentEmpty()) { 1094 return; 1095 } 1096 SkRefPtr<SkPDFFormXObject> curContent; 1097 createFormXObjectFromDevice(&curContent); 1098 1099 // Redraw what we already had, but with the clip as a mask. 1100 drawFormXObjectWithClip(curContent.get(), clipStack, clipRegion, true); 1101} 1102 1103void SkPDFDevice::drawFormXObjectWithClip(SkPDFFormXObject* xobject, 1104 const SkClipStack* clipStack, 1105 const SkRegion& clipRegion, 1106 bool invertClip) { 1107 if (clipRegion.isEmpty() && !invertClip) { 1108 return; 1109 } 1110 1111 // Create the mask. 1112 SkMatrix identity; 1113 identity.reset(); 1114 SkDraw draw; 1115 draw.fMatrix = &identity; 1116 draw.fClip = &clipRegion; 1117 draw.fClipStack = clipStack; 1118 SkPaint stockPaint; 1119 this->drawPaint(draw, stockPaint); 1120 SkRefPtr<SkPDFFormXObject> maskFormXObject; 1121 createFormXObjectFromDevice(&maskFormXObject); 1122 SkRefPtr<SkPDFGraphicState> sMaskGS = 1123 SkPDFGraphicState::getSMaskGraphicState(maskFormXObject.get(), 1124 invertClip); 1125 sMaskGS->unref(); // SkRefPtr and getSMaskGraphicState both took a ref. 1126 1127 // Draw the xobject with the clip as a mask. 1128 ScopedContentEntry content(this, &fExistingClipStack, fExistingClipRegion, 1129 identity, stockPaint); 1130 if (!content.entry()) { 1131 return; 1132 } 1133 SkPDFUtils::ApplyGraphicState(addGraphicStateResource(sMaskGS.get()), 1134 &content.entry()->fContent); 1135 SkPDFUtils::DrawFormXObject(fXObjectResources.count(), 1136 &content.entry()->fContent); 1137 fXObjectResources.push(xobject); 1138 xobject->ref(); 1139 1140 sMaskGS = SkPDFGraphicState::getNoSMaskGraphicState(); 1141 sMaskGS->unref(); // SkRefPtr and getSMaskGraphicState both took a ref. 1142 SkPDFUtils::ApplyGraphicState(addGraphicStateResource(sMaskGS.get()), 1143 &content.entry()->fContent); 1144} 1145 1146ContentEntry* SkPDFDevice::setUpContentEntry(const SkClipStack* clipStack, 1147 const SkRegion& clipRegion, 1148 const SkMatrix& matrix, 1149 const SkPaint& paint, 1150 bool hasText, 1151 SkRefPtr<SkPDFFormXObject>* dst) { 1152 if (clipRegion.isEmpty()) { 1153 return NULL; 1154 } 1155 1156 // The clip stack can come from an SkDraw where it is technically optional. 1157 SkClipStack synthesizedClipStack; 1158 if (clipStack == NULL) { 1159 if (clipRegion == fExistingClipRegion) { 1160 clipStack = &fExistingClipStack; 1161 } else { 1162 // GraphicStackState::updateClip expects the clip stack to have 1163 // fExistingClip as a prefix, so start there, then set the clip 1164 // to the passed region. 1165 synthesizedClipStack = fExistingClipStack; 1166 SkPath clipPath; 1167 clipRegion.getBoundaryPath(&clipPath); 1168 synthesizedClipStack.clipDevPath(clipPath, SkRegion::kReplace_Op); 1169 clipStack = &synthesizedClipStack; 1170 } 1171 } 1172 1173 SkXfermode::Mode xfermode = SkXfermode::kSrcOver_Mode; 1174 if (paint.getXfermode()) { 1175 paint.getXfermode()->asMode(&xfermode); 1176 } 1177 1178 if (xfermode == SkXfermode::kClear_Mode || 1179 xfermode == SkXfermode::kSrc_Mode) { 1180 this->clearClipFromContent(clipStack, clipRegion); 1181 } else if (xfermode == SkXfermode::kSrcIn_Mode || 1182 xfermode == SkXfermode::kDstIn_Mode || 1183 xfermode == SkXfermode::kSrcOut_Mode || 1184 xfermode == SkXfermode::kDstOut_Mode) { 1185 // For the following modes, we use both source and destination, but 1186 // we use one as a smask for the other, so we have to make form xobjects 1187 // out of both of them: SrcIn, DstIn, SrcOut, DstOut. 1188 if (isContentEmpty()) { 1189 return NULL; 1190 } else { 1191 createFormXObjectFromDevice(dst); 1192 } 1193 } 1194 // TODO(vandebo) Figure out how/if we can handle the following modes: 1195 // SrcAtop, DestAtop, Xor, Plus. 1196 1197 // These xfer modes don't draw source at all. 1198 if (xfermode == SkXfermode::kClear_Mode || 1199 xfermode == SkXfermode::kDst_Mode) { 1200 return NULL; 1201 } 1202 1203 ContentEntry* entry; 1204 SkTScopedPtr<ContentEntry> newEntry; 1205 if (fLastContentEntry && fLastContentEntry->fContent.getOffset() == 0) { 1206 entry = fLastContentEntry; 1207 } else { 1208 newEntry.reset(new ContentEntry); 1209 entry = newEntry.get(); 1210 } 1211 1212 populateGraphicStateEntryFromPaint(matrix, *clipStack, clipRegion, paint, 1213 hasText, &entry->fState); 1214 if (fLastContentEntry && xfermode != SkXfermode::kDstOver_Mode && 1215 entry->fState.compareInitialState(fLastContentEntry->fState)) { 1216 return fLastContentEntry; 1217 } 1218 1219 if (!fLastContentEntry) { 1220 fContentEntries.reset(entry); 1221 fLastContentEntry = entry; 1222 } else if (xfermode == SkXfermode::kDstOver_Mode) { 1223 entry->fNext.reset(fContentEntries.release()); 1224 fContentEntries.reset(entry); 1225 } else { 1226 fLastContentEntry->fNext.reset(entry); 1227 fLastContentEntry = entry; 1228 } 1229 newEntry.release(); 1230 return entry; 1231} 1232 1233void SkPDFDevice::finishContentEntry(const SkXfermode::Mode xfermode, 1234 SkPDFFormXObject* dst) { 1235 if (xfermode != SkXfermode::kSrcIn_Mode && 1236 xfermode != SkXfermode::kDstIn_Mode && 1237 xfermode != SkXfermode::kSrcOut_Mode && 1238 xfermode != SkXfermode::kDstOut_Mode) { 1239 SkASSERT(!dst); 1240 return; 1241 } 1242 SkASSERT(dst); 1243 SkASSERT(!fContentEntries->fNext.get()); 1244 1245 // We have to make a copy of these here because changing the current 1246 // content into a form xobject will destroy them. 1247 SkClipStack clipStack = fContentEntries->fState.fClipStack; 1248 SkRegion clipRegion = fContentEntries->fState.fClipRegion; 1249 1250 SkRefPtr<SkPDFFormXObject> srcFormXObject; 1251 if (!isContentEmpty()) { 1252 createFormXObjectFromDevice(&srcFormXObject); 1253 } 1254 1255 drawFormXObjectWithClip(dst, &clipStack, clipRegion, true); 1256 1257 // We've redrawn dst minus the clip area, if there's no src, we're done. 1258 if (!srcFormXObject.get()) { 1259 return; 1260 } 1261 1262 SkMatrix identity; 1263 identity.reset(); 1264 SkPaint stockPaint; 1265 ScopedContentEntry inClipContentEntry(this, &fExistingClipStack, 1266 fExistingClipRegion, identity, 1267 stockPaint); 1268 if (!inClipContentEntry.entry()) { 1269 return; 1270 } 1271 1272 SkRefPtr<SkPDFGraphicState> sMaskGS; 1273 if (xfermode == SkXfermode::kSrcIn_Mode || 1274 xfermode == SkXfermode::kSrcOut_Mode) { 1275 sMaskGS = SkPDFGraphicState::getSMaskGraphicState( 1276 dst, xfermode == SkXfermode::kSrcOut_Mode); 1277 fXObjectResources.push(srcFormXObject.get()); 1278 srcFormXObject->ref(); 1279 } else { 1280 sMaskGS = SkPDFGraphicState::getSMaskGraphicState( 1281 srcFormXObject.get(), xfermode == SkXfermode::kDstOut_Mode); 1282 // dst already added to fXObjectResources in drawFormXObjectWithClip. 1283 } 1284 sMaskGS->unref(); // SkRefPtr and getSMaskGraphicState both took a ref. 1285 SkPDFUtils::ApplyGraphicState(addGraphicStateResource(sMaskGS.get()), 1286 &inClipContentEntry.entry()->fContent); 1287 1288 SkPDFUtils::DrawFormXObject(fXObjectResources.count() - 1, 1289 &inClipContentEntry.entry()->fContent); 1290 1291 sMaskGS = SkPDFGraphicState::getNoSMaskGraphicState(); 1292 sMaskGS->unref(); // SkRefPtr and getSMaskGraphicState both took a ref. 1293 SkPDFUtils::ApplyGraphicState(addGraphicStateResource(sMaskGS.get()), 1294 &inClipContentEntry.entry()->fContent); 1295} 1296 1297bool SkPDFDevice::isContentEmpty() { 1298 if (!fContentEntries.get() || fContentEntries->fContent.getOffset() == 0) { 1299 SkASSERT(!fContentEntries.get() || !fContentEntries->fNext.get()); 1300 return true; 1301 } 1302 return false; 1303} 1304 1305 1306void SkPDFDevice::populateGraphicStateEntryFromPaint( 1307 const SkMatrix& matrix, 1308 const SkClipStack& clipStack, 1309 const SkRegion& clipRegion, 1310 const SkPaint& paint, 1311 bool hasText, 1312 GraphicStateEntry* entry) { 1313 SkASSERT(paint.getPathEffect() == NULL); 1314 1315 NOT_IMPLEMENTED(paint.getMaskFilter() != NULL, false); 1316 NOT_IMPLEMENTED(paint.getColorFilter() != NULL, false); 1317 1318 entry->fMatrix = matrix; 1319 entry->fClipStack = clipStack; 1320 entry->fClipRegion = clipRegion; 1321 1322 // PDF treats a shader as a color, so we only set one or the other. 1323 SkRefPtr<SkPDFShader> pdfShader; 1324 const SkShader* shader = paint.getShader(); 1325 SkColor color = paint.getColor(); 1326 if (shader) { 1327 // PDF positions patterns relative to the initial transform, so 1328 // we need to apply the current transform to the shader parameters. 1329 SkMatrix transform = matrix; 1330 transform.postConcat(fInitialTransform); 1331 1332 // PDF doesn't support kClamp_TileMode, so we simulate it by making 1333 // a pattern the size of the current clip. 1334 SkIRect bounds = clipRegion.getBounds(); 1335 pdfShader = SkPDFShader::getPDFShader(*shader, transform, bounds); 1336 SkSafeUnref(pdfShader.get()); // getShader and SkRefPtr both took a ref 1337 1338 // A color shader is treated as an invalid shader so we don't have 1339 // to set a shader just for a color. 1340 if (pdfShader.get() == NULL) { 1341 entry->fColor = 0; 1342 color = 0; 1343 1344 // Check for a color shader. 1345 SkShader::GradientInfo gradientInfo; 1346 SkColor gradientColor; 1347 gradientInfo.fColors = &gradientColor; 1348 gradientInfo.fColorOffsets = NULL; 1349 gradientInfo.fColorCount = 1; 1350 if (shader->asAGradient(&gradientInfo) == 1351 SkShader::kColor_GradientType) { 1352 entry->fColor = SkColorSetA(gradientColor, 0xFF); 1353 color = gradientColor; 1354 } 1355 } 1356 } 1357 1358 if (pdfShader) { 1359 // pdfShader has been canonicalized so we can directly compare 1360 // pointers. 1361 int resourceIndex = fShaderResources.find(pdfShader.get()); 1362 if (resourceIndex < 0) { 1363 resourceIndex = fShaderResources.count(); 1364 fShaderResources.push(pdfShader.get()); 1365 pdfShader->ref(); 1366 } 1367 entry->fShaderIndex = resourceIndex; 1368 } else { 1369 entry->fShaderIndex = -1; 1370 entry->fColor = SkColorSetA(paint.getColor(), 0xFF); 1371 color = paint.getColor(); 1372 } 1373 1374 SkRefPtr<SkPDFGraphicState> newGraphicState; 1375 if (color == paint.getColor()) { 1376 newGraphicState = SkPDFGraphicState::getGraphicStateForPaint(paint); 1377 } else { 1378 SkPaint newPaint = paint; 1379 newPaint.setColor(color); 1380 newGraphicState = SkPDFGraphicState::getGraphicStateForPaint(newPaint); 1381 } 1382 newGraphicState->unref(); // getGraphicState and SkRefPtr both took a ref. 1383 int resourceIndex = addGraphicStateResource(newGraphicState.get()); 1384 entry->fGraphicStateIndex = resourceIndex; 1385 1386 if (hasText) { 1387 entry->fTextScaleX = paint.getTextScaleX(); 1388 entry->fTextFill = paint.getStyle(); 1389 } else { 1390 entry->fTextScaleX = 0; 1391 } 1392} 1393 1394int SkPDFDevice::addGraphicStateResource(SkPDFGraphicState* gs) { 1395 // Assumes that gs has been canonicalized (so we can directly compare 1396 // pointers). 1397 int result = fGraphicStateResources.find(gs); 1398 if (result < 0) { 1399 result = fGraphicStateResources.count(); 1400 fGraphicStateResources.push(gs); 1401 gs->ref(); 1402 } 1403 return result; 1404} 1405 1406void SkPDFDevice::updateFont(const SkPaint& paint, uint16_t glyphID, 1407 ContentEntry* contentEntry) { 1408 SkTypeface* typeface = paint.getTypeface(); 1409 if (contentEntry->fState.fFont == NULL || 1410 contentEntry->fState.fTextSize != paint.getTextSize() || 1411 !contentEntry->fState.fFont->hasGlyph(glyphID)) { 1412 int fontIndex = getFontResourceIndex(typeface, glyphID); 1413 contentEntry->fContent.writeText("/F"); 1414 contentEntry->fContent.writeDecAsText(fontIndex); 1415 contentEntry->fContent.writeText(" "); 1416 SkPDFScalar::Append(paint.getTextSize(), &contentEntry->fContent); 1417 contentEntry->fContent.writeText(" Tf\n"); 1418 contentEntry->fState.fFont = fFontResources[fontIndex]; 1419 } 1420} 1421 1422int SkPDFDevice::getFontResourceIndex(SkTypeface* typeface, uint16_t glyphID) { 1423 SkRefPtr<SkPDFFont> newFont = SkPDFFont::getFontResource(typeface, glyphID); 1424 newFont->unref(); // getFontResource and SkRefPtr both took a ref. 1425 int resourceIndex = fFontResources.find(newFont.get()); 1426 if (resourceIndex < 0) { 1427 resourceIndex = fFontResources.count(); 1428 fFontResources.push(newFont.get()); 1429 newFont->ref(); 1430 } 1431 return resourceIndex; 1432} 1433 1434void SkPDFDevice::internalDrawBitmap(const SkMatrix& matrix, 1435 const SkClipStack* clipStack, 1436 const SkRegion& clipRegion, 1437 const SkBitmap& bitmap, 1438 const SkIRect* srcRect, 1439 const SkPaint& paint) { 1440 SkMatrix scaled; 1441 // Adjust for origin flip. 1442 scaled.setScale(1, -1); 1443 scaled.postTranslate(0, 1); 1444 // Scale the image up from 1x1 to WxH. 1445 SkIRect subset = SkIRect::MakeWH(bitmap.width(), bitmap.height()); 1446 scaled.postScale(SkIntToScalar(subset.width()), 1447 SkIntToScalar(subset.height())); 1448 scaled.postConcat(matrix); 1449 ScopedContentEntry content(this, clipStack, clipRegion, scaled, paint); 1450 if (!content.entry()) { 1451 return; 1452 } 1453 1454 if (srcRect && !subset.intersect(*srcRect)) { 1455 return; 1456 } 1457 1458 SkPDFImage* image = SkPDFImage::CreateImage(bitmap, subset, paint); 1459 if (!image) { 1460 return; 1461 } 1462 1463 fXObjectResources.push(image); // Transfer reference. 1464 SkPDFUtils::DrawFormXObject(fXObjectResources.count() - 1, 1465 &content.entry()->fContent); 1466} 1467