/src/mozilla-central/layout/generic/nsHTMLCanvasFrame.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
2 | | /* vim: set ts=8 sts=2 et sw=2 tw=80: */ |
3 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
4 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
5 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
6 | | |
7 | | /* rendering object for the HTML <canvas> element */ |
8 | | |
9 | | #include "nsHTMLCanvasFrame.h" |
10 | | |
11 | | #include "nsGkAtoms.h" |
12 | | #include "mozilla/Assertions.h" |
13 | | #include "mozilla/dom/HTMLCanvasElement.h" |
14 | | #include "mozilla/layers/WebRenderBridgeChild.h" |
15 | | #include "mozilla/layers/WebRenderCanvasRenderer.h" |
16 | | #include "mozilla/layers/WebRenderLayerManager.h" |
17 | | #include "nsDisplayList.h" |
18 | | #include "nsLayoutUtils.h" |
19 | | #include "nsStyleUtil.h" |
20 | | #include "ImageLayers.h" |
21 | | #include "Layers.h" |
22 | | #include "ActiveLayerTracker.h" |
23 | | |
24 | | #include <algorithm> |
25 | | |
26 | | using namespace mozilla; |
27 | | using namespace mozilla::dom; |
28 | | using namespace mozilla::layers; |
29 | | using namespace mozilla::gfx; |
30 | | |
31 | | /* Helper for our nsIFrame::GetIntrinsicSize() impl. Takes the result of |
32 | | * "GetCanvasSize()" as a parameter, which may help avoid redundant |
33 | | * indirect calls to GetCanvasSize(). |
34 | | * |
35 | | * @param aCanvasSizeInPx The canvas's size in CSS pixels, as returned |
36 | | * by GetCanvasSize(). |
37 | | * @return The canvas's intrinsic size, as an IntrinsicSize object. |
38 | | */ |
39 | | static IntrinsicSize |
40 | | IntrinsicSizeFromCanvasSize(const nsIntSize& aCanvasSizeInPx) |
41 | 0 | { |
42 | 0 | IntrinsicSize intrinsicSize; |
43 | 0 | intrinsicSize.width.SetCoordValue( |
44 | 0 | nsPresContext::CSSPixelsToAppUnits(aCanvasSizeInPx.width)); |
45 | 0 | intrinsicSize.height.SetCoordValue( |
46 | 0 | nsPresContext::CSSPixelsToAppUnits(aCanvasSizeInPx.height)); |
47 | 0 |
|
48 | 0 | return intrinsicSize; |
49 | 0 | } |
50 | | |
51 | | /* Helper for our nsIFrame::GetIntrinsicRatio() impl. Takes the result of |
52 | | * "GetCanvasSize()" as a parameter, which may help avoid redundant |
53 | | * indirect calls to GetCanvasSize(). |
54 | | * |
55 | | * @param aCanvasSizeInPx The canvas's size in CSS pixels, as returned |
56 | | * by GetCanvasSize(). |
57 | | * @return The canvas's intrinsic ratio, as a nsSize. |
58 | | */ |
59 | | static nsSize |
60 | | IntrinsicRatioFromCanvasSize(const nsIntSize& aCanvasSizeInPx) |
61 | 0 | { |
62 | 0 | return nsSize(nsPresContext::CSSPixelsToAppUnits(aCanvasSizeInPx.width), |
63 | 0 | nsPresContext::CSSPixelsToAppUnits(aCanvasSizeInPx.height)); |
64 | 0 | } |
65 | | |
66 | | class nsDisplayCanvas final : public nsDisplayItem |
67 | | { |
68 | | public: |
69 | | nsDisplayCanvas(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame) |
70 | | : nsDisplayItem(aBuilder, aFrame) |
71 | 0 | { |
72 | 0 | MOZ_COUNT_CTOR(nsDisplayCanvas); |
73 | 0 | } |
74 | | #ifdef NS_BUILD_REFCNT_LOGGING |
75 | | virtual ~nsDisplayCanvas() { |
76 | | MOZ_COUNT_DTOR(nsDisplayCanvas); |
77 | | } |
78 | | #endif |
79 | | |
80 | | NS_DISPLAY_DECL_NAME("nsDisplayCanvas", TYPE_CANVAS) |
81 | | |
82 | | virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder, |
83 | | bool* aSnap) const override |
84 | 0 | { |
85 | 0 | *aSnap = false; |
86 | 0 | nsHTMLCanvasFrame* f = static_cast<nsHTMLCanvasFrame*>(Frame()); |
87 | 0 | HTMLCanvasElement* canvas = |
88 | 0 | HTMLCanvasElement::FromNode(f->GetContent()); |
89 | 0 | nsRegion result; |
90 | 0 | if (canvas->GetIsOpaque()) { |
91 | 0 | // OK, the entire region painted by the canvas is opaque. But what is |
92 | 0 | // that region? It's the canvas's "dest rect" (controlled by the |
93 | 0 | // object-fit/object-position CSS properties), clipped to the container's |
94 | 0 | // content box (which is what GetBounds() returns). So, we grab those |
95 | 0 | // rects and intersect them. |
96 | 0 | nsRect constraintRect = GetBounds(aBuilder, aSnap); |
97 | 0 |
|
98 | 0 | // Need intrinsic size & ratio, for ComputeObjectDestRect: |
99 | 0 | nsIntSize canvasSize = f->GetCanvasSize(); |
100 | 0 | IntrinsicSize intrinsicSize = IntrinsicSizeFromCanvasSize(canvasSize); |
101 | 0 | nsSize intrinsicRatio = IntrinsicRatioFromCanvasSize(canvasSize); |
102 | 0 |
|
103 | 0 | const nsRect destRect = |
104 | 0 | nsLayoutUtils::ComputeObjectDestRect(constraintRect, |
105 | 0 | intrinsicSize, intrinsicRatio, |
106 | 0 | f->StylePosition()); |
107 | 0 | return nsRegion(destRect.Intersect(constraintRect)); |
108 | 0 | } |
109 | 0 | return result; |
110 | 0 | } |
111 | | |
112 | | virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, |
113 | | bool* aSnap) const override |
114 | 0 | { |
115 | 0 | *aSnap = true; |
116 | 0 | nsHTMLCanvasFrame* f = static_cast<nsHTMLCanvasFrame*>(Frame()); |
117 | 0 | return f->GetInnerArea() + ToReferenceFrame(); |
118 | 0 | } |
119 | | |
120 | | virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder, |
121 | | LayerManager* aManager, |
122 | | const ContainerLayerParameters& aContainerParameters) override |
123 | 0 | { |
124 | 0 | return static_cast<nsHTMLCanvasFrame*>(mFrame)-> |
125 | 0 | BuildLayer(aBuilder, aManager, this, aContainerParameters); |
126 | 0 | } |
127 | | |
128 | | virtual bool CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder, |
129 | | wr::IpcResourceUpdateQueue& aResources, |
130 | | const StackingContextHelper& aSc, |
131 | | mozilla::layers::WebRenderLayerManager* aManager, |
132 | | nsDisplayListBuilder* aDisplayListBuilder) override |
133 | 0 | { |
134 | 0 | HTMLCanvasElement* element = static_cast<HTMLCanvasElement*>(mFrame->GetContent()); |
135 | 0 | element->HandlePrintCallback(mFrame->PresContext()->Type()); |
136 | 0 |
|
137 | 0 | switch(element->GetCurrentContextType()) { |
138 | 0 | case CanvasContextType::Canvas2D: |
139 | 0 | case CanvasContextType::WebGL1: |
140 | 0 | case CanvasContextType::WebGL2: |
141 | 0 | { |
142 | 0 | bool isRecycled; |
143 | 0 | RefPtr<WebRenderCanvasData> canvasData = |
144 | 0 | aManager->CommandBuilder().CreateOrRecycleWebRenderUserData<WebRenderCanvasData>(this, &isRecycled); |
145 | 0 | nsHTMLCanvasFrame* canvasFrame = static_cast<nsHTMLCanvasFrame*>(mFrame); |
146 | 0 | if (!canvasFrame->UpdateWebRenderCanvasData(aDisplayListBuilder, canvasData)) { |
147 | 0 | return true; |
148 | 0 | } |
149 | 0 | WebRenderCanvasRendererAsync* data = |
150 | 0 | static_cast<WebRenderCanvasRendererAsync*>(canvasData->GetCanvasRenderer()); |
151 | 0 | MOZ_ASSERT(data); |
152 | 0 | data->UpdateCompositableClient(); |
153 | 0 |
|
154 | 0 | // Push IFrame for async image pipeline. |
155 | 0 | // XXX Remove this once partial display list update is supported. |
156 | 0 |
|
157 | 0 | nsIntSize canvasSizeInPx = data->GetSize(); |
158 | 0 | IntrinsicSize intrinsicSize = IntrinsicSizeFromCanvasSize(canvasSizeInPx); |
159 | 0 | nsSize intrinsicRatio = IntrinsicRatioFromCanvasSize(canvasSizeInPx); |
160 | 0 |
|
161 | 0 | nsRect area = mFrame->GetContentRectRelativeToSelf() + ToReferenceFrame(); |
162 | 0 | nsRect dest = |
163 | 0 | nsLayoutUtils::ComputeObjectDestRect(area, intrinsicSize, intrinsicRatio, |
164 | 0 | mFrame->StylePosition()); |
165 | 0 |
|
166 | 0 | LayoutDeviceRect bounds = LayoutDeviceRect::FromAppUnits( |
167 | 0 | dest, mFrame->PresContext()->AppUnitsPerDevPixel()); |
168 | 0 |
|
169 | 0 | // We don't push a stacking context for this async image pipeline here. |
170 | 0 | // Instead, we do it inside the iframe that hosts the image. As a result, |
171 | 0 | // a bunch of the calculations normally done as part of that stacking |
172 | 0 | // context need to be done manually and pushed over to the parent side, |
173 | 0 | // where it will be done when we build the display list for the iframe. |
174 | 0 | // That happens in WebRenderCompositableHolder. |
175 | 0 |
|
176 | 0 | wr::LayoutRect r = wr::ToRoundedLayoutRect(bounds); |
177 | 0 | aBuilder.PushIFrame(r, !BackfaceIsHidden(), data->GetPipelineId().ref(), /*ignoreMissingPipelines*/ false); |
178 | 0 |
|
179 | 0 | gfx::Matrix4x4 scTransform; |
180 | 0 | gfxRect destGFXRect = mFrame->PresContext()->AppUnitsToGfxUnits(dest); |
181 | 0 | scTransform.PreScale(destGFXRect.Width() / canvasSizeInPx.width, |
182 | 0 | destGFXRect.Height() / canvasSizeInPx.height, 1.0f); |
183 | 0 | if (data->NeedsYFlip()) { |
184 | 0 | scTransform = scTransform.PreTranslate(0, data->GetSize().height, 0).PreScale(1, -1, 1); |
185 | 0 | } |
186 | 0 |
|
187 | 0 | MaybeIntSize scaleToSize; |
188 | 0 | LayoutDeviceRect scBounds(LayoutDevicePoint(0, 0), bounds.Size()); |
189 | 0 | wr::ImageRendering filter = wr::ToImageRendering(nsLayoutUtils::GetSamplingFilterForFrame(mFrame)); |
190 | 0 | wr::MixBlendMode mixBlendMode = wr::MixBlendMode::Normal; |
191 | 0 | aManager->WrBridge()->AddWebRenderParentCommand(OpUpdateAsyncImagePipeline(data->GetPipelineId().value(), |
192 | 0 | scBounds, |
193 | 0 | scTransform, |
194 | 0 | scaleToSize, |
195 | 0 | filter, |
196 | 0 | mixBlendMode)); |
197 | 0 | break; |
198 | 0 | } |
199 | 0 | case CanvasContextType::ImageBitmap: |
200 | 0 | { |
201 | 0 | // TODO: Support ImageBitmap |
202 | 0 | break; |
203 | 0 | } |
204 | 0 | case CanvasContextType::NoContext: |
205 | 0 | return false; |
206 | 0 | } |
207 | 0 | return true; |
208 | 0 | } |
209 | | |
210 | | virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder, |
211 | | LayerManager* aManager, |
212 | | const ContainerLayerParameters& aParameters) override |
213 | 0 | { |
214 | 0 | if (HTMLCanvasElement::FromNode(mFrame->GetContent())->ShouldForceInactiveLayer(aManager)) |
215 | 0 | return LAYER_INACTIVE; |
216 | 0 | |
217 | 0 | // If compositing is cheap, just do that |
218 | 0 | if (aManager->IsCompositingCheap() || |
219 | 0 | ActiveLayerTracker::IsContentActive(mFrame)) |
220 | 0 | return mozilla::LAYER_ACTIVE; |
221 | 0 | |
222 | 0 | return LAYER_INACTIVE; |
223 | 0 | } |
224 | | }; |
225 | | |
226 | | |
227 | | nsIFrame* |
228 | | NS_NewHTMLCanvasFrame(nsIPresShell* aPresShell, ComputedStyle* aStyle) |
229 | 0 | { |
230 | 0 | return new (aPresShell) nsHTMLCanvasFrame(aStyle); |
231 | 0 | } |
232 | | |
233 | 0 | NS_QUERYFRAME_HEAD(nsHTMLCanvasFrame) |
234 | 0 | NS_QUERYFRAME_ENTRY(nsHTMLCanvasFrame) |
235 | 0 | NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame) |
236 | | |
237 | | NS_IMPL_FRAMEARENA_HELPERS(nsHTMLCanvasFrame) |
238 | | |
239 | | void |
240 | | nsHTMLCanvasFrame::Init(nsIContent* aContent, |
241 | | nsContainerFrame* aParent, |
242 | | nsIFrame* aPrevInFlow) |
243 | 0 | { |
244 | 0 | nsContainerFrame::Init(aContent, aParent, aPrevInFlow); |
245 | 0 |
|
246 | 0 | // We can fill in the canvas before the canvas frame is created, in |
247 | 0 | // which case we never get around to marking the content as active. Therefore, |
248 | 0 | // we mark it active here when we create the frame. |
249 | 0 | ActiveLayerTracker::NotifyContentChange(this); |
250 | 0 | } |
251 | | |
252 | | nsHTMLCanvasFrame::~nsHTMLCanvasFrame() |
253 | 0 | { |
254 | 0 | } |
255 | | |
256 | | nsIntSize |
257 | | nsHTMLCanvasFrame::GetCanvasSize() |
258 | 0 | { |
259 | 0 | nsIntSize size(0,0); |
260 | 0 | HTMLCanvasElement *canvas = |
261 | 0 | HTMLCanvasElement::FromNodeOrNull(GetContent()); |
262 | 0 | if (canvas) { |
263 | 0 | size = canvas->GetSize(); |
264 | 0 | MOZ_ASSERT(size.width >= 0 && size.height >= 0, |
265 | 0 | "we should've required <canvas> width/height attrs to be " |
266 | 0 | "unsigned (non-negative) values"); |
267 | 0 | } else { |
268 | 0 | MOZ_ASSERT_UNREACHABLE("couldn't get canvas size"); |
269 | 0 | } |
270 | 0 |
|
271 | 0 | return size; |
272 | 0 | } |
273 | | |
274 | | /* virtual */ nscoord |
275 | | nsHTMLCanvasFrame::GetMinISize(gfxContext *aRenderingContext) |
276 | 0 | { |
277 | 0 | // XXX The caller doesn't account for constraints of the height, |
278 | 0 | // min-height, and max-height properties. |
279 | 0 | bool vertical = GetWritingMode().IsVertical(); |
280 | 0 | nscoord result = nsPresContext::CSSPixelsToAppUnits( |
281 | 0 | vertical ? GetCanvasSize().height : GetCanvasSize().width); |
282 | 0 | DISPLAY_MIN_INLINE_SIZE(this, result); |
283 | 0 | return result; |
284 | 0 | } |
285 | | |
286 | | /* virtual */ nscoord |
287 | | nsHTMLCanvasFrame::GetPrefISize(gfxContext *aRenderingContext) |
288 | 0 | { |
289 | 0 | // XXX The caller doesn't account for constraints of the height, |
290 | 0 | // min-height, and max-height properties. |
291 | 0 | bool vertical = GetWritingMode().IsVertical(); |
292 | 0 | nscoord result = nsPresContext::CSSPixelsToAppUnits( |
293 | 0 | vertical ? GetCanvasSize().height : GetCanvasSize().width); |
294 | 0 | DISPLAY_PREF_INLINE_SIZE(this, result); |
295 | 0 | return result; |
296 | 0 | } |
297 | | |
298 | | /* virtual */ IntrinsicSize |
299 | | nsHTMLCanvasFrame::GetIntrinsicSize() |
300 | 0 | { |
301 | 0 | return IntrinsicSizeFromCanvasSize(GetCanvasSize()); |
302 | 0 | } |
303 | | |
304 | | /* virtual */ nsSize |
305 | | nsHTMLCanvasFrame::GetIntrinsicRatio() |
306 | 0 | { |
307 | 0 | return IntrinsicRatioFromCanvasSize(GetCanvasSize()); |
308 | 0 | } |
309 | | |
310 | | /* virtual */ |
311 | | LogicalSize |
312 | | nsHTMLCanvasFrame::ComputeSize(gfxContext *aRenderingContext, |
313 | | WritingMode aWM, |
314 | | const LogicalSize& aCBSize, |
315 | | nscoord aAvailableISize, |
316 | | const LogicalSize& aMargin, |
317 | | const LogicalSize& aBorder, |
318 | | const LogicalSize& aPadding, |
319 | | ComputeSizeFlags aFlags) |
320 | 0 | { |
321 | 0 | nsIntSize size = GetCanvasSize(); |
322 | 0 |
|
323 | 0 | IntrinsicSize intrinsicSize; |
324 | 0 | intrinsicSize.width.SetCoordValue(nsPresContext::CSSPixelsToAppUnits(size.width)); |
325 | 0 | intrinsicSize.height.SetCoordValue(nsPresContext::CSSPixelsToAppUnits(size.height)); |
326 | 0 |
|
327 | 0 | nsSize intrinsicRatio = GetIntrinsicRatio(); // won't actually be used |
328 | 0 |
|
329 | 0 | return ComputeSizeWithIntrinsicDimensions(aRenderingContext, aWM, |
330 | 0 | intrinsicSize, intrinsicRatio, |
331 | 0 | aCBSize, aMargin, aBorder, aPadding, |
332 | 0 | aFlags); |
333 | 0 | } |
334 | | |
335 | | void |
336 | | nsHTMLCanvasFrame::Reflow(nsPresContext* aPresContext, |
337 | | ReflowOutput& aMetrics, |
338 | | const ReflowInput& aReflowInput, |
339 | | nsReflowStatus& aStatus) |
340 | 0 | { |
341 | 0 | MarkInReflow(); |
342 | 0 | DO_GLOBAL_REFLOW_COUNT("nsHTMLCanvasFrame"); |
343 | 0 | DISPLAY_REFLOW(aPresContext, this, aReflowInput, aMetrics, aStatus); |
344 | 0 | MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!"); |
345 | 0 | NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS, |
346 | 0 | ("enter nsHTMLCanvasFrame::Reflow: availSize=%d,%d", |
347 | 0 | aReflowInput.AvailableWidth(), aReflowInput.AvailableHeight())); |
348 | 0 |
|
349 | 0 | MOZ_ASSERT(mState & NS_FRAME_IN_REFLOW, "frame is not in reflow"); |
350 | 0 |
|
351 | 0 | WritingMode wm = aReflowInput.GetWritingMode(); |
352 | 0 | LogicalSize finalSize(wm, |
353 | 0 | aReflowInput.ComputedISize(), |
354 | 0 | aReflowInput.ComputedBSize()); |
355 | 0 |
|
356 | 0 | // stash this away so we can compute our inner area later |
357 | 0 | mBorderPadding = aReflowInput.ComputedLogicalBorderPadding(); |
358 | 0 |
|
359 | 0 | finalSize.ISize(wm) += mBorderPadding.IStartEnd(wm); |
360 | 0 | finalSize.BSize(wm) += mBorderPadding.BStartEnd(wm); |
361 | 0 |
|
362 | 0 | if (GetPrevInFlow()) { |
363 | 0 | nscoord y = GetContinuationOffset(&finalSize.ISize(wm)); |
364 | 0 | finalSize.BSize(wm) -= y + mBorderPadding.BStart(wm); |
365 | 0 | finalSize.BSize(wm) = std::max(0, finalSize.BSize(wm)); |
366 | 0 | } |
367 | 0 |
|
368 | 0 | aMetrics.SetSize(wm, finalSize); |
369 | 0 | aMetrics.SetOverflowAreasToDesiredBounds(); |
370 | 0 | FinishAndStoreOverflow(&aMetrics); |
371 | 0 |
|
372 | 0 | // Reflow the single anon block child. |
373 | 0 | nsReflowStatus childStatus; |
374 | 0 | nsIFrame* childFrame = mFrames.FirstChild(); |
375 | 0 | WritingMode childWM = childFrame->GetWritingMode(); |
376 | 0 | LogicalSize availSize = aReflowInput.ComputedSize(childWM); |
377 | 0 | availSize.BSize(childWM) = NS_UNCONSTRAINEDSIZE; |
378 | 0 | NS_ASSERTION(!childFrame->GetNextSibling(), "HTML canvas should have 1 kid"); |
379 | 0 | ReflowOutput childDesiredSize(aReflowInput.GetWritingMode()); |
380 | 0 | ReflowInput childReflowInput(aPresContext, aReflowInput, childFrame, |
381 | 0 | availSize); |
382 | 0 | ReflowChild(childFrame, aPresContext, childDesiredSize, childReflowInput, |
383 | 0 | 0, 0, 0, childStatus, nullptr); |
384 | 0 | FinishReflowChild(childFrame, aPresContext, childDesiredSize, |
385 | 0 | &childReflowInput, 0, 0, 0); |
386 | 0 |
|
387 | 0 | NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS, |
388 | 0 | ("exit nsHTMLCanvasFrame::Reflow: size=%d,%d", |
389 | 0 | aMetrics.ISize(wm), aMetrics.BSize(wm))); |
390 | 0 | NS_FRAME_SET_TRUNCATION(aStatus, aReflowInput, aMetrics); |
391 | 0 | } |
392 | | |
393 | | // FIXME taken from nsImageFrame, but then had splittable frame stuff |
394 | | // removed. That needs to be fixed. |
395 | | // XXXdholbert As in nsImageFrame, this function's clients should probably |
396 | | // just be calling GetContentRectRelativeToSelf(). |
397 | | nsRect |
398 | | nsHTMLCanvasFrame::GetInnerArea() const |
399 | 0 | { |
400 | 0 | nsMargin bp = mBorderPadding.GetPhysicalMargin(GetWritingMode()); |
401 | 0 | nsRect r; |
402 | 0 | r.x = bp.left; |
403 | 0 | r.y = bp.top; |
404 | 0 | r.width = mRect.width - bp.left - bp.right; |
405 | 0 | r.height = mRect.height - bp.top - bp.bottom; |
406 | 0 | return r; |
407 | 0 | } |
408 | | |
409 | | already_AddRefed<Layer> |
410 | | nsHTMLCanvasFrame::BuildLayer(nsDisplayListBuilder* aBuilder, |
411 | | LayerManager* aManager, |
412 | | nsDisplayItem* aItem, |
413 | | const ContainerLayerParameters& aContainerParameters) |
414 | 0 | { |
415 | 0 | nsRect area = GetContentRectRelativeToSelf() + aItem->ToReferenceFrame(); |
416 | 0 | HTMLCanvasElement* element = static_cast<HTMLCanvasElement*>(GetContent()); |
417 | 0 | nsIntSize canvasSizeInPx = GetCanvasSize(); |
418 | 0 |
|
419 | 0 | nsPresContext* presContext = PresContext(); |
420 | 0 | element->HandlePrintCallback(presContext->Type()); |
421 | 0 |
|
422 | 0 | if (canvasSizeInPx.width <= 0 || canvasSizeInPx.height <= 0 || area.IsEmpty()) |
423 | 0 | return nullptr; |
424 | 0 | |
425 | 0 | CanvasLayer* oldLayer = static_cast<CanvasLayer*> |
426 | 0 | (aManager->GetLayerBuilder()->GetLeafLayerFor(aBuilder, aItem)); |
427 | 0 | RefPtr<Layer> layer = element->GetCanvasLayer(aBuilder, oldLayer, aManager); |
428 | 0 | if (!layer) |
429 | 0 | return nullptr; |
430 | 0 | |
431 | 0 | IntrinsicSize intrinsicSize = IntrinsicSizeFromCanvasSize(canvasSizeInPx); |
432 | 0 | nsSize intrinsicRatio = IntrinsicRatioFromCanvasSize(canvasSizeInPx); |
433 | 0 |
|
434 | 0 | nsRect dest = |
435 | 0 | nsLayoutUtils::ComputeObjectDestRect(area, intrinsicSize, intrinsicRatio, |
436 | 0 | StylePosition()); |
437 | 0 |
|
438 | 0 | gfxRect destGFXRect = presContext->AppUnitsToGfxUnits(dest); |
439 | 0 |
|
440 | 0 | // Transform the canvas into the right place |
441 | 0 | gfxPoint p = destGFXRect.TopLeft() + aContainerParameters.mOffset; |
442 | 0 | Matrix transform = Matrix::Translation(p.x, p.y); |
443 | 0 | transform.PreScale(destGFXRect.Width() / canvasSizeInPx.width, |
444 | 0 | destGFXRect.Height() / canvasSizeInPx.height); |
445 | 0 | layer->SetBaseTransform(gfx::Matrix4x4::From2D(transform)); |
446 | 0 | if (layer->GetType() == layers::Layer::TYPE_CANVAS) { |
447 | 0 | RefPtr<CanvasLayer> canvasLayer = static_cast<CanvasLayer*>(layer.get()); |
448 | 0 | canvasLayer->SetSamplingFilter(nsLayoutUtils::GetSamplingFilterForFrame(this)); |
449 | 0 | nsIntRect bounds; |
450 | 0 | bounds.SetRect(0, 0, canvasSizeInPx.width, canvasSizeInPx.height); |
451 | 0 | canvasLayer->SetBounds(bounds); |
452 | 0 | } else if (layer->GetType() == layers::Layer::TYPE_IMAGE) { |
453 | 0 | RefPtr<ImageLayer> imageLayer = static_cast<ImageLayer*>(layer.get()); |
454 | 0 | imageLayer->SetSamplingFilter(nsLayoutUtils::GetSamplingFilterForFrame(this)); |
455 | 0 | } |
456 | 0 |
|
457 | 0 | return layer.forget(); |
458 | 0 | } |
459 | | |
460 | | bool |
461 | | nsHTMLCanvasFrame::UpdateWebRenderCanvasData(nsDisplayListBuilder* aBuilder, |
462 | | WebRenderCanvasData* aCanvasData) |
463 | 0 | { |
464 | 0 | HTMLCanvasElement* element = static_cast<HTMLCanvasElement*>(GetContent()); |
465 | 0 | return element->UpdateWebRenderCanvasData(aBuilder, aCanvasData); |
466 | 0 | } |
467 | | |
468 | | void |
469 | | nsHTMLCanvasFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, |
470 | | const nsDisplayListSet& aLists) |
471 | 0 | { |
472 | 0 | if (!IsVisibleForPainting(aBuilder)) |
473 | 0 | return; |
474 | 0 | |
475 | 0 | DisplayBorderBackgroundOutline(aBuilder, aLists); |
476 | 0 |
|
477 | 0 | uint32_t clipFlags = |
478 | 0 | nsStyleUtil::ObjectPropsMightCauseOverflow(StylePosition()) ? |
479 | 0 | 0 : DisplayListClipState::ASSUME_DRAWING_RESTRICTED_TO_CONTENT_RECT; |
480 | 0 |
|
481 | 0 | DisplayListClipState::AutoClipContainingBlockDescendantsToContentBox |
482 | 0 | clip(aBuilder, this, clipFlags); |
483 | 0 |
|
484 | 0 | aLists.Content()->AppendToTop( |
485 | 0 | MakeDisplayItem<nsDisplayCanvas>(aBuilder, this)); |
486 | 0 |
|
487 | 0 | DisplaySelectionOverlay(aBuilder, aLists.Content(), |
488 | 0 | nsISelectionDisplay::DISPLAY_IMAGES); |
489 | 0 | } |
490 | | |
491 | | // get the offset into the content area of the image where aImg starts if it is a continuation. |
492 | | // from nsImageFrame |
493 | | nscoord |
494 | | nsHTMLCanvasFrame::GetContinuationOffset(nscoord* aWidth) const |
495 | 0 | { |
496 | 0 | nscoord offset = 0; |
497 | 0 | if (aWidth) { |
498 | 0 | *aWidth = 0; |
499 | 0 | } |
500 | 0 |
|
501 | 0 | if (GetPrevInFlow()) { |
502 | 0 | for (nsIFrame* prevInFlow = GetPrevInFlow() ; prevInFlow; prevInFlow = prevInFlow->GetPrevInFlow()) { |
503 | 0 | nsRect rect = prevInFlow->GetRect(); |
504 | 0 | if (aWidth) { |
505 | 0 | *aWidth = rect.width; |
506 | 0 | } |
507 | 0 | offset += rect.height; |
508 | 0 | } |
509 | 0 | offset -= mBorderPadding.GetPhysicalMargin(GetWritingMode()).top; |
510 | 0 | offset = std::max(0, offset); |
511 | 0 | } |
512 | 0 | return offset; |
513 | 0 | } |
514 | | |
515 | | void |
516 | | nsHTMLCanvasFrame::AppendDirectlyOwnedAnonBoxes(nsTArray<OwnedAnonBox>& aResult) |
517 | 0 | { |
518 | 0 | MOZ_ASSERT(mFrames.FirstChild(), "Must have our canvas content anon box"); |
519 | 0 | MOZ_ASSERT(!mFrames.FirstChild()->GetNextSibling(), |
520 | 0 | "Must only have our canvas content anon box"); |
521 | 0 | aResult.AppendElement(OwnedAnonBox(mFrames.FirstChild())); |
522 | 0 | } |
523 | | |
524 | | #ifdef ACCESSIBILITY |
525 | | a11y::AccType |
526 | | nsHTMLCanvasFrame::AccessibleType() |
527 | 0 | { |
528 | 0 | return a11y::eHTMLCanvasType; |
529 | 0 | } |
530 | | #endif |
531 | | |
532 | | #ifdef DEBUG_FRAME_DUMP |
533 | | nsresult |
534 | | nsHTMLCanvasFrame::GetFrameName(nsAString& aResult) const |
535 | | { |
536 | | return MakeFrameName(NS_LITERAL_STRING("HTMLCanvas"), aResult); |
537 | | } |
538 | | #endif |
539 | | |