gfxSVGGlyphs.h (7619B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 #ifndef GFX_SVG_GLYPHS_WRAPPER_H 6 #define GFX_SVG_GLYPHS_WRAPPER_H 7 8 #include "gfxFontUtils.h" 9 #include "mozilla/gfx/2D.h" 10 #include "nsString.h" 11 #include "nsClassHashtable.h" 12 #include "nsBaseHashtable.h" 13 #include "nsHashKeys.h" 14 #include "gfxPattern.h" 15 #include "mozilla/gfx/UserData.h" 16 #include "mozilla/SVGContextPaint.h" 17 #include "nsRefreshObservers.h" 18 19 class nsIDocumentViewer; 20 class gfxSVGGlyphs; 21 22 namespace mozilla { 23 class PresShell; 24 class SVGContextPaint; 25 namespace dom { 26 class Document; 27 class Element; 28 } // namespace dom 29 } // namespace mozilla 30 31 /** 32 * Wraps an SVG document contained in the SVG table of an OpenType font. 33 * There may be multiple SVG documents in an SVG table which we lazily parse 34 * so we have an instance of this class for every document in the SVG table 35 * which contains a glyph ID which has been used 36 * Finds and looks up elements contained in the SVG document which have glyph 37 * mappings to be drawn by gfxSVGGlyphs 38 */ 39 class gfxSVGGlyphsDocument final : public nsAPostRefreshObserver { 40 typedef mozilla::dom::Element Element; 41 42 public: 43 gfxSVGGlyphsDocument(const uint8_t* aBuffer, uint32_t aBufLen, 44 gfxSVGGlyphs* aSVGGlyphs); 45 46 Element* GetGlyphElement(uint32_t aGlyphId); 47 48 ~gfxSVGGlyphsDocument(); 49 50 void DidRefresh() override; 51 52 size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; 53 54 private: 55 nsresult ParseDocument(const uint8_t* aBuffer, uint32_t aBufLen); 56 57 nsresult SetupPresentation(); 58 59 void FindGlyphElements(Element* aElement); 60 61 void InsertGlyphId(Element* aGlyphElement); 62 63 // Weak so as not to create a cycle. mOwner owns us so this can't dangle. 64 gfxSVGGlyphs* mOwner; 65 RefPtr<mozilla::dom::Document> mDocument; 66 nsCOMPtr<nsIDocumentViewer> mViewer; 67 RefPtr<mozilla::PresShell> mPresShell; 68 69 nsBaseHashtable<nsUint32HashKey, Element*, Element*> mGlyphIdMap; 70 }; 71 72 /** 73 * Used by |gfxFontEntry| to represent the SVG table of an OpenType font. 74 * Handles lazy parsing of the SVG documents in the table, looking up SVG glyphs 75 * and rendering SVG glyphs. 76 * Each |gfxFontEntry| owns at most one |gfxSVGGlyphs| instance. 77 */ 78 class gfxSVGGlyphs { 79 private: 80 typedef mozilla::dom::Element Element; 81 82 public: 83 /** 84 * @param aSVGTable The SVG table from the OpenType font 85 * 86 * The gfxSVGGlyphs object takes over ownership of the blob references 87 * that are passed in, and will hb_blob_destroy() them when finished; 88 * the caller should -not- destroy these references. 89 */ 90 gfxSVGGlyphs(hb_blob_t* aSVGTable, gfxFontEntry* aFontEntry); 91 92 /** 93 * Releases our references to the SVG table and cleans up everything else. 94 */ 95 ~gfxSVGGlyphs(); 96 97 /** 98 * This is called when the refresh driver has ticked. 99 */ 100 void DidRefresh(); 101 102 /** 103 * Find the |gfxSVGGlyphsDocument| containing an SVG glyph for |aGlyphId|. 104 * If |aGlyphId| does not map to an SVG document, return null. 105 * If a |gfxSVGGlyphsDocument| has not been created for the document, create 106 * one. 107 */ 108 gfxSVGGlyphsDocument* FindOrCreateGlyphsDocument(uint32_t aGlyphId); 109 110 /** 111 * Return true iff there is an SVG glyph for |aGlyphId| 112 */ 113 bool HasSVGGlyph(uint32_t aGlyphId); 114 115 /** 116 * Render the SVG glyph for |aGlyphId| 117 * @param aContextPaint Information on text context paints. 118 * See |SVGContextPaint|. 119 */ 120 void RenderGlyph(gfxContext* aContext, uint32_t aGlyphId, 121 mozilla::SVGContextPaint* aContextPaint); 122 123 /** 124 * Get the extents for the SVG glyph associated with |aGlyphId| 125 * @param aSVGToAppSpace The matrix mapping the SVG glyph space to the 126 * target context space 127 */ 128 bool GetGlyphExtents(uint32_t aGlyphId, const gfxMatrix& aSVGToAppSpace, 129 gfxRect* aResult); 130 131 size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; 132 133 gfxFontEntry* FontEntry() const { return mFontEntry; } 134 135 private: 136 Element* GetGlyphElement(uint32_t aGlyphId); 137 138 nsClassHashtable<nsUint32HashKey, gfxSVGGlyphsDocument> mGlyphDocs; 139 nsBaseHashtable<nsUint32HashKey, Element*, Element*> mGlyphIdMap; 140 141 hb_blob_t* mSVGData; 142 143 // pointer to the font entry that owns this gfxSVGGlyphs object 144 gfxFontEntry* MOZ_NON_OWNING_REF mFontEntry; 145 146 const struct Header { 147 mozilla::AutoSwap_PRUint16 mVersion; 148 mozilla::AutoSwap_PRUint32 mDocIndexOffset; 149 mozilla::AutoSwap_PRUint32 mColorPalettesOffset; 150 }* mHeader; 151 152 struct IndexEntry { 153 mozilla::AutoSwap_PRUint16 mStartGlyph; 154 mozilla::AutoSwap_PRUint16 mEndGlyph; 155 mozilla::AutoSwap_PRUint32 mDocOffset; 156 mozilla::AutoSwap_PRUint32 mDocLength; 157 }; 158 159 const struct DocIndex { 160 mozilla::AutoSwap_PRUint16 mNumEntries; 161 IndexEntry mEntries[1]; /* actual length = mNumEntries */ 162 }* mDocIndex; 163 164 static int CompareIndexEntries(const void* _a, const void* _b); 165 }; 166 167 /** 168 * XXX This is a complete hack and should die (see bug 1291494). 169 * 170 * This class is used when code fails to pass through an SVGContextPaint from 171 * the context in which we are painting. In that case we create one of these 172 * as a fallback and have it wrap the gfxContext's current gfxPattern and 173 * pretend that that is the paint context's fill pattern. In some contexts 174 * that will be the case, in others it will not. As we convert more code to 175 * Moz2D the less likely it is that this hack will work. It will also make 176 * converting to Moz2D harder. 177 */ 178 class SimpleTextContextPaint : public mozilla::SVGContextPaint { 179 private: 180 static constexpr mozilla::gfx::DeviceColor sZero{}; 181 182 static gfxMatrix SetupDeviceToPatternMatrix(gfxPattern* aPattern, 183 const gfxMatrix& aCTM) { 184 if (!aPattern) { 185 return gfxMatrix(); 186 } 187 gfxMatrix deviceToUser = aCTM; 188 if (!deviceToUser.Invert()) { 189 return gfxMatrix(0, 0, 0, 0, 0, 0); // singular 190 } 191 return deviceToUser * aPattern->GetMatrix(); 192 } 193 194 public: 195 SimpleTextContextPaint(gfxPattern* aFillPattern, gfxPattern* aStrokePattern, 196 const gfxMatrix& aCTM) 197 : mFillPattern(aFillPattern ? aFillPattern : new gfxPattern(sZero)), 198 mStrokePattern(aStrokePattern ? aStrokePattern 199 : new gfxPattern(sZero)) { 200 mFillMatrix = SetupDeviceToPatternMatrix(aFillPattern, aCTM); 201 mStrokeMatrix = SetupDeviceToPatternMatrix(aStrokePattern, aCTM); 202 } 203 204 already_AddRefed<gfxPattern> GetFillPattern( 205 const DrawTarget* aDrawTarget, float aOpacity, const gfxMatrix& aCTM, 206 imgDrawingParams& aImgParams) override { 207 if (mFillPattern) { 208 mFillPattern->SetMatrix(aCTM * mFillMatrix); 209 } 210 RefPtr<gfxPattern> fillPattern = mFillPattern; 211 return fillPattern.forget(); 212 } 213 214 already_AddRefed<gfxPattern> GetStrokePattern( 215 const DrawTarget* aDrawTarget, float aOpacity, const gfxMatrix& aCTM, 216 imgDrawingParams& aImgParams) override { 217 if (mStrokePattern) { 218 mStrokePattern->SetMatrix(aCTM * mStrokeMatrix); 219 } 220 RefPtr<gfxPattern> strokePattern = mStrokePattern; 221 return strokePattern.forget(); 222 } 223 224 float GetFillOpacity() const override { return mFillPattern ? 1.0f : 0.0f; } 225 226 float GetStrokeOpacity() const override { 227 return mStrokePattern ? 1.0f : 0.0f; 228 } 229 230 private: 231 RefPtr<gfxPattern> mFillPattern; 232 RefPtr<gfxPattern> mStrokePattern; 233 234 // Device space to pattern space transforms 235 gfxMatrix mFillMatrix; 236 gfxMatrix mStrokeMatrix; 237 }; 238 239 #endif