1/*
2 * Copyright 2015 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7#ifndef SkPDFCanon_DEFINED
8#define SkPDFCanon_DEFINED
9
10#include "SkPDFGraphicState.h"
11#include "SkPDFShader.h"
12#include "SkPixelSerializer.h"
13#include "SkTDArray.h"
14#include "SkTHash.h"
15#include "SkBitmapKey.h"
16
17class SkAdvancedTypefaceMetrics;
18class SkPDFFont;
19
20/**
21 *  The SkPDFCanon canonicalizes objects across PDF pages
22 *  (SkPDFDevices) and across draw calls.
23 *
24 *  The PDF backend works correctly if:
25 *  -  There is no more than one SkPDFCanon for each thread.
26 *  -  Every SkPDFDevice is given a pointer to a SkPDFCanon on creation.
27 *  -  All SkPDFDevices in a document share the same SkPDFCanon.
28 *  The SkPDFDocument class makes this happen by owning a single
29 *  SkPDFCanon.
30 *
31 *  The addFoo() methods will ref the Foo; the canon's destructor will
32 *  call foo->unref() on all of these objects.
33 *
34 *  The findFoo() methods do not change the ref count of the Foo
35 *  objects.
36 */
37class SkPDFCanon : SkNoncopyable {
38public:
39    ~SkPDFCanon();
40
41    // reset to original setting, unrefs all objects.
42    void reset();
43
44    sk_sp<SkPDFObject> findFunctionShader(const SkPDFShader::State&) const;
45    void addFunctionShader(sk_sp<SkPDFObject>, SkPDFShader::State);
46
47    sk_sp<SkPDFObject> findAlphaShader(const SkPDFShader::State&) const;
48    void addAlphaShader(sk_sp<SkPDFObject>, SkPDFShader::State);
49
50    sk_sp<SkPDFObject> findImageShader(const SkPDFShader::State&) const;
51    void addImageShader(sk_sp<SkPDFObject>, SkPDFShader::State);
52
53    const SkPDFGraphicState* findGraphicState(const SkPDFGraphicState&) const;
54    void addGraphicState(const SkPDFGraphicState*);
55
56    sk_sp<SkPDFObject> findPDFBitmap(SkBitmapKey key) const;
57    void addPDFBitmap(SkBitmapKey key, sk_sp<SkPDFObject>);
58
59    SkTHashMap<uint32_t, SkAdvancedTypefaceMetrics*> fTypefaceMetrics;
60    SkTHashMap<uint32_t, SkPDFDict*> fFontDescriptors;
61    SkTHashMap<uint64_t, SkPDFFont*> fFontMap;
62
63    SkPixelSerializer* getPixelSerializer() const { return fPixelSerializer.get(); }
64    void setPixelSerializer(sk_sp<SkPixelSerializer> ps) {
65        fPixelSerializer = std::move(ps);
66    }
67
68    sk_sp<SkPDFStream> makeInvertFunction();
69    sk_sp<SkPDFDict> makeNoSmaskGraphicState();
70    sk_sp<SkPDFArray> makeRangeObject();
71
72private:
73    struct ShaderRec {
74        SkPDFShader::State fShaderState;
75        sk_sp<SkPDFObject> fShaderObject;
76        ShaderRec(SkPDFShader::State s, sk_sp<SkPDFObject> o)
77            : fShaderState(std::move(s)), fShaderObject(std::move(o)) {}
78    };
79    SkTArray<ShaderRec> fFunctionShaderRecords;
80    SkTArray<ShaderRec> fAlphaShaderRecords;
81    SkTArray<ShaderRec> fImageShaderRecords;
82
83    struct WrapGS {
84        explicit WrapGS(const SkPDFGraphicState* ptr = nullptr) : fPtr(ptr) {}
85        const SkPDFGraphicState* fPtr;
86        bool operator==(const WrapGS& rhs) const {
87            SkASSERT(fPtr);
88            SkASSERT(rhs.fPtr);
89            return *fPtr == *rhs.fPtr;
90        }
91        struct Hash {
92            uint32_t operator()(const WrapGS& w) const {
93                SkASSERT(w.fPtr);
94                return w.fPtr->hash();
95            }
96        };
97    };
98    SkTHashSet<WrapGS, WrapGS::Hash> fGraphicStateRecords;
99
100    // TODO(halcanary): make SkTHashMap<K, sk_sp<V>> work correctly.
101    SkTHashMap<SkBitmapKey, SkPDFObject*> fPDFBitmapMap;
102
103    sk_sp<SkPixelSerializer> fPixelSerializer;
104    sk_sp<SkPDFStream> fInvertFunction;
105    sk_sp<SkPDFDict> fNoSmaskGraphicState;
106    sk_sp<SkPDFArray> fRangeObject;
107};
108#endif  // SkPDFCanon_DEFINED
109