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 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 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 "FontGlyphs.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 46#include <windows.h> 47 48using namespace WTF::Unicode; 49 50namespace WebCore { 51 52HDC g_screenDC = GetDC(0); 53 54class ScreenDcReleaser { 55public: 56 ~ScreenDcReleaser() 57 { 58 ReleaseDC(0, g_screenDC); 59 } 60}; 61 62ScreenDcReleaser releaseScreenDc; 63 64void Font::drawGlyphs(GraphicsContext* graphicsContext, const SimpleFontData* fontData, const GlyphBuffer& glyphBuffer, 65 int from, int numGlyphs, const FloatPoint& point) const 66{ 67 graphicsContext->drawText(fontData, glyphBuffer, from, numGlyphs, point); 68} 69 70class TextRunComponent { 71public: 72 TextRunComponent() : m_textRun(0, 0) {} 73 TextRunComponent(const UChar *start, int length, const TextRun& parentTextRun, const Font &font, int offset); 74 TextRunComponent(int spaces, const Font &font, int offset); 75 ~TextRunComponent() { m_textRun; } 76 77 bool isSpace() const { return m_spaces; } 78 int textLength() const { return m_spaces ? m_spaces : m_textRun.length(); } 79 80 TextRun m_textRun; 81 float m_width; 82 int m_offset; 83 int m_spaces; 84}; 85 86TextRunComponent::TextRunComponent(const UChar *start, int length, const TextRun& parentTextRun, const Font &font, int o) 87 : m_textRun(start, length, 0, 0 88 , parentTextRun.allowsTrailingExpansion() ? TextRun::AllowTrailingExpansion : TextRun::ForbidTrailingExpansion 89 , parentTextRun.direction() 90 , parentTextRun.directionalOverride()) 91 , m_offset(o) 92 , m_spaces(0) 93{ 94 m_textRun.setTabSize(parentTextRun.allowTabs(), parentTextRun.tabSize()); 95 96 WidthIterator it(&font, m_textRun); 97 it.advance(m_textRun.length(), 0); 98 m_width = it.m_runWidthSoFar; 99} 100 101TextRunComponent::TextRunComponent(int s, const Font &font, int o) 102 : m_textRun(0, 0) 103 , m_offset(o) 104 , m_spaces(s) 105{ 106 m_width = s * font.primaryFont()->widthForGlyph(' '); 107} 108 109typedef Vector<TextRunComponent, 128> TextRunComponents; 110 111static int generateComponents(TextRunComponents* components, const Font &font, const TextRun &run) 112{ 113 int letterSpacing = font.letterSpacing(); 114 int wordSpacing = font.wordSpacing(); 115 int padding = run.expansion(); 116 int numSpaces = 0; 117 if (padding) { 118 for (int i = 0; i < run.length(); i++) 119 if (Font::treatAsSpace(run[i])) 120 ++numSpaces; 121 } 122 123 int offset = 0; 124 if (letterSpacing) { 125 // need to draw every letter on it's own 126 int start = 0; 127 if (Font::treatAsSpace(run[0])) { 128 int add = 0; 129 if (numSpaces) { 130 add = padding/numSpaces; 131 padding -= add; 132 --numSpaces; 133 } 134 components->append(TextRunComponent(1, font, offset)); 135 offset += add + letterSpacing + components->last().m_width; 136 start = 1; 137 } 138 for (int i = 1; i < run.length(); ++i) { 139 UChar ch = run[i]; 140 if (U16_IS_LEAD(ch) && U16_IS_TRAIL(run[i-1])) 141 ch = U16_GET_SUPPLEMENTARY(ch, run[i-1]); 142 if (U16_IS_TRAIL(ch) || U_GET_GC_MASK(ch) & U_GC_MN_MASK) 143 continue; 144 if (Font::treatAsSpace(run[i])) { 145 int add = 0; 146 if (i - start > 0) { 147 components->append(TextRunComponent(run.characters16() + start, i - start, 148 run, font, offset)); 149 offset += components->last().m_width + letterSpacing; 150 } 151 if (numSpaces) { 152 add = padding/numSpaces; 153 padding -= add; 154 --numSpaces; 155 } 156 components->append(TextRunComponent(1, font, offset)); 157 offset += wordSpacing + add + components->last().m_width + letterSpacing; 158 start = i + 1; 159 continue; 160 } 161 if (i - start > 0) { 162 components->append(TextRunComponent(run.characters16() + start, i - start, 163 run, 164 font, offset)); 165 offset += components->last().m_width + letterSpacing; 166 } 167 start = i; 168 } 169 if (run.length() - start > 0) { 170 components->append(TextRunComponent(run.characters16() + start, run.length() - start, 171 run, 172 font, offset)); 173 offset += components->last().m_width; 174 } 175 offset += letterSpacing; 176 } else { 177 int start = 0; 178 for (int i = 0; i < run.length(); ++i) { 179 if (Font::treatAsSpace(run[i])) { 180 if (i - start > 0) { 181 components->append(TextRunComponent(run.characters16() + start, i - start, 182 run, 183 font, offset)); 184 offset += components->last().m_width; 185 } 186 int add = 0; 187 if (numSpaces) { 188 add = padding/numSpaces; 189 padding -= add; 190 --numSpaces; 191 } 192 components->append(TextRunComponent(1, font, offset)); 193 offset += add + components->last().m_width; 194 if (i) 195 offset += wordSpacing; 196 start = i + 1; 197 } 198 } 199 if (run.length() - start > 0) { 200 components->append(TextRunComponent(run.characters16() + start, run.length() - start, 201 run, 202 font, offset)); 203 offset += components->last().m_width; 204 } 205 } 206 return offset; 207} 208 209float Font::drawComplexText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, 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 float widthOfDrawnText = 0; 220 int curPos = 0; 221 for (int i = 0; i < (int)components.size(); ++i) { 222 const TextRunComponent& comp = components.at(i); 223 int len = comp.textLength(); 224 int curEnd = curPos + len; 225 if (curPos < to && from < curEnd && !comp.isSpace()) { 226 FloatPoint pt = point; 227 if (run.rtl()) 228 pt.setX(point.x() + w - comp.m_offset - comp.m_width); 229 else 230 pt.setX(point.x() + comp.m_offset); 231 widthOfDrawnText += drawSimpleText(context, comp.m_textRun, pt, from - curPos, std::min(to, curEnd) - curPos); 232 } 233 curPos += len; 234 if (from < curPos) 235 from = curPos; 236 } 237 return widthOfDrawnText; 238} 239 240void Font::drawEmphasisMarksForComplexText(GraphicsContext* /* context */, const TextRun& /* run */, const AtomicString& /* mark */, const FloatPoint& /* point */, int /* from */, int /* to */) const 241{ 242 notImplemented(); 243} 244 245float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const 246{ 247 TextRunComponents components; 248 int w = generateComponents(&components, *this, run); 249 return w; 250} 251 252int Font::offsetForPositionForComplexText(const TextRun& run, float xFloat, bool includePartialGlyphs) const 253{ 254 // FIXME: This truncation is not a problem for HTML, but only affects SVG, which passes floating-point numbers 255 // to Font::offsetForPosition(). Bug http://webkit.org/b/40673 tracks fixing this problem. 256 int position = static_cast<int>(xFloat); 257 258 TextRunComponents components; 259 int w = generateComponents(&components, *this, run); 260 261 if (position >= w) 262 return run.length(); 263 264 int offset = 0; 265 if (run.rtl()) { 266 for (size_t i = 0; i < components.size(); ++i) { 267 const TextRunComponent& comp = components.at(i); 268 int xe = w - comp.m_offset; 269 int xs = xe - comp.m_width; 270 if (position >= xs) 271 return offset + (comp.isSpace() 272 ? static_cast<int>((position - xe) * comp.m_spaces / std::max(1.f, comp.m_width) + 0.5) 273 : offsetForPositionForSimpleText(comp.m_textRun, position - xs, includePartialGlyphs)); 274 275 offset += comp.textLength(); 276 } 277 } else { 278 for (size_t i = 0; i < components.size(); ++i) { 279 const TextRunComponent& comp = components.at(i); 280 int xs = comp.m_offset; 281 int xe = xs + comp.m_width; 282 if (position <= xe) { 283 if (position - xs >= xe) 284 return offset + comp.textLength(); 285 return offset + (comp.isSpace() 286 ? static_cast<int>((position - xs) * comp.m_spaces / std::max(1.f, comp.m_width) + 0.5) 287 : offsetForPositionForSimpleText(comp.m_textRun, position - xs, includePartialGlyphs)); 288 } 289 offset += comp.textLength(); 290 } 291 } 292 return run.length(); 293} 294 295 296static float cursorToX(const Font* font, const TextRunComponents& components, int width, bool rtl, int cursor) 297{ 298 int start = 0; 299 for (size_t i = 0; i < components.size(); ++i) { 300 const TextRunComponent& comp = components.at(i); 301 if (start + comp.textLength() <= cursor) { 302 start += comp.textLength(); 303 continue; 304 } 305 int xs = comp.m_offset; 306 if (rtl) 307 xs = width - xs - comp.m_width; 308 309 int pos = cursor - start; 310 if (comp.isSpace()) { 311 if (rtl) 312 pos = comp.textLength() - pos; 313 return xs + pos * comp.m_width / comp.m_spaces; 314 } 315 WidthIterator it(font, comp.m_textRun); 316 GlyphBuffer glyphBuffer; 317 it.advance(pos, &glyphBuffer); 318 return xs + it.m_runWidthSoFar; 319 } 320 return width; 321} 322 323FloatRect Font::selectionRectForComplexText(const TextRun& run, const FloatPoint& pt, 324 int h, int from, int to) const 325{ 326 TextRunComponents components; 327 int w = generateComponents(&components, *this, run); 328 329 if (!from && to == run.length()) 330 return FloatRect(pt.x(), pt.y(), w, h); 331 332 float x1 = cursorToX(this, components, w, run.rtl(), from); 333 float x2 = cursorToX(this, components, w, run.rtl(), to); 334 if (x2 < x1) 335 std::swap(x1, x2); 336 337 return FloatRect(pt.x() + x1, pt.y(), x2 - x1, h); 338} 339 340bool Font::canReturnFallbackFontsForComplexText() 341{ 342 return false; 343} 344 345bool Font::canExpandAroundIdeographsInComplexText() 346{ 347 return false; 348} 349 350} // namespace WebCore 351