71a8c8c5b86b9ddeb1861fff14302573f118f4dd
[WebKit-https.git] / WebCore / rendering / RenderHTMLCanvas.cpp
1 /*
2  * Copyright (C) 2004, 2006 Apple Computer, Inc.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 //#define DEBUG_LAYOUT
27
28 #include "config.h"
29 #include "RenderHTMLCanvas.h"
30
31 #if __APPLE__
32
33 #include "Document.h"
34 #include "GraphicsContext.h"
35 #include "HTMLCanvasElement.h"
36 #include "HTMLNames.h"
37
38 namespace WebCore {
39
40 using namespace HTMLNames;
41
42 RenderHTMLCanvas::RenderHTMLCanvas(Node *_node)
43     : RenderImage(_node), _drawingContext(0), _drawingContextData(0), _drawnImage(0), _needsImageUpdate(0)
44 {
45 }
46
47 RenderHTMLCanvas::~RenderHTMLCanvas()
48 {
49     if (_drawingContext) {
50         CFRelease (_drawingContext);
51         _drawingContext = 0;
52     }
53     
54     fastFree(_drawingContextData);
55     _drawingContextData = 0;
56     
57     if (_drawnImage) {
58         CFRelease (_drawnImage);
59         _drawnImage = 0;
60     }
61 }
62
63 #define BITS_PER_COMPONENT 8
64 #define BYTES_PER_ROW(width,bitsPerComponent,numComponents) ((width * bitsPerComponent * numComponents + 7)/8)
65
66 void RenderHTMLCanvas::createDrawingContext()
67 {
68     if (_drawingContext) {
69         CFRelease (_drawingContext);
70         _drawingContext = 0;
71     }
72     fastFree(_drawingContextData);
73     CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
74
75     int cWidth = contentWidth();
76     int cHeight = contentHeight();
77     size_t numComponents = CGColorSpaceGetNumberOfComponents(colorSpace);
78     size_t bytesPerRow = BYTES_PER_ROW(cWidth,BITS_PER_COMPONENT,(numComponents+1)); // + 1 for alpha
79     _drawingContextData = fastCalloc(height(), bytesPerRow);
80     _drawingContext = CGBitmapContextCreate(_drawingContextData, cWidth, cHeight, BITS_PER_COMPONENT, bytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast);
81     
82 #ifdef DEBUG_CANVAS_BACKGROUND
83     CGContextSetRGBFillColor(_drawingContext, 1.0, 0., 0., 1.);
84     CGContextFillRect (_drawingContext, CGRectMake (0, 0, width(), height()));
85     CGContextFlush (_drawingContext);
86 #endif
87     
88     updateDrawnImage();
89     
90     CFRelease (colorSpace);
91 }
92
93 CGContextRef RenderHTMLCanvas::drawingContext()
94 {
95     if (!_drawingContext) {
96         document()->updateLayout();
97         createDrawingContext();
98     }
99     
100     return _drawingContext;
101 }
102
103 void RenderHTMLCanvas::setNeedsImageUpdate()
104 {
105     _needsImageUpdate = true;
106     repaint();
107 }
108
109
110 void RenderHTMLCanvas::updateDrawnImage()
111 {
112     if (_drawnImage)
113         CFRelease (_drawnImage);
114     CGContextFlush (_drawingContext);
115     _drawnImage = CGBitmapContextCreateImage (_drawingContext);
116 }
117
118 CGImageRef RenderHTMLCanvas::drawnImage()
119 {
120     return _drawnImage;
121 }
122
123 void RenderHTMLCanvas::paint(PaintInfo& i, int _tx, int _ty)
124 {
125     if (!shouldPaint(i, _tx, _ty))
126         return;
127
128     int x = _tx + m_x;
129     int y = _ty + m_y;
130
131     if (shouldPaintBackgroundOrBorder() && (i.phase == PaintPhaseForeground || i.phase == PaintPhaseSelection)) 
132         paintBoxDecorations(i, x, y);
133
134     GraphicsContext* p = i.p;
135     if (p->paintingDisabled())
136         return;
137     
138     if ((i.phase == PaintPhaseOutline || i.phase == PaintPhaseSelfOutline) && style()->outlineWidth() && style()->visibility() == VISIBLE)
139         paintOutline(p, x, y, width(), height(), style());
140     
141     if (i.phase != PaintPhaseForeground && i.phase != PaintPhaseSelection)
142         return;
143
144     if (!shouldPaintWithinRoot(i))
145         return;
146
147     bool isPrinting = i.p->printing();
148     bool drawSelectionTint = (selectionState() != SelectionNone) && !isPrinting;
149     if (i.phase == PaintPhaseSelection) {
150         if (selectionState() == SelectionNone)
151             return;
152         drawSelectionTint = false;
153     }
154
155     int cWidth = contentWidth();
156     int cHeight = contentHeight();
157     int leftBorder = borderLeft();
158     int topBorder = borderTop();
159     int leftPad = paddingLeft();
160     int topPad = paddingTop();
161
162     x += leftBorder + leftPad;
163     y += topBorder + topPad;
164     
165     if (_needsImageUpdate) {
166         updateDrawnImage();
167         _needsImageUpdate = false;
168     }
169     
170     if (drawnImage()) {
171         HTMLCanvasElement* i = (element() && element()->hasTagName(canvasTag)) ? static_cast<HTMLCanvasElement*>(element()) : 0;
172         int oldOperation = 0;
173         if (i) {
174             oldOperation = GraphicsContext::getCompositeOperation(GraphicsContext::currentCGContext());
175             GraphicsContext::setCompositeOperation(GraphicsContext::currentCGContext(), i->compositeOperator());
176         }
177         CGContextDrawImage(GraphicsContext::currentCGContext(), CGRectMake(x, y, cWidth, cHeight), drawnImage());
178         if (i)
179             GraphicsContext::setCompositeOperation(GraphicsContext::currentCGContext(), oldOperation);
180     }
181
182     if (drawSelectionTint)
183         p->fillRect(selectionRect(), selectionColor(p));
184 }
185
186 void RenderHTMLCanvas::layout()
187 {
188     KHTMLAssert(needsLayout());
189     KHTMLAssert(minMaxKnown());
190
191     IntRect oldBounds;
192     bool checkForRepaint = checkForRepaintDuringLayout();
193     if (checkForRepaint)
194         oldBounds = getAbsoluteRepaintRect();
195
196     int oldwidth = m_width;
197     int oldheight = m_height;
198     
199     calcWidth();
200     calcHeight();
201
202     if ( m_width != oldwidth || m_height != oldheight ) {
203         createDrawingContext();
204     }
205
206     if (checkForRepaint)
207         repaintAfterLayoutIfNeeded(oldBounds, oldBounds);
208     
209     setNeedsLayout(false);
210 }
211
212 }
213
214 #endif