1 /* 2 * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. 3 * Copyright (C) 2007-2009 Torch Mobile, Inc. 4 * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) 5 * Copyright (C) 2008 Holger Hans Peter Freyther 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY 17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 20 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 21 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 22 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 23 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 24 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include "config.h" 30 #include "Font.h" 31 32 #include "AffineTransform.h" 33 #include "FloatRect.h" 34 #include "FontCache.h" 35 #include "FontData.h" 36 #include "FontFallbackList.h" 37 #include "GlyphBuffer.h" 38 #include "GraphicsContext.h" 39 #include "IntRect.h" 40 #include "NotImplemented.h" 41 #include "TextRun.h" 42 #include "WidthIterator.h" 43 #include <wtf/MathExtras.h> 44 #include <wtf/OwnPtr.h> 45 #include <wtf/unicode/Unicode.h> 46 47 #include <windows.h> 48 49 using namespace WTF::Unicode; 50 51 namespace WebCore { 52 53 HDC g_screenDC = GetDC(0); 54 55 class ScreenDcReleaser { 56 public: 57 ~ScreenDcReleaser() 58 { 59 ReleaseDC(0, g_screenDC); 60 } 61 }; 62 63 ScreenDcReleaser releaseScreenDc; 64 65 void Font::drawGlyphs(GraphicsContext* graphicsContext, const SimpleFontData* fontData, const GlyphBuffer& glyphBuffer, 66 int from, int numGlyphs, const FloatPoint& point) const 67 { 68 graphicsContext->drawText(fontData, glyphBuffer, from, numGlyphs, point); 69 } 70 71 class TextRunComponent { 72 public: 73 TextRunComponent() : m_textRun(0, 0) {} 74 TextRunComponent(const UChar *start, int length, const TextRun& parentTextRun, const Font &font, int offset); 75 TextRunComponent(int spaces, const Font &font, int offset); 76 ~TextRunComponent() { m_textRun; } 77 78 bool isSpace() const { return m_spaces; } 79 int textLength() const { return m_spaces ? m_spaces : m_textRun.length(); } 80 81 TextRun m_textRun; 82 float m_width; 83 int m_offset; 84 int m_spaces; 85 }; 86 87 TextRunComponent::TextRunComponent(const UChar *start, int length, const TextRun& parentTextRun, const Font &font, int o) 88 : m_textRun(start, length, parentTextRun.allowTabs(), 0, 0 89 , parentTextRun.allowsTrailingExpansion() ? TextRun::AllowTrailingExpansion : TextRun::ForbidTrailingExpansion 90 , parentTextRun.rtl() 91 , parentTextRun.directionalOverride()) 92 , m_offset(o) 93 , m_spaces(0) 94 { 95 WidthIterator it(&font, m_textRun); 96 it.advance(m_textRun.length(), 0); 97 m_width = it.m_runWidthSoFar; 98 } 99 100 TextRunComponent::TextRunComponent(int s, const Font &font, int o) 101 : m_textRun(0, 0) 102 , m_offset(o) 103 , m_spaces(s) 104 { 105 m_width = s * font.primaryFont()->widthForGlyph(' '); 106 } 107 108 typedef Vector<TextRunComponent, 128> TextRunComponents; 109 110 static int generateComponents(TextRunComponents* components, const Font &font, const TextRun &run) 111 { 112 int letterSpacing = font.letterSpacing(); 113 int wordSpacing = font.wordSpacing(); 114 int padding = run.expansion(); 115 int numSpaces = 0; 116 if (padding) { 117 for (int i = 0; i < run.length(); i++) 118 if (Font::treatAsSpace(run[i])) 119 ++numSpaces; 120 } 121 122 int offset = 0; 123 if (letterSpacing) { 124 // need to draw every letter on it's own 125 int start = 0; 126 if (Font::treatAsSpace(run[0])) { 127 int add = 0; 128 if (numSpaces) { 129 add = padding/numSpaces; 130 padding -= add; 131 --numSpaces; 132 } 133 components->append(TextRunComponent(1, font, offset)); 134 offset += add + letterSpacing + components->last().m_width; 135 start = 1; 136 } 137 for (int i = 1; i < run.length(); ++i) { 138 uint ch = run[i]; 139 if (isHighSurrogate(ch) && isLowSurrogate(run[i-1])) 140 ch = surrogateToUcs4(ch, run[i-1]); 141 if (isLowSurrogate(ch) || category(ch) == Mark_NonSpacing) 142 continue; 143 if (Font::treatAsSpace(run[i])) { 144 int add = 0; 145 if (i - start > 0) { 146 components->append(TextRunComponent(run.characters() + start, i - start, 147 run, font, offset)); 148 offset += components->last().m_width + letterSpacing; 149 } 150 if (numSpaces) { 151 add = padding/numSpaces; 152 padding -= add; 153 --numSpaces; 154 } 155 components->append(TextRunComponent(1, font, offset)); 156 offset += wordSpacing + add + components->last().m_width + letterSpacing; 157 start = i + 1; 158 continue; 159 } 160 if (i - start > 0) { 161 components->append(TextRunComponent(run.characters() + start, i - start, 162 run, 163 font, offset)); 164 offset += components->last().m_width + letterSpacing; 165 } 166 start = i; 167 } 168 if (run.length() - start > 0) { 169 components->append(TextRunComponent(run.characters() + start, run.length() - start, 170 run, 171 font, offset)); 172 offset += components->last().m_width; 173 } 174 offset += letterSpacing; 175 } else { 176 int start = 0; 177 for (int i = 0; i < run.length(); ++i) { 178 if (Font::treatAsSpace(run[i])) { 179 if (i - start > 0) { 180 components->append(TextRunComponent(run.characters() + start, i - start, 181 run, 182 font, offset)); 183 offset += components->last().m_width; 184 } 185 int add = 0; 186 if (numSpaces) { 187 add = padding/numSpaces; 188 padding -= add; 189 --numSpaces; 190 } 191 components->append(TextRunComponent(1, font, offset)); 192 offset += add + components->last().m_width; 193 if (i) 194 offset += wordSpacing; 195 start = i + 1; 196 } 197 } 198 if (run.length() - start > 0) { 199 components->append(TextRunComponent(run.characters() + start, run.length() - start, 200 run, 201 font, offset)); 202 offset += components->last().m_width; 203 } 204 } 205 return offset; 206 } 207 208 void Font::drawComplexText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, 209 int from, int to) const 210 { 211 if (to < 0) 212 to = run.length(); 213 if (from < 0) 214 from = 0; 215 216 TextRunComponents components; 217 int w = generateComponents(&components, *this, run); 218 219 int curPos = 0; 220 for (int i = 0; i < (int)components.size(); ++i) { 221 const TextRunComponent& comp = components.at(i); 222 int len = comp.textLength(); 223 int curEnd = curPos + len; 224 if (curPos < to && from < curEnd && !comp.isSpace()) { 225 FloatPoint pt = point; 226 if (run.rtl()) 227 pt.setX(point.x() + w - comp.m_offset - comp.m_width); 228 else 229 pt.setX(point.x() + comp.m_offset); 230 drawSimpleText(context, comp.m_textRun, pt, from - curPos, std::min(to, curEnd) - curPos); 231 } 232 curPos += len; 233 if (from < curPos) 234 from = curPos; 235 } 236 } 237 238 void Font::drawEmphasisMarksForComplexText(GraphicsContext* /* context */, const TextRun& /* run */, const AtomicString& /* mark */, const FloatPoint& /* point */, int /* from */, int /* to */) const 239 { 240 notImplemented(); 241 } 242 243 float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const 244 { 245 TextRunComponents components; 246 int w = generateComponents(&components, *this, run); 247 return w; 248 } 249 250 int Font::offsetForPositionForComplexText(const TextRun& run, float xFloat, bool includePartialGlyphs) const 251 { 252 // FIXME: This truncation is not a problem for HTML, but only affects SVG, which passes floating-point numbers 253 // to Font::offsetForPosition(). Bug http://webkit.org/b/40673 tracks fixing this problem. 254 int position = static_cast<int>(xFloat); 255 256 TextRunComponents components; 257 int w = generateComponents(&components, *this, run); 258 259 if (position >= w) 260 return run.length(); 261 262 int offset = 0; 263 if (run.rtl()) { 264 for (size_t i = 0; i < components.size(); ++i) { 265 const TextRunComponent& comp = components.at(i); 266 int xe = w - comp.m_offset; 267 int xs = xe - comp.m_width; 268 if (position >= xs) 269 return offset + (comp.isSpace() 270 ? static_cast<int>((position - xe) * comp.m_spaces / std::max(1.f, comp.m_width) + 0.5) 271 : offsetForPositionForSimpleText(comp.m_textRun, position - xs, includePartialGlyphs)); 272 273 offset += comp.textLength(); 274 } 275 } else { 276 for (size_t i = 0; i < components.size(); ++i) { 277 const TextRunComponent& comp = components.at(i); 278 int xs = comp.m_offset; 279 int xe = xs + comp.m_width; 280 if (position <= xe) { 281 if (position - xs >= xe) 282 return offset + comp.textLength(); 283 return offset + (comp.isSpace() 284 ? static_cast<int>((position - xs) * comp.m_spaces / std::max(1.f, comp.m_width) + 0.5) 285 : offsetForPositionForSimpleText(comp.m_textRun, position - xs, includePartialGlyphs)); 286 } 287 offset += comp.textLength(); 288 } 289 } 290 return run.length(); 291 } 292 293 294 static float cursorToX(const Font* font, const TextRunComponents& components, int width, bool rtl, int cursor) 295 { 296 int start = 0; 297 for (size_t i = 0; i < components.size(); ++i) { 298 const TextRunComponent& comp = components.at(i); 299 if (start + comp.textLength() <= cursor) { 300 start += comp.textLength(); 301 continue; 302 } 303 int xs = comp.m_offset; 304 if (rtl) 305 xs = width - xs - comp.m_width; 306 307 int pos = cursor - start; 308 if (comp.isSpace()) { 309 if (rtl) 310 pos = comp.textLength() - pos; 311 return xs + pos * comp.m_width / comp.m_spaces; 312 } 313 WidthIterator it(font, comp.m_textRun); 314 it.advance(pos); 315 return xs + it.m_runWidthSoFar; 316 } 317 return width; 318 } 319 320 FloatRect Font::selectionRectForComplexText(const TextRun& run, const FloatPoint& pt, 321 int h, int from, int to) const 322 { 323 TextRunComponents components; 324 int w = generateComponents(&components, *this, run); 325 326 if (!from && to == run.length()) 327 return FloatRect(pt.x(), pt.y(), w, h); 328 329 float x1 = cursorToX(this, components, w, run.rtl(), from); 330 float x2 = cursorToX(this, components, w, run.rtl(), to); 331 if (x2 < x1) 332 std::swap(x1, x2); 333 334 return FloatRect(pt.x() + x1, pt.y(), x2 - x1, h); 335 } 336 337 bool Font::canReturnFallbackFontsForComplexText() 338 { 339 return false; 340 } 341 342 bool Font::canExpandAroundIdeographsInComplexText() 343 { 344 return false; 345 } 346 347 } // namespace WebCore 348