📄 graphicscontextskia.cpp
字号:
/* * Copyright (c) 2006, 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 "GraphicsContext.h"#include "GraphicsContextPlatformPrivate.h"#include "GraphicsContextPrivate.h"#include "Color.h"#include "FloatRect.h"#include "Gradient.h"#include "ImageBuffer.h"#include "IntRect.h"#include "NativeImageSkia.h"#include "NotImplemented.h"#include "PlatformContextSkia.h"#include "TransformationMatrix.h"#include "SkBitmap.h"#include "SkBlurDrawLooper.h"#include "SkCornerPathEffect.h"#include "skia/ext/platform_canvas.h"#include "SkiaUtils.h"#include "SkShader.h"#include <math.h>#include <wtf/Assertions.h>#include <wtf/MathExtras.h>using namespace std;namespace WebCore {namespace {// "Seatbelt" functions ------------------------------------------------------//// These functions check certain graphics primitives for being "safe".// Skia has historically crashed when sent crazy data. These functions do// additional checking to prevent crashes.//// Ideally, all of these would be fixed in the graphics layer and we would not// have to do any checking. You can uncomment the ENSURE_VALUE_SAFETY_FOR_SKIA// flag to check the graphics layer.#define ENSURE_VALUE_SAFETY_FOR_SKIAstatic bool isCoordinateSkiaSafe(float coord){#ifdef ENSURE_VALUE_SAFETY_FOR_SKIA // First check for valid floats.#if defined(_MSC_VER) if (!_finite(coord))#else if (!finite(coord))#endif return false; // Skia uses 16.16 fixed point and 26.6 fixed point in various places. If // the transformed point exceeds 15 bits, we just declare that it's // unreasonable to catch both of these cases. static const int maxPointMagnitude = 32767; if (coord > maxPointMagnitude || coord < -maxPointMagnitude) return false; return true;#else return true;#endif}static bool isPointSkiaSafe(const SkMatrix& transform, const SkPoint& pt){#ifdef ENSURE_VALUE_SAFETY_FOR_SKIA // Now check for points that will overflow. We check the *transformed* // points since this is what will be rasterized. SkPoint xPt; transform.mapPoints(&xPt, &pt, 1); return isCoordinateSkiaSafe(xPt.fX) && isCoordinateSkiaSafe(xPt.fY);#else return true;#endif}static bool isRectSkiaSafe(const SkMatrix& transform, const SkRect& rc){#ifdef ENSURE_VALUE_SAFETY_FOR_SKIA SkPoint topleft = {rc.fLeft, rc.fTop}; SkPoint bottomright = {rc.fRight, rc.fBottom}; return isPointSkiaSafe(transform, topleft) && isPointSkiaSafe(transform, bottomright);#else return true;#endif}bool isPathSkiaSafe(const SkMatrix& transform, const SkPath& path){#ifdef ENSURE_VALUE_SAFETY_FOR_SKIA SkPoint current_points[4]; SkPath::Iter iter(path, false); for (SkPath::Verb verb = iter.next(current_points); verb != SkPath::kDone_Verb; verb = iter.next(current_points)) { switch (verb) { case SkPath::kMove_Verb: // This move will be duplicated in the next verb, so we can ignore. break; case SkPath::kLine_Verb: // iter.next returns 2 points. if (!isPointSkiaSafe(transform, current_points[0]) || !isPointSkiaSafe(transform, current_points[1])) return false; break; case SkPath::kQuad_Verb: // iter.next returns 3 points. if (!isPointSkiaSafe(transform, current_points[0]) || !isPointSkiaSafe(transform, current_points[1]) || !isPointSkiaSafe(transform, current_points[2])) return false; break; case SkPath::kCubic_Verb: // iter.next returns 4 points. if (!isPointSkiaSafe(transform, current_points[0]) || !isPointSkiaSafe(transform, current_points[1]) || !isPointSkiaSafe(transform, current_points[2]) || !isPointSkiaSafe(transform, current_points[3])) return false; break; case SkPath::kClose_Verb: case SkPath::kDone_Verb: default: break; } } return true;#else return true;#endif}// Local helper functions ------------------------------------------------------void addCornerArc(SkPath* path, const SkRect& rect, const IntSize& size, int startAngle){ SkIRect ir; int rx = SkMin32(SkScalarRound(rect.width()), size.width()); int ry = SkMin32(SkScalarRound(rect.height()), size.height()); ir.set(-rx, -ry, rx, ry); switch (startAngle) { case 0: ir.offset(rect.fRight - ir.fRight, rect.fBottom - ir.fBottom); break; case 90: ir.offset(rect.fLeft - ir.fLeft, rect.fBottom - ir.fBottom); break; case 180: ir.offset(rect.fLeft - ir.fLeft, rect.fTop - ir.fTop); break; case 270: ir.offset(rect.fRight - ir.fRight, rect.fTop - ir.fTop); break; default: ASSERT(0); } SkRect r; r.set(ir); path->arcTo(r, SkIntToScalar(startAngle), SkIntToScalar(90), false);}inline int fastMod(int value, int max){ int sign = SkExtractSign(value); value = SkApplySign(value, sign); if (value >= max) value %= max; return SkApplySign(value, sign);}inline float square(float n){ return n * n;}} // namespace// -----------------------------------------------------------------------------// This may be called with a NULL pointer to create a graphics context that has// no painting.GraphicsContext::GraphicsContext(PlatformGraphicsContext* gc) : m_common(createGraphicsContextPrivate()) , m_data(new GraphicsContextPlatformPrivate(gc)){ setPaintingDisabled(!gc || !platformContext()->canvas());}GraphicsContext::~GraphicsContext(){ delete m_data; this->destroyGraphicsContextPrivate(m_common);}PlatformGraphicsContext* GraphicsContext::platformContext() const{ ASSERT(!paintingDisabled()); return m_data->context();}// State saving ----------------------------------------------------------------void GraphicsContext::savePlatformState(){ if (paintingDisabled()) return; // Save our private State. platformContext()->save();}void GraphicsContext::restorePlatformState(){ if (paintingDisabled()) return; // Restore our private State. platformContext()->restore();}void GraphicsContext::beginTransparencyLayer(float opacity){ if (paintingDisabled()) return; // We need the "alpha" layer flag here because the base layer is opaque // (the surface of the page) but layers on top may have transparent parts. // Without explicitly setting the alpha flag, the layer will inherit the // opaque setting of the base and some things won't work properly. platformContext()->canvas()->saveLayerAlpha( 0, static_cast<unsigned char>(opacity * 255), static_cast<SkCanvas::SaveFlags>(SkCanvas::kHasAlphaLayer_SaveFlag | SkCanvas::kFullColorLayer_SaveFlag));}void GraphicsContext::endTransparencyLayer(){ if (paintingDisabled()) return; platformContext()->canvas()->restore();}// Graphics primitives ---------------------------------------------------------void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, int thickness){ if (paintingDisabled()) return; SkRect r(rect); if (!isRectSkiaSafe(getCTM(), r)) return; SkPath path; path.addOval(r, SkPath::kCW_Direction); // only perform the inset if we won't invert r if (2 * thickness < rect.width() && 2 * thickness < rect.height()) { r.inset(SkIntToScalar(thickness) ,SkIntToScalar(thickness)); path.addOval(r, SkPath::kCCW_Direction); } platformContext()->canvas()->clipPath(path);}void GraphicsContext::addPath(const Path& path){ if (paintingDisabled()) return; platformContext()->addPath(*path.platformPath());}void GraphicsContext::beginPath(){ if (paintingDisabled()) return; platformContext()->beginPath();}void GraphicsContext::clearPlatformShadow(){ if (paintingDisabled()) return; platformContext()->setDrawLooper(0);}void GraphicsContext::clearRect(const FloatRect& rect){ if (paintingDisabled()) return; SkRect r = rect; if (!isRectSkiaSafe(getCTM(), r)) ClipRectToCanvas(*platformContext()->canvas(), r, &r); SkPaint paint; platformContext()->setupPaintForFilling(&paint); paint.setPorterDuffXfermode(SkPorterDuff::kClear_Mode); platformContext()->canvas()->drawRect(r, paint);}void GraphicsContext::clip(const FloatRect& rect){ if (paintingDisabled()) return; SkRect r(rect); if (!isRectSkiaSafe(getCTM(), r)) return; platformContext()->canvas()->clipRect(r);}void GraphicsContext::clip(const Path& path){ if (paintingDisabled()) return; const SkPath& p = *path.platformPath(); if (!isPathSkiaSafe(getCTM(), p)) return; platformContext()->canvas()->clipPath(p);}void GraphicsContext::clipOut(const IntRect& rect){ if (paintingDisabled()) return; SkRect r(rect); if (!isRectSkiaSafe(getCTM(), r)) return; platformContext()->canvas()->clipRect(r, SkRegion::kDifference_Op);}void GraphicsContext::clipOut(const Path& p){ if (paintingDisabled()) return; const SkPath& path = *p.platformPath(); if (!isPathSkiaSafe(getCTM(), path))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -