Changeset 23154 in webkit
- Timestamp:
- Mar 21, 2007 4:37:42 PM (17 years ago)
- Location:
- branches/WindowsMerge/WebCore
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/WindowsMerge/WebCore/ChangeLog
r23137 r23154 1 2007-03-21 Dave Hyatt <hyatt@apple.com> 2 3 Fix numerous bugs in RTL support. Only use a directional override if the run 4 tells us to. Uniscribe will give incorrect results when measuring RTL runs as LTR if the 5 directional override is set. Switch from logical order for glyphs to visual order 6 instead. This is more similar to ATSUI (less similar to the fast code path, which always uses 7 logical ordering for glyph generation). Using visual ordering forces a lot of games to be played 8 (have to walk the script items in backwards order for RTL for example), but Uniscribe does not combine 9 glyphs properly if visual ordering is not used. 10 11 Add support for justification, letter-spacing, word-spacing and rounding hacks. The CG vs. ATSUI layout 12 test now passes with identical results to the Mac. The ATSUI spacing features layout test now 13 generates correct results (although they are different from the Mac because we fall back to Arial for 14 Hebrew instead of Lucida Grande). 15 16 Reviewed by NOBODY (OOPS!). 17 18 WARNING: NO TEST CASES ADDED OR CHANGED 19 20 * platform/win/UniscribeController.cpp: 21 (WebCore::UniscribeController::UniscribeController): 22 (WebCore::UniscribeController::resetControlAndState): 23 (WebCore::UniscribeController::shapeAndPlaceItem): 24 (WebCore::UniscribeController::shape): 25 * platform/win/UniscribeController.h: 26 1 27 2007-03-20 Adam Roben <aroben@apple.com> 2 28 -
branches/WindowsMerge/WebCore/platform/win/UniscribeController.cpp
r23128 r23154 36 36 namespace WebCore { 37 37 38 // FIXME: Rearchitect this to be more like WidthIterator in Font.cpp. Have an advance() method 39 // that does stuff in that method instead of doing everything in the constructor. Have advance() 40 // take the GlyphBuffer as an arg so that we don't have to populate the glyph buffer when 41 // measuring. 38 42 UniscribeController::UniscribeController(const Font* font, const TextRun& run, const TextStyle& style, 39 43 GraphicsContext* graphicsContext) … … 44 48 , m_width(0) 45 49 { 50 m_padding = m_style.padding(); 51 if (!m_padding) 52 m_padPerSpace = 0; 53 else { 54 float numSpaces = 0; 55 for (int s = 0; s < m_run.length(); s++) 56 if (Font::treatAsSpace(m_run[s])) 57 numSpaces++; 58 59 if (numSpaces == 0) 60 m_padPerSpace = 0; 61 else 62 m_padPerSpace = ceilf(m_style.padding() / numSpaces); 63 } 64 46 65 // Null out our uniscribe structs 47 66 resetControlAndState(); … … 63 82 m_items.resize(numItems + 1); 64 83 65 for (unsigned i = 0; i < m_items.size() - 1; i++) 66 shapeAndPlaceItem(i); 84 if (m_style.rtl()) { 85 for (int i = m_items.size() - 2; i >= 0; i--) 86 shapeAndPlaceItem(i); 87 } else { 88 for (unsigned i = 0; i < m_items.size() - 1; i++) 89 shapeAndPlaceItem(i); 90 } 67 91 } 68 92 … … 75 99 m_state.uBidiLevel = m_style.rtl(); 76 100 77 // Lock the correct directional override. This is much simpler than ATSUI. We don't 78 // need to access style.directionalOverride(), since Uniscribe just supports an absolute 79 // override. 80 m_state.fOverrideDirection = true; 101 // Lock the correct directional override. 102 m_state.fOverrideDirection = m_style.directionalOverride(); 81 103 } 82 104 … … 113 135 if (shape(str, len, item, fontData, glyphs, clusters, visualAttributes)) 114 136 break; 115 else { 116 // Try again with the next font in the list. 117 if (lastResortFontTried) { 118 fontData = 0; 119 break; 120 } else { 121 fontData = m_font.fontDataAt(++dataIndex); 122 if (!fontData) { 123 // Out of fonts. Get a font data based on the actual characters. 124 fontData = m_font.fontDataForCharacters(str, len); 125 lastResortFontTried = true; 126 } 127 } 137 138 // Try again with the next font in the list. 139 if (lastResortFontTried) { 140 fontData = 0; 141 break; 142 } 143 144 fontData = m_font.fontDataAt(++dataIndex); 145 if (!fontData) { 146 // Out of fonts. Get a font data based on the actual characters. 147 fontData = m_font.fontDataForCharacters(str, len); 148 lastResortFontTried = true; 128 149 } 129 150 } … … 157 178 } 158 179 159 if (FAILED(placeResult) )180 if (FAILED(placeResult) || glyphs.isEmpty()) 160 181 return; 161 182 183 // Convert all chars that should be treated as spaces to use the space glyph. 184 // We also create a map that allows us to quickly go from space glyphs or rounding 185 // hack glyphs back to their corresponding characters. 186 Vector<int> spaceCharacters(glyphs.size()); 187 spaceCharacters.fill(-1); 188 Vector<int> roundingHackCharacters(glyphs.size()); 189 roundingHackCharacters.fill(-1); 190 Vector<int> roundingHackWordBoundaries(glyphs.size()); 191 roundingHackWordBoundaries.fill(-1); 192 unsigned logicalSpaceWidth = fontData->m_spaceWidth * 32.0f; 193 float roundedSpaceWidth = roundf(fontData->m_spaceWidth); 194 195 unsigned k; 196 for (k = 0; k < len; k++) { 197 UChar ch = *(str + k); 198 if (Font::treatAsSpace(ch)) { 199 // Substitute in the space glyph at the appropriate place in the glyphs 200 // array. 201 glyphs[clusters[k]] = fontData->m_spaceGlyph; 202 advances[clusters[k]] = logicalSpaceWidth; 203 spaceCharacters[clusters[k]] = k + m_items[i].iCharPos; 204 } 205 206 if (Font::isRoundingHackCharacter(ch)) 207 roundingHackCharacters[clusters[k]] = k + m_items[i].iCharPos; 208 209 if (k + m_items[i].iCharPos < m_run.length() && 210 Font::isRoundingHackCharacter(*(str + k + 1))) 211 roundingHackWordBoundaries[clusters[k]] = k + m_items[i].iCharPos; 212 } 213 162 214 // Populate our glyph buffer with this information. 163 for (unsigned i = 0; i < glyphs.size(); i++) { 164 Glyph glyph = glyphs[i]; 165 float advance = advances[i] / 32.0f; 215 bool hasExtraSpacing = m_font.letterSpacing() || m_font.wordSpacing() || m_padding; 216 217 for (k = 0; k < glyphs.size(); k++) { 218 Glyph glyph = glyphs[k]; 219 float advance = advances[k] / 32.0f; 220 221 // Match AppKit's rules for the integer vs. non-integer rendering modes. 222 float roundedAdvance = roundf(advance); 166 223 if (!m_font.isPrinterFont() && !fontData->isSystemFont()) 167 advance = lroundf(advance); 168 GOFFSET offset = offsets[i]; // FIXME: What the heck do i do with this? 224 advance = roundedAdvance; 225 226 // We special case spaces in two ways when applying word rounding. 227 // First, we round spaces to an adjusted width in all fonts. 228 // Second, in fixed-pitch fonts we ensure that all glyphs that 229 // match the width of the space glyph have the same width as the space glyph. 230 if (roundedAdvance == roundedSpaceWidth && (fontData->m_treatAsFixedPitch || glyph == fontData->m_spaceGlyph) && 231 m_style.applyWordRounding()) 232 advance = fontData->m_adjustedSpaceWidth; 233 234 if (hasExtraSpacing) { 235 // If we're a glyph with an advance, go ahead and add in letter-spacing. 236 // That way we weed out zero width lurkers. This behavior matches the fast text code path. 237 if (advance && m_font.letterSpacing()) 238 advance += m_font.letterSpacing(); 239 240 // Handle justification and word-spacing. 241 if (glyph == fontData->m_spaceGlyph) { 242 // Account for padding. WebCore uses space padding to justify text. 243 // We distribute the specified padding over the available spaces in the run. 244 if (m_padding) { 245 // Use leftover padding if not evenly divisible by number of spaces. 246 if (m_padding < m_padPerSpace) { 247 advance += m_padding; 248 m_padding = 0; 249 } else { 250 advance += m_padPerSpace; 251 m_padding -= m_padPerSpace; 252 } 253 } 254 255 // Account for word-spacing. 256 int characterIndex = spaceCharacters[k]; 257 if (characterIndex > 0 && !Font::treatAsSpace(m_run.characters()[characterIndex-1]) && m_font.wordSpacing()) 258 advance += m_font.wordSpacing(); 259 } 260 } 261 262 // Deal with the float/integer impedance mismatch between CG and WebCore. "Words" (characters 263 // followed by a character defined by isRoundingHackCharacter()) are always an integer width. 264 // We adjust the width of the last character of a "word" to ensure an integer width. 265 // Force characters that are used to determine word boundaries for the rounding hack 266 // to be integer width, so the following words will start on an integer boundary. 267 int roundingHackIndex = roundingHackCharacters[k]; 268 if (m_style.applyWordRounding() && roundingHackIndex != -1) 269 advance = ceilf(advance); 270 271 // Check to see if the next character is a "rounding hack character", if so, adjust the 272 // width so that the total run width will be on an integer boundary. 273 bool lastGlyph = (k == glyphs.size() - 1) && (m_style.rtl() ? i == 0 : i == m_items.size() - 2); // FIXME: This won't always be correct once we support m_run.to(). 274 if ((m_style.applyWordRounding() && roundingHackWordBoundaries[k] != -1) || 275 (m_style.applyRunRounding() && lastGlyph)) { 276 float totalWidth = m_width + advance; 277 advance += ceilf(totalWidth) - totalWidth; 278 } 279 169 280 m_width += advance; 281 282 // FIXME: We need to take the GOFFSETS for combining glyphs and store them in the glyph buffer 283 // as well, so that when the time comes to draw those glyphs, we can apply the appropriate 284 // translation. 170 285 m_glyphBuffer.add(glyph, fontData, advance); 171 286 } 172 173 // Swap the order of the glyphs if right-to-left.174 if (m_style.rtl())175 for (int j = 0, end = m_glyphBuffer.size() - 1; j < m_glyphBuffer.size() / 2; ++j, --end)176 m_glyphBuffer.swap(j, end);177 287 } 178 288 … … 186 296 int glyphCount = 0; 187 297 do { 188 item.a.fLogicalOrder = true;189 298 shapeResult = ScriptShape(hdc, fontData->scriptCache(), str, len, glyphs.size(), &item.a, 190 299 glyphs.data(), clusters.data(), visualAttributes.data(), &glyphCount); -
branches/WindowsMerge/WebCore/platform/win/UniscribeController.h
r23128 r23154 66 66 float m_width; 67 67 GlyphBuffer m_glyphBuffer; 68 69 float m_padding; 70 float m_padPerSpace; 68 71 }; 69 72
Note: See TracChangeset
for help on using the changeset viewer.