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