• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, 2011 Apple Inc. All rights reserved.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public License
18  * along with this library; see the file COPYING.LIB.  If not, write to
19  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20  * Boston, MA 02110-1301, USA.
21  *
22  */
23 
24 #ifndef TextRun_h
25 #define TextRun_h
26 
27 #include "platform/PlatformExport.h"
28 #include "platform/geometry/FloatRect.h"
29 #include "platform/text/TextDirection.h"
30 #include "wtf/RefCounted.h"
31 #include "wtf/text/WTFString.h"
32 
33 namespace WebCore {
34 
35 class FloatPoint;
36 class Font;
37 class GraphicsContext;
38 class GlyphBuffer;
39 class SimpleFontData;
40 struct GlyphData;
41 struct WidthIterator;
42 
43 class PLATFORM_EXPORT TextRun {
44     WTF_MAKE_FAST_ALLOCATED;
45 public:
46     enum ExpansionBehaviorFlags {
47         ForbidTrailingExpansion = 0 << 0,
48         AllowTrailingExpansion = 1 << 0,
49         ForbidLeadingExpansion = 0 << 1,
50         AllowLeadingExpansion = 1 << 1,
51     };
52 
53     typedef unsigned ExpansionBehavior;
54 
55     enum RoundingHackFlags {
56         NoRounding = 0,
57         RunRounding = 1 << 0,
58         WordRounding = 1 << 1,
59     };
60 
61     typedef unsigned RoundingHacks;
62 
63     TextRun(const LChar* c, unsigned len, float xpos = 0, float expansion = 0, ExpansionBehavior expansionBehavior = AllowTrailingExpansion | ForbidLeadingExpansion, TextDirection direction = LTR, bool directionalOverride = false, bool characterScanForCodePath = true, RoundingHacks roundingHacks = RunRounding | WordRounding)
m_charactersLength(len)64         : m_charactersLength(len)
65         , m_len(len)
66         , m_xpos(xpos)
67         , m_horizontalGlyphStretch(1)
68         , m_expansion(expansion)
69         , m_expansionBehavior(expansionBehavior)
70         , m_is8Bit(true)
71         , m_allowTabs(false)
72         , m_direction(direction)
73         , m_directionalOverride(directionalOverride)
74         , m_characterScanForCodePath(characterScanForCodePath)
75         , m_applyRunRounding((roundingHacks & RunRounding) && s_allowsRoundingHacks)
76         , m_applyWordRounding((roundingHacks & WordRounding) && s_allowsRoundingHacks)
77         , m_disableSpacing(false)
78         , m_tabSize(0)
79     {
80         m_data.characters8 = c;
81     }
82 
83     TextRun(const UChar* c, unsigned len, float xpos = 0, float expansion = 0, ExpansionBehavior expansionBehavior = AllowTrailingExpansion | ForbidLeadingExpansion, TextDirection direction = LTR, bool directionalOverride = false, bool characterScanForCodePath = true, RoundingHacks roundingHacks = RunRounding | WordRounding)
m_charactersLength(len)84         : m_charactersLength(len)
85         , m_len(len)
86         , m_xpos(xpos)
87         , m_horizontalGlyphStretch(1)
88         , m_expansion(expansion)
89         , m_expansionBehavior(expansionBehavior)
90         , m_is8Bit(false)
91         , m_allowTabs(false)
92         , m_direction(direction)
93         , m_directionalOverride(directionalOverride)
94         , m_characterScanForCodePath(characterScanForCodePath)
95         , m_applyRunRounding((roundingHacks & RunRounding) && s_allowsRoundingHacks)
96         , m_applyWordRounding((roundingHacks & WordRounding) && s_allowsRoundingHacks)
97         , m_disableSpacing(false)
98         , m_tabSize(0)
99     {
100         m_data.characters16 = c;
101     }
102 
103     TextRun(const String& string, float xpos = 0, float expansion = 0, ExpansionBehavior expansionBehavior = AllowTrailingExpansion | ForbidLeadingExpansion, TextDirection direction = LTR, bool directionalOverride = false, bool characterScanForCodePath = true, RoundingHacks roundingHacks = RunRounding | WordRounding)
104         : m_charactersLength(string.length())
105         , m_len(string.length())
106         , m_xpos(xpos)
107         , m_horizontalGlyphStretch(1)
108         , m_expansion(expansion)
109         , m_expansionBehavior(expansionBehavior)
110         , m_allowTabs(false)
111         , m_direction(direction)
112         , m_directionalOverride(directionalOverride)
113         , m_characterScanForCodePath(characterScanForCodePath)
114         , m_applyRunRounding((roundingHacks & RunRounding) && s_allowsRoundingHacks)
115         , m_applyWordRounding((roundingHacks & WordRounding) && s_allowsRoundingHacks)
116         , m_disableSpacing(false)
117         , m_tabSize(0)
118     {
119         if (!m_charactersLength) {
120             m_is8Bit = true;
121             m_data.characters8 = 0;
122         } else if (string.is8Bit()) {
123             m_data.characters8 = string.characters8();
124             m_is8Bit = true;
125         } else {
126             m_data.characters16 = string.characters16();
127             m_is8Bit = false;
128         }
129     }
130 
131     TextRun(const StringView& string, float xpos = 0, float expansion = 0, ExpansionBehavior expansionBehavior = AllowTrailingExpansion | ForbidLeadingExpansion, TextDirection direction = LTR, bool directionalOverride = false, bool characterScanForCodePath = true, RoundingHacks roundingHacks = RunRounding | WordRounding)
132         : m_charactersLength(string.length())
133         , m_len(string.length())
134         , m_xpos(xpos)
135         , m_horizontalGlyphStretch(1)
136         , m_expansion(expansion)
137         , m_expansionBehavior(expansionBehavior)
138         , m_allowTabs(false)
139         , m_direction(direction)
140         , m_directionalOverride(directionalOverride)
141         , m_characterScanForCodePath(characterScanForCodePath)
142         , m_applyRunRounding((roundingHacks & RunRounding) && s_allowsRoundingHacks)
143         , m_applyWordRounding((roundingHacks & WordRounding) && s_allowsRoundingHacks)
144         , m_disableSpacing(false)
145         , m_tabSize(0)
146     {
147         if (!m_charactersLength) {
148             m_is8Bit = true;
149             m_data.characters8 = 0;
150         } else if (string.is8Bit()) {
151             m_data.characters8 = string.characters8();
152             m_is8Bit = true;
153         } else {
154             m_data.characters16 = string.characters16();
155             m_is8Bit = false;
156         }
157     }
158 
subRun(unsigned startOffset,unsigned length)159     TextRun subRun(unsigned startOffset, unsigned length) const
160     {
161         ASSERT(startOffset < m_len);
162 
163         TextRun result = *this;
164 
165         if (is8Bit()) {
166             result.setText(data8(startOffset), length);
167             return result;
168         }
169         result.setText(data16(startOffset), length);
170         return result;
171     }
172 
173     UChar operator[](unsigned i) const { ASSERT_WITH_SECURITY_IMPLICATION(i < m_len); return is8Bit() ? m_data.characters8[i] :m_data.characters16[i]; }
data8(unsigned i)174     const LChar* data8(unsigned i) const { ASSERT_WITH_SECURITY_IMPLICATION(i < m_len); ASSERT(is8Bit()); return &m_data.characters8[i]; }
data16(unsigned i)175     const UChar* data16(unsigned i) const { ASSERT_WITH_SECURITY_IMPLICATION(i < m_len); ASSERT(!is8Bit()); return &m_data.characters16[i]; }
176 
characters8()177     const LChar* characters8() const { ASSERT(is8Bit()); return m_data.characters8; }
characters16()178     const UChar* characters16() const { ASSERT(!is8Bit()); return m_data.characters16; }
179 
is8Bit()180     bool is8Bit() const { return m_is8Bit; }
length()181     int length() const { return m_len; }
charactersLength()182     int charactersLength() const { return m_charactersLength; }
183 
setText(const LChar * c,unsigned len)184     void setText(const LChar* c, unsigned len) { m_data.characters8 = c; m_len = len; m_is8Bit = true;}
setText(const UChar * c,unsigned len)185     void setText(const UChar* c, unsigned len) { m_data.characters16 = c; m_len = len; m_is8Bit = false;}
186     void setText(const String&);
setCharactersLength(unsigned charactersLength)187     void setCharactersLength(unsigned charactersLength) { m_charactersLength = charactersLength; }
188 
horizontalGlyphStretch()189     float horizontalGlyphStretch() const { return m_horizontalGlyphStretch; }
setHorizontalGlyphStretch(float scale)190     void setHorizontalGlyphStretch(float scale) { m_horizontalGlyphStretch = scale; }
191 
allowTabs()192     bool allowTabs() const { return m_allowTabs; }
tabSize()193     unsigned tabSize() const { return m_tabSize; }
194     void setTabSize(bool, unsigned);
195 
xPos()196     float xPos() const { return m_xpos; }
setXPos(float xPos)197     void setXPos(float xPos) { m_xpos = xPos; }
expansion()198     float expansion() const { return m_expansion; }
allowsLeadingExpansion()199     bool allowsLeadingExpansion() const { return m_expansionBehavior & AllowLeadingExpansion; }
allowsTrailingExpansion()200     bool allowsTrailingExpansion() const { return m_expansionBehavior & AllowTrailingExpansion; }
direction()201     TextDirection direction() const { return static_cast<TextDirection>(m_direction); }
rtl()202     bool rtl() const { return m_direction == RTL; }
ltr()203     bool ltr() const { return m_direction == LTR; }
directionalOverride()204     bool directionalOverride() const { return m_directionalOverride; }
characterScanForCodePath()205     bool characterScanForCodePath() const { return m_characterScanForCodePath; }
applyRunRounding()206     bool applyRunRounding() const { return m_applyRunRounding; }
applyWordRounding()207     bool applyWordRounding() const { return m_applyWordRounding; }
spacingDisabled()208     bool spacingDisabled() const { return m_disableSpacing; }
209 
disableSpacing()210     void disableSpacing() { m_disableSpacing = true; }
disableRoundingHacks()211     void disableRoundingHacks() { m_applyRunRounding = m_applyWordRounding = false; }
setDirection(TextDirection direction)212     void setDirection(TextDirection direction) { m_direction = direction; }
setDirectionalOverride(bool override)213     void setDirectionalOverride(bool override) { m_directionalOverride = override; }
setCharacterScanForCodePath(bool scan)214     void setCharacterScanForCodePath(bool scan) { m_characterScanForCodePath = scan; }
215 
216     class RenderingContext : public RefCounted<RenderingContext> {
217     public:
~RenderingContext()218         virtual ~RenderingContext() { }
219 
220         virtual GlyphData glyphDataForCharacter(const Font&, const TextRun&, WidthIterator&, UChar32 character, bool mirror, int currentCharacter, unsigned& advanceLength) = 0;
221         virtual void drawSVGGlyphs(GraphicsContext*, const TextRun&, const SimpleFontData*, const GlyphBuffer&, int from, int to, const FloatPoint&) const = 0;
222         virtual float floatWidthUsingSVGFont(const Font&, const TextRun&, int& charsConsumed, String& glyphName) const = 0;
223     };
224 
renderingContext()225     RenderingContext* renderingContext() const { return m_renderingContext.get(); }
setRenderingContext(PassRefPtr<RenderingContext> context)226     void setRenderingContext(PassRefPtr<RenderingContext> context) { m_renderingContext = context; }
227 
228     static void setAllowsRoundingHacks(bool);
229     static bool allowsRoundingHacks();
230 
231 private:
232     static bool s_allowsRoundingHacks;
233 
234     union {
235         const LChar* characters8;
236         const UChar* characters16;
237     } m_data;
238     unsigned m_charactersLength; // Marks the end of the characters buffer. Default equals to m_len.
239     unsigned m_len;
240 
241     // m_xpos is the x position relative to the left start of the text line, not relative to the left
242     // start of the containing block. In the case of right alignment or center alignment, left start of
243     // the text line is not the same as left start of the containing block.
244     float m_xpos;
245     float m_horizontalGlyphStretch;
246 
247     float m_expansion;
248     ExpansionBehavior m_expansionBehavior : 2;
249     unsigned m_is8Bit : 1;
250     unsigned m_allowTabs : 1;
251     unsigned m_direction : 1;
252     unsigned m_directionalOverride : 1; // Was this direction set by an override character.
253     unsigned m_characterScanForCodePath : 1;
254     unsigned m_applyRunRounding : 1;
255     unsigned m_applyWordRounding : 1;
256     unsigned m_disableSpacing : 1;
257     unsigned m_tabSize;
258     RefPtr<RenderingContext> m_renderingContext;
259 };
260 
setTabSize(bool allow,unsigned size)261 inline void TextRun::setTabSize(bool allow, unsigned size)
262 {
263     m_allowTabs = allow;
264     m_tabSize = size;
265 }
266 
267 // Container for parameters needed to paint TextRun.
268 struct TextRunPaintInfo {
TextRunPaintInfoTextRunPaintInfo269     explicit TextRunPaintInfo(const TextRun& r)
270         : run(r)
271         , from(0)
272         , to(r.length())
273     {
274     }
275 
276     const TextRun& run;
277     int from;
278     int to;
279     FloatRect bounds;
280 };
281 
282 }
283 #endif
284