1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
15 * The Original Code is mozilla.org code.
17 * The Initial Developer of the Original Code is
18 * Vladimir Vukicevic <vladimir@pobox.com>
19 * Portions created by the Initial Developer are Copyright (C) 2004
20 * the Initial Developer. All Rights Reserved.
23 * Vladimir Vukicevic <vladimir@pobox.com> (original author)
25 * Alternatively, the contents of this file may be used under the terms of
26 * either of the GNU General Public License Version 2 or later (the "GPL"),
27 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 * in which case the provisions of the GPL or the LGPL are applicable instead
29 * of those above. If you wish to allow use of your version of this file only
30 * under the terms of either the GPL or the LGPL, and not to allow others to
31 * use your version of this file under the terms of the MPL, indicate your
32 * decision by deleting the provisions above and replace them with the notice
33 * and other provisions required by the GPL or the LGPL. If you do not delete
34 * the provisions above, a recipient may use your version of this file under
35 * the terms of any one of the MPL, the GPL or the LGPL.
37 * ***** END LICENSE BLOCK ***** */
39 /* rendering object for the HTML <canvas> element */
41 #include "nsHTMLParts.h"
43 #include "nsIServiceManager.h"
44 #include "nsGkAtoms.h"
46 #include "nsHTMLCanvasFrame.h"
47 #include "nsICanvasElement.h"
48 #include "nsDisplayList.h"
50 #include "nsTransform2D.h"
53 class nsDisplayItemCanvas
: public nsDisplayItem
{
55 nsDisplayItemCanvas(nsIFrame
* aFrame
)
56 : nsDisplayItem(aFrame
)
58 MOZ_COUNT_CTOR(nsDisplayItemCanvas
);
60 #ifdef NS_BUILD_REFCNT_LOGGING
61 virtual ~nsDisplayItemCanvas() {
62 MOZ_COUNT_DTOR(nsDisplayItemCanvas
);
66 NS_DISPLAY_DECL_NAME("nsDisplayItemCanvas")
68 virtual void Paint(nsDisplayListBuilder
* aBuilder
, nsIRenderingContext
* aCtx
,
69 const nsRect
& aDirtyRect
) {
70 nsHTMLCanvasFrame
* f
= static_cast<nsHTMLCanvasFrame
*>(GetUnderlyingFrame());
71 f
->PaintCanvas(*aCtx
, aDirtyRect
, aBuilder
->ToReferenceFrame(f
));
74 virtual PRBool
IsOpaque(nsDisplayListBuilder
* aBuilder
) {
75 nsIFrame
* f
= GetUnderlyingFrame();
76 nsCOMPtr
<nsICanvasElement
> canvas(do_QueryInterface(f
->GetContent()));
77 return canvas
->GetIsOpaque();
80 virtual nsRect
GetBounds(nsDisplayListBuilder
* aBuilder
) {
81 nsHTMLCanvasFrame
* f
= static_cast<nsHTMLCanvasFrame
*>(GetUnderlyingFrame());
82 return f
->GetInnerArea() + aBuilder
->ToReferenceFrame(f
);
88 NS_NewHTMLCanvasFrame(nsIPresShell
* aPresShell
, nsStyleContext
* aContext
)
90 return new (aPresShell
) nsHTMLCanvasFrame(aContext
);
93 nsHTMLCanvasFrame::~nsHTMLCanvasFrame()
98 nsHTMLCanvasFrame::GetCanvasSize()
102 nsCOMPtr
<nsICanvasElement
> canvas(do_QueryInterface(GetContent()));
104 rv
= canvas
->GetSize(&w
, &h
);
106 rv
= NS_ERROR_NULL_POINTER
;
110 NS_NOTREACHED("couldn't get canvas size");
114 return nsIntSize(w
, h
);
117 /* virtual */ nscoord
118 nsHTMLCanvasFrame::GetMinWidth(nsIRenderingContext
*aRenderingContext
)
120 // XXX The caller doesn't account for constraints of the height,
121 // min-height, and max-height properties.
122 nscoord result
= nsPresContext::CSSPixelsToAppUnits(GetCanvasSize().width
);
123 DISPLAY_MIN_WIDTH(this, result
);
127 /* virtual */ nscoord
128 nsHTMLCanvasFrame::GetPrefWidth(nsIRenderingContext
*aRenderingContext
)
130 // XXX The caller doesn't account for constraints of the height,
131 // min-height, and max-height properties.
132 nscoord result
= nsPresContext::CSSPixelsToAppUnits(GetCanvasSize().width
);
133 DISPLAY_PREF_WIDTH(this, result
);
138 nsHTMLCanvasFrame::GetIntrinsicRatio()
140 nsIntSize
size(GetCanvasSize());
141 return nsSize(nsPresContext::CSSPixelsToAppUnits(size
.width
),
142 nsPresContext::CSSPixelsToAppUnits(size
.height
));
146 nsHTMLCanvasFrame::ComputeSize(nsIRenderingContext
*aRenderingContext
,
147 nsSize aCBSize
, nscoord aAvailableWidth
,
148 nsSize aMargin
, nsSize aBorder
, nsSize aPadding
,
151 nsIntSize size
= GetCanvasSize();
153 IntrinsicSize intrinsicSize
;
154 intrinsicSize
.width
.SetCoordValue(nsPresContext::CSSPixelsToAppUnits(size
.width
));
155 intrinsicSize
.height
.SetCoordValue(nsPresContext::CSSPixelsToAppUnits(size
.height
));
157 nsSize intrinsicRatio
= GetIntrinsicRatio(); // won't actually be used
159 return nsLayoutUtils::ComputeSizeWithIntrinsicDimensions(
160 aRenderingContext
, this,
161 intrinsicSize
, intrinsicRatio
, aCBSize
,
162 aMargin
, aBorder
, aPadding
);
166 nsHTMLCanvasFrame::Reflow(nsPresContext
* aPresContext
,
167 nsHTMLReflowMetrics
& aMetrics
,
168 const nsHTMLReflowState
& aReflowState
,
169 nsReflowStatus
& aStatus
)
171 DO_GLOBAL_REFLOW_COUNT("nsHTMLCanvasFrame");
172 DISPLAY_REFLOW(aPresContext
, this, aReflowState
, aMetrics
, aStatus
);
173 NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS
,
174 ("enter nsHTMLCanvasFrame::Reflow: availSize=%d,%d",
175 aReflowState
.availableWidth
, aReflowState
.availableHeight
));
177 NS_PRECONDITION(mState
& NS_FRAME_IN_REFLOW
, "frame is not in reflow");
179 aStatus
= NS_FRAME_COMPLETE
;
181 aMetrics
.width
= aReflowState
.ComputedWidth();
182 aMetrics
.height
= aReflowState
.ComputedHeight();
184 // stash this away so we can compute our inner area later
185 mBorderPadding
= aReflowState
.mComputedBorderPadding
;
187 aMetrics
.width
+= mBorderPadding
.left
+ mBorderPadding
.right
;
188 aMetrics
.height
+= mBorderPadding
.top
+ mBorderPadding
.bottom
;
190 if (GetPrevInFlow()) {
191 nscoord y
= GetContinuationOffset(&aMetrics
.width
);
192 aMetrics
.height
-= y
+ mBorderPadding
.top
;
193 aMetrics
.height
= PR_MAX(0, aMetrics
.height
);
196 aMetrics
.mOverflowArea
.SetRect(0, 0, aMetrics
.width
, aMetrics
.height
);
197 FinishAndStoreOverflow(&aMetrics
);
199 if (mRect
.width
!= aMetrics
.width
|| mRect
.height
!= aMetrics
.height
) {
200 Invalidate(nsRect(0, 0, mRect
.width
, mRect
.height
));
203 NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS
,
204 ("exit nsHTMLCanvasFrame::Reflow: size=%d,%d",
205 aMetrics
.width
, aMetrics
.height
));
206 NS_FRAME_SET_TRUNCATION(aStatus
, aReflowState
, aMetrics
);
210 // FIXME taken from nsImageFrame, but then had splittable frame stuff
211 // removed. That needs to be fixed.
213 nsHTMLCanvasFrame::GetInnerArea() const
216 r
.x
= mBorderPadding
.left
;
217 r
.y
= mBorderPadding
.top
;
218 r
.width
= mRect
.width
- mBorderPadding
.left
- mBorderPadding
.right
;
219 r
.height
= mRect
.height
- mBorderPadding
.top
- mBorderPadding
.bottom
;
224 nsHTMLCanvasFrame::PaintCanvas(nsIRenderingContext
& aRenderingContext
,
225 const nsRect
& aDirtyRect
, nsPoint aPt
)
227 nsRect inner
= GetInnerArea() + aPt
;
229 nsCOMPtr
<nsICanvasElement
> canvas(do_QueryInterface(GetContent()));
234 if (inner
.width
== 0 || inner
.height
== 0)
237 nsIntSize canvasSize
= GetCanvasSize();
238 nsSize
sizeAppUnits(PresContext()->DevPixelsToAppUnits(canvasSize
.width
),
239 PresContext()->DevPixelsToAppUnits(canvasSize
.height
));
241 // XXXvlad clip to aDirtyRect!
243 if (inner
.Size() != sizeAppUnits
)
245 float sx
= inner
.width
/ (float) sizeAppUnits
.width
;
246 float sy
= inner
.height
/ (float) sizeAppUnits
.height
;
248 aRenderingContext
.PushState();
249 aRenderingContext
.Translate(inner
.x
, inner
.y
);
250 aRenderingContext
.Scale(sx
, sy
);
252 canvas
->RenderContexts(aRenderingContext
.ThebesContext());
254 aRenderingContext
.PopState();
256 //nsIRenderingContext::AutoPushTranslation(&aRenderingContext, px, py);
258 aRenderingContext
.PushState();
259 aRenderingContext
.Translate(inner
.x
, inner
.y
);
261 canvas
->RenderContexts(aRenderingContext
.ThebesContext());
263 aRenderingContext
.PopState();
268 nsHTMLCanvasFrame::BuildDisplayList(nsDisplayListBuilder
* aBuilder
,
269 const nsRect
& aDirtyRect
,
270 const nsDisplayListSet
& aLists
)
272 if (!IsVisibleForPainting(aBuilder
))
275 nsresult rv
= DisplayBorderBackgroundOutline(aBuilder
, aLists
);
276 NS_ENSURE_SUCCESS(rv
, rv
);
278 rv
= aLists
.Content()->AppendNewToTop(new (aBuilder
)
279 nsDisplayItemCanvas(this));
280 NS_ENSURE_SUCCESS(rv
, rv
);
282 return DisplaySelectionOverlay(aBuilder
, aLists
,
283 nsISelectionDisplay::DISPLAY_IMAGES
);
287 nsHTMLCanvasFrame::GetContentForEvent(nsPresContext
* aPresContext
,
289 nsIContent
** aContent
)
291 NS_ENSURE_ARG_POINTER(aContent
);
292 *aContent
= GetContent();
293 NS_IF_ADDREF(*aContent
);
298 nsHTMLCanvasFrame::GetType() const
300 return nsGkAtoms::HTMLCanvasFrame
;
303 // get the offset into the content area of the image where aImg starts if it is a continuation.
306 nsHTMLCanvasFrame::GetContinuationOffset(nscoord
* aWidth
) const
313 if (GetPrevInFlow()) {
314 for (nsIFrame
* prevInFlow
= GetPrevInFlow() ; prevInFlow
; prevInFlow
= prevInFlow
->GetPrevInFlow()) {
315 nsRect rect
= prevInFlow
->GetRect();
317 *aWidth
= rect
.width
;
319 offset
+= rect
.height
;
321 offset
-= mBorderPadding
.top
;
322 offset
= PR_MAX(0, offset
);
329 nsHTMLCanvasFrame::GetAccessible(nsIAccessible
** aAccessible
)
331 return NS_ERROR_FAILURE
;
337 nsHTMLCanvasFrame::GetFrameName(nsAString
& aResult
) const
339 return MakeFrameName(NS_LITERAL_STRING("HTMLCanvas"), aResult
);
343 nsHTMLCanvasFrame::List(FILE* out
, PRInt32 aIndent
) const
345 IndentBy(out
, aIndent
);