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