Home | History | Annotate | Download | only in text
      1 /*
      2  * Copyright (C) 2000 Lars Knoll (knoll (at) kde.org)
      3  *           (C) 2000 Antti Koivisto (koivisto (at) kde.org)
      4  *           (C) 2000 Dirk Mueller (mueller (at) 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)
     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)
     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 
    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]; }
    174     const LChar* data8(unsigned i) const { ASSERT_WITH_SECURITY_IMPLICATION(i < m_len); ASSERT(is8Bit()); return &m_data.characters8[i]; }
    175     const UChar* data16(unsigned i) const { ASSERT_WITH_SECURITY_IMPLICATION(i < m_len); ASSERT(!is8Bit()); return &m_data.characters16[i]; }
    176 
    177     const LChar* characters8() const { ASSERT(is8Bit()); return m_data.characters8; }
    178     const UChar* characters16() const { ASSERT(!is8Bit()); return m_data.characters16; }
    179 
    180     bool is8Bit() const { return m_is8Bit; }
    181     int length() const { return m_len; }
    182     int charactersLength() const { return m_charactersLength; }
    183 
    184     void setText(const LChar* c, unsigned len) { m_data.characters8 = c; m_len = len; m_is8Bit = true;}
    185     void setText(const UChar* c, unsigned len) { m_data.characters16 = c; m_len = len; m_is8Bit = false;}
    186     void setText(const String&);
    187     void setCharactersLength(unsigned charactersLength) { m_charactersLength = charactersLength; }
    188 
    189     float horizontalGlyphStretch() const { return m_horizontalGlyphStretch; }
    190     void setHorizontalGlyphStretch(float scale) { m_horizontalGlyphStretch = scale; }
    191 
    192     bool allowTabs() const { return m_allowTabs; }
    193     unsigned tabSize() const { return m_tabSize; }
    194     void setTabSize(bool, unsigned);
    195 
    196     float xPos() const { return m_xpos; }
    197     void setXPos(float xPos) { m_xpos = xPos; }
    198     float expansion() const { return m_expansion; }
    199     bool allowsLeadingExpansion() const { return m_expansionBehavior & AllowLeadingExpansion; }
    200     bool allowsTrailingExpansion() const { return m_expansionBehavior & AllowTrailingExpansion; }
    201     TextDirection direction() const { return static_cast<TextDirection>(m_direction); }
    202     bool rtl() const { return m_direction == RTL; }
    203     bool ltr() const { return m_direction == LTR; }
    204     bool directionalOverride() const { return m_directionalOverride; }
    205     bool characterScanForCodePath() const { return m_characterScanForCodePath; }
    206     bool applyRunRounding() const { return m_applyRunRounding; }
    207     bool applyWordRounding() const { return m_applyWordRounding; }
    208     bool spacingDisabled() const { return m_disableSpacing; }
    209 
    210     void disableSpacing() { m_disableSpacing = true; }
    211     void disableRoundingHacks() { m_applyRunRounding = m_applyWordRounding = false; }
    212     void setDirection(TextDirection direction) { m_direction = direction; }
    213     void setDirectionalOverride(bool override) { m_directionalOverride = override; }
    214     void setCharacterScanForCodePath(bool scan) { m_characterScanForCodePath = scan; }
    215 
    216     class RenderingContext : public RefCounted<RenderingContext> {
    217     public:
    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 
    225     RenderingContext* renderingContext() const { return m_renderingContext.get(); }
    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 
    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 {
    269     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