📄 canvasrenderingcontext2d.cpp
字号:
/* * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) * Copyright (C) 2007 Alp Toker <alp@atoker.com> * Copyright (C) 2008 Eric Seidel <eric@webkit.org> * Copyright (C) 2008 Dirk Schulze <krit@webkit.org> * * 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 "CanvasRenderingContext2D.h"#include "TransformationMatrix.h"#include "CSSParser.h"#include "CachedImage.h"#include "CanvasGradient.h"#include "CanvasPattern.h"#include "CanvasStyle.h"#include "CSSPropertyNames.h"#include "CSSStyleSelector.h"#include "Document.h"#include "ExceptionCode.h"#include "FloatConversion.h"#include "Frame.h"#include "GraphicsContext.h"#include "HTMLCanvasElement.h"#include "HTMLImageElement.h"#include "HTMLNames.h"#include "ImageBuffer.h"#include "ImageData.h"#include "KURL.h"#include "NotImplemented.h"#include "Page.h"#include "RenderHTMLCanvas.h"#include "SecurityOrigin.h"#include "Settings.h"#include "StrokeStyleApplier.h"#include "TextMetrics.h"#include <stdio.h>#include <wtf/ByteArray.h>#include <wtf/MathExtras.h>using namespace std;namespace WebCore {using namespace HTMLNames;static const char* const defaultFont = "10px sans-serif";class CanvasStrokeStyleApplier : public StrokeStyleApplier {public: CanvasStrokeStyleApplier(CanvasRenderingContext2D* canvasContext) : m_canvasContext(canvasContext) { } virtual void strokeStyle(GraphicsContext* c) { c->setStrokeThickness(m_canvasContext->lineWidth()); c->setLineCap(m_canvasContext->getLineCap()); c->setLineJoin(m_canvasContext->getLineJoin()); c->setMiterLimit(m_canvasContext->miterLimit()); }private: CanvasRenderingContext2D* m_canvasContext;};CanvasRenderingContext2D::CanvasRenderingContext2D(HTMLCanvasElement* canvas) : m_canvas(canvas) , m_stateStack(1){}void CanvasRenderingContext2D::ref(){ m_canvas->ref();}void CanvasRenderingContext2D::deref(){ m_canvas->deref(); }void CanvasRenderingContext2D::reset(){ m_stateStack.resize(1); m_stateStack.first() = State();}CanvasRenderingContext2D::State::State() : m_strokeStyle(CanvasStyle::create("black")) , m_fillStyle(CanvasStyle::create("black")) , m_lineWidth(1) , m_lineCap(ButtCap) , m_lineJoin(MiterJoin) , m_miterLimit(10) , m_shadowBlur(0) , m_shadowColor("black") , m_globalAlpha(1) , m_globalComposite(CompositeSourceOver) , m_invertibleCTM(true) , m_textAlign(StartTextAlign) , m_textBaseline(AlphabeticTextBaseline) , m_unparsedFont(defaultFont) , m_realizedFont(false){}void CanvasRenderingContext2D::save(){ ASSERT(m_stateStack.size() >= 1); m_stateStack.append(state()); GraphicsContext* c = drawingContext(); if (!c) return; c->save();}void CanvasRenderingContext2D::restore(){ ASSERT(m_stateStack.size() >= 1); if (m_stateStack.size() <= 1) return; m_path.transform(state().m_transform); m_stateStack.removeLast(); m_path.transform(state().m_transform.inverse()); GraphicsContext* c = drawingContext(); if (!c) return; c->restore();}CanvasStyle* CanvasRenderingContext2D::strokeStyle() const{ return state().m_strokeStyle.get();}void CanvasRenderingContext2D::setStrokeStyle(PassRefPtr<CanvasStyle> style){ if (!style) return; if (m_canvas->originClean()) { if (CanvasPattern* pattern = style->canvasPattern()) { if (!pattern->originClean()) m_canvas->setOriginTainted(); } } state().m_strokeStyle = style; GraphicsContext* c = drawingContext(); if (!c) return; state().m_strokeStyle->applyStrokeColor(c);}CanvasStyle* CanvasRenderingContext2D::fillStyle() const{ return state().m_fillStyle.get();}void CanvasRenderingContext2D::setFillStyle(PassRefPtr<CanvasStyle> style){ if (!style) return; if (m_canvas->originClean()) { if (CanvasPattern* pattern = style->canvasPattern()) { if (!pattern->originClean()) m_canvas->setOriginTainted(); } } state().m_fillStyle = style; GraphicsContext* c = drawingContext(); if (!c) return; state().m_fillStyle->applyFillColor(c);}float CanvasRenderingContext2D::lineWidth() const{ return state().m_lineWidth;}void CanvasRenderingContext2D::setLineWidth(float width){ if (!(width > 0)) return; state().m_lineWidth = width; GraphicsContext* c = drawingContext(); if (!c) return; c->setStrokeThickness(width);}String CanvasRenderingContext2D::lineCap() const{ return lineCapName(state().m_lineCap);}void CanvasRenderingContext2D::setLineCap(const String& s){ LineCap cap; if (!parseLineCap(s, cap)) return; state().m_lineCap = cap; GraphicsContext* c = drawingContext(); if (!c) return; c->setLineCap(cap);}String CanvasRenderingContext2D::lineJoin() const{ return lineJoinName(state().m_lineJoin);}void CanvasRenderingContext2D::setLineJoin(const String& s){ LineJoin join; if (!parseLineJoin(s, join)) return; state().m_lineJoin = join; GraphicsContext* c = drawingContext(); if (!c) return; c->setLineJoin(join);}float CanvasRenderingContext2D::miterLimit() const{ return state().m_miterLimit;}void CanvasRenderingContext2D::setMiterLimit(float limit){ if (!(limit > 0)) return; state().m_miterLimit = limit; GraphicsContext* c = drawingContext(); if (!c) return; c->setMiterLimit(limit);}float CanvasRenderingContext2D::shadowOffsetX() const{ return state().m_shadowOffset.width();}void CanvasRenderingContext2D::setShadowOffsetX(float x){ state().m_shadowOffset.setWidth(x); applyShadow();}float CanvasRenderingContext2D::shadowOffsetY() const{ return state().m_shadowOffset.height();}void CanvasRenderingContext2D::setShadowOffsetY(float y){ state().m_shadowOffset.setHeight(y); applyShadow();}float CanvasRenderingContext2D::shadowBlur() const{ return state().m_shadowBlur;}void CanvasRenderingContext2D::setShadowBlur(float blur){ state().m_shadowBlur = blur; applyShadow();}String CanvasRenderingContext2D::shadowColor() const{ // FIXME: What should this return if you called setShadow with a non-string color? return state().m_shadowColor;}void CanvasRenderingContext2D::setShadowColor(const String& color){ state().m_shadowColor = color; applyShadow();}float CanvasRenderingContext2D::globalAlpha() const{ return state().m_globalAlpha;}void CanvasRenderingContext2D::setGlobalAlpha(float alpha){ if (!(alpha >= 0 && alpha <= 1)) return; state().m_globalAlpha = alpha; GraphicsContext* c = drawingContext(); if (!c) return; c->setAlpha(alpha);}String CanvasRenderingContext2D::globalCompositeOperation() const{ return compositeOperatorName(state().m_globalComposite);}void CanvasRenderingContext2D::setGlobalCompositeOperation(const String& operation){ CompositeOperator op; if (!parseCompositeOperator(operation, op)) return; state().m_globalComposite = op; GraphicsContext* c = drawingContext(); if (!c) return; c->setCompositeOperation(op);}void CanvasRenderingContext2D::scale(float sx, float sy){ GraphicsContext* c = drawingContext(); if (!c) return; if (!state().m_invertibleCTM) return; TransformationMatrix newTransform = state().m_transform; newTransform.scaleNonUniform(sx, sy); if (!newTransform.isInvertible()) { state().m_invertibleCTM = false; return; } state().m_transform = newTransform; c->scale(FloatSize(sx, sy)); m_path.transform(TransformationMatrix().scaleNonUniform(1.0/sx, 1.0/sy));}void CanvasRenderingContext2D::rotate(float angleInRadians){ GraphicsContext* c = drawingContext(); if (!c) return; if (!state().m_invertibleCTM) return; TransformationMatrix newTransform = state().m_transform; newTransform.rotate(angleInRadians / piDouble * 180.0); if (!newTransform.isInvertible()) { state().m_invertibleCTM = false; return; } state().m_transform = newTransform; c->rotate(angleInRadians); m_path.transform(TransformationMatrix().rotate(-angleInRadians / piDouble * 180.0));}void CanvasRenderingContext2D::translate(float tx, float ty){ GraphicsContext* c = drawingContext(); if (!c) return; if (!state().m_invertibleCTM) return; TransformationMatrix newTransform = state().m_transform; newTransform.translate(tx, ty); if (!newTransform.isInvertible()) { state().m_invertibleCTM = false; return; } state().m_transform = newTransform; c->translate(tx, ty); m_path.transform(TransformationMatrix().translate(-tx, -ty));}void CanvasRenderingContext2D::transform(float m11, float m12, float m21, float m22, float dx, float dy){ GraphicsContext* c = drawingContext(); if (!c) return; if (!state().m_invertibleCTM) return; // HTML5 3.14.11.1 -- ignore any calls that pass non-finite numbers if (!isfinite(m11) | !isfinite(m21) | !isfinite(dx) | !isfinite(m12) | !isfinite(m22) | !isfinite(dy)) return; TransformationMatrix transform(m11, m12, m21, m22, dx, dy); TransformationMatrix newTransform = transform * state().m_transform; if (!newTransform.isInvertible()) { state().m_invertibleCTM = false; return; } state().m_transform = newTransform; c->concatCTM(transform); m_path.transform(transform.inverse());}void CanvasRenderingContext2D::setTransform(float m11, float m12, float m21, float m22, float dx, float dy){ GraphicsContext* c = drawingContext(); if (!c) return; // HTML5 3.14.11.1 -- ignore any calls that pass non-finite numbers if (!isfinite(m11) | !isfinite(m21) | !isfinite(dx) | !isfinite(m12) | !isfinite(m22) | !isfinite(dy)) return; TransformationMatrix ctm = state().m_transform; if (!ctm.isInvertible()) return; c->concatCTM(c->getCTM().inverse()); c->concatCTM(m_canvas->baseTransform()); state().m_transform.multiply(ctm.inverse()); m_path.transform(ctm); state().m_invertibleCTM = true; transform(m11, m12, m21, m22, dx, dy);}void CanvasRenderingContext2D::setStrokeColor(const String& color){ setStrokeStyle(CanvasStyle::create(color));}void CanvasRenderingContext2D::setStrokeColor(float grayLevel){ setStrokeStyle(CanvasStyle::create(grayLevel, 1));}void CanvasRenderingContext2D::setStrokeColor(const String& color, float alpha){ setStrokeStyle(CanvasStyle::create(color, alpha));}void CanvasRenderingContext2D::setStrokeColor(float grayLevel, float alpha){ setStrokeStyle(CanvasStyle::create(grayLevel, alpha));}void CanvasRenderingContext2D::setStrokeColor(float r, float g, float b, float a){ setStrokeStyle(CanvasStyle::create(r, g, b, a));}void CanvasRenderingContext2D::setStrokeColor(float c, float m, float y, float k, float a){ setStrokeStyle(CanvasStyle::create(c, m, y, k, a));}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -