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

📄 skiafontwin.cpp

📁 linux下开源浏览器WebKit的源码,市面上的很多商用浏览器都是移植自WebKit
💻 CPP
字号:
/* * Copyright (c) 2008, 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 "SkiaFontWin.h"#include "PlatformContextSkia.h"#include "Gradient.h"#include "Pattern.h"#include "SkCanvas.h"#include "SkPaint.h"#include "SkShader.h"#include "TransformationMatrix.h"#include <wtf/ListHashSet.h>#include <wtf/Vector.h>namespace WebCore {struct CachedOutlineKey {    CachedOutlineKey() : font(0), glyph(0), path(0) {}    CachedOutlineKey(HFONT f, WORD g) : font(f), glyph(g), path(0) {}    HFONT font;    WORD glyph;    // The lifetime of this pointer is managed externally to this class. Be sure    // to call DeleteOutline to remove items.    SkPath* path;};const bool operator==(const CachedOutlineKey& a, const CachedOutlineKey& b){    return a.font == b.font && a.glyph == b.glyph;}struct CachedOutlineKeyHash {    static unsigned hash(const CachedOutlineKey& key)    {        unsigned keyBytes;        memcpy(&keyBytes, &key.font, sizeof(unsigned));        return keyBytes + key.glyph;    }    static unsigned equal(const CachedOutlineKey& a, const CachedOutlineKey& b)    {        return a.font == b.font && a.glyph == b.glyph;    }    static const bool safeToCompareToEmptyOrDeleted = true;};typedef ListHashSet<CachedOutlineKey, CachedOutlineKeyHash> OutlineCache;// FIXME: Convert from static constructor to accessor function. WebCore tries to// avoid global constructors to save on start-up time.static OutlineCache outlineCache;// The global number of glyph outlines we'll cache.static const int outlineCacheSize = 256;static SkScalar FIXEDToSkScalar(FIXED fixed){    SkFixed skFixed;    memcpy(&skFixed, &fixed, sizeof(SkFixed));    return SkFixedToScalar(skFixed);}// Removes the given key from the cached outlines, also deleting the path.static void deleteOutline(OutlineCache::iterator deleteMe){    delete deleteMe->path;    outlineCache.remove(deleteMe);}static void addPolyCurveToPath(const TTPOLYCURVE* polyCurve, SkPath* path){    switch (polyCurve->wType) {    case TT_PRIM_LINE:        for (WORD i = 0; i < polyCurve->cpfx; i++) {          path->lineTo(FIXEDToSkScalar(polyCurve->apfx[i].x), -FIXEDToSkScalar(polyCurve->apfx[i].y));        }        break;    case TT_PRIM_QSPLINE:        // FIXME: doesn't this duplicate points if we do the loop > once?        for (WORD i = 0; i < polyCurve->cpfx - 1; i++) {            SkScalar bx = FIXEDToSkScalar(polyCurve->apfx[i].x);            SkScalar by = FIXEDToSkScalar(polyCurve->apfx[i].y);            SkScalar cx = FIXEDToSkScalar(polyCurve->apfx[i + 1].x);            SkScalar cy = FIXEDToSkScalar(polyCurve->apfx[i + 1].y);            if (i < polyCurve->cpfx - 2) {                // We're not the last point, compute C.                cx = SkScalarAve(bx, cx);                cy = SkScalarAve(by, cy);            }            // Need to flip the y coordinates since the font's coordinate system is            // flipped from ours vertically.            path->quadTo(bx, -by, cx, -cy);        }        break;    case TT_PRIM_CSPLINE:        // FIXME        break;    }}// The size of the glyph path buffer.static const int glyphPathBufferSize = 4096;// Fills the given SkPath with the outline for the given glyph index. The font// currently selected into the given DC is used. Returns true on success.static bool getPathForGlyph(HDC dc, WORD glyph, SkPath* path){    char buffer[glyphPathBufferSize];    GLYPHMETRICS gm;    MAT2 mat = {{0, 1}, {0, 0}, {0, 0}, {0, 1}};  // Each one is (fract,value).    DWORD totalSize = GetGlyphOutlineW(dc, glyph, GGO_GLYPH_INDEX | GGO_NATIVE,                                       &gm, glyphPathBufferSize, buffer, &mat);    if (totalSize == GDI_ERROR)        return false;    const char* curGlyph = buffer;    const char* endGlyph = &buffer[totalSize];    while (curGlyph < endGlyph) {        const TTPOLYGONHEADER* polyHeader =            reinterpret_cast<const TTPOLYGONHEADER*>(curGlyph);        path->moveTo(FIXEDToSkScalar(polyHeader->pfxStart.x),                     -FIXEDToSkScalar(polyHeader->pfxStart.y));        const char* curPoly = curGlyph + sizeof(TTPOLYGONHEADER);        const char* endPoly = curGlyph + polyHeader->cb;        while (curPoly < endPoly) {            const TTPOLYCURVE* polyCurve =                reinterpret_cast<const TTPOLYCURVE*>(curPoly);            addPolyCurveToPath(polyCurve, path);            curPoly += sizeof(WORD) * 2 + sizeof(POINTFX) * polyCurve->cpfx;        }        curGlyph += polyHeader->cb;    }    path->close();    return true;}// Returns a SkPath corresponding to the give glyph in the given font. The font// should be selected into the given DC. The returned path is owned by the// hashtable. Returns 0 on error.const SkPath* SkiaWinOutlineCache::lookupOrCreatePathForGlyph(HDC hdc, HFONT font, WORD glyph){    CachedOutlineKey key(font, glyph);    OutlineCache::iterator found = outlineCache.find(key);    if (found != outlineCache.end()) {        // Keep in MRU order by removing & reinserting the value.        key = *found;        outlineCache.remove(found);        outlineCache.add(key);        return key.path;    }    key.path = new SkPath;    if (!getPathForGlyph(hdc, glyph, key.path))      return 0;    if (outlineCache.size() > outlineCacheSize)        // The cache is too big, find the oldest value (first in the list).        deleteOutline(outlineCache.begin());    outlineCache.add(key);    return key.path;}void SkiaWinOutlineCache::removePathsForFont(HFONT hfont){    // ListHashSet isn't the greatest structure for deleting stuff out of, but    // removing entries will be relatively rare (we don't remove fonts much, nor    // do we draw out own glyphs using these routines much either).    //    // We keep a list of all glyphs we're removing which we do in a separate    // pass.    Vector<CachedOutlineKey> outlinesToDelete;    for (OutlineCache::iterator i = outlineCache.begin();         i != outlineCache.end(); ++i)        outlinesToDelete.append(*i);    for (Vector<CachedOutlineKey>::iterator i = outlinesToDelete.begin();         i != outlinesToDelete.end(); ++i)        deleteOutline(outlineCache.find(*i));}bool windowsCanHandleTextDrawing(GraphicsContext* context){    // Check for non-translation transforms. Sometimes zooms will look better in    // Skia, and sometimes better in Windows. The main problem is that zooming    // in using Skia will show you the hinted outlines for the smaller size,    // which look weird. All else being equal, it's better to use Windows' text    // drawing, so we don't check for zooms.    const TransformationMatrix& matrix = context->getCTM();    if (matrix.b() != 0 || matrix.c() != 0)  // Check for skew.        return false;    // Check for stroke effects.    if (context->platformContext()->getTextDrawingMode() != cTextFill)        return false;    // Check for gradients.    if (context->fillGradient() || context->strokeGradient())        return false;    // Check for patterns.    if (context->fillPattern() || context->strokePattern())        return false;    // Check for shadow effects.    if (context->platformContext()->getDrawLooper())        return false;    return true;}// Draws the given text string using skia.  Note that gradient or// pattern may be NULL, in which case a solid colour is used.static bool skiaDrawText(HFONT hfont,                         HDC dc,                         SkCanvas* canvas,                         const SkPoint& point,                         SkPaint* paint,                         const TransformationMatrix& transformationMatrix,                         Gradient* gradient,                         Pattern* pattern,                         const WORD* glyphs,                         const int* advances,                         const GOFFSET* offsets,                         int numGlyphs){    SkShader* shader = NULL;    SkMatrix oldShaderMatrix;    if (gradient) {        shader = gradient->platformGradient();        // Get the length of the string in pixels.        int width = 0;        for (int i = 0; i < numGlyphs; i++)            width += advances[i];        // Save the current shader matrix.        shader->getLocalMatrix(&oldShaderMatrix);        // Scale up the gradient matrix by the width of the text string.        SkMatrix shaderMatrix(oldShaderMatrix);        shaderMatrix.postScale(static_cast<float>(width), 1.0f);        shaderMatrix.postTranslate(point.fX, point.fY);        shader->setLocalMatrix(shaderMatrix);    } else if (pattern)        shader = pattern->createPlatformPattern(transformationMatrix);    paint->setShader(shader);    float x = point.fX, y = point.fY;    for (int i = 0; i < numGlyphs; i++) {        const SkPath* path = SkiaWinOutlineCache::lookupOrCreatePathForGlyph(dc, hfont, glyphs[i]);        if (!path)            return false;        float offsetX = 0.0f, offsetY = 0.0f;        if (offsets && (offsets[i].du != 0 || offsets[i].dv != 0)) {            offsetX = offsets[i].du;            offsetY = offsets[i].dv;        }        SkPath newPath;        newPath.addPath(*path, x + offsetX, y + offsetY);        canvas->drawPath(newPath, *paint);                x += advances[i];    }    // Restore the previous shader matrix.    if (gradient)        shader->setLocalMatrix(oldShaderMatrix);    return true;}bool paintSkiaText(GraphicsContext* context,                   HFONT hfont,                   int numGlyphs,                   const WORD* glyphs,                   const int* advances,                   const GOFFSET* offsets,                   const SkPoint* origin){    HDC dc = GetDC(0);    HGDIOBJ oldFont = SelectObject(dc, hfont);    PlatformContextSkia* platformContext = context->platformContext();    int textMode = platformContext->getTextDrawingMode();    // Filling (if necessary). This is the common case.    SkPaint paint;    platformContext->setupPaintForFilling(&paint);    paint.setFlags(SkPaint::kAntiAlias_Flag);    bool didFill = false;    if ((textMode & cTextFill) && SkColorGetA(paint.getColor())) {        if (!skiaDrawText(hfont, dc, platformContext->canvas(), *origin, &paint,                          context->getCTM(), context->fillGradient(),                          context->fillPattern(), &glyphs[0], &advances[0],                          &offsets[0], numGlyphs))            return false;        didFill = true;    }    // Stroking on top (if necessary).    if ((textMode & WebCore::cTextStroke)        && platformContext->getStrokeStyle() != NoStroke        && platformContext->getStrokeThickness() > 0) {        paint.reset();        platformContext->setupPaintForStroking(&paint, 0, 0);        paint.setFlags(SkPaint::kAntiAlias_Flag);        if (didFill) {            // If there is a shadow and we filled above, there will already be            // a shadow. We don't want to draw it again or it will be too dark            // and it will go on top of the fill.            //            // Note that this isn't strictly correct, since the stroke could be            // very thick and the shadow wouldn't account for this. The "right"            // thing would be to draw to a new layer and then draw that layer            // with a shadow. But this is a lot of extra work for something            // that isn't normally an issue.            paint.setLooper(0)->safeUnref();        }        if (!skiaDrawText(hfont, dc, platformContext->canvas(), *origin, &paint,                          context->getCTM(), context->strokeGradient(),                          context->strokePattern(), &glyphs[0], &advances[0],                          &offsets[0], numGlyphs))            return false;    }    SelectObject(dc, oldFont);    ReleaseDC(0, dc);    return true;}}  // namespace WebCore

⌨️ 快捷键说明

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