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 "WidthIterator.h" 42#include <wtf/MathExtras.h> 43#include <wtf/OwnPtr.h> 44#include <wtf/unicode/Unicode.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, parentTextRun.allowTabs(), 0, 0 88 , parentTextRun.rtl() 89 , parentTextRun.directionalOverride() 90 , parentTextRun.applyRunRounding() 91 , parentTextRun.applyWordRounding()) 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 100TextRunComponent::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 108typedef Vector<TextRunComponent, 128> TextRunComponents; 109 110static 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.padding(); 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 208void 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 238float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts) const 239{ 240 TextRunComponents components; 241 int w = generateComponents(&components, *this, run); 242 return w; 243} 244 245int Font::offsetForPositionForComplexText(const TextRun& run, int position, bool includePartialGlyphs) const 246{ 247 TextRunComponents components; 248 int w = generateComponents(&components, *this, run); 249 250 if (position >= w) 251 return run.length(); 252 253 int offset = 0; 254 if (run.rtl()) { 255 for (size_t i = 0; i < components.size(); ++i) { 256 const TextRunComponent& comp = components.at(i); 257 int xe = w - comp.m_offset; 258 int xs = xe - comp.m_width; 259 if (position >= xs) 260 return offset + (comp.isSpace() 261 ? static_cast<int>((position - xe) * comp.m_spaces / std::max(1.f, comp.m_width) + 0.5) 262 : offsetForPositionForSimpleText(comp.m_textRun, position - xs, includePartialGlyphs)); 263 264 offset += comp.textLength(); 265 } 266 } else { 267 for (size_t i = 0; i < components.size(); ++i) { 268 const TextRunComponent& comp = components.at(i); 269 int xs = comp.m_offset; 270 int xe = xs + comp.m_width; 271 if (position <= xe) { 272 if (position - xs >= xe) 273 return offset + comp.textLength(); 274 return offset + (comp.isSpace() 275 ? static_cast<int>((position - xs) * comp.m_spaces / std::max(1.f, comp.m_width) + 0.5) 276 : offsetForPositionForSimpleText(comp.m_textRun, position - xs, includePartialGlyphs)); 277 } 278 offset += comp.textLength(); 279 } 280 } 281 return run.length(); 282} 283 284 285static float cursorToX(const Font* font, const TextRunComponents& components, int width, bool rtl, int cursor) 286{ 287 int start = 0; 288 for (size_t i = 0; i < components.size(); ++i) { 289 const TextRunComponent& comp = components.at(i); 290 if (start + comp.textLength() <= cursor) { 291 start += comp.textLength(); 292 continue; 293 } 294 int xs = comp.m_offset; 295 if (rtl) 296 xs = width - xs - comp.m_width; 297 298 int pos = cursor - start; 299 if (comp.isSpace()) { 300 if (rtl) 301 pos = comp.textLength() - pos; 302 return xs + pos * comp.m_width / comp.m_spaces; 303 } 304 WidthIterator it(font, comp.m_textRun); 305 it.advance(pos); 306 return xs + it.m_runWidthSoFar; 307 } 308 return width; 309} 310 311FloatRect Font::selectionRectForComplexText(const TextRun& run, const IntPoint& pt, 312 int h, int from, int to) const 313{ 314 TextRunComponents components; 315 int w = generateComponents(&components, *this, run); 316 317 if (!from && to == run.length()) 318 return FloatRect(pt.x(), pt.y(), w, h); 319 320 float x1 = cursorToX(this, components, w, run.rtl(), from); 321 float x2 = cursorToX(this, components, w, run.rtl(), to); 322 if (x2 < x1) 323 std::swap(x1, x2); 324 325 return FloatRect(pt.x() + x1, pt.y(), x2 - x1, h); 326} 327 328bool Font::canReturnFallbackFontsForComplexText() 329{ 330 return false; 331} 332 333} 334