diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
commit | 1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch) | |
tree | 46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebCore/platform/graphics/cairo/FontCairo.cpp | |
parent | 32761a6cee1d0dee366b885b7b9c777e67885688 (diff) | |
download | WebKitGtk-tarball-master.tar.gz |
webkitgtk-2.16.5HEADwebkitgtk-2.16.5master
Diffstat (limited to 'Source/WebCore/platform/graphics/cairo/FontCairo.cpp')
-rw-r--r-- | Source/WebCore/platform/graphics/cairo/FontCairo.cpp | 252 |
1 files changed, 225 insertions, 27 deletions
diff --git a/Source/WebCore/platform/graphics/cairo/FontCairo.cpp b/Source/WebCore/platform/graphics/cairo/FontCairo.cpp index a09e555d2..a712d0011 100644 --- a/Source/WebCore/platform/graphics/cairo/FontCairo.cpp +++ b/Source/WebCore/platform/graphics/cairo/FontCairo.cpp @@ -1,9 +1,10 @@ /* - * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2006 Apple Inc. All rights reserved. * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com * Copyright (C) 2007, 2008 Alp Toker <alp@atoker.com> * Copyright (C) 2009 Dirk Schulze <krit@webkit.org> * Copyright (C) 2010 Holger Hans Peter Freyther + * Copyright (C) 2014 Igalia S.L. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -14,10 +15,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. 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 @@ -28,29 +29,32 @@ */ #include "config.h" -#include "Font.h" +#include "FontCascade.h" + +#if USE(CAIRO) #include "AffineTransform.h" #include "CairoUtilities.h" +#include "Font.h" #include "GlyphBuffer.h" #include "Gradient.h" #include "GraphicsContext.h" #include "ImageBuffer.h" #include "Pattern.h" #include "PlatformContextCairo.h" +#include "PlatformPathCairo.h" #include "ShadowBlur.h" -#include "SimpleFontData.h" namespace WebCore { -static void drawGlyphsToContext(cairo_t* context, const SimpleFontData* font, GlyphBufferGlyph* glyphs, int numGlyphs) +static void drawGlyphsToContext(cairo_t* context, const Font& font, GlyphBufferGlyph* glyphs, unsigned numGlyphs) { cairo_matrix_t originalTransform; - float syntheticBoldOffset = font->syntheticBoldOffset(); + float syntheticBoldOffset = font.syntheticBoldOffset(); if (syntheticBoldOffset) cairo_get_matrix(context, &originalTransform); - cairo_set_scaled_font(context, font->platformData().scaledFont()); + cairo_set_scaled_font(context, font.platformData().scaledFont()); cairo_show_glyphs(context, glyphs, numGlyphs); if (syntheticBoldOffset) { @@ -62,21 +66,21 @@ static void drawGlyphsToContext(cairo_t* context, const SimpleFontData* font, Gl cairo_set_matrix(context, &originalTransform); } -static void drawGlyphsShadow(GraphicsContext* graphicsContext, const FloatPoint& point, const SimpleFontData* font, GlyphBufferGlyph* glyphs, int numGlyphs) +static void drawGlyphsShadow(GraphicsContext& graphicsContext, const FloatPoint& point, const Font& font, GlyphBufferGlyph* glyphs, unsigned numGlyphs) { - ShadowBlur& shadow = graphicsContext->platformContext()->shadowBlur(); + ShadowBlur& shadow = graphicsContext.platformContext()->shadowBlur(); - if (!(graphicsContext->textDrawingMode() & TextModeFill) || shadow.type() == ShadowBlur::NoShadow) + if (!(graphicsContext.textDrawingMode() & TextModeFill) || shadow.type() == ShadowBlur::NoShadow) return; - if (!graphicsContext->mustUseShadowBlur()) { + if (!graphicsContext.mustUseShadowBlur()) { // Optimize non-blurry shadows, by just drawing text without the ShadowBlur. - cairo_t* context = graphicsContext->platformContext()->cr(); + cairo_t* context = graphicsContext.platformContext()->cr(); cairo_save(context); - FloatSize shadowOffset(graphicsContext->state().shadowOffset); + FloatSize shadowOffset(graphicsContext.state().shadowOffset); cairo_translate(context, shadowOffset.width(), shadowOffset.height()); - setSourceRGBAFromColor(context, graphicsContext->state().shadowColor); + setSourceRGBAFromColor(context, graphicsContext.state().shadowColor); drawGlyphsToContext(context, font, glyphs, numGlyphs); cairo_restore(context); @@ -84,7 +88,7 @@ static void drawGlyphsShadow(GraphicsContext* graphicsContext, const FloatPoint& } cairo_text_extents_t extents; - cairo_scaled_font_glyph_extents(font->platformData().scaledFont(), glyphs, numGlyphs, &extents); + cairo_scaled_font_glyph_extents(font.platformData().scaledFont(), glyphs, numGlyphs, &extents); FloatRect fontExtentsRect(point.x() + extents.x_bearing, point.y() + extents.y_bearing, extents.width, extents.height); if (GraphicsContext* shadowContext = shadow.beginShadowLayer(graphicsContext, fontExtentsRect)) { @@ -93,29 +97,29 @@ static void drawGlyphsShadow(GraphicsContext* graphicsContext, const FloatPoint& } } -void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, const GlyphBuffer& glyphBuffer, - int from, int numGlyphs, const FloatPoint& point) const +void FontCascade::drawGlyphs(GraphicsContext& context, const Font& font, const GlyphBuffer& glyphBuffer, + unsigned from, unsigned numGlyphs, const FloatPoint& point, FontSmoothingMode) { - if (!font->platformData().size()) + if (!font.platformData().size()) return; GlyphBufferGlyph* glyphs = const_cast<GlyphBufferGlyph*>(glyphBuffer.glyphs(from)); float offset = point.x(); - for (int i = 0; i < numGlyphs; i++) { + for (unsigned i = 0; i < numGlyphs; i++) { glyphs[i].x = offset; glyphs[i].y = point.y(); offset += glyphBuffer.advanceAt(from + i).width(); } - PlatformContextCairo* platformContext = context->platformContext(); + PlatformContextCairo* platformContext = context.platformContext(); drawGlyphsShadow(context, point, font, glyphs, numGlyphs); cairo_t* cr = platformContext->cr(); cairo_save(cr); - if (context->textDrawingMode() & TextModeFill) { - platformContext->prepareForFilling(context->state(), PlatformContextCairo::AdjustPatternForGlobalAlpha); + if (context.textDrawingMode() & TextModeFill) { + platformContext->prepareForFilling(context.state(), PlatformContextCairo::AdjustPatternForGlobalAlpha); drawGlyphsToContext(cr, font, glyphs, numGlyphs); } @@ -123,12 +127,12 @@ void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, cons // twice the size of the width of the text we will not ask cairo to stroke // the text as even one single stroke would cover the full wdth of the text. // See https://bugs.webkit.org/show_bug.cgi?id=33759. - if (context->textDrawingMode() & TextModeStroke && context->strokeThickness() < 2 * offset) { - platformContext->prepareForStroking(context->state()); - cairo_set_line_width(cr, context->strokeThickness()); + if (context.textDrawingMode() & TextModeStroke && context.strokeThickness() < 2 * offset) { + platformContext->prepareForStroking(context.state()); + cairo_set_line_width(cr, context.strokeThickness()); // This may disturb the CTM, but we are going to call cairo_restore soon after. - cairo_set_scaled_font(cr, font->platformData().scaledFont()); + cairo_set_scaled_font(cr, font.platformData().scaledFont()); cairo_glyph_path(cr, glyphs, numGlyphs); cairo_stroke(cr); } @@ -136,4 +140,198 @@ void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, cons cairo_restore(cr); } +#if ENABLE(CSS3_TEXT_DECORATION_SKIP_INK) +struct GlyphIterationState { + GlyphIterationState(FloatPoint startingPoint, FloatPoint currentPoint, float centerOfLine, float minX, float maxX) + : startingPoint(startingPoint) + , currentPoint(currentPoint) + , centerOfLine(centerOfLine) + , minX(minX) + , maxX(maxX) + { + } + FloatPoint startingPoint; + FloatPoint currentPoint; + float centerOfLine; + float minX; + float maxX; +}; + +static bool findIntersectionPoint(float y, FloatPoint p1, FloatPoint p2, float& x) +{ + x = p1.x() + (y - p1.y()) * (p2.x() - p1.x()) / (p2.y() - p1.y()); + return (p1.y() < y && p2.y() > y) || (p1.y() > y && p2.y() < y); +} + +static void updateX(GlyphIterationState& state, float x) +{ + state.minX = std::min(state.minX, x); + state.maxX = std::max(state.maxX, x); +} + +// This function is called by Path::apply and is therefore invoked for each contour in a glyph. This +// function models each contours as a straight line and calculates the intersections between each +// pseudo-contour and the vertical center of the underline found in GlyphIterationState::centerOfLine. +// It keeps track of the leftmost and rightmost intersection in GlyphIterationState::minX and +// GlyphIterationState::maxX. +static void findPathIntersections(GlyphIterationState& state, const PathElement& element) +{ + bool doIntersection = false; + FloatPoint point = FloatPoint(); + switch (element.type) { + case PathElementMoveToPoint: + state.startingPoint = element.points[0]; + state.currentPoint = element.points[0]; + break; + case PathElementAddLineToPoint: + doIntersection = true; + point = element.points[0]; + break; + case PathElementAddQuadCurveToPoint: + doIntersection = true; + point = element.points[1]; + break; + case PathElementAddCurveToPoint: + doIntersection = true; + point = element.points[2]; + break; + case PathElementCloseSubpath: + doIntersection = true; + point = state.startingPoint; + break; + } + + if (!doIntersection) + return; + + float x; + if (findIntersectionPoint(state.centerOfLine, state.currentPoint, point, x)) + updateX(state, x); + + state.currentPoint = point; } + +class CairoGlyphToPathTranslator final : public GlyphToPathTranslator { +public: + CairoGlyphToPathTranslator(const TextRun& textRun, const GlyphBuffer& glyphBuffer, const FloatPoint& textOrigin) + : m_index(0) + , m_textRun(textRun) + , m_glyphBuffer(glyphBuffer) + , m_fontData(glyphBuffer.fontAt(m_index)) + , m_translation(AffineTransform().translate(textOrigin.x(), textOrigin.y())) + { + } + + bool containsMorePaths() final { return m_index != m_glyphBuffer.size(); } + Path path() final; + std::pair<float, float> extents() final; + GlyphUnderlineType underlineType() final; + void advance() final; + +private: + unsigned m_index; + const TextRun& m_textRun; + const GlyphBuffer& m_glyphBuffer; + const Font* m_fontData; + AffineTransform m_translation; +}; + +Path CairoGlyphToPathTranslator::path() +{ + Path path; + path.ensurePlatformPath(); + + cairo_glyph_t cairoGlyph = { m_glyphBuffer.glyphAt(m_index), 0, 0 }; + cairo_set_scaled_font(path.platformPath()->context(), m_fontData->platformData().scaledFont()); + cairo_glyph_path(path.platformPath()->context(), &cairoGlyph, 1); + + float syntheticBoldOffset = m_fontData->syntheticBoldOffset(); + if (syntheticBoldOffset) { + cairo_translate(path.platformPath()->context(), syntheticBoldOffset, 0); + cairo_show_glyphs(path.platformPath()->context(), &cairoGlyph, 1); + } + + path.transform(m_translation); + return path; +} + +std::pair<float, float> CairoGlyphToPathTranslator::extents() +{ + FloatPoint beginning = m_translation.mapPoint(FloatPoint()); + FloatSize end = m_translation.mapSize(m_glyphBuffer.advanceAt(m_index)); + return std::make_pair(static_cast<float>(beginning.x()), static_cast<float>(beginning.x() + end.width())); +} + +GlyphToPathTranslator::GlyphUnderlineType CairoGlyphToPathTranslator::underlineType() +{ + return computeUnderlineType(m_textRun, m_glyphBuffer, m_index); +} + +void CairoGlyphToPathTranslator::advance() +{ + GlyphBufferAdvance advance = m_glyphBuffer.advanceAt(m_index); + m_translation = m_translation.translate(advance.width(), advance.height()); + ++m_index; + if (m_index < m_glyphBuffer.size()) + m_fontData = m_glyphBuffer.fontAt(m_index); +} + +DashArray FontCascade::dashesForIntersectionsWithRect(const TextRun& run, const FloatPoint& textOrigin, const FloatRect& lineExtents) const +{ + if (isLoadingCustomFonts()) + return DashArray(); + + GlyphBuffer glyphBuffer; + glyphBuffer.saveOffsetsInString(); + float deltaX; + if (codePath(run) != FontCascade::Complex) + deltaX = getGlyphsAndAdvancesForSimpleText(run, 0, run.length(), glyphBuffer); + else + deltaX = getGlyphsAndAdvancesForComplexText(run, 0, run.length(), glyphBuffer); + + if (!glyphBuffer.size()) + return DashArray(); + + // FIXME: Handle SVG + non-SVG interleaved runs. https://bugs.webkit.org/show_bug.cgi?id=133778 + FloatPoint origin = FloatPoint(textOrigin.x() + deltaX, textOrigin.y()); + CairoGlyphToPathTranslator translator(run, glyphBuffer, origin); + DashArray result; + for (int index = 0; translator.containsMorePaths(); ++index, translator.advance()) { + float centerOfLine = lineExtents.y() + (lineExtents.height() / 2); + GlyphIterationState info = GlyphIterationState(FloatPoint(), FloatPoint(), centerOfLine, lineExtents.x() + lineExtents.width(), lineExtents.x()); + const Font* localFontData = glyphBuffer.fontAt(index); + if (!localFontData) { + // The advances will get all messed up if we do anything other than bail here. + result.clear(); + break; + } + switch (translator.underlineType()) { + case GlyphToPathTranslator::GlyphUnderlineType::SkipDescenders: { + Path path = translator.path(); + path.apply([&info](const PathElement& pathElement) { + findPathIntersections(info, pathElement); + }); + if (info.minX < info.maxX) { + result.append(info.minX - lineExtents.x()); + result.append(info.maxX - lineExtents.x()); + } + break; + } + case GlyphToPathTranslator::GlyphUnderlineType::SkipGlyph: { + std::pair<float, float> extents = translator.extents(); + result.append(extents.first - lineExtents.x()); + result.append(extents.second - lineExtents.x()); + break; + } + case GlyphToPathTranslator::GlyphUnderlineType::DrawOverGlyph: + // Nothing to do + break; + } + } + return result; +} +#endif // ENABLE(CSS3_TEXT_DECORATION_SKIP_INK) + +} // namespace WebCore + +#endif // USE(CAIRO) |