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
4 : *
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/
9 : *
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
13 : * License.
14 : *
15 : * The Original Code is mozilla.org code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 1998
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : *
24 : * Alternatively, the contents of this file may be used under the terms of
25 : * either of the GNU General Public License Version 2 or later (the "GPL"),
26 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 : * in which case the provisions of the GPL or the LGPL are applicable instead
28 : * of those above. If you wish to allow use of your version of this file only
29 : * under the terms of either the GPL or the LGPL, and not to allow others to
30 : * use your version of this file under the terms of the MPL, indicate your
31 : * decision by deleting the provisions above and replace them with the notice
32 : * and other provisions required by the GPL or the LGPL. If you do not delete
33 : * the provisions above, a recipient may use your version of this file under
34 : * the terms of any one of the MPL, the GPL or the LGPL.
35 : *
36 : * ***** END LICENSE BLOCK ***** */
37 :
38 : /* rendering object that goes directly inside the document's scrollbars */
39 :
40 : #include "nsCanvasFrame.h"
41 : #include "nsIServiceManager.h"
42 : #include "nsHTMLParts.h"
43 : #include "nsContainerFrame.h"
44 : #include "nsCSSRendering.h"
45 : #include "nsPresContext.h"
46 : #include "nsStyleContext.h"
47 : #include "nsRenderingContext.h"
48 : #include "nsGUIEvent.h"
49 : #include "nsStyleConsts.h"
50 : #include "nsGkAtoms.h"
51 : #include "nsEventStateManager.h"
52 : #include "nsIPresShell.h"
53 : #include "nsIScrollPositionListener.h"
54 : #include "nsDisplayList.h"
55 : #include "nsCSSFrameConstructor.h"
56 : #include "nsFrameManager.h"
57 :
58 : // for focus
59 : #include "nsIScrollableFrame.h"
60 : #include "nsIDocShell.h"
61 :
62 : #ifdef DEBUG_rods
63 : //#define DEBUG_CANVAS_FOCUS
64 : #endif
65 :
66 :
67 : nsIFrame*
68 0 : NS_NewCanvasFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
69 : {
70 0 : return new (aPresShell) nsCanvasFrame(aContext);
71 : }
72 :
73 0 : NS_IMPL_FRAMEARENA_HELPERS(nsCanvasFrame)
74 :
75 0 : NS_QUERYFRAME_HEAD(nsCanvasFrame)
76 0 : NS_QUERYFRAME_ENTRY(nsCanvasFrame)
77 0 : NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)
78 :
79 : void
80 0 : nsCanvasFrame::DestroyFrom(nsIFrame* aDestructRoot)
81 : {
82 0 : DestroyAbsoluteFrames(aDestructRoot);
83 : nsIScrollableFrame* sf =
84 0 : PresContext()->GetPresShell()->GetRootScrollFrameAsScrollable();
85 0 : if (sf) {
86 0 : sf->RemoveScrollPositionListener(this);
87 : }
88 :
89 0 : nsContainerFrame::DestroyFrom(aDestructRoot);
90 0 : }
91 :
92 : void
93 0 : nsCanvasFrame::ScrollPositionWillChange(nscoord aX, nscoord aY)
94 : {
95 0 : if (mDoPaintFocus) {
96 0 : mDoPaintFocus = false;
97 0 : PresContext()->FrameManager()->GetRootFrame()->InvalidateFrameSubtree();
98 : }
99 0 : }
100 :
101 : NS_IMETHODIMP
102 0 : nsCanvasFrame::SetHasFocus(bool aHasFocus)
103 : {
104 0 : if (mDoPaintFocus != aHasFocus) {
105 0 : mDoPaintFocus = aHasFocus;
106 0 : PresContext()->FrameManager()->GetRootFrame()->InvalidateFrameSubtree();
107 :
108 0 : if (!mAddedScrollPositionListener) {
109 : nsIScrollableFrame* sf =
110 0 : PresContext()->GetPresShell()->GetRootScrollFrameAsScrollable();
111 0 : if (sf) {
112 0 : sf->AddScrollPositionListener(this);
113 0 : mAddedScrollPositionListener = true;
114 : }
115 : }
116 : }
117 0 : return NS_OK;
118 : }
119 :
120 : NS_IMETHODIMP
121 0 : nsCanvasFrame::SetInitialChildList(ChildListID aListID,
122 : nsFrameList& aChildList)
123 : {
124 0 : NS_ASSERTION(aListID != kPrincipalList ||
125 : aChildList.IsEmpty() || aChildList.OnlyChild(),
126 : "Primary child list can have at most one frame in it");
127 0 : return nsContainerFrame::SetInitialChildList(aListID, aChildList);
128 : }
129 :
130 : NS_IMETHODIMP
131 0 : nsCanvasFrame::AppendFrames(ChildListID aListID,
132 : nsFrameList& aFrameList)
133 : {
134 0 : NS_ASSERTION(aListID == kPrincipalList ||
135 : aListID == kAbsoluteList, "unexpected child list ID");
136 0 : NS_PRECONDITION(aListID != kAbsoluteList ||
137 : mFrames.IsEmpty(), "already have a child frame");
138 0 : if (aListID != kPrincipalList) {
139 : // We only support the Principal and Absolute child lists.
140 0 : return NS_ERROR_INVALID_ARG;
141 : }
142 :
143 0 : if (!mFrames.IsEmpty()) {
144 : // We only allow a single principal child frame.
145 0 : return NS_ERROR_INVALID_ARG;
146 : }
147 :
148 : // Insert the new frames
149 0 : NS_ASSERTION(aFrameList.FirstChild() == aFrameList.LastChild(),
150 : "Only one principal child frame allowed");
151 : #ifdef NS_DEBUG
152 0 : nsFrame::VerifyDirtyBitSet(aFrameList);
153 : #endif
154 0 : mFrames.AppendFrames(nsnull, aFrameList);
155 :
156 0 : PresContext()->PresShell()->
157 : FrameNeedsReflow(this, nsIPresShell::eTreeChange,
158 0 : NS_FRAME_HAS_DIRTY_CHILDREN);
159 :
160 0 : return NS_OK;
161 : }
162 :
163 : NS_IMETHODIMP
164 0 : nsCanvasFrame::InsertFrames(ChildListID aListID,
165 : nsIFrame* aPrevFrame,
166 : nsFrameList& aFrameList)
167 : {
168 : // Because we only support a single child frame inserting is the same
169 : // as appending
170 0 : NS_PRECONDITION(!aPrevFrame, "unexpected previous sibling frame");
171 0 : if (aPrevFrame)
172 0 : return NS_ERROR_UNEXPECTED;
173 :
174 0 : return AppendFrames(aListID, aFrameList);
175 : }
176 :
177 : NS_IMETHODIMP
178 0 : nsCanvasFrame::RemoveFrame(ChildListID aListID,
179 : nsIFrame* aOldFrame)
180 : {
181 0 : NS_ASSERTION(aListID == kPrincipalList ||
182 : aListID == kAbsoluteList, "unexpected child list ID");
183 0 : if (aListID != kPrincipalList || aListID != kAbsoluteList) {
184 : // We only support the Principal and Absolute child lists.
185 0 : return NS_ERROR_INVALID_ARG;
186 : }
187 :
188 0 : if (aOldFrame != mFrames.FirstChild())
189 0 : return NS_ERROR_FAILURE;
190 :
191 : // It's our one and only child frame
192 : // Damage the area occupied by the deleted frame
193 : // The child of the canvas probably can't have an outline, but why bother
194 : // thinking about that?
195 0 : Invalidate(aOldFrame->GetVisualOverflowRect() + aOldFrame->GetPosition());
196 :
197 : // Remove the frame and destroy it
198 0 : mFrames.DestroyFrame(aOldFrame);
199 :
200 0 : PresContext()->PresShell()->
201 : FrameNeedsReflow(this, nsIPresShell::eTreeChange,
202 0 : NS_FRAME_HAS_DIRTY_CHILDREN);
203 0 : return NS_OK;
204 : }
205 :
206 0 : nsRect nsCanvasFrame::CanvasArea() const
207 : {
208 : // Not clear which overflow rect we want here, but it probably doesn't
209 : // matter.
210 0 : nsRect result(GetVisualOverflowRect());
211 :
212 0 : nsIScrollableFrame *scrollableFrame = do_QueryFrame(GetParent());
213 0 : if (scrollableFrame) {
214 0 : nsRect portRect = scrollableFrame->GetScrollPortRect();
215 0 : result.UnionRect(result, nsRect(nsPoint(0, 0), portRect.Size()));
216 : }
217 : return result;
218 : }
219 :
220 : void
221 0 : nsDisplayCanvasBackground::Paint(nsDisplayListBuilder* aBuilder,
222 : nsRenderingContext* aCtx)
223 : {
224 0 : nsCanvasFrame* frame = static_cast<nsCanvasFrame*>(mFrame);
225 0 : nsPoint offset = ToReferenceFrame();
226 0 : nsRect bgClipRect = frame->CanvasArea() + offset;
227 :
228 0 : if (NS_GET_A(mExtraBackgroundColor) > 0) {
229 0 : aCtx->SetColor(mExtraBackgroundColor);
230 0 : aCtx->FillRect(bgClipRect);
231 : }
232 :
233 : nsCSSRendering::PaintBackground(mFrame->PresContext(), *aCtx, mFrame,
234 : mVisibleRect,
235 0 : nsRect(offset, mFrame->GetSize()),
236 : aBuilder->GetBackgroundPaintFlags(),
237 0 : &bgClipRect);
238 0 : }
239 :
240 : /**
241 : * A display item to paint the focus ring for the document.
242 : *
243 : * The only reason this can't use nsDisplayGeneric is overriding GetBounds.
244 : */
245 : class nsDisplayCanvasFocus : public nsDisplayItem {
246 : public:
247 0 : nsDisplayCanvasFocus(nsDisplayListBuilder* aBuilder, nsCanvasFrame *aFrame)
248 0 : : nsDisplayItem(aBuilder, aFrame)
249 : {
250 0 : MOZ_COUNT_CTOR(nsDisplayCanvasFocus);
251 0 : }
252 0 : virtual ~nsDisplayCanvasFocus() {
253 0 : MOZ_COUNT_DTOR(nsDisplayCanvasFocus);
254 0 : }
255 :
256 0 : virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder)
257 : {
258 : // This is an overestimate, but that's not a problem.
259 0 : nsCanvasFrame* frame = static_cast<nsCanvasFrame*>(mFrame);
260 0 : return frame->CanvasArea() + ToReferenceFrame();
261 : }
262 :
263 0 : virtual void Paint(nsDisplayListBuilder* aBuilder,
264 : nsRenderingContext* aCtx)
265 : {
266 0 : nsCanvasFrame* frame = static_cast<nsCanvasFrame*>(mFrame);
267 0 : frame->PaintFocus(*aCtx, ToReferenceFrame());
268 0 : }
269 :
270 0 : NS_DISPLAY_DECL_NAME("CanvasFocus", TYPE_CANVAS_FOCUS)
271 : };
272 :
273 : NS_IMETHODIMP
274 0 : nsCanvasFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
275 : const nsRect& aDirtyRect,
276 : const nsDisplayListSet& aLists)
277 : {
278 : nsresult rv;
279 :
280 0 : if (GetPrevInFlow()) {
281 0 : DisplayOverflowContainers(aBuilder, aDirtyRect, aLists);
282 : }
283 :
284 : // Force a background to be shown. We may have a background propagated to us,
285 : // in which case GetStyleBackground wouldn't have the right background
286 : // and the code in nsFrame::DisplayBorderBackgroundOutline might not give us
287 : // a background.
288 : // We don't have any border or outline, and our background draws over
289 : // the overflow area, so just add nsDisplayCanvasBackground instead of
290 : // calling DisplayBorderBackgroundOutline.
291 0 : if (IsVisibleForPainting(aBuilder)) {
292 : rv = aLists.BorderBackground()->AppendNewToTop(new (aBuilder)
293 0 : nsDisplayCanvasBackground(aBuilder, this));
294 0 : NS_ENSURE_SUCCESS(rv, rv);
295 : }
296 :
297 : nsIFrame* kid;
298 0 : for (kid = GetFirstPrincipalChild(); kid; kid = kid->GetNextSibling()) {
299 : // Put our child into its own pseudo-stack.
300 0 : rv = BuildDisplayListForChild(aBuilder, kid, aDirtyRect, aLists);
301 0 : NS_ENSURE_SUCCESS(rv, rv);
302 : }
303 :
304 : #ifdef DEBUG_CANVAS_FOCUS
305 : nsCOMPtr<nsIContent> focusContent;
306 : aPresContext->EventStateManager()->
307 : GetFocusedContent(getter_AddRefs(focusContent));
308 :
309 : bool hasFocus = false;
310 : nsCOMPtr<nsISupports> container;
311 : aPresContext->GetContainer(getter_AddRefs(container));
312 : nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(container));
313 : if (docShell) {
314 : docShell->GetHasFocus(&hasFocus);
315 : printf("%p - nsCanvasFrame::Paint R:%d,%d,%d,%d DR: %d,%d,%d,%d\n", this,
316 : mRect.x, mRect.y, mRect.width, mRect.height,
317 : aDirtyRect.x, aDirtyRect.y, aDirtyRect.width, aDirtyRect.height);
318 : }
319 : printf("%p - Focus: %s c: %p DoPaint:%s\n", docShell.get(), hasFocus?"Y":"N",
320 : focusContent.get(), mDoPaintFocus?"Y":"N");
321 : #endif
322 :
323 0 : if (!mDoPaintFocus)
324 0 : return NS_OK;
325 : // Only paint the focus if we're visible
326 0 : if (!GetStyleVisibility()->IsVisible())
327 0 : return NS_OK;
328 :
329 : return aLists.Outlines()->AppendNewToTop(new (aBuilder)
330 0 : nsDisplayCanvasFocus(aBuilder, this));
331 : }
332 :
333 : void
334 0 : nsCanvasFrame::PaintFocus(nsRenderingContext& aRenderingContext, nsPoint aPt)
335 : {
336 0 : nsRect focusRect(aPt, GetSize());
337 :
338 0 : nsIScrollableFrame *scrollableFrame = do_QueryFrame(GetParent());
339 0 : if (scrollableFrame) {
340 0 : nsRect portRect = scrollableFrame->GetScrollPortRect();
341 0 : focusRect.width = portRect.width;
342 0 : focusRect.height = portRect.height;
343 0 : focusRect.MoveBy(scrollableFrame->GetScrollPosition());
344 : }
345 :
346 : // XXX use the root frame foreground color, but should we find BODY frame
347 : // for HTML documents?
348 0 : nsIFrame* root = mFrames.FirstChild();
349 : const nsStyleColor* color =
350 0 : root ? root->GetStyleContext()->GetStyleColor() :
351 0 : mStyleContext->GetStyleColor();
352 0 : if (!color) {
353 0 : NS_ERROR("current color cannot be found");
354 : return;
355 : }
356 :
357 : nsCSSRendering::PaintFocus(PresContext(), aRenderingContext,
358 0 : focusRect, color->mColor);
359 : }
360 :
361 : /* virtual */ nscoord
362 0 : nsCanvasFrame::GetMinWidth(nsRenderingContext *aRenderingContext)
363 : {
364 : nscoord result;
365 0 : DISPLAY_MIN_WIDTH(this, result);
366 0 : if (mFrames.IsEmpty())
367 0 : result = 0;
368 : else
369 0 : result = mFrames.FirstChild()->GetMinWidth(aRenderingContext);
370 0 : return result;
371 : }
372 :
373 : /* virtual */ nscoord
374 0 : nsCanvasFrame::GetPrefWidth(nsRenderingContext *aRenderingContext)
375 : {
376 : nscoord result;
377 0 : DISPLAY_PREF_WIDTH(this, result);
378 0 : if (mFrames.IsEmpty())
379 0 : result = 0;
380 : else
381 0 : result = mFrames.FirstChild()->GetPrefWidth(aRenderingContext);
382 0 : return result;
383 : }
384 :
385 : NS_IMETHODIMP
386 0 : nsCanvasFrame::Reflow(nsPresContext* aPresContext,
387 : nsHTMLReflowMetrics& aDesiredSize,
388 : const nsHTMLReflowState& aReflowState,
389 : nsReflowStatus& aStatus)
390 : {
391 0 : DO_GLOBAL_REFLOW_COUNT("nsCanvasFrame");
392 0 : DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);
393 0 : NS_FRAME_TRACE_REFLOW_IN("nsCanvasFrame::Reflow");
394 :
395 : // Initialize OUT parameter
396 0 : aStatus = NS_FRAME_COMPLETE;
397 :
398 : nsCanvasFrame* prevCanvasFrame = static_cast<nsCanvasFrame*>
399 0 : (GetPrevInFlow());
400 0 : if (prevCanvasFrame) {
401 0 : nsAutoPtr<nsFrameList> overflow(prevCanvasFrame->StealOverflowFrames());
402 0 : if (overflow) {
403 0 : NS_ASSERTION(overflow->OnlyChild(),
404 : "must have doc root as canvas frame's only child");
405 0 : nsContainerFrame::ReparentFrameViewList(aPresContext, *overflow,
406 0 : prevCanvasFrame, this);
407 : // Prepend overflow to the our child list. There may already be
408 : // children placeholders for fixed-pos elements, which don't get
409 : // reflowed but must not be lost until the canvas frame is destroyed.
410 0 : mFrames.InsertFrames(this, nsnull, *overflow);
411 : }
412 : }
413 :
414 : // Set our size up front, since some parts of reflow depend on it
415 : // being already set. Note that the computed height may be
416 : // unconstrained; that's ok. Consumers should watch out for that.
417 0 : SetSize(nsSize(aReflowState.ComputedWidth(), aReflowState.ComputedHeight()));
418 :
419 : // Reflow our one and only normal child frame. It's either the root
420 : // element's frame or a placeholder for that frame, if the root element
421 : // is abs-pos or fixed-pos. We may have additional children which
422 : // are placeholders for continuations of fixed-pos content, but those
423 : // don't need to be reflowed. The normal child is always comes before
424 : // the fixed-pos placeholders, because we insert it at the start
425 : // of the child list, above.
426 0 : nsHTMLReflowMetrics kidDesiredSize;
427 0 : if (mFrames.IsEmpty()) {
428 : // We have no child frame, so return an empty size
429 0 : aDesiredSize.width = aDesiredSize.height = 0;
430 : } else {
431 0 : nsIFrame* kidFrame = mFrames.FirstChild();
432 0 : nsRect oldKidRect = kidFrame->GetRect();
433 0 : bool kidDirty = (kidFrame->GetStateBits() & NS_FRAME_IS_DIRTY) != 0;
434 :
435 : nsHTMLReflowState kidReflowState(aPresContext, aReflowState, kidFrame,
436 : nsSize(aReflowState.availableWidth,
437 0 : aReflowState.availableHeight));
438 :
439 0 : if (aReflowState.mFlags.mVResize &&
440 0 : (kidFrame->GetStateBits() & NS_FRAME_CONTAINS_RELATIVE_HEIGHT)) {
441 : // Tell our kid it's being vertically resized too. Bit of a
442 : // hack for framesets.
443 0 : kidReflowState.mFlags.mVResize = true;
444 : }
445 :
446 : nsPoint kidPt(kidReflowState.mComputedMargin.left,
447 0 : kidReflowState.mComputedMargin.top);
448 : // Apply CSS relative positioning
449 0 : const nsStyleDisplay* styleDisp = kidFrame->GetStyleDisplay();
450 0 : if (NS_STYLE_POSITION_RELATIVE == styleDisp->mPosition) {
451 : kidPt += nsPoint(kidReflowState.mComputedOffsets.left,
452 0 : kidReflowState.mComputedOffsets.top);
453 : }
454 :
455 : // Reflow the frame
456 : ReflowChild(kidFrame, aPresContext, kidDesiredSize, kidReflowState,
457 0 : kidPt.x, kidPt.y, 0, aStatus);
458 :
459 : // Complete the reflow and position and size the child frame
460 : FinishReflowChild(kidFrame, aPresContext, &kidReflowState, kidDesiredSize,
461 0 : kidPt.x, kidPt.y, 0);
462 :
463 0 : if (!NS_FRAME_IS_FULLY_COMPLETE(aStatus)) {
464 0 : nsIFrame* nextFrame = kidFrame->GetNextInFlow();
465 0 : NS_ASSERTION(nextFrame || aStatus & NS_FRAME_REFLOW_NEXTINFLOW,
466 : "If it's incomplete and has no nif yet, it must flag a nif reflow.");
467 0 : if (!nextFrame) {
468 : nsresult rv = aPresContext->PresShell()->FrameConstructor()->
469 0 : CreateContinuingFrame(aPresContext, kidFrame, this, &nextFrame);
470 0 : NS_ENSURE_SUCCESS(rv, rv);
471 0 : SetOverflowFrames(aPresContext, nsFrameList(nextFrame, nextFrame));
472 : // Root overflow containers will be normal children of
473 : // the canvas frame, but that's ok because there
474 : // aren't any other frames we need to isolate them from
475 : // during reflow.
476 : }
477 0 : if (NS_FRAME_OVERFLOW_IS_INCOMPLETE(aStatus)) {
478 0 : nextFrame->AddStateBits(NS_FRAME_IS_OVERFLOW_CONTAINER);
479 : }
480 : }
481 :
482 : // If the child frame was just inserted, then we're responsible for making sure
483 : // it repaints
484 0 : if (kidDirty) {
485 : // But we have a new child, which will affect our background, so
486 : // invalidate our whole rect.
487 : // Note: Even though we request to be sized to our child's size, our
488 : // scroll frame ensures that we are always the size of the viewport.
489 : // Also note: GetPosition() on a CanvasFrame is always going to return
490 : // (0, 0). We only want to invalidate GetRect() since Get*OverflowRect()
491 : // could also include overflow to our top and left (out of the viewport)
492 : // which doesn't need to be painted.
493 0 : nsIFrame* viewport = PresContext()->GetPresShell()->GetRootFrame();
494 0 : viewport->Invalidate(nsRect(nsPoint(0, 0), viewport->GetSize()));
495 : } else {
496 0 : nsRect newKidRect = kidFrame->GetRect();
497 0 : if (newKidRect.TopLeft() == oldKidRect.TopLeft()) {
498 0 : InvalidateRectDifference(oldKidRect, kidFrame->GetRect());
499 : } else {
500 0 : Invalidate(oldKidRect);
501 0 : Invalidate(newKidRect);
502 : }
503 : }
504 :
505 : // Return our desired size. Normally it's what we're told, but
506 : // sometimes we can be given an unconstrained height (when a window
507 : // is sizing-to-content), and we should compute our desired height.
508 0 : aDesiredSize.width = aReflowState.ComputedWidth();
509 0 : if (aReflowState.ComputedHeight() == NS_UNCONSTRAINEDSIZE) {
510 0 : aDesiredSize.height = kidFrame->GetRect().height +
511 0 : kidReflowState.mComputedMargin.TopBottom();
512 : } else {
513 0 : aDesiredSize.height = aReflowState.ComputedHeight();
514 : }
515 :
516 0 : aDesiredSize.SetOverflowAreasToDesiredBounds();
517 : aDesiredSize.mOverflowAreas.UnionWith(
518 0 : kidDesiredSize.mOverflowAreas + kidPt);
519 :
520 : // Handle invalidating fixed-attachment backgrounds propagated to the
521 : // canvas when the canvas size (and therefore the background positioning
522 : // area's size) changes. Such backgrounds are not invalidated in the
523 : // normal manner because the size of the original frame for that background
524 : // may not have changed.
525 : //
526 : // This isn't the right fix for this issue, taken more generally. In
527 : // particular, this doesn't handle fixed-attachment backgrounds that are *not*
528 : // propagated. If a layer with the characteristics tested for below exists
529 : // in a non-propagated background, we should invalidate the "corresponding"
530 : // frame (which subsumes this special case if defined broadly). For now,
531 : // however, this addresses the most common case. Given that this behavior has
532 : // long been broken (non-zero percent background-size may be a new instance,
533 : // but non-zero percent background-position is longstanding), we defer a
534 : // fully correct fix until later.
535 0 : if (nsSize(aDesiredSize.width, aDesiredSize.height) != GetSize()) {
536 : nsIFrame* rootElementFrame =
537 0 : aPresContext->PresShell()->FrameConstructor()->GetRootElementStyleFrame();
538 : nsStyleContext* bgSC =
539 0 : nsCSSRendering::FindCanvasBackground(this, rootElementFrame);
540 0 : const nsStyleBackground* bg = bgSC->GetStyleBackground();
541 0 : if (!bg->IsTransparent()) {
542 0 : NS_FOR_VISIBLE_BACKGROUND_LAYERS_BACK_TO_FRONT(i, bg) {
543 0 : const nsStyleBackground::Layer& layer = bg->mLayers[i];
544 0 : if (layer.mAttachment == NS_STYLE_BG_ATTACHMENT_FIXED &&
545 0 : layer.RenderingMightDependOnFrameSize()) {
546 0 : Invalidate(nsRect(nsPoint(0, 0), GetSize()));
547 0 : break;
548 : }
549 : }
550 : }
551 : }
552 : }
553 :
554 0 : if (prevCanvasFrame) {
555 : ReflowOverflowContainerChildren(aPresContext, aReflowState,
556 : aDesiredSize.mOverflowAreas, 0,
557 0 : aStatus);
558 : }
559 :
560 0 : FinishReflowWithAbsoluteFrames(aPresContext, aDesiredSize, aReflowState, aStatus);
561 :
562 0 : NS_FRAME_TRACE_REFLOW_OUT("nsCanvasFrame::Reflow", aStatus);
563 0 : NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
564 0 : return NS_OK;
565 : }
566 :
567 : PRIntn
568 0 : nsCanvasFrame::GetSkipSides() const
569 : {
570 0 : return 0;
571 : }
572 :
573 : nsIAtom*
574 0 : nsCanvasFrame::GetType() const
575 : {
576 0 : return nsGkAtoms::canvasFrame;
577 : }
578 :
579 : NS_IMETHODIMP
580 0 : nsCanvasFrame::GetContentForEvent(nsEvent* aEvent,
581 : nsIContent** aContent)
582 : {
583 0 : NS_ENSURE_ARG_POINTER(aContent);
584 : nsresult rv = nsFrame::GetContentForEvent(aEvent,
585 0 : aContent);
586 0 : if (NS_FAILED(rv) || !*aContent) {
587 0 : nsIFrame* kid = mFrames.FirstChild();
588 0 : if (kid) {
589 : rv = kid->GetContentForEvent(aEvent,
590 0 : aContent);
591 : }
592 : }
593 :
594 0 : return rv;
595 : }
596 :
597 : #ifdef DEBUG
598 : NS_IMETHODIMP
599 0 : nsCanvasFrame::GetFrameName(nsAString& aResult) const
600 : {
601 0 : return MakeFrameName(NS_LITERAL_STRING("Canvas"), aResult);
602 : }
603 : #endif
|