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 "WidthIterator.h"
     42 #include <wtf/MathExtras.h>
     43 #include <wtf/OwnPtr.h>
     44 #include <wtf/unicode/Unicode.h>
     45 
     46 #include <windows.h>
     47 
     48 using namespace WTF::Unicode;
     49 
     50 namespace WebCore {
     51 
     52 HDC g_screenDC = GetDC(0);
     53 
     54 class ScreenDcReleaser {
     55 public:
     56     ~ScreenDcReleaser()
     57     {
     58         ReleaseDC(0, g_screenDC);
     59     }
     60 };
     61 
     62 ScreenDcReleaser releaseScreenDc;
     63 
     64 void 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 
     70 class TextRunComponent {
     71 public:
     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 
     86 TextRunComponent::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 
    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.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 
    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 float 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 
    245 int 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 
    285 static 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 
    311 FloatRect 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 
    328 bool Font::canReturnFallbackFontsForComplexText()
    329 {
    330     return false;
    331 }
    332 
    333 }
    334