/src/mozilla-central/layout/generic/nsCanvasFrame.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 that goes directly inside the document's scrollbars */ |
8 | | |
9 | | #include "nsCanvasFrame.h" |
10 | | |
11 | | #include "gfxContext.h" |
12 | | #include "gfxUtils.h" |
13 | | #include "nsContainerFrame.h" |
14 | | #include "nsContentCreatorFunctions.h" |
15 | | #include "nsCSSRendering.h" |
16 | | #include "nsPresContext.h" |
17 | | #include "nsPopupSetFrame.h" |
18 | | #include "nsGkAtoms.h" |
19 | | #include "nsIFrameInlines.h" |
20 | | #include "nsIPresShell.h" |
21 | | #include "nsDisplayList.h" |
22 | | #include "nsCSSFrameConstructor.h" |
23 | | #include "nsFrameManager.h" |
24 | | #include "gfxPlatform.h" |
25 | | #include "nsPrintfCString.h" |
26 | | #include "mozilla/AccessibleCaretEventHub.h" |
27 | | #include "mozilla/ComputedStyle.h" |
28 | | #include "mozilla/dom/AnonymousContent.h" |
29 | | #include "mozilla/layers/StackingContextHelper.h" |
30 | | #include "mozilla/layers/WebRenderLayerManager.h" |
31 | | #include "mozilla/PresShell.h" |
32 | | // for focus |
33 | | #include "nsIScrollableFrame.h" |
34 | | #ifdef DEBUG_CANVAS_FOCUS |
35 | | #include "nsIDocShell.h" |
36 | | #endif |
37 | | |
38 | | //#define DEBUG_CANVAS_FOCUS |
39 | | |
40 | | using namespace mozilla; |
41 | | using namespace mozilla::dom; |
42 | | using namespace mozilla::layout; |
43 | | using namespace mozilla::gfx; |
44 | | using namespace mozilla::layers; |
45 | | |
46 | | nsCanvasFrame* |
47 | | NS_NewCanvasFrame(nsIPresShell* aPresShell, ComputedStyle* aStyle) |
48 | 0 | { |
49 | 0 | return new (aPresShell) nsCanvasFrame(aStyle); |
50 | 0 | } |
51 | | |
52 | | NS_IMPL_FRAMEARENA_HELPERS(nsCanvasFrame) |
53 | | |
54 | 0 | NS_QUERYFRAME_HEAD(nsCanvasFrame) |
55 | 0 | NS_QUERYFRAME_ENTRY(nsCanvasFrame) |
56 | 0 | NS_QUERYFRAME_ENTRY(nsIAnonymousContentCreator) |
57 | 0 | NS_QUERYFRAME_ENTRY(nsIPopupContainer) |
58 | 0 | NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame) |
59 | | |
60 | | void |
61 | | nsCanvasFrame::ShowCustomContentContainer() |
62 | 0 | { |
63 | 0 | if (mCustomContentContainer) { |
64 | 0 | mCustomContentContainer->UnsetAttr(kNameSpaceID_None, nsGkAtoms::hidden, true); |
65 | 0 | } |
66 | 0 | } |
67 | | |
68 | | void |
69 | | nsCanvasFrame::HideCustomContentContainer() |
70 | 0 | { |
71 | 0 | if (mCustomContentContainer) { |
72 | 0 | mCustomContentContainer->SetAttr(kNameSpaceID_None, nsGkAtoms::hidden, |
73 | 0 | NS_LITERAL_STRING("true"), |
74 | 0 | true); |
75 | 0 | } |
76 | 0 | } |
77 | | |
78 | | nsresult |
79 | | nsCanvasFrame::CreateAnonymousContent(nsTArray<ContentInfo>& aElements) |
80 | 0 | { |
81 | 0 | MOZ_ASSERT(!mCustomContentContainer); |
82 | 0 |
|
83 | 0 | if (!mContent) { |
84 | 0 | return NS_OK; |
85 | 0 | } |
86 | 0 | |
87 | 0 | nsCOMPtr<nsIDocument> doc = mContent->OwnerDoc(); |
88 | 0 |
|
89 | 0 | RefPtr<AccessibleCaretEventHub> eventHub = |
90 | 0 | PresShell()->GetAccessibleCaretEventHub(); |
91 | 0 |
|
92 | 0 | // This will go through InsertAnonymousContent and such, and we don't really |
93 | 0 | // want it to end up inserting into our content container. |
94 | 0 | // |
95 | 0 | // FIXME(emilio): The fact that this enters into InsertAnonymousContent is a |
96 | 0 | // bit nasty, can we avoid it, maybe doing this off a scriptrunner? |
97 | 0 | if (eventHub) { |
98 | 0 | eventHub->Init(); |
99 | 0 | } |
100 | 0 |
|
101 | 0 | // Create the custom content container. |
102 | 0 | mCustomContentContainer = doc->CreateHTMLElement(nsGkAtoms::div); |
103 | | #ifdef DEBUG |
104 | | // We restyle our mCustomContentContainer, even though it's root anonymous |
105 | | // content. Normally that's not OK because the frame constructor doesn't know |
106 | | // how to order the frame tree in such cases, but we make this work for this |
107 | | // particular case, so it's OK. |
108 | | mCustomContentContainer->SetProperty(nsGkAtoms::restylableAnonymousNode, |
109 | | reinterpret_cast<void*>(true)); |
110 | | #endif // DEBUG |
111 | |
|
112 | 0 | mCustomContentContainer->SetProperty(nsGkAtoms::docLevelNativeAnonymousContent, |
113 | 0 | reinterpret_cast<void*>(true)); |
114 | 0 |
|
115 | 0 | // This will usually be done by the caller, but in this case we do it here, |
116 | 0 | // since we reuse the document's AnoymousContent list, and those survive |
117 | 0 | // across reframes and thus may already be flagged as being in an anonymous |
118 | 0 | // subtree. We don't really want to have this semi-broken state where |
119 | 0 | // anonymous nodes have a non-anonymous. |
120 | 0 | mCustomContentContainer->SetIsNativeAnonymousRoot(); |
121 | 0 |
|
122 | 0 | aElements.AppendElement(mCustomContentContainer); |
123 | 0 |
|
124 | 0 | // Do not create an accessible object for the container. |
125 | 0 | mCustomContentContainer->SetAttr(kNameSpaceID_None, nsGkAtoms::role, |
126 | 0 | NS_LITERAL_STRING("presentation"), false); |
127 | 0 |
|
128 | 0 | mCustomContentContainer->SetAttr(kNameSpaceID_None, nsGkAtoms::_class, |
129 | 0 | NS_LITERAL_STRING("moz-custom-content-container"), |
130 | 0 | false); |
131 | 0 |
|
132 | 0 | // Only create a frame for mCustomContentContainer if it has some children. |
133 | 0 | if (doc->GetAnonymousContents().IsEmpty()) { |
134 | 0 | HideCustomContentContainer(); |
135 | 0 | } |
136 | 0 |
|
137 | 0 | for (RefPtr<AnonymousContent>& anonContent : doc->GetAnonymousContents()) { |
138 | 0 | if (nsCOMPtr<nsINode> parent = anonContent->ContentNode().GetParentNode()) { |
139 | 0 | // Parent had better be an old custom content container already removed |
140 | 0 | // from a reframe. Forget about it since we're about to get inserted in a |
141 | 0 | // new one. |
142 | 0 | // |
143 | 0 | // TODO(emilio): Maybe we should extend PostDestroyData and do this stuff |
144 | 0 | // there instead, or something... |
145 | 0 | MOZ_ASSERT(parent != mCustomContentContainer); |
146 | 0 | MOZ_ASSERT(parent->IsElement()); |
147 | 0 | MOZ_ASSERT(parent->AsElement()->IsRootOfNativeAnonymousSubtree()); |
148 | 0 | MOZ_ASSERT(!parent->IsInComposedDoc()); |
149 | 0 | MOZ_ASSERT(!parent->GetParentNode()); |
150 | 0 |
|
151 | 0 | parent->RemoveChildNode(&anonContent->ContentNode(), false); |
152 | 0 | } |
153 | 0 |
|
154 | 0 | mCustomContentContainer->AppendChildTo(&anonContent->ContentNode(), false); |
155 | 0 | } |
156 | 0 |
|
157 | 0 | // Create a popupgroup element for chrome privileged top level non-XUL |
158 | 0 | // documents to support context menus and tooltips. |
159 | 0 | if (PresContext()->IsChrome() && PresContext()->IsRoot() && |
160 | 0 | doc->AllowXULXBL() && !doc->IsXULDocument()) { |
161 | 0 | nsNodeInfoManager* nodeInfoManager = doc->NodeInfoManager(); |
162 | 0 | RefPtr<NodeInfo> nodeInfo = |
163 | 0 | nodeInfoManager->GetNodeInfo(nsGkAtoms::popupgroup, |
164 | 0 | nullptr, kNameSpaceID_XUL, |
165 | 0 | nsINode::ELEMENT_NODE); |
166 | 0 |
|
167 | 0 | nsresult rv = NS_NewXULElement(getter_AddRefs(mPopupgroupContent), |
168 | 0 | nodeInfo.forget(), |
169 | 0 | dom::NOT_FROM_PARSER); |
170 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
171 | 0 |
|
172 | 0 | aElements.AppendElement(mPopupgroupContent); |
173 | 0 |
|
174 | 0 | nodeInfo = nodeInfoManager->GetNodeInfo(nsGkAtoms::tooltip, nullptr, |
175 | 0 | kNameSpaceID_XUL, |
176 | 0 | nsINode::ELEMENT_NODE); |
177 | 0 |
|
178 | 0 | rv = NS_NewXULElement(getter_AddRefs(mTooltipContent), nodeInfo.forget(), |
179 | 0 | dom::NOT_FROM_PARSER); |
180 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
181 | 0 |
|
182 | 0 | mTooltipContent->SetAttr(kNameSpaceID_None, nsGkAtoms::_default, |
183 | 0 | NS_LITERAL_STRING("true"), false); |
184 | 0 | // Set the page attribute so the XBL binding will find the text for the |
185 | 0 | // tooltip from the currently hovered element. |
186 | 0 | mTooltipContent->SetAttr(kNameSpaceID_None, nsGkAtoms::page, |
187 | 0 | NS_LITERAL_STRING("true"), false); |
188 | 0 |
|
189 | 0 | aElements.AppendElement(mTooltipContent); |
190 | 0 | } |
191 | 0 |
|
192 | 0 | return NS_OK; |
193 | 0 | } |
194 | | |
195 | | void |
196 | | nsCanvasFrame::AppendAnonymousContentTo(nsTArray<nsIContent*>& aElements, uint32_t aFilter) |
197 | 0 | { |
198 | 0 | if (mCustomContentContainer) { |
199 | 0 | aElements.AppendElement(mCustomContentContainer); |
200 | 0 | } |
201 | 0 | if (mPopupgroupContent) { |
202 | 0 | aElements.AppendElement(mPopupgroupContent); |
203 | 0 | } |
204 | 0 | if (mTooltipContent) { |
205 | 0 | aElements.AppendElement(mTooltipContent); |
206 | 0 | } |
207 | 0 | } |
208 | | |
209 | | void |
210 | | nsCanvasFrame::DestroyFrom(nsIFrame* aDestructRoot, PostDestroyData& aPostDestroyData) |
211 | 0 | { |
212 | 0 | nsIScrollableFrame* sf = |
213 | 0 | PresContext()->GetPresShell()->GetRootScrollFrameAsScrollable(); |
214 | 0 | if (sf) { |
215 | 0 | sf->RemoveScrollPositionListener(this); |
216 | 0 | } |
217 | 0 |
|
218 | 0 | aPostDestroyData.AddAnonymousContent(mCustomContentContainer.forget()); |
219 | 0 | if (mPopupgroupContent) { |
220 | 0 | aPostDestroyData.AddAnonymousContent(mPopupgroupContent.forget()); |
221 | 0 | } |
222 | 0 | if (mTooltipContent) { |
223 | 0 | aPostDestroyData.AddAnonymousContent(mTooltipContent.forget()); |
224 | 0 | } |
225 | 0 |
|
226 | 0 | MOZ_ASSERT(!mPopupSetFrame || |
227 | 0 | nsLayoutUtils::IsProperAncestorFrame(this, mPopupSetFrame), |
228 | 0 | "Someone forgot to clear popup set frame"); |
229 | 0 | nsContainerFrame::DestroyFrom(aDestructRoot, aPostDestroyData); |
230 | 0 | } |
231 | | |
232 | | void |
233 | | nsCanvasFrame::ScrollPositionWillChange(nscoord aX, nscoord aY) |
234 | 0 | { |
235 | 0 | if (mDoPaintFocus) { |
236 | 0 | mDoPaintFocus = false; |
237 | 0 | PresShell()->GetRootFrame()->InvalidateFrameSubtree(); |
238 | 0 | } |
239 | 0 | } |
240 | | |
241 | | NS_IMETHODIMP |
242 | | nsCanvasFrame::SetHasFocus(bool aHasFocus) |
243 | 0 | { |
244 | 0 | if (mDoPaintFocus != aHasFocus) { |
245 | 0 | mDoPaintFocus = aHasFocus; |
246 | 0 | PresShell()->GetRootFrame()->InvalidateFrameSubtree(); |
247 | 0 |
|
248 | 0 | if (!mAddedScrollPositionListener) { |
249 | 0 | nsIScrollableFrame* sf = |
250 | 0 | PresContext()->GetPresShell()->GetRootScrollFrameAsScrollable(); |
251 | 0 | if (sf) { |
252 | 0 | sf->AddScrollPositionListener(this); |
253 | 0 | mAddedScrollPositionListener = true; |
254 | 0 | } |
255 | 0 | } |
256 | 0 | } |
257 | 0 | return NS_OK; |
258 | 0 | } |
259 | | |
260 | | void |
261 | | nsCanvasFrame::SetInitialChildList(ChildListID aListID, |
262 | | nsFrameList& aChildList) |
263 | 0 | { |
264 | 0 | NS_ASSERTION(aListID != kPrincipalList || |
265 | 0 | aChildList.IsEmpty() || aChildList.OnlyChild(), |
266 | 0 | "Primary child list can have at most one frame in it"); |
267 | 0 | nsContainerFrame::SetInitialChildList(aListID, aChildList); |
268 | 0 | MaybePropagateRootElementWritingMode(); |
269 | 0 | } |
270 | | |
271 | | void |
272 | | nsCanvasFrame::AppendFrames(ChildListID aListID, |
273 | | nsFrameList& aFrameList) |
274 | 0 | { |
275 | | #ifdef DEBUG |
276 | | MOZ_ASSERT(aListID == kPrincipalList, "unexpected child list"); |
277 | | if (!mFrames.IsEmpty()) { |
278 | | for (nsFrameList::Enumerator e(aFrameList); !e.AtEnd(); e.Next()) { |
279 | | // We only allow native anonymous child frames to be in principal child |
280 | | // list in canvas frame. |
281 | | MOZ_ASSERT(e.get()->GetContent()->IsInNativeAnonymousSubtree(), |
282 | | "invalid child list"); |
283 | | } |
284 | | } |
285 | | nsFrame::VerifyDirtyBitSet(aFrameList); |
286 | | #endif |
287 | | nsContainerFrame::AppendFrames(aListID, aFrameList); |
288 | 0 | MaybePropagateRootElementWritingMode(); |
289 | 0 | } |
290 | | |
291 | | void |
292 | | nsCanvasFrame::InsertFrames(ChildListID aListID, |
293 | | nsIFrame* aPrevFrame, |
294 | | nsFrameList& aFrameList) |
295 | 0 | { |
296 | 0 | // Because we only support a single child frame inserting is the same |
297 | 0 | // as appending |
298 | 0 | MOZ_ASSERT(!aPrevFrame, "unexpected previous sibling frame"); |
299 | 0 | AppendFrames(aListID, aFrameList); |
300 | 0 | MaybePropagateRootElementWritingMode(); |
301 | 0 | } |
302 | | |
303 | | #ifdef DEBUG |
304 | | void |
305 | | nsCanvasFrame::RemoveFrame(ChildListID aListID, |
306 | | nsIFrame* aOldFrame) |
307 | | { |
308 | | MOZ_ASSERT(aListID == kPrincipalList, "unexpected child list"); |
309 | | nsContainerFrame::RemoveFrame(aListID, aOldFrame); |
310 | | } |
311 | | #endif |
312 | | |
313 | | nsRect nsCanvasFrame::CanvasArea() const |
314 | 0 | { |
315 | 0 | // Not clear which overflow rect we want here, but it probably doesn't |
316 | 0 | // matter. |
317 | 0 | nsRect result(GetVisualOverflowRect()); |
318 | 0 |
|
319 | 0 | nsIScrollableFrame *scrollableFrame = do_QueryFrame(GetParent()); |
320 | 0 | if (scrollableFrame) { |
321 | 0 | nsRect portRect = scrollableFrame->GetScrollPortRect(); |
322 | 0 | result.UnionRect(result, nsRect(nsPoint(0, 0), portRect.Size())); |
323 | 0 | } |
324 | 0 | return result; |
325 | 0 | } |
326 | | |
327 | | nsPopupSetFrame* |
328 | | nsCanvasFrame::GetPopupSetFrame() |
329 | 0 | { |
330 | 0 | return mPopupSetFrame; |
331 | 0 | } |
332 | | |
333 | | void |
334 | | nsCanvasFrame::SetPopupSetFrame(nsPopupSetFrame* aPopupSet) |
335 | 0 | { |
336 | 0 | MOZ_ASSERT(!aPopupSet || !mPopupSetFrame, |
337 | 0 | "Popup set is already defined! Only 1 allowed."); |
338 | 0 | mPopupSetFrame = aPopupSet; |
339 | 0 | } |
340 | | |
341 | | Element* |
342 | | nsCanvasFrame::GetDefaultTooltip() |
343 | 0 | { |
344 | 0 | return mTooltipContent; |
345 | 0 | } |
346 | | |
347 | | void |
348 | | nsCanvasFrame::SetDefaultTooltip(Element* aTooltip) |
349 | 0 | { |
350 | 0 | MOZ_ASSERT(!aTooltip || aTooltip == mTooltipContent, |
351 | 0 | "Default tooltip should be anonymous content tooltip."); |
352 | 0 | mTooltipContent = aTooltip; |
353 | 0 | } |
354 | | |
355 | | void |
356 | | nsDisplayCanvasBackgroundColor::Paint(nsDisplayListBuilder* aBuilder, |
357 | | gfxContext* aCtx) |
358 | 0 | { |
359 | 0 | nsCanvasFrame* frame = static_cast<nsCanvasFrame*>(mFrame); |
360 | 0 | nsPoint offset = ToReferenceFrame(); |
361 | 0 | nsRect bgClipRect = frame->CanvasArea() + offset; |
362 | 0 | if (NS_GET_A(mColor) > 0) { |
363 | 0 | DrawTarget* drawTarget = aCtx->GetDrawTarget(); |
364 | 0 | int32_t appUnitsPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel(); |
365 | 0 | Rect devPxRect = |
366 | 0 | NSRectToSnappedRect(bgClipRect, appUnitsPerDevPixel, *drawTarget); |
367 | 0 | drawTarget->FillRect(devPxRect, ColorPattern(ToDeviceColor(mColor))); |
368 | 0 | } |
369 | 0 | } |
370 | | |
371 | | already_AddRefed<Layer> |
372 | | nsDisplayCanvasBackgroundColor::BuildLayer(nsDisplayListBuilder* aBuilder, |
373 | | LayerManager* aManager, |
374 | | const ContainerLayerParameters& aContainerParameters) |
375 | 0 | { |
376 | 0 | if (NS_GET_A(mColor) == 0) { |
377 | 0 | return nullptr; |
378 | 0 | } |
379 | 0 | |
380 | 0 | RefPtr<ColorLayer> layer = static_cast<ColorLayer*> |
381 | 0 | (aManager->GetLayerBuilder()->GetLeafLayerFor(aBuilder, this)); |
382 | 0 | if (!layer) { |
383 | 0 | layer = aManager->CreateColorLayer(); |
384 | 0 | if (!layer) { |
385 | 0 | return nullptr; |
386 | 0 | } |
387 | 0 | } |
388 | 0 | layer->SetColor(ToDeviceColor(mColor)); |
389 | 0 |
|
390 | 0 | nsCanvasFrame* frame = static_cast<nsCanvasFrame*>(mFrame); |
391 | 0 | nsPoint offset = ToReferenceFrame(); |
392 | 0 | nsRect bgClipRect = frame->CanvasArea() + offset; |
393 | 0 |
|
394 | 0 | int32_t appUnitsPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel(); |
395 | 0 |
|
396 | 0 | layer->SetBounds(bgClipRect.ToNearestPixels(appUnitsPerDevPixel)); |
397 | 0 | layer->SetBaseTransform(gfx::Matrix4x4::Translation(aContainerParameters.mOffset.x, |
398 | 0 | aContainerParameters.mOffset.y, 0)); |
399 | 0 |
|
400 | 0 | return layer.forget(); |
401 | 0 | } |
402 | | |
403 | | bool |
404 | | nsDisplayCanvasBackgroundColor::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder, |
405 | | mozilla::wr::IpcResourceUpdateQueue& aResources, |
406 | | const StackingContextHelper& aSc, |
407 | | WebRenderLayerManager* aManager, |
408 | | nsDisplayListBuilder* aDisplayListBuilder) |
409 | 0 | { |
410 | 0 | ContainerLayerParameters parameter; |
411 | 0 |
|
412 | 0 | nsCanvasFrame *frame = static_cast<nsCanvasFrame *>(mFrame); |
413 | 0 | nsPoint offset = ToReferenceFrame(); |
414 | 0 | nsRect bgClipRect = frame->CanvasArea() + offset; |
415 | 0 | int32_t appUnitsPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel(); |
416 | 0 |
|
417 | 0 | LayoutDeviceRect rect = LayoutDeviceRect::FromAppUnits( |
418 | 0 | bgClipRect, appUnitsPerDevPixel); |
419 | 0 |
|
420 | 0 | wr::LayoutRect roundedRect = wr::ToRoundedLayoutRect(rect); |
421 | 0 | aBuilder.PushRect(roundedRect, |
422 | 0 | roundedRect, |
423 | 0 | !BackfaceIsHidden(), |
424 | 0 | wr::ToColorF(ToDeviceColor(mColor))); |
425 | 0 | return true; |
426 | 0 | } |
427 | | |
428 | | #ifdef MOZ_DUMP_PAINTING |
429 | | void |
430 | | nsDisplayCanvasBackgroundColor::WriteDebugInfo(std::stringstream& aStream) |
431 | | { |
432 | | aStream << " (rgba " |
433 | | << (int)NS_GET_R(mColor) << "," |
434 | | << (int)NS_GET_G(mColor) << "," |
435 | | << (int)NS_GET_B(mColor) << "," |
436 | | << (int)NS_GET_A(mColor) << ")"; |
437 | | } |
438 | | #endif |
439 | | |
440 | | void |
441 | | nsDisplayCanvasBackgroundImage::Paint(nsDisplayListBuilder* aBuilder, |
442 | | gfxContext* aCtx) |
443 | 0 | { |
444 | 0 | nsCanvasFrame* frame = static_cast<nsCanvasFrame*>(mFrame); |
445 | 0 | nsPoint offset = ToReferenceFrame(); |
446 | 0 | nsRect bgClipRect = frame->CanvasArea() + offset; |
447 | 0 |
|
448 | 0 | PaintInternal(aBuilder, aCtx, GetPaintRect(), &bgClipRect); |
449 | 0 | } |
450 | | |
451 | | bool |
452 | | nsDisplayCanvasBackgroundImage::IsSingleFixedPositionImage(nsDisplayListBuilder* aBuilder, |
453 | | const nsRect& aClipRect, |
454 | | gfxRect* aDestRect) |
455 | 0 | { |
456 | 0 | if (!mBackgroundStyle) |
457 | 0 | return false; |
458 | 0 | |
459 | 0 | if (mBackgroundStyle->StyleBackground()->mImage.mLayers.Length() != 1) |
460 | 0 | return false; |
461 | 0 | |
462 | 0 | |
463 | 0 | nsPresContext* presContext = mFrame->PresContext(); |
464 | 0 | uint32_t flags = aBuilder->GetBackgroundPaintFlags(); |
465 | 0 | nsRect borderArea = nsRect(ToReferenceFrame(), mFrame->GetSize()); |
466 | 0 | const nsStyleImageLayers::Layer &layer = mBackgroundStyle->StyleBackground()->mImage.mLayers[mLayer]; |
467 | 0 |
|
468 | 0 | if (layer.mAttachment != StyleImageLayerAttachment::Fixed) |
469 | 0 | return false; |
470 | 0 | |
471 | 0 | nsBackgroundLayerState state = |
472 | 0 | nsCSSRendering::PrepareImageLayer(presContext, mFrame, flags, |
473 | 0 | borderArea, aClipRect, layer); |
474 | 0 |
|
475 | 0 |
|
476 | 0 | // We only care about images here, not gradients. |
477 | 0 | if (!mIsRasterImage) |
478 | 0 | return false; |
479 | 0 | |
480 | 0 | int32_t appUnitsPerDevPixel = presContext->AppUnitsPerDevPixel(); |
481 | 0 | *aDestRect = nsLayoutUtils::RectToGfxRect(state.mFillArea, appUnitsPerDevPixel); |
482 | 0 |
|
483 | 0 | return true; |
484 | 0 | } |
485 | | |
486 | | |
487 | | void |
488 | | nsDisplayCanvasThemedBackground::Paint(nsDisplayListBuilder* aBuilder, |
489 | | gfxContext* aCtx) |
490 | 0 | { |
491 | 0 | nsCanvasFrame* frame = static_cast<nsCanvasFrame*>(mFrame); |
492 | 0 | nsPoint offset = ToReferenceFrame(); |
493 | 0 | nsRect bgClipRect = frame->CanvasArea() + offset; |
494 | 0 |
|
495 | 0 | PaintInternal(aBuilder, aCtx, GetPaintRect(), &bgClipRect); |
496 | 0 | } |
497 | | |
498 | | /** |
499 | | * A display item to paint the focus ring for the document. |
500 | | * |
501 | | * The only reason this can't use nsDisplayGeneric is overriding GetBounds. |
502 | | */ |
503 | | class nsDisplayCanvasFocus : public nsDisplayItem { |
504 | | public: |
505 | | nsDisplayCanvasFocus(nsDisplayListBuilder* aBuilder, nsCanvasFrame *aFrame) |
506 | | : nsDisplayItem(aBuilder, aFrame) |
507 | 0 | { |
508 | 0 | MOZ_COUNT_CTOR(nsDisplayCanvasFocus); |
509 | 0 | } |
510 | 0 | virtual ~nsDisplayCanvasFocus() { |
511 | 0 | MOZ_COUNT_DTOR(nsDisplayCanvasFocus); |
512 | 0 | } |
513 | | |
514 | | virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, |
515 | | bool* aSnap) const override |
516 | 0 | { |
517 | 0 | *aSnap = false; |
518 | 0 | // This is an overestimate, but that's not a problem. |
519 | 0 | nsCanvasFrame* frame = static_cast<nsCanvasFrame*>(mFrame); |
520 | 0 | return frame->CanvasArea() + ToReferenceFrame(); |
521 | 0 | } |
522 | | |
523 | | virtual void Paint(nsDisplayListBuilder* aBuilder, |
524 | | gfxContext* aCtx) override |
525 | 0 | { |
526 | 0 | nsCanvasFrame* frame = static_cast<nsCanvasFrame*>(mFrame); |
527 | 0 | frame->PaintFocus(aCtx->GetDrawTarget(), ToReferenceFrame()); |
528 | 0 | } |
529 | | |
530 | | NS_DISPLAY_DECL_NAME("CanvasFocus", TYPE_CANVAS_FOCUS) |
531 | | }; |
532 | | |
533 | | void |
534 | | nsCanvasFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, |
535 | | const nsDisplayListSet& aLists) |
536 | 0 | { |
537 | 0 | if (GetPrevInFlow()) { |
538 | 0 | DisplayOverflowContainers(aBuilder, aLists); |
539 | 0 | } |
540 | 0 |
|
541 | 0 | // Force a background to be shown. We may have a background propagated to us, |
542 | 0 | // in which case StyleBackground wouldn't have the right background |
543 | 0 | // and the code in nsFrame::DisplayBorderBackgroundOutline might not give us |
544 | 0 | // a background. |
545 | 0 | // We don't have any border or outline, and our background draws over |
546 | 0 | // the overflow area, so just add nsDisplayCanvasBackground instead of |
547 | 0 | // calling DisplayBorderBackgroundOutline. |
548 | 0 | if (IsVisibleForPainting(aBuilder)) { |
549 | 0 | ComputedStyle* bg = nullptr; |
550 | 0 | nsIFrame* dependentFrame = nullptr; |
551 | 0 | bool isThemed = IsThemed(); |
552 | 0 | if (!isThemed && nsCSSRendering::FindBackgroundFrame(this, &dependentFrame)) { |
553 | 0 | bg = dependentFrame->Style(); |
554 | 0 | if (dependentFrame == this) { |
555 | 0 | dependentFrame = nullptr; |
556 | 0 | } |
557 | 0 | } |
558 | 0 | aLists.BorderBackground()->AppendToTop( |
559 | 0 | MakeDisplayItem<nsDisplayCanvasBackgroundColor>(aBuilder, this)); |
560 | 0 |
|
561 | 0 | if (isThemed) { |
562 | 0 | aLists.BorderBackground()->AppendToTop( |
563 | 0 | MakeDisplayItem<nsDisplayCanvasThemedBackground>(aBuilder, this)); |
564 | 0 | return; |
565 | 0 | } |
566 | 0 | |
567 | 0 | if (!bg) { |
568 | 0 | return; |
569 | 0 | } |
570 | 0 | |
571 | 0 | const ActiveScrolledRoot* asr = |
572 | 0 | aBuilder->CurrentActiveScrolledRoot(); |
573 | 0 |
|
574 | 0 | bool needBlendContainer = false; |
575 | 0 | nsDisplayListBuilder::AutoContainerASRTracker contASRTracker(aBuilder); |
576 | 0 |
|
577 | 0 | // Create separate items for each background layer. |
578 | 0 | const nsStyleImageLayers& layers = bg->StyleBackground()->mImage; |
579 | 0 | NS_FOR_VISIBLE_IMAGE_LAYERS_BACK_TO_FRONT(i, layers) { |
580 | 0 | if (layers.mLayers[i].mImage.IsEmpty()) { |
581 | 0 | continue; |
582 | 0 | } |
583 | 0 | if (layers.mLayers[i].mBlendMode != NS_STYLE_BLEND_NORMAL) { |
584 | 0 | needBlendContainer = true; |
585 | 0 | } |
586 | 0 |
|
587 | 0 | nsRect bgRect = GetRectRelativeToSelf() + aBuilder->ToReferenceFrame(this); |
588 | 0 |
|
589 | 0 | const ActiveScrolledRoot* thisItemASR = asr; |
590 | 0 | nsDisplayList thisItemList; |
591 | 0 | nsDisplayBackgroundImage::InitData bgData = |
592 | 0 | nsDisplayBackgroundImage::GetInitData(aBuilder, this, i, bgRect, bg); |
593 | 0 |
|
594 | 0 | if (bgData.shouldFixToViewport) { |
595 | 0 |
|
596 | 0 | auto* displayData = aBuilder->GetCurrentFixedBackgroundDisplayData(); |
597 | 0 | nsDisplayListBuilder::AutoBuildingDisplayList |
598 | 0 | buildingDisplayList(aBuilder, this, aBuilder->GetVisibleRect(), aBuilder->GetDirtyRect(), false); |
599 | 0 |
|
600 | 0 | DisplayListClipState::AutoSaveRestore clipState(aBuilder); |
601 | 0 | nsDisplayListBuilder::AutoCurrentActiveScrolledRootSetter asrSetter(aBuilder); |
602 | 0 | if (displayData) { |
603 | 0 | nsPoint offset = GetOffsetTo(PresContext()->GetPresShell()->GetRootFrame()); |
604 | 0 | aBuilder->SetVisibleRect(displayData->mVisibleRect + offset); |
605 | 0 | aBuilder->SetDirtyRect(displayData->mDirtyRect + offset); |
606 | 0 |
|
607 | 0 | clipState.SetClipChainForContainingBlockDescendants( |
608 | 0 | displayData->mContainingBlockClipChain); |
609 | 0 | asrSetter.SetCurrentActiveScrolledRoot( |
610 | 0 | displayData->mContainingBlockActiveScrolledRoot); |
611 | 0 | thisItemASR = displayData->mContainingBlockActiveScrolledRoot; |
612 | 0 | } |
613 | 0 | nsDisplayCanvasBackgroundImage* bgItem = nullptr; |
614 | 0 | { |
615 | 0 | DisplayListClipState::AutoSaveRestore bgImageClip(aBuilder); |
616 | 0 | bgImageClip.Clear(); |
617 | 0 | bgItem = MakeDisplayItem<nsDisplayCanvasBackgroundImage>(aBuilder, bgData); |
618 | 0 | bgItem->SetDependentFrame(aBuilder, dependentFrame); |
619 | 0 | } |
620 | 0 | thisItemList.AppendToTop( |
621 | 0 | nsDisplayFixedPosition::CreateForFixedBackground(aBuilder, this, bgItem, i)); |
622 | 0 |
|
623 | 0 | } else { |
624 | 0 | nsDisplayCanvasBackgroundImage* bgItem = MakeDisplayItem<nsDisplayCanvasBackgroundImage>(aBuilder, bgData); |
625 | 0 | bgItem->SetDependentFrame(aBuilder, dependentFrame); |
626 | 0 | thisItemList.AppendToTop(bgItem); |
627 | 0 | } |
628 | 0 |
|
629 | 0 | if (layers.mLayers[i].mBlendMode != NS_STYLE_BLEND_NORMAL) { |
630 | 0 | DisplayListClipState::AutoSaveRestore blendClip(aBuilder); |
631 | 0 | thisItemList.AppendToTop( |
632 | 0 | MakeDisplayItem<nsDisplayBlendMode>(aBuilder, this, &thisItemList, |
633 | 0 | layers.mLayers[i].mBlendMode, |
634 | 0 | thisItemASR, i + 1)); |
635 | 0 | } |
636 | 0 | aLists.BorderBackground()->AppendToTop(&thisItemList); |
637 | 0 | } |
638 | 0 |
|
639 | 0 | if (needBlendContainer) { |
640 | 0 | const ActiveScrolledRoot* containerASR = contASRTracker.GetContainerASR(); |
641 | 0 | DisplayListClipState::AutoSaveRestore blendContainerClip(aBuilder); |
642 | 0 | aLists.BorderBackground()->AppendToTop( |
643 | 0 | nsDisplayBlendContainer::CreateForBackgroundBlendMode(aBuilder, this, |
644 | 0 | aLists.BorderBackground(), |
645 | 0 | containerASR)); |
646 | 0 | } |
647 | 0 | } |
648 | 0 |
|
649 | 0 | for (nsIFrame* kid : PrincipalChildList()) { |
650 | 0 | // Put our child into its own pseudo-stack. |
651 | 0 | BuildDisplayListForChild(aBuilder, kid, aLists); |
652 | 0 | } |
653 | 0 |
|
654 | | #ifdef DEBUG_CANVAS_FOCUS |
655 | | nsCOMPtr<nsIContent> focusContent; |
656 | | aPresContext->EventStateManager()-> |
657 | | GetFocusedContent(getter_AddRefs(focusContent)); |
658 | | |
659 | | bool hasFocus = false; |
660 | | nsCOMPtr<nsISupports> container; |
661 | | aPresContext->GetContainer(getter_AddRefs(container)); |
662 | | nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(container)); |
663 | | if (docShell) { |
664 | | docShell->GetHasFocus(&hasFocus); |
665 | | nsRect dirty = aBuilder->GetDirtyRect(); |
666 | | printf("%p - nsCanvasFrame::Paint R:%d,%d,%d,%d DR: %d,%d,%d,%d\n", this, |
667 | | mRect.x, mRect.y, mRect.width, mRect.height, |
668 | | dirty.x, dirty.y, dirty.width, dirty.height); |
669 | | } |
670 | | printf("%p - Focus: %s c: %p DoPaint:%s\n", docShell.get(), hasFocus?"Y":"N", |
671 | | focusContent.get(), mDoPaintFocus?"Y":"N"); |
672 | | #endif |
673 | |
|
674 | 0 | if (!mDoPaintFocus) |
675 | 0 | return; |
676 | 0 | // Only paint the focus if we're visible |
677 | 0 | if (!StyleVisibility()->IsVisible()) |
678 | 0 | return; |
679 | 0 | |
680 | 0 | aLists.Outlines()->AppendToTop( |
681 | 0 | MakeDisplayItem<nsDisplayCanvasFocus>(aBuilder, this)); |
682 | 0 | } |
683 | | |
684 | | void |
685 | | nsCanvasFrame::PaintFocus(DrawTarget* aDrawTarget, nsPoint aPt) |
686 | 0 | { |
687 | 0 | nsRect focusRect(aPt, GetSize()); |
688 | 0 |
|
689 | 0 | nsIScrollableFrame *scrollableFrame = do_QueryFrame(GetParent()); |
690 | 0 | if (scrollableFrame) { |
691 | 0 | nsRect portRect = scrollableFrame->GetScrollPortRect(); |
692 | 0 | focusRect.width = portRect.width; |
693 | 0 | focusRect.height = portRect.height; |
694 | 0 | focusRect.MoveBy(scrollableFrame->GetScrollPosition()); |
695 | 0 | } |
696 | 0 |
|
697 | 0 | // XXX use the root frame foreground color, but should we find BODY frame |
698 | 0 | // for HTML documents? |
699 | 0 | nsIFrame* root = mFrames.FirstChild(); |
700 | 0 | const nsStyleColor* color = root ? root->StyleColor() : StyleColor(); |
701 | 0 | if (!color) { |
702 | 0 | NS_ERROR("current color cannot be found"); |
703 | 0 | return; |
704 | 0 | } |
705 | 0 |
|
706 | 0 | nsCSSRendering::PaintFocus(PresContext(), aDrawTarget, |
707 | 0 | focusRect, color->mColor); |
708 | 0 | } |
709 | | |
710 | | /* virtual */ nscoord |
711 | | nsCanvasFrame::GetMinISize(gfxContext *aRenderingContext) |
712 | 0 | { |
713 | 0 | nscoord result; |
714 | 0 | DISPLAY_MIN_INLINE_SIZE(this, result); |
715 | 0 | if (mFrames.IsEmpty()) |
716 | 0 | result = 0; |
717 | 0 | else |
718 | 0 | result = mFrames.FirstChild()->GetMinISize(aRenderingContext); |
719 | 0 | return result; |
720 | 0 | } |
721 | | |
722 | | /* virtual */ nscoord |
723 | | nsCanvasFrame::GetPrefISize(gfxContext *aRenderingContext) |
724 | 0 | { |
725 | 0 | nscoord result; |
726 | 0 | DISPLAY_PREF_INLINE_SIZE(this, result); |
727 | 0 | if (mFrames.IsEmpty()) |
728 | 0 | result = 0; |
729 | 0 | else |
730 | 0 | result = mFrames.FirstChild()->GetPrefISize(aRenderingContext); |
731 | 0 | return result; |
732 | 0 | } |
733 | | |
734 | | void |
735 | | nsCanvasFrame::Reflow(nsPresContext* aPresContext, |
736 | | ReflowOutput& aDesiredSize, |
737 | | const ReflowInput& aReflowInput, |
738 | | nsReflowStatus& aStatus) |
739 | 0 | { |
740 | 0 | MarkInReflow(); |
741 | 0 | DO_GLOBAL_REFLOW_COUNT("nsCanvasFrame"); |
742 | 0 | DISPLAY_REFLOW(aPresContext, this, aReflowInput, aDesiredSize, aStatus); |
743 | 0 | MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!"); |
744 | 0 | NS_FRAME_TRACE_REFLOW_IN("nsCanvasFrame::Reflow"); |
745 | 0 |
|
746 | 0 | nsCanvasFrame* prevCanvasFrame = static_cast<nsCanvasFrame*> |
747 | 0 | (GetPrevInFlow()); |
748 | 0 | if (prevCanvasFrame) { |
749 | 0 | AutoFrameListPtr overflow(aPresContext, |
750 | 0 | prevCanvasFrame->StealOverflowFrames()); |
751 | 0 | if (overflow) { |
752 | 0 | NS_ASSERTION(overflow->OnlyChild(), |
753 | 0 | "must have doc root as canvas frame's only child"); |
754 | 0 | nsContainerFrame::ReparentFrameViewList(*overflow, prevCanvasFrame, this); |
755 | 0 | // Prepend overflow to the our child list. There may already be |
756 | 0 | // children placeholders for fixed-pos elements, which don't get |
757 | 0 | // reflowed but must not be lost until the canvas frame is destroyed. |
758 | 0 | mFrames.InsertFrames(this, nullptr, *overflow); |
759 | 0 | } |
760 | 0 | } |
761 | 0 |
|
762 | 0 | // Set our size up front, since some parts of reflow depend on it |
763 | 0 | // being already set. Note that the computed height may be |
764 | 0 | // unconstrained; that's ok. Consumers should watch out for that. |
765 | 0 | SetSize(nsSize(aReflowInput.ComputedWidth(), aReflowInput.ComputedHeight())); |
766 | 0 |
|
767 | 0 | // Reflow our one and only normal child frame. It's either the root |
768 | 0 | // element's frame or a placeholder for that frame, if the root element |
769 | 0 | // is abs-pos or fixed-pos. We may have additional children which |
770 | 0 | // are placeholders for continuations of fixed-pos content, but those |
771 | 0 | // don't need to be reflowed. The normal child is always comes before |
772 | 0 | // the fixed-pos placeholders, because we insert it at the start |
773 | 0 | // of the child list, above. |
774 | 0 | ReflowOutput kidDesiredSize(aReflowInput); |
775 | 0 | if (mFrames.IsEmpty()) { |
776 | 0 | // We have no child frame, so return an empty size |
777 | 0 | aDesiredSize.Width() = aDesiredSize.Height() = 0; |
778 | 0 | } else if (mFrames.FirstChild() != mPopupSetFrame) { |
779 | 0 | nsIFrame* kidFrame = mFrames.FirstChild(); |
780 | 0 | bool kidDirty = (kidFrame->GetStateBits() & NS_FRAME_IS_DIRTY) != 0; |
781 | 0 |
|
782 | 0 | ReflowInput |
783 | 0 | kidReflowInput(aPresContext, aReflowInput, kidFrame, |
784 | 0 | aReflowInput.AvailableSize(kidFrame->GetWritingMode())); |
785 | 0 |
|
786 | 0 | if (aReflowInput.IsBResizeForWM(kidReflowInput.GetWritingMode()) && |
787 | 0 | (kidFrame->GetStateBits() & NS_FRAME_CONTAINS_RELATIVE_BSIZE)) { |
788 | 0 | // Tell our kid it's being block-dir resized too. Bit of a |
789 | 0 | // hack for framesets. |
790 | 0 | kidReflowInput.SetBResize(true); |
791 | 0 | } |
792 | 0 |
|
793 | 0 | WritingMode wm = aReflowInput.GetWritingMode(); |
794 | 0 | WritingMode kidWM = kidReflowInput.GetWritingMode(); |
795 | 0 | nsSize containerSize = aReflowInput.ComputedPhysicalSize(); |
796 | 0 |
|
797 | 0 | LogicalMargin margin = kidReflowInput.ComputedLogicalMargin(); |
798 | 0 | LogicalPoint kidPt(kidWM, margin.IStart(kidWM), margin.BStart(kidWM)); |
799 | 0 |
|
800 | 0 | kidReflowInput.ApplyRelativePositioning(&kidPt, containerSize); |
801 | 0 |
|
802 | 0 | // Reflow the frame |
803 | 0 | ReflowChild(kidFrame, aPresContext, kidDesiredSize, kidReflowInput, |
804 | 0 | kidWM, kidPt, containerSize, 0, aStatus); |
805 | 0 |
|
806 | 0 | // Complete the reflow and position and size the child frame |
807 | 0 | FinishReflowChild(kidFrame, aPresContext, kidDesiredSize, &kidReflowInput, |
808 | 0 | kidWM, kidPt, containerSize, 0); |
809 | 0 |
|
810 | 0 | if (!aStatus.IsFullyComplete()) { |
811 | 0 | nsIFrame* nextFrame = kidFrame->GetNextInFlow(); |
812 | 0 | NS_ASSERTION(nextFrame || aStatus.NextInFlowNeedsReflow(), |
813 | 0 | "If it's incomplete and has no nif yet, it must flag a nif reflow."); |
814 | 0 | if (!nextFrame) { |
815 | 0 | nextFrame = aPresContext->PresShell()->FrameConstructor()-> |
816 | 0 | CreateContinuingFrame(aPresContext, kidFrame, this); |
817 | 0 | SetOverflowFrames(nsFrameList(nextFrame, nextFrame)); |
818 | 0 | // Root overflow containers will be normal children of |
819 | 0 | // the canvas frame, but that's ok because there |
820 | 0 | // aren't any other frames we need to isolate them from |
821 | 0 | // during reflow. |
822 | 0 | } |
823 | 0 | if (aStatus.IsOverflowIncomplete()) { |
824 | 0 | nextFrame->AddStateBits(NS_FRAME_IS_OVERFLOW_CONTAINER); |
825 | 0 | } |
826 | 0 | } |
827 | 0 |
|
828 | 0 | // If the child frame was just inserted, then we're responsible for making sure |
829 | 0 | // it repaints |
830 | 0 | if (kidDirty) { |
831 | 0 | // But we have a new child, which will affect our background, so |
832 | 0 | // invalidate our whole rect. |
833 | 0 | // Note: Even though we request to be sized to our child's size, our |
834 | 0 | // scroll frame ensures that we are always the size of the viewport. |
835 | 0 | // Also note: GetPosition() on a CanvasFrame is always going to return |
836 | 0 | // (0, 0). We only want to invalidate GetRect() since Get*OverflowRect() |
837 | 0 | // could also include overflow to our top and left (out of the viewport) |
838 | 0 | // which doesn't need to be painted. |
839 | 0 | nsIFrame* viewport = PresContext()->GetPresShell()->GetRootFrame(); |
840 | 0 | viewport->InvalidateFrame(); |
841 | 0 | } |
842 | 0 |
|
843 | 0 | // Return our desired size. Normally it's what we're told, but |
844 | 0 | // sometimes we can be given an unconstrained height (when a window |
845 | 0 | // is sizing-to-content), and we should compute our desired height. |
846 | 0 | LogicalSize finalSize(wm); |
847 | 0 | finalSize.ISize(wm) = aReflowInput.ComputedISize(); |
848 | 0 | if (aReflowInput.ComputedBSize() == NS_UNCONSTRAINEDSIZE) { |
849 | 0 | finalSize.BSize(wm) = kidFrame->GetLogicalSize(wm).BSize(wm) + |
850 | 0 | kidReflowInput.ComputedLogicalMargin().BStartEnd(wm); |
851 | 0 | } else { |
852 | 0 | finalSize.BSize(wm) = aReflowInput.ComputedBSize(); |
853 | 0 | } |
854 | 0 |
|
855 | 0 | aDesiredSize.SetSize(wm, finalSize); |
856 | 0 | aDesiredSize.SetOverflowAreasToDesiredBounds(); |
857 | 0 | aDesiredSize.mOverflowAreas.UnionWith( |
858 | 0 | kidDesiredSize.mOverflowAreas + kidFrame->GetPosition()); |
859 | 0 | } |
860 | 0 |
|
861 | 0 | if (prevCanvasFrame) { |
862 | 0 | ReflowOverflowContainerChildren(aPresContext, aReflowInput, |
863 | 0 | aDesiredSize.mOverflowAreas, 0, |
864 | 0 | aStatus); |
865 | 0 | } |
866 | 0 |
|
867 | 0 | if (mPopupSetFrame) { |
868 | 0 | MOZ_ASSERT(mFrames.ContainsFrame(mPopupSetFrame), "Only normal flow supported."); |
869 | 0 | nsReflowStatus popupStatus; |
870 | 0 | ReflowOutput popupDesiredSize(aReflowInput.GetWritingMode()); |
871 | 0 | WritingMode wm = mPopupSetFrame->GetWritingMode(); |
872 | 0 | LogicalSize availSize = aReflowInput.ComputedSize(wm); |
873 | 0 | availSize.BSize(wm) = NS_UNCONSTRAINEDSIZE; |
874 | 0 | ReflowInput popupReflowInput(aPresContext, aReflowInput, |
875 | 0 | mPopupSetFrame, availSize); |
876 | 0 | ReflowChild(mPopupSetFrame, aPresContext, popupDesiredSize, |
877 | 0 | popupReflowInput, 0, 0, NS_FRAME_NO_MOVE_FRAME, popupStatus); |
878 | 0 | FinishReflowChild(mPopupSetFrame, aPresContext, popupDesiredSize, |
879 | 0 | &popupReflowInput, 0, 0, NS_FRAME_NO_MOVE_FRAME); |
880 | 0 | } |
881 | 0 |
|
882 | 0 | FinishReflowWithAbsoluteFrames(aPresContext, aDesiredSize, aReflowInput, aStatus); |
883 | 0 |
|
884 | 0 | NS_FRAME_TRACE_REFLOW_OUT("nsCanvasFrame::Reflow", aStatus); |
885 | 0 | NS_FRAME_SET_TRUNCATION(aStatus, aReflowInput, aDesiredSize); |
886 | 0 | } |
887 | | |
888 | | nsresult |
889 | | nsCanvasFrame::GetContentForEvent(WidgetEvent* aEvent, nsIContent** aContent) |
890 | 0 | { |
891 | 0 | NS_ENSURE_ARG_POINTER(aContent); |
892 | 0 | nsresult rv = nsFrame::GetContentForEvent(aEvent, aContent); |
893 | 0 | if (NS_FAILED(rv) || !*aContent) { |
894 | 0 | nsIFrame* kid = mFrames.FirstChild(); |
895 | 0 | if (kid) { |
896 | 0 | rv = kid->GetContentForEvent(aEvent, |
897 | 0 | aContent); |
898 | 0 | } |
899 | 0 | } |
900 | 0 |
|
901 | 0 | return rv; |
902 | 0 | } |
903 | | |
904 | | void |
905 | | nsCanvasFrame::MaybePropagateRootElementWritingMode() |
906 | 0 | { |
907 | 0 | nsIFrame* child = PrincipalChildList().FirstChild(); |
908 | 0 | if (child && child->GetContent() && |
909 | 0 | child->GetContent() == PresContext()->Document()->GetRootElement()) { |
910 | 0 | nsIFrame* childPrimary = child->GetContent()->GetPrimaryFrame(); |
911 | 0 | PropagateRootElementWritingMode(childPrimary->GetWritingMode()); |
912 | 0 | } |
913 | 0 | } |
914 | | |
915 | | #ifdef DEBUG_FRAME_DUMP |
916 | | nsresult |
917 | | nsCanvasFrame::GetFrameName(nsAString& aResult) const |
918 | | { |
919 | | return MakeFrameName(NS_LITERAL_STRING("Canvas"), aResult); |
920 | | } |
921 | | #endif |