Home | History | Annotate | Download | only in wince
      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