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/fonts/Glyph.h"
     29 #include "platform/geometry/FloatRect.h"
     30 #include "platform/text/TextDirection.h"
     31 #include "platform/text/TextPath.h"
     32 #include "wtf/RefCounted.h"
     33 #include "wtf/text/WTFString.h"
     34 
     35 namespace WebCore {
     36 
     37 class FloatPoint;
     38 class Font;
     39 class GraphicsContext;
     40 class GlyphBuffer;
     41 class SimpleFontData;
     42 struct GlyphData;
     43 struct WidthIterator;
     44 
     45 class PLATFORM_EXPORT TextRun {
     46     WTF_MAKE_FAST_ALLOCATED;
     47 public:
     48     enum ExpansionBehaviorFlags {
     49         ForbidTrailingExpansion = 0 << 0,
     50         AllowTrailingExpansion = 1 << 0,
     51         ForbidLeadingExpansion = 0 << 1,
     52         AllowLeadingExpansion = 1 << 1,
     53     };
     54 
     55     typedef unsigned ExpansionBehavior;
     56 
     57     enum RoundingHackFlags {
     58         NoRounding = 0,
     59         RunRounding = 1 << 0,
     60         WordRounding = 1 << 1,
     61     };
     62 
     63     typedef unsigned RoundingHacks;
     64 
     65     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)
     66         : m_charactersLength(len)
     67         , m_len(len)
     68         , m_xpos(xpos)
     69         , m_horizontalGlyphStretch(1)
     70         , m_expansion(expansion)
     71         , m_expansionBehavior(expansionBehavior)
     72         , m_is8Bit(true)
     73         , m_allowTabs(false)
     74         , m_direction(direction)
     75         , m_directionalOverride(directionalOverride)
     76         , m_characterScanForCodePath(characterScanForCodePath)
     77         , m_applyRunRounding((roundingHacks & RunRounding) && s_allowsRoundingHacks)
     78         , m_applyWordRounding((roundingHacks & WordRounding) && s_allowsRoundingHacks)
     79         , m_disableSpacing(false)
     80         , m_tabSize(0)
     81     {
     82         m_data.characters8 = c;
     83     }
     84 
     85     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)
     86         : m_charactersLength(len)
     87         , m_len(len)
     88         , m_xpos(xpos)
     89         , m_horizontalGlyphStretch(1)
     90         , m_expansion(expansion)
     91         , m_expansionBehavior(expansionBehavior)
     92         , m_is8Bit(false)
     93         , m_allowTabs(false)
     94         , m_direction(direction)
     95         , m_directionalOverride(directionalOverride)
     96         , m_characterScanForCodePath(characterScanForCodePath)
     97         , m_applyRunRounding((roundingHacks & RunRounding) && s_allowsRoundingHacks)
     98         , m_applyWordRounding((roundingHacks & WordRounding) && s_allowsRoundingHacks)
     99         , m_disableSpacing(false)
    100         , m_tabSize(0)
    101     {
    102         m_data.characters16 = c;
    103     }
    104 
    105     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)
    106         : m_charactersLength(string.length())
    107         , m_len(string.length())
    108         , m_xpos(xpos)
    109         , m_horizontalGlyphStretch(1)
    110         , m_expansion(expansion)
    111         , m_expansionBehavior(expansionBehavior)
    112         , m_allowTabs(false)
    113         , m_direction(direction)
    114         , m_directionalOverride(directionalOverride)
    115         , m_characterScanForCodePath(characterScanForCodePath)
    116         , m_applyRunRounding((roundingHacks & RunRounding) && s_allowsRoundingHacks)
    117         , m_applyWordRounding((roundingHacks & WordRounding) && s_allowsRoundingHacks)
    118         , m_disableSpacing(false)
    119         , m_tabSize(0)
    120     {
    121         if (!m_charactersLength) {
    122             m_is8Bit = true;
    123             m_data.characters8 = 0;
    124         } else if (string.is8Bit()) {
    125             m_data.characters8 = string.characters8();
    126             m_is8Bit = true;
    127         } else {
    128             m_data.characters16 = string.characters16();
    129             m_is8Bit = false;
    130         }
    131     }
    132 
    133     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)
    134         : m_charactersLength(string.length())
    135         , m_len(string.length())
    136         , m_xpos(xpos)
    137         , m_horizontalGlyphStretch(1)
    138         , m_expansion(expansion)
    139         , m_expansionBehavior(expansionBehavior)
    140         , m_allowTabs(false)
    141         , m_direction(direction)
    142         , m_directionalOverride(directionalOverride)
    143         , m_characterScanForCodePath(characterScanForCodePath)
    144         , m_applyRunRounding((roundingHacks & RunRounding) && s_allowsRoundingHacks)
    145         , m_applyWordRounding((roundingHacks & WordRounding) && s_allowsRoundingHacks)
    146         , m_disableSpacing(false)
    147         , m_tabSize(0)
    148     {
    149         if (!m_charactersLength) {
    150             m_is8Bit = true;
    151             m_data.characters8 = 0;
    152         } else if (string.is8Bit()) {
    153             m_data.characters8 = string.characters8();
    154             m_is8Bit = true;
    155         } else {
    156             m_data.characters16 = string.characters16();
    157             m_is8Bit = false;
    158         }
    159     }
    160 
    161     TextRun subRun(unsigned startOffset, unsigned length) const
    162     {
    163         ASSERT(startOffset < m_len);
    164 
    165         TextRun result = *this;
    166 
    167         if (is8Bit()) {
    168             result.setText(data8(startOffset), length);
    169             return result;
    170         }
    171         result.setText(data16(startOffset), length);
    172         return result;
    173     }
    174 
    175     UChar operator[](unsigned i) const { ASSERT_WITH_SECURITY_IMPLICATION(i < m_len); return is8Bit() ? m_data.characters8[i] :m_data.characters16[i]; }
    176     const LChar* data8(unsigned i) const { ASSERT_WITH_SECURITY_IMPLICATION(i < m_len); ASSERT(is8Bit()); return &m_data.characters8[i]; }
    177     const UChar* data16(unsigned i) const { ASSERT_WITH_SECURITY_IMPLICATION(i < m_len); ASSERT(!is8Bit()); return &m_data.characters16[i]; }
    178 
    179     const LChar* characters8() const { ASSERT(is8Bit()); return m_data.characters8; }
    180     const UChar* characters16() const { ASSERT(!is8Bit()); return m_data.characters16; }
    181 
    182     bool is8Bit() const { return m_is8Bit; }
    183     int length() const { return m_len; }
    184     int charactersLength() const { return m_charactersLength; }
    185 
    186     void setText(const LChar* c, unsigned len) { m_data.characters8 = c; m_len = len; m_is8Bit = true;}
    187     void setText(const UChar* c, unsigned len) { m_data.characters16 = c; m_len = len; m_is8Bit = false;}
    188     void setText(const String&);
    189     void setCharactersLength(unsigned charactersLength) { m_charactersLength = charactersLength; }
    190 
    191     float horizontalGlyphStretch() const { return m_horizontalGlyphStretch; }
    192     void setHorizontalGlyphStretch(float scale) { m_horizontalGlyphStretch = scale; }
    193 
    194     bool allowTabs() const { return m_allowTabs; }
    195     unsigned tabSize() const { return m_tabSize; }
    196     void setTabSize(bool, unsigned);
    197 
    198     float xPos() const { return m_xpos; }
    199     void setXPos(float xPos) { m_xpos = xPos; }
    200     float expansion() const { return m_expansion; }
    201     bool allowsLeadingExpansion() const { return m_expansionBehavior & AllowLeadingExpansion; }
    202     bool allowsTrailingExpansion() const { return m_expansionBehavior & AllowTrailingExpansion; }
    203     TextDirection direction() const { return static_cast<TextDirection>(m_direction); }
    204     bool rtl() const { return m_direction == RTL; }
    205     bool ltr() const { return m_direction == LTR; }
    206     bool directionalOverride() const { return m_directionalOverride; }
    207     bool characterScanForCodePath() const { return m_characterScanForCodePath; }
    208     bool applyRunRounding() const { return m_applyRunRounding; }
    209     bool applyWordRounding() const { return m_applyWordRounding; }
    210     bool spacingDisabled() const { return m_disableSpacing; }
    211 
    212     void disableSpacing() { m_disableSpacing = true; }
    213     void disableRoundingHacks() { m_applyRunRounding = m_applyWordRounding = false; }
    214     void setDirection(TextDirection direction) { m_direction = direction; }
    215     void setDirectionalOverride(bool override) { m_directionalOverride = override; }
    216     void setCharacterScanForCodePath(bool scan) { m_characterScanForCodePath = scan; }
    217 
    218     class RenderingContext : public RefCounted<RenderingContext> {
    219     public:
    220         virtual ~RenderingContext() { }
    221 
    222         virtual GlyphData glyphDataForCharacter(const Font&, const TextRun&, WidthIterator&, UChar32 character, bool mirror, int currentCharacter, unsigned& advanceLength) = 0;
    223         virtual void drawSVGGlyphs(GraphicsContext*, const TextRun&, const SimpleFontData*, const GlyphBuffer&, int from, int to, const FloatPoint&) const = 0;
    224         virtual float floatWidthUsingSVGFont(const Font&, const TextRun&, int& charsConsumed, Glyph& glyphId) const = 0;
    225     };
    226 
    227     RenderingContext* renderingContext() const { return m_renderingContext.get(); }
    228     void setRenderingContext(PassRefPtr<RenderingContext> context) { m_renderingContext = context; }
    229 
    230     static void setAllowsRoundingHacks(bool);
    231     static bool allowsRoundingHacks();
    232 
    233 private:
    234     static bool s_allowsRoundingHacks;
    235 
    236     union {
    237         const LChar* characters8;
    238         const UChar* characters16;
    239     } m_data;
    240     unsigned m_charactersLength; // Marks the end of the characters buffer. Default equals to m_len.
    241     unsigned m_len;
    242 
    243     // m_xpos is the x position relative to the left start of the text line, not relative to the left
    244     // start of the containing block. In the case of right alignment or center alignment, left start of
    245     // the text line is not the same as left start of the containing block.
    246     float m_xpos;
    247     float m_horizontalGlyphStretch;
    248 
    249     float m_expansion;
    250     ExpansionBehavior m_expansionBehavior : 2;
    251     unsigned m_is8Bit : 1;
    252     unsigned m_allowTabs : 1;
    253     unsigned m_direction : 1;
    254     unsigned m_directionalOverride : 1; // Was this direction set by an override character.
    255     unsigned m_characterScanForCodePath : 1;
    256     unsigned m_applyRunRounding : 1;
    257     unsigned m_applyWordRounding : 1;
    258     unsigned m_disableSpacing : 1;
    259     unsigned m_tabSize;
    260     RefPtr<RenderingContext> m_renderingContext;
    261 };
    262 
    263 inline void TextRun::setTabSize(bool allow, unsigned size)
    264 {
    265     m_allowTabs = allow;
    266     m_tabSize = size;
    267 }
    268 
    269 // Container for parameters needed to paint TextRun.
    270 struct TextRunPaintInfo {
    271     explicit TextRunPaintInfo(const TextRun& r)
    272         : run(r)
    273         , from(0)
    274         , to(r.length())
    275     {
    276     }
    277 
    278     const TextRun& run;
    279     int from;
    280     int to;
    281     FloatRect bounds;
    282 };
    283 
    284 }
    285 #endif
    286