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

📄 fontmacatsui.mm

📁 linux下开源浏览器WebKit的源码,市面上的很多商用浏览器都是移植自WebKit
💻 MM
📖 第 1 页 / 共 2 页
字号:
/* * Copyright (C) 1999 Lars Knoll (knoll@kde.org) *           (C) 1999 Antti Koivisto (koivisto@kde.org) *           (C) 2000 Dirk Mueller (mueller@kde.org) * Copyright (C) 2003, 2006 Apple Computer, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB.  If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */#import "config.h"#import "Font.h"#if USE(ATSUI)#import "CharacterNames.h"#import "GraphicsContext.h"#import "Logging.h"#import "ShapeArabic.h"#import "SimpleFontData.h"#import <wtf/OwnArrayPtr.h>#define SYNTHETIC_OBLIQUE_ANGLE 14#ifdef __LP64__#define URefCon void*#else#define URefCon UInt32#endifusing namespace std;namespace WebCore {struct ATSULayoutParameters : Noncopyable{    ATSULayoutParameters(const TextRun& run)        : m_run(run)        , m_font(0)        , m_hasSyntheticBold(false)        , m_syntheticBoldPass(false)        , m_padPerSpace(0)    {}    ~ATSULayoutParameters()    {        ATSUDisposeTextLayout(m_layout);    }    void initialize(const Font*, const GraphicsContext* = 0);    const TextRun& m_run;        const Font* m_font;        ATSUTextLayout m_layout;    OwnArrayPtr<const SimpleFontData*> m_fonts;        OwnArrayPtr<UChar> m_charBuffer;    bool m_hasSyntheticBold;    bool m_syntheticBoldPass;    float m_padPerSpace;};static TextRun copyRunForDirectionalOverrideIfNecessary(const TextRun& run, OwnArrayPtr<UChar>& charactersWithOverride){    if (!run.directionalOverride())        return run;    charactersWithOverride.set(new UChar[run.length() + 2]);    charactersWithOverride[0] = run.rtl() ? rightToLeftOverride : leftToRightOverride;    memcpy(&charactersWithOverride[1], run.data(0), sizeof(UChar) * run.length());    charactersWithOverride[run.length() + 1] = popDirectionalFormatting;    TextRun result = run;    result.setText(charactersWithOverride.get(), run.length() + 2);    return result;}static bool fontHasMirroringInfo(ATSUFontID fontID){    ByteCount propTableSize;    OSStatus status = ATSFontGetTable(fontID, 'prop', 0, 0, 0, &propTableSize);    if (status == noErr)    // naively assume that if a 'prop' table exists then it contains mirroring info        return true;    else if (status != kATSInvalidFontTableAccess) // anything other than a missing table is logged as an error        LOG_ERROR("ATSFontGetTable failed (%d)", status);    return false;}static void disableLigatures(const SimpleFontData* fontData){    // Don't be too aggressive: if the font doesn't contain 'a', then assume that any ligatures it contains are    // in characters that always go through ATSUI, and therefore allow them. Geeza Pro is an example.    // See bugzilla 5166.    if (fontData->platformData().allowsLigatures())        return;    ATSUFontFeatureType featureTypes[] = { kLigaturesType };    ATSUFontFeatureSelector featureSelectors[] = { kCommonLigaturesOffSelector };    OSStatus status = ATSUSetFontFeatures(fontData->m_ATSUStyle, 1, featureTypes, featureSelectors);    if (status != noErr)        LOG_ERROR("ATSUSetFontFeatures failed (%d) -- ligatures remain enabled", status);}static void initializeATSUStyle(const SimpleFontData* fontData){    if (fontData->m_ATSUStyleInitialized)        return;    ATSUFontID fontID = fontData->platformData().m_atsuFontID;    if (!fontID) {        LOG_ERROR("unable to get ATSUFontID for %@", fontData->m_font.font());        return;    }    OSStatus status = ATSUCreateStyle(&fontData->m_ATSUStyle);    if (status != noErr)        // Who knows how many ATSU functions will crash when passed a NULL style...        LOG_ERROR("ATSUCreateStyle failed (%d)", status);    CGAffineTransform transform = CGAffineTransformMakeScale(1, -1);    if (fontData->m_font.m_syntheticOblique)        transform = CGAffineTransformConcat(transform, CGAffineTransformMake(1, 0, -tanf(SYNTHETIC_OBLIQUE_ANGLE * acosf(0) / 90), 1, 0, 0));    Fixed fontSize = FloatToFixed(fontData->platformData().m_size);    ByteCount styleSizes[4] = { sizeof(Fixed), sizeof(ATSUFontID), sizeof(CGAffineTransform), sizeof(Fract) };    // Turn off automatic kerning until it is supported in the CG code path (bug 6136)    Fract kerningInhibitFactor = FloatToFract(1.0);        ATSUAttributeTag styleTags[4] = { kATSUSizeTag, kATSUFontTag, kATSUFontMatrixTag, kATSUKerningInhibitFactorTag };    ATSUAttributeValuePtr styleValues[4] = { &fontSize, &fontID, &transform, &kerningInhibitFactor };    status = ATSUSetAttributes(fontData->m_ATSUStyle, 4, styleTags, styleSizes, styleValues);    if (status != noErr)        LOG_ERROR("ATSUSetAttributes failed (%d)", status);    fontData->m_ATSUMirrors = fontHasMirroringInfo(fontID);    // Turn off ligatures such as 'fi' to match the CG code path's behavior, until bug 6135 is fixed.    disableLigatures(fontData);    fontData->m_ATSUStyleInitialized = true;}static OSStatus overrideLayoutOperation(ATSULayoutOperationSelector, ATSULineRef iLineRef, URefCon iRefCon, void*, ATSULayoutOperationCallbackStatus* oCallbackStatus){    ATSULayoutParameters* params = reinterpret_cast<ATSULayoutParameters*>(iRefCon);    OSStatus status;    ItemCount count;    ATSLayoutRecord *layoutRecords;    if (params->m_run.applyWordRounding()) {        status = ATSUDirectGetLayoutDataArrayPtrFromLineRef(iLineRef, kATSUDirectDataLayoutRecordATSLayoutRecordCurrent, true, (void **)&layoutRecords, &count);        if (status != noErr) {            *oCallbackStatus = kATSULayoutOperationCallbackStatusContinue;            return status;        }                Fixed lastNativePos = 0;        float lastAdjustedPos = 0;        const UChar* characters = params->m_charBuffer ? params->m_charBuffer.get() : params->m_run.characters();        const SimpleFontData** renderers = params->m_fonts.get();        const SimpleFontData* renderer;        const SimpleFontData* lastRenderer = 0;        ByteCount offset = layoutRecords[0].originalOffset;        UChar nextCh = *(UChar *)(((char *)characters)+offset);        bool shouldRound = false;        bool syntheticBoldPass = params->m_syntheticBoldPass;        Fixed syntheticBoldOffset = 0;        ATSGlyphRef spaceGlyph = 0;        bool hasExtraSpacing = (params->m_font->letterSpacing() || params->m_font->wordSpacing() || params->m_run.padding()) && !params->m_run.spacingDisabled();        float padding = params->m_run.padding();        // In the CoreGraphics code path, the rounding hack is applied in logical order.        // Here it is applied in visual left-to-right order, which may be better.        ItemCount lastRoundingChar = 0;        ItemCount i;        for (i = 1; i < count; i++) {            bool isLastChar = i == count - 1;            renderer = renderers[offset / 2];            if (renderer != lastRenderer) {                lastRenderer = renderer;                spaceGlyph = renderer->m_spaceGlyph;                // The CoreGraphics interpretation of NSFontAntialiasedIntegerAdvancementsRenderingMode seems                // to be "round each glyph's width to the nearest integer". This is not the same as ATSUI                // does in any of its device-metrics modes.                shouldRound = renderer->platformData().roundsGlyphAdvances();                if (syntheticBoldPass)                    syntheticBoldOffset = FloatToFixed(renderer->m_syntheticBoldOffset);            }            float width;            if (nextCh == zeroWidthSpace || Font::treatAsZeroWidthSpace(nextCh) && !Font::treatAsSpace(nextCh)) {                width = 0;                layoutRecords[i-1].glyphID = spaceGlyph;            } else {                width = FixedToFloat(layoutRecords[i].realPos - lastNativePos);                if (shouldRound)                    width = roundf(width);                width += renderer->m_syntheticBoldOffset;                if (renderer->m_treatAsFixedPitch ? width == renderer->m_spaceWidth : (layoutRecords[i-1].flags & kATSGlyphInfoIsWhiteSpace))                    width = renderer->m_adjustedSpaceWidth;            }            lastNativePos = layoutRecords[i].realPos;            if (hasExtraSpacing) {                if (width && params->m_font->letterSpacing())                    width +=params->m_font->letterSpacing();                if (Font::treatAsSpace(nextCh)) {                    if (params->m_run.padding()) {                        if (padding < params->m_padPerSpace) {                            width += padding;                            padding = 0;                        } else {                            width += params->m_padPerSpace;                            padding -= params->m_padPerSpace;                        }                    }                    if (offset != 0 && !Font::treatAsSpace(*((UChar *)(((char *)characters)+offset) - 1)) && params->m_font->wordSpacing())                        width += params->m_font->wordSpacing();                }            }            UChar ch = nextCh;            offset = layoutRecords[i].originalOffset;            // Use space for nextCh at the end of the loop so that we get inside the rounding hack code.            // We won't actually round unless the other conditions are satisfied.            nextCh = isLastChar ? ' ' : *(UChar *)(((char *)characters)+offset);            if (Font::isRoundingHackCharacter(ch))                width = ceilf(width);            lastAdjustedPos = lastAdjustedPos + width;            if (Font::isRoundingHackCharacter(nextCh) && (!isLastChar || params->m_run.applyRunRounding())){                if (params->m_run.ltr())                    lastAdjustedPos = ceilf(lastAdjustedPos);                else {                    float roundingWidth = ceilf(lastAdjustedPos) - lastAdjustedPos;                    Fixed rw = FloatToFixed(roundingWidth);                    ItemCount j;                    for (j = lastRoundingChar; j < i; j++)                        layoutRecords[j].realPos += rw;                    lastRoundingChar = i;                    lastAdjustedPos += roundingWidth;                }            }            if (syntheticBoldPass) {                if (syntheticBoldOffset)                    layoutRecords[i-1].realPos += syntheticBoldOffset;                else                    layoutRecords[i-1].glyphID = spaceGlyph;            }            layoutRecords[i].realPos = FloatToFixed(lastAdjustedPos);        }                status = ATSUDirectReleaseLayoutDataArrayPtr(iLineRef, kATSUDirectDataLayoutRecordATSLayoutRecordCurrent, (void **)&layoutRecords);    }    *oCallbackStatus = kATSULayoutOperationCallbackStatusHandled;    return noErr;}static inline bool isArabicLamWithAlefLigature(UChar c){    return c >= 0xfef5 && c <= 0xfefc;}static void shapeArabic(const UChar* source, UChar* dest, unsigned totalLength, unsigned shapingStart){    while (shapingStart < totalLength) {        unsigned shapingEnd;        // We do not want to pass a Lam with Alef ligature followed by a space to the shaper,        // since we want to be able to identify this sequence as the result of shaping a Lam        // followed by an Alef and padding with a space.        bool foundLigatureSpace = false;        for (shapingEnd = shapingStart; !foundLigatureSpace && shapingEnd < totalLength - 1; ++shapingEnd)            foundLigatureSpace = isArabicLamWithAlefLigature(source[shapingEnd]) && source[shapingEnd + 1] == ' ';        shapingEnd++;        UErrorCode shapingError = U_ZERO_ERROR;        unsigned charsWritten = shapeArabic(source + shapingStart, shapingEnd - shapingStart, dest + shapingStart, shapingEnd - shapingStart, U_SHAPE_LETTERS_SHAPE | U_SHAPE_LENGTH_FIXED_SPACES_NEAR, &shapingError);        if (U_SUCCESS(shapingError) && charsWritten == shapingEnd - shapingStart) {            for (unsigned j = shapingStart; j < shapingEnd - 1; ++j) {                if (isArabicLamWithAlefLigature(dest[j]) && dest[j + 1] == ' ')                    dest[++j] = zeroWidthSpace;            }            if (foundLigatureSpace) {                dest[shapingEnd] = ' ';                shapingEnd++;            } else if (isArabicLamWithAlefLigature(dest[shapingEnd - 1])) {                // u_shapeArabic quirk: if the last two characters in the source string are a Lam and an Alef,                // the space is put at the beginning of the string, despite U_SHAPE_LENGTH_FIXED_SPACES_NEAR.                ASSERT(dest[shapingStart] == ' ');                dest[shapingStart] = zeroWidthSpace;            }        } else {            // Something went wrong. Abandon shaping and just copy the rest of the buffer.            LOG_ERROR("u_shapeArabic failed(%d)", shapingError);            shapingEnd = totalLength;            memcpy(dest + shapingStart, source + shapingStart, (shapingEnd - shapingStart) * sizeof(UChar));        }        shapingStart = shapingEnd;    }

⌨️ 快捷键说明

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