File indexing completed on 2024-05-05 16:10:09
0001 /* 0002 * Copyright (C) 2007, 2008 Maksim Orlovich <maksim@kde.org> 0003 * Copyright (C) 2004 Apple Computer, Inc. All rights reserved. 0004 * Copyright (C) 2007, 2008 Fredrik Höglund <fredrik@kde.org> 0005 * 0006 * This library is free software; you can redistribute it and/or 0007 * modify it under the terms of the GNU Lesser General Public 0008 * License as published by the Free Software Foundation; either 0009 * version 2 of the License, or (at your option) any later version. 0010 * 0011 * This library is distributed in the hope that it will be useful, 0012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0014 * Lesser General Public License for more details. 0015 * 0016 * You should have received a copy of the GNU Lesser General Public 0017 * License along with this library; if not, write to the Free Software 0018 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 0019 * 0020 * Portions of this code are (c) by Apple Computer, Inc. and were licensed 0021 * under the following terms: 0022 * 0023 * Redistribution and use in source and binary forms, with or without 0024 * modification, are permitted provided that the following conditions 0025 * are met: 0026 * 1. Redistributions of source code must retain the above copyright 0027 * notice, this list of conditions and the following disclaimer. 0028 * 2. Redistributions in binary form must reproduce the above copyright 0029 * notice, this list of conditions and the following disclaimer in the 0030 * documentation and/or other materials provided with the distribution. 0031 * 0032 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY 0033 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 0034 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 0035 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 0036 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 0037 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 0038 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 0039 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 0040 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 0041 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 0042 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 0043 */ 0044 #ifndef HTML_CANVASIMPL_H 0045 #define HTML_CANVASIMPL_H 0046 0047 #include "dom/dom_string.h" 0048 #include "html/html_elementimpl.h" 0049 #include "misc/khtmllayout.h" 0050 #include "rendering/render_object.h" 0051 0052 #include <QRegion> 0053 #include <QMap> 0054 #include <QList> 0055 #include <QStack> 0056 #include <QPixmap> 0057 #include <QGradient> 0058 0059 namespace khtmlImLoad 0060 { 0061 class CanvasImage; 0062 } 0063 0064 namespace DOM 0065 { 0066 0067 class CanvasContext2DImpl; 0068 0069 class HTMLCanvasElementImpl : public HTMLElementImpl 0070 { 0071 public: 0072 HTMLCanvasElementImpl(DocumentImpl *doc); 0073 ~HTMLCanvasElementImpl(); 0074 0075 void parseAttribute(AttributeImpl *) override; 0076 Id id() const override; 0077 0078 void attach() override; 0079 0080 int width() const 0081 { 0082 return w; 0083 } 0084 int height() const 0085 { 0086 return h; 0087 } 0088 0089 CanvasContext2DImpl *getContext2D(); 0090 0091 // Note: we use QString here for efficiency reasons. We only need 0092 // one version since we only do the required image/png 0093 QString toDataURL(int &exceptionCode); 0094 0095 // Returns the canvas image, but does not guarantee it's 0096 // up-to-date 0097 khtmlImLoad::CanvasImage *getCanvasImage(); 0098 0099 bool isUnsafe() const; 0100 void markUnsafe(); 0101 private: 0102 int w, h; 0103 SharedPtr<CanvasContext2DImpl> context; 0104 bool unsafe; 0105 }; 0106 0107 // Base class for representing styles for fill and stroke. 0108 // Not part of the DOM 0109 class CanvasStyleBaseImpl : public khtml::Shared<CanvasStyleBaseImpl> 0110 { 0111 public: 0112 enum Type { 0113 Color, 0114 Gradient, 0115 Pattern 0116 }; 0117 0118 virtual bool isUnsafe() const 0119 { 0120 return false; 0121 } 0122 virtual ~CanvasStyleBaseImpl() {} 0123 0124 virtual Type type() const = 0; 0125 virtual QBrush toBrush() const = 0; 0126 }; 0127 0128 // Not part of the DOM. 0129 class CanvasColorImpl : public CanvasStyleBaseImpl 0130 { 0131 public: 0132 QColor color; 0133 0134 CanvasColorImpl(const QColor &newColor) : color(newColor) 0135 {} 0136 0137 Type type() const override 0138 { 0139 return Color; 0140 } 0141 0142 QBrush toBrush() const override 0143 { 0144 return QBrush(color); 0145 } 0146 0147 DOM::DOMString toString() const; 0148 0149 // Note: returns 0 if it can not be parsed. 0150 static CanvasColorImpl *fromString(const DOM::DOMString &s); 0151 }; 0152 0153 class CanvasPatternImpl : public CanvasStyleBaseImpl 0154 { 0155 public: 0156 CanvasPatternImpl(const QImage &inImg, bool unsafe, bool rx, bool ry); 0157 0158 Type type() const override 0159 { 0160 return Pattern; 0161 } 0162 QBrush toBrush() const override; 0163 0164 // Returns the rect that a pattern fill or stroke should be clipped to, given 0165 // the repeat setting and the indicated brush origin and bounding rect. 0166 // The bounding rect (usually the canvas rect) limits the clip rect extent 0167 // in the repeating dimension(s). 0168 QRectF clipForRepeat(const QPointF &origin, const QRectF &bounds) const; 0169 0170 bool isUnsafe() const override 0171 { 0172 return unsafe; 0173 } 0174 private: 0175 QImage img; 0176 bool repeatX, repeatY; 0177 bool unsafe; 0178 }; 0179 0180 class CanvasGradientImpl : public CanvasStyleBaseImpl 0181 { 0182 public: 0183 CanvasGradientImpl(QGradient *newGradient, float innerRadius = 0.0, bool inverse = false); 0184 ~CanvasGradientImpl(); 0185 0186 // Our internal interface.. 0187 Type type() const override 0188 { 0189 return Gradient; 0190 } 0191 QBrush toBrush() const override; 0192 0193 // DOM API 0194 void addColorStop(float offset, const DOM::DOMString &color, int &exceptionCode); 0195 private: 0196 QGradient *gradient; 0197 float innerRadius; // In a radial gradient 0198 bool inverse; // For radial gradients only 0199 }; 0200 0201 class CanvasImageDataImpl : public khtml::Shared<CanvasImageDataImpl> 0202 { 0203 public: 0204 // Creates an uninitialized image.. 0205 CanvasImageDataImpl(unsigned width, unsigned height); 0206 CanvasImageDataImpl *clone() const; 0207 0208 unsigned width() const; 0209 unsigned height() const; 0210 QColor pixel(unsigned pixelNum) const; 0211 void setPixel(unsigned pixelNum, const QColor &val); 0212 void setComponent(unsigned pixelNum, int component, int value); 0213 QImage data; 0214 private: 0215 CanvasImageDataImpl(const QImage &_data); 0216 }; 0217 0218 class CanvasContext2DImpl : public khtml::Shared<CanvasContext2DImpl> 0219 { 0220 public: 0221 CanvasContext2DImpl(HTMLCanvasElementImpl *element, int width, int height); 0222 ~CanvasContext2DImpl(); 0223 0224 // Note: the native API does not attempt to validate 0225 // input for NaN and +/- infinity to raise exceptions; 0226 // but it does handle them for transformations 0227 0228 // For renderer.. 0229 void commit(); 0230 0231 // Public API, exported via the DOM. 0232 HTMLCanvasElementImpl *canvas() const; 0233 0234 // State management 0235 void save(); 0236 void restore(); 0237 0238 // Transformations 0239 void scale(float x, float y); 0240 void rotate(float angle); 0241 void translate(float x, float y); 0242 void transform(float m11, float m12, float m21, float m22, float dx, float dy); 0243 void setTransform(float m11, float m12, float m21, float m22, float dx, float dy); 0244 0245 // Composition state setting 0246 float globalAlpha() const; 0247 void setGlobalAlpha(float a); 0248 DOMString globalCompositeOperation() const; 0249 void setGlobalCompositeOperation(const DOMString &op); 0250 0251 // Colors and styles.. 0252 void setStrokeStyle(CanvasStyleBaseImpl *strokeStyle); 0253 CanvasStyleBaseImpl *strokeStyle() const; 0254 void setFillStyle(CanvasStyleBaseImpl *fillStyle); 0255 CanvasStyleBaseImpl *fillStyle() const; 0256 CanvasGradientImpl *createLinearGradient(float x0, float y0, float x1, float y1) const; 0257 CanvasGradientImpl *createRadialGradient(float x0, float y0, float r0, float x1, float y1, float r1, int &exceptionCode) const; 0258 CanvasPatternImpl *createPattern(ElementImpl *pat, const DOMString &rpt, int &exceptionCode) const; 0259 0260 // Line attributes 0261 float lineWidth() const; 0262 void setLineWidth(float newLW); 0263 DOMString lineCap() const; 0264 void setLineCap(const DOMString &newCap); 0265 DOMString lineJoin() const; 0266 void setLineJoin(const DOMString &newJoin); 0267 float miterLimit() const; 0268 void setMiterLimit(float newML); 0269 0270 // Shadow attributes 0271 float shadowOffsetX() const; 0272 void setShadowOffsetX(float newOX); 0273 float shadowOffsetY() const; 0274 void setShadowOffsetY(float newOY); 0275 float shadowBlur() const; 0276 void setShadowBlur(float newBlur); 0277 DOMString shadowColor() const; 0278 void setShadowColor(const DOMString &newColor); 0279 0280 // Rectangle operations 0281 void clearRect(float x, float y, float w, float h, int &exceptionCode); 0282 void fillRect(float x, float y, float w, float h, int &exceptionCode); 0283 void strokeRect(float x, float y, float w, float h, int &exceptionCode); 0284 0285 // Path-based ops 0286 void beginPath(); 0287 void closePath(); 0288 void moveTo(float x, float y); 0289 void lineTo(float x, float y); 0290 void quadraticCurveTo(float cpx, float cpy, float x, float y); 0291 void bezierCurveTo(float cp1x, float cp1y, float cp2x, float cp2y, float x, float y); 0292 void arcTo(float x1, float y1, float x2, float y2, float radius, int &exceptionCode); 0293 void rect(float x, float y, float w, float h, int &exceptionCode); 0294 void arc(float x, float y, float radius, float startAngle, float endAngle, 0295 bool ccw, int &exceptionCode); 0296 void fill(); 0297 void stroke(); 0298 void clip(); 0299 bool isPointInPath(float x, float y) const; 0300 0301 // Image ops 0302 void drawImage(ElementImpl *image, float dx, float dy, int &exceptionCode); 0303 void drawImage(ElementImpl *image, float dx, float dy, float dw, float dh, int &exceptionCode); 0304 void drawImage(ElementImpl *image, float sx, float sy, float sw, float sh, 0305 float dx, float dy, float dw, float dh, int &exceptionCode); 0306 0307 // Pixel ops 0308 CanvasImageDataImpl *getImageData(float sx, float sy, float sw, float sh, int &exceptionCode); 0309 void putImageData(CanvasImageDataImpl *data, float dx, float dy, int &exceptionCode); 0310 CanvasImageDataImpl *createImageData(float sw, float sh, int &exceptionCode); 0311 0312 private: 0313 friend class HTMLCanvasElementImpl; 0314 0315 enum PathPaintOp { DrawFill, DrawStroke }; 0316 enum PaintFlags { NoPaintFlags = 0, NotUsingCanvasPattern = 1 }; 0317 0318 // initialize canvas for new size 0319 void resetContext(int width, int height); 0320 0321 bool isPathEmpty() const; 0322 0323 bool needsShadow() const; 0324 0325 // Returns the clip path in device coordinates that the fill or stroke should be 0326 // limited to, given the repeat setting of the pattern that will be used. 0327 QPainterPath clipForPatternRepeat(QPainter *painter, const PathPaintOp op) const; 0328 0329 // Helper function that fills or strokes a path, honoring shadow and pattern 0330 // repeat settings. 0331 void drawPath(QPainter *painter, const QPainterPath &path, PathPaintOp op) const; 0332 0333 // Draws a shadowed path using the painter. 0334 void drawPathWithShadow(QPainter *painter, const QPainterPath &path, PathPaintOp op, 0335 PaintFlags flags = NoPaintFlags) const; 0336 0337 void drawImage(QPainter *painter, const QRectF &dstRect, const QImage &image, 0338 const QRectF &srcRect) const; 0339 0340 // Cleared by canvas dtor.. 0341 HTMLCanvasElementImpl *canvasElement; 0342 0343 // Helper for methods that take images via elements; this will extract them, 0344 // and signal an exception if needed be. It will also return if the 0345 // image is unsafe 0346 QImage extractImage(ElementImpl *el, int &exceptionCode, bool &unsafeOut) const; 0347 0348 // This method will prepare a painter for use, making sure it's active, 0349 // that all the dirty state got sync'd, etc, and will mark the 0350 // canvas as dirty so the renderer can flush everything, etc. 0351 QPainter *acquirePainter(); 0352 0353 // We use khtmlImLoad to manage our canvas image, so that 0354 // the Renderer can scale easily. 0355 khtmlImLoad::CanvasImage *canvasImage; 0356 0357 // The path is global, and never saved/restored 0358 QPainterPath path; 0359 0360 // We keep track of non-path state ourselves. There are two reasons: 0361 // 1) The painter may have to be end()ed so we can not rely on it to remember 0362 // things 0363 // 2) The stroke and fill style can actually be DOM objects, so we have to 0364 // be able to hand them back 0365 // "The canvas state" section of the spec describes what's included here 0366 struct PaintState { 0367 // Viewport state (not readable from outside) 0368 QTransform transform; 0369 bool infinityTransform; // Marks that the transform has become invalid, 0370 // and should be treated as identity. 0371 QPainterPath clipPath; // This is in -physical- coordinates 0372 bool clipping; // If clipping is enabled 0373 0374 // Compositing state 0375 float globalAlpha; 0376 QPainter::CompositionMode globalCompositeOperation; 0377 0378 // Stroke and fill styles. 0379 SharedPtr<CanvasStyleBaseImpl> strokeStyle; 0380 SharedPtr<CanvasStyleBaseImpl> fillStyle; 0381 0382 // Line stuff 0383 float lineWidth; 0384 Qt::PenCapStyle lineCap; 0385 Qt::PenJoinStyle lineJoin; 0386 float miterLimit; 0387 0388 // Shadow stuff 0389 float shadowOffsetX; 0390 float shadowOffsetY; 0391 float shadowBlur; 0392 QColor shadowColor; 0393 }; 0394 0395 // The stack of states. The entry on the top is always the current state. 0396 QStack<PaintState> stateStack; 0397 0398 const PaintState &activeState() const 0399 { 0400 return stateStack.top(); 0401 } 0402 PaintState &activeState() 0403 { 0404 return stateStack.top(); 0405 } 0406 0407 QPointF mapToDevice(const QPointF &point) const 0408 { 0409 return point * stateStack.top().transform; 0410 } 0411 0412 QPointF mapToDevice(float x, float y) const 0413 { 0414 return QPointF(x, y) * stateStack.top().transform; 0415 } 0416 0417 QPointF mapToUser(const QPointF &point) const 0418 { 0419 return point * stateStack.top().transform.inverted(); 0420 } 0421 0422 enum DirtyFlags { 0423 DrtTransform = 0x01, 0424 DrtClip = 0x02, 0425 DrtAlpha = 0x04, 0426 DrtCompOp = 0x08, 0427 DrtStroke = 0x10, 0428 DrtFill = 0x20, 0429 DrtAll = 0xFF 0430 }; 0431 0432 // The painter for working on the QImage. Might not be active. 0433 // Should not be used directly, but rather via acquirePainter 0434 QPainter workPainter; 0435 0436 // How out-of-date the painter is, if it is active. 0437 int dirty; 0438 0439 // If we have not committed all the changes to the entire 0440 // scaler hierarchy 0441 bool needsCommit; 0442 0443 // Tells the element and then the renderer that we changed, so need 0444 // repainting. 0445 void needRendererUpdate(); 0446 0447 // Flushes changes to the backbuffer. 0448 void syncBackBuffer(); 0449 0450 // False if no user moveTo-element was inserted in the path 0451 // see CanvasContext2DImpl::beginPath() 0452 bool emptyPath; 0453 }; 0454 0455 } //namespace 0456 0457 #endif