| OLD | NEW |
| (Empty) |
| 1 /* | |
| 2 * Copyright (C) 2003, 2006, 2008, 2009, 2010, 2011 Apple Inc. All rights | |
| 3 * reserved. | |
| 4 * Copyright (C) 2008 Holger Hans Peter Freyther | |
| 5 * Copyright (C) 2014 Google 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 #include "platform/fonts/shaping/SimpleShaper.h" | |
| 25 | |
| 26 #include "platform/fonts/Font.h" | |
| 27 #include "platform/fonts/GlyphBuffer.h" | |
| 28 #include "platform/fonts/Latin1TextIterator.h" | |
| 29 #include "platform/fonts/SimpleFontData.h" | |
| 30 #include "platform/fonts/UTF16TextIterator.h" | |
| 31 #include "platform/text/Character.h" | |
| 32 #include "wtf/MathExtras.h" | |
| 33 #include "wtf/text/CharacterNames.h" | |
| 34 | |
| 35 using namespace WTF; | |
| 36 using namespace Unicode; | |
| 37 | |
| 38 namespace blink { | |
| 39 | |
| 40 SimpleShaper::SimpleShaper(const Font* font, | |
| 41 const TextRun& run, | |
| 42 const GlyphData* emphasisData, | |
| 43 HashSet<const SimpleFontData*>* fallbackFonts, | |
| 44 FloatRect* bounds) | |
| 45 : Shaper(font, run, emphasisData, fallbackFonts, bounds), | |
| 46 m_currentCharacter(0), | |
| 47 m_runWidthSoFar(0) { | |
| 48 // If the padding is non-zero, count the number of spaces in the run | |
| 49 // and divide that by the padding for per space addition. | |
| 50 m_expansion = m_textRun.expansion(); | |
| 51 if (!m_expansion) { | |
| 52 m_expansionPerOpportunity = 0; | |
| 53 } else { | |
| 54 bool isAfterExpansion = m_isAfterExpansion; | |
| 55 unsigned expansionOpportunityCount = | |
| 56 m_textRun.is8Bit() ? Character::expansionOpportunityCount( | |
| 57 m_textRun.characters8(), m_textRun.length(), | |
| 58 m_textRun.direction(), isAfterExpansion, | |
| 59 m_textRun.getTextJustify()) | |
| 60 : Character::expansionOpportunityCount( | |
| 61 m_textRun.characters16(), m_textRun.length(), | |
| 62 m_textRun.direction(), isAfterExpansion, | |
| 63 m_textRun.getTextJustify()); | |
| 64 if (isAfterExpansion && !m_textRun.allowsTrailingExpansion()) | |
| 65 expansionOpportunityCount--; | |
| 66 | |
| 67 if (!expansionOpportunityCount) | |
| 68 m_expansionPerOpportunity = 0; | |
| 69 else | |
| 70 m_expansionPerOpportunity = m_expansion / expansionOpportunityCount; | |
| 71 } | |
| 72 } | |
| 73 | |
| 74 GlyphData SimpleShaper::glyphDataForCharacter(CharacterData& charData, | |
| 75 bool normalizeSpace) { | |
| 76 ASSERT(m_font); | |
| 77 return m_font->glyphDataForCharacter(charData.character, m_textRun.rtl(), | |
| 78 normalizeSpace); | |
| 79 } | |
| 80 | |
| 81 float SimpleShaper::characterWidth(UChar32 character, | |
| 82 const GlyphData& glyphData) const { | |
| 83 const SimpleFontData* fontData = glyphData.fontData; | |
| 84 ASSERT(fontData); | |
| 85 | |
| 86 if (UNLIKELY(character == tabulationCharacter && m_textRun.allowTabs())) | |
| 87 return m_font->tabWidth(fontData, m_textRun.getTabSize(), | |
| 88 m_textRun.xPos() + m_runWidthSoFar); | |
| 89 | |
| 90 float width = fontData->widthForGlyph(glyphData.glyph); | |
| 91 | |
| 92 // SVG uses horizontalGlyphStretch(), when textLength is used to | |
| 93 // stretch/squeeze text. | |
| 94 if (UNLIKELY(m_textRun.horizontalGlyphStretch() != 1)) | |
| 95 width *= m_textRun.horizontalGlyphStretch(); | |
| 96 | |
| 97 return width; | |
| 98 } | |
| 99 | |
| 100 float SimpleShaper::adjustSpacing(float width, const CharacterData& charData) { | |
| 101 // Account for letter-spacing. | |
| 102 if (width) | |
| 103 width += m_font->getFontDescription().letterSpacing(); | |
| 104 | |
| 105 bool isExpansionOpportunity = | |
| 106 Character::treatAsSpace(charData.character) || | |
| 107 (m_textRun.getTextJustify() == TextJustifyDistribute); | |
| 108 if (isExpansionOpportunity || | |
| 109 (m_textRun.getTextJustify() == TextJustifyAuto && | |
| 110 Character::isCJKIdeographOrSymbol(charData.character))) { | |
| 111 // Distribute the run's total expansion evenly over all expansion | |
| 112 // opportunities in the run. | |
| 113 if (m_expansion) { | |
| 114 if (!isExpansionOpportunity && !m_isAfterExpansion) { | |
| 115 // Take the expansion opportunity before this ideograph. | |
| 116 m_expansion -= m_expansionPerOpportunity; | |
| 117 m_runWidthSoFar += m_expansionPerOpportunity; | |
| 118 } | |
| 119 if (m_textRun.allowsTrailingExpansion() || | |
| 120 (m_textRun.ltr() && | |
| 121 charData.characterOffset + charData.clusterLength < | |
| 122 m_textRun.length()) || | |
| 123 (m_textRun.rtl() && charData.characterOffset)) { | |
| 124 m_expansion -= m_expansionPerOpportunity; | |
| 125 width += m_expansionPerOpportunity; | |
| 126 m_isAfterExpansion = true; | |
| 127 } | |
| 128 } else { | |
| 129 m_isAfterExpansion = false; | |
| 130 } | |
| 131 | |
| 132 // Account for word spacing. | |
| 133 // We apply additional space between "words" by adding width to the space | |
| 134 // character. | |
| 135 if (isExpansionOpportunity && | |
| 136 (charData.character != tabulationCharacter || !m_textRun.allowTabs()) && | |
| 137 (charData.characterOffset || | |
| 138 charData.character == noBreakSpaceCharacter) && | |
| 139 m_font->getFontDescription().wordSpacing()) { | |
| 140 width += m_font->getFontDescription().wordSpacing(); | |
| 141 } | |
| 142 } else { | |
| 143 m_isAfterExpansion = false; | |
| 144 } | |
| 145 | |
| 146 return width; | |
| 147 } | |
| 148 | |
| 149 template <typename TextIterator> | |
| 150 unsigned SimpleShaper::advanceInternal(TextIterator& textIterator, | |
| 151 GlyphBuffer* glyphBuffer) { | |
| 152 bool hasExtraSpacing = | |
| 153 (m_font->getFontDescription().letterSpacing() || | |
| 154 m_font->getFontDescription().wordSpacing() || m_expansion) && | |
| 155 !m_textRun.spacingDisabled(); | |
| 156 | |
| 157 const SimpleFontData* lastFontData = m_font->primaryFont(); | |
| 158 bool normalizeSpace = m_textRun.normalizeSpace(); | |
| 159 const float initialRunWidth = m_runWidthSoFar; | |
| 160 | |
| 161 CharacterData charData; | |
| 162 while (textIterator.consume(charData.character)) { | |
| 163 charData.characterOffset = textIterator.offset(); | |
| 164 charData.clusterLength = textIterator.glyphLength(); | |
| 165 GlyphData glyphData = glyphDataForCharacter(charData, normalizeSpace); | |
| 166 | |
| 167 // Some fonts do not have a glyph for zero-width-space, | |
| 168 // in that case use the space character and override the width. | |
| 169 float width; | |
| 170 bool spaceUsedAsZeroWidthSpace = false; | |
| 171 if (!glyphData.glyph && | |
| 172 Character::treatAsZeroWidthSpace(charData.character)) { | |
| 173 charData.character = spaceCharacter; | |
| 174 glyphData = glyphDataForCharacter(charData); | |
| 175 width = 0; | |
| 176 spaceUsedAsZeroWidthSpace = true; | |
| 177 } else { | |
| 178 width = characterWidth(charData.character, glyphData); | |
| 179 } | |
| 180 | |
| 181 Glyph glyph = glyphData.glyph; | |
| 182 const SimpleFontData* fontData = glyphData.fontData; | |
| 183 ASSERT(fontData); | |
| 184 | |
| 185 if (m_fallbackFonts && lastFontData != fontData && width) { | |
| 186 lastFontData = fontData; | |
| 187 trackNonPrimaryFallbackFont(fontData); | |
| 188 } | |
| 189 | |
| 190 if (hasExtraSpacing && !spaceUsedAsZeroWidthSpace) | |
| 191 width = adjustSpacing(width, charData); | |
| 192 | |
| 193 if (m_glyphBoundingBox) { | |
| 194 ASSERT(glyphData.fontData); | |
| 195 FloatRect glyphBounds = | |
| 196 glyphData.fontData->boundsForGlyph(glyphData.glyph); | |
| 197 // We are handling simple text run here, so Y-Offset will be zero. | |
| 198 // FIXME: Computing bounds relative to the initial advance seems odd. Are | |
| 199 // we adjusting these someplace else? If not, we'll end up with different | |
| 200 // bounds depending on how we segment our advance() calls. | |
| 201 glyphBounds.move(m_runWidthSoFar - initialRunWidth, 0); | |
| 202 m_glyphBoundingBox->unite(glyphBounds); | |
| 203 } | |
| 204 | |
| 205 if (glyphBuffer) { | |
| 206 if (!forTextEmphasis()) { | |
| 207 glyphBuffer->add(glyph, fontData, m_runWidthSoFar); | |
| 208 } else if (Character::canReceiveTextEmphasis(charData.character)) { | |
| 209 addEmphasisMark(glyphBuffer, m_runWidthSoFar + width / 2); | |
| 210 } | |
| 211 } | |
| 212 | |
| 213 // Advance past the character we just dealt with. | |
| 214 textIterator.advance(); | |
| 215 m_runWidthSoFar += width; | |
| 216 } | |
| 217 | |
| 218 unsigned consumedCharacters = textIterator.offset() - m_currentCharacter; | |
| 219 m_currentCharacter = textIterator.offset(); | |
| 220 | |
| 221 return consumedCharacters; | |
| 222 } | |
| 223 | |
| 224 unsigned SimpleShaper::advance(int offset, GlyphBuffer* glyphBuffer) { | |
| 225 int length = m_textRun.length(); | |
| 226 | |
| 227 if (offset > length) | |
| 228 offset = length; | |
| 229 | |
| 230 if (m_currentCharacter >= static_cast<unsigned>(offset)) | |
| 231 return 0; | |
| 232 | |
| 233 if (m_textRun.is8Bit()) { | |
| 234 Latin1TextIterator textIterator(m_textRun.data8(m_currentCharacter), | |
| 235 m_currentCharacter, offset); | |
| 236 return advanceInternal(textIterator, glyphBuffer); | |
| 237 } | |
| 238 | |
| 239 UTF16TextIterator textIterator(m_textRun.data16(m_currentCharacter), | |
| 240 m_currentCharacter, offset, length); | |
| 241 return advanceInternal(textIterator, glyphBuffer); | |
| 242 } | |
| 243 | |
| 244 bool SimpleShaper::advanceOneCharacter(float& width) { | |
| 245 float initialWidth = m_runWidthSoFar; | |
| 246 | |
| 247 if (!advance(m_currentCharacter + 1)) | |
| 248 return false; | |
| 249 | |
| 250 width = m_runWidthSoFar - initialWidth; | |
| 251 return true; | |
| 252 } | |
| 253 | |
| 254 } // namespace blink | |
| OLD | NEW |