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

📄 graphicscontextcairo.cpp

📁 linux下开源浏览器WebKit的源码,市面上的很多商用浏览器都是移植自WebKit
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/* * Copyright (C) 2006 Apple Computer, Inc.  All rights reserved. * Copyright (C) 2007 Alp Toker <alp@atoker.com> * Copyright (C) 2008 Dirk Schulze <vbs85@gmx.de> * Copyright (C) 2008 Nuanti Ltd. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. 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. * * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, 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 * 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 "GraphicsContext.h"#if PLATFORM(CAIRO)#include "TransformationMatrix.h"#include "CairoPath.h"#include "FloatRect.h"#include "Font.h"#include "ImageBuffer.h"#include "IntRect.h"#include "NotImplemented.h"#include "Path.h"#include "Pattern.h"#include "SimpleFontData.h"#include <cairo.h>#include <math.h>#include <stdio.h>#include <wtf/MathExtras.h>#if PLATFORM(GTK)#include <gdk/gdk.h>#include <pango/pango.h>#elif PLATFORM(WIN)#include <cairo-win32.h>#endif#include "GraphicsContextPrivate.h"#include "GraphicsContextPlatformPrivateCairo.h"#ifndef M_PI#define M_PI 3.14159265358979323846#endifnamespace WebCore {static const unsigned aquaFocusRingColor = 0xFF7DADD9;Color focusRingColor(){    static Color focusRingColor = aquaFocusRingColor;    return focusRingColor;}static inline void setColor(cairo_t* cr, const Color& col){    float red, green, blue, alpha;    col.getRGBA(red, green, blue, alpha);    cairo_set_source_rgba(cr, red, green, blue, alpha);}// A fillRect helperstatic inline void fillRectSourceOver(cairo_t* cr, const FloatRect& rect, const Color& col){    setColor(cr, col);    cairo_rectangle(cr, rect.x(), rect.y(), rect.width(), rect.height());    cairo_set_operator(cr, CAIRO_OPERATOR_OVER);    cairo_fill(cr);}GraphicsContext::GraphicsContext(PlatformGraphicsContext* cr)    : m_common(createGraphicsContextPrivate())    , m_data(new GraphicsContextPlatformPrivate){    m_data->cr = cairo_reference(cr);    setPaintingDisabled(!cr);}GraphicsContext::~GraphicsContext(){    destroyGraphicsContextPrivate(m_common);    delete m_data;}TransformationMatrix GraphicsContext::getCTM() const{    cairo_t* cr = platformContext();    cairo_matrix_t m;    cairo_get_matrix(cr, &m);    return TransformationMatrix(m.xx, m.yx, m.xy, m.yy, m.x0, m.y0);}cairo_t* GraphicsContext::platformContext() const{    return m_data->cr;}void GraphicsContext::savePlatformState(){    cairo_save(m_data->cr);    m_data->save();}void GraphicsContext::restorePlatformState(){    cairo_restore(m_data->cr);    m_data->restore();}// Draws a filled rectangle with a stroked border.void GraphicsContext::drawRect(const IntRect& rect){    if (paintingDisabled())        return;    cairo_t* cr = m_data->cr;    cairo_save(cr);    if (fillColor().alpha())        fillRectSourceOver(cr, rect, fillColor());    if (strokeStyle() != NoStroke) {        setColor(cr, strokeColor());        FloatRect r(rect);        r.inflate(-.5f);        cairo_rectangle(cr, r.x(), r.y(), r.width(), r.height());        cairo_set_line_width(cr, 1.0);        cairo_stroke(cr);    }    cairo_restore(cr);}// FIXME: Now that this is refactored, it should be shared by all contexts.static void adjustLineToPixelBoundaries(FloatPoint& p1, FloatPoint& p2, float strokeWidth, StrokeStyle style){    // For odd widths, we add in 0.5 to the appropriate x/y so that the float arithmetic    // works out.  For example, with a border width of 3, KHTML will pass us (y1+y2)/2, e.g.,    // (50+53)/2 = 103/2 = 51 when we want 51.5.  It is always true that an even width gave    // us a perfect position, but an odd width gave us a position that is off by exactly 0.5.    if (style == DottedStroke || style == DashedStroke) {        if (p1.x() == p2.x()) {            p1.setY(p1.y() + strokeWidth);            p2.setY(p2.y() - strokeWidth);        }        else {            p1.setX(p1.x() + strokeWidth);            p2.setX(p2.x() - strokeWidth);        }    }    if (static_cast<int>(strokeWidth) % 2) {        if (p1.x() == p2.x()) {            // We're a vertical line.  Adjust our x.            p1.setX(p1.x() + 0.5);            p2.setX(p2.x() + 0.5);        }        else {            // We're a horizontal line. Adjust our y.            p1.setY(p1.y() + 0.5);            p2.setY(p2.y() + 0.5);        }    }}// This is only used to draw borders.void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2){    if (paintingDisabled())        return;    StrokeStyle style = strokeStyle();    if (style == NoStroke)        return;    cairo_t* cr = m_data->cr;    cairo_save(cr);    float width = strokeThickness();    if (width < 1)        width = 1;    FloatPoint p1 = point1;    FloatPoint p2 = point2;    bool isVerticalLine = (p1.x() == p2.x());    adjustLineToPixelBoundaries(p1, p2, width, style);    cairo_set_line_width(cr, width);    int patWidth = 0;    switch (style) {    case NoStroke:    case SolidStroke:        break;    case DottedStroke:        patWidth = static_cast<int>(width);        break;    case DashedStroke:        patWidth = 3*static_cast<int>(width);        break;    }    setColor(cr, strokeColor());    cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE);    if (patWidth) {        // Do a rect fill of our endpoints.  This ensures we always have the        // appearance of being a border.  We then draw the actual dotted/dashed line.        if (isVerticalLine) {            fillRectSourceOver(cr, FloatRect(p1.x() - width/2, p1.y() - width, width, width), strokeColor());            fillRectSourceOver(cr, FloatRect(p2.x() - width/2, p2.y(), width, width), strokeColor());        } else {            fillRectSourceOver(cr, FloatRect(p1.x() - width, p1.y() - width/2, width, width), strokeColor());            fillRectSourceOver(cr, FloatRect(p2.x(), p2.y() - width/2, width, width), strokeColor());        }        // Example: 80 pixels with a width of 30 pixels.        // Remainder is 20.  The maximum pixels of line we could paint        // will be 50 pixels.        int distance = (isVerticalLine ? (point2.y() - point1.y()) : (point2.x() - point1.x())) - 2*static_cast<int>(width);        int remainder = distance%patWidth;        int coverage = distance-remainder;        int numSegments = coverage/patWidth;        float patternOffset = 0;        // Special case 1px dotted borders for speed.        if (patWidth == 1)            patternOffset = 1.0;        else {            bool evenNumberOfSegments = numSegments%2 == 0;            if (remainder)                evenNumberOfSegments = !evenNumberOfSegments;            if (evenNumberOfSegments) {                if (remainder) {                    patternOffset += patWidth - remainder;                    patternOffset += remainder/2;                }                else                    patternOffset = patWidth/2;            }            else if (!evenNumberOfSegments) {                if (remainder)                    patternOffset = (patWidth - remainder)/2;            }        }        double dash = patWidth;        cairo_set_dash(cr, &dash, 1, patternOffset);    }    cairo_move_to(cr, p1.x(), p1.y());    cairo_line_to(cr, p2.x(), p2.y());    cairo_stroke(cr);    cairo_restore(cr);}// This method is only used to draw the little circles used in lists.void GraphicsContext::drawEllipse(const IntRect& rect){    if (paintingDisabled())        return;    cairo_t* cr = m_data->cr;    cairo_save(cr);    float yRadius = .5 * rect.height();    float xRadius = .5 * rect.width();    cairo_translate(cr, rect.x() + xRadius, rect.y() + yRadius);    cairo_scale(cr, xRadius, yRadius);    cairo_arc(cr, 0., 0., 1., 0., 2 * M_PI);    cairo_restore(cr);    if (fillColor().alpha()) {        setColor(cr, fillColor());        cairo_fill_preserve(cr);    }    if (strokeStyle() != NoStroke) {        setColor(cr, strokeColor());        cairo_set_line_width(cr, strokeThickness());        cairo_stroke(cr);    }    cairo_new_path(cr);}void GraphicsContext::strokeArc(const IntRect& rect, int startAngle, int angleSpan){    if (paintingDisabled() || strokeStyle() == NoStroke)        return;    int x = rect.x();    int y = rect.y();    float w = rect.width();    float h = rect.height();    float scaleFactor = h / w;    float reverseScaleFactor = w / h;    float hRadius = w / 2;    float vRadius = h / 2;    float fa = startAngle;    float falen =  fa + angleSpan;    cairo_t* cr = m_data->cr;    cairo_save(cr);    if (w != h)        cairo_scale(cr, 1., scaleFactor);        cairo_arc_negative(cr, x + hRadius, (y + vRadius) * reverseScaleFactor, hRadius, -fa * M_PI/180, -falen * M_PI/180);    if (w != h)        cairo_scale(cr, 1., reverseScaleFactor);    float width = strokeThickness();    int patWidth = 0;        switch (strokeStyle()) {        case DottedStroke:            patWidth = static_cast<int>(width / 2);            break;        case DashedStroke:            patWidth = 3 * static_cast<int>(width / 2);            break;        default:            break;    }    setColor(cr, strokeColor());    if (patWidth) {        // Example: 80 pixels with a width of 30 pixels.        // Remainder is 20.  The maximum pixels of line we could paint        // will be 50 pixels.        int distance;        if (hRadius == vRadius)            distance = static_cast<int>((M_PI * hRadius) / 2.0);        else // We are elliptical and will have to estimate the distance            distance = static_cast<int>((M_PI * sqrtf((hRadius * hRadius + vRadius * vRadius) / 2.0)) / 2.0);                int remainder = distance % patWidth;        int coverage = distance - remainder;        int numSegments = coverage / patWidth;        float patternOffset = 0.0;        // Special case 1px dotted borders for speed.        if (patWidth == 1)            patternOffset = 1.0;        else {            bool evenNumberOfSegments = numSegments % 2 == 0;            if (remainder)                evenNumberOfSegments = !evenNumberOfSegments;            if (evenNumberOfSegments) {                if (remainder) {                    patternOffset += patWidth - remainder;                    patternOffset += remainder / 2.0;                } else                    patternOffset = patWidth / 2.0;            } else {                if (remainder)                    patternOffset = (patWidth - remainder) / 2.0;            }        }        double dash = patWidth;        cairo_set_dash(cr, &dash, 1, patternOffset);    }    cairo_stroke(cr);    cairo_restore(cr);}void GraphicsContext::drawConvexPolygon(size_t npoints, const FloatPoint* points, bool shouldAntialias){    if (paintingDisabled())        return;    if (npoints <= 1)        return;    cairo_t* cr = m_data->cr;    cairo_save(cr);    cairo_set_antialias(cr, shouldAntialias ? CAIRO_ANTIALIAS_DEFAULT : CAIRO_ANTIALIAS_NONE);    cairo_move_to(cr, points[0].x(), points[0].y());    for (size_t i = 1; i < npoints; i++)        cairo_line_to(cr, points[i].x(), points[i].y());    cairo_close_path(cr);    if (fillColor().alpha()) {        setColor(cr, fillColor());        cairo_set_fill_rule(cr, CAIRO_FILL_RULE_EVEN_ODD);        cairo_fill_preserve(cr);    }    if (strokeStyle() != NoStroke) {        setColor(cr, strokeColor());        cairo_set_line_width(cr, strokeThickness());        cairo_stroke(cr);    }    cairo_new_path(cr);    cairo_restore(cr);}void GraphicsContext::fillPath(){    if (paintingDisabled())        return;    cairo_t* cr = m_data->cr;    cairo_save(cr);    cairo_set_fill_rule(cr, fillRule() == RULE_EVENODD ? CAIRO_FILL_RULE_EVEN_ODD : CAIRO_FILL_RULE_WINDING);    switch (m_common->state.fillColorSpace) {    case SolidColorSpace:        setColor(cr, fillColor());        cairo_clip(cr);        cairo_paint_with_alpha(cr, m_common->state.globalAlpha);        break;    case PatternColorSpace: {        TransformationMatrix affine;        cairo_set_source(cr, m_common->state.fillPattern->createPlatformPattern(affine));        cairo_clip(cr);        cairo_paint_with_alpha(cr, m_common->state.globalAlpha);        break;    }    case GradientColorSpace:        cairo_pattern_t* pattern = m_common->state.fillGradient->platformGradient();        cairo_set_source(cr, pattern);        cairo_clip(cr);        cairo_paint_with_alpha(cr, m_common->state.globalAlpha);        break;    }    cairo_restore(cr);}void GraphicsContext::strokePath(){    if (paintingDisabled())        return;    cairo_t* cr = m_data->cr;    cairo_save(cr);    switch (m_common->state.strokeColorSpace) {    case SolidColorSpace:        float red, green, blue, alpha;        strokeColor().getRGBA(red, green, blue, alpha);        if (m_common->state.globalAlpha < 1.0f)            alpha *= m_common->state.globalAlpha;        cairo_set_source_rgba(cr, red, green, blue, alpha);        cairo_stroke(cr);        break;    case PatternColorSpace: {        TransformationMatrix affine;        cairo_set_source(cr, m_common->state.strokePattern->createPlatformPattern(affine));        if (m_common->state.globalAlpha < 1.0f) {            cairo_push_group(cr);            cairo_paint_with_alpha(cr, m_common->state.globalAlpha);            cairo_pop_group_to_source(cr);        }        cairo_stroke(cr);        break;    }    case GradientColorSpace:        cairo_pattern_t* pattern = m_common->state.strokeGradient->platformGradient();        cairo_set_source(cr, pattern);        if (m_common->state.globalAlpha < 1.0f) {            cairo_push_group(cr);            cairo_paint_with_alpha(cr, m_common->state.globalAlpha);            cairo_pop_group_to_source(cr);        }        cairo_stroke(cr);        break;    }    cairo_restore(cr);}void GraphicsContext::drawPath(){    fillPath();    strokePath();}void GraphicsContext::fillRect(const FloatRect& rect){    if (paintingDisabled())        return;    cairo_t* cr = m_data->cr;    cairo_rectangle(cr, rect.x(), rect.y(), rect.width(), rect.height());    fillPath();}void GraphicsContext::fillRect(const FloatRect& rect, const Color& color){    if (paintingDisabled())        return;    if (color.alpha())        fillRectSourceOver(m_data->cr, rect, color);}void GraphicsContext::clip(const FloatRect& rect){    if (paintingDisabled())        return;    cairo_t* cr = m_data->cr;    cairo_rectangle(cr, rect.x(), rect.y(), rect.width(), rect.height());    cairo_fill_rule_t savedFillRule = cairo_get_fill_rule(cr);    cairo_set_fill_rule(cr, CAIRO_FILL_RULE_WINDING);    cairo_clip(cr);    cairo_set_fill_rule(cr, savedFillRule);    m_data->clip(rect);}void GraphicsContext::clipPath(WindRule clipRule){    if (paintingDisabled())        return;    cairo_t* cr = m_data->cr;    cairo_set_fill_rule(cr, clipRule == RULE_EVENODD ? CAIRO_FILL_RULE_EVEN_ODD : CAIRO_FILL_RULE_WINDING);    cairo_clip(cr);}void GraphicsContext::drawFocusRing(const Color& color){    if (paintingDisabled())        return;

⌨️ 快捷键说明

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