e62c45724b4ea95f0c4dd6b04988d2bc9aa2c4f2
[WebKit-https.git] / Source / WebCore / platform / graphics / FontCascade.h
1 /*
2  * Copyright (C) 2000 Lars Knoll (knoll@kde.org)
3  *           (C) 2000 Antti Koivisto (koivisto@kde.org)
4  *           (C) 2000 Dirk Mueller (mueller@kde.org)
5  * Copyright (C) 2003, 2006, 2007, 2010, 2011 Apple Inc. All rights reserved.
6  * Copyright (C) 2008 Holger Hans Peter Freyther
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public License
19  * along with this library; see the file COPYING.LIB.  If not, write to
20  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21  * Boston, MA 02110-1301, USA.
22  *
23  */
24
25 #ifndef FontCascade_h
26 #define FontCascade_h
27
28 #include "DashArray.h"
29 #include "Font.h"
30 #include "FontCascadeFonts.h"
31 #include "FontDescription.h"
32 #include "Path.h"
33 #include "TextFlags.h"
34 #include <wtf/HashSet.h>
35 #include <wtf/Optional.h>
36 #include <wtf/WeakPtr.h>
37 #include <wtf/unicode/CharacterNames.h>
38
39 // "X11/X.h" defines Complex to 0 and conflicts
40 // with Complex value in CodePath enum.
41 #ifdef Complex
42 #undef Complex
43 #endif
44
45 namespace WebCore {
46
47 class FloatPoint;
48 class FloatRect;
49 class FontData;
50 class FontMetrics;
51 class FontPlatformData;
52 class FontSelector;
53 class GlyphBuffer;
54 class GraphicsContext;
55 class LayoutRect;
56 class RenderText;
57 class TextLayout;
58 class TextRun;
59
60 struct GlyphData;
61
62 struct GlyphOverflow {
63     GlyphOverflow()
64         : left(0)
65         , right(0)
66         , top(0)
67         , bottom(0)
68         , computeBounds(false)
69     {
70     }
71
72     inline bool isEmpty()
73     {
74         return !left && !right && !top && !bottom;
75     }
76
77     inline void extendTo(const GlyphOverflow& other)
78     {
79         left = std::max(left, other.left);
80         right = std::max(right, other.right);
81         top = std::max(top, other.top);
82         bottom = std::max(bottom, other.bottom);
83     }
84
85     bool operator!=(const GlyphOverflow& other)
86     {
87         return left != other.left || right != other.right || top != other.top || bottom != other.bottom;
88     }
89
90     int left;
91     int right;
92     int top;
93     int bottom;
94     bool computeBounds;
95 };
96
97 class GlyphToPathTranslator {
98 public:
99     enum class GlyphUnderlineType {SkipDescenders, SkipGlyph, DrawOverGlyph};
100     virtual bool containsMorePaths() = 0;
101     virtual Path path() = 0;
102     virtual std::pair<float, float> extents() = 0;
103     virtual GlyphUnderlineType underlineType() = 0;
104     virtual void advance() = 0;
105     virtual ~GlyphToPathTranslator() { }
106 };
107 GlyphToPathTranslator::GlyphUnderlineType computeUnderlineType(const TextRun&, const GlyphBuffer&, unsigned index);
108
109 class TextLayoutDeleter {
110 public:
111     void operator()(TextLayout*) const;
112 };
113
114 class FontCascade {
115 public:
116     WEBCORE_EXPORT FontCascade();
117     WEBCORE_EXPORT FontCascade(const FontCascadeDescription&, float letterSpacing, float wordSpacing);
118     // This constructor is only used if the platform wants to start with a native font.
119     WEBCORE_EXPORT FontCascade(const FontPlatformData&, FontSmoothingMode = AutoSmoothing);
120
121     FontCascade(const FontCascade&);
122     WEBCORE_EXPORT FontCascade& operator=(const FontCascade&);
123
124     WEBCORE_EXPORT bool operator==(const FontCascade& other) const;
125     bool operator!=(const FontCascade& other) const { return !(*this == other); }
126
127     const FontCascadeDescription& fontDescription() const { return m_fontDescription; }
128
129     int pixelSize() const { return fontDescription().computedPixelSize(); }
130     float size() const { return fontDescription().computedSize(); }
131
132     void update(RefPtr<FontSelector>&&) const;
133
134     enum CustomFontNotReadyAction { DoNotPaintIfFontNotReady, UseFallbackIfFontNotReady };
135     WEBCORE_EXPORT float drawText(GraphicsContext&, const TextRun&, const FloatPoint&, unsigned from = 0, Optional<unsigned> to = Nullopt, CustomFontNotReadyAction = DoNotPaintIfFontNotReady) const;
136     static void drawGlyphs(GraphicsContext&, const Font&, const GlyphBuffer&, unsigned from, unsigned numGlyphs, const FloatPoint&, FontSmoothingMode);
137     void drawEmphasisMarks(GraphicsContext&, const TextRun&, const AtomicString& mark, const FloatPoint&, unsigned from = 0, Optional<unsigned> to = Nullopt) const;
138
139     DashArray dashesForIntersectionsWithRect(const TextRun&, const FloatPoint& textOrigin, const FloatRect& lineExtents) const;
140
141     WEBCORE_EXPORT float width(const TextRun&, HashSet<const Font*>* fallbackFonts = 0, GlyphOverflow* = 0) const;
142
143     std::unique_ptr<TextLayout, TextLayoutDeleter> createLayout(RenderText&, float xPos, bool collapseWhiteSpace) const;
144     static float width(TextLayout&, unsigned from, unsigned len, HashSet<const Font*>* fallbackFonts = 0);
145
146     int offsetForPosition(const TextRun&, float position, bool includePartialGlyphs) const;
147     void adjustSelectionRectForText(const TextRun&, LayoutRect& selectionRect, unsigned from = 0, Optional<unsigned> to = Nullopt) const;
148
149     bool isSmallCaps() const { return m_fontDescription.variantCaps() == FontVariantCaps::Small; }
150
151     float wordSpacing() const { return m_wordSpacing; }
152     float letterSpacing() const { return m_letterSpacing; }
153     void setWordSpacing(float s) { m_wordSpacing = s; }
154     void setLetterSpacing(float s) { m_letterSpacing = s; }
155     bool isFixedPitch() const;
156     
157     FontRenderingMode renderingMode() const { return m_fontDescription.renderingMode(); }
158
159     bool enableKerning() const { return m_enableKerning; }
160     bool requiresShaping() const { return m_requiresShaping; }
161
162     const AtomicString& firstFamily() const { return m_fontDescription.firstFamily(); }
163     unsigned familyCount() const { return m_fontDescription.familyCount(); }
164     const AtomicString& familyAt(unsigned i) const { return m_fontDescription.familyAt(i); }
165
166     FontItalic italic() const { return m_fontDescription.italic(); }
167     FontWeight weight() const { return m_fontDescription.weight(); }
168     FontWidthVariant widthVariant() const { return m_fontDescription.widthVariant(); }
169
170     bool isPlatformFont() const { return m_fonts->isForPlatformFont(); }
171
172     const FontMetrics& fontMetrics() const { return primaryFont().fontMetrics(); }
173     float spaceWidth() const { return primaryFont().spaceWidth() + m_letterSpacing; }
174     float tabWidth(const Font&, unsigned tabSize, float position) const;
175     float tabWidth(unsigned tabSize, float position) const { return tabWidth(primaryFont(), tabSize, position); }
176     bool hasValidAverageCharWidth() const;
177     bool fastAverageCharWidthIfAvailable(float &width) const; // returns true on success
178
179     int emphasisMarkAscent(const AtomicString&) const;
180     int emphasisMarkDescent(const AtomicString&) const;
181     int emphasisMarkHeight(const AtomicString&) const;
182
183     const Font& primaryFont() const;
184     const FontRanges& fallbackRangesAt(unsigned) const;
185     GlyphData glyphDataForCharacter(UChar32, bool mirror, FontVariant = AutoVariant) const;
186     
187 #if PLATFORM(COCOA)
188     const Font* fontForCombiningCharacterSequence(const UChar*, size_t length) const;
189 #endif
190
191     static bool isCJKIdeograph(UChar32);
192     static bool isCJKIdeographOrSymbol(UChar32);
193
194     // Returns (the number of opportunities, whether the last expansion is a trailing expansion)
195     // If there are no opportunities, the bool will be true iff we are forbidding leading expansions.
196     static std::pair<unsigned, bool> expansionOpportunityCount(const StringView&, TextDirection, ExpansionBehavior);
197
198     // Whether or not there is an expansion opportunity just before the first character
199     // Note that this does not take a isAfterExpansion flag; this assumes that isAfterExpansion is false
200     // Here, "Leading" and "Trailing" are relevant after the line has been rearranged for bidi.
201     // ("Leading" means "left" and "Trailing" means "right.")
202     static bool leadingExpansionOpportunity(const StringView&, TextDirection);
203     static bool trailingExpansionOpportunity(const StringView&, TextDirection);
204
205     WEBCORE_EXPORT static void setShouldUseSmoothing(bool);
206     WEBCORE_EXPORT static bool shouldUseSmoothing();
207
208     enum CodePath { Auto, Simple, Complex, SimpleWithGlyphOverflow };
209     CodePath codePath(const TextRun&) const;
210     static CodePath characterRangeCodePath(const LChar*, unsigned) { return Simple; }
211     static CodePath characterRangeCodePath(const UChar*, unsigned len);
212
213     bool primaryFontIsSystemFont() const;
214
215     WeakPtr<FontCascade> createWeakPtr() const { return m_weakPtrFactory.createWeakPtr(); }
216
217 private:
218     enum ForTextEmphasisOrNot { NotForTextEmphasis, ForTextEmphasis };
219
220     float glyphBufferForTextRun(CodePath, const TextRun&, unsigned from, unsigned to, GlyphBuffer&) const;
221     // Returns the initial in-stream advance.
222     float getGlyphsAndAdvancesForSimpleText(const TextRun&, unsigned from, unsigned to, GlyphBuffer&, ForTextEmphasisOrNot = NotForTextEmphasis) const;
223     void drawEmphasisMarksForSimpleText(GraphicsContext&, const TextRun&, const AtomicString& mark, const FloatPoint&, unsigned from, unsigned to) const;
224     void drawGlyphBuffer(GraphicsContext&, const GlyphBuffer&, FloatPoint&) const;
225     void drawEmphasisMarks(GraphicsContext&, const GlyphBuffer&, const AtomicString&, const FloatPoint&) const;
226     float floatWidthForSimpleText(const TextRun&, HashSet<const Font*>* fallbackFonts = 0, GlyphOverflow* = 0) const;
227     int offsetForPositionForSimpleText(const TextRun&, float position, bool includePartialGlyphs) const;
228     void adjustSelectionRectForSimpleText(const TextRun&, LayoutRect& selectionRect, unsigned from, unsigned to) const;
229
230     Optional<GlyphData> getEmphasisMarkGlyphData(const AtomicString&) const;
231
232     static bool canReturnFallbackFontsForComplexText();
233     static bool canExpandAroundIdeographsInComplexText();
234
235     // Returns the initial in-stream advance.
236     float getGlyphsAndAdvancesForComplexText(const TextRun&, unsigned from, unsigned to, GlyphBuffer&, ForTextEmphasisOrNot = NotForTextEmphasis) const;
237     void drawEmphasisMarksForComplexText(GraphicsContext&, const TextRun&, const AtomicString& mark, const FloatPoint&, unsigned from, unsigned to) const;
238     float floatWidthForComplexText(const TextRun&, HashSet<const Font*>* fallbackFonts = 0, GlyphOverflow* = 0) const;
239     int offsetForPositionForComplexText(const TextRun&, float position, bool includePartialGlyphs) const;
240     void adjustSelectionRectForComplexText(const TextRun&, LayoutRect& selectionRect, unsigned from, unsigned to) const;
241
242     static std::pair<unsigned, bool> expansionOpportunityCountInternal(const LChar*, unsigned length, TextDirection, ExpansionBehavior);
243     static std::pair<unsigned, bool> expansionOpportunityCountInternal(const UChar*, unsigned length, TextDirection, ExpansionBehavior);
244
245     friend struct WidthIterator;
246
247 public:
248 #if ENABLE(IOS_TEXT_AUTOSIZING)
249     bool equalForTextAutoSizing(const FontCascade& other) const
250     {
251         return m_fontDescription.equalForTextAutoSizing(other.m_fontDescription)
252             && m_letterSpacing == other.m_letterSpacing
253             && m_wordSpacing == other.m_wordSpacing;
254     }
255 #endif
256
257     // Useful for debugging the different font rendering code paths.
258     WEBCORE_EXPORT static void setCodePath(CodePath);
259     static CodePath codePath();
260     static CodePath s_codePath;
261
262     FontSelector* fontSelector() const;
263     static bool treatAsSpace(UChar c) { return c == ' ' || c == '\t' || c == '\n' || c == noBreakSpace; }
264     static bool treatAsZeroWidthSpace(UChar c) { return treatAsZeroWidthSpaceInComplexScript(c) || c == 0x200c || c == 0x200d; }
265     static bool treatAsZeroWidthSpaceInComplexScript(UChar c) { return c < 0x20 || (c >= 0x7F && c < 0xA0) || c == softHyphen || c == zeroWidthSpace || (c >= 0x200e && c <= 0x200f) || (c >= 0x202a && c <= 0x202e) || c == zeroWidthNoBreakSpace || c == objectReplacementCharacter; }
266     static bool canReceiveTextEmphasis(UChar32);
267
268     static inline UChar normalizeSpaces(UChar character)
269     {
270         if (treatAsSpace(character))
271             return space;
272
273         if (treatAsZeroWidthSpace(character))
274             return zeroWidthSpace;
275
276         return character;
277     }
278
279     static String normalizeSpaces(const LChar*, unsigned length);
280     static String normalizeSpaces(const UChar*, unsigned length);
281
282     bool useBackslashAsYenSymbol() const { return m_useBackslashAsYenSymbol; }
283     FontCascadeFonts* fonts() const { return m_fonts.get(); }
284
285 private:
286     bool isLoadingCustomFonts() const;
287
288     bool advancedTextRenderingMode() const
289     {
290         auto textRenderingMode = m_fontDescription.textRenderingMode();
291         if (textRenderingMode == GeometricPrecision || textRenderingMode == OptimizeLegibility)
292             return true;
293         if (textRenderingMode == OptimizeSpeed)
294             return false;
295 #if PLATFORM(COCOA)
296         return true;
297 #else
298         return false;
299 #endif
300     }
301
302     bool computeEnableKerning() const
303     {
304         auto kerning = m_fontDescription.kerning();
305         if (kerning == Kerning::Normal)
306             return true;
307         if (kerning == Kerning::NoShift)
308             return false;
309         return advancedTextRenderingMode();
310     }
311
312     bool computeRequiresShaping() const
313     {
314 #if PLATFORM(COCOA)
315         if (!m_fontDescription.variantSettings().isAllNormal())
316             return true;
317         if (m_fontDescription.featureSettings().size())
318             return true;
319 #endif
320         return advancedTextRenderingMode();
321     }
322
323     FontCascadeDescription m_fontDescription;
324     mutable RefPtr<FontCascadeFonts> m_fonts;
325     WeakPtrFactory<FontCascade> m_weakPtrFactory;
326     float m_letterSpacing;
327     float m_wordSpacing;
328     mutable bool m_useBackslashAsYenSymbol;
329     mutable unsigned m_enableKerning : 1; // Computed from m_fontDescription.
330     mutable unsigned m_requiresShaping : 1; // Computed from m_fontDescription.
331 };
332
333 void invalidateFontCascadeCache();
334 void pruneUnreferencedEntriesFromFontCascadeCache();
335 void pruneSystemFallbackFonts();
336 void clearWidthCaches();
337
338 inline const Font& FontCascade::primaryFont() const
339 {
340     ASSERT(m_fonts);
341     return m_fonts->primaryFont(m_fontDescription);
342 }
343
344 inline const FontRanges& FontCascade::fallbackRangesAt(unsigned index) const
345 {
346     ASSERT(m_fonts);
347     return m_fonts->realizeFallbackRangesAt(m_fontDescription, index);
348 }
349
350 inline bool FontCascade::isFixedPitch() const
351 {
352     ASSERT(m_fonts);
353     return m_fonts->isFixedPitch(m_fontDescription);
354 }
355
356 inline FontSelector* FontCascade::fontSelector() const
357 {
358     return m_fonts ? m_fonts->fontSelector() : nullptr;
359 }
360
361 inline float FontCascade::tabWidth(const Font& font, unsigned tabSize, float position) const
362 {
363     if (!tabSize)
364         return letterSpacing();
365     float tabWidth = tabSize * font.spaceWidth() + letterSpacing();
366     float tabDeltaWidth = tabWidth - fmodf(position, tabWidth);
367     return (tabDeltaWidth < font.spaceWidth() / 2) ? tabWidth : tabDeltaWidth;
368 }
369
370 }
371
372 #endif