SkPDFDevice.h revision e97f0856a8044866b12527819d14cdfbcdfd96f2
1/*
2 * Copyright (C) 2011 Google Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#ifndef SkPDFDevice_DEFINED
18#define SkPDFDevice_DEFINED
19
20#include "SkCanvas.h"
21#include "SkDevice.h"
22#include "SkPaint.h"
23#include "SkPath.h"
24#include "SkRefCnt.h"
25#include "SkStream.h"
26#include "SkTScopedPtr.h"
27
28class SkPDFArray;
29class SkPDFDevice;
30class SkPDFDict;
31class SkPDFFont;
32class SkPDFFormXObject;
33class SkPDFGraphicState;
34class SkPDFObject;
35class SkPDFShader;
36class SkPDFStream;
37
38// Private classes.
39struct ContentEntry;
40struct GraphicStateEntry;
41
42class SkPDFDeviceFactory : public SkDeviceFactory {
43public:
44    virtual SkDevice* newDevice(SkCanvas*, SkBitmap::Config, int width,
45                                int height, bool isOpaque, bool isForLayer);
46};
47
48/** \class SkPDFDevice
49
50    The drawing context for the PDF backend.
51*/
52class SkPDFDevice : public SkDevice {
53public:
54    /** Create a PDF drawing context with the given width and height.
55     *  72 points/in means letter paper is 612x792.
56     *  @param pageSize Page size in points.
57     *  @param contentSize The content size of the page in points. This will be
58     *         combined with the initial transform to determine the drawing area
59     *         (as reported by the width and height methods). Anything outside
60     *         of the drawing area will be clipped.
61     *  @param initialTransform The initial transform to apply to the page.
62     *         This may be useful to, for example, move the origin in and
63     *         over a bit to account for a margin, scale the canvas,
64     *         or apply a rotation.  Note1: the SkPDFDevice also applies
65     *         a scale+translate transform to move the origin from the
66     *         bottom left (PDF default) to the top left.  Note2: drawDevice
67     *         (used by layer restore) draws the device after this initial
68     *         transform is applied, so the PDF device factory does an
69     *         inverse scale+translate to accommodate the one that SkPDFDevice
70     *         always does.
71     */
72    // TODO(vandebo) The sizes should be SkSize and not SkISize.
73    SK_API SkPDFDevice(const SkISize& pageSize, const SkISize& contentSize,
74                       const SkMatrix& initialTransform);
75    SK_API virtual ~SkPDFDevice();
76
77    virtual uint32_t getDeviceCapabilities() { return kVector_Capability; }
78
79    virtual void clear(SkColor color);
80
81    virtual bool readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
82        return false;
83    }
84
85    /** These are called inside the per-device-layer loop for each draw call.
86     When these are called, we have already applied any saveLayer operations,
87     and are handling any looping from the paint, and any effects from the
88     DrawFilter.
89     */
90    virtual void drawPaint(const SkDraw&, const SkPaint& paint);
91    virtual void drawPoints(const SkDraw&, SkCanvas::PointMode mode,
92                            size_t count, const SkPoint[],
93                            const SkPaint& paint);
94    virtual void drawRect(const SkDraw&, const SkRect& r, const SkPaint& paint);
95    virtual void drawPath(const SkDraw&, const SkPath& origpath,
96                          const SkPaint& paint, const SkMatrix* prePathMatrix,
97                          bool pathIsMutable);
98    virtual void drawBitmap(const SkDraw&, const SkBitmap& bitmap,
99                            const SkIRect* srcRectOrNull,
100                            const SkMatrix& matrix, const SkPaint& paint);
101    virtual void drawSprite(const SkDraw&, const SkBitmap& bitmap, int x, int y,
102                            const SkPaint& paint);
103    virtual void drawText(const SkDraw&, const void* text, size_t len,
104                          SkScalar x, SkScalar y, const SkPaint& paint);
105    virtual void drawPosText(const SkDraw&, const void* text, size_t len,
106                             const SkScalar pos[], SkScalar constY,
107                             int scalarsPerPos, const SkPaint& paint);
108    virtual void drawTextOnPath(const SkDraw&, const void* text, size_t len,
109                                const SkPath& path, const SkMatrix* matrix,
110                                const SkPaint& paint);
111    virtual void drawVertices(const SkDraw&, SkCanvas::VertexMode,
112                              int vertexCount, const SkPoint verts[],
113                              const SkPoint texs[], const SkColor colors[],
114                              SkXfermode* xmode, const uint16_t indices[],
115                              int indexCount, const SkPaint& paint);
116    virtual void drawDevice(const SkDraw&, SkDevice*, int x, int y,
117                            const SkPaint&);
118
119    // PDF specific methods.
120
121    /** Returns a reference to the resource dictionary for this device.
122     */
123    SK_API const SkRefPtr<SkPDFDict>& getResourceDict();
124
125    /** Get the list of resources (PDF objects) used on this page.
126     *  @param resourceList A list to append the resources to.
127     */
128    SK_API void getResources(SkTDArray<SkPDFObject*>* resourceList) const;
129
130    /** Get the fonts used on this device.
131     */
132    SK_API const SkTDArray<SkPDFFont*>& getFontResources() const;
133
134    /** Returns the media box for this device.
135     */
136    SK_API SkRefPtr<SkPDFArray> getMediaBox() const;
137
138    /** Returns a SkStream with the page contents.  The caller is responsible
139        for a reference to the returned value.
140     */
141    SK_API SkStream* content() const;
142
143    SK_API const SkMatrix& initialTransform() const {
144        return fInitialTransform;
145    }
146
147protected:
148    // override
149    virtual SkDeviceFactory* onNewDeviceFactory();
150
151private:
152    friend class SkPDFDeviceFactory;
153    // TODO(vandebo) push most of SkPDFDevice's state into a core object in
154    // order to get the right access levels without using friend.
155    friend class ScopedContentEntry;
156
157    SkISize fPageSize;
158    SkISize fContentSize;
159    SkMatrix fInitialTransform;
160    SkClipStack fExistingClipStack;
161    SkRegion fExistingClipRegion;
162    SkRefPtr<SkPDFDict> fResourceDict;
163
164    SkTDArray<SkPDFGraphicState*> fGraphicStateResources;
165    SkTDArray<SkPDFObject*> fXObjectResources;
166    SkTDArray<SkPDFFont*> fFontResources;
167    SkTDArray<SkPDFShader*> fShaderResources;
168
169    SkTScopedPtr<ContentEntry> fContentEntries;
170    ContentEntry* fLastContentEntry;
171
172    // For use by the DeviceFactory.
173    SkPDFDevice(const SkISize& layerSize, const SkClipStack& existingClipStack,
174                const SkRegion& existingClipRegion);
175
176    // override from SkDevice
177    virtual SkDevice* onCreateCompatibleDevice(SkBitmap::Config config,
178                                               int width, int height,
179                                               bool isOpaque,
180                                               Usage usage);
181
182    void init();
183    void cleanUp();
184    void createFormXObjectFromDevice(SkRefPtr<SkPDFFormXObject>* xobject);
185
186    // Clear the passed clip from all existing content entries.
187    void clearClipFromContent(const SkClipStack* clipStack,
188                              const SkRegion& clipRegion);
189    void drawFormXObjectWithClip(SkPDFFormXObject* form,
190                                 const SkClipStack* clipStack,
191                                 const SkRegion& clipRegion,
192                                 bool invertClip);
193
194    // If the paint or clip is such that we shouldn't draw anything, this
195    // returns NULL and does not create a content entry.
196    // setUpContentEntry and finishContentEntry can be used directly, but
197    // the preferred method is to use the ScopedContentEntry helper class.
198    ContentEntry* setUpContentEntry(const SkClipStack* clipStack,
199                                    const SkRegion& clipRegion,
200                                    const SkMatrix& matrix,
201                                    const SkPaint& paint,
202                                    bool hasText,
203                                    SkRefPtr<SkPDFFormXObject>* dst);
204    void finishContentEntry(SkXfermode::Mode xfermode,
205                            SkPDFFormXObject* dst);
206    bool isContentEmpty();
207
208    void populateGraphicStateEntryFromPaint(const SkMatrix& matrix,
209                                            const SkClipStack& clipStack,
210                                            const SkRegion& clipRegion,
211                                            const SkPaint& paint,
212                                            bool hasText,
213                                            GraphicStateEntry* entry);
214    int addGraphicStateResource(SkPDFGraphicState* gs);
215
216    void updateFont(const SkPaint& paint, uint16_t glyphID,
217                    ContentEntry* contentEntry);
218    int getFontResourceIndex(SkTypeface* typeface, uint16_t glyphID);
219
220    void internalDrawPaint(const SkPaint& paint, ContentEntry* contentEntry);
221    void internalDrawBitmap(const SkMatrix& matrix,
222                            const SkClipStack* clipStack,
223                            const SkRegion& clipRegion,
224                            const SkBitmap& bitmap,
225                            const SkIRect* srcRect,
226                            const SkPaint& paint);
227
228    // Disable the default copy and assign implementation.
229    SkPDFDevice(const SkPDFDevice&);
230    void operator=(const SkPDFDevice&);
231};
232
233#endif
234