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