⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 uniscribehelper.cpp

📁 linux下开源浏览器WebKit的源码,市面上的很多商用浏览器都是移植自WebKit
💻 CPP
📖 第 1 页 / 共 3 页
字号:
/* * Copyright (c) 2006, 2007, 2008, 2009, Google Inc. All rights reserved. *  * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: *  *     * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. *     * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. *     * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. *  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */#include "config.h"#include "UniscribeHelper.h"#include <windows.h>#include "FontUtilsChromiumWin.h"#include "PlatformContextSkia.h"#include "SkiaFontWin.h"#include "SkPoint.h"#include <wtf/Assertions.h>namespace WebCore {// This function is used to see where word spacing should be applied inside// runs. Note that this must match Font::treatAsSpace so we all agree where// and how much space this is, so we don't want to do more general Unicode// "is this a word break" thing.static bool treatAsSpace(UChar c){    return c == ' ' || c == '\t' || c == '\n' || c == 0x00A0;}// SCRIPT_FONTPROPERTIES contains glyph indices for default, invalid// and blank glyphs. Just because ScriptShape succeeds does not mean// that a text run is rendered correctly. Some characters may be rendered// with default/invalid/blank glyphs. Therefore, we need to check if the glyph// array returned by ScriptShape contains any of those glyphs to make// sure that the text run is rendered successfully.static bool containsMissingGlyphs(WORD *glyphs,                                  int length,                                  SCRIPT_FONTPROPERTIES* properties){    for (int i = 0; i < length; ++i) {        if (glyphs[i] == properties->wgDefault            || (glyphs[i] == properties->wgInvalid            && glyphs[i] != properties->wgBlank))            return true;    }    return false;}// HFONT is the 'incarnation' of 'everything' about font, but it's an opaque// handle and we can't directly query it to make a new HFONT sharing// its characteristics (height, style, etc) except for family name.// This function uses GetObject to convert HFONT back to LOGFONT,// resets the fields of LOGFONT and calculates style to use later// for the creation of a font identical to HFONT other than family name.static void setLogFontAndStyle(HFONT hfont, LOGFONT *logfont, int *style){    ASSERT(hfont && logfont);    if (!hfont || !logfont)        return;    GetObject(hfont, sizeof(LOGFONT), logfont);    // We reset these fields to values appropriate for CreateFontIndirect.    // while keeping lfHeight, which is the most important value in creating    // a new font similar to hfont.    logfont->lfWidth = 0;    logfont->lfEscapement = 0;    logfont->lfOrientation = 0;    logfont->lfCharSet = DEFAULT_CHARSET;    logfont->lfOutPrecision = OUT_TT_ONLY_PRECIS;    logfont->lfQuality = DEFAULT_QUALITY;  // Honor user's desktop settings.    logfont->lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;    if (style)        *style = getStyleFromLogfont(logfont);}UniscribeHelper::UniscribeHelper(const UChar* input,                                int inputLength,                                bool isRtl,                                HFONT hfont,                                SCRIPT_CACHE* scriptCache,                                SCRIPT_FONTPROPERTIES* fontProperties)    : m_input(input)    , m_inputLength(inputLength)    , m_isRtl(isRtl)    , m_hfont(hfont)    , m_scriptCache(scriptCache)    , m_fontProperties(fontProperties)    , m_directionalOverride(false)    , m_inhibitLigate(false)    , m_letterSpacing(0)    , m_spaceWidth(0)    , m_wordSpacing(0)    , m_ascent(0)    , m_disableFontFallback(false){    m_logfont.lfFaceName[0] = 0;}UniscribeHelper::~UniscribeHelper(){}void UniscribeHelper::initWithOptionalLengthProtection(bool lengthProtection){    // We cap the input length and just don't do anything. We'll allocate a lot    // of things of the size of the number of characters, so the allocated    // memory will be several times the input length. Plus shaping such a large    // buffer may be a form of denial of service. No legitimate text should be    // this long.  It also appears that Uniscribe flatly rejects very long    // strings, so we don't lose anything by doing this.    //    // The input length protection may be disabled by the unit tests to cause    // an error condition.    static const int kMaxInputLength = 65535;    if (m_inputLength == 0 || (lengthProtection && m_inputLength > kMaxInputLength))        return;    fillRuns();    fillShapes();    fillScreenOrder();}int UniscribeHelper::width() const{    int width = 0;    for (int itemIndex = 0; itemIndex < static_cast<int>(m_runs.size()); itemIndex++)        width += advanceForItem(itemIndex);    return width;}void UniscribeHelper::justify(int additionalSpace){    // Count the total number of glyphs we have so we know how big to make the    // buffers below.    int totalGlyphs = 0;    for (size_t run = 0; run < m_runs.size(); run++) {        int runIndex = m_screenOrder[run];        totalGlyphs += static_cast<int>(m_shapes[runIndex].glyphLength());    }    if (totalGlyphs == 0)        return;  // Nothing to do.    // We make one big buffer in screen order of all the glyphs we are drawing    // across runs so that the justification function will adjust evenly across    // all glyphs.    Vector<SCRIPT_VISATTR, 64> visualAttributes;    visualAttributes.resize(totalGlyphs);    Vector<int, 64> advances;    advances.resize(totalGlyphs);    Vector<int, 64> justify;    justify.resize(totalGlyphs);    // Build the packed input.    int destIndex = 0;    for (size_t run = 0; run < m_runs.size(); run++) {        int runIndex = m_screenOrder[run];        const Shaping& shaping = m_shapes[runIndex];        for (int i = 0; i < shaping.glyphLength(); i++, destIndex++) {            memcpy(&visualAttributes[destIndex], &shaping.m_visualAttributes[i],                   sizeof(SCRIPT_VISATTR));            advances[destIndex] = shaping.m_advance[i];        }    }    // The documentation for Scriptjustify is wrong, the parameter is the space    // to add and not the width of the column you want.    const int minKashida = 1;  // How do we decide what this should be?    ScriptJustify(&visualAttributes[0], &advances[0], totalGlyphs,                  additionalSpace, minKashida, &justify[0]);    // Now we have to unpack the justification amounts back into the runs so    // the glyph indices match.    int globalGlyphIndex = 0;    for (size_t run = 0; run < m_runs.size(); run++) {        int runIndex = m_screenOrder[run];        Shaping& shaping = m_shapes[runIndex];        shaping.m_justify.resize(shaping.glyphLength());        for (int i = 0; i < shaping.glyphLength(); i++, globalGlyphIndex++)            shaping.m_justify[i] = justify[globalGlyphIndex];    }}int UniscribeHelper::characterToX(int offset) const{    HRESULT hr;    ASSERT(offset <= m_inputLength);    // Our algorithm is to traverse the items in screen order from left to    // right, adding in each item's screen width until we find the item with    // the requested character in it.    int width = 0;    for (size_t screenIndex = 0; screenIndex < m_runs.size(); screenIndex++) {        // Compute the length of this run.        int itemIndex = m_screenOrder[screenIndex];        const SCRIPT_ITEM& item = m_runs[itemIndex];        const Shaping& shaping = m_shapes[itemIndex];        int itemLength = shaping.charLength();        if (offset >= item.iCharPos && offset <= item.iCharPos + itemLength) {            // Character offset is in this run.            int charLength = offset - item.iCharPos;            int curX = 0;            hr = ScriptCPtoX(charLength, FALSE, itemLength,                             shaping.glyphLength(),                             &shaping.m_logs[0], &shaping.m_visualAttributes[0],                             shaping.effectiveAdvances(), &item.a, &curX);            if (FAILED(hr))                return 0;            width += curX + shaping.m_prePadding;            ASSERT(width >= 0);            return width;        }        // Move to the next item.        width += advanceForItem(itemIndex);    }    ASSERT(width >= 0);    return width;}int UniscribeHelper::xToCharacter(int x) const{    // We iterate in screen order until we find the item with the given pixel    // position in it. When we find that guy, we ask Uniscribe for the    // character index.    HRESULT hr;    for (size_t screenIndex = 0; screenIndex < m_runs.size(); screenIndex++) {        int itemIndex = m_screenOrder[screenIndex];        int itemAdvance = advanceForItem(itemIndex);        // Note that the run may be empty if shaping failed, so we want to skip        // over it.        const Shaping& shaping = m_shapes[itemIndex];        int itemLength = shaping.charLength();        if (x <= itemAdvance && itemLength > 0) {            // The requested offset is within this item.            const SCRIPT_ITEM& item = m_runs[itemIndex];            // Account for the leading space we've added to this run that            // Uniscribe doesn't know about.            x -= shaping.m_prePadding;            int charX = 0;            int trailing;            hr = ScriptXtoCP(x, itemLength, shaping.glyphLength(),                             &shaping.m_logs[0], &shaping.m_visualAttributes[0],                             shaping.effectiveAdvances(), &item.a, &charX,                             &trailing);            // The character offset is within the item. We need to add the            // item's offset to transform it into the space of the TextRun            return charX + item.iCharPos;        }        // The offset is beyond this item, account for its length and move on.        x -= itemAdvance;    }    // Error condition, we don't know what to do if we don't have that X    // position in any of our items.    return 0;}void UniscribeHelper::draw(GraphicsContext* graphicsContext,                           HDC dc, int x, int y, int from, int to){    HGDIOBJ oldFont = 0;    int curX = x;    bool firstRun = true;    bool useWindowsDrawing = windowsCanHandleTextDrawing(graphicsContext);    for (size_t screenIndex = 0; screenIndex < m_runs.size(); screenIndex++) {        int itemIndex = m_screenOrder[screenIndex];        const SCRIPT_ITEM& item = m_runs[itemIndex];        const Shaping& shaping = m_shapes[itemIndex];        // Character offsets within this run. THESE MAY NOT BE IN RANGE and may        // be negative, etc. The code below handles this.        int fromChar = from - item.iCharPos;        int toChar = to - item.iCharPos;        // See if we need to draw any characters in this item.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -