1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : // vim:cindent:ts=2:et:sw=2:
3 : /* ***** BEGIN LICENSE BLOCK *****
4 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 : *
6 : * The contents of this file are subject to the Mozilla Public License Version
7 : * 1.1 (the "License"); you may not use this file except in compliance with
8 : * the License. You may obtain a copy of the License at
9 : * http://www.mozilla.org/MPL/
10 : *
11 : * Software distributed under the License is distributed on an "AS IS" basis,
12 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 : * for the specific language governing rights and limitations under the
14 : * License.
15 : *
16 : * The Original Code is mozilla.org code.
17 : *
18 : * The Initial Developer of the Original Code is
19 : * Netscape Communications Corporation.
20 : * Portions created by the Initial Developer are Copyright (C) 1998
21 : * the Initial Developer. All Rights Reserved.
22 : *
23 : * Contributor(s):
24 : * Pierre Phaneuf <pp@ludusdesign.com>
25 : * Uri Bernstein <uriber@gmail.com>
26 : * Eli Friedman <sharparrow1@yahoo.com>
27 : * Mats Palmgren <matspal@gmail.com>
28 : *
29 : * Alternatively, the contents of this file may be used under the terms of
30 : * either of the GNU General Public License Version 2 or later (the "GPL"),
31 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
32 : * in which case the provisions of the GPL or the LGPL are applicable instead
33 : * of those above. If you wish to allow use of your version of this file only
34 : * under the terms of either the GPL or the LGPL, and not to allow others to
35 : * use your version of this file under the terms of the MPL, indicate your
36 : * decision by deleting the provisions above and replace them with the notice
37 : * and other provisions required by the GPL or the LGPL. If you do not delete
38 : * the provisions above, a recipient may use your version of this file under
39 : * the terms of any one of the MPL, the GPL or the LGPL.
40 : *
41 : * ***** END LICENSE BLOCK ***** */
42 :
43 : /* base class of all rendering objects */
44 :
45 : #include "mozilla/Attributes.h"
46 : #include "mozilla/Util.h"
47 :
48 : #include "nsCOMPtr.h"
49 : #include "nsFrame.h"
50 : #include "nsFrameList.h"
51 : #include "nsPlaceholderFrame.h"
52 : #include "nsLineLayout.h"
53 : #include "nsIContent.h"
54 : #include "nsContentUtils.h"
55 : #include "nsIAtom.h"
56 : #include "nsString.h"
57 : #include "nsReadableUtils.h"
58 : #include "nsStyleContext.h"
59 : #include "nsIView.h"
60 : #include "nsIViewManager.h"
61 : #include "nsIScrollableFrame.h"
62 : #include "nsPresContext.h"
63 : #include "nsCRT.h"
64 : #include "nsGUIEvent.h"
65 : #include "nsIDOMEvent.h"
66 : #include "nsAsyncDOMEvent.h"
67 : #include "nsStyleConsts.h"
68 : #include "nsIPresShell.h"
69 : #include "prlog.h"
70 : #include "prprf.h"
71 : #include <stdarg.h>
72 : #include "nsFrameManager.h"
73 : #include "nsCSSRendering.h"
74 : #include "nsLayoutUtils.h"
75 : #ifdef ACCESSIBILITY
76 : #include "nsIAccessible.h"
77 : #endif
78 :
79 : #include "nsIDOMNode.h"
80 : #include "nsIEditorDocShell.h"
81 : #include "nsEventStateManager.h"
82 : #include "nsISelection.h"
83 : #include "nsISelectionPrivate.h"
84 : #include "nsFrameSelection.h"
85 : #include "nsHTMLParts.h"
86 : #include "nsGkAtoms.h"
87 : #include "nsCSSAnonBoxes.h"
88 : #include "nsCSSPseudoElements.h"
89 : #include "nsIHTMLContentSink.h"
90 : #include "nsCSSFrameConstructor.h"
91 :
92 : #include "nsFrameTraversal.h"
93 : #include "nsStyleChangeList.h"
94 : #include "nsIDOMRange.h"
95 : #include "nsRange.h"
96 : #include "nsITableLayout.h" //selection necessity
97 : #include "nsITableCellLayout.h"// "
98 : #include "nsITextControlFrame.h"
99 : #include "nsINameSpaceManager.h"
100 : #include "nsIPercentHeightObserver.h"
101 : #include "nsStyleStructInlines.h"
102 :
103 : #ifdef IBMBIDI
104 : #include "nsBidiPresUtils.h"
105 : #endif
106 :
107 : // For triple-click pref
108 : #include "nsIServiceManager.h"
109 : #include "imgIContainer.h"
110 : #include "imgIRequest.h"
111 : #include "nsLayoutCID.h"
112 : #include "nsUnicharUtils.h"
113 : #include "nsLayoutErrors.h"
114 : #include "nsContentErrors.h"
115 : #include "nsContainerFrame.h"
116 : #include "nsBoxLayoutState.h"
117 : #include "nsBlockFrame.h"
118 : #include "nsDisplayList.h"
119 : #include "nsIObjectLoadingContent.h"
120 : #include "nsExpirationTracker.h"
121 : #include "nsSVGIntegrationUtils.h"
122 : #include "nsSVGEffects.h"
123 : #include "nsChangeHint.h"
124 : #include "nsDeckFrame.h"
125 :
126 : #include "gfxContext.h"
127 : #include "CSSCalc.h"
128 : #include "nsAbsoluteContainingBlock.h"
129 :
130 : #include "mozilla/Preferences.h"
131 : #include "mozilla/LookAndFeel.h"
132 :
133 : using namespace mozilla;
134 : using namespace mozilla::layers;
135 : using namespace mozilla::layout;
136 :
137 : // Struct containing cached metrics for box-wrapped frames.
138 : struct nsBoxLayoutMetrics
139 0 : {
140 : nsSize mPrefSize;
141 : nsSize mMinSize;
142 : nsSize mMaxSize;
143 :
144 : nsSize mBlockMinSize;
145 : nsSize mBlockPrefSize;
146 : nscoord mBlockAscent;
147 :
148 : nscoord mFlex;
149 : nscoord mAscent;
150 :
151 : nsSize mLastSize;
152 : };
153 :
154 : struct nsContentAndOffset
155 : {
156 : nsIContent* mContent;
157 : PRInt32 mOffset;
158 : };
159 :
160 : // Some Misc #defines
161 : #define SELECTION_DEBUG 0
162 : #define FORCE_SELECTION_UPDATE 1
163 : #define CALC_DEBUG 0
164 :
165 :
166 : #include "nsILineIterator.h"
167 :
168 : //non Hack prototypes
169 : #if 0
170 : static void RefreshContentFrames(nsPresContext* aPresContext, nsIContent * aStartContent, nsIContent * aEndContent);
171 : #endif
172 :
173 : #include "prenv.h"
174 :
175 : // Formerly the nsIFrameDebug interface
176 :
177 : #ifdef NS_DEBUG
178 : static bool gShowFrameBorders = false;
179 :
180 0 : void nsFrame::ShowFrameBorders(bool aEnable)
181 : {
182 0 : gShowFrameBorders = aEnable;
183 0 : }
184 :
185 0 : bool nsFrame::GetShowFrameBorders()
186 : {
187 0 : return gShowFrameBorders;
188 : }
189 :
190 : static bool gShowEventTargetFrameBorder = false;
191 :
192 0 : void nsFrame::ShowEventTargetFrameBorder(bool aEnable)
193 : {
194 0 : gShowEventTargetFrameBorder = aEnable;
195 0 : }
196 :
197 0 : bool nsFrame::GetShowEventTargetFrameBorder()
198 : {
199 0 : return gShowEventTargetFrameBorder;
200 : }
201 :
202 : /**
203 : * Note: the log module is created during library initialization which
204 : * means that you cannot perform logging before then.
205 : */
206 : static PRLogModuleInfo* gLogModule;
207 :
208 : static PRLogModuleInfo* gStyleVerifyTreeLogModuleInfo;
209 :
210 : static PRUint32 gStyleVerifyTreeEnable = 0x55;
211 :
212 : bool
213 0 : nsFrame::GetVerifyStyleTreeEnable()
214 : {
215 0 : if (gStyleVerifyTreeEnable == 0x55) {
216 0 : if (nsnull == gStyleVerifyTreeLogModuleInfo) {
217 0 : gStyleVerifyTreeLogModuleInfo = PR_NewLogModule("styleverifytree");
218 0 : gStyleVerifyTreeEnable = 0 != gStyleVerifyTreeLogModuleInfo->level;
219 : }
220 : }
221 0 : return gStyleVerifyTreeEnable;
222 : }
223 :
224 : void
225 0 : nsFrame::SetVerifyStyleTreeEnable(bool aEnabled)
226 : {
227 0 : gStyleVerifyTreeEnable = aEnabled;
228 0 : }
229 :
230 : PRLogModuleInfo*
231 0 : nsFrame::GetLogModuleInfo()
232 : {
233 0 : if (nsnull == gLogModule) {
234 0 : gLogModule = PR_NewLogModule("frame");
235 : }
236 0 : return gLogModule;
237 : }
238 :
239 : void
240 0 : nsFrame::DumpFrameTree(nsIFrame* aFrame)
241 : {
242 0 : RootFrameList(aFrame->PresContext(), stdout, 0);
243 0 : }
244 :
245 : void
246 0 : nsFrame::RootFrameList(nsPresContext* aPresContext, FILE* out, PRInt32 aIndent)
247 : {
248 0 : if (!aPresContext || !out)
249 0 : return;
250 :
251 0 : nsIPresShell *shell = aPresContext->GetPresShell();
252 0 : if (shell) {
253 0 : nsIFrame* frame = shell->FrameManager()->GetRootFrame();
254 0 : if(frame) {
255 0 : frame->List(out, aIndent);
256 : }
257 : }
258 : }
259 : #endif
260 :
261 : static void
262 0 : DestroyAbsoluteContainingBlock(void* aPropertyValue)
263 : {
264 0 : delete static_cast<nsAbsoluteContainingBlock*>(aPropertyValue);
265 0 : }
266 :
267 0 : NS_DECLARE_FRAME_PROPERTY(AbsoluteContainingBlockProperty, DestroyAbsoluteContainingBlock)
268 :
269 : bool
270 0 : nsIFrame::HasAbsolutelyPositionedChildren() const {
271 0 : return IsAbsoluteContainer() && GetAbsoluteContainingBlock()->HasAbsoluteFrames();
272 : }
273 :
274 : nsAbsoluteContainingBlock*
275 0 : nsIFrame::GetAbsoluteContainingBlock() const {
276 0 : NS_ASSERTION(IsAbsoluteContainer(), "The frame is not marked as an abspos container correctly");
277 : nsAbsoluteContainingBlock* absCB = static_cast<nsAbsoluteContainingBlock*>
278 0 : (Properties().Get(AbsoluteContainingBlockProperty()));
279 0 : NS_ASSERTION(absCB, "The frame is marked as an abspos container but doesn't have the property");
280 0 : return absCB;
281 : }
282 :
283 : void
284 0 : nsIFrame::MarkAsAbsoluteContainingBlock() {
285 0 : AddStateBits(NS_FRAME_HAS_ABSPOS_CHILDREN);
286 0 : Properties().Set(AbsoluteContainingBlockProperty(), new nsAbsoluteContainingBlock(GetAbsoluteListID()));
287 0 : }
288 :
289 : bool
290 0 : nsIFrame::CheckAndClearPaintedState()
291 : {
292 0 : bool result = (GetStateBits() & NS_FRAME_PAINTED_THEBES);
293 0 : RemoveStateBits(NS_FRAME_PAINTED_THEBES);
294 :
295 0 : nsIFrame::ChildListIterator lists(this);
296 0 : for (; !lists.IsDone(); lists.Next()) {
297 0 : nsFrameList::Enumerator childFrames(lists.CurrentList());
298 0 : for (; !childFrames.AtEnd(); childFrames.Next()) {
299 0 : nsIFrame* child = childFrames.get();
300 0 : if (child->CheckAndClearPaintedState()) {
301 0 : result = true;
302 : }
303 : }
304 : }
305 0 : return result;
306 : }
307 :
308 : bool
309 0 : nsIFrame::IsVisibleConsideringAncestors(PRUint32 aFlags) const
310 : {
311 0 : if (!GetStyleVisibility()->IsVisible()) {
312 0 : return false;
313 : }
314 :
315 0 : const nsIFrame* frame = this;
316 0 : while (frame) {
317 0 : nsIView* view = frame->GetView();
318 0 : if (view && view->GetVisibility() == nsViewVisibility_kHide)
319 0 : return false;
320 :
321 0 : nsIFrame* parent = frame->GetParent();
322 0 : nsDeckFrame* deck = do_QueryFrame(parent);
323 0 : if (deck) {
324 0 : if (deck->GetSelectedBox() != frame)
325 0 : return false;
326 : }
327 :
328 0 : if (parent) {
329 0 : frame = parent;
330 : } else {
331 0 : parent = nsLayoutUtils::GetCrossDocParentFrame(frame);
332 0 : if (!parent)
333 0 : break;
334 :
335 0 : if ((aFlags & nsIFrame::VISIBILITY_CROSS_CHROME_CONTENT_BOUNDARY) == 0 &&
336 0 : parent->PresContext()->IsChrome() && !frame->PresContext()->IsChrome()) {
337 0 : break;
338 : }
339 :
340 0 : if (!parent->GetStyleVisibility()->IsVisible())
341 0 : return false;
342 :
343 0 : frame = parent;
344 : }
345 : }
346 :
347 0 : return true;
348 : }
349 :
350 : static bool ApplyOverflowClipping(nsDisplayListBuilder* aBuilder,
351 : const nsIFrame* aFrame,
352 : const nsStyleDisplay* aDisp,
353 : nsRect* aRect);
354 :
355 : static bool ApplyClipPropClipping(nsDisplayListBuilder* aBuilder,
356 : const nsStyleDisplay* aDisp,
357 : const nsIFrame* aFrame,
358 : nsRect* aRect);
359 :
360 : void
361 0 : NS_MergeReflowStatusInto(nsReflowStatus* aPrimary, nsReflowStatus aSecondary)
362 : {
363 : *aPrimary |= aSecondary &
364 : (NS_FRAME_NOT_COMPLETE | NS_FRAME_OVERFLOW_INCOMPLETE |
365 0 : NS_FRAME_TRUNCATED | NS_FRAME_REFLOW_NEXTINFLOW);
366 0 : if (*aPrimary & NS_FRAME_NOT_COMPLETE) {
367 0 : *aPrimary &= ~NS_FRAME_OVERFLOW_INCOMPLETE;
368 : }
369 0 : }
370 :
371 : void
372 2928 : nsWeakFrame::InitInternal(nsIFrame* aFrame)
373 : {
374 2928 : Clear(mFrame ? mFrame->PresContext()->GetPresShell() : nsnull);
375 2928 : mFrame = aFrame;
376 2928 : if (mFrame) {
377 0 : nsIPresShell* shell = mFrame->PresContext()->GetPresShell();
378 0 : NS_WARN_IF_FALSE(shell, "Null PresShell in nsWeakFrame!");
379 0 : if (shell) {
380 0 : shell->AddWeakFrame(this);
381 : } else {
382 0 : mFrame = nsnull;
383 : }
384 : }
385 2928 : }
386 :
387 : nsIFrame*
388 0 : NS_NewEmptyFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
389 : {
390 0 : return new (aPresShell) nsFrame(aContext);
391 : }
392 :
393 0 : nsFrame::nsFrame(nsStyleContext* aContext)
394 : {
395 0 : MOZ_COUNT_CTOR(nsFrame);
396 :
397 0 : mState = NS_FRAME_FIRST_REFLOW | NS_FRAME_IS_DIRTY;
398 0 : mStyleContext = aContext;
399 0 : mStyleContext->AddRef();
400 0 : }
401 :
402 0 : nsFrame::~nsFrame()
403 : {
404 0 : MOZ_COUNT_DTOR(nsFrame);
405 :
406 0 : NS_IF_RELEASE(mContent);
407 0 : if (mStyleContext)
408 0 : mStyleContext->Release();
409 0 : }
410 :
411 0 : NS_IMPL_FRAMEARENA_HELPERS(nsFrame)
412 :
413 : // Dummy operator delete. Will never be called, but must be defined
414 : // to satisfy some C++ ABIs.
415 : void
416 0 : nsFrame::operator delete(void *, size_t)
417 : {
418 0 : NS_RUNTIMEABORT("nsFrame::operator delete should never be called");
419 0 : }
420 :
421 0 : NS_QUERYFRAME_HEAD(nsFrame)
422 0 : NS_QUERYFRAME_ENTRY(nsIFrame)
423 0 : NS_QUERYFRAME_TAIL_INHERITANCE_ROOT
424 :
425 : /////////////////////////////////////////////////////////////////////////////
426 : // nsIFrame
427 :
428 : static bool
429 0 : IsFontSizeInflationContainer(nsIFrame* aFrame,
430 : const nsStyleDisplay* aStyleDisplay)
431 : {
432 : /*
433 : * Font size inflation is built around the idea that we're inflating
434 : * the fonts for a pan-and-zoom UI so that when the user scales up a
435 : * block or other container to fill the width of the device, the fonts
436 : * will be readable. To do this, we need to pick what counts as a
437 : * container.
438 : *
439 : * From a code perspective, the only hard requirement is that frames
440 : * that are line participants
441 : * (nsIFrame::IsFrameOfType(nsIFrame::eLineParticipant)) are never
442 : * containers, since line layout assumes that the inflation is
443 : * consistent within a line.
444 : *
445 : * This is not an imposition, since we obviously want a bunch of text
446 : * (possibly with inline elements) flowing within a block to count the
447 : * block (or higher) as its container.
448 : *
449 : * We also want form controls, including the text in the anonymous
450 : * content inside of them, to match each other and the text next to
451 : * them, so they and their anonymous content should also not be a
452 : * container.
453 : *
454 : * However, because we can't reliably compute sizes across XUL during
455 : * reflow, any XUL frame with a XUL parent is always a container.
456 : *
457 : * There are contexts where it would be nice if some blocks didn't
458 : * count as a container, so that, for example, an indented quotation
459 : * didn't end up with a smaller font size. However, it's hard to
460 : * distinguish these situations where we really do want the indented
461 : * thing to count as a container, so we don't try, and blocks are
462 : * always containers.
463 : */
464 0 : nsIContent *content = aFrame->GetContent();
465 : bool isInline = (aStyleDisplay->mDisplay == NS_STYLE_DISPLAY_INLINE ||
466 0 : (aStyleDisplay->IsFloating() &&
467 0 : aFrame->GetType() == nsGkAtoms::letterFrame) ||
468 : // Given multiple frames for the same node, only the
469 : // outer one should be considered a container.
470 : // (Important, e.g., for nsSelectsAreaFrame.)
471 0 : (aFrame->GetParent() &&
472 0 : aFrame->GetParent()->GetContent() == content) ||
473 0 : (content && (content->IsHTML(nsGkAtoms::option) ||
474 0 : content->IsHTML(nsGkAtoms::optgroup) ||
475 0 : content->IsInNativeAnonymousSubtree()))) &&
476 0 : !(aFrame->IsBoxFrame() && aFrame->GetParent() &&
477 0 : aFrame->GetParent()->IsBoxFrame());
478 0 : NS_ASSERTION(!aFrame->IsFrameOfType(nsIFrame::eLineParticipant) ||
479 : isInline ||
480 : // br frames and mathml frames report being line
481 : // participants even when their position or display is
482 : // set
483 : aFrame->GetType() == nsGkAtoms::brFrame ||
484 : aFrame->IsFrameOfType(nsIFrame::eMathML),
485 : "line participants must not be containers");
486 0 : NS_ASSERTION(aFrame->GetType() != nsGkAtoms::bulletFrame || isInline,
487 : "bullets should not be containers");
488 0 : return !isInline;
489 : }
490 :
491 : NS_IMETHODIMP
492 0 : nsFrame::Init(nsIContent* aContent,
493 : nsIFrame* aParent,
494 : nsIFrame* aPrevInFlow)
495 : {
496 0 : NS_PRECONDITION(!mContent, "Double-initing a frame?");
497 0 : NS_ASSERTION(IsFrameOfType(eDEBUGAllFrames) &&
498 : !IsFrameOfType(eDEBUGNoFrames),
499 : "IsFrameOfType implementation that doesn't call base class");
500 :
501 0 : mContent = aContent;
502 0 : mParent = aParent;
503 :
504 0 : if (aContent) {
505 0 : NS_ADDREF(aContent);
506 : }
507 :
508 0 : if (aPrevInFlow) {
509 : // Make sure the general flags bits are the same
510 0 : nsFrameState state = aPrevInFlow->GetStateBits();
511 :
512 : // Make bits that are currently off (see constructor) the same:
513 : mState |= state & (NS_FRAME_INDEPENDENT_SELECTION |
514 : NS_FRAME_IS_SPECIAL |
515 0 : NS_FRAME_MAY_BE_TRANSFORMED);
516 : }
517 0 : if (mParent) {
518 0 : nsFrameState state = mParent->GetStateBits();
519 :
520 : // Make bits that are currently off (see constructor) the same:
521 : mState |= state & (NS_FRAME_INDEPENDENT_SELECTION |
522 0 : NS_FRAME_GENERATED_CONTENT);
523 : }
524 0 : const nsStyleDisplay *disp = GetStyleDisplay();
525 0 : if (disp->HasTransform()) {
526 : // The frame gets reconstructed if we toggle the -moz-transform
527 : // property, so we can set this bit here and then ignore it.
528 0 : mState |= NS_FRAME_MAY_BE_TRANSFORMED;
529 : }
530 :
531 0 : if (nsLayoutUtils::FontSizeInflationEnabled(PresContext())
532 : #ifdef DEBUG
533 : // We have assertions that check inflation invariants even when
534 : // font size inflation is not enabled.
535 : || true
536 : #endif
537 : ) {
538 0 : if (IsFontSizeInflationContainer(this, disp)) {
539 0 : mState |= NS_FRAME_FONT_INFLATION_CONTAINER;
540 : }
541 : }
542 :
543 0 : DidSetStyleContext(nsnull);
544 :
545 0 : if (IsBoxWrapped())
546 0 : InitBoxMetrics(false);
547 :
548 0 : return NS_OK;
549 : }
550 :
551 0 : NS_IMETHODIMP nsFrame::SetInitialChildList(ChildListID aListID,
552 : nsFrameList& aChildList)
553 : {
554 : // XXX This shouldn't be getting called at all, but currently is for backwards
555 : // compatility reasons...
556 : #if 0
557 : NS_ERROR("not a container");
558 : return NS_ERROR_UNEXPECTED;
559 : #else
560 0 : NS_ASSERTION(aChildList.IsEmpty(), "not a container");
561 0 : return NS_OK;
562 : #endif
563 : }
564 :
565 : NS_IMETHODIMP
566 0 : nsFrame::AppendFrames(ChildListID aListID,
567 : nsFrameList& aFrameList)
568 : {
569 0 : NS_PRECONDITION(false, "not a container");
570 0 : return NS_ERROR_UNEXPECTED;
571 : }
572 :
573 : NS_IMETHODIMP
574 0 : nsFrame::InsertFrames(ChildListID aListID,
575 : nsIFrame* aPrevFrame,
576 : nsFrameList& aFrameList)
577 : {
578 0 : NS_PRECONDITION(false, "not a container");
579 0 : return NS_ERROR_UNEXPECTED;
580 : }
581 :
582 : NS_IMETHODIMP
583 0 : nsFrame::RemoveFrame(ChildListID aListID,
584 : nsIFrame* aOldFrame)
585 : {
586 0 : NS_PRECONDITION(false, "not a container");
587 0 : return NS_ERROR_UNEXPECTED;
588 : }
589 :
590 : void
591 0 : nsFrame::DestroyFrom(nsIFrame* aDestructRoot)
592 : {
593 0 : NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
594 : "destroy called on frame while scripts not blocked");
595 0 : NS_ASSERTION(!GetNextSibling() && !GetPrevSibling(),
596 : "Frames should be removed before destruction.");
597 0 : NS_ASSERTION(aDestructRoot, "Must specify destruct root");
598 :
599 0 : nsSVGEffects::InvalidateDirectRenderingObservers(this);
600 :
601 : // Get the view pointer now before the frame properties disappear
602 : // when we call NotifyDestroyingFrame()
603 0 : nsIView* view = GetView();
604 0 : nsPresContext* presContext = PresContext();
605 :
606 0 : nsIPresShell *shell = presContext->GetPresShell();
607 0 : if (mState & NS_FRAME_OUT_OF_FLOW) {
608 : nsPlaceholderFrame* placeholder =
609 0 : shell->FrameManager()->GetPlaceholderFrameFor(this);
610 0 : NS_ASSERTION(!placeholder || (aDestructRoot != this),
611 : "Don't call Destroy() on OOFs, call Destroy() on the placeholder.");
612 0 : NS_ASSERTION(!placeholder ||
613 : nsLayoutUtils::IsProperAncestorFrame(aDestructRoot, placeholder),
614 : "Placeholder relationship should have been torn down already; "
615 : "this might mean we have a stray placeholder in the tree.");
616 0 : if (placeholder) {
617 0 : shell->FrameManager()->UnregisterPlaceholderFrame(placeholder);
618 0 : placeholder->SetOutOfFlowFrame(nsnull);
619 : }
620 : }
621 :
622 : // If we have any IB split special siblings, clear their references to us.
623 : // (Note: This has to happen before we call shell->NotifyDestroyingFrame,
624 : // because that clears our Properties() table.)
625 0 : if (mState & NS_FRAME_IS_SPECIAL) {
626 : // Delete previous sibling's reference to me.
627 : nsIFrame* prevSib = static_cast<nsIFrame*>
628 0 : (Properties().Get(nsIFrame::IBSplitSpecialPrevSibling()));
629 0 : if (prevSib) {
630 0 : NS_WARN_IF_FALSE(this ==
631 : prevSib->Properties().Get(nsIFrame::IBSplitSpecialSibling()),
632 : "IB sibling chain is inconsistent");
633 0 : prevSib->Properties().Delete(nsIFrame::IBSplitSpecialSibling());
634 : }
635 :
636 : // Delete next sibling's reference to me.
637 : nsIFrame* nextSib = static_cast<nsIFrame*>
638 0 : (Properties().Get(nsIFrame::IBSplitSpecialSibling()));
639 0 : if (nextSib) {
640 0 : NS_WARN_IF_FALSE(this ==
641 : nextSib->Properties().Get(nsIFrame::IBSplitSpecialPrevSibling()),
642 : "IB sibling chain is inconsistent");
643 0 : nextSib->Properties().Delete(nsIFrame::IBSplitSpecialPrevSibling());
644 : }
645 : }
646 :
647 0 : shell->NotifyDestroyingFrame(this);
648 :
649 0 : if (mState & NS_FRAME_EXTERNAL_REFERENCE) {
650 0 : shell->ClearFrameRefs(this);
651 : }
652 :
653 0 : if (view) {
654 : // Break association between view and frame
655 0 : view->SetFrame(nsnull);
656 :
657 : // Destroy the view
658 0 : view->Destroy();
659 : }
660 :
661 : // Make sure that our deleted frame can't be returned from GetPrimaryFrame()
662 0 : if (mContent && mContent->GetPrimaryFrame() == this) {
663 0 : mContent->SetPrimaryFrame(nsnull);
664 : }
665 :
666 : // Must retrieve the object ID before calling destructors, so the
667 : // vtable is still valid.
668 : //
669 : // Note to future tweakers: having the method that returns the
670 : // object size call the destructor will not avoid an indirect call;
671 : // the compiler cannot devirtualize the call to the destructor even
672 : // if it's from a method defined in the same class.
673 :
674 0 : nsQueryFrame::FrameIID id = GetFrameId();
675 0 : this->~nsFrame();
676 :
677 : // Now that we're totally cleaned out, we need to add ourselves to
678 : // the presshell's recycler.
679 0 : shell->FreeFrame(id, this);
680 0 : }
681 :
682 : NS_IMETHODIMP
683 0 : nsFrame::GetOffsets(PRInt32 &aStart, PRInt32 &aEnd) const
684 : {
685 0 : aStart = 0;
686 0 : aEnd = 0;
687 0 : return NS_OK;
688 : }
689 :
690 : static bool
691 0 : EqualImages(imgIRequest *aOldImage, imgIRequest *aNewImage)
692 : {
693 0 : if (aOldImage == aNewImage)
694 0 : return true;
695 :
696 0 : if (!aOldImage || !aNewImage)
697 0 : return false;
698 :
699 0 : nsCOMPtr<nsIURI> oldURI, newURI;
700 0 : aOldImage->GetURI(getter_AddRefs(oldURI));
701 0 : aNewImage->GetURI(getter_AddRefs(newURI));
702 : bool equal;
703 0 : return NS_SUCCEEDED(oldURI->Equals(newURI, &equal)) && equal;
704 : }
705 :
706 : // Subclass hook for style post processing
707 : /* virtual */ void
708 0 : nsFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext)
709 : {
710 0 : if (aOldStyleContext) {
711 : // If the old context had a background image image and new context
712 : // does not have the same image, clear the image load notifier
713 : // (which keeps the image loading, if it still is) for the frame.
714 : // We want to do this conservatively because some frames paint their
715 : // backgrounds from some other frame's style data, and we don't want
716 : // to clear those notifiers unless we have to. (They'll be reset
717 : // when we paint, although we could miss a notification in that
718 : // interval.)
719 0 : const nsStyleBackground *oldBG = aOldStyleContext->GetStyleBackground();
720 0 : const nsStyleBackground *newBG = GetStyleBackground();
721 0 : NS_FOR_VISIBLE_BACKGROUND_LAYERS_BACK_TO_FRONT(i, oldBG) {
722 0 : if (i >= newBG->mImageCount ||
723 0 : oldBG->mLayers[i].mImage != newBG->mLayers[i].mImage) {
724 : // stop the image loading for the frame, the image has changed
725 : PresContext()->SetImageLoaders(this,
726 0 : nsPresContext::BACKGROUND_IMAGE, nsnull);
727 0 : break;
728 : }
729 : }
730 :
731 : // If we detect a change on margin, padding or border, we store the old
732 : // values on the frame itself between now and reflow, so if someone
733 : // calls GetUsed(Margin|Border|Padding)() before the next reflow, we
734 : // can give an accurate answer.
735 : // We don't want to set the property if one already exists.
736 0 : FrameProperties props = Properties();
737 0 : nsMargin oldValue(0, 0, 0, 0);
738 0 : nsMargin newValue(0, 0, 0, 0);
739 0 : const nsStyleMargin* oldMargin = aOldStyleContext->PeekStyleMargin();
740 0 : if (oldMargin && oldMargin->GetMargin(oldValue)) {
741 0 : if ((!GetStyleMargin()->GetMargin(newValue) || oldValue != newValue) &&
742 0 : !props.Get(UsedMarginProperty())) {
743 0 : props.Set(UsedMarginProperty(), new nsMargin(oldValue));
744 : }
745 : }
746 :
747 0 : const nsStylePadding* oldPadding = aOldStyleContext->PeekStylePadding();
748 0 : if (oldPadding && oldPadding->GetPadding(oldValue)) {
749 0 : if ((!GetStylePadding()->GetPadding(newValue) || oldValue != newValue) &&
750 0 : !props.Get(UsedPaddingProperty())) {
751 0 : props.Set(UsedPaddingProperty(), new nsMargin(oldValue));
752 : }
753 : }
754 :
755 0 : const nsStyleBorder* oldBorder = aOldStyleContext->PeekStyleBorder();
756 0 : if (oldBorder) {
757 0 : oldValue = oldBorder->GetActualBorder();
758 0 : newValue = GetStyleBorder()->GetActualBorder();
759 0 : if (oldValue != newValue &&
760 0 : !props.Get(UsedBorderProperty())) {
761 0 : props.Set(UsedBorderProperty(), new nsMargin(oldValue));
762 : }
763 : }
764 : }
765 :
766 : imgIRequest *oldBorderImage = aOldStyleContext
767 0 : ? aOldStyleContext->GetStyleBorder()->GetBorderImage()
768 0 : : nsnull;
769 : // For border-images, we can't be as conservative (we need to set the
770 : // new loaders if there has been any change) since the CalcDifference
771 : // call depended on the result of GetActualBorder() and that result
772 : // depends on whether the image has loaded, start the image load now
773 : // so that we'll get notified when it completes loading and can do a
774 : // restyle. Otherwise, the image might finish loading from the
775 : // network before we start listening to its notifications, and then
776 : // we'll never know that it's finished loading. Likewise, we want to
777 : // do this for freshly-created frames to prevent a similar race if the
778 : // image loads between reflow (which can depend on whether the image
779 : // is loaded) and paint. We also don't really care about any callers
780 : // who try to paint borders with a different style context, because
781 : // they won't have the correct size for the border either.
782 0 : if (!EqualImages(oldBorderImage, GetStyleBorder()->GetBorderImage())) {
783 : // stop and restart the image loading/notification
784 0 : PresContext()->SetupBorderImageLoaders(this, GetStyleBorder());
785 : }
786 :
787 : // If the page contains markup that overrides text direction, and
788 : // does not contain any characters that would activate the Unicode
789 : // bidi algorithm, we need to call |SetBidiEnabled| on the pres
790 : // context before reflow starts. See bug 115921.
791 0 : if (GetStyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL) {
792 0 : PresContext()->SetBidiEnabled();
793 : }
794 0 : }
795 :
796 : // MSVC fails with link error "one or more multiply defined symbols found",
797 : // gcc fails with "hidden symbol `nsIFrame::kPrincipalList' isn't defined"
798 : // etc if they are not defined.
799 : #ifndef _MSC_VER
800 : // static nsIFrame constants; initialized in the header file.
801 : const nsIFrame::ChildListID nsIFrame::kPrincipalList;
802 : const nsIFrame::ChildListID nsIFrame::kAbsoluteList;
803 : const nsIFrame::ChildListID nsIFrame::kBulletList;
804 : const nsIFrame::ChildListID nsIFrame::kCaptionList;
805 : const nsIFrame::ChildListID nsIFrame::kColGroupList;
806 : const nsIFrame::ChildListID nsIFrame::kExcessOverflowContainersList;
807 : const nsIFrame::ChildListID nsIFrame::kFixedList;
808 : const nsIFrame::ChildListID nsIFrame::kFloatList;
809 : const nsIFrame::ChildListID nsIFrame::kOverflowContainersList;
810 : const nsIFrame::ChildListID nsIFrame::kOverflowList;
811 : const nsIFrame::ChildListID nsIFrame::kOverflowOutOfFlowList;
812 : const nsIFrame::ChildListID nsIFrame::kPopupList;
813 : const nsIFrame::ChildListID nsIFrame::kPushedFloatsList;
814 : const nsIFrame::ChildListID nsIFrame::kSelectPopupList;
815 : const nsIFrame::ChildListID nsIFrame::kNoReflowPrincipalList;
816 : #endif
817 :
818 : /* virtual */ nsMargin
819 0 : nsIFrame::GetUsedMargin() const
820 : {
821 0 : nsMargin margin(0, 0, 0, 0);
822 0 : if ((mState & NS_FRAME_FIRST_REFLOW) &&
823 0 : !(mState & NS_FRAME_IN_REFLOW))
824 0 : return margin;
825 :
826 : nsMargin *m = static_cast<nsMargin*>
827 0 : (Properties().Get(UsedMarginProperty()));
828 0 : if (m) {
829 0 : margin = *m;
830 : } else {
831 : #ifdef DEBUG
832 : bool hasMargin =
833 : #endif
834 0 : GetStyleMargin()->GetMargin(margin);
835 0 : NS_ASSERTION(hasMargin, "We should have a margin here! (out of memory?)");
836 : }
837 0 : return margin;
838 : }
839 :
840 : /* virtual */ nsMargin
841 0 : nsIFrame::GetUsedBorder() const
842 : {
843 0 : nsMargin border(0, 0, 0, 0);
844 0 : if ((mState & NS_FRAME_FIRST_REFLOW) &&
845 0 : !(mState & NS_FRAME_IN_REFLOW))
846 0 : return border;
847 :
848 : // Theme methods don't use const-ness.
849 0 : nsIFrame *mutable_this = const_cast<nsIFrame*>(this);
850 :
851 0 : const nsStyleDisplay *disp = GetStyleDisplay();
852 0 : if (mutable_this->IsThemed(disp)) {
853 0 : nsIntMargin result;
854 0 : nsPresContext *presContext = PresContext();
855 0 : presContext->GetTheme()->GetWidgetBorder(presContext->DeviceContext(),
856 : mutable_this, disp->mAppearance,
857 0 : &result);
858 0 : border.left = presContext->DevPixelsToAppUnits(result.left);
859 0 : border.top = presContext->DevPixelsToAppUnits(result.top);
860 0 : border.right = presContext->DevPixelsToAppUnits(result.right);
861 0 : border.bottom = presContext->DevPixelsToAppUnits(result.bottom);
862 0 : return border;
863 : }
864 :
865 : nsMargin *b = static_cast<nsMargin*>
866 0 : (Properties().Get(UsedBorderProperty()));
867 0 : if (b) {
868 0 : border = *b;
869 : } else {
870 0 : border = GetStyleBorder()->GetActualBorder();
871 : }
872 0 : return border;
873 : }
874 :
875 : /* virtual */ nsMargin
876 0 : nsIFrame::GetUsedPadding() const
877 : {
878 0 : nsMargin padding(0, 0, 0, 0);
879 0 : if ((mState & NS_FRAME_FIRST_REFLOW) &&
880 0 : !(mState & NS_FRAME_IN_REFLOW))
881 0 : return padding;
882 :
883 : // Theme methods don't use const-ness.
884 0 : nsIFrame *mutable_this = const_cast<nsIFrame*>(this);
885 :
886 0 : const nsStyleDisplay *disp = GetStyleDisplay();
887 0 : if (mutable_this->IsThemed(disp)) {
888 0 : nsPresContext *presContext = PresContext();
889 0 : nsIntMargin widget;
890 0 : if (presContext->GetTheme()->GetWidgetPadding(presContext->DeviceContext(),
891 : mutable_this,
892 : disp->mAppearance,
893 0 : &widget)) {
894 0 : padding.top = presContext->DevPixelsToAppUnits(widget.top);
895 0 : padding.right = presContext->DevPixelsToAppUnits(widget.right);
896 0 : padding.bottom = presContext->DevPixelsToAppUnits(widget.bottom);
897 0 : padding.left = presContext->DevPixelsToAppUnits(widget.left);
898 0 : return padding;
899 : }
900 : }
901 :
902 : nsMargin *p = static_cast<nsMargin*>
903 0 : (Properties().Get(UsedPaddingProperty()));
904 0 : if (p) {
905 0 : padding = *p;
906 : } else {
907 : #ifdef DEBUG
908 : bool hasPadding =
909 : #endif
910 0 : GetStylePadding()->GetPadding(padding);
911 0 : NS_ASSERTION(hasPadding, "We should have padding here! (out of memory?)");
912 : }
913 0 : return padding;
914 : }
915 :
916 : void
917 0 : nsIFrame::ApplySkipSides(nsMargin& aMargin) const
918 : {
919 0 : PRIntn skipSides = GetSkipSides();
920 0 : if (skipSides & (1 << NS_SIDE_TOP))
921 0 : aMargin.top = 0;
922 0 : if (skipSides & (1 << NS_SIDE_RIGHT))
923 0 : aMargin.right = 0;
924 0 : if (skipSides & (1 << NS_SIDE_BOTTOM))
925 0 : aMargin.bottom = 0;
926 0 : if (skipSides & (1 << NS_SIDE_LEFT))
927 0 : aMargin.left = 0;
928 0 : }
929 :
930 : nsRect
931 0 : nsIFrame::GetPaddingRectRelativeToSelf() const
932 : {
933 0 : nsMargin bp(GetUsedBorder());
934 0 : ApplySkipSides(bp);
935 0 : nsRect r(0, 0, mRect.width, mRect.height);
936 0 : r.Deflate(bp);
937 : return r;
938 : }
939 :
940 : nsRect
941 0 : nsIFrame::GetPaddingRect() const
942 : {
943 0 : return GetPaddingRectRelativeToSelf() + GetPosition();
944 : }
945 :
946 : bool
947 0 : nsIFrame::IsTransformed() const
948 : {
949 : return (mState & NS_FRAME_MAY_BE_TRANSFORMED) &&
950 0 : GetStyleDisplay()->HasTransform();
951 : }
952 :
953 : bool
954 0 : nsIFrame::Preserves3DChildren() const
955 : {
956 0 : if (GetStyleDisplay()->mTransformStyle != NS_STYLE_TRANSFORM_STYLE_PRESERVE_3D || !IsTransformed())
957 0 : return false;
958 :
959 : // If we're all scroll frame, then all descendants will be clipped, so we can't preserve 3d.
960 0 : if (GetType() == nsGkAtoms::scrollFrame)
961 0 : return false;
962 :
963 0 : nsRect temp;
964 0 : return (!ApplyOverflowClipping(nsnull, this, GetStyleDisplay(), &temp) &&
965 0 : !ApplyClipPropClipping(nsnull, GetStyleDisplay(), this, &temp) &&
966 0 : !nsSVGIntegrationUtils::UsingEffectsForFrame(this));
967 : }
968 :
969 : bool
970 0 : nsIFrame::Preserves3D() const
971 : {
972 0 : if (!GetParent() || !GetParent()->Preserves3DChildren() || !IsTransformed()) {
973 0 : return false;
974 : }
975 0 : return true;
976 : }
977 :
978 : bool
979 0 : nsIFrame::HasPerspective() const
980 : {
981 0 : if (!IsTransformed()) {
982 0 : return false;
983 : }
984 0 : const nsStyleDisplay* parentDisp = nsnull;
985 0 : nsStyleContext* parentStyleContext = GetStyleContext()->GetParent();
986 0 : if (parentStyleContext) {
987 0 : parentDisp = parentStyleContext->GetStyleDisplay();
988 : }
989 :
990 0 : if (parentDisp &&
991 0 : parentDisp->mChildPerspective.GetUnit() == eStyleUnit_Coord &&
992 0 : parentDisp->mChildPerspective.GetCoordValue() > 0.0) {
993 0 : return true;
994 : }
995 0 : return false;
996 : }
997 :
998 : bool
999 0 : nsIFrame::ChildrenHavePerspective() const
1000 : {
1001 0 : const nsStyleDisplay *disp = GetStyleContext()->GetStyleDisplay();
1002 0 : if (disp &&
1003 0 : disp->mChildPerspective.GetUnit() == eStyleUnit_Coord &&
1004 0 : disp->mChildPerspective.GetCoordValue() > 0.0) {
1005 0 : return true;
1006 : }
1007 0 : return false;
1008 : }
1009 :
1010 : nsRect
1011 0 : nsIFrame::GetContentRectRelativeToSelf() const
1012 : {
1013 0 : nsMargin bp(GetUsedBorderAndPadding());
1014 0 : ApplySkipSides(bp);
1015 0 : nsRect r(0, 0, mRect.width, mRect.height);
1016 0 : r.Deflate(bp);
1017 : return r;
1018 : }
1019 :
1020 : nsRect
1021 0 : nsIFrame::GetContentRect() const
1022 : {
1023 0 : return GetContentRectRelativeToSelf() + GetPosition();
1024 : }
1025 :
1026 : bool
1027 0 : nsIFrame::ComputeBorderRadii(const nsStyleCorners& aBorderRadius,
1028 : const nsSize& aFrameSize,
1029 : const nsSize& aBorderArea,
1030 : PRIntn aSkipSides,
1031 : nscoord aRadii[8])
1032 : {
1033 : // Percentages are relative to whichever side they're on.
1034 0 : NS_FOR_CSS_HALF_CORNERS(i) {
1035 0 : const nsStyleCoord c = aBorderRadius.Get(i);
1036 : nscoord axis =
1037 0 : NS_HALF_CORNER_IS_X(i) ? aFrameSize.width : aFrameSize.height;
1038 :
1039 0 : if (c.IsCoordPercentCalcUnit()) {
1040 0 : aRadii[i] = nsRuleNode::ComputeCoordPercentCalc(c, axis);
1041 0 : if (aRadii[i] < 0) {
1042 : // clamp calc()
1043 0 : aRadii[i] = 0;
1044 : }
1045 : } else {
1046 0 : NS_NOTREACHED("ComputeBorderRadii: bad unit");
1047 0 : aRadii[i] = 0;
1048 : }
1049 : }
1050 :
1051 0 : if (aSkipSides & (1 << NS_SIDE_TOP)) {
1052 0 : aRadii[NS_CORNER_TOP_LEFT_X] = 0;
1053 0 : aRadii[NS_CORNER_TOP_LEFT_Y] = 0;
1054 0 : aRadii[NS_CORNER_TOP_RIGHT_X] = 0;
1055 0 : aRadii[NS_CORNER_TOP_RIGHT_Y] = 0;
1056 : }
1057 :
1058 0 : if (aSkipSides & (1 << NS_SIDE_RIGHT)) {
1059 0 : aRadii[NS_CORNER_TOP_RIGHT_X] = 0;
1060 0 : aRadii[NS_CORNER_TOP_RIGHT_Y] = 0;
1061 0 : aRadii[NS_CORNER_BOTTOM_RIGHT_X] = 0;
1062 0 : aRadii[NS_CORNER_BOTTOM_RIGHT_Y] = 0;
1063 : }
1064 :
1065 0 : if (aSkipSides & (1 << NS_SIDE_BOTTOM)) {
1066 0 : aRadii[NS_CORNER_BOTTOM_RIGHT_X] = 0;
1067 0 : aRadii[NS_CORNER_BOTTOM_RIGHT_Y] = 0;
1068 0 : aRadii[NS_CORNER_BOTTOM_LEFT_X] = 0;
1069 0 : aRadii[NS_CORNER_BOTTOM_LEFT_Y] = 0;
1070 : }
1071 :
1072 0 : if (aSkipSides & (1 << NS_SIDE_LEFT)) {
1073 0 : aRadii[NS_CORNER_BOTTOM_LEFT_X] = 0;
1074 0 : aRadii[NS_CORNER_BOTTOM_LEFT_Y] = 0;
1075 0 : aRadii[NS_CORNER_TOP_LEFT_X] = 0;
1076 0 : aRadii[NS_CORNER_TOP_LEFT_Y] = 0;
1077 : }
1078 :
1079 : // css3-background specifies this algorithm for reducing
1080 : // corner radii when they are too big.
1081 0 : bool haveRadius = false;
1082 0 : double ratio = 1.0f;
1083 0 : NS_FOR_CSS_SIDES(side) {
1084 0 : PRUint32 hc1 = NS_SIDE_TO_HALF_CORNER(side, false, true);
1085 0 : PRUint32 hc2 = NS_SIDE_TO_HALF_CORNER(side, true, true);
1086 : nscoord length =
1087 0 : NS_SIDE_IS_VERTICAL(side) ? aBorderArea.height : aBorderArea.width;
1088 0 : nscoord sum = aRadii[hc1] + aRadii[hc2];
1089 0 : if (sum)
1090 0 : haveRadius = true;
1091 :
1092 : // avoid floating point division in the normal case
1093 0 : if (length < sum)
1094 0 : ratio = NS_MIN(ratio, double(length)/sum);
1095 : }
1096 0 : if (ratio < 1.0) {
1097 0 : NS_FOR_CSS_HALF_CORNERS(corner) {
1098 0 : aRadii[corner] *= ratio;
1099 : }
1100 : }
1101 :
1102 0 : return haveRadius;
1103 : }
1104 :
1105 : /* static */ void
1106 0 : nsIFrame::InsetBorderRadii(nscoord aRadii[8], const nsMargin &aOffsets)
1107 : {
1108 0 : NS_FOR_CSS_SIDES(side) {
1109 0 : nscoord offset = aOffsets.Side(side);
1110 0 : PRUint32 hc1 = NS_SIDE_TO_HALF_CORNER(side, false, false);
1111 0 : PRUint32 hc2 = NS_SIDE_TO_HALF_CORNER(side, true, false);
1112 0 : aRadii[hc1] = NS_MAX(0, aRadii[hc1] - offset);
1113 0 : aRadii[hc2] = NS_MAX(0, aRadii[hc2] - offset);
1114 : }
1115 0 : }
1116 :
1117 : /* static */ void
1118 0 : nsIFrame::OutsetBorderRadii(nscoord aRadii[8], const nsMargin &aOffsets)
1119 : {
1120 0 : NS_FOR_CSS_SIDES(side) {
1121 0 : nscoord offset = aOffsets.Side(side);
1122 0 : PRUint32 hc1 = NS_SIDE_TO_HALF_CORNER(side, false, false);
1123 0 : PRUint32 hc2 = NS_SIDE_TO_HALF_CORNER(side, true, false);
1124 0 : if (aRadii[hc1] > 0)
1125 0 : aRadii[hc1] += offset;
1126 0 : if (aRadii[hc2] > 0)
1127 0 : aRadii[hc2] += offset;
1128 : }
1129 0 : }
1130 :
1131 : /* virtual */ bool
1132 0 : nsIFrame::GetBorderRadii(nscoord aRadii[8]) const
1133 : {
1134 0 : if (IsThemed()) {
1135 : // When we're themed, the native theme code draws the border and
1136 : // background, and therefore it doesn't make sense to tell other
1137 : // code that's interested in border-radius that we have any radii.
1138 : //
1139 : // In an ideal world, we might have a way for the them to tell us an
1140 : // border radius, but since we don't, we're better off assuming
1141 : // zero.
1142 0 : NS_FOR_CSS_HALF_CORNERS(corner) {
1143 0 : aRadii[corner] = 0;
1144 : }
1145 0 : return false;
1146 : }
1147 0 : nsSize size = GetSize();
1148 0 : return ComputeBorderRadii(GetStyleBorder()->mBorderRadius, size, size,
1149 0 : GetSkipSides(), aRadii);
1150 : }
1151 :
1152 : bool
1153 0 : nsIFrame::GetPaddingBoxBorderRadii(nscoord aRadii[8]) const
1154 : {
1155 0 : if (!GetBorderRadii(aRadii))
1156 0 : return false;
1157 0 : InsetBorderRadii(aRadii, GetUsedBorder());
1158 0 : NS_FOR_CSS_HALF_CORNERS(corner) {
1159 0 : if (aRadii[corner])
1160 0 : return true;
1161 : }
1162 0 : return false;
1163 : }
1164 :
1165 : bool
1166 0 : nsIFrame::GetContentBoxBorderRadii(nscoord aRadii[8]) const
1167 : {
1168 0 : if (!GetBorderRadii(aRadii))
1169 0 : return false;
1170 0 : InsetBorderRadii(aRadii, GetUsedBorderAndPadding());
1171 0 : NS_FOR_CSS_HALF_CORNERS(corner) {
1172 0 : if (aRadii[corner])
1173 0 : return true;
1174 : }
1175 0 : return false;
1176 : }
1177 :
1178 : nsStyleContext*
1179 0 : nsFrame::GetAdditionalStyleContext(PRInt32 aIndex) const
1180 : {
1181 0 : NS_PRECONDITION(aIndex >= 0, "invalid index number");
1182 0 : return nsnull;
1183 : }
1184 :
1185 : void
1186 0 : nsFrame::SetAdditionalStyleContext(PRInt32 aIndex,
1187 : nsStyleContext* aStyleContext)
1188 : {
1189 0 : NS_PRECONDITION(aIndex >= 0, "invalid index number");
1190 0 : }
1191 :
1192 : nscoord
1193 0 : nsFrame::GetBaseline() const
1194 : {
1195 0 : NS_ASSERTION(!NS_SUBTREE_DIRTY(this),
1196 : "frame must not be dirty");
1197 : // Default to the bottom margin edge, per CSS2.1's definition of the
1198 : // 'baseline' value of 'vertical-align'.
1199 0 : return mRect.height + GetUsedMargin().bottom;
1200 : }
1201 :
1202 : const nsFrameList&
1203 0 : nsFrame::GetChildList(ChildListID aListID) const
1204 : {
1205 0 : if (IsAbsoluteContainer() &&
1206 0 : aListID == GetAbsoluteListID()) {
1207 0 : return GetAbsoluteContainingBlock()->GetChildList();
1208 : } else {
1209 0 : return nsFrameList::EmptyList();
1210 : }
1211 : }
1212 :
1213 : void
1214 0 : nsFrame::GetChildLists(nsTArray<ChildList>* aLists) const
1215 : {
1216 0 : if (IsAbsoluteContainer()) {
1217 0 : nsFrameList absoluteList = GetAbsoluteContainingBlock()->GetChildList();
1218 0 : absoluteList.AppendIfNonempty(aLists, GetAbsoluteListID());
1219 : }
1220 0 : }
1221 :
1222 : static nsIFrame*
1223 0 : GetActiveSelectionFrame(nsPresContext* aPresContext, nsIFrame* aFrame)
1224 : {
1225 0 : nsIContent* capturingContent = nsIPresShell::GetCapturingContent();
1226 0 : if (capturingContent) {
1227 0 : nsIFrame* activeFrame = aPresContext->GetPrimaryFrameFor(capturingContent);
1228 0 : return activeFrame ? activeFrame : aFrame;
1229 : }
1230 :
1231 0 : return aFrame;
1232 : }
1233 :
1234 : PRInt16
1235 0 : nsFrame::DisplaySelection(nsPresContext* aPresContext, bool isOkToTurnOn)
1236 : {
1237 0 : PRInt16 selType = nsISelectionController::SELECTION_OFF;
1238 :
1239 0 : nsCOMPtr<nsISelectionController> selCon;
1240 0 : nsresult result = GetSelectionController(aPresContext, getter_AddRefs(selCon));
1241 0 : if (NS_SUCCEEDED(result) && selCon) {
1242 0 : result = selCon->GetDisplaySelection(&selType);
1243 0 : if (NS_SUCCEEDED(result) && (selType != nsISelectionController::SELECTION_OFF)) {
1244 : // Check whether style allows selection.
1245 : bool selectable;
1246 0 : IsSelectable(&selectable, nsnull);
1247 0 : if (!selectable) {
1248 0 : selType = nsISelectionController::SELECTION_OFF;
1249 0 : isOkToTurnOn = false;
1250 : }
1251 : }
1252 0 : if (isOkToTurnOn && (selType == nsISelectionController::SELECTION_OFF)) {
1253 0 : selCon->SetDisplaySelection(nsISelectionController::SELECTION_ON);
1254 0 : selType = nsISelectionController::SELECTION_ON;
1255 : }
1256 : }
1257 0 : return selType;
1258 : }
1259 :
1260 : class nsDisplaySelectionOverlay : public nsDisplayItem {
1261 : public:
1262 0 : nsDisplaySelectionOverlay(nsDisplayListBuilder* aBuilder,
1263 : nsFrame* aFrame, PRInt16 aSelectionValue)
1264 0 : : nsDisplayItem(aBuilder, aFrame), mSelectionValue(aSelectionValue) {
1265 0 : MOZ_COUNT_CTOR(nsDisplaySelectionOverlay);
1266 0 : }
1267 : #ifdef NS_BUILD_REFCNT_LOGGING
1268 0 : virtual ~nsDisplaySelectionOverlay() {
1269 0 : MOZ_COUNT_DTOR(nsDisplaySelectionOverlay);
1270 0 : }
1271 : #endif
1272 :
1273 : virtual void Paint(nsDisplayListBuilder* aBuilder,
1274 : nsRenderingContext* aCtx);
1275 0 : NS_DISPLAY_DECL_NAME("SelectionOverlay", TYPE_SELECTION_OVERLAY)
1276 : private:
1277 : PRInt16 mSelectionValue;
1278 : };
1279 :
1280 0 : void nsDisplaySelectionOverlay::Paint(nsDisplayListBuilder* aBuilder,
1281 : nsRenderingContext* aCtx)
1282 : {
1283 : LookAndFeel::ColorID colorID;
1284 0 : if (mSelectionValue == nsISelectionController::SELECTION_ON) {
1285 0 : colorID = LookAndFeel::eColorID_TextSelectBackground;
1286 0 : } else if (mSelectionValue == nsISelectionController::SELECTION_ATTENTION) {
1287 0 : colorID = LookAndFeel::eColorID_TextSelectBackgroundAttention;
1288 : } else {
1289 0 : colorID = LookAndFeel::eColorID_TextSelectBackgroundDisabled;
1290 : }
1291 :
1292 0 : nscolor color = LookAndFeel::GetColor(colorID, NS_RGB(255, 255, 255));
1293 :
1294 0 : gfxRGBA c(color);
1295 0 : c.a = .5;
1296 :
1297 0 : gfxContext *ctx = aCtx->ThebesContext();
1298 0 : ctx->SetColor(c);
1299 :
1300 : nsIntRect pxRect =
1301 0 : mVisibleRect.ToOutsidePixels(mFrame->PresContext()->AppUnitsPerDevPixel());
1302 0 : ctx->NewPath();
1303 0 : ctx->Rectangle(gfxRect(pxRect.x, pxRect.y, pxRect.width, pxRect.height), true);
1304 0 : ctx->Fill();
1305 0 : }
1306 :
1307 : /********************************************************
1308 : * Refreshes each content's frame
1309 : *********************************************************/
1310 :
1311 : nsresult
1312 0 : nsFrame::DisplaySelectionOverlay(nsDisplayListBuilder* aBuilder,
1313 : nsDisplayList* aList,
1314 : PRUint16 aContentType)
1315 : {
1316 0 : if (!IsSelected() || !IsVisibleForPainting(aBuilder))
1317 0 : return NS_OK;
1318 :
1319 0 : nsPresContext* presContext = PresContext();
1320 0 : nsIPresShell *shell = presContext->PresShell();
1321 0 : if (!shell)
1322 0 : return NS_OK;
1323 :
1324 0 : PRInt16 displaySelection = shell->GetSelectionFlags();
1325 0 : if (!(displaySelection & aContentType))
1326 0 : return NS_OK;
1327 :
1328 0 : const nsFrameSelection* frameSelection = GetConstFrameSelection();
1329 0 : PRInt16 selectionValue = frameSelection->GetDisplaySelection();
1330 :
1331 0 : if (selectionValue <= nsISelectionController::SELECTION_HIDDEN)
1332 0 : return NS_OK; // selection is hidden or off
1333 :
1334 0 : nsIContent *newContent = mContent->GetParent();
1335 :
1336 : //check to see if we are anonymous content
1337 0 : PRInt32 offset = 0;
1338 0 : if (newContent) {
1339 : // XXXbz there has GOT to be a better way of determining this!
1340 0 : offset = newContent->IndexOf(mContent);
1341 : }
1342 :
1343 : SelectionDetails *details;
1344 : //look up to see what selection(s) are on this frame
1345 0 : details = frameSelection->LookUpSelection(newContent, offset, 1, false);
1346 : // XXX is the above really necessary? We don't actually DO anything
1347 : // with the details other than test that they're non-null
1348 0 : if (!details)
1349 0 : return NS_OK;
1350 :
1351 0 : while (details) {
1352 0 : SelectionDetails *next = details->mNext;
1353 0 : delete details;
1354 0 : details = next;
1355 : }
1356 :
1357 : return aList->AppendNewToTop(new (aBuilder)
1358 0 : nsDisplaySelectionOverlay(aBuilder, this, selectionValue));
1359 : }
1360 :
1361 : nsresult
1362 0 : nsFrame::DisplayOutlineUnconditional(nsDisplayListBuilder* aBuilder,
1363 : const nsDisplayListSet& aLists)
1364 : {
1365 0 : if (GetStyleOutline()->GetOutlineStyle() == NS_STYLE_BORDER_STYLE_NONE)
1366 0 : return NS_OK;
1367 :
1368 : return aLists.Outlines()->AppendNewToTop(
1369 0 : new (aBuilder) nsDisplayOutline(aBuilder, this));
1370 : }
1371 :
1372 : nsresult
1373 0 : nsFrame::DisplayOutline(nsDisplayListBuilder* aBuilder,
1374 : const nsDisplayListSet& aLists)
1375 : {
1376 0 : if (!IsVisibleForPainting(aBuilder))
1377 0 : return NS_OK;
1378 :
1379 0 : return DisplayOutlineUnconditional(aBuilder, aLists);
1380 : }
1381 :
1382 : nsresult
1383 0 : nsIFrame::DisplayCaret(nsDisplayListBuilder* aBuilder,
1384 : const nsRect& aDirtyRect, nsDisplayList* aList)
1385 : {
1386 0 : if (!IsVisibleForPainting(aBuilder))
1387 0 : return NS_OK;
1388 :
1389 : return aList->AppendNewToTop(
1390 0 : new (aBuilder) nsDisplayCaret(aBuilder, this, aBuilder->GetCaret()));
1391 : }
1392 :
1393 : nscolor
1394 0 : nsIFrame::GetCaretColorAt(PRInt32 aOffset)
1395 : {
1396 : // Use text color.
1397 0 : return GetStyleColor()->mColor;
1398 : }
1399 :
1400 : bool
1401 0 : nsIFrame::HasBorder() const
1402 : {
1403 : // Border images contribute to the background of the content area
1404 : // even if there's no border proper.
1405 0 : return (GetUsedBorder() != nsMargin(0,0,0,0) ||
1406 0 : GetStyleBorder()->IsBorderImageLoaded());
1407 : }
1408 :
1409 : nsresult
1410 0 : nsFrame::DisplayBackgroundUnconditional(nsDisplayListBuilder* aBuilder,
1411 : const nsDisplayListSet& aLists,
1412 : bool aForceBackground)
1413 : {
1414 : // Here we don't try to detect background propagation. Frames that might
1415 : // receive a propagated background should just set aForceBackground to
1416 : // true.
1417 0 : if (aBuilder->IsForEventDelivery() || aForceBackground ||
1418 0 : !GetStyleBackground()->IsTransparent() || GetStyleDisplay()->mAppearance) {
1419 : return aLists.BorderBackground()->AppendNewToTop(new (aBuilder)
1420 0 : nsDisplayBackground(aBuilder, this));
1421 : }
1422 0 : return NS_OK;
1423 : }
1424 :
1425 : nsresult
1426 0 : nsFrame::DisplayBorderBackgroundOutline(nsDisplayListBuilder* aBuilder,
1427 : const nsDisplayListSet& aLists,
1428 : bool aForceBackground)
1429 : {
1430 : // The visibility check belongs here since child elements have the
1431 : // opportunity to override the visibility property and display even if
1432 : // their parent is hidden.
1433 0 : if (!IsVisibleForPainting(aBuilder))
1434 0 : return NS_OK;
1435 :
1436 0 : bool hasBoxShadow = GetStyleBorder()->mBoxShadow != nsnull;
1437 0 : if (hasBoxShadow) {
1438 : nsresult rv = aLists.BorderBackground()->AppendNewToTop(new (aBuilder)
1439 0 : nsDisplayBoxShadowOuter(aBuilder, this));
1440 0 : NS_ENSURE_SUCCESS(rv, rv);
1441 : }
1442 :
1443 : nsresult rv =
1444 0 : DisplayBackgroundUnconditional(aBuilder, aLists, aForceBackground);
1445 0 : NS_ENSURE_SUCCESS(rv, rv);
1446 :
1447 0 : if (hasBoxShadow) {
1448 : rv = aLists.BorderBackground()->AppendNewToTop(new (aBuilder)
1449 0 : nsDisplayBoxShadowInner(aBuilder, this));
1450 0 : NS_ENSURE_SUCCESS(rv, rv);
1451 : }
1452 :
1453 0 : if (HasBorder()) {
1454 : rv = aLists.BorderBackground()->AppendNewToTop(new (aBuilder)
1455 0 : nsDisplayBorder(aBuilder, this));
1456 0 : NS_ENSURE_SUCCESS(rv, rv);
1457 : }
1458 :
1459 0 : return DisplayOutlineUnconditional(aBuilder, aLists);
1460 : }
1461 :
1462 : bool
1463 0 : nsIFrame::GetClipPropClipRect(const nsStyleDisplay* aDisp, nsRect* aRect,
1464 : const nsSize& aSize) const
1465 : {
1466 0 : NS_PRECONDITION(aRect, "Must have aRect out parameter");
1467 :
1468 0 : if (!aDisp->IsAbsolutelyPositioned() ||
1469 0 : !(aDisp->mClipFlags & NS_STYLE_CLIP_RECT))
1470 0 : return false;
1471 :
1472 0 : *aRect = aDisp->mClip;
1473 0 : if (NS_STYLE_CLIP_RIGHT_AUTO & aDisp->mClipFlags) {
1474 0 : aRect->width = aSize.width - aRect->x;
1475 : }
1476 0 : if (NS_STYLE_CLIP_BOTTOM_AUTO & aDisp->mClipFlags) {
1477 0 : aRect->height = aSize.height - aRect->y;
1478 : }
1479 0 : return true;
1480 : }
1481 :
1482 0 : static bool ApplyClipPropClipping(nsDisplayListBuilder* aBuilder,
1483 : const nsStyleDisplay* aDisp, const nsIFrame* aFrame,
1484 : nsRect* aRect) {
1485 0 : if (!aFrame->GetClipPropClipRect(aDisp, aRect, aFrame->GetSize()))
1486 0 : return false;
1487 :
1488 0 : if (aBuilder) {
1489 0 : *aRect += aBuilder->ToReferenceFrame(aFrame);
1490 : }
1491 0 : return true;
1492 : }
1493 :
1494 0 : static bool ApplyOverflowClipping(nsDisplayListBuilder* aBuilder,
1495 : const nsIFrame* aFrame,
1496 : const nsStyleDisplay* aDisp, nsRect* aRect) {
1497 : // REVIEW: from nsContainerFrame.cpp SyncFrameViewGeometryDependentProperties,
1498 : // except that that function used the border-edge for
1499 : // -moz-hidden-unscrollable which I don't think is correct... Also I've
1500 : // changed -moz-hidden-unscrollable to apply to any kind of frame.
1501 :
1502 : // Only -moz-hidden-unscrollable is handled here (and 'hidden' for table
1503 : // frames, and any non-visible value for blocks in a paginated context).
1504 : // Other overflow clipping is applied by nsHTML/XULScrollFrame.
1505 : // We allow -moz-hidden-unscrollable to apply to any kind of frame. This
1506 : // is required by comboboxes which make their display text (an inline frame)
1507 : // have clipping.
1508 0 : if (!nsFrame::ApplyOverflowClipping(aFrame, aDisp)) {
1509 0 : return false;
1510 : }
1511 0 : *aRect = aFrame->GetPaddingRect() - aFrame->GetPosition();
1512 0 : if (aBuilder) {
1513 0 : *aRect += aBuilder->ToReferenceFrame(aFrame);
1514 : }
1515 0 : return true;
1516 : }
1517 :
1518 : class nsOverflowClipWrapper : public nsDisplayWrapper
1519 0 : {
1520 : public:
1521 : /**
1522 : * Create a wrapper to apply overflow clipping for aContainer.
1523 : * @param aClipBorderBackground set to true to clip the BorderBackground()
1524 : * list, otherwise it will not be clipped
1525 : * @param aClipAll set to true to clip all descendants, even those for
1526 : * which we aren't the containing block
1527 : */
1528 0 : nsOverflowClipWrapper(nsIFrame* aContainer, const nsRect& aRect,
1529 : const nscoord aRadii[8],
1530 : bool aClipBorderBackground, bool aClipAll)
1531 : : mContainer(aContainer), mRect(aRect),
1532 : mClipBorderBackground(aClipBorderBackground), mClipAll(aClipAll),
1533 0 : mHaveRadius(false)
1534 : {
1535 0 : memcpy(mRadii, aRadii, sizeof(mRadii));
1536 0 : NS_FOR_CSS_HALF_CORNERS(corner) {
1537 0 : if (aRadii[corner] > 0) {
1538 0 : mHaveRadius = true;
1539 0 : break;
1540 : }
1541 : }
1542 0 : }
1543 0 : virtual bool WrapBorderBackground() { return mClipBorderBackground; }
1544 0 : virtual nsDisplayItem* WrapList(nsDisplayListBuilder* aBuilder,
1545 : nsIFrame* aFrame, nsDisplayList* aList) {
1546 : // We are not a stacking context root. There is no valid underlying
1547 : // frame for the whole list. These items are all in-flow descendants so
1548 : // we can safely just clip them.
1549 0 : if (mHaveRadius) {
1550 : return new (aBuilder) nsDisplayClipRoundedRect(aBuilder, nsnull, aList,
1551 0 : mRect, mRadii);
1552 : }
1553 0 : return new (aBuilder) nsDisplayClip(aBuilder, nsnull, aList, mRect);
1554 : }
1555 0 : virtual nsDisplayItem* WrapItem(nsDisplayListBuilder* aBuilder,
1556 : nsDisplayItem* aItem) {
1557 0 : nsIFrame* f = aItem->GetUnderlyingFrame();
1558 0 : if (mClipAll ||
1559 0 : nsLayoutUtils::IsProperAncestorFrame(mContainer, f, nsnull)) {
1560 0 : if (mHaveRadius) {
1561 : return new (aBuilder) nsDisplayClipRoundedRect(aBuilder, f, aItem,
1562 0 : mRect, mRadii);
1563 : }
1564 0 : return new (aBuilder) nsDisplayClip(aBuilder, f, aItem, mRect);
1565 : }
1566 0 : return aItem;
1567 : }
1568 : protected:
1569 : nsIFrame* mContainer;
1570 : nsRect mRect;
1571 : nscoord mRadii[8];
1572 : bool mClipBorderBackground;
1573 : bool mClipAll;
1574 : bool mHaveRadius;
1575 : };
1576 :
1577 : class nsDisplayClipPropWrapper : public nsDisplayWrapper
1578 0 : {
1579 : public:
1580 0 : nsDisplayClipPropWrapper(const nsRect& aRect)
1581 0 : : mRect(aRect) {}
1582 0 : virtual nsDisplayItem* WrapList(nsDisplayListBuilder* aBuilder,
1583 : nsIFrame* aFrame, nsDisplayList* aList) {
1584 : // We are not a stacking context root. There is no valid underlying
1585 : // frame for the whole list.
1586 0 : return new (aBuilder) nsDisplayClip(aBuilder, nsnull, aList, mRect);
1587 : }
1588 0 : virtual nsDisplayItem* WrapItem(nsDisplayListBuilder* aBuilder,
1589 : nsDisplayItem* aItem) {
1590 : return new (aBuilder) nsDisplayClip(aBuilder, aItem->GetUnderlyingFrame(),
1591 0 : aItem, mRect);
1592 : }
1593 : protected:
1594 : nsRect mRect;
1595 : };
1596 :
1597 : nsresult
1598 0 : nsIFrame::OverflowClip(nsDisplayListBuilder* aBuilder,
1599 : const nsDisplayListSet& aFromSet,
1600 : const nsDisplayListSet& aToSet,
1601 : const nsRect& aClipRect,
1602 : const nscoord aClipRadii[8],
1603 : bool aClipBorderBackground,
1604 : bool aClipAll)
1605 : {
1606 : nsOverflowClipWrapper wrapper(this, aClipRect, aClipRadii,
1607 0 : aClipBorderBackground, aClipAll);
1608 0 : return wrapper.WrapLists(aBuilder, this, aFromSet, aToSet);
1609 : }
1610 :
1611 : static nsresult
1612 0 : BuildDisplayListWithOverflowClip(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
1613 : const nsRect& aDirtyRect, const nsDisplayListSet& aSet,
1614 : const nsRect& aClipRect, const nscoord aClipRadii[8])
1615 : {
1616 0 : nsDisplayListCollection set;
1617 0 : nsresult rv = aFrame->BuildDisplayList(aBuilder, aDirtyRect, set);
1618 0 : NS_ENSURE_SUCCESS(rv, rv);
1619 0 : rv = aBuilder->DisplayCaret(aFrame, aDirtyRect, aSet.Content());
1620 0 : NS_ENSURE_SUCCESS(rv, rv);
1621 :
1622 0 : return aFrame->OverflowClip(aBuilder, set, aSet, aClipRect, aClipRadii);
1623 : }
1624 :
1625 : #ifdef NS_DEBUG
1626 0 : static void PaintDebugBorder(nsIFrame* aFrame, nsRenderingContext* aCtx,
1627 : const nsRect& aDirtyRect, nsPoint aPt) {
1628 0 : nsRect r(aPt, aFrame->GetSize());
1629 0 : if (aFrame->HasView()) {
1630 0 : aCtx->SetColor(NS_RGB(0,0,255));
1631 : } else {
1632 0 : aCtx->SetColor(NS_RGB(255,0,0));
1633 : }
1634 0 : aCtx->DrawRect(r);
1635 0 : }
1636 :
1637 0 : static void PaintEventTargetBorder(nsIFrame* aFrame, nsRenderingContext* aCtx,
1638 : const nsRect& aDirtyRect, nsPoint aPt) {
1639 0 : nsRect r(aPt, aFrame->GetSize());
1640 0 : aCtx->SetColor(NS_RGB(128,0,128));
1641 0 : aCtx->DrawRect(r);
1642 0 : }
1643 :
1644 : static void
1645 0 : DisplayDebugBorders(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
1646 : const nsDisplayListSet& aLists) {
1647 : // Draw a border around the child
1648 : // REVIEW: From nsContainerFrame::PaintChild
1649 0 : if (nsFrame::GetShowFrameBorders() && !aFrame->GetRect().IsEmpty()) {
1650 : aLists.Outlines()->AppendNewToTop(new (aBuilder)
1651 : nsDisplayGeneric(aBuilder, aFrame, PaintDebugBorder, "DebugBorder",
1652 0 : nsDisplayItem::TYPE_DEBUG_BORDER));
1653 : }
1654 : // Draw a border around the current event target
1655 0 : if (nsFrame::GetShowEventTargetFrameBorder() &&
1656 0 : aFrame->PresContext()->PresShell()->GetDrawEventTargetFrame() == aFrame) {
1657 : aLists.Outlines()->AppendNewToTop(new (aBuilder)
1658 : nsDisplayGeneric(aBuilder, aFrame, PaintEventTargetBorder, "EventTargetBorder",
1659 0 : nsDisplayItem::TYPE_EVENT_TARGET_BORDER));
1660 : }
1661 0 : }
1662 : #endif
1663 :
1664 : static nsresult
1665 0 : WrapPreserve3DListInternal(nsIFrame* aFrame, nsDisplayListBuilder *aBuilder, nsDisplayList *aList, PRUint32& aIndex)
1666 : {
1667 0 : if (aIndex > nsDisplayTransform::INDEX_MAX) {
1668 0 : return NS_OK;
1669 : }
1670 :
1671 0 : nsresult rv = NS_OK;
1672 0 : nsDisplayList newList;
1673 0 : nsDisplayList temp;
1674 0 : while (nsDisplayItem *item = aList->RemoveBottom()) {
1675 0 : nsIFrame *childFrame = item->GetUnderlyingFrame();
1676 :
1677 : // We accumulate sequential items that aren't transforms into the 'temp' list
1678 : // and then flush this list into newList by wrapping the whole lot with a single
1679 : // nsDisplayTransform.
1680 :
1681 0 : if (childFrame && (childFrame->GetParent()->Preserves3DChildren() || childFrame == aFrame)) {
1682 0 : switch (item->GetType()) {
1683 : case nsDisplayItem::TYPE_TRANSFORM: {
1684 0 : if (!temp.IsEmpty()) {
1685 0 : newList.AppendToTop(new (aBuilder) nsDisplayTransform(aBuilder, aFrame, &temp, aIndex++));
1686 : }
1687 0 : newList.AppendToTop(item);
1688 0 : break;
1689 : }
1690 : case nsDisplayItem::TYPE_WRAP_LIST: {
1691 0 : if (!temp.IsEmpty()) {
1692 0 : newList.AppendToTop(new (aBuilder) nsDisplayTransform(aBuilder, aFrame, &temp, aIndex++));
1693 : }
1694 0 : nsDisplayWrapList *list = static_cast<nsDisplayWrapList*>(item);
1695 0 : rv = WrapPreserve3DListInternal(aFrame, aBuilder, list->GetList(), aIndex);
1696 0 : newList.AppendToTop(list->GetList());
1697 0 : list->~nsDisplayWrapList();
1698 0 : break;
1699 : }
1700 : case nsDisplayItem::TYPE_OPACITY: {
1701 0 : if (!temp.IsEmpty()) {
1702 0 : newList.AppendToTop(new (aBuilder) nsDisplayTransform(aBuilder, aFrame, &temp, aIndex++));
1703 : }
1704 0 : nsDisplayOpacity *opacity = static_cast<nsDisplayOpacity*>(item);
1705 0 : rv = WrapPreserve3DListInternal(aFrame, aBuilder, opacity->GetList(), aIndex);
1706 0 : newList.AppendToTop(item);
1707 0 : break;
1708 : }
1709 : default: {
1710 0 : temp.AppendToTop(item);
1711 0 : break;
1712 : }
1713 : }
1714 : } else {
1715 0 : temp.AppendToTop(item);
1716 : }
1717 :
1718 0 : if (NS_FAILED(rv) || !item || aIndex > nsDisplayTransform::INDEX_MAX)
1719 0 : return rv;
1720 : }
1721 :
1722 0 : if (!temp.IsEmpty()) {
1723 0 : newList.AppendToTop(new (aBuilder) nsDisplayTransform(aBuilder, aFrame, &temp, aIndex++));
1724 : }
1725 :
1726 0 : aList->AppendToTop(&newList);
1727 0 : return NS_OK;
1728 : }
1729 :
1730 : static nsresult
1731 0 : WrapPreserve3DList(nsIFrame* aFrame, nsDisplayListBuilder* aBuilder, nsDisplayList *aList)
1732 : {
1733 0 : PRUint32 index = 0;
1734 0 : return WrapPreserve3DListInternal(aFrame, aBuilder, aList, index);
1735 : }
1736 :
1737 : nsresult
1738 0 : nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
1739 : const nsRect& aDirtyRect,
1740 : nsDisplayList* aList) {
1741 0 : if (GetStateBits() & NS_FRAME_TOO_DEEP_IN_FRAME_TREE)
1742 0 : return NS_OK;
1743 :
1744 : // Replaced elements have their visibility handled here, because
1745 : // they're visually atomic
1746 0 : if (IsFrameOfType(eReplaced) && !IsVisibleForPainting(aBuilder))
1747 0 : return NS_OK;
1748 :
1749 0 : nsRect clipPropClip;
1750 0 : const nsStyleDisplay* disp = GetStyleDisplay();
1751 : // We can stop right away if this is a zero-opacity stacking context and
1752 : // we're painting.
1753 0 : if (disp->mOpacity == 0.0 && aBuilder->IsForPainting())
1754 0 : return NS_OK;
1755 :
1756 : bool applyClipPropClipping =
1757 0 : ApplyClipPropClipping(aBuilder, disp, this, &clipPropClip);
1758 0 : nsRect dirtyRect = aDirtyRect;
1759 :
1760 0 : bool inTransform = aBuilder->IsInTransform();
1761 0 : if ((mState & NS_FRAME_MAY_BE_TRANSFORMED) &&
1762 0 : disp->HasTransform()) {
1763 0 : if (nsDisplayTransform::ShouldPrerenderTransformedContent(aBuilder, this) ||
1764 0 : Preserves3DChildren()) {
1765 0 : dirtyRect = GetVisualOverflowRectRelativeToSelf();
1766 : } else {
1767 : // Transform dirtyRect into our frame's local coordinate space. Note that
1768 : // the new value is the bounds of the old value's transformed vertices, so
1769 : // the area covered by dirtyRect may increase here.
1770 : //
1771 : // Although we don't bother to check for and maintain the 1x1 size of the
1772 : // magic rect indicating a hit test point, in reality this is extremely
1773 : // unlikely to matter. The rect starts off with dimensions of 1x1 *app*
1774 : // units, and it would require a very large number of elements with
1775 : // transforms along a parent chain to noticably expand this by an entire
1776 : // device pixel.
1777 0 : if (!nsDisplayTransform::UntransformRect(dirtyRect, this, nsPoint(0, 0), &dirtyRect)) {
1778 : // we have a singular transform - just grab the entire overflow rect
1779 0 : dirtyRect = GetVisualOverflowRectRelativeToSelf();
1780 : }
1781 : }
1782 0 : inTransform = true;
1783 : }
1784 :
1785 0 : if (applyClipPropClipping) {
1786 : dirtyRect.IntersectRect(dirtyRect,
1787 0 : clipPropClip - aBuilder->ToReferenceFrame(this));
1788 : }
1789 :
1790 0 : bool usingSVGEffects = nsSVGIntegrationUtils::UsingEffectsForFrame(this);
1791 0 : if (usingSVGEffects) {
1792 : dirtyRect =
1793 0 : nsSVGIntegrationUtils::GetRequiredSourceForInvalidArea(this, dirtyRect);
1794 : }
1795 :
1796 : // Mark the display list items for absolutely positioned children
1797 0 : MarkAbsoluteFramesForDisplayList(aBuilder, dirtyRect);
1798 :
1799 0 : nsDisplayListCollection set;
1800 : nsresult rv;
1801 : {
1802 0 : nsDisplayListBuilder::AutoIsRootSetter rootSetter(aBuilder, true);
1803 : nsDisplayListBuilder::AutoInTransformSetter
1804 0 : inTransformSetter(aBuilder, inTransform);
1805 0 : rv = BuildDisplayList(aBuilder, dirtyRect, set);
1806 : }
1807 0 : NS_ENSURE_SUCCESS(rv, rv);
1808 :
1809 0 : if (aBuilder->IsBackgroundOnly()) {
1810 0 : set.BlockBorderBackgrounds()->DeleteAll();
1811 0 : set.Floats()->DeleteAll();
1812 0 : set.Content()->DeleteAll();
1813 0 : set.PositionedDescendants()->DeleteAll();
1814 0 : set.Outlines()->DeleteAll();
1815 : }
1816 :
1817 : // This z-order sort also sorts secondarily by content order. We need to do
1818 : // this so that boxes produced by the same element are placed together
1819 : // in the sort. Consider a position:relative inline element that breaks
1820 : // across lines and has absolutely positioned children; all the abs-pos
1821 : // children should be z-ordered after all the boxes for the position:relative
1822 : // element itself.
1823 0 : set.PositionedDescendants()->SortByZOrder(aBuilder, GetContent());
1824 :
1825 0 : nsRect overflowClip;
1826 0 : if (ApplyOverflowClipping(aBuilder, this, disp, &overflowClip)) {
1827 : nscoord radii[8];
1828 0 : this->GetPaddingBoxBorderRadii(radii);
1829 : nsOverflowClipWrapper wrapper(this, overflowClip, radii,
1830 0 : false, false);
1831 0 : rv = wrapper.WrapListsInPlace(aBuilder, this, set);
1832 0 : NS_ENSURE_SUCCESS(rv, rv);
1833 : }
1834 : // We didn't use overflowClip to restrict the dirty rect, since some of the
1835 : // descendants may not be clipped by it. Even if we end up with unnecessary
1836 : // display items, they'll be pruned during ComputeVisibility.
1837 :
1838 0 : nsDisplayList resultList;
1839 : // Now follow the rules of http://www.w3.org/TR/CSS21/zindex.html
1840 : // 1,2: backgrounds and borders
1841 0 : resultList.AppendToTop(set.BorderBackground());
1842 : // 3: negative z-index children.
1843 0 : for (;;) {
1844 0 : nsDisplayItem* item = set.PositionedDescendants()->GetBottom();
1845 0 : if (item) {
1846 0 : nsIFrame* f = item->GetUnderlyingFrame();
1847 0 : NS_ASSERTION(f, "After sorting, every item in the list should have an underlying frame");
1848 0 : if (nsLayoutUtils::GetZIndex(f) < 0) {
1849 0 : set.PositionedDescendants()->RemoveBottom();
1850 0 : resultList.AppendToTop(item);
1851 0 : continue;
1852 : }
1853 : }
1854 : break;
1855 : }
1856 : // 4: block backgrounds
1857 0 : resultList.AppendToTop(set.BlockBorderBackgrounds());
1858 : // 5: floats
1859 0 : resultList.AppendToTop(set.Floats());
1860 : // 7: general content
1861 0 : resultList.AppendToTop(set.Content());
1862 : // 7.5: outlines, in content tree order. We need to sort by content order
1863 : // because an element with outline that breaks and has children with outline
1864 : // might have placed child outline items between its own outline items.
1865 : // The element's outline items need to all come before any child outline
1866 : // items.
1867 0 : set.Outlines()->SortByContentOrder(aBuilder, GetContent());
1868 : #ifdef NS_DEBUG
1869 0 : DisplayDebugBorders(aBuilder, this, set);
1870 : #endif
1871 0 : resultList.AppendToTop(set.Outlines());
1872 : // 8, 9: non-negative z-index children
1873 0 : resultList.AppendToTop(set.PositionedDescendants());
1874 :
1875 : /* If we have absolute position clipping and we have, or will have, items to
1876 : * be clipped, wrap the list in a clip wrapper.
1877 : */
1878 0 : if (applyClipPropClipping &&
1879 0 : (!resultList.IsEmpty() || usingSVGEffects)) {
1880 0 : nsDisplayClipPropWrapper wrapper(clipPropClip);
1881 0 : nsDisplayItem* item = wrapper.WrapList(aBuilder, this, &resultList);
1882 0 : if (!item)
1883 0 : return NS_ERROR_OUT_OF_MEMORY;
1884 : // resultList was emptied
1885 0 : resultList.AppendToTop(item);
1886 : }
1887 :
1888 : /* If there are any SVG effects, wrap the list up in an SVG effects item
1889 : * (which also handles CSS group opacity). Note that we create an SVG effects
1890 : * item even if resultList is empty, since a filter can produce graphical
1891 : * output even if the element being filtered wouldn't otherwise do so.
1892 : */
1893 0 : if (usingSVGEffects) {
1894 : /* List now emptied, so add the new list to the top. */
1895 : rv = resultList.AppendNewToTop(
1896 0 : new (aBuilder) nsDisplaySVGEffects(aBuilder, this, &resultList));
1897 0 : if (NS_FAILED(rv))
1898 0 : return rv;
1899 : }
1900 : /* Else, if the list is non-empty and there is CSS group opacity without SVG
1901 : * effects, wrap it up in an opacity item.
1902 : */
1903 0 : else if (disp->mOpacity < 1.0f && !resultList.IsEmpty()) {
1904 : rv = resultList.AppendNewToTop(
1905 0 : new (aBuilder) nsDisplayOpacity(aBuilder, this, &resultList));
1906 0 : if (NS_FAILED(rv))
1907 0 : return rv;
1908 : }
1909 :
1910 : /* If we're going to apply a transformation and don't have preserve-3d set, wrap
1911 : * everything in an nsDisplayTransform. If there's nothing in the list, don't add
1912 : * anything.
1913 : *
1914 : * For the preserve-3d case we want to individually wrap every child in the list with
1915 : * a separate nsDisplayTransform instead. When the child is already an nsDisplayTransform,
1916 : * we can skip this step, as the computed transform will already include our own.
1917 : *
1918 : * We also traverse into sublists created by nsDisplayWrapList or nsDisplayOpacity, so that
1919 : * we find all the correct children.
1920 : */
1921 0 : if ((mState & NS_FRAME_MAY_BE_TRANSFORMED) &&
1922 0 : disp->HasTransform() && !resultList.IsEmpty()) {
1923 0 : if (Preserves3DChildren()) {
1924 0 : rv = WrapPreserve3DList(this, aBuilder, &resultList);
1925 0 : if (NS_FAILED(rv))
1926 0 : return rv;
1927 : } else {
1928 : rv = resultList.AppendNewToTop(
1929 0 : new (aBuilder) nsDisplayTransform(aBuilder, this, &resultList));
1930 0 : if (NS_FAILED(rv))
1931 0 : return rv;
1932 : }
1933 : }
1934 :
1935 0 : aList->AppendToTop(&resultList);
1936 0 : return rv;
1937 : }
1938 :
1939 : nsresult
1940 0 : nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
1941 : nsIFrame* aChild,
1942 : const nsRect& aDirtyRect,
1943 : const nsDisplayListSet& aLists,
1944 : PRUint32 aFlags) {
1945 : // If painting is restricted to just the background of the top level frame,
1946 : // then we have nothing to do here.
1947 0 : if (aBuilder->IsBackgroundOnly())
1948 0 : return NS_OK;
1949 :
1950 0 : nsIFrame* child = aChild;
1951 0 : if (child->GetStateBits() & NS_FRAME_TOO_DEEP_IN_FRAME_TREE)
1952 0 : return NS_OK;
1953 :
1954 : // true if this is a real or pseudo stacking context
1955 : bool pseudoStackingContext =
1956 0 : (aFlags & DISPLAY_CHILD_FORCE_PSEUDO_STACKING_CONTEXT) != 0;
1957 0 : if ((aFlags & DISPLAY_CHILD_INLINE) &&
1958 0 : !child->IsFrameOfType(eLineParticipant)) {
1959 : // child is a non-inline frame in an inline context, i.e.,
1960 : // it acts like inline-block or inline-table. Therefore it is a
1961 : // pseudo-stacking-context.
1962 0 : pseudoStackingContext = true;
1963 : }
1964 :
1965 : // dirty rect in child-relative coordinates
1966 0 : nsRect dirty = aDirtyRect - child->GetOffsetTo(this);
1967 :
1968 0 : nsIAtom* childType = child->GetType();
1969 0 : if (childType == nsGkAtoms::placeholderFrame) {
1970 0 : nsPlaceholderFrame* placeholder = static_cast<nsPlaceholderFrame*>(child);
1971 0 : child = placeholder->GetOutOfFlowFrame();
1972 0 : NS_ASSERTION(child, "No out of flow frame?");
1973 : // If 'child' is a pushed float then it's owned by a block that's not an
1974 : // ancestor of the placeholder, and it will be painted by that block and
1975 : // should not be painted through the placeholder.
1976 0 : if (!child || nsLayoutUtils::IsPopup(child) ||
1977 0 : (child->GetStateBits() & NS_FRAME_IS_PUSHED_FLOAT))
1978 0 : return NS_OK;
1979 : // Make sure that any attempt to use childType below is disappointed. We
1980 : // could call GetType again but since we don't currently need it, let's
1981 : // avoid the virtual call.
1982 0 : childType = nsnull;
1983 : // Recheck NS_FRAME_TOO_DEEP_IN_FRAME_TREE
1984 0 : if (child->GetStateBits() & NS_FRAME_TOO_DEEP_IN_FRAME_TREE)
1985 0 : return NS_OK;
1986 : nsRect* savedDirty = static_cast<nsRect*>
1987 0 : (child->Properties().Get(nsDisplayListBuilder::OutOfFlowDirtyRectProperty()));
1988 0 : if (savedDirty) {
1989 0 : dirty = *savedDirty;
1990 : } else {
1991 : // The out-of-flow frame did not intersect the dirty area. We may still
1992 : // need to traverse into it, since it may contain placeholders we need
1993 : // to enter to reach other out-of-flow frames that are visible.
1994 0 : dirty.SetEmpty();
1995 : }
1996 0 : pseudoStackingContext = true;
1997 : }
1998 :
1999 : // Mark the display list items for absolutely positioned children
2000 0 : child->MarkAbsoluteFramesForDisplayList(aBuilder, dirty);
2001 :
2002 0 : if (childType != nsGkAtoms::placeholderFrame &&
2003 0 : aBuilder->GetSelectedFramesOnly() &&
2004 0 : child->IsLeaf() &&
2005 0 : !aChild->IsSelected()) {
2006 0 : return NS_OK;
2007 : }
2008 :
2009 0 : if (aBuilder->GetIncludeAllOutOfFlows() &&
2010 0 : (child->GetStateBits() & NS_FRAME_OUT_OF_FLOW)) {
2011 0 : dirty = child->GetVisualOverflowRect();
2012 0 : } else if (!(child->GetStateBits() & NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO)) {
2013 : // No need to descend into child to catch placeholders for visible
2014 : // positioned stuff. So see if we can short-circuit frame traversal here.
2015 :
2016 : // We can stop if child's frame subtree's intersection with the
2017 : // dirty area is empty.
2018 : // If the child is a scrollframe that we want to ignore, then we need
2019 : // to descend into it because its scrolled child may intersect the dirty
2020 : // area even if the scrollframe itself doesn't.
2021 0 : if (child != aBuilder->GetIgnoreScrollFrame()) {
2022 0 : nsRect childDirty;
2023 0 : if (!childDirty.IntersectRect(dirty, child->GetVisualOverflowRect()))
2024 0 : return NS_OK;
2025 : // Usually we could set dirty to childDirty now but there's no
2026 : // benefit, and it can be confusing. It can especially confuse
2027 : // situations where we're going to ignore a scrollframe's clipping;
2028 : // we wouldn't want to clip the dirty area to the scrollframe's
2029 : // bounds in that case.
2030 : }
2031 : }
2032 :
2033 : // XXX need to have inline-block and inline-table set pseudoStackingContext
2034 :
2035 0 : const nsStyleDisplay* ourDisp = GetStyleDisplay();
2036 : // REVIEW: Taken from nsBoxFrame::Paint
2037 : // Don't paint our children if the theme object is a leaf.
2038 0 : if (IsThemed(ourDisp) &&
2039 0 : !PresContext()->GetTheme()->WidgetIsContainer(ourDisp->mAppearance))
2040 0 : return NS_OK;
2041 :
2042 : // Child is composited if it's transformed, partially transparent, or has
2043 : // SVG effects.
2044 0 : const nsStyleDisplay* disp = child->GetStyleDisplay();
2045 : bool isVisuallyAtomic = disp->mOpacity != 1.0f
2046 0 : || child->IsTransformed()
2047 0 : || nsSVGIntegrationUtils::UsingEffectsForFrame(child);
2048 :
2049 0 : bool isPositioned = disp->IsPositioned();
2050 0 : if (isVisuallyAtomic || isPositioned || disp->IsFloating() ||
2051 : (aFlags & DISPLAY_CHILD_FORCE_STACKING_CONTEXT)) {
2052 : // If you change this, also change IsPseudoStackingContextFromStyle()
2053 0 : pseudoStackingContext = true;
2054 : }
2055 :
2056 0 : nsRect overflowClip;
2057 : nscoord overflowClipRadii[8];
2058 : bool applyOverflowClip =
2059 0 : ApplyOverflowClipping(aBuilder, child, disp, &overflowClip);
2060 0 : if (applyOverflowClip) {
2061 0 : child->GetPaddingBoxBorderRadii(overflowClipRadii);
2062 : }
2063 : // Don't use overflowClip to restrict the dirty rect, since some of the
2064 : // descendants may not be clipped by it. Even if we end up with unnecessary
2065 : // display items, they'll be pruned during ComputeVisibility. Note that
2066 : // this overflow-clipping here only applies to overflow:-moz-hidden-unscrollable;
2067 : // overflow:hidden etc creates an nsHTML/XULScrollFrame which does its own
2068 : // clipping.
2069 :
2070 0 : nsDisplayListBuilder::AutoIsRootSetter rootSetter(aBuilder, pseudoStackingContext);
2071 : nsresult rv;
2072 0 : if (!pseudoStackingContext) {
2073 : // THIS IS THE COMMON CASE.
2074 : // Not a pseudo or real stacking context. Do the simple thing and
2075 : // return early.
2076 0 : if (applyOverflowClip) {
2077 : rv = BuildDisplayListWithOverflowClip(aBuilder, child, dirty, aLists,
2078 0 : overflowClip, overflowClipRadii);
2079 : } else {
2080 0 : rv = child->BuildDisplayList(aBuilder, dirty, aLists);
2081 0 : if (NS_SUCCEEDED(rv)) {
2082 0 : rv = aBuilder->DisplayCaret(child, dirty, aLists.Content());
2083 : }
2084 : }
2085 : #ifdef NS_DEBUG
2086 0 : DisplayDebugBorders(aBuilder, child, aLists);
2087 : #endif
2088 0 : return rv;
2089 : }
2090 :
2091 0 : nsDisplayList list;
2092 0 : nsDisplayList extraPositionedDescendants;
2093 0 : const nsStylePosition* pos = child->GetStylePosition();
2094 0 : if ((isPositioned && pos->mZIndex.GetUnit() == eStyleUnit_Integer) ||
2095 : isVisuallyAtomic || (aFlags & DISPLAY_CHILD_FORCE_STACKING_CONTEXT)) {
2096 : // True stacking context
2097 0 : rv = child->BuildDisplayListForStackingContext(aBuilder, dirty, &list);
2098 0 : if (NS_SUCCEEDED(rv)) {
2099 0 : rv = aBuilder->DisplayCaret(child, dirty, &list);
2100 : }
2101 : } else {
2102 0 : nsRect clipRect;
2103 : bool applyClipPropClipping =
2104 0 : ApplyClipPropClipping(aBuilder, disp, child, &clipRect);
2105 : // A pseudo-stacking context (e.g., a positioned element with z-index auto).
2106 : // We allow positioned descendants of the child to escape to our parent
2107 : // stacking context's positioned descendant list, because they might be
2108 : // z-index:non-auto
2109 0 : nsDisplayListCollection pseudoStack;
2110 0 : nsRect clippedDirtyRect = dirty;
2111 0 : if (applyClipPropClipping) {
2112 : // clipRect is in builder-reference-frame coordinates,
2113 : // dirty/clippedDirtyRect are in child coordinates
2114 : clippedDirtyRect.IntersectRect(clippedDirtyRect,
2115 0 : clipRect - aBuilder->ToReferenceFrame(child));
2116 : }
2117 :
2118 0 : if (applyOverflowClip) {
2119 : rv = BuildDisplayListWithOverflowClip(aBuilder, child, clippedDirtyRect,
2120 : pseudoStack, overflowClip,
2121 0 : overflowClipRadii);
2122 : } else {
2123 0 : rv = child->BuildDisplayList(aBuilder, clippedDirtyRect, pseudoStack);
2124 0 : if (NS_SUCCEEDED(rv)) {
2125 0 : rv = aBuilder->DisplayCaret(child, dirty, pseudoStack.Content());
2126 : }
2127 : }
2128 :
2129 0 : if (NS_SUCCEEDED(rv)) {
2130 0 : if (applyClipPropClipping) {
2131 0 : nsDisplayClipPropWrapper wrapper(clipRect);
2132 0 : rv = wrapper.WrapListsInPlace(aBuilder, child, pseudoStack);
2133 : }
2134 : }
2135 0 : list.AppendToTop(pseudoStack.BorderBackground());
2136 0 : list.AppendToTop(pseudoStack.BlockBorderBackgrounds());
2137 0 : list.AppendToTop(pseudoStack.Floats());
2138 0 : list.AppendToTop(pseudoStack.Content());
2139 0 : list.AppendToTop(pseudoStack.Outlines());
2140 0 : extraPositionedDescendants.AppendToTop(pseudoStack.PositionedDescendants());
2141 : #ifdef NS_DEBUG
2142 0 : DisplayDebugBorders(aBuilder, child, aLists);
2143 : #endif
2144 : }
2145 0 : NS_ENSURE_SUCCESS(rv, rv);
2146 :
2147 0 : if (isPositioned || isVisuallyAtomic ||
2148 : (aFlags & DISPLAY_CHILD_FORCE_STACKING_CONTEXT)) {
2149 : // Genuine stacking contexts, and positioned pseudo-stacking-contexts,
2150 : // go in this level.
2151 : rv = aLists.PositionedDescendants()->AppendNewToTop(new (aBuilder)
2152 0 : nsDisplayWrapList(aBuilder, child, &list));
2153 0 : NS_ENSURE_SUCCESS(rv, rv);
2154 0 : } else if (disp->IsFloating()) {
2155 : rv = aLists.Floats()->AppendNewToTop(new (aBuilder)
2156 0 : nsDisplayWrapList(aBuilder, child, &list));
2157 0 : NS_ENSURE_SUCCESS(rv, rv);
2158 : } else {
2159 0 : aLists.Content()->AppendToTop(&list);
2160 : }
2161 : // We delay placing the positioned descendants of positioned frames to here,
2162 : // because in the absence of z-index this is the correct order for them.
2163 : // This doesn't affect correctness because the positioned descendants list
2164 : // is sorted by z-order and content in BuildDisplayListForStackingContext,
2165 : // but it means that sort routine needs to do less work.
2166 0 : aLists.PositionedDescendants()->AppendToTop(&extraPositionedDescendants);
2167 0 : return NS_OK;
2168 : }
2169 :
2170 : void
2171 0 : nsIFrame::MarkAbsoluteFramesForDisplayList(nsDisplayListBuilder* aBuilder,
2172 : const nsRect& aDirtyRect)
2173 : {
2174 0 : if (IsAbsoluteContainer()) {
2175 0 : aBuilder->MarkFramesForDisplayList(this, GetAbsoluteContainingBlock()->GetChildList(), aDirtyRect);
2176 : }
2177 0 : }
2178 :
2179 : void
2180 0 : nsIFrame::WrapReplacedContentForBorderRadius(nsDisplayListBuilder* aBuilder,
2181 : nsDisplayList* aFromList,
2182 : const nsDisplayListSet& aToLists)
2183 : {
2184 : nscoord radii[8];
2185 0 : if (GetContentBoxBorderRadii(radii)) {
2186 : // If we have a border-radius, we have to clip our content to that
2187 : // radius.
2188 0 : nsDisplayListCollection set;
2189 0 : set.Content()->AppendToTop(aFromList);
2190 0 : nsRect clipRect = GetContentRect() - GetPosition() +
2191 0 : aBuilder->ToReferenceFrame(this);
2192 0 : OverflowClip(aBuilder, set, aToLists, clipRect, radii, false, true);
2193 :
2194 : return;
2195 : }
2196 :
2197 0 : aToLists.Content()->AppendToTop(aFromList);
2198 : }
2199 :
2200 : NS_IMETHODIMP
2201 0 : nsFrame::GetContentForEvent(nsEvent* aEvent,
2202 : nsIContent** aContent)
2203 : {
2204 0 : nsIFrame* f = nsLayoutUtils::GetNonGeneratedAncestor(this);
2205 0 : *aContent = f->GetContent();
2206 0 : NS_IF_ADDREF(*aContent);
2207 0 : return NS_OK;
2208 : }
2209 :
2210 : void
2211 0 : nsFrame::FireDOMEvent(const nsAString& aDOMEventName, nsIContent *aContent)
2212 : {
2213 0 : nsIContent* target = aContent ? aContent : mContent;
2214 :
2215 0 : if (target) {
2216 : nsRefPtr<nsAsyncDOMEvent> event =
2217 0 : new nsAsyncDOMEvent(target, aDOMEventName, true, false);
2218 0 : if (NS_FAILED(event->PostDOMEvent()))
2219 0 : NS_WARNING("Failed to dispatch nsAsyncDOMEvent");
2220 : }
2221 0 : }
2222 :
2223 : NS_IMETHODIMP
2224 0 : nsFrame::HandleEvent(nsPresContext* aPresContext,
2225 : nsGUIEvent* aEvent,
2226 : nsEventStatus* aEventStatus)
2227 : {
2228 :
2229 0 : if (aEvent->message == NS_MOUSE_MOVE) {
2230 0 : return HandleDrag(aPresContext, aEvent, aEventStatus);
2231 : }
2232 :
2233 0 : if (aEvent->eventStructType == NS_MOUSE_EVENT &&
2234 : static_cast<nsMouseEvent*>(aEvent)->button == nsMouseEvent::eLeftButton) {
2235 0 : if (aEvent->message == NS_MOUSE_BUTTON_DOWN) {
2236 0 : HandlePress(aPresContext, aEvent, aEventStatus);
2237 0 : } else if (aEvent->message == NS_MOUSE_BUTTON_UP) {
2238 0 : HandleRelease(aPresContext, aEvent, aEventStatus);
2239 : }
2240 : }
2241 0 : return NS_OK;
2242 : }
2243 :
2244 : NS_IMETHODIMP
2245 0 : nsFrame::GetDataForTableSelection(const nsFrameSelection *aFrameSelection,
2246 : nsIPresShell *aPresShell, nsMouseEvent *aMouseEvent,
2247 : nsIContent **aParentContent, PRInt32 *aContentOffset, PRInt32 *aTarget)
2248 : {
2249 0 : if (!aFrameSelection || !aPresShell || !aMouseEvent || !aParentContent || !aContentOffset || !aTarget)
2250 0 : return NS_ERROR_NULL_POINTER;
2251 :
2252 0 : *aParentContent = nsnull;
2253 0 : *aContentOffset = 0;
2254 0 : *aTarget = 0;
2255 :
2256 0 : PRInt16 displaySelection = aPresShell->GetSelectionFlags();
2257 :
2258 0 : bool selectingTableCells = aFrameSelection->GetTableCellSelection();
2259 :
2260 : // DISPLAY_ALL means we're in an editor.
2261 : // If already in cell selection mode,
2262 : // continue selecting with mouse drag or end on mouse up,
2263 : // or when using shift key to extend block of cells
2264 : // (Mouse down does normal selection unless Ctrl/Cmd is pressed)
2265 : bool doTableSelection =
2266 : displaySelection == nsISelectionDisplay::DISPLAY_ALL && selectingTableCells &&
2267 : (aMouseEvent->message == NS_MOUSE_MOVE ||
2268 : (aMouseEvent->message == NS_MOUSE_BUTTON_UP &&
2269 : aMouseEvent->button == nsMouseEvent::eLeftButton) ||
2270 0 : aMouseEvent->isShift);
2271 :
2272 0 : if (!doTableSelection)
2273 : {
2274 : // In Browser, special 'table selection' key must be pressed for table selection
2275 : // or when just Shift is pressed and we're already in table/cell selection mode
2276 : #ifdef XP_MACOSX
2277 : doTableSelection = aMouseEvent->isMeta || (aMouseEvent->isShift && selectingTableCells);
2278 : #else
2279 0 : doTableSelection = aMouseEvent->isControl || (aMouseEvent->isShift && selectingTableCells);
2280 : #endif
2281 : }
2282 0 : if (!doTableSelection)
2283 0 : return NS_OK;
2284 :
2285 : // Get the cell frame or table frame (or parent) of the current content node
2286 0 : nsIFrame *frame = this;
2287 0 : bool foundCell = false;
2288 0 : bool foundTable = false;
2289 :
2290 : // Get the limiting node to stop parent frame search
2291 0 : nsIContent* limiter = aFrameSelection->GetLimiter();
2292 :
2293 : // If our content node is an ancestor of the limiting node,
2294 : // we should stop the search right now.
2295 0 : if (limiter && nsContentUtils::ContentIsDescendantOf(limiter, GetContent()))
2296 0 : return NS_OK;
2297 :
2298 : //We don't initiate row/col selection from here now,
2299 : // but we may in future
2300 : //bool selectColumn = false;
2301 : //bool selectRow = false;
2302 :
2303 0 : while (frame)
2304 : {
2305 : // Check for a table cell by querying to a known CellFrame interface
2306 0 : nsITableCellLayout *cellElement = do_QueryFrame(frame);
2307 0 : if (cellElement)
2308 : {
2309 0 : foundCell = true;
2310 : //TODO: If we want to use proximity to top or left border
2311 : // for row and column selection, this is the place to do it
2312 0 : break;
2313 : }
2314 : else
2315 : {
2316 : // If not a cell, check for table
2317 : // This will happen when starting frame is the table or child of a table,
2318 : // such as a row (we were inbetween cells or in table border)
2319 0 : nsITableLayout *tableElement = do_QueryFrame(frame);
2320 0 : if (tableElement)
2321 : {
2322 0 : foundTable = true;
2323 : //TODO: How can we select row when along left table edge
2324 : // or select column when along top edge?
2325 0 : break;
2326 : } else {
2327 0 : frame = frame->GetParent();
2328 : // Stop if we have hit the selection's limiting content node
2329 0 : if (frame && frame->GetContent() == limiter)
2330 0 : break;
2331 : }
2332 : }
2333 : }
2334 : // We aren't in a cell or table
2335 0 : if (!foundCell && !foundTable) return NS_OK;
2336 :
2337 0 : nsIContent* tableOrCellContent = frame->GetContent();
2338 0 : if (!tableOrCellContent) return NS_ERROR_FAILURE;
2339 :
2340 0 : nsCOMPtr<nsIContent> parentContent = tableOrCellContent->GetParent();
2341 0 : if (!parentContent) return NS_ERROR_FAILURE;
2342 :
2343 0 : PRInt32 offset = parentContent->IndexOf(tableOrCellContent);
2344 : // Not likely?
2345 0 : if (offset < 0) return NS_ERROR_FAILURE;
2346 :
2347 : // Everything is OK -- set the return values
2348 0 : *aParentContent = parentContent;
2349 0 : NS_ADDREF(*aParentContent);
2350 :
2351 0 : *aContentOffset = offset;
2352 :
2353 : #if 0
2354 : if (selectRow)
2355 : *aTarget = nsISelectionPrivate::TABLESELECTION_ROW;
2356 : else if (selectColumn)
2357 : *aTarget = nsISelectionPrivate::TABLESELECTION_COLUMN;
2358 : else
2359 : #endif
2360 0 : if (foundCell)
2361 0 : *aTarget = nsISelectionPrivate::TABLESELECTION_CELL;
2362 0 : else if (foundTable)
2363 0 : *aTarget = nsISelectionPrivate::TABLESELECTION_TABLE;
2364 :
2365 0 : return NS_OK;
2366 : }
2367 :
2368 : NS_IMETHODIMP
2369 0 : nsFrame::IsSelectable(bool* aSelectable, PRUint8* aSelectStyle) const
2370 : {
2371 0 : if (!aSelectable) //it's ok if aSelectStyle is null
2372 0 : return NS_ERROR_NULL_POINTER;
2373 :
2374 : // Like 'visibility', we must check all the parents: if a parent
2375 : // is not selectable, none of its children is selectable.
2376 : //
2377 : // The -moz-all value acts similarly: if a frame has 'user-select:-moz-all',
2378 : // all its children are selectable, even those with 'user-select:none'.
2379 : //
2380 : // As a result, if 'none' and '-moz-all' are not present in the frame hierarchy,
2381 : // aSelectStyle returns the first style that is not AUTO. If these values
2382 : // are present in the frame hierarchy, aSelectStyle returns the style of the
2383 : // topmost parent that has either 'none' or '-moz-all'.
2384 : //
2385 : // For instance, if the frame hierarchy is:
2386 : // AUTO -> _MOZ_ALL -> NONE -> TEXT, the returned value is _MOZ_ALL
2387 : // TEXT -> NONE -> AUTO -> _MOZ_ALL, the returned value is NONE
2388 : // _MOZ_ALL -> TEXT -> AUTO -> AUTO, the returned value is _MOZ_ALL
2389 : // AUTO -> CELL -> TEXT -> AUTO, the returned value is TEXT
2390 : //
2391 0 : PRUint8 selectStyle = NS_STYLE_USER_SELECT_AUTO;
2392 0 : nsIFrame* frame = (nsIFrame*)this;
2393 :
2394 0 : while (frame) {
2395 0 : const nsStyleUIReset* userinterface = frame->GetStyleUIReset();
2396 0 : switch (userinterface->mUserSelect) {
2397 : case NS_STYLE_USER_SELECT_ALL:
2398 : case NS_STYLE_USER_SELECT_NONE:
2399 : case NS_STYLE_USER_SELECT_MOZ_ALL:
2400 : // override the previous values
2401 0 : selectStyle = userinterface->mUserSelect;
2402 0 : break;
2403 : default:
2404 : // otherwise return the first value which is not 'auto'
2405 0 : if (selectStyle == NS_STYLE_USER_SELECT_AUTO) {
2406 0 : selectStyle = userinterface->mUserSelect;
2407 : }
2408 0 : break;
2409 : }
2410 0 : frame = frame->GetParent();
2411 : }
2412 :
2413 : // convert internal values to standard values
2414 0 : if (selectStyle == NS_STYLE_USER_SELECT_AUTO)
2415 0 : selectStyle = NS_STYLE_USER_SELECT_TEXT;
2416 : else
2417 0 : if (selectStyle == NS_STYLE_USER_SELECT_MOZ_ALL)
2418 0 : selectStyle = NS_STYLE_USER_SELECT_ALL;
2419 : else
2420 0 : if (selectStyle == NS_STYLE_USER_SELECT_MOZ_NONE)
2421 0 : selectStyle = NS_STYLE_USER_SELECT_NONE;
2422 :
2423 : // return stuff
2424 0 : if (aSelectStyle)
2425 0 : *aSelectStyle = selectStyle;
2426 0 : if (mState & NS_FRAME_GENERATED_CONTENT)
2427 0 : *aSelectable = false;
2428 : else
2429 0 : *aSelectable = (selectStyle != NS_STYLE_USER_SELECT_NONE);
2430 0 : return NS_OK;
2431 : }
2432 :
2433 : /**
2434 : * Handles the Mouse Press Event for the frame
2435 : */
2436 : NS_IMETHODIMP
2437 0 : nsFrame::HandlePress(nsPresContext* aPresContext,
2438 : nsGUIEvent* aEvent,
2439 : nsEventStatus* aEventStatus)
2440 : {
2441 0 : NS_ENSURE_ARG_POINTER(aEventStatus);
2442 0 : if (nsEventStatus_eConsumeNoDefault == *aEventStatus) {
2443 0 : return NS_OK;
2444 : }
2445 :
2446 : //We often get out of sync state issues with mousedown events that
2447 : //get interrupted by alerts/dialogs.
2448 : //Check with the ESM to see if we should process this one
2449 0 : if (!aPresContext->EventStateManager()->EventStatusOK(aEvent))
2450 0 : return NS_OK;
2451 :
2452 : nsresult rv;
2453 0 : nsIPresShell *shell = aPresContext->GetPresShell();
2454 0 : if (!shell)
2455 0 : return NS_ERROR_FAILURE;
2456 :
2457 : // if we are in Navigator and the click is in a draggable node, we don't want
2458 : // to start selection because we don't want to interfere with a potential
2459 : // drag of said node and steal all its glory.
2460 0 : PRInt16 isEditor = shell->GetSelectionFlags();
2461 : //weaaak. only the editor can display frame selection not just text and images
2462 0 : isEditor = isEditor == nsISelectionDisplay::DISPLAY_ALL;
2463 :
2464 0 : nsInputEvent* keyEvent = (nsInputEvent*)aEvent;
2465 0 : if (!keyEvent->isAlt) {
2466 :
2467 0 : for (nsIContent* content = mContent; content;
2468 0 : content = content->GetParent()) {
2469 0 : if (nsContentUtils::ContentIsDraggable(content) &&
2470 0 : !content->IsEditable()) {
2471 : // coordinate stuff is the fix for bug #55921
2472 0 : if ((mRect - GetPosition()).Contains(
2473 0 : nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, this)))
2474 0 : return NS_OK;
2475 : }
2476 : }
2477 : }
2478 :
2479 : // check whether style allows selection
2480 : // if not, don't tell selection the mouse event even occurred.
2481 : bool selectable;
2482 : PRUint8 selectStyle;
2483 0 : rv = IsSelectable(&selectable, &selectStyle);
2484 0 : if (NS_FAILED(rv)) return rv;
2485 :
2486 : // check for select: none
2487 0 : if (!selectable)
2488 0 : return NS_OK;
2489 :
2490 : // When implementing NS_STYLE_USER_SELECT_ELEMENT, NS_STYLE_USER_SELECT_ELEMENTS and
2491 : // NS_STYLE_USER_SELECT_TOGGLE, need to change this logic
2492 0 : bool useFrameSelection = (selectStyle == NS_STYLE_USER_SELECT_TEXT);
2493 :
2494 : // If the mouse is dragged outside the nearest enclosing scrollable area
2495 : // while making a selection, the area will be scrolled. To do this, capture
2496 : // the mouse on the nearest scrollable frame. If there isn't a scrollable
2497 : // frame, or something else is already capturing the mouse, there's no
2498 : // reason to capture.
2499 0 : if (!nsIPresShell::GetCapturingContent()) {
2500 0 : nsIFrame* checkFrame = this;
2501 0 : nsIScrollableFrame *scrollFrame = nsnull;
2502 0 : while (checkFrame) {
2503 0 : scrollFrame = do_QueryFrame(checkFrame);
2504 0 : if (scrollFrame) {
2505 0 : nsIPresShell::SetCapturingContent(checkFrame->GetContent(), CAPTURE_IGNOREALLOWED);
2506 0 : break;
2507 : }
2508 0 : checkFrame = checkFrame->GetParent();
2509 : }
2510 : }
2511 :
2512 : // XXX This is screwy; it really should use the selection frame, not the
2513 : // event frame
2514 0 : const nsFrameSelection* frameselection = nsnull;
2515 0 : if (useFrameSelection)
2516 0 : frameselection = GetConstFrameSelection();
2517 : else
2518 0 : frameselection = shell->ConstFrameSelection();
2519 :
2520 0 : if (!frameselection || frameselection->GetDisplaySelection() == nsISelectionController::SELECTION_OFF)
2521 0 : return NS_OK;//nothing to do we cannot affect selection from here
2522 :
2523 0 : nsMouseEvent *me = (nsMouseEvent *)aEvent;
2524 :
2525 : #ifdef XP_MACOSX
2526 : if (me->isControl)
2527 : return NS_OK;//short circuit. hard coded for mac due to time restraints.
2528 : bool control = me->isMeta;
2529 : #else
2530 0 : bool control = me->isControl;
2531 : #endif
2532 :
2533 0 : nsRefPtr<nsFrameSelection> fc = const_cast<nsFrameSelection*>(frameselection);
2534 0 : if (me->clickCount > 1)
2535 : {
2536 : // These methods aren't const but can't actually delete anything,
2537 : // so no need for nsWeakFrame.
2538 0 : fc->SetMouseDownState(true);
2539 0 : fc->SetMouseDoubleDown(true);
2540 0 : return HandleMultiplePress(aPresContext, aEvent, aEventStatus, control);
2541 : }
2542 :
2543 0 : nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, this);
2544 0 : ContentOffsets offsets = GetContentOffsetsFromPoint(pt);
2545 :
2546 0 : if (!offsets.content)
2547 0 : return NS_ERROR_FAILURE;
2548 :
2549 : // On touchables devices, touch the screen is usually a pan action,
2550 : // so let reposition the caret if needed but do not select text
2551 0 : if (Preferences::GetBool("browser.ignoreNativeFrameTextSelection", false)) {
2552 0 : return fc->HandleClick(offsets.content, offsets.StartOffset(),
2553 0 : offsets.EndOffset(), false, false,
2554 0 : offsets.associateWithNext);
2555 : }
2556 :
2557 : // Let Ctrl/Cmd+mouse down do table selection instead of drag initiation
2558 0 : nsCOMPtr<nsIContent>parentContent;
2559 : PRInt32 contentOffset;
2560 : PRInt32 target;
2561 0 : rv = GetDataForTableSelection(frameselection, shell, me, getter_AddRefs(parentContent), &contentOffset, &target);
2562 0 : if (NS_SUCCEEDED(rv) && parentContent)
2563 : {
2564 0 : fc->SetMouseDownState(true);
2565 0 : return fc->HandleTableSelection(parentContent, contentOffset, target, me);
2566 : }
2567 :
2568 0 : fc->SetDelayedCaretData(0);
2569 :
2570 : // Check if any part of this frame is selected, and if the
2571 : // user clicked inside the selected region. If so, we delay
2572 : // starting a new selection since the user may be trying to
2573 : // drag the selected region to some other app.
2574 :
2575 0 : SelectionDetails *details = 0;
2576 0 : if (GetContent()->IsSelectionDescendant())
2577 : {
2578 0 : bool inSelection = false;
2579 : details = frameselection->LookUpSelection(offsets.content, 0,
2580 0 : offsets.EndOffset(), false);
2581 :
2582 : //
2583 : // If there are any details, check to see if the user clicked
2584 : // within any selected region of the frame.
2585 : //
2586 :
2587 0 : SelectionDetails *curDetail = details;
2588 :
2589 0 : while (curDetail)
2590 : {
2591 : //
2592 : // If the user clicked inside a selection, then just
2593 : // return without doing anything. We will handle placing
2594 : // the caret later on when the mouse is released. We ignore
2595 : // the spellcheck, find and url formatting selections.
2596 : //
2597 0 : if (curDetail->mType != nsISelectionController::SELECTION_SPELLCHECK &&
2598 : curDetail->mType != nsISelectionController::SELECTION_FIND &&
2599 : curDetail->mType != nsISelectionController::SELECTION_URLSECONDARY &&
2600 0 : curDetail->mStart <= offsets.StartOffset() &&
2601 0 : offsets.EndOffset() <= curDetail->mEnd)
2602 : {
2603 0 : inSelection = true;
2604 : }
2605 :
2606 0 : SelectionDetails *nextDetail = curDetail->mNext;
2607 0 : delete curDetail;
2608 0 : curDetail = nextDetail;
2609 : }
2610 :
2611 0 : if (inSelection) {
2612 0 : fc->SetMouseDownState(false);
2613 0 : fc->SetDelayedCaretData(me);
2614 0 : return NS_OK;
2615 : }
2616 : }
2617 :
2618 0 : fc->SetMouseDownState(true);
2619 :
2620 : // Do not touch any nsFrame members after this point without adding
2621 : // weakFrame checks.
2622 0 : rv = fc->HandleClick(offsets.content, offsets.StartOffset(),
2623 0 : offsets.EndOffset(), me->isShift, control,
2624 0 : offsets.associateWithNext);
2625 :
2626 0 : if (NS_FAILED(rv))
2627 0 : return rv;
2628 :
2629 0 : if (offsets.offset != offsets.secondaryOffset)
2630 0 : fc->MaintainSelection();
2631 :
2632 0 : if (isEditor && !me->isShift &&
2633 0 : (offsets.EndOffset() - offsets.StartOffset()) == 1)
2634 : {
2635 : // A single node is selected and we aren't extending an existing
2636 : // selection, which means the user clicked directly on an object (either
2637 : // -moz-user-select: all or a non-text node without children).
2638 : // Therefore, disable selection extension during mouse moves.
2639 : // XXX This is a bit hacky; shouldn't editor be able to deal with this?
2640 0 : fc->SetMouseDownState(false);
2641 : }
2642 :
2643 0 : return rv;
2644 : }
2645 :
2646 : /**
2647 : * Multiple Mouse Press -- line or paragraph selection -- for the frame.
2648 : * Wouldn't it be nice if this didn't have to be hardwired into Frame code?
2649 : */
2650 : NS_IMETHODIMP
2651 0 : nsFrame::HandleMultiplePress(nsPresContext* aPresContext,
2652 : nsGUIEvent* aEvent,
2653 : nsEventStatus* aEventStatus,
2654 : bool aControlHeld)
2655 : {
2656 0 : NS_ENSURE_ARG_POINTER(aEventStatus);
2657 0 : if (nsEventStatus_eConsumeNoDefault == *aEventStatus) {
2658 0 : return NS_OK;
2659 : }
2660 :
2661 0 : if (DisplaySelection(aPresContext) == nsISelectionController::SELECTION_OFF) {
2662 0 : return NS_OK;
2663 : }
2664 :
2665 : // Find out whether we're doing line or paragraph selection.
2666 : // If browser.triple_click_selects_paragraph is true, triple-click selects paragraph.
2667 : // Otherwise, triple-click selects line, and quadruple-click selects paragraph
2668 : // (on platforms that support quadruple-click).
2669 : nsSelectionAmount beginAmount, endAmount;
2670 0 : nsMouseEvent *me = (nsMouseEvent *)aEvent;
2671 0 : if (!me) return NS_OK;
2672 :
2673 0 : if (me->clickCount == 4) {
2674 0 : beginAmount = endAmount = eSelectParagraph;
2675 0 : } else if (me->clickCount == 3) {
2676 0 : if (Preferences::GetBool("browser.triple_click_selects_paragraph")) {
2677 0 : beginAmount = endAmount = eSelectParagraph;
2678 : } else {
2679 0 : beginAmount = eSelectBeginLine;
2680 0 : endAmount = eSelectEndLine;
2681 : }
2682 0 : } else if (me->clickCount == 2) {
2683 : // We only want inline frames; PeekBackwardAndForward dislikes blocks
2684 0 : beginAmount = endAmount = eSelectWord;
2685 : } else {
2686 0 : return NS_OK;
2687 : }
2688 :
2689 0 : nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, this);
2690 0 : ContentOffsets offsets = GetContentOffsetsFromPoint(pt);
2691 0 : if (!offsets.content) return NS_ERROR_FAILURE;
2692 :
2693 : nsIFrame* theFrame;
2694 : PRInt32 offset;
2695 : // Maybe make this a static helper?
2696 : const nsFrameSelection* frameSelection =
2697 0 : PresContext()->GetPresShell()->ConstFrameSelection();
2698 : theFrame = frameSelection->
2699 : GetFrameForNodeOffset(offsets.content, offsets.offset,
2700 : nsFrameSelection::HINT(offsets.associateWithNext),
2701 0 : &offset);
2702 0 : if (!theFrame)
2703 0 : return NS_ERROR_FAILURE;
2704 :
2705 0 : nsFrame* frame = static_cast<nsFrame*>(theFrame);
2706 :
2707 : return frame->PeekBackwardAndForward(beginAmount, endAmount,
2708 : offsets.offset, aPresContext,
2709 : beginAmount != eSelectWord,
2710 0 : aControlHeld);
2711 : }
2712 :
2713 : NS_IMETHODIMP
2714 0 : nsFrame::PeekBackwardAndForward(nsSelectionAmount aAmountBack,
2715 : nsSelectionAmount aAmountForward,
2716 : PRInt32 aStartPos,
2717 : nsPresContext* aPresContext,
2718 : bool aJumpLines,
2719 : bool aMultipleSelection)
2720 : {
2721 0 : nsIFrame* baseFrame = this;
2722 0 : PRInt32 baseOffset = aStartPos;
2723 : nsresult rv;
2724 :
2725 0 : if (aAmountBack == eSelectWord) {
2726 : // To avoid selecting the previous word when at start of word,
2727 : // first move one character forward.
2728 0 : nsPeekOffsetStruct pos;
2729 : pos.SetData(eSelectCharacter,
2730 : eDirNext,
2731 : aStartPos,
2732 : 0,
2733 : aJumpLines,
2734 : true, //limit on scrolled views
2735 : false,
2736 0 : false);
2737 0 : rv = PeekOffset(&pos);
2738 0 : if (NS_SUCCEEDED(rv)) {
2739 0 : baseFrame = pos.mResultFrame;
2740 0 : baseOffset = pos.mContentOffset;
2741 : }
2742 : }
2743 :
2744 : // Use peek offset one way then the other:
2745 0 : nsPeekOffsetStruct startpos;
2746 : startpos.SetData(aAmountBack,
2747 : eDirPrevious,
2748 : baseOffset,
2749 : 0,
2750 : aJumpLines,
2751 : true, //limit on scrolled views
2752 : false,
2753 0 : false);
2754 0 : rv = baseFrame->PeekOffset(&startpos);
2755 0 : if (NS_FAILED(rv))
2756 0 : return rv;
2757 :
2758 0 : nsPeekOffsetStruct endpos;
2759 : endpos.SetData(aAmountForward,
2760 : eDirNext,
2761 : aStartPos,
2762 : 0,
2763 : aJumpLines,
2764 : true, //limit on scrolled views
2765 : false,
2766 0 : false);
2767 0 : rv = PeekOffset(&endpos);
2768 0 : if (NS_FAILED(rv))
2769 0 : return rv;
2770 :
2771 : // Keep frameSelection alive.
2772 0 : nsRefPtr<nsFrameSelection> frameSelection = GetFrameSelection();
2773 :
2774 : rv = frameSelection->HandleClick(startpos.mResultContent,
2775 : startpos.mContentOffset, startpos.mContentOffset,
2776 : false, aMultipleSelection,
2777 0 : nsFrameSelection::HINTRIGHT);
2778 0 : if (NS_FAILED(rv))
2779 0 : return rv;
2780 :
2781 : rv = frameSelection->HandleClick(endpos.mResultContent,
2782 : endpos.mContentOffset, endpos.mContentOffset,
2783 : true, false,
2784 0 : nsFrameSelection::HINTLEFT);
2785 0 : if (NS_FAILED(rv))
2786 0 : return rv;
2787 :
2788 : // maintain selection
2789 0 : return frameSelection->MaintainSelection(aAmountBack);
2790 : }
2791 :
2792 0 : NS_IMETHODIMP nsFrame::HandleDrag(nsPresContext* aPresContext,
2793 : nsGUIEvent* aEvent,
2794 : nsEventStatus* aEventStatus)
2795 : {
2796 : bool selectable;
2797 : PRUint8 selectStyle;
2798 0 : IsSelectable(&selectable, &selectStyle);
2799 : // XXX Do we really need to exclude non-selectable content here?
2800 : // GetContentOffsetsFromPoint can handle it just fine, although some
2801 : // other stuff might not like it.
2802 0 : if (!selectable)
2803 0 : return NS_OK;
2804 0 : if (DisplaySelection(aPresContext) == nsISelectionController::SELECTION_OFF) {
2805 0 : return NS_OK;
2806 : }
2807 0 : nsIPresShell *presShell = aPresContext->PresShell();
2808 :
2809 0 : nsRefPtr<nsFrameSelection> frameselection = GetFrameSelection();
2810 0 : bool mouseDown = frameselection->GetMouseDownState();
2811 0 : if (!mouseDown)
2812 0 : return NS_OK;
2813 :
2814 0 : frameselection->StopAutoScrollTimer();
2815 :
2816 : // Check if we are dragging in a table cell
2817 0 : nsCOMPtr<nsIContent> parentContent;
2818 : PRInt32 contentOffset;
2819 : PRInt32 target;
2820 0 : nsMouseEvent *me = (nsMouseEvent *)aEvent;
2821 : nsresult result;
2822 : result = GetDataForTableSelection(frameselection, presShell, me,
2823 0 : getter_AddRefs(parentContent),
2824 0 : &contentOffset, &target);
2825 :
2826 0 : nsWeakFrame weakThis = this;
2827 0 : if (NS_SUCCEEDED(result) && parentContent) {
2828 0 : frameselection->HandleTableSelection(parentContent, contentOffset, target, me);
2829 : } else {
2830 0 : nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, this);
2831 0 : frameselection->HandleDrag(this, pt);
2832 : }
2833 :
2834 : // The frameselection object notifies selection listeners synchronously above
2835 : // which might have killed us.
2836 0 : if (!weakThis.IsAlive()) {
2837 0 : return NS_OK;
2838 : }
2839 :
2840 : // get the nearest scrollframe
2841 0 : nsIFrame* checkFrame = this;
2842 0 : nsIScrollableFrame *scrollFrame = nsnull;
2843 0 : while (checkFrame) {
2844 0 : scrollFrame = do_QueryFrame(checkFrame);
2845 0 : if (scrollFrame) {
2846 0 : break;
2847 : }
2848 0 : checkFrame = checkFrame->GetParent();
2849 : }
2850 :
2851 0 : if (scrollFrame) {
2852 0 : nsIFrame* capturingFrame = scrollFrame->GetScrolledFrame();
2853 0 : if (capturingFrame) {
2854 : nsPoint pt =
2855 0 : nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, capturingFrame);
2856 0 : frameselection->StartAutoScrollTimer(capturingFrame, pt, 30);
2857 : }
2858 : }
2859 :
2860 0 : return NS_OK;
2861 : }
2862 :
2863 : /**
2864 : * This static method handles part of the nsFrame::HandleRelease in a way
2865 : * which doesn't rely on the nsFrame object to stay alive.
2866 : */
2867 : static nsresult
2868 0 : HandleFrameSelection(nsFrameSelection* aFrameSelection,
2869 : nsIFrame::ContentOffsets& aOffsets,
2870 : bool aHandleTableSel,
2871 : PRInt32 aContentOffsetForTableSel,
2872 : PRInt32 aTargetForTableSel,
2873 : nsIContent* aParentContentForTableSel,
2874 : nsGUIEvent* aEvent,
2875 : nsEventStatus* aEventStatus)
2876 : {
2877 0 : if (!aFrameSelection) {
2878 0 : return NS_OK;
2879 : }
2880 :
2881 0 : nsresult rv = NS_OK;
2882 :
2883 0 : if (nsEventStatus_eConsumeNoDefault != *aEventStatus) {
2884 0 : if (!aHandleTableSel) {
2885 0 : nsMouseEvent *me = aFrameSelection->GetDelayedCaretData();
2886 0 : if (!aOffsets.content || !me) {
2887 0 : return NS_ERROR_FAILURE;
2888 : }
2889 :
2890 : // We are doing this to simulate what we would have done on HandlePress.
2891 : // We didn't do it there to give the user an opportunity to drag
2892 : // the text, but since they didn't drag, we want to place the
2893 : // caret.
2894 : // However, we'll use the mouse position from the release, since:
2895 : // * it's easier
2896 : // * that's the normal click position to use (although really, in
2897 : // the normal case, small movements that don't count as a drag
2898 : // can do selection)
2899 0 : aFrameSelection->SetMouseDownState(true);
2900 :
2901 : rv = aFrameSelection->HandleClick(aOffsets.content,
2902 0 : aOffsets.StartOffset(),
2903 0 : aOffsets.EndOffset(),
2904 : me->isShift, false,
2905 0 : aOffsets.associateWithNext);
2906 0 : if (NS_FAILED(rv)) {
2907 0 : return rv;
2908 : }
2909 0 : } else if (aParentContentForTableSel) {
2910 0 : aFrameSelection->SetMouseDownState(false);
2911 : rv = aFrameSelection->HandleTableSelection(aParentContentForTableSel,
2912 : aContentOffsetForTableSel,
2913 : aTargetForTableSel,
2914 0 : (nsMouseEvent *)aEvent);
2915 0 : if (NS_FAILED(rv)) {
2916 0 : return rv;
2917 : }
2918 : }
2919 0 : aFrameSelection->SetDelayedCaretData(0);
2920 : }
2921 :
2922 0 : aFrameSelection->SetMouseDownState(false);
2923 0 : aFrameSelection->StopAutoScrollTimer();
2924 :
2925 0 : return NS_OK;
2926 : }
2927 :
2928 0 : NS_IMETHODIMP nsFrame::HandleRelease(nsPresContext* aPresContext,
2929 : nsGUIEvent* aEvent,
2930 : nsEventStatus* aEventStatus)
2931 : {
2932 0 : nsIFrame* activeFrame = GetActiveSelectionFrame(aPresContext, this);
2933 :
2934 0 : nsCOMPtr<nsIContent> captureContent = nsIPresShell::GetCapturingContent();
2935 :
2936 : // We can unconditionally stop capturing because
2937 : // we should never be capturing when the mouse button is up
2938 0 : nsIPresShell::SetCapturingContent(nsnull, 0);
2939 :
2940 : bool selectionOff =
2941 0 : (DisplaySelection(aPresContext) == nsISelectionController::SELECTION_OFF);
2942 :
2943 0 : nsRefPtr<nsFrameSelection> frameselection;
2944 0 : ContentOffsets offsets;
2945 0 : nsCOMPtr<nsIContent> parentContent;
2946 0 : PRInt32 contentOffsetForTableSel = 0;
2947 0 : PRInt32 targetForTableSel = 0;
2948 0 : bool handleTableSelection = true;
2949 :
2950 0 : if (!selectionOff) {
2951 0 : frameselection = GetFrameSelection();
2952 0 : if (nsEventStatus_eConsumeNoDefault != *aEventStatus && frameselection) {
2953 : // Check if the frameselection recorded the mouse going down.
2954 : // If not, the user must have clicked in a part of the selection.
2955 : // Place the caret before continuing!
2956 :
2957 0 : bool mouseDown = frameselection->GetMouseDownState();
2958 0 : nsMouseEvent *me = frameselection->GetDelayedCaretData();
2959 :
2960 0 : if (!mouseDown && me && me->clickCount < 2) {
2961 0 : nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, this);
2962 0 : offsets = GetContentOffsetsFromPoint(pt);
2963 0 : handleTableSelection = false;
2964 : } else {
2965 : GetDataForTableSelection(frameselection, PresContext()->PresShell(),
2966 : (nsMouseEvent *)aEvent,
2967 0 : getter_AddRefs(parentContent),
2968 : &contentOffsetForTableSel,
2969 0 : &targetForTableSel);
2970 : }
2971 : }
2972 : }
2973 :
2974 : // We might be capturing in some other document and the event just happened to
2975 : // trickle down here. Make sure that document's frame selection is notified.
2976 : // Note, this may cause the current nsFrame object to be deleted, bug 336592.
2977 0 : nsRefPtr<nsFrameSelection> frameSelection;
2978 0 : if (activeFrame != this &&
2979 0 : static_cast<nsFrame*>(activeFrame)->DisplaySelection(activeFrame->PresContext())
2980 : != nsISelectionController::SELECTION_OFF) {
2981 0 : frameSelection = activeFrame->GetFrameSelection();
2982 : }
2983 :
2984 : // Also check the selection of the capturing content which might be in a
2985 : // different document.
2986 0 : if (!frameSelection && captureContent) {
2987 0 : nsIDocument* doc = captureContent->GetCurrentDoc();
2988 0 : if (doc) {
2989 0 : nsIPresShell* capturingShell = doc->GetShell();
2990 0 : if (capturingShell && capturingShell != PresContext()->GetPresShell()) {
2991 0 : frameSelection = capturingShell->FrameSelection();
2992 : }
2993 : }
2994 : }
2995 :
2996 0 : if (frameSelection) {
2997 0 : frameSelection->SetMouseDownState(false);
2998 0 : frameSelection->StopAutoScrollTimer();
2999 : }
3000 :
3001 : // Do not call any methods of the current object after this point!!!
3002 : // The object is perhaps dead!
3003 :
3004 : return selectionOff
3005 : ? NS_OK
3006 : : HandleFrameSelection(frameselection, offsets, handleTableSelection,
3007 : contentOffsetForTableSel, targetForTableSel,
3008 0 : parentContent, aEvent, aEventStatus);
3009 : }
3010 :
3011 0 : struct NS_STACK_CLASS FrameContentRange {
3012 0 : FrameContentRange(nsIContent* aContent, PRInt32 aStart, PRInt32 aEnd) :
3013 0 : content(aContent), start(aStart), end(aEnd) { }
3014 : nsCOMPtr<nsIContent> content;
3015 : PRInt32 start;
3016 : PRInt32 end;
3017 : };
3018 :
3019 : // Retrieve the content offsets of a frame
3020 0 : static FrameContentRange GetRangeForFrame(nsIFrame* aFrame) {
3021 0 : nsCOMPtr<nsIContent> content, parent;
3022 0 : content = aFrame->GetContent();
3023 0 : if (!content) {
3024 0 : NS_WARNING("Frame has no content");
3025 0 : return FrameContentRange(nsnull, -1, -1);
3026 : }
3027 0 : nsIAtom* type = aFrame->GetType();
3028 0 : if (type == nsGkAtoms::textFrame) {
3029 : PRInt32 offset, offsetEnd;
3030 0 : aFrame->GetOffsets(offset, offsetEnd);
3031 0 : return FrameContentRange(content, offset, offsetEnd);
3032 : }
3033 0 : if (type == nsGkAtoms::brFrame) {
3034 0 : parent = content->GetParent();
3035 0 : PRInt32 beginOffset = parent->IndexOf(content);
3036 0 : return FrameContentRange(parent, beginOffset, beginOffset);
3037 : }
3038 : // Loop to deal with anonymous content, which has no index; this loop
3039 : // probably won't run more than twice under normal conditions
3040 0 : do {
3041 0 : parent = content->GetParent();
3042 0 : if (parent) {
3043 0 : PRInt32 beginOffset = parent->IndexOf(content);
3044 0 : if (beginOffset >= 0)
3045 0 : return FrameContentRange(parent, beginOffset, beginOffset + 1);
3046 0 : content = parent;
3047 : }
3048 0 : } while (parent);
3049 :
3050 : // The root content node must act differently
3051 0 : return FrameContentRange(content, 0, content->GetChildCount());
3052 : }
3053 :
3054 : // The FrameTarget represents the closest frame to a point that can be selected
3055 : // The frame is the frame represented, frameEdge says whether one end of the
3056 : // frame is the result (in which case different handling is needed), and
3057 : // afterFrame says which end is repersented if frameEdge is true
3058 : struct FrameTarget {
3059 0 : FrameTarget(nsIFrame* aFrame, bool aFrameEdge, bool aAfterFrame,
3060 : bool aEmptyBlock = false) :
3061 : frame(aFrame), frameEdge(aFrameEdge), afterFrame(aAfterFrame),
3062 0 : emptyBlock(aEmptyBlock) { }
3063 0 : static FrameTarget Null() {
3064 0 : return FrameTarget(nsnull, false, false);
3065 : }
3066 0 : bool IsNull() {
3067 0 : return !frame;
3068 : }
3069 : nsIFrame* frame;
3070 : bool frameEdge;
3071 : bool afterFrame;
3072 : bool emptyBlock;
3073 : };
3074 :
3075 : // See function implementation for information
3076 : static FrameTarget GetSelectionClosestFrame(nsIFrame* aFrame, nsPoint aPoint);
3077 :
3078 0 : static bool SelfIsSelectable(nsIFrame* aFrame)
3079 : {
3080 0 : return !(aFrame->IsGeneratedContentFrame() ||
3081 0 : aFrame->GetStyleUIReset()->mUserSelect == NS_STYLE_USER_SELECT_NONE);
3082 : }
3083 :
3084 0 : static bool SelectionDescendToKids(nsIFrame* aFrame) {
3085 0 : PRUint8 style = aFrame->GetStyleUIReset()->mUserSelect;
3086 0 : nsIFrame* parent = aFrame->GetParent();
3087 : // If we are only near (not directly over) then don't traverse
3088 : // frames with independent selection (e.g. text and list controls)
3089 : // unless we're already inside such a frame (see bug 268497). Note that this
3090 : // prevents any of the users of this method from entering form controls.
3091 : // XXX We might want some way to allow using the up-arrow to go into a form
3092 : // control, but the focus didn't work right anyway; it'd probably be enough
3093 : // if the left and right arrows could enter textboxes (which I don't believe
3094 : // they can at the moment)
3095 0 : return !aFrame->IsGeneratedContentFrame() &&
3096 : style != NS_STYLE_USER_SELECT_ALL &&
3097 : style != NS_STYLE_USER_SELECT_NONE &&
3098 0 : ((parent->GetStateBits() & NS_FRAME_INDEPENDENT_SELECTION) ||
3099 0 : !(aFrame->GetStateBits() & NS_FRAME_INDEPENDENT_SELECTION));
3100 : }
3101 :
3102 0 : static FrameTarget GetSelectionClosestFrameForChild(nsIFrame* aChild,
3103 : nsPoint aPoint)
3104 : {
3105 0 : nsIFrame* parent = aChild->GetParent();
3106 0 : if (SelectionDescendToKids(aChild)) {
3107 0 : nsPoint pt = aPoint - aChild->GetOffsetTo(parent);
3108 0 : return GetSelectionClosestFrame(aChild, pt);
3109 : }
3110 0 : return FrameTarget(aChild, false, false);
3111 : }
3112 :
3113 : // When the cursor needs to be at the beginning of a block, it shouldn't be
3114 : // before the first child. A click on a block whose first child is a block
3115 : // should put the cursor in the child. The cursor shouldn't be between the
3116 : // blocks, because that's not where it's expected.
3117 : // Note that this method is guaranteed to succeed.
3118 0 : static FrameTarget DrillDownToSelectionFrame(nsIFrame* aFrame,
3119 : bool aEndFrame) {
3120 0 : if (SelectionDescendToKids(aFrame)) {
3121 0 : nsIFrame* result = nsnull;
3122 0 : nsIFrame *frame = aFrame->GetFirstPrincipalChild();
3123 0 : if (!aEndFrame) {
3124 0 : while (frame && (!SelfIsSelectable(frame) ||
3125 0 : frame->IsEmpty()))
3126 0 : frame = frame->GetNextSibling();
3127 0 : if (frame)
3128 0 : result = frame;
3129 : } else {
3130 : // Because the frame tree is singly linked, to find the last frame,
3131 : // we have to iterate through all the frames
3132 : // XXX I have a feeling this could be slow for long blocks, although
3133 : // I can't find any slowdowns
3134 0 : while (frame) {
3135 0 : if (!frame->IsEmpty() && SelfIsSelectable(frame))
3136 0 : result = frame;
3137 0 : frame = frame->GetNextSibling();
3138 : }
3139 : }
3140 0 : if (result)
3141 0 : return DrillDownToSelectionFrame(result, aEndFrame);
3142 : }
3143 : // If the current frame has no targetable children, target the current frame
3144 0 : return FrameTarget(aFrame, true, aEndFrame);
3145 : }
3146 :
3147 : // This method finds the closest valid FrameTarget on a given line; if there is
3148 : // no valid FrameTarget on the line, it returns a null FrameTarget
3149 0 : static FrameTarget GetSelectionClosestFrameForLine(
3150 : nsBlockFrame* aParent,
3151 : nsBlockFrame::line_iterator aLine,
3152 : nsPoint aPoint)
3153 : {
3154 0 : nsIFrame *frame = aLine->mFirstChild;
3155 : // Account for end of lines (any iterator from the block is valid)
3156 0 : if (aLine == aParent->end_lines())
3157 0 : return DrillDownToSelectionFrame(aParent, true);
3158 0 : nsIFrame *closestFromLeft = nsnull, *closestFromRight = nsnull;
3159 0 : nsRect rect = aLine->mBounds;
3160 0 : nscoord closestLeft = rect.x, closestRight = rect.XMost();
3161 0 : for (PRInt32 n = aLine->GetChildCount(); n;
3162 : --n, frame = frame->GetNextSibling()) {
3163 0 : if (!SelfIsSelectable(frame) || frame->IsEmpty())
3164 0 : continue;
3165 0 : nsRect frameRect = frame->GetRect();
3166 0 : if (aPoint.x >= frameRect.x) {
3167 0 : if (aPoint.x < frameRect.XMost()) {
3168 0 : return GetSelectionClosestFrameForChild(frame, aPoint);
3169 : }
3170 0 : if (frameRect.XMost() >= closestLeft) {
3171 0 : closestFromLeft = frame;
3172 0 : closestLeft = frameRect.XMost();
3173 : }
3174 : } else {
3175 0 : if (frameRect.x <= closestRight) {
3176 0 : closestFromRight = frame;
3177 0 : closestRight = frameRect.x;
3178 : }
3179 : }
3180 : }
3181 0 : if (!closestFromLeft && !closestFromRight) {
3182 : // We should only get here if there are no selectable frames on a line
3183 : // XXX Do we need more elaborate handling here?
3184 0 : return FrameTarget::Null();
3185 : }
3186 0 : if (closestFromLeft &&
3187 : (!closestFromRight ||
3188 0 : (abs(aPoint.x - closestLeft) <= abs(aPoint.x - closestRight)))) {
3189 0 : return GetSelectionClosestFrameForChild(closestFromLeft, aPoint);
3190 : }
3191 0 : return GetSelectionClosestFrameForChild(closestFromRight, aPoint);
3192 : }
3193 :
3194 : // This method is for the special handling we do for block frames; they're
3195 : // special because they represent paragraphs and because they are organized
3196 : // into lines, which have bounds that are not stored elsewhere in the
3197 : // frame tree. Returns a null FrameTarget for frames which are not
3198 : // blocks or blocks with no lines except editable one.
3199 0 : static FrameTarget GetSelectionClosestFrameForBlock(nsIFrame* aFrame,
3200 : nsPoint aPoint)
3201 : {
3202 0 : nsBlockFrame* bf = nsLayoutUtils::GetAsBlock(aFrame); // used only for QI
3203 0 : if (!bf)
3204 0 : return FrameTarget::Null();
3205 :
3206 : // This code searches for the correct line
3207 0 : nsBlockFrame::line_iterator firstLine = bf->begin_lines();
3208 0 : nsBlockFrame::line_iterator end = bf->end_lines();
3209 0 : if (firstLine == end) {
3210 0 : nsIContent *blockContent = aFrame->GetContent();
3211 0 : if (blockContent && blockContent->IsEditable()) {
3212 : // If the frame is ediable empty block, we should return it with empty
3213 : // flag.
3214 0 : return FrameTarget(aFrame, false, false, true);
3215 : }
3216 0 : return FrameTarget::Null();
3217 : }
3218 0 : nsBlockFrame::line_iterator curLine = firstLine;
3219 0 : nsBlockFrame::line_iterator closestLine = end;
3220 0 : while (curLine != end) {
3221 : // Check to see if our point lies with the line's Y bounds
3222 0 : nscoord y = aPoint.y - curLine->mBounds.y;
3223 0 : nscoord height = curLine->mBounds.height;
3224 0 : if (y >= 0 && y < height) {
3225 0 : closestLine = curLine;
3226 0 : break; // We found the line; stop looking
3227 : }
3228 0 : if (y < 0)
3229 0 : break;
3230 0 : ++curLine;
3231 : }
3232 :
3233 0 : if (closestLine == end) {
3234 0 : nsBlockFrame::line_iterator prevLine = curLine.prev();
3235 0 : nsBlockFrame::line_iterator nextLine = curLine;
3236 : // Avoid empty lines
3237 0 : while (nextLine != end && nextLine->IsEmpty())
3238 0 : ++nextLine;
3239 0 : while (prevLine != end && prevLine->IsEmpty())
3240 0 : --prevLine;
3241 :
3242 : // This hidden pref dictates whether a point above or below all lines comes
3243 : // up with a line or the beginning or end of the frame; 0 on Windows,
3244 : // 1 on other platforms by default at the writing of this code
3245 : PRInt32 dragOutOfFrame =
3246 0 : Preferences::GetInt("browser.drag_out_of_frame_style");
3247 :
3248 0 : if (prevLine == end) {
3249 0 : if (dragOutOfFrame == 1 || nextLine == end)
3250 0 : return DrillDownToSelectionFrame(aFrame, false);
3251 0 : closestLine = nextLine;
3252 0 : } else if (nextLine == end) {
3253 0 : if (dragOutOfFrame == 1)
3254 0 : return DrillDownToSelectionFrame(aFrame, true);
3255 0 : closestLine = prevLine;
3256 : } else { // Figure out which line is closer
3257 0 : if (aPoint.y - prevLine->mBounds.YMost() < nextLine->mBounds.y - aPoint.y)
3258 0 : closestLine = prevLine;
3259 : else
3260 0 : closestLine = nextLine;
3261 : }
3262 : }
3263 :
3264 0 : do {
3265 : FrameTarget target = GetSelectionClosestFrameForLine(bf, closestLine,
3266 0 : aPoint);
3267 0 : if (!target.IsNull())
3268 0 : return target;
3269 0 : ++closestLine;
3270 : } while (closestLine != end);
3271 : // Fall back to just targeting the last targetable place
3272 0 : return DrillDownToSelectionFrame(aFrame, true);
3273 : }
3274 :
3275 : // GetSelectionClosestFrame is the helper function that calculates the closest
3276 : // frame to the given point.
3277 : // It doesn't completely account for offset styles, so needs to be used in
3278 : // restricted environments.
3279 : // Cannot handle overlapping frames correctly, so it should receive the output
3280 : // of GetFrameForPoint
3281 : // Guaranteed to return a valid FrameTarget
3282 0 : static FrameTarget GetSelectionClosestFrame(nsIFrame* aFrame, nsPoint aPoint)
3283 : {
3284 : {
3285 : // Handle blocks; if the frame isn't a block, the method fails
3286 0 : FrameTarget target = GetSelectionClosestFrameForBlock(aFrame, aPoint);
3287 0 : if (!target.IsNull())
3288 0 : return target;
3289 : }
3290 :
3291 0 : nsIFrame *kid = aFrame->GetFirstPrincipalChild();
3292 :
3293 0 : if (kid) {
3294 : // Go through all the child frames to find the closest one
3295 :
3296 : // Large number to force the comparison to succeed
3297 0 : const nscoord HUGE_DISTANCE = nscoord_MAX;
3298 0 : nscoord closestXDistance = HUGE_DISTANCE;
3299 0 : nscoord closestYDistance = HUGE_DISTANCE;
3300 0 : nsIFrame *closestFrame = nsnull;
3301 :
3302 0 : for (; kid; kid = kid->GetNextSibling()) {
3303 0 : if (!SelfIsSelectable(kid) || kid->IsEmpty())
3304 0 : continue;
3305 :
3306 0 : nsRect rect = kid->GetRect();
3307 :
3308 0 : nscoord fromLeft = aPoint.x - rect.x;
3309 0 : nscoord fromRight = aPoint.x - rect.XMost();
3310 :
3311 : nscoord xDistance;
3312 0 : if (fromLeft >= 0 && fromRight <= 0) {
3313 0 : xDistance = 0;
3314 : } else {
3315 0 : xDistance = NS_MIN(abs(fromLeft), abs(fromRight));
3316 : }
3317 :
3318 0 : if (xDistance <= closestXDistance)
3319 : {
3320 0 : if (xDistance < closestXDistance)
3321 0 : closestYDistance = HUGE_DISTANCE;
3322 :
3323 0 : nscoord fromTop = aPoint.y - rect.y;
3324 0 : nscoord fromBottom = aPoint.y - rect.YMost();
3325 :
3326 : nscoord yDistance;
3327 0 : if (fromTop >= 0 && fromBottom <= 0)
3328 0 : yDistance = 0;
3329 : else
3330 0 : yDistance = NS_MIN(abs(fromTop), abs(fromBottom));
3331 :
3332 0 : if (yDistance < closestYDistance)
3333 : {
3334 0 : closestXDistance = xDistance;
3335 0 : closestYDistance = yDistance;
3336 0 : closestFrame = kid;
3337 : }
3338 : }
3339 : }
3340 0 : if (closestFrame)
3341 0 : return GetSelectionClosestFrameForChild(closestFrame, aPoint);
3342 : }
3343 0 : return FrameTarget(aFrame, false, false);
3344 : }
3345 :
3346 0 : nsIFrame::ContentOffsets OffsetsForSingleFrame(nsIFrame* aFrame, nsPoint aPoint)
3347 : {
3348 0 : nsIFrame::ContentOffsets offsets;
3349 0 : FrameContentRange range = GetRangeForFrame(aFrame);
3350 0 : offsets.content = range.content;
3351 : // If there are continuations (meaning it's not one rectangle), this is the
3352 : // best this function can do
3353 0 : if (aFrame->GetNextContinuation() || aFrame->GetPrevContinuation()) {
3354 0 : offsets.offset = range.start;
3355 0 : offsets.secondaryOffset = range.end;
3356 0 : offsets.associateWithNext = true;
3357 : return offsets;
3358 : }
3359 :
3360 : // Figure out whether the offsets should be over, after, or before the frame
3361 0 : nsRect rect(nsPoint(0, 0), aFrame->GetSize());
3362 :
3363 0 : bool isBlock = (aFrame->GetStyleDisplay()->mDisplay != NS_STYLE_DISPLAY_INLINE);
3364 0 : bool isRtl = (aFrame->GetStyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL);
3365 0 : if ((isBlock && rect.y < aPoint.y) ||
3366 0 : (!isBlock && ((isRtl && rect.x + rect.width / 2 > aPoint.x) ||
3367 0 : (!isRtl && rect.x + rect.width / 2 < aPoint.x)))) {
3368 0 : offsets.offset = range.end;
3369 0 : if (rect.Contains(aPoint))
3370 0 : offsets.secondaryOffset = range.start;
3371 : else
3372 0 : offsets.secondaryOffset = range.end;
3373 : } else {
3374 0 : offsets.offset = range.start;
3375 0 : if (rect.Contains(aPoint))
3376 0 : offsets.secondaryOffset = range.end;
3377 : else
3378 0 : offsets.secondaryOffset = range.start;
3379 : }
3380 0 : offsets.associateWithNext = (offsets.offset == range.start);
3381 : return offsets;
3382 : }
3383 :
3384 0 : static nsIFrame* AdjustFrameForSelectionStyles(nsIFrame* aFrame) {
3385 0 : nsIFrame* adjustedFrame = aFrame;
3386 0 : for (nsIFrame* frame = aFrame; frame; frame = frame->GetParent())
3387 : {
3388 : // These are the conditions that make all children not able to handle
3389 : // a cursor.
3390 0 : if (frame->GetStyleUIReset()->mUserSelect == NS_STYLE_USER_SELECT_NONE ||
3391 0 : frame->GetStyleUIReset()->mUserSelect == NS_STYLE_USER_SELECT_ALL ||
3392 0 : frame->IsGeneratedContentFrame()) {
3393 0 : adjustedFrame = frame;
3394 : }
3395 : }
3396 0 : return adjustedFrame;
3397 : }
3398 :
3399 :
3400 0 : nsIFrame::ContentOffsets nsIFrame::GetContentOffsetsFromPoint(nsPoint aPoint,
3401 : bool aIgnoreSelectionStyle)
3402 : {
3403 : nsIFrame *adjustedFrame;
3404 0 : if (aIgnoreSelectionStyle) {
3405 0 : adjustedFrame = this;
3406 : }
3407 : else {
3408 : // This section of code deals with special selection styles. Note that
3409 : // -moz-none and -moz-all exist, even though they don't need to be explicitly
3410 : // handled.
3411 : // The offset is forced not to end up in generated content; content offsets
3412 : // cannot represent content outside of the document's content tree.
3413 :
3414 0 : adjustedFrame = AdjustFrameForSelectionStyles(this);
3415 :
3416 : // -moz-user-select: all needs special handling, because clicking on it
3417 : // should lead to the whole frame being selected
3418 0 : if (adjustedFrame && adjustedFrame->GetStyleUIReset()->mUserSelect ==
3419 : NS_STYLE_USER_SELECT_ALL) {
3420 : return OffsetsForSingleFrame(adjustedFrame, aPoint +
3421 0 : this->GetOffsetTo(adjustedFrame));
3422 : }
3423 :
3424 : // For other cases, try to find a closest frame starting from the parent of
3425 : // the unselectable frame
3426 0 : if (adjustedFrame != this)
3427 0 : adjustedFrame = adjustedFrame->GetParent();
3428 : }
3429 :
3430 0 : nsPoint adjustedPoint = aPoint + this->GetOffsetTo(adjustedFrame);
3431 :
3432 0 : FrameTarget closest = GetSelectionClosestFrame(adjustedFrame, adjustedPoint);
3433 :
3434 0 : if (closest.emptyBlock) {
3435 0 : ContentOffsets offsets;
3436 0 : NS_ASSERTION(closest.frame,
3437 : "closest.frame must not be null when it's empty");
3438 0 : offsets.content = closest.frame->GetContent();
3439 0 : offsets.offset = 0;
3440 0 : offsets.secondaryOffset = 0;
3441 0 : offsets.associateWithNext = true;
3442 0 : return offsets;
3443 : }
3444 :
3445 : // If the correct offset is at one end of a frame, use offset-based
3446 : // calculation method
3447 0 : if (closest.frameEdge) {
3448 0 : ContentOffsets offsets;
3449 0 : FrameContentRange range = GetRangeForFrame(closest.frame);
3450 0 : offsets.content = range.content;
3451 0 : if (closest.afterFrame)
3452 0 : offsets.offset = range.end;
3453 : else
3454 0 : offsets.offset = range.start;
3455 0 : offsets.secondaryOffset = offsets.offset;
3456 0 : offsets.associateWithNext = (offsets.offset == range.start);
3457 0 : return offsets;
3458 : }
3459 0 : nsPoint pt = aPoint - closest.frame->GetOffsetTo(this);
3460 0 : return static_cast<nsFrame*>(closest.frame)->CalcContentOffsetsFromFramePoint(pt);
3461 :
3462 : // XXX should I add some kind of offset standardization?
3463 : // consider <b>xxxxx</b><i>zzzzz</i>; should any click between the last
3464 : // x and first z put the cursor in the same logical position in addition
3465 : // to the same visual position?
3466 : }
3467 :
3468 0 : nsIFrame::ContentOffsets nsFrame::CalcContentOffsetsFromFramePoint(nsPoint aPoint)
3469 : {
3470 0 : return OffsetsForSingleFrame(this, aPoint);
3471 : }
3472 :
3473 : NS_IMETHODIMP
3474 0 : nsFrame::GetCursor(const nsPoint& aPoint,
3475 : nsIFrame::Cursor& aCursor)
3476 : {
3477 0 : FillCursorInformationFromStyle(GetStyleUserInterface(), aCursor);
3478 0 : if (NS_STYLE_CURSOR_AUTO == aCursor.mCursor) {
3479 0 : aCursor.mCursor = NS_STYLE_CURSOR_DEFAULT;
3480 : }
3481 :
3482 :
3483 0 : return NS_OK;
3484 : }
3485 :
3486 : // Resize and incremental reflow
3487 :
3488 : /* virtual */ void
3489 0 : nsFrame::MarkIntrinsicWidthsDirty()
3490 : {
3491 : // This version is meant only for what used to be box-to-block adaptors.
3492 : // It should not be called by other derived classes.
3493 0 : if (IsBoxWrapped()) {
3494 0 : nsBoxLayoutMetrics *metrics = BoxMetrics();
3495 :
3496 0 : SizeNeedsRecalc(metrics->mPrefSize);
3497 0 : SizeNeedsRecalc(metrics->mMinSize);
3498 0 : SizeNeedsRecalc(metrics->mMaxSize);
3499 0 : SizeNeedsRecalc(metrics->mBlockPrefSize);
3500 0 : SizeNeedsRecalc(metrics->mBlockMinSize);
3501 0 : CoordNeedsRecalc(metrics->mFlex);
3502 0 : CoordNeedsRecalc(metrics->mAscent);
3503 : }
3504 0 : }
3505 :
3506 : /* virtual */ nscoord
3507 0 : nsFrame::GetMinWidth(nsRenderingContext *aRenderingContext)
3508 : {
3509 0 : nscoord result = 0;
3510 0 : DISPLAY_MIN_WIDTH(this, result);
3511 0 : return result;
3512 : }
3513 :
3514 : /* virtual */ nscoord
3515 0 : nsFrame::GetPrefWidth(nsRenderingContext *aRenderingContext)
3516 : {
3517 0 : nscoord result = 0;
3518 0 : DISPLAY_PREF_WIDTH(this, result);
3519 0 : return result;
3520 : }
3521 :
3522 : /* virtual */ void
3523 0 : nsFrame::AddInlineMinWidth(nsRenderingContext *aRenderingContext,
3524 : nsIFrame::InlineMinWidthData *aData)
3525 : {
3526 0 : NS_ASSERTION(GetParent(), "Must have a parent if we get here!");
3527 0 : bool canBreak = !CanContinueTextRun() &&
3528 0 : GetParent()->GetStyleText()->WhiteSpaceCanWrap();
3529 :
3530 0 : if (canBreak)
3531 0 : aData->OptionallyBreak(aRenderingContext);
3532 0 : aData->trailingWhitespace = 0;
3533 0 : aData->skipWhitespace = false;
3534 0 : aData->trailingTextFrame = nsnull;
3535 : aData->currentLine += nsLayoutUtils::IntrinsicForContainer(aRenderingContext,
3536 0 : this, nsLayoutUtils::MIN_WIDTH);
3537 0 : aData->atStartOfLine = false;
3538 0 : if (canBreak)
3539 0 : aData->OptionallyBreak(aRenderingContext);
3540 0 : }
3541 :
3542 : /* virtual */ void
3543 0 : nsFrame::AddInlinePrefWidth(nsRenderingContext *aRenderingContext,
3544 : nsIFrame::InlinePrefWidthData *aData)
3545 : {
3546 0 : aData->trailingWhitespace = 0;
3547 0 : aData->skipWhitespace = false;
3548 : nscoord myPref = nsLayoutUtils::IntrinsicForContainer(aRenderingContext,
3549 0 : this, nsLayoutUtils::PREF_WIDTH);
3550 0 : aData->currentLine = NSCoordSaturatingAdd(aData->currentLine, myPref);
3551 0 : }
3552 :
3553 : void
3554 0 : nsIFrame::InlineMinWidthData::ForceBreak(nsRenderingContext *aRenderingContext)
3555 : {
3556 0 : currentLine -= trailingWhitespace;
3557 0 : prevLines = NS_MAX(prevLines, currentLine);
3558 0 : currentLine = trailingWhitespace = 0;
3559 :
3560 0 : for (PRUint32 i = 0, i_end = floats.Length(); i != i_end; ++i) {
3561 0 : nsIFrame *floatFrame = floats[i];
3562 : nscoord float_min =
3563 : nsLayoutUtils::IntrinsicForContainer(aRenderingContext, floatFrame,
3564 0 : nsLayoutUtils::MIN_WIDTH);
3565 0 : if (float_min > prevLines)
3566 0 : prevLines = float_min;
3567 : }
3568 0 : floats.Clear();
3569 0 : trailingTextFrame = nsnull;
3570 0 : skipWhitespace = true;
3571 0 : }
3572 :
3573 : void
3574 0 : nsIFrame::InlineMinWidthData::OptionallyBreak(nsRenderingContext *aRenderingContext,
3575 : nscoord aHyphenWidth)
3576 : {
3577 0 : trailingTextFrame = nsnull;
3578 :
3579 : // If we can fit more content into a smaller width by staying on this
3580 : // line (because we're still at a negative offset due to negative
3581 : // text-indent or negative margin), don't break. Otherwise, do the
3582 : // same as ForceBreak. it doesn't really matter when we accumulate
3583 : // floats.
3584 0 : if (currentLine + aHyphenWidth < 0 || atStartOfLine)
3585 0 : return;
3586 0 : currentLine += aHyphenWidth;
3587 0 : ForceBreak(aRenderingContext);
3588 : }
3589 :
3590 : void
3591 0 : nsIFrame::InlinePrefWidthData::ForceBreak(nsRenderingContext *aRenderingContext)
3592 : {
3593 0 : if (floats.Length() != 0) {
3594 : // preferred widths accumulated for floats that have already
3595 : // been cleared past
3596 0 : nscoord floats_done = 0,
3597 : // preferred widths accumulated for floats that have not yet
3598 : // been cleared past
3599 0 : floats_cur_left = 0,
3600 0 : floats_cur_right = 0;
3601 :
3602 0 : for (PRUint32 i = 0, i_end = floats.Length(); i != i_end; ++i) {
3603 0 : nsIFrame *floatFrame = floats[i];
3604 0 : const nsStyleDisplay *floatDisp = floatFrame->GetStyleDisplay();
3605 0 : if (floatDisp->mBreakType == NS_STYLE_CLEAR_LEFT ||
3606 : floatDisp->mBreakType == NS_STYLE_CLEAR_RIGHT ||
3607 : floatDisp->mBreakType == NS_STYLE_CLEAR_LEFT_AND_RIGHT) {
3608 : nscoord floats_cur = NSCoordSaturatingAdd(floats_cur_left,
3609 0 : floats_cur_right);
3610 0 : if (floats_cur > floats_done)
3611 0 : floats_done = floats_cur;
3612 0 : if (floatDisp->mBreakType != NS_STYLE_CLEAR_RIGHT)
3613 0 : floats_cur_left = 0;
3614 0 : if (floatDisp->mBreakType != NS_STYLE_CLEAR_LEFT)
3615 0 : floats_cur_right = 0;
3616 : }
3617 :
3618 : nscoord &floats_cur = floatDisp->mFloats == NS_STYLE_FLOAT_LEFT
3619 0 : ? floats_cur_left : floats_cur_right;
3620 : nscoord floatWidth =
3621 : nsLayoutUtils::IntrinsicForContainer(aRenderingContext,
3622 : floatFrame,
3623 0 : nsLayoutUtils::PREF_WIDTH);
3624 : // Negative-width floats don't change the available space so they
3625 : // shouldn't change our intrinsic line width either.
3626 : floats_cur =
3627 0 : NSCoordSaturatingAdd(floats_cur, NS_MAX(0, floatWidth));
3628 : }
3629 :
3630 : nscoord floats_cur =
3631 0 : NSCoordSaturatingAdd(floats_cur_left, floats_cur_right);
3632 0 : if (floats_cur > floats_done)
3633 0 : floats_done = floats_cur;
3634 :
3635 0 : currentLine = NSCoordSaturatingAdd(currentLine, floats_done);
3636 :
3637 0 : floats.Clear();
3638 : }
3639 :
3640 : currentLine =
3641 0 : NSCoordSaturatingSubtract(currentLine, trailingWhitespace, nscoord_MAX);
3642 0 : prevLines = NS_MAX(prevLines, currentLine);
3643 0 : currentLine = trailingWhitespace = 0;
3644 0 : skipWhitespace = true;
3645 0 : }
3646 :
3647 : static void
3648 0 : AddCoord(const nsStyleCoord& aStyle,
3649 : nsRenderingContext* aRenderingContext,
3650 : nsIFrame* aFrame,
3651 : nscoord* aCoord, float* aPercent,
3652 : bool aClampNegativeToZero)
3653 : {
3654 0 : switch (aStyle.GetUnit()) {
3655 : case eStyleUnit_Coord: {
3656 0 : NS_ASSERTION(!aClampNegativeToZero || aStyle.GetCoordValue() >= 0,
3657 : "unexpected negative value");
3658 0 : *aCoord += aStyle.GetCoordValue();
3659 0 : return;
3660 : }
3661 : case eStyleUnit_Percent: {
3662 0 : NS_ASSERTION(!aClampNegativeToZero || aStyle.GetPercentValue() >= 0.0f,
3663 : "unexpected negative value");
3664 0 : *aPercent += aStyle.GetPercentValue();
3665 0 : return;
3666 : }
3667 : case eStyleUnit_Calc: {
3668 0 : const nsStyleCoord::Calc *calc = aStyle.GetCalcValue();
3669 0 : if (aClampNegativeToZero) {
3670 : // This is far from ideal when one is negative and one is positive.
3671 0 : *aCoord += NS_MAX(calc->mLength, 0);
3672 0 : *aPercent += NS_MAX(calc->mPercent, 0.0f);
3673 : } else {
3674 0 : *aCoord += calc->mLength;
3675 0 : *aPercent += calc->mPercent;
3676 : }
3677 0 : return;
3678 : }
3679 : default: {
3680 0 : return;
3681 : }
3682 : }
3683 : }
3684 :
3685 : /* virtual */ nsIFrame::IntrinsicWidthOffsetData
3686 0 : nsFrame::IntrinsicWidthOffsets(nsRenderingContext* aRenderingContext)
3687 : {
3688 0 : IntrinsicWidthOffsetData result;
3689 :
3690 0 : const nsStyleMargin *styleMargin = GetStyleMargin();
3691 : AddCoord(styleMargin->mMargin.GetLeft(), aRenderingContext, this,
3692 0 : &result.hMargin, &result.hPctMargin, false);
3693 : AddCoord(styleMargin->mMargin.GetRight(), aRenderingContext, this,
3694 0 : &result.hMargin, &result.hPctMargin, false);
3695 :
3696 0 : const nsStylePadding *stylePadding = GetStylePadding();
3697 : AddCoord(stylePadding->mPadding.GetLeft(), aRenderingContext, this,
3698 0 : &result.hPadding, &result.hPctPadding, true);
3699 : AddCoord(stylePadding->mPadding.GetRight(), aRenderingContext, this,
3700 0 : &result.hPadding, &result.hPctPadding, true);
3701 :
3702 0 : const nsStyleBorder *styleBorder = GetStyleBorder();
3703 0 : result.hBorder += styleBorder->GetActualBorderWidth(NS_SIDE_LEFT);
3704 0 : result.hBorder += styleBorder->GetActualBorderWidth(NS_SIDE_RIGHT);
3705 :
3706 0 : const nsStyleDisplay *disp = GetStyleDisplay();
3707 0 : if (IsThemed(disp)) {
3708 0 : nsPresContext *presContext = PresContext();
3709 :
3710 0 : nsIntMargin border;
3711 0 : presContext->GetTheme()->GetWidgetBorder(presContext->DeviceContext(),
3712 : this, disp->mAppearance,
3713 0 : &border);
3714 0 : result.hBorder = presContext->DevPixelsToAppUnits(border.LeftRight());
3715 :
3716 0 : nsIntMargin padding;
3717 0 : if (presContext->GetTheme()->GetWidgetPadding(presContext->DeviceContext(),
3718 : this, disp->mAppearance,
3719 0 : &padding)) {
3720 0 : result.hPadding = presContext->DevPixelsToAppUnits(padding.LeftRight());
3721 0 : result.hPctPadding = 0;
3722 : }
3723 : }
3724 :
3725 : return result;
3726 : }
3727 :
3728 : /* virtual */ nsIFrame::IntrinsicSize
3729 0 : nsFrame::GetIntrinsicSize()
3730 : {
3731 0 : return IntrinsicSize(); // default is width/height set to eStyleUnit_None
3732 : }
3733 :
3734 : /* virtual */ nsSize
3735 0 : nsFrame::GetIntrinsicRatio()
3736 : {
3737 0 : return nsSize(0, 0);
3738 : }
3739 :
3740 : /* virtual */ nsSize
3741 0 : nsFrame::ComputeSize(nsRenderingContext *aRenderingContext,
3742 : nsSize aCBSize, nscoord aAvailableWidth,
3743 : nsSize aMargin, nsSize aBorder, nsSize aPadding,
3744 : bool aShrinkWrap)
3745 : {
3746 : nsSize result = ComputeAutoSize(aRenderingContext, aCBSize, aAvailableWidth,
3747 0 : aMargin, aBorder, aPadding, aShrinkWrap);
3748 0 : nsSize boxSizingAdjust(0,0);
3749 0 : const nsStylePosition *stylePos = GetStylePosition();
3750 :
3751 0 : switch (stylePos->mBoxSizing) {
3752 : case NS_STYLE_BOX_SIZING_BORDER:
3753 0 : boxSizingAdjust += aBorder;
3754 : // fall through
3755 : case NS_STYLE_BOX_SIZING_PADDING:
3756 0 : boxSizingAdjust += aPadding;
3757 : }
3758 : nscoord boxSizingToMarginEdgeWidth =
3759 0 : aMargin.width + aBorder.width + aPadding.width - boxSizingAdjust.width;
3760 :
3761 : // Compute width
3762 :
3763 0 : if (stylePos->mWidth.GetUnit() != eStyleUnit_Auto) {
3764 : result.width =
3765 : nsLayoutUtils::ComputeWidthValue(aRenderingContext, this,
3766 : aCBSize.width, boxSizingAdjust.width, boxSizingToMarginEdgeWidth,
3767 0 : stylePos->mWidth);
3768 : }
3769 :
3770 0 : if (stylePos->mMaxWidth.GetUnit() != eStyleUnit_None) {
3771 : nscoord maxWidth =
3772 : nsLayoutUtils::ComputeWidthValue(aRenderingContext, this,
3773 : aCBSize.width, boxSizingAdjust.width, boxSizingToMarginEdgeWidth,
3774 0 : stylePos->mMaxWidth);
3775 0 : if (maxWidth < result.width)
3776 0 : result.width = maxWidth;
3777 : }
3778 :
3779 : nscoord minWidth =
3780 : nsLayoutUtils::ComputeWidthValue(aRenderingContext, this,
3781 : aCBSize.width, boxSizingAdjust.width, boxSizingToMarginEdgeWidth,
3782 0 : stylePos->mMinWidth);
3783 0 : if (minWidth > result.width)
3784 0 : result.width = minWidth;
3785 :
3786 : // Compute height
3787 :
3788 0 : if (!nsLayoutUtils::IsAutoHeight(stylePos->mHeight, aCBSize.height)) {
3789 : result.height =
3790 0 : nsLayoutUtils::ComputeHeightValue(aCBSize.height, stylePos->mHeight) -
3791 0 : boxSizingAdjust.height;
3792 : }
3793 :
3794 0 : if (result.height != NS_UNCONSTRAINEDSIZE) {
3795 0 : if (!nsLayoutUtils::IsAutoHeight(stylePos->mMaxHeight, aCBSize.height)) {
3796 : nscoord maxHeight =
3797 0 : nsLayoutUtils::ComputeHeightValue(aCBSize.height, stylePos->mMaxHeight) -
3798 0 : boxSizingAdjust.height;
3799 0 : if (maxHeight < result.height)
3800 0 : result.height = maxHeight;
3801 : }
3802 :
3803 0 : if (!nsLayoutUtils::IsAutoHeight(stylePos->mMinHeight, aCBSize.height)) {
3804 : nscoord minHeight =
3805 0 : nsLayoutUtils::ComputeHeightValue(aCBSize.height, stylePos->mMinHeight) -
3806 0 : boxSizingAdjust.height;
3807 0 : if (minHeight > result.height)
3808 0 : result.height = minHeight;
3809 : }
3810 : }
3811 :
3812 0 : const nsStyleDisplay *disp = GetStyleDisplay();
3813 0 : if (IsThemed(disp)) {
3814 0 : nsIntSize widget(0, 0);
3815 0 : bool canOverride = true;
3816 0 : nsPresContext *presContext = PresContext();
3817 0 : presContext->GetTheme()->
3818 : GetMinimumWidgetSize(aRenderingContext, this, disp->mAppearance,
3819 0 : &widget, &canOverride);
3820 :
3821 0 : nsSize size;
3822 0 : size.width = presContext->DevPixelsToAppUnits(widget.width);
3823 0 : size.height = presContext->DevPixelsToAppUnits(widget.height);
3824 :
3825 : // GMWS() returns border-box; we need content-box
3826 0 : size.width -= aBorder.width + aPadding.width;
3827 0 : size.height -= aBorder.height + aPadding.height;
3828 :
3829 0 : if (size.height > result.height || !canOverride)
3830 0 : result.height = size.height;
3831 0 : if (size.width > result.width || !canOverride)
3832 0 : result.width = size.width;
3833 : }
3834 :
3835 0 : if (result.width < 0)
3836 0 : result.width = 0;
3837 :
3838 0 : if (result.height < 0)
3839 0 : result.height = 0;
3840 :
3841 : return result;
3842 : }
3843 :
3844 : nsRect
3845 0 : nsIFrame::ComputeTightBounds(gfxContext* aContext) const
3846 : {
3847 0 : return GetVisualOverflowRect();
3848 : }
3849 :
3850 : nsRect
3851 0 : nsFrame::ComputeSimpleTightBounds(gfxContext* aContext) const
3852 : {
3853 0 : if (GetStyleOutline()->GetOutlineStyle() != NS_STYLE_BORDER_STYLE_NONE ||
3854 0 : HasBorder() || !GetStyleBackground()->IsTransparent() ||
3855 0 : GetStyleDisplay()->mAppearance) {
3856 : // Not necessarily tight, due to clipping, negative
3857 : // outline-offset, and lots of other issues, but that's OK
3858 0 : return GetVisualOverflowRect();
3859 : }
3860 :
3861 0 : nsRect r(0, 0, 0, 0);
3862 0 : ChildListIterator lists(this);
3863 0 : for (; !lists.IsDone(); lists.Next()) {
3864 0 : nsFrameList::Enumerator childFrames(lists.CurrentList());
3865 0 : for (; !childFrames.AtEnd(); childFrames.Next()) {
3866 0 : nsIFrame* child = childFrames.get();
3867 0 : r.UnionRect(r, child->ComputeTightBounds(aContext) + child->GetPosition());
3868 : }
3869 : }
3870 0 : return r;
3871 : }
3872 :
3873 : /* virtual */ nsSize
3874 0 : nsFrame::ComputeAutoSize(nsRenderingContext *aRenderingContext,
3875 : nsSize aCBSize, nscoord aAvailableWidth,
3876 : nsSize aMargin, nsSize aBorder, nsSize aPadding,
3877 : bool aShrinkWrap)
3878 : {
3879 : // Use basic shrink-wrapping as a default implementation.
3880 0 : nsSize result(0xdeadbeef, NS_UNCONSTRAINEDSIZE);
3881 :
3882 : // don't bother setting it if the result won't be used
3883 0 : if (GetStylePosition()->mWidth.GetUnit() == eStyleUnit_Auto) {
3884 : nscoord availBased = aAvailableWidth - aMargin.width - aBorder.width -
3885 0 : aPadding.width;
3886 0 : result.width = ShrinkWidthToFit(aRenderingContext, availBased);
3887 : }
3888 : return result;
3889 : }
3890 :
3891 : nscoord
3892 0 : nsFrame::ShrinkWidthToFit(nsRenderingContext *aRenderingContext,
3893 : nscoord aWidthInCB)
3894 : {
3895 : // If we're a container for font size inflation, then shrink
3896 : // wrapping inside of us should not apply font size inflation.
3897 0 : AutoMaybeNullInflationContainer an(this);
3898 :
3899 : nscoord result;
3900 0 : nscoord minWidth = GetMinWidth(aRenderingContext);
3901 0 : if (minWidth > aWidthInCB) {
3902 0 : result = minWidth;
3903 : } else {
3904 0 : nscoord prefWidth = GetPrefWidth(aRenderingContext);
3905 0 : if (prefWidth > aWidthInCB) {
3906 0 : result = aWidthInCB;
3907 : } else {
3908 0 : result = prefWidth;
3909 : }
3910 : }
3911 0 : return result;
3912 : }
3913 :
3914 : NS_IMETHODIMP
3915 0 : nsFrame::WillReflow(nsPresContext* aPresContext)
3916 : {
3917 : #ifdef DEBUG_dbaron_off
3918 : // bug 81268
3919 : NS_ASSERTION(!(mState & NS_FRAME_IN_REFLOW),
3920 : "nsFrame::WillReflow: frame is already in reflow");
3921 : #endif
3922 :
3923 0 : NS_FRAME_TRACE_MSG(NS_FRAME_TRACE_CALLS,
3924 : ("WillReflow: oldState=%x", mState));
3925 0 : mState |= NS_FRAME_IN_REFLOW;
3926 0 : return NS_OK;
3927 : }
3928 :
3929 : NS_IMETHODIMP
3930 0 : nsFrame::DidReflow(nsPresContext* aPresContext,
3931 : const nsHTMLReflowState* aReflowState,
3932 : nsDidReflowStatus aStatus)
3933 : {
3934 0 : NS_FRAME_TRACE_MSG(NS_FRAME_TRACE_CALLS,
3935 : ("nsFrame::DidReflow: aStatus=%d", aStatus));
3936 :
3937 0 : if (NS_FRAME_REFLOW_FINISHED == aStatus) {
3938 : mState &= ~(NS_FRAME_IN_REFLOW | NS_FRAME_FIRST_REFLOW | NS_FRAME_IS_DIRTY |
3939 0 : NS_FRAME_HAS_DIRTY_CHILDREN);
3940 : }
3941 :
3942 : // Notify the percent height observer if there is a percent height.
3943 : // The observer may be able to initiate another reflow with a computed
3944 : // height. This happens in the case where a table cell has no computed
3945 : // height but can fabricate one when the cell height is known.
3946 0 : if (aReflowState && aReflowState->mPercentHeightObserver &&
3947 0 : !GetPrevInFlow()) {
3948 0 : const nsStyleCoord &height = aReflowState->mStylePosition->mHeight;
3949 0 : if (height.HasPercent()) {
3950 0 : aReflowState->mPercentHeightObserver->NotifyPercentHeight(*aReflowState);
3951 : }
3952 : }
3953 :
3954 0 : return NS_OK;
3955 : }
3956 :
3957 : void
3958 0 : nsFrame::FinishReflowWithAbsoluteFrames(nsPresContext* aPresContext,
3959 : nsHTMLReflowMetrics& aDesiredSize,
3960 : const nsHTMLReflowState& aReflowState,
3961 : nsReflowStatus& aStatus,
3962 : bool aConstrainHeight)
3963 : {
3964 0 : ReflowAbsoluteFrames(aPresContext, aDesiredSize, aReflowState, aStatus, aConstrainHeight);
3965 :
3966 0 : FinishAndStoreOverflow(&aDesiredSize);
3967 0 : }
3968 :
3969 : void
3970 0 : nsFrame::DestroyAbsoluteFrames(nsIFrame* aDestructRoot)
3971 : {
3972 0 : if (IsAbsoluteContainer()) {
3973 0 : GetAbsoluteContainingBlock()->DestroyFrames(this, aDestructRoot);
3974 : }
3975 0 : }
3976 :
3977 : void
3978 0 : nsFrame::ReflowAbsoluteFrames(nsPresContext* aPresContext,
3979 : nsHTMLReflowMetrics& aDesiredSize,
3980 : const nsHTMLReflowState& aReflowState,
3981 : nsReflowStatus& aStatus,
3982 : bool aConstrainHeight)
3983 : {
3984 0 : if (HasAbsolutelyPositionedChildren()) {
3985 0 : nsAbsoluteContainingBlock* absoluteContainer = GetAbsoluteContainingBlock();
3986 :
3987 : // Let the absolutely positioned container reflow any absolutely positioned
3988 : // child frames that need to be reflowed
3989 :
3990 : // The containing block for the abs pos kids is formed by our padding edge.
3991 : nsMargin computedBorder =
3992 0 : aReflowState.mComputedBorderPadding - aReflowState.mComputedPadding;
3993 : nscoord containingBlockWidth =
3994 0 : aDesiredSize.width - computedBorder.LeftRight();
3995 : nscoord containingBlockHeight =
3996 0 : aDesiredSize.height - computedBorder.TopBottom();
3997 :
3998 0 : nsContainerFrame* container = do_QueryFrame(this);
3999 0 : NS_ASSERTION(container, "Abs-pos children only supported on container frames for now");
4000 :
4001 : absoluteContainer->Reflow(container, aPresContext, aReflowState, aStatus,
4002 : containingBlockWidth, containingBlockHeight,
4003 : aConstrainHeight, true, true, // XXX could be optimized
4004 0 : &aDesiredSize.mOverflowAreas);
4005 : }
4006 0 : }
4007 :
4008 : /* virtual */ bool
4009 0 : nsFrame::CanContinueTextRun() const
4010 : {
4011 : // By default, a frame will *not* allow a text run to be continued
4012 : // through it.
4013 0 : return false;
4014 : }
4015 :
4016 : NS_IMETHODIMP
4017 0 : nsFrame::Reflow(nsPresContext* aPresContext,
4018 : nsHTMLReflowMetrics& aDesiredSize,
4019 : const nsHTMLReflowState& aReflowState,
4020 : nsReflowStatus& aStatus)
4021 : {
4022 0 : DO_GLOBAL_REFLOW_COUNT("nsFrame");
4023 0 : aDesiredSize.width = 0;
4024 0 : aDesiredSize.height = 0;
4025 0 : aStatus = NS_FRAME_COMPLETE;
4026 0 : NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
4027 0 : return NS_OK;
4028 : }
4029 :
4030 : NS_IMETHODIMP
4031 0 : nsFrame::CharacterDataChanged(CharacterDataChangeInfo* aInfo)
4032 : {
4033 0 : NS_NOTREACHED("should only be called for text frames");
4034 0 : return NS_OK;
4035 : }
4036 :
4037 : NS_IMETHODIMP
4038 0 : nsFrame::AttributeChanged(PRInt32 aNameSpaceID,
4039 : nsIAtom* aAttribute,
4040 : PRInt32 aModType)
4041 : {
4042 0 : return NS_OK;
4043 : }
4044 :
4045 : // Flow member functions
4046 :
4047 : nsSplittableType
4048 0 : nsFrame::GetSplittableType() const
4049 : {
4050 0 : return NS_FRAME_NOT_SPLITTABLE;
4051 : }
4052 :
4053 0 : nsIFrame* nsFrame::GetPrevContinuation() const
4054 : {
4055 0 : return nsnull;
4056 : }
4057 :
4058 0 : NS_IMETHODIMP nsFrame::SetPrevContinuation(nsIFrame* aPrevContinuation)
4059 : {
4060 : // Ignore harmless requests to set it to NULL
4061 0 : if (aPrevContinuation) {
4062 0 : NS_ERROR("not splittable");
4063 0 : return NS_ERROR_NOT_IMPLEMENTED;
4064 : }
4065 :
4066 0 : return NS_OK;
4067 : }
4068 :
4069 0 : nsIFrame* nsFrame::GetNextContinuation() const
4070 : {
4071 0 : return nsnull;
4072 : }
4073 :
4074 0 : NS_IMETHODIMP nsFrame::SetNextContinuation(nsIFrame*)
4075 : {
4076 0 : NS_ERROR("not splittable");
4077 0 : return NS_ERROR_NOT_IMPLEMENTED;
4078 : }
4079 :
4080 0 : nsIFrame* nsFrame::GetPrevInFlowVirtual() const
4081 : {
4082 0 : return nsnull;
4083 : }
4084 :
4085 0 : NS_IMETHODIMP nsFrame::SetPrevInFlow(nsIFrame* aPrevInFlow)
4086 : {
4087 : // Ignore harmless requests to set it to NULL
4088 0 : if (aPrevInFlow) {
4089 0 : NS_ERROR("not splittable");
4090 0 : return NS_ERROR_NOT_IMPLEMENTED;
4091 : }
4092 :
4093 0 : return NS_OK;
4094 : }
4095 :
4096 0 : nsIFrame* nsFrame::GetNextInFlowVirtual() const
4097 : {
4098 0 : return nsnull;
4099 : }
4100 :
4101 0 : NS_IMETHODIMP nsFrame::SetNextInFlow(nsIFrame*)
4102 : {
4103 0 : NS_ERROR("not splittable");
4104 0 : return NS_ERROR_NOT_IMPLEMENTED;
4105 : }
4106 :
4107 0 : nsIFrame* nsIFrame::GetTailContinuation()
4108 : {
4109 0 : nsIFrame* frame = this;
4110 0 : while (frame->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER) {
4111 0 : frame = frame->GetPrevContinuation();
4112 0 : NS_ASSERTION(frame, "first continuation can't be overflow container");
4113 : }
4114 0 : for (nsIFrame* next = frame->GetNextContinuation();
4115 0 : next && !(next->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER);
4116 0 : next = frame->GetNextContinuation()) {
4117 0 : frame = next;
4118 : }
4119 0 : NS_POSTCONDITION(frame, "illegal state in continuation chain.");
4120 0 : return frame;
4121 : }
4122 :
4123 0 : NS_DECLARE_FRAME_PROPERTY(ViewProperty, nsnull)
4124 :
4125 : // Associated view object
4126 : nsIView*
4127 0 : nsIFrame::GetView() const
4128 : {
4129 : // Check the frame state bit and see if the frame has a view
4130 0 : if (!(GetStateBits() & NS_FRAME_HAS_VIEW))
4131 0 : return nsnull;
4132 :
4133 : // Check for a property on the frame
4134 0 : void* value = Properties().Get(ViewProperty());
4135 0 : NS_ASSERTION(value, "frame state bit was set but frame has no view");
4136 0 : return static_cast<nsIView*>(value);
4137 : }
4138 :
4139 : /* virtual */ nsIView*
4140 0 : nsIFrame::GetViewExternal() const
4141 : {
4142 0 : return GetView();
4143 : }
4144 :
4145 : nsresult
4146 0 : nsIFrame::SetView(nsIView* aView)
4147 : {
4148 0 : if (aView) {
4149 0 : aView->SetFrame(this);
4150 :
4151 : // Set a property on the frame
4152 0 : Properties().Set(ViewProperty(), aView);
4153 :
4154 : // Set the frame state bit that says the frame has a view
4155 0 : AddStateBits(NS_FRAME_HAS_VIEW);
4156 :
4157 : // Let all of the ancestors know they have a descendant with a view.
4158 0 : for (nsIFrame* f = GetParent();
4159 0 : f && !(f->GetStateBits() & NS_FRAME_HAS_CHILD_WITH_VIEW);
4160 : f = f->GetParent())
4161 0 : f->AddStateBits(NS_FRAME_HAS_CHILD_WITH_VIEW);
4162 : }
4163 :
4164 0 : return NS_OK;
4165 : }
4166 :
4167 0 : nsIFrame* nsIFrame::GetAncestorWithViewExternal() const
4168 : {
4169 0 : return GetAncestorWithView();
4170 : }
4171 :
4172 : // Find the first geometric parent that has a view
4173 0 : nsIFrame* nsIFrame::GetAncestorWithView() const
4174 : {
4175 0 : for (nsIFrame* f = mParent; nsnull != f; f = f->GetParent()) {
4176 0 : if (f->HasView()) {
4177 0 : return f;
4178 : }
4179 : }
4180 0 : return nsnull;
4181 : }
4182 :
4183 : // virtual
4184 0 : nsPoint nsIFrame::GetOffsetToExternal(const nsIFrame* aOther) const
4185 : {
4186 0 : return GetOffsetTo(aOther);
4187 : }
4188 :
4189 0 : nsPoint nsIFrame::GetOffsetTo(const nsIFrame* aOther) const
4190 : {
4191 0 : NS_PRECONDITION(aOther,
4192 : "Must have frame for destination coordinate system!");
4193 :
4194 0 : NS_ASSERTION(PresContext() == aOther->PresContext(),
4195 : "GetOffsetTo called on frames in different documents");
4196 :
4197 0 : nsPoint offset(0, 0);
4198 : const nsIFrame* f;
4199 0 : for (f = this; f != aOther && f; f = f->GetParent()) {
4200 0 : offset += f->GetPosition();
4201 : }
4202 :
4203 0 : if (f != aOther) {
4204 : // Looks like aOther wasn't an ancestor of |this|. So now we have
4205 : // the root-frame-relative position of |this| in |offset|. Convert back
4206 : // to the coordinates of aOther
4207 0 : while (aOther) {
4208 0 : offset -= aOther->GetPosition();
4209 0 : aOther = aOther->GetParent();
4210 : }
4211 : }
4212 :
4213 : return offset;
4214 : }
4215 :
4216 0 : nsPoint nsIFrame::GetOffsetToCrossDoc(const nsIFrame* aOther) const
4217 : {
4218 0 : return GetOffsetToCrossDoc(aOther, PresContext()->AppUnitsPerDevPixel());
4219 : }
4220 :
4221 : nsPoint
4222 0 : nsIFrame::GetOffsetToCrossDoc(const nsIFrame* aOther, const PRInt32 aAPD) const
4223 : {
4224 0 : NS_PRECONDITION(aOther,
4225 : "Must have frame for destination coordinate system!");
4226 0 : NS_ASSERTION(PresContext()->GetRootPresContext() ==
4227 : aOther->PresContext()->GetRootPresContext(),
4228 : "trying to get the offset between frames in different document "
4229 : "hierarchies?");
4230 0 : if (PresContext()->GetRootPresContext() !=
4231 0 : aOther->PresContext()->GetRootPresContext()) {
4232 : // crash right away, we are almost certainly going to crash anyway.
4233 : NS_RUNTIMEABORT("trying to get the offset between frames in different "
4234 0 : "document hierarchies?");
4235 : }
4236 :
4237 0 : const nsIFrame* root = nsnull;
4238 : // offset will hold the final offset
4239 : // docOffset holds the currently accumulated offset at the current APD, it
4240 : // will be converted and added to offset when the current APD changes.
4241 0 : nsPoint offset(0, 0), docOffset(0, 0);
4242 0 : const nsIFrame* f = this;
4243 0 : PRInt32 currAPD = PresContext()->AppUnitsPerDevPixel();
4244 0 : while (f && f != aOther) {
4245 0 : docOffset += f->GetPosition();
4246 0 : nsIFrame* parent = f->GetParent();
4247 0 : if (parent) {
4248 0 : f = parent;
4249 : } else {
4250 0 : nsPoint newOffset(0, 0);
4251 0 : root = f;
4252 0 : f = nsLayoutUtils::GetCrossDocParentFrame(f, &newOffset);
4253 0 : PRInt32 newAPD = f ? f->PresContext()->AppUnitsPerDevPixel() : 0;
4254 0 : if (!f || newAPD != currAPD) {
4255 : // Convert docOffset to the right APD and add it to offset.
4256 0 : offset += docOffset.ConvertAppUnits(currAPD, aAPD);
4257 0 : docOffset.x = docOffset.y = 0;
4258 : }
4259 0 : currAPD = newAPD;
4260 0 : docOffset += newOffset;
4261 : }
4262 : }
4263 0 : if (f == aOther) {
4264 0 : offset += docOffset.ConvertAppUnits(currAPD, aAPD);
4265 : } else {
4266 : // Looks like aOther wasn't an ancestor of |this|. So now we have
4267 : // the root-document-relative position of |this| in |offset|. Subtract the
4268 : // root-document-relative position of |aOther| from |offset|.
4269 : // This call won't try to recurse again because root is an ancestor of
4270 : // aOther.
4271 0 : nsPoint negOffset = aOther->GetOffsetToCrossDoc(root, aAPD);
4272 0 : offset -= negOffset;
4273 : }
4274 :
4275 : return offset;
4276 : }
4277 :
4278 : // virtual
4279 0 : nsIntRect nsIFrame::GetScreenRectExternal() const
4280 : {
4281 0 : return GetScreenRect();
4282 : }
4283 :
4284 0 : nsIntRect nsIFrame::GetScreenRect() const
4285 : {
4286 0 : return GetScreenRectInAppUnits().ToNearestPixels(PresContext()->AppUnitsPerCSSPixel());
4287 : }
4288 :
4289 : // virtual
4290 0 : nsRect nsIFrame::GetScreenRectInAppUnitsExternal() const
4291 : {
4292 0 : return GetScreenRectInAppUnits();
4293 : }
4294 :
4295 0 : nsRect nsIFrame::GetScreenRectInAppUnits() const
4296 : {
4297 0 : nsPresContext* presContext = PresContext();
4298 : nsIFrame* rootFrame =
4299 0 : presContext->PresShell()->FrameManager()->GetRootFrame();
4300 0 : nsPoint rootScreenPos(0, 0);
4301 0 : nsPoint rootFrameOffsetInParent(0, 0);
4302 : nsIFrame* rootFrameParent =
4303 0 : nsLayoutUtils::GetCrossDocParentFrame(rootFrame, &rootFrameOffsetInParent);
4304 0 : if (rootFrameParent) {
4305 0 : nsRect parentScreenRectAppUnits = rootFrameParent->GetScreenRectInAppUnits();
4306 0 : nsPresContext* parentPresContext = rootFrameParent->PresContext();
4307 0 : double parentScale = double(presContext->AppUnitsPerDevPixel())/
4308 0 : parentPresContext->AppUnitsPerDevPixel();
4309 0 : nsPoint rootPt = parentScreenRectAppUnits.TopLeft() + rootFrameOffsetInParent;
4310 0 : rootScreenPos.x = NS_round(parentScale*rootPt.x);
4311 0 : rootScreenPos.y = NS_round(parentScale*rootPt.y);
4312 : } else {
4313 0 : nsCOMPtr<nsIWidget> rootWidget;
4314 0 : presContext->PresShell()->GetViewManager()->GetRootWidget(getter_AddRefs(rootWidget));
4315 0 : if (rootWidget) {
4316 0 : nsIntPoint rootDevPx = rootWidget->WidgetToScreenOffset();
4317 0 : rootScreenPos.x = presContext->DevPixelsToAppUnits(rootDevPx.x);
4318 0 : rootScreenPos.y = presContext->DevPixelsToAppUnits(rootDevPx.y);
4319 : }
4320 : }
4321 :
4322 0 : return nsRect(rootScreenPos + GetOffsetTo(rootFrame), GetSize());
4323 : }
4324 :
4325 : // Returns the offset from this frame to the closest geometric parent that
4326 : // has a view. Also returns the containing view or null in case of error
4327 0 : NS_IMETHODIMP nsFrame::GetOffsetFromView(nsPoint& aOffset,
4328 : nsIView** aView) const
4329 : {
4330 0 : NS_PRECONDITION(nsnull != aView, "null OUT parameter pointer");
4331 0 : nsIFrame* frame = (nsIFrame*)this;
4332 :
4333 0 : *aView = nsnull;
4334 0 : aOffset.MoveTo(0, 0);
4335 0 : do {
4336 0 : aOffset += frame->GetPosition();
4337 0 : frame = frame->GetParent();
4338 0 : } while (frame && !frame->HasView());
4339 0 : if (frame)
4340 0 : *aView = frame->GetView();
4341 0 : return NS_OK;
4342 : }
4343 :
4344 : nsIWidget*
4345 0 : nsIFrame::GetNearestWidget() const
4346 : {
4347 0 : return GetClosestView()->GetNearestWidget(nsnull);
4348 : }
4349 :
4350 : nsIWidget*
4351 0 : nsIFrame::GetNearestWidget(nsPoint& aOffset) const
4352 : {
4353 0 : nsPoint offsetToView;
4354 0 : nsPoint offsetToWidget;
4355 : nsIWidget* widget =
4356 0 : GetClosestView(&offsetToView)->GetNearestWidget(&offsetToWidget);
4357 0 : aOffset = offsetToView + offsetToWidget;
4358 0 : return widget;
4359 : }
4360 :
4361 : nsIAtom*
4362 0 : nsFrame::GetType() const
4363 : {
4364 0 : return nsnull;
4365 : }
4366 :
4367 : bool
4368 0 : nsIFrame::IsLeaf() const
4369 : {
4370 0 : return true;
4371 : }
4372 :
4373 : Layer*
4374 0 : nsIFrame::InvalidateLayer(const nsRect& aDamageRect, PRUint32 aDisplayItemKey)
4375 : {
4376 0 : NS_ASSERTION(aDisplayItemKey > 0, "Need a key");
4377 :
4378 0 : Layer* layer = FrameLayerBuilder::GetDedicatedLayer(this, aDisplayItemKey);
4379 0 : if (!layer) {
4380 0 : Invalidate(aDamageRect);
4381 0 : return nsnull;
4382 : }
4383 :
4384 0 : PRUint32 flags = INVALIDATE_NO_THEBES_LAYERS;
4385 0 : if (aDisplayItemKey == nsDisplayItem::TYPE_VIDEO ||
4386 : aDisplayItemKey == nsDisplayItem::TYPE_PLUGIN ||
4387 : aDisplayItemKey == nsDisplayItem::TYPE_CANVAS) {
4388 0 : flags |= INVALIDATE_NO_UPDATE_LAYER_TREE;
4389 : }
4390 :
4391 0 : InvalidateWithFlags(aDamageRect, flags);
4392 0 : return layer;
4393 : }
4394 :
4395 : void
4396 0 : nsIFrame::InvalidateTransformLayer()
4397 : {
4398 0 : NS_ASSERTION(mParent, "How can a viewport frame have a transform?");
4399 :
4400 : bool hasLayer =
4401 0 : FrameLayerBuilder::GetDedicatedLayer(this, nsDisplayItem::TYPE_TRANSFORM) != nsnull;
4402 : // Invalidate post-transform area in the parent. We have to invalidate
4403 : // in the parent because our transform style may have changed from what was
4404 : // used to paint this frame.
4405 : // It's OK to bypass the SVG effects processing and other processing
4406 : // performed if we called this->InvalidateWithFlags, because those effects
4407 : // are performed before applying transforms.
4408 0 : mParent->InvalidateInternal(GetVisualOverflowRect() + GetPosition(),
4409 : 0, 0, this,
4410 0 : hasLayer ? INVALIDATE_NO_THEBES_LAYERS : 0);
4411 0 : }
4412 :
4413 : class LayerActivity {
4414 : public:
4415 0 : LayerActivity(nsIFrame* aFrame) : mFrame(aFrame), mChangeHint(nsChangeHint(0)) {}
4416 : ~LayerActivity();
4417 0 : nsExpirationState* GetExpirationState() { return &mState; }
4418 :
4419 : nsIFrame* mFrame;
4420 : nsExpirationState mState;
4421 : // mChangeHint can be some combination of nsChangeHint_UpdateOpacityLayer and
4422 : // nsChangeHint_UpdateTransformLayer (or neither)
4423 : // The presence of those bits indicates whether opacity or transform
4424 : // changes have been detected.
4425 : nsChangeHint mChangeHint;
4426 : };
4427 :
4428 : class LayerActivityTracker MOZ_FINAL : public nsExpirationTracker<LayerActivity,4> {
4429 : public:
4430 : // 75-100ms is a good timeout period. We use 4 generations of 25ms each.
4431 : enum { GENERATION_MS = 100 };
4432 0 : LayerActivityTracker()
4433 0 : : nsExpirationTracker<LayerActivity,4>(GENERATION_MS) {}
4434 0 : ~LayerActivityTracker() {
4435 0 : AgeAllGenerations();
4436 0 : }
4437 :
4438 : virtual void NotifyExpired(LayerActivity* aObject);
4439 : };
4440 :
4441 : static LayerActivityTracker* gLayerActivityTracker = nsnull;
4442 :
4443 0 : LayerActivity::~LayerActivity()
4444 : {
4445 0 : if (mFrame) {
4446 0 : NS_ASSERTION(gLayerActivityTracker, "Should still have a tracker");
4447 0 : gLayerActivityTracker->RemoveObject(this);
4448 : }
4449 0 : }
4450 :
4451 0 : static void DestroyLayerActivity(void* aPropertyValue)
4452 : {
4453 0 : delete static_cast<LayerActivity*>(aPropertyValue);
4454 0 : }
4455 :
4456 0 : NS_DECLARE_FRAME_PROPERTY(LayerActivityProperty, DestroyLayerActivity)
4457 :
4458 : void
4459 0 : LayerActivityTracker::NotifyExpired(LayerActivity* aObject)
4460 : {
4461 0 : RemoveObject(aObject);
4462 :
4463 0 : nsIFrame* f = aObject->mFrame;
4464 0 : aObject->mFrame = nsnull;
4465 0 : f->Properties().Delete(LayerActivityProperty());
4466 0 : f->InvalidateFrameSubtree();
4467 0 : }
4468 :
4469 : void
4470 0 : nsIFrame::MarkLayersActive(nsChangeHint aChangeHint)
4471 : {
4472 0 : FrameProperties properties = Properties();
4473 : LayerActivity* layerActivity =
4474 0 : static_cast<LayerActivity*>(properties.Get(LayerActivityProperty()));
4475 0 : if (layerActivity) {
4476 0 : gLayerActivityTracker->MarkUsed(layerActivity);
4477 : } else {
4478 0 : if (!gLayerActivityTracker) {
4479 0 : gLayerActivityTracker = new LayerActivityTracker();
4480 : }
4481 0 : layerActivity = new LayerActivity(this);
4482 0 : gLayerActivityTracker->AddObject(layerActivity);
4483 0 : properties.Set(LayerActivityProperty(), layerActivity);
4484 : }
4485 0 : NS_UpdateHint(layerActivity->mChangeHint, aChangeHint);
4486 0 : }
4487 :
4488 : bool
4489 0 : nsIFrame::AreLayersMarkedActive()
4490 : {
4491 0 : return Properties().Get(LayerActivityProperty()) != nsnull;
4492 : }
4493 :
4494 : bool
4495 0 : nsIFrame::AreLayersMarkedActive(nsChangeHint aChangeHint)
4496 : {
4497 : LayerActivity* layerActivity =
4498 0 : static_cast<LayerActivity*>(Properties().Get(LayerActivityProperty()));
4499 0 : return layerActivity && (layerActivity->mChangeHint & aChangeHint);
4500 : }
4501 :
4502 : /* static */ void
4503 1403 : nsFrame::ShutdownLayerActivityTimer()
4504 : {
4505 1403 : delete gLayerActivityTracker;
4506 1403 : gLayerActivityTracker = nsnull;
4507 1403 : }
4508 :
4509 : void
4510 0 : nsIFrame::InvalidateWithFlags(const nsRect& aDamageRect, PRUint32 aFlags)
4511 : {
4512 0 : if (aDamageRect.IsEmpty()) {
4513 0 : return;
4514 : }
4515 :
4516 : // Don't allow invalidates to do anything when
4517 : // painting is suppressed.
4518 0 : nsIPresShell *shell = PresContext()->GetPresShell();
4519 0 : if (shell) {
4520 0 : if (shell->IsPaintingSuppressed())
4521 0 : return;
4522 : }
4523 :
4524 0 : InvalidateInternal(aDamageRect, 0, 0, nsnull, aFlags);
4525 : }
4526 :
4527 : /**
4528 : * Helper function that funnels an InvalidateInternal request up to the
4529 : * parent. This function is used so that if MOZ_SVG is not defined, we still
4530 : * have unified control paths in the InvalidateInternal chain.
4531 : *
4532 : * @param aDamageRect The rect to invalidate.
4533 : * @param aX The x offset from the origin of this frame to the rectangle.
4534 : * @param aY The y offset from the origin of this frame to the rectangle.
4535 : * @param aImmediate Whether to redraw immediately.
4536 : * @return None, though this funnels the request up to the parent frame.
4537 : */
4538 : void
4539 0 : nsIFrame::InvalidateInternalAfterResize(const nsRect& aDamageRect, nscoord aX,
4540 : nscoord aY, PRUint32 aFlags)
4541 : {
4542 : /* If we're a transformed frame, then we need to apply our transform to the
4543 : * damage rectangle so that the redraw correctly redraws the transformed
4544 : * region. We're moved over aX and aY from our origin, but since this aX
4545 : * and aY is contained within our border, we need to scoot back by -aX and
4546 : * -aY to get back to the origin of the transform.
4547 : *
4548 : * There's one more problem, though, and that's that we don't know what
4549 : * coordinate space this rectangle is in. Sometimes it's in the local
4550 : * coordinate space for the frame, and sometimes its in the transformed
4551 : * coordinate space. If we get it wrong, we'll display incorrectly. Until I
4552 : * find a better fix for this problem, we'll invalidate the union of the two
4553 : * rectangles (original rectangle and transformed rectangle). At least one of
4554 : * these will be correct.
4555 : *
4556 : * When we are preserving-3d, we can have arbitrary hierarchies of preserved 3d
4557 : * children. The computed transform on these children is relative to the root
4558 : * transform object in the hierarchy, not necessarily their direct ancestor.
4559 : * In this case we transform by the child's transform, and mark the rectangle
4560 : * as being transformed until it is passed up to the root of the hierarchy.
4561 : *
4562 : * See bug #452496 for more details.
4563 : */
4564 :
4565 : // Check the transformed flags and remove it
4566 0 : bool rectIsTransformed = (aFlags & INVALIDATE_ALREADY_TRANSFORMED);
4567 0 : if (!Preserves3D()) {
4568 : // We only want to remove the flag if we aren't preserving 3d. Otherwise
4569 : // the rect will already have been transformed into the root preserve-3d
4570 : // frame coordinate space, and we should continue passing it up without
4571 : // further transforms.
4572 0 : aFlags &= ~INVALIDATE_ALREADY_TRANSFORMED;
4573 : }
4574 :
4575 0 : if ((mState & NS_FRAME_HAS_CONTAINER_LAYER) &&
4576 0 : !(aFlags & INVALIDATE_NO_THEBES_LAYERS)) {
4577 : // XXX for now I'm going to assume this is in the local coordinate space
4578 : // This only matters for frames with transforms and retained layers,
4579 : // which can't happen right now since transforms trigger fallback
4580 : // rendering and the display items that trigger layers are nested inside
4581 : // the nsDisplayTransform
4582 : // XXX need to set INVALIDATE_NO_THEBES_LAYERS for certain kinds of
4583 : // invalidation, e.g. video update, 'opacity' change
4584 : FrameLayerBuilder::InvalidateThebesLayerContents(this,
4585 0 : aDamageRect + nsPoint(aX, aY));
4586 : // Don't need to invalidate any more Thebes layers
4587 0 : aFlags |= INVALIDATE_NO_THEBES_LAYERS;
4588 0 : if (aFlags & INVALIDATE_ONLY_THEBES_LAYERS) {
4589 0 : return;
4590 : }
4591 : }
4592 0 : if (IsTransformed() && !rectIsTransformed) {
4593 0 : nsRect newDamageRect;
4594 : newDamageRect.UnionRect(nsDisplayTransform::TransformRectOut
4595 0 : (aDamageRect, this, nsPoint(-aX, -aY)), aDamageRect);
4596 :
4597 : // If we are preserving 3d, then our computed transform includes that of any
4598 : // ancestor frames that also preserve 3d. Mark the rectangle as already being
4599 : // transformed into the parent's coordinate space.
4600 0 : if (Preserves3D()) {
4601 0 : aFlags |= INVALIDATE_ALREADY_TRANSFORMED;
4602 : }
4603 :
4604 0 : GetParent()->
4605 : InvalidateInternal(newDamageRect, aX + mRect.x, aY + mRect.y, this,
4606 0 : aFlags);
4607 : }
4608 : else
4609 0 : GetParent()->
4610 0 : InvalidateInternal(aDamageRect, aX + mRect.x, aY + mRect.y, this, aFlags);
4611 : }
4612 :
4613 : void
4614 0 : nsIFrame::InvalidateInternal(const nsRect& aDamageRect, nscoord aX, nscoord aY,
4615 : nsIFrame* aForChild, PRUint32 aFlags)
4616 : {
4617 0 : nsSVGEffects::InvalidateDirectRenderingObservers(this);
4618 0 : if (nsSVGIntegrationUtils::UsingEffectsForFrame(this)) {
4619 : nsRect r = nsSVGIntegrationUtils::GetInvalidAreaForChangedSource(this,
4620 0 : aDamageRect + nsPoint(aX, aY));
4621 : /* Rectangle is now in our own local space, so aX and aY are effectively
4622 : * zero. Thus we'll pretend that the entire time this was in our own
4623 : * local coordinate space and do any remaining processing.
4624 : */
4625 0 : InvalidateInternalAfterResize(r, 0, 0, aFlags);
4626 : return;
4627 : }
4628 :
4629 0 : InvalidateInternalAfterResize(aDamageRect, aX, aY, aFlags);
4630 : }
4631 :
4632 : gfx3DMatrix
4633 0 : nsIFrame::GetTransformMatrix(nsIFrame* aStopAtAncestor,
4634 : nsIFrame** aOutAncestor)
4635 : {
4636 0 : NS_PRECONDITION(aOutAncestor, "Need a place to put the ancestor!");
4637 :
4638 : /* If we're transformed, we want to hand back the combination
4639 : * transform/translate matrix that will apply our current transform, then
4640 : * shift us to our parent.
4641 : */
4642 0 : if (IsTransformed()) {
4643 : /* Compute the delta to the parent, which we need because we are converting
4644 : * coordinates to our parent.
4645 : */
4646 0 : NS_ASSERTION(nsLayoutUtils::GetCrossDocParentFrame(this),
4647 : "Cannot transform the viewport frame!");
4648 0 : PRInt32 scaleFactor = PresContext()->AppUnitsPerDevPixel();
4649 :
4650 : gfx3DMatrix result =
4651 : nsDisplayTransform::GetResultingTransformMatrix(this, nsPoint(0, 0),
4652 0 : scaleFactor, nsnull, aOutAncestor);
4653 0 : nsPoint delta = GetOffsetToCrossDoc(*aOutAncestor);
4654 : /* Combine the raw transform with a translation to our parent. */
4655 : result *= gfx3DMatrix::Translation
4656 : (NSAppUnitsToFloatPixels(delta.x, scaleFactor),
4657 : NSAppUnitsToFloatPixels(delta.y, scaleFactor),
4658 0 : 0.0f);
4659 0 : return result;
4660 : }
4661 :
4662 0 : *aOutAncestor = nsLayoutUtils::GetCrossDocParentFrame(this);
4663 :
4664 : /* Otherwise, we're not transformed. In that case, we'll walk up the frame
4665 : * tree until we either hit the root frame or something that may be
4666 : * transformed. We'll then change coordinates into that frame, since we're
4667 : * guaranteed that nothing in-between can be transformed. First, however,
4668 : * we have to check to see if we have a parent. If not, we'll set the
4669 : * outparam to null (indicating that there's nothing left) and will hand back
4670 : * the identity matrix.
4671 : */
4672 0 : if (!*aOutAncestor)
4673 0 : return gfx3DMatrix();
4674 :
4675 : /* Keep iterating while the frame can't possibly be transformed. */
4676 0 : while (!(*aOutAncestor)->IsTransformed() && *aOutAncestor != aStopAtAncestor) {
4677 : /* If no parent, stop iterating. Otherwise, update the ancestor. */
4678 0 : nsIFrame* parent = nsLayoutUtils::GetCrossDocParentFrame(*aOutAncestor);
4679 0 : if (!parent)
4680 0 : break;
4681 :
4682 0 : *aOutAncestor = parent;
4683 : }
4684 :
4685 0 : NS_ASSERTION(*aOutAncestor, "Somehow ended up with a null ancestor...?");
4686 :
4687 : /* Translate from this frame to our ancestor, if it exists. That's the
4688 : * entire transform, so we're done.
4689 : */
4690 0 : nsPoint delta = GetOffsetToCrossDoc(*aOutAncestor);
4691 0 : PRInt32 scaleFactor = PresContext()->AppUnitsPerDevPixel();
4692 : return gfx3DMatrix().Translation
4693 : (NSAppUnitsToFloatPixels(delta.x, scaleFactor),
4694 : NSAppUnitsToFloatPixels(delta.y, scaleFactor),
4695 0 : 0.0f);
4696 : }
4697 :
4698 : void
4699 0 : nsIFrame::InvalidateRectDifference(const nsRect& aR1, const nsRect& aR2)
4700 : {
4701 0 : nsRect sizeHStrip, sizeVStrip;
4702 0 : nsLayoutUtils::GetRectDifferenceStrips(aR1, aR2, &sizeHStrip, &sizeVStrip);
4703 0 : Invalidate(sizeVStrip);
4704 0 : Invalidate(sizeHStrip);
4705 0 : }
4706 :
4707 : void
4708 0 : nsIFrame::InvalidateFrameSubtree()
4709 : {
4710 0 : Invalidate(GetVisualOverflowRectRelativeToSelf());
4711 0 : FrameLayerBuilder::InvalidateThebesLayersInSubtree(this);
4712 0 : }
4713 :
4714 : void
4715 0 : nsIFrame::InvalidateOverflowRect()
4716 : {
4717 0 : Invalidate(GetVisualOverflowRectRelativeToSelf());
4718 0 : }
4719 :
4720 0 : NS_DECLARE_FRAME_PROPERTY(DeferInvalidatesProperty, nsIFrame::DestroyRegion)
4721 :
4722 : void
4723 0 : nsIFrame::InvalidateRoot(const nsRect& aDamageRect, PRUint32 aFlags)
4724 : {
4725 0 : NS_ASSERTION(nsLayoutUtils::GetDisplayRootFrame(this) == this,
4726 : "Can only call this on display roots");
4727 :
4728 0 : if ((mState & NS_FRAME_HAS_CONTAINER_LAYER) &&
4729 0 : !(aFlags & INVALIDATE_NO_THEBES_LAYERS)) {
4730 0 : FrameLayerBuilder::InvalidateThebesLayerContents(this, aDamageRect);
4731 0 : if (aFlags & INVALIDATE_ONLY_THEBES_LAYERS) {
4732 0 : return;
4733 : }
4734 : }
4735 :
4736 0 : nsRect rect = aDamageRect;
4737 : nsRegion* excludeRegion = static_cast<nsRegion*>
4738 0 : (Properties().Get(DeferInvalidatesProperty()));
4739 0 : if (excludeRegion && (aFlags & INVALIDATE_EXCLUDE_CURRENT_PAINT)) {
4740 0 : nsRegion r;
4741 0 : r.Sub(rect, *excludeRegion);
4742 0 : if (r.IsEmpty())
4743 : return;
4744 0 : rect = r.GetBounds();
4745 : }
4746 :
4747 0 : if (!(aFlags & INVALIDATE_NO_UPDATE_LAYER_TREE)) {
4748 0 : AddStateBits(NS_FRAME_UPDATE_LAYER_TREE);
4749 : }
4750 :
4751 0 : nsIView* view = GetView();
4752 0 : NS_ASSERTION(view, "This can only be called on frames with views");
4753 0 : view->GetViewManager()->InvalidateViewNoSuppression(view, rect);
4754 : }
4755 :
4756 : void
4757 0 : nsIFrame::BeginDeferringInvalidatesForDisplayRoot(const nsRegion& aExcludeRegion)
4758 : {
4759 0 : NS_ASSERTION(nsLayoutUtils::GetDisplayRootFrame(this) == this,
4760 : "Can only call this on display roots");
4761 0 : Properties().Set(DeferInvalidatesProperty(), new nsRegion(aExcludeRegion));
4762 0 : }
4763 :
4764 : void
4765 0 : nsIFrame::EndDeferringInvalidatesForDisplayRoot()
4766 : {
4767 0 : NS_ASSERTION(nsLayoutUtils::GetDisplayRootFrame(this) == this,
4768 : "Can only call this on display roots");
4769 0 : Properties().Delete(DeferInvalidatesProperty());
4770 0 : }
4771 :
4772 : /**
4773 : * @param aAnyOutlineOrEffects set to true if this frame has any
4774 : * outline, SVG effects or box shadows that mean we need to invalidate
4775 : * the whole overflow area if the frame's size changes.
4776 : */
4777 : static nsRect
4778 0 : ComputeOutlineAndEffectsRect(nsIFrame* aFrame, bool* aAnyOutlineOrEffects,
4779 : const nsRect& aOverflowRect,
4780 : const nsSize& aNewSize,
4781 : bool aStoreRectProperties) {
4782 0 : nsRect r = aOverflowRect;
4783 0 : *aAnyOutlineOrEffects = false;
4784 :
4785 : // box-shadow
4786 0 : nsCSSShadowArray* boxShadows = aFrame->GetStyleBorder()->mBoxShadow;
4787 0 : if (boxShadows) {
4788 0 : nsRect shadows;
4789 0 : PRInt32 A2D = aFrame->PresContext()->AppUnitsPerDevPixel();
4790 0 : for (PRUint32 i = 0; i < boxShadows->Length(); ++i) {
4791 0 : nsRect tmpRect(nsPoint(0, 0), aNewSize);
4792 0 : nsCSSShadowItem* shadow = boxShadows->ShadowAt(i);
4793 :
4794 : // inset shadows are never painted outside the frame
4795 0 : if (shadow->mInset)
4796 0 : continue;
4797 :
4798 0 : tmpRect.MoveBy(nsPoint(shadow->mXOffset, shadow->mYOffset));
4799 0 : tmpRect.Inflate(shadow->mSpread, shadow->mSpread);
4800 : tmpRect.Inflate(
4801 0 : nsContextBoxBlur::GetBlurRadiusMargin(shadow->mRadius, A2D));
4802 :
4803 0 : shadows.UnionRect(shadows, tmpRect);
4804 : }
4805 0 : r.UnionRect(r, shadows);
4806 0 : *aAnyOutlineOrEffects = true;
4807 : }
4808 :
4809 0 : const nsStyleOutline* outline = aFrame->GetStyleOutline();
4810 0 : PRUint8 outlineStyle = outline->GetOutlineStyle();
4811 0 : if (outlineStyle != NS_STYLE_BORDER_STYLE_NONE) {
4812 : nscoord width;
4813 : #ifdef DEBUG
4814 : bool result =
4815 : #endif
4816 0 : outline->GetOutlineWidth(width);
4817 0 : NS_ASSERTION(result, "GetOutlineWidth had no cached outline width");
4818 0 : if (width > 0) {
4819 0 : if (aStoreRectProperties) {
4820 : aFrame->Properties().
4821 0 : Set(nsIFrame::OutlineInnerRectProperty(), new nsRect(r));
4822 : }
4823 :
4824 0 : nscoord offset = outline->mOutlineOffset;
4825 0 : nscoord inflateBy = NS_MAX(width + offset, 0);
4826 : // FIXME (bug 599652): We probably want outline to be drawn around
4827 : // something smaller than the visual overflow rect (perhaps the
4828 : // scrollable overflow rect is correct). When we change that, we
4829 : // need to keep this code (and the storing of properties just
4830 : // above) in sync with GetOutlineInnerRect in nsCSSRendering.cpp.
4831 0 : r.Inflate(inflateBy, inflateBy);
4832 0 : *aAnyOutlineOrEffects = true;
4833 : }
4834 : }
4835 :
4836 : // Note that we don't remove the outlineInnerRect if a frame loses outline
4837 : // style. That would require an extra property lookup for every frame,
4838 : // or a new frame state bit to track whether a property had been stored,
4839 : // or something like that. It's not worth doing that here. At most it's
4840 : // only one heap-allocated rect per frame and it will be cleaned up when
4841 : // the frame dies.
4842 :
4843 0 : if (nsSVGIntegrationUtils::UsingEffectsForFrame(aFrame)) {
4844 0 : *aAnyOutlineOrEffects = true;
4845 0 : if (aStoreRectProperties) {
4846 : aFrame->Properties().
4847 0 : Set(nsIFrame::PreEffectsBBoxProperty(), new nsRect(r));
4848 : }
4849 0 : r = nsSVGIntegrationUtils::ComputeFrameEffectsRect(aFrame, r);
4850 : }
4851 :
4852 : return r;
4853 : }
4854 :
4855 : nsPoint
4856 0 : nsIFrame::GetRelativeOffset(const nsStyleDisplay* aDisplay) const
4857 : {
4858 0 : if (!aDisplay || NS_STYLE_POSITION_RELATIVE == aDisplay->mPosition) {
4859 : nsPoint *offsets = static_cast<nsPoint*>
4860 0 : (Properties().Get(ComputedOffsetProperty()));
4861 0 : if (offsets) {
4862 0 : return *offsets;
4863 : }
4864 : }
4865 0 : return nsPoint(0,0);
4866 : }
4867 :
4868 : nsRect
4869 0 : nsIFrame::GetOverflowRect(nsOverflowType aType) const
4870 : {
4871 0 : NS_ABORT_IF_FALSE(aType == eVisualOverflow || aType == eScrollableOverflow,
4872 : "unexpected type");
4873 :
4874 : // Note that in some cases the overflow area might not have been
4875 : // updated (yet) to reflect any outline set on the frame or the area
4876 : // of child frames. That's OK because any reflow that updates these
4877 : // areas will invalidate the appropriate area, so any (mis)uses of
4878 : // this method will be fixed up.
4879 :
4880 0 : if (mOverflow.mType == NS_FRAME_OVERFLOW_LARGE) {
4881 : // there is an overflow rect, and it's not stored as deltas but as
4882 : // a separately-allocated rect
4883 : return static_cast<nsOverflowAreas*>(const_cast<nsIFrame*>(this)->
4884 0 : GetOverflowAreasProperty())->Overflow(aType);
4885 : }
4886 :
4887 0 : if (aType == eVisualOverflow &&
4888 : mOverflow.mType != NS_FRAME_OVERFLOW_NONE) {
4889 0 : return GetVisualOverflowFromDeltas();
4890 : }
4891 :
4892 0 : return nsRect(nsPoint(0, 0), GetSize());
4893 : }
4894 :
4895 : nsOverflowAreas
4896 0 : nsIFrame::GetOverflowAreas() const
4897 : {
4898 0 : if (mOverflow.mType == NS_FRAME_OVERFLOW_LARGE) {
4899 : // there is an overflow rect, and it's not stored as deltas but as
4900 : // a separately-allocated rect
4901 0 : return *const_cast<nsIFrame*>(this)->GetOverflowAreasProperty();
4902 : }
4903 :
4904 0 : return nsOverflowAreas(GetVisualOverflowFromDeltas(),
4905 0 : nsRect(nsPoint(0, 0), GetSize()));
4906 : }
4907 :
4908 : nsRect
4909 0 : nsIFrame::GetScrollableOverflowRectRelativeToParent() const
4910 : {
4911 0 : return GetScrollableOverflowRect() + mRect.TopLeft();
4912 : }
4913 :
4914 : nsRect
4915 0 : nsIFrame::GetVisualOverflowRectRelativeToSelf() const
4916 : {
4917 0 : if (IsTransformed()) {
4918 : nsOverflowAreas* preTransformOverflows = static_cast<nsOverflowAreas*>
4919 0 : (Properties().Get(PreTransformOverflowAreasProperty()));
4920 0 : if (preTransformOverflows)
4921 0 : return preTransformOverflows->VisualOverflow();
4922 : }
4923 0 : return GetVisualOverflowRect();
4924 : }
4925 :
4926 : /* virtual */ bool
4927 0 : nsFrame::UpdateOverflow()
4928 : {
4929 0 : nsRect rect(nsPoint(0, 0), GetSize());
4930 0 : nsOverflowAreas overflowAreas(rect, rect);
4931 :
4932 0 : bool isBox = IsBoxFrame() || IsBoxWrapped();
4933 0 : if (!isBox || (!IsCollapsed() && !DoesClipChildren())) {
4934 0 : nsLayoutUtils::UnionChildOverflow(this, overflowAreas);
4935 : }
4936 :
4937 0 : if (FinishAndStoreOverflow(overflowAreas, GetSize())) {
4938 0 : nsIView* view = GetView();
4939 0 : if (view) {
4940 0 : PRUint32 flags = 0;
4941 0 : GetLayoutFlags(flags);
4942 :
4943 0 : if ((flags & NS_FRAME_NO_SIZE_VIEW) == 0) {
4944 : // Make sure the frame's view is properly sized.
4945 0 : nsIViewManager* vm = view->GetViewManager();
4946 0 : vm->ResizeView(view, overflowAreas.VisualOverflow(), true);
4947 : }
4948 : }
4949 :
4950 0 : return true;
4951 : }
4952 :
4953 0 : return false;
4954 : }
4955 :
4956 : void
4957 0 : nsFrame::CheckInvalidateSizeChange(nsHTMLReflowMetrics& aNewDesiredSize)
4958 : {
4959 0 : nsIFrame::CheckInvalidateSizeChange(mRect, GetVisualOverflowRect(),
4960 0 : nsSize(aNewDesiredSize.width, aNewDesiredSize.height));
4961 0 : }
4962 :
4963 : static void
4964 0 : InvalidateRectForFrameSizeChange(nsIFrame* aFrame, const nsRect& aRect)
4965 : {
4966 : nsStyleContext *bgSC;
4967 0 : if (!nsCSSRendering::FindBackground(aFrame->PresContext(), aFrame, &bgSC)) {
4968 : nsIFrame* rootFrame =
4969 0 : aFrame->PresContext()->PresShell()->FrameManager()->GetRootFrame();
4970 0 : rootFrame->Invalidate(nsRect(nsPoint(0, 0), rootFrame->GetSize()));
4971 : }
4972 :
4973 0 : aFrame->Invalidate(aRect);
4974 0 : }
4975 :
4976 : void
4977 0 : nsIFrame::CheckInvalidateSizeChange(const nsRect& aOldRect,
4978 : const nsRect& aOldVisualOverflowRect,
4979 : const nsSize& aNewDesiredSize)
4980 : {
4981 0 : if (aNewDesiredSize == aOldRect.Size())
4982 0 : return;
4983 :
4984 : // Below, we invalidate the old frame area (or, in the case of
4985 : // outline, combined area) if the outline, border or background
4986 : // settings indicate that something other than the difference
4987 : // between the old and new areas needs to be painted. We are
4988 : // assuming that the difference between the old and new areas will
4989 : // be invalidated by some other means. That also means invalidating
4990 : // the old frame area is the same as invalidating the new frame area
4991 : // (since in either case the UNION of old and new areas will be
4992 : // invalidated)
4993 :
4994 : // We use InvalidateRectForFrameSizeChange throughout this method, even
4995 : // though root-invalidation is technically only needed in the case where
4996 : // layer.RenderingMightDependOnFrameSize(). This allows us to simplify the
4997 : // code somewhat and return immediately after invalidation in the earlier
4998 : // cases.
4999 :
5000 : // Invalidate the entire old frame+outline if the frame has an outline
5001 : bool anyOutlineOrEffects;
5002 : nsRect r = ComputeOutlineAndEffectsRect(this, &anyOutlineOrEffects,
5003 : aOldVisualOverflowRect,
5004 : aNewDesiredSize,
5005 0 : false);
5006 0 : if (anyOutlineOrEffects) {
5007 0 : r.UnionRect(aOldVisualOverflowRect, r);
5008 0 : InvalidateRectForFrameSizeChange(this, r);
5009 : return;
5010 : }
5011 :
5012 : // Invalidate the old frame border box if the frame has borders. Those
5013 : // borders may be moving.
5014 0 : const nsStyleBorder* border = GetStyleBorder();
5015 0 : NS_FOR_CSS_SIDES(side) {
5016 0 : if (border->GetActualBorderWidth(side) != 0) {
5017 0 : if ((side == NS_SIDE_LEFT || side == NS_SIDE_TOP) &&
5018 0 : !nsLayoutUtils::HasNonZeroCornerOnSide(border->mBorderRadius, side) &&
5019 0 : !border->GetBorderImage() &&
5020 0 : border->GetBorderStyle(side) == NS_STYLE_BORDER_STYLE_SOLID) {
5021 : // We also need to be sure that the bottom-left or top-right
5022 : // corner is simple. For example, if the bottom or right border
5023 : // has a different color, we would need to invalidate the corner
5024 : // area. But that's OK because if there is a right or bottom border,
5025 : // we'll invalidate the entire border-box here anyway.
5026 0 : continue;
5027 : }
5028 0 : InvalidateRectForFrameSizeChange(this, nsRect(0, 0, aOldRect.width, aOldRect.height));
5029 : return;
5030 : }
5031 : }
5032 :
5033 0 : const nsStyleBackground *bg = GetStyleBackground();
5034 0 : if (!bg->IsTransparent()) {
5035 : // Invalidate the old frame background if the frame has a background
5036 : // whose position depends on the size of the frame
5037 0 : NS_FOR_VISIBLE_BACKGROUND_LAYERS_BACK_TO_FRONT(i, bg) {
5038 0 : const nsStyleBackground::Layer &layer = bg->mLayers[i];
5039 0 : if (layer.RenderingMightDependOnFrameSize()) {
5040 0 : InvalidateRectForFrameSizeChange(this, nsRect(0, 0, aOldRect.width, aOldRect.height));
5041 : return;
5042 : }
5043 : }
5044 :
5045 : // Invalidate the old frame background if the frame has a background
5046 : // that is being clipped by border-radius, since the old or new area
5047 : // clipped off by the radius is not necessarily in the area that has
5048 : // already been invalidated (even if only the top-left corner has a
5049 : // border radius).
5050 0 : if (nsLayoutUtils::HasNonZeroCorner(border->mBorderRadius)) {
5051 0 : InvalidateRectForFrameSizeChange(this, nsRect(0, 0, aOldRect.width, aOldRect.height));
5052 : return;
5053 : }
5054 : }
5055 : }
5056 :
5057 : // Define the MAX_FRAME_DEPTH to be the ContentSink's MAX_REFLOW_DEPTH plus
5058 : // 4 for the frames above the document's frames:
5059 : // the Viewport, GFXScroll, ScrollPort, and Canvas
5060 : #define MAX_FRAME_DEPTH (MAX_REFLOW_DEPTH+4)
5061 :
5062 : bool
5063 0 : nsFrame::IsFrameTreeTooDeep(const nsHTMLReflowState& aReflowState,
5064 : nsHTMLReflowMetrics& aMetrics,
5065 : nsReflowStatus& aStatus)
5066 : {
5067 0 : if (aReflowState.mReflowDepth > MAX_FRAME_DEPTH) {
5068 0 : NS_WARNING("frame tree too deep; setting zero size and returning");
5069 0 : mState |= NS_FRAME_TOO_DEEP_IN_FRAME_TREE;
5070 0 : ClearOverflowRects();
5071 0 : aMetrics.width = 0;
5072 0 : aMetrics.height = 0;
5073 0 : aMetrics.ascent = 0;
5074 0 : aMetrics.mCarriedOutBottomMargin.Zero();
5075 0 : aMetrics.mOverflowAreas.Clear();
5076 :
5077 0 : if (GetNextInFlow()) {
5078 : // Reflow depth might vary between reflows, so we might have
5079 : // successfully reflowed and split this frame before. If so, we
5080 : // shouldn't delete its continuations.
5081 0 : aStatus = NS_FRAME_NOT_COMPLETE;
5082 : } else {
5083 0 : aStatus = NS_FRAME_COMPLETE;
5084 : }
5085 :
5086 0 : return true;
5087 : }
5088 0 : mState &= ~NS_FRAME_TOO_DEEP_IN_FRAME_TREE;
5089 0 : return false;
5090 : }
5091 :
5092 : bool
5093 0 : nsIFrame::IsBlockWrapper() const
5094 : {
5095 0 : nsIAtom *pseudoType = GetStyleContext()->GetPseudo();
5096 : return (pseudoType == nsCSSAnonBoxes::mozAnonymousBlock ||
5097 : pseudoType == nsCSSAnonBoxes::mozAnonymousPositionedBlock ||
5098 0 : pseudoType == nsCSSAnonBoxes::cellContent);
5099 : }
5100 :
5101 : static nsIFrame*
5102 0 : GetNearestBlockContainer(nsIFrame* frame)
5103 : {
5104 : // The block wrappers we use to wrap blocks inside inlines aren't
5105 : // described in the CSS spec. We need to make them not be containing
5106 : // blocks.
5107 : // Since the parent of such a block is either a normal block or
5108 : // another such pseudo, this shouldn't cause anything bad to happen.
5109 : // Also the anonymous blocks inside table cells are not containing blocks.
5110 0 : while (frame->IsFrameOfType(nsIFrame::eLineParticipant) ||
5111 0 : frame->IsBlockWrapper() ||
5112 : // Table rows are not containing blocks either
5113 0 : frame->GetType() == nsGkAtoms::tableRowFrame) {
5114 0 : frame = frame->GetParent();
5115 0 : NS_ASSERTION(frame, "How come we got to the root frame without seeing a containing block?");
5116 : }
5117 0 : return frame;
5118 : }
5119 :
5120 : nsIFrame*
5121 0 : nsIFrame::GetContainingBlock() const
5122 : {
5123 : // MathML frames might have absolute positioning style, but they would
5124 : // still be in-flow. So we have to check to make sure that the frame
5125 : // is really out-of-flow too.
5126 0 : if (GetStyleDisplay()->IsAbsolutelyPositioned() &&
5127 0 : (GetStateBits() & NS_FRAME_OUT_OF_FLOW)) {
5128 0 : return GetParent(); // the parent is always the containing block
5129 : }
5130 0 : return GetNearestBlockContainer(GetParent());
5131 : }
5132 :
5133 : #ifdef NS_DEBUG
5134 :
5135 0 : PRInt32 nsFrame::ContentIndexInContainer(const nsIFrame* aFrame)
5136 : {
5137 0 : PRInt32 result = -1;
5138 :
5139 0 : nsIContent* content = aFrame->GetContent();
5140 0 : if (content) {
5141 0 : nsIContent* parentContent = content->GetParent();
5142 0 : if (parentContent) {
5143 0 : result = parentContent->IndexOf(content);
5144 : }
5145 : }
5146 :
5147 0 : return result;
5148 : }
5149 :
5150 : /**
5151 : * List a frame tree to stdout. Meant to be called from gdb.
5152 : */
5153 : void
5154 0 : DebugListFrameTree(nsIFrame* aFrame)
5155 : {
5156 0 : ((nsFrame*)aFrame)->List(stdout, 0);
5157 0 : }
5158 :
5159 :
5160 : // Debugging
5161 : NS_IMETHODIMP
5162 0 : nsFrame::List(FILE* out, PRInt32 aIndent) const
5163 : {
5164 0 : IndentBy(out, aIndent);
5165 0 : ListTag(out);
5166 : #ifdef DEBUG_waterson
5167 : fprintf(out, " [parent=%p]", static_cast<void*>(mParent));
5168 : #endif
5169 0 : if (HasView()) {
5170 0 : fprintf(out, " [view=%p]", static_cast<void*>(GetView()));
5171 : }
5172 0 : fprintf(out, " {%d,%d,%d,%d}", mRect.x, mRect.y, mRect.width, mRect.height);
5173 0 : if (0 != mState) {
5174 0 : fprintf(out, " [state=%016llx]", (unsigned long long)mState);
5175 : }
5176 0 : nsIFrame* prevInFlow = GetPrevInFlow();
5177 0 : nsIFrame* nextInFlow = GetNextInFlow();
5178 0 : if (nsnull != prevInFlow) {
5179 0 : fprintf(out, " prev-in-flow=%p", static_cast<void*>(prevInFlow));
5180 : }
5181 0 : if (nsnull != nextInFlow) {
5182 0 : fprintf(out, " next-in-flow=%p", static_cast<void*>(nextInFlow));
5183 : }
5184 0 : fprintf(out, " [content=%p]", static_cast<void*>(mContent));
5185 0 : nsFrame* f = const_cast<nsFrame*>(this);
5186 0 : if (f->HasOverflowAreas()) {
5187 0 : nsRect overflowArea = f->GetVisualOverflowRect();
5188 : fprintf(out, " [vis-overflow=%d,%d,%d,%d]", overflowArea.x, overflowArea.y,
5189 0 : overflowArea.width, overflowArea.height);
5190 0 : overflowArea = f->GetScrollableOverflowRect();
5191 : fprintf(out, " [scr-overflow=%d,%d,%d,%d]", overflowArea.x, overflowArea.y,
5192 0 : overflowArea.width, overflowArea.height);
5193 : }
5194 0 : fprintf(out, " [sc=%p]", static_cast<void*>(mStyleContext));
5195 0 : fputs("\n", out);
5196 0 : return NS_OK;
5197 : }
5198 :
5199 : NS_IMETHODIMP
5200 0 : nsFrame::GetFrameName(nsAString& aResult) const
5201 : {
5202 0 : return MakeFrameName(NS_LITERAL_STRING("Frame"), aResult);
5203 : }
5204 :
5205 : NS_IMETHODIMP_(nsFrameState)
5206 0 : nsFrame::GetDebugStateBits() const
5207 : {
5208 : // We'll ignore these flags for the purposes of comparing frame state:
5209 : //
5210 : // NS_FRAME_EXTERNAL_REFERENCE
5211 : // because this is set by the event state manager or the
5212 : // caret code when a frame is focused. Depending on whether
5213 : // or not the regression tests are run as the focused window
5214 : // will make this value vary randomly.
5215 : #define IRRELEVANT_FRAME_STATE_FLAGS NS_FRAME_EXTERNAL_REFERENCE
5216 :
5217 : #define FRAME_STATE_MASK (~(IRRELEVANT_FRAME_STATE_FLAGS))
5218 :
5219 0 : return GetStateBits() & FRAME_STATE_MASK;
5220 : }
5221 :
5222 : nsresult
5223 0 : nsFrame::MakeFrameName(const nsAString& aType, nsAString& aResult) const
5224 : {
5225 0 : aResult = aType;
5226 0 : if (mContent && !mContent->IsNodeOfType(nsINode::eTEXT)) {
5227 0 : nsAutoString buf;
5228 0 : mContent->Tag()->ToString(buf);
5229 0 : aResult.Append(NS_LITERAL_STRING("(") + buf + NS_LITERAL_STRING(")"));
5230 : }
5231 : char buf[40];
5232 0 : PR_snprintf(buf, sizeof(buf), "(%d)", ContentIndexInContainer(this));
5233 0 : AppendASCIItoUTF16(buf, aResult);
5234 0 : return NS_OK;
5235 : }
5236 :
5237 : void
5238 0 : nsFrame::XMLQuote(nsString& aString)
5239 : {
5240 0 : PRInt32 i, len = aString.Length();
5241 0 : for (i = 0; i < len; i++) {
5242 0 : PRUnichar ch = aString.CharAt(i);
5243 0 : if (ch == '<') {
5244 0 : nsAutoString tmp(NS_LITERAL_STRING("<"));
5245 0 : aString.Cut(i, 1);
5246 0 : aString.Insert(tmp, i);
5247 0 : len += 3;
5248 0 : i += 3;
5249 : }
5250 0 : else if (ch == '>') {
5251 0 : nsAutoString tmp(NS_LITERAL_STRING(">"));
5252 0 : aString.Cut(i, 1);
5253 0 : aString.Insert(tmp, i);
5254 0 : len += 3;
5255 0 : i += 3;
5256 : }
5257 0 : else if (ch == '\"') {
5258 0 : nsAutoString tmp(NS_LITERAL_STRING("""));
5259 0 : aString.Cut(i, 1);
5260 0 : aString.Insert(tmp, i);
5261 0 : len += 5;
5262 0 : i += 5;
5263 : }
5264 : }
5265 0 : }
5266 : #endif
5267 :
5268 : bool
5269 0 : nsIFrame::IsVisibleForPainting(nsDisplayListBuilder* aBuilder) {
5270 0 : if (!GetStyleVisibility()->IsVisible())
5271 0 : return false;
5272 0 : nsISelection* sel = aBuilder->GetBoundingSelection();
5273 0 : return !sel || IsVisibleInSelection(sel);
5274 : }
5275 :
5276 : bool
5277 0 : nsIFrame::IsVisibleForPainting() {
5278 0 : if (!GetStyleVisibility()->IsVisible())
5279 0 : return false;
5280 :
5281 0 : nsPresContext* pc = PresContext();
5282 0 : if (!pc->IsRenderingOnlySelection())
5283 0 : return true;
5284 :
5285 0 : nsCOMPtr<nsISelectionController> selcon(do_QueryInterface(pc->PresShell()));
5286 0 : if (selcon) {
5287 0 : nsCOMPtr<nsISelection> sel;
5288 0 : selcon->GetSelection(nsISelectionController::SELECTION_NORMAL,
5289 0 : getter_AddRefs(sel));
5290 0 : if (sel)
5291 0 : return IsVisibleInSelection(sel);
5292 : }
5293 0 : return true;
5294 : }
5295 :
5296 : bool
5297 0 : nsIFrame::IsVisibleInSelection(nsDisplayListBuilder* aBuilder) {
5298 0 : nsISelection* sel = aBuilder->GetBoundingSelection();
5299 0 : return !sel || IsVisibleInSelection(sel);
5300 : }
5301 :
5302 : bool
5303 0 : nsIFrame::IsVisibleOrCollapsedForPainting(nsDisplayListBuilder* aBuilder) {
5304 0 : if (!GetStyleVisibility()->IsVisibleOrCollapsed())
5305 0 : return false;
5306 0 : nsISelection* sel = aBuilder->GetBoundingSelection();
5307 0 : return !sel || IsVisibleInSelection(sel);
5308 : }
5309 :
5310 : bool
5311 0 : nsIFrame::IsVisibleInSelection(nsISelection* aSelection)
5312 : {
5313 0 : if (!GetContent() || !GetContent()->IsSelectionDescendant()) {
5314 0 : return false;
5315 : }
5316 :
5317 0 : nsCOMPtr<nsIDOMNode> node(do_QueryInterface(mContent));
5318 : bool vis;
5319 0 : nsresult rv = aSelection->ContainsNode(node, true, &vis);
5320 0 : return NS_FAILED(rv) || vis;
5321 : }
5322 :
5323 : /* virtual */ bool
5324 0 : nsFrame::IsEmpty()
5325 : {
5326 0 : return false;
5327 : }
5328 :
5329 : bool
5330 0 : nsIFrame::CachedIsEmpty()
5331 : {
5332 0 : NS_PRECONDITION(!(GetStateBits() & NS_FRAME_IS_DIRTY),
5333 : "Must only be called on reflowed lines");
5334 0 : return IsEmpty();
5335 : }
5336 :
5337 : /* virtual */ bool
5338 0 : nsFrame::IsSelfEmpty()
5339 : {
5340 0 : return false;
5341 : }
5342 :
5343 : NS_IMETHODIMP
5344 0 : nsFrame::GetSelectionController(nsPresContext *aPresContext, nsISelectionController **aSelCon)
5345 : {
5346 0 : if (!aPresContext || !aSelCon)
5347 0 : return NS_ERROR_INVALID_ARG;
5348 :
5349 0 : nsIFrame *frame = this;
5350 0 : while (frame && (frame->GetStateBits() & NS_FRAME_INDEPENDENT_SELECTION)) {
5351 0 : nsITextControlFrame *tcf = do_QueryFrame(frame);
5352 0 : if (tcf) {
5353 0 : return tcf->GetOwnedSelectionController(aSelCon);
5354 : }
5355 0 : frame = frame->GetParent();
5356 : }
5357 :
5358 0 : return CallQueryInterface(aPresContext->GetPresShell(), aSelCon);
5359 : }
5360 :
5361 : already_AddRefed<nsFrameSelection>
5362 0 : nsIFrame::GetFrameSelection()
5363 : {
5364 : nsFrameSelection* fs =
5365 0 : const_cast<nsFrameSelection*>(GetConstFrameSelection());
5366 0 : NS_IF_ADDREF(fs);
5367 0 : return fs;
5368 : }
5369 :
5370 : const nsFrameSelection*
5371 0 : nsIFrame::GetConstFrameSelection() const
5372 : {
5373 0 : nsIFrame* frame = const_cast<nsIFrame*>(this);
5374 0 : while (frame && (frame->GetStateBits() & NS_FRAME_INDEPENDENT_SELECTION)) {
5375 0 : nsITextControlFrame* tcf = do_QueryFrame(frame);
5376 0 : if (tcf) {
5377 0 : return tcf->GetOwnedFrameSelection();
5378 : }
5379 0 : frame = frame->GetParent();
5380 : }
5381 :
5382 0 : return PresContext()->PresShell()->ConstFrameSelection();
5383 : }
5384 :
5385 : #ifdef NS_DEBUG
5386 : NS_IMETHODIMP
5387 0 : nsFrame::DumpRegressionData(nsPresContext* aPresContext, FILE* out, PRInt32 aIndent)
5388 : {
5389 0 : IndentBy(out, aIndent);
5390 0 : fprintf(out, "<frame va=\"%ld\" type=\"", PRUptrdiff(this));
5391 0 : nsAutoString name;
5392 0 : GetFrameName(name);
5393 0 : XMLQuote(name);
5394 0 : fputs(NS_LossyConvertUTF16toASCII(name).get(), out);
5395 : fprintf(out, "\" state=\"%016llx\" parent=\"%ld\">\n",
5396 0 : (unsigned long long)GetDebugStateBits(), PRUptrdiff(mParent));
5397 :
5398 0 : aIndent++;
5399 0 : DumpBaseRegressionData(aPresContext, out, aIndent);
5400 0 : aIndent--;
5401 :
5402 0 : IndentBy(out, aIndent);
5403 0 : fprintf(out, "</frame>\n");
5404 :
5405 0 : return NS_OK;
5406 : }
5407 :
5408 : void
5409 0 : nsFrame::DumpBaseRegressionData(nsPresContext* aPresContext, FILE* out, PRInt32 aIndent)
5410 : {
5411 0 : if (GetNextSibling()) {
5412 0 : IndentBy(out, aIndent);
5413 0 : fprintf(out, "<next-sibling va=\"%ld\"/>\n", PRUptrdiff(GetNextSibling()));
5414 : }
5415 :
5416 0 : if (HasView()) {
5417 0 : IndentBy(out, aIndent);
5418 0 : fprintf(out, "<view va=\"%ld\">\n", PRUptrdiff(GetView()));
5419 0 : aIndent++;
5420 : // XXX add in code to dump out view state too...
5421 0 : aIndent--;
5422 0 : IndentBy(out, aIndent);
5423 0 : fprintf(out, "</view>\n");
5424 : }
5425 :
5426 0 : IndentBy(out, aIndent);
5427 : fprintf(out, "<bbox x=\"%d\" y=\"%d\" w=\"%d\" h=\"%d\"/>\n",
5428 0 : mRect.x, mRect.y, mRect.width, mRect.height);
5429 :
5430 : // Now dump all of the children on all of the child lists
5431 0 : ChildListIterator lists(this);
5432 0 : for (; !lists.IsDone(); lists.Next()) {
5433 0 : IndentBy(out, aIndent);
5434 0 : if (lists.CurrentID() != kPrincipalList) {
5435 0 : fprintf(out, "<child-list name=\"%s\">\n", mozilla::layout::ChildListName(lists.CurrentID()));
5436 : }
5437 : else {
5438 0 : fprintf(out, "<child-list>\n");
5439 : }
5440 0 : aIndent++;
5441 0 : nsFrameList::Enumerator childFrames(lists.CurrentList());
5442 0 : for (; !childFrames.AtEnd(); childFrames.Next()) {
5443 0 : nsIFrame* kid = childFrames.get();
5444 0 : kid->DumpRegressionData(aPresContext, out, aIndent);
5445 : }
5446 0 : aIndent--;
5447 0 : IndentBy(out, aIndent);
5448 0 : fprintf(out, "</child-list>\n");
5449 : }
5450 0 : }
5451 : #endif
5452 :
5453 : bool
5454 0 : nsIFrame::IsFrameSelected() const
5455 : {
5456 0 : NS_ASSERTION(!GetContent() || GetContent()->IsSelectionDescendant(),
5457 : "use the public IsSelected() instead");
5458 0 : return nsRange::IsNodeSelected(GetContent(), 0,
5459 0 : GetContent()->GetChildCount());
5460 : }
5461 :
5462 : NS_IMETHODIMP
5463 0 : nsFrame::GetPointFromOffset(PRInt32 inOffset, nsPoint* outPoint)
5464 : {
5465 0 : NS_PRECONDITION(outPoint != nsnull, "Null parameter");
5466 0 : nsRect contentRect = GetContentRect() - GetPosition();
5467 0 : nsPoint pt = contentRect.TopLeft();
5468 0 : if (mContent)
5469 : {
5470 0 : nsIContent* newContent = mContent->GetParent();
5471 0 : if (newContent){
5472 0 : PRInt32 newOffset = newContent->IndexOf(mContent);
5473 :
5474 0 : bool isRTL = (NS_GET_EMBEDDING_LEVEL(this) & 1) == 1;
5475 0 : if ((!isRTL && inOffset > newOffset) ||
5476 : (isRTL && inOffset <= newOffset)) {
5477 0 : pt = contentRect.TopRight();
5478 : }
5479 : }
5480 : }
5481 0 : *outPoint = pt;
5482 0 : return NS_OK;
5483 : }
5484 :
5485 : NS_IMETHODIMP
5486 0 : nsFrame::GetChildFrameContainingOffset(PRInt32 inContentOffset, bool inHint, PRInt32* outFrameContentOffset, nsIFrame **outChildFrame)
5487 : {
5488 0 : NS_PRECONDITION(outChildFrame && outFrameContentOffset, "Null parameter");
5489 0 : *outFrameContentOffset = (PRInt32)inHint;
5490 : //the best frame to reflect any given offset would be a visible frame if possible
5491 : //i.e. we are looking for a valid frame to place the blinking caret
5492 0 : nsRect rect = GetRect();
5493 0 : if (!rect.width || !rect.height)
5494 : {
5495 : //if we have a 0 width or height then lets look for another frame that possibly has
5496 : //the same content. If we have no frames in flow then just let us return 'this' frame
5497 0 : nsIFrame* nextFlow = GetNextInFlow();
5498 0 : if (nextFlow)
5499 0 : return nextFlow->GetChildFrameContainingOffset(inContentOffset, inHint, outFrameContentOffset, outChildFrame);
5500 : }
5501 0 : *outChildFrame = this;
5502 0 : return NS_OK;
5503 : }
5504 :
5505 : //
5506 : // What I've pieced together about this routine:
5507 : // Starting with a block frame (from which a line frame can be gotten)
5508 : // and a line number, drill down and get the first/last selectable
5509 : // frame on that line, depending on aPos->mDirection.
5510 : // aOutSideLimit != 0 means ignore aLineStart, instead work from
5511 : // the end (if > 0) or beginning (if < 0).
5512 : //
5513 : nsresult
5514 0 : nsFrame::GetNextPrevLineFromeBlockFrame(nsPresContext* aPresContext,
5515 : nsPeekOffsetStruct *aPos,
5516 : nsIFrame *aBlockFrame,
5517 : PRInt32 aLineStart,
5518 : PRInt8 aOutSideLimit
5519 : )
5520 : {
5521 : //magic numbers aLineStart will be -1 for end of block 0 will be start of block
5522 0 : if (!aBlockFrame || !aPos)
5523 0 : return NS_ERROR_NULL_POINTER;
5524 :
5525 0 : aPos->mResultFrame = nsnull;
5526 0 : aPos->mResultContent = nsnull;
5527 0 : aPos->mAttachForward = (aPos->mDirection == eDirNext);
5528 :
5529 0 : nsAutoLineIterator it = aBlockFrame->GetLineIterator();
5530 0 : if (!it)
5531 0 : return NS_ERROR_FAILURE;
5532 0 : PRInt32 searchingLine = aLineStart;
5533 0 : PRInt32 countLines = it->GetNumLines();
5534 0 : if (aOutSideLimit > 0) //start at end
5535 0 : searchingLine = countLines;
5536 0 : else if (aOutSideLimit <0)//start at beginning
5537 0 : searchingLine = -1;//"next" will be 0
5538 : else
5539 0 : if ((aPos->mDirection == eDirPrevious && searchingLine == 0) ||
5540 : (aPos->mDirection == eDirNext && searchingLine >= (countLines -1) )){
5541 : //we need to jump to new block frame.
5542 0 : return NS_ERROR_FAILURE;
5543 : }
5544 : PRInt32 lineFrameCount;
5545 0 : nsIFrame *resultFrame = nsnull;
5546 0 : nsIFrame *farStoppingFrame = nsnull; //we keep searching until we find a "this" frame then we go to next line
5547 0 : nsIFrame *nearStoppingFrame = nsnull; //if we are backing up from edge, stop here
5548 : nsIFrame *firstFrame;
5549 : nsIFrame *lastFrame;
5550 0 : nsRect rect;
5551 : bool isBeforeFirstFrame, isAfterLastFrame;
5552 0 : bool found = false;
5553 :
5554 0 : nsresult result = NS_OK;
5555 0 : while (!found)
5556 : {
5557 0 : if (aPos->mDirection == eDirPrevious)
5558 0 : searchingLine --;
5559 : else
5560 0 : searchingLine ++;
5561 0 : if ((aPos->mDirection == eDirPrevious && searchingLine < 0) ||
5562 : (aPos->mDirection == eDirNext && searchingLine >= countLines ))
5563 : {
5564 : //we need to jump to new block frame.
5565 0 : return NS_ERROR_FAILURE;
5566 : }
5567 : PRUint32 lineFlags;
5568 0 : result = it->GetLine(searchingLine, &firstFrame, &lineFrameCount,
5569 0 : rect, &lineFlags);
5570 0 : if (!lineFrameCount)
5571 0 : continue;
5572 0 : if (NS_SUCCEEDED(result)){
5573 0 : lastFrame = firstFrame;
5574 0 : for (;lineFrameCount > 1;lineFrameCount --){
5575 : //result = lastFrame->GetNextSibling(&lastFrame, searchingLine);
5576 0 : result = it->GetNextSiblingOnLine(lastFrame, searchingLine);
5577 0 : if (NS_FAILED(result) || !lastFrame){
5578 0 : NS_ERROR("GetLine promised more frames than could be found");
5579 0 : return NS_ERROR_FAILURE;
5580 : }
5581 : }
5582 0 : GetLastLeaf(aPresContext, &lastFrame);
5583 :
5584 0 : if (aPos->mDirection == eDirNext){
5585 0 : nearStoppingFrame = firstFrame;
5586 0 : farStoppingFrame = lastFrame;
5587 : }
5588 : else{
5589 0 : nearStoppingFrame = lastFrame;
5590 0 : farStoppingFrame = firstFrame;
5591 : }
5592 0 : nsPoint offset;
5593 : nsIView * view; //used for call of get offset from view
5594 0 : aBlockFrame->GetOffsetFromView(offset,&view);
5595 0 : nscoord newDesiredX = aPos->mDesiredX - offset.x;//get desired x into blockframe coordinates!
5596 0 : result = it->FindFrameAt(searchingLine, newDesiredX, &resultFrame, &isBeforeFirstFrame, &isAfterLastFrame);
5597 0 : if(NS_FAILED(result))
5598 0 : continue;
5599 : }
5600 :
5601 0 : if (NS_SUCCEEDED(result) && resultFrame)
5602 : {
5603 : //check to see if this is ANOTHER blockframe inside the other one if so then call into its lines
5604 0 : nsAutoLineIterator newIt = resultFrame->GetLineIterator();
5605 0 : if (newIt)
5606 : {
5607 0 : aPos->mResultFrame = resultFrame;
5608 0 : return NS_OK;
5609 : }
5610 : //resultFrame is not a block frame
5611 0 : result = NS_ERROR_FAILURE;
5612 :
5613 0 : nsCOMPtr<nsIFrameEnumerator> frameTraversal;
5614 0 : result = NS_NewFrameTraversal(getter_AddRefs(frameTraversal),
5615 : aPresContext, resultFrame,
5616 : ePostOrder,
5617 : false, // aVisual
5618 : aPos->mScrollViewStop,
5619 : false // aFollowOOFs
5620 0 : );
5621 0 : if (NS_FAILED(result))
5622 0 : return result;
5623 0 : nsIFrame *storeOldResultFrame = resultFrame;
5624 0 : while ( !found ){
5625 0 : nsPoint point;
5626 0 : point.x = aPos->mDesiredX;
5627 :
5628 0 : nsRect tempRect = resultFrame->GetRect();
5629 0 : nsPoint offset;
5630 : nsIView * view; //used for call of get offset from view
5631 0 : result = resultFrame->GetOffsetFromView(offset, &view);
5632 0 : if (NS_FAILED(result))
5633 0 : return result;
5634 0 : point.y = tempRect.height + offset.y;
5635 :
5636 : //special check. if we allow non-text selection then we can allow a hit location to fall before a table.
5637 : //otherwise there is no way to get and click signal to fall before a table (it being a line iterator itself)
5638 0 : nsIPresShell *shell = aPresContext->GetPresShell();
5639 0 : if (!shell)
5640 0 : return NS_ERROR_FAILURE;
5641 0 : PRInt16 isEditor = shell->GetSelectionFlags();
5642 0 : isEditor = isEditor == nsISelectionDisplay::DISPLAY_ALL;
5643 0 : if ( isEditor )
5644 : {
5645 0 : if (resultFrame->GetType() == nsGkAtoms::tableOuterFrame)
5646 : {
5647 0 : if (((point.x - offset.x + tempRect.x)<0) || ((point.x - offset.x+ tempRect.x)>tempRect.width))//off left/right side
5648 : {
5649 0 : nsIContent* content = resultFrame->GetContent();
5650 0 : if (content)
5651 : {
5652 0 : nsIContent* parent = content->GetParent();
5653 0 : if (parent)
5654 : {
5655 0 : aPos->mResultContent = parent;
5656 0 : aPos->mContentOffset = parent->IndexOf(content);
5657 0 : aPos->mAttachForward = false;
5658 0 : if ((point.x - offset.x+ tempRect.x)>tempRect.width)
5659 : {
5660 0 : aPos->mContentOffset++;//go to end of this frame
5661 0 : aPos->mAttachForward = true;
5662 : }
5663 : //result frame is the result frames parent.
5664 0 : aPos->mResultFrame = resultFrame->GetParent();
5665 0 : return NS_POSITION_BEFORE_TABLE;
5666 : }
5667 : }
5668 : }
5669 : }
5670 : }
5671 :
5672 0 : if (!resultFrame->HasView())
5673 : {
5674 : nsIView* view;
5675 0 : nsPoint offset;
5676 0 : resultFrame->GetOffsetFromView(offset, &view);
5677 : ContentOffsets offsets =
5678 0 : resultFrame->GetContentOffsetsFromPoint(point - offset);
5679 0 : aPos->mResultContent = offsets.content;
5680 0 : aPos->mContentOffset = offsets.offset;
5681 0 : aPos->mAttachForward = offsets.associateWithNext;
5682 0 : if (offsets.content)
5683 : {
5684 : bool selectable;
5685 0 : resultFrame->IsSelectable(&selectable, nsnull);
5686 0 : if (selectable)
5687 : {
5688 0 : found = true;
5689 : break;
5690 : }
5691 : }
5692 : }
5693 :
5694 0 : if (aPos->mDirection == eDirPrevious && (resultFrame == farStoppingFrame))
5695 : break;
5696 0 : if (aPos->mDirection == eDirNext && (resultFrame == nearStoppingFrame))
5697 : break;
5698 : //always try previous on THAT line if that fails go the other way
5699 0 : frameTraversal->Prev();
5700 0 : resultFrame = frameTraversal->CurrentItem();
5701 0 : if (!resultFrame)
5702 0 : return NS_ERROR_FAILURE;
5703 : }
5704 :
5705 0 : if (!found){
5706 0 : resultFrame = storeOldResultFrame;
5707 0 : result = NS_NewFrameTraversal(getter_AddRefs(frameTraversal),
5708 : aPresContext, resultFrame,
5709 : eLeaf,
5710 : false, // aVisual
5711 : aPos->mScrollViewStop,
5712 : false // aFollowOOFs
5713 0 : );
5714 : }
5715 0 : while ( !found ){
5716 0 : nsPoint point(aPos->mDesiredX, 0);
5717 : nsIView* view;
5718 0 : nsPoint offset;
5719 0 : resultFrame->GetOffsetFromView(offset, &view);
5720 : ContentOffsets offsets =
5721 0 : resultFrame->GetContentOffsetsFromPoint(point - offset);
5722 0 : aPos->mResultContent = offsets.content;
5723 0 : aPos->mContentOffset = offsets.offset;
5724 0 : aPos->mAttachForward = offsets.associateWithNext;
5725 0 : if (offsets.content)
5726 : {
5727 : bool selectable;
5728 0 : resultFrame->IsSelectable(&selectable, nsnull);
5729 0 : if (selectable)
5730 : {
5731 0 : found = true;
5732 0 : if (resultFrame == farStoppingFrame)
5733 0 : aPos->mAttachForward = false;
5734 : else
5735 0 : aPos->mAttachForward = true;
5736 : break;
5737 : }
5738 : }
5739 0 : if (aPos->mDirection == eDirPrevious && (resultFrame == nearStoppingFrame))
5740 : break;
5741 0 : if (aPos->mDirection == eDirNext && (resultFrame == farStoppingFrame))
5742 : break;
5743 : //previous didnt work now we try "next"
5744 0 : frameTraversal->Next();
5745 0 : nsIFrame *tempFrame = frameTraversal->CurrentItem();
5746 0 : if (!tempFrame)
5747 : break;
5748 0 : resultFrame = tempFrame;
5749 : }
5750 0 : aPos->mResultFrame = resultFrame;
5751 : }
5752 : else {
5753 : //we need to jump to new block frame.
5754 0 : aPos->mAmount = eSelectLine;
5755 0 : aPos->mStartOffset = 0;
5756 0 : aPos->mAttachForward = !(aPos->mDirection == eDirNext);
5757 0 : if (aPos->mDirection == eDirPrevious)
5758 0 : aPos->mStartOffset = -1;//start from end
5759 0 : return aBlockFrame->PeekOffset(aPos);
5760 : }
5761 : }
5762 0 : return NS_OK;
5763 : }
5764 :
5765 0 : nsPeekOffsetStruct nsIFrame::GetExtremeCaretPosition(bool aStart)
5766 : {
5767 0 : nsPeekOffsetStruct result;
5768 :
5769 0 : FrameTarget targetFrame = DrillDownToSelectionFrame(this, !aStart);
5770 0 : FrameContentRange range = GetRangeForFrame(targetFrame.frame);
5771 0 : result.mResultContent = range.content;
5772 0 : result.mContentOffset = aStart ? range.start : range.end;
5773 0 : result.mAttachForward = (result.mContentOffset == range.start);
5774 : return result;
5775 : }
5776 :
5777 : // Find the first (or last) descendant of the given frame
5778 : // which is either a block frame or a BRFrame.
5779 : static nsContentAndOffset
5780 0 : FindBlockFrameOrBR(nsIFrame* aFrame, nsDirection aDirection)
5781 : {
5782 : nsContentAndOffset result;
5783 0 : result.mContent = nsnull;
5784 0 : result.mOffset = 0;
5785 :
5786 0 : if (aFrame->IsGeneratedContentFrame())
5787 0 : return result;
5788 :
5789 : // Treat form controls as inline leaves
5790 : // XXX we really need a way to determine whether a frame is inline-level
5791 0 : nsIFormControlFrame* fcf = do_QueryFrame(aFrame);
5792 0 : if (fcf)
5793 0 : return result;
5794 :
5795 : // Check the frame itself
5796 : // Fall through "special" block frames because their mContent is the content
5797 : // of the inline frames they were created from. The first/last child of
5798 : // such frames is the real block frame we're looking for.
5799 0 : if ((nsLayoutUtils::GetAsBlock(aFrame) && !(aFrame->GetStateBits() & NS_FRAME_IS_SPECIAL)) ||
5800 0 : aFrame->GetType() == nsGkAtoms::brFrame) {
5801 0 : nsIContent* content = aFrame->GetContent();
5802 0 : result.mContent = content->GetParent();
5803 : // In some cases (bug 310589, bug 370174) we end up here with a null content.
5804 : // This probably shouldn't ever happen, but since it sometimes does, we want
5805 : // to avoid crashing here.
5806 0 : NS_ASSERTION(result.mContent, "Unexpected orphan content");
5807 0 : if (result.mContent)
5808 0 : result.mOffset = result.mContent->IndexOf(content) +
5809 0 : (aDirection == eDirPrevious ? 1 : 0);
5810 0 : return result;
5811 : }
5812 :
5813 : // If this is a preformatted text frame, see if it ends with a newline
5814 0 : if (aFrame->HasTerminalNewline() &&
5815 0 : aFrame->GetStyleContext()->GetStyleText()->NewlineIsSignificant()) {
5816 : PRInt32 startOffset, endOffset;
5817 0 : aFrame->GetOffsets(startOffset, endOffset);
5818 0 : result.mContent = aFrame->GetContent();
5819 0 : result.mOffset = endOffset - (aDirection == eDirPrevious ? 0 : 1);
5820 0 : return result;
5821 : }
5822 :
5823 : // Iterate over children and call ourselves recursively
5824 0 : if (aDirection == eDirPrevious) {
5825 0 : nsIFrame* child = aFrame->GetLastChild(nsIFrame::kPrincipalList);
5826 0 : while(child && !result.mContent) {
5827 0 : result = FindBlockFrameOrBR(child, aDirection);
5828 0 : child = child->GetPrevSibling();
5829 : }
5830 : } else { // eDirNext
5831 0 : nsIFrame* child = aFrame->GetFirstPrincipalChild();
5832 0 : while(child && !result.mContent) {
5833 0 : result = FindBlockFrameOrBR(child, aDirection);
5834 0 : child = child->GetNextSibling();
5835 : }
5836 : }
5837 0 : return result;
5838 : }
5839 :
5840 : nsresult
5841 0 : nsIFrame::PeekOffsetParagraph(nsPeekOffsetStruct *aPos)
5842 : {
5843 0 : nsIFrame* frame = this;
5844 : nsContentAndOffset blockFrameOrBR;
5845 0 : blockFrameOrBR.mContent = nsnull;
5846 0 : bool reachedBlockAncestor = false;
5847 :
5848 : // Go through containing frames until reaching a block frame.
5849 : // In each step, search the previous (or next) siblings for the closest
5850 : // "stop frame" (a block frame or a BRFrame).
5851 : // If found, set it to be the selection boundray and abort.
5852 :
5853 0 : if (aPos->mDirection == eDirPrevious) {
5854 0 : while (!reachedBlockAncestor) {
5855 0 : nsIFrame* parent = frame->GetParent();
5856 : // Treat a frame associated with the root content as if it were a block frame.
5857 0 : if (!frame->mContent || !frame->mContent->GetParent()) {
5858 0 : reachedBlockAncestor = true;
5859 0 : break;
5860 : }
5861 0 : nsIFrame* sibling = frame->GetPrevSibling();
5862 0 : while (sibling && !blockFrameOrBR.mContent) {
5863 0 : blockFrameOrBR = FindBlockFrameOrBR(sibling, eDirPrevious);
5864 0 : sibling = sibling->GetPrevSibling();
5865 : }
5866 0 : if (blockFrameOrBR.mContent) {
5867 0 : aPos->mResultContent = blockFrameOrBR.mContent;
5868 0 : aPos->mContentOffset = blockFrameOrBR.mOffset;
5869 0 : break;
5870 : }
5871 0 : frame = parent;
5872 0 : reachedBlockAncestor = (nsLayoutUtils::GetAsBlock(frame) != nsnull);
5873 : }
5874 0 : if (reachedBlockAncestor) { // no "stop frame" found
5875 0 : aPos->mResultContent = frame->GetContent();
5876 0 : aPos->mContentOffset = 0;
5877 : }
5878 : } else { // eDirNext
5879 0 : while (!reachedBlockAncestor) {
5880 0 : nsIFrame* parent = frame->GetParent();
5881 : // Treat a frame associated with the root content as if it were a block frame.
5882 0 : if (!frame->mContent || !frame->mContent->GetParent()) {
5883 0 : reachedBlockAncestor = true;
5884 0 : break;
5885 : }
5886 0 : nsIFrame* sibling = frame;
5887 0 : while (sibling && !blockFrameOrBR.mContent) {
5888 0 : blockFrameOrBR = FindBlockFrameOrBR(sibling, eDirNext);
5889 0 : sibling = sibling->GetNextSibling();
5890 : }
5891 0 : if (blockFrameOrBR.mContent) {
5892 0 : aPos->mResultContent = blockFrameOrBR.mContent;
5893 0 : aPos->mContentOffset = blockFrameOrBR.mOffset;
5894 0 : break;
5895 : }
5896 0 : frame = parent;
5897 0 : reachedBlockAncestor = (nsLayoutUtils::GetAsBlock(frame) != nsnull);
5898 : }
5899 0 : if (reachedBlockAncestor) { // no "stop frame" found
5900 0 : aPos->mResultContent = frame->GetContent();
5901 0 : if (aPos->mResultContent)
5902 0 : aPos->mContentOffset = aPos->mResultContent->GetChildCount();
5903 : }
5904 : }
5905 0 : return NS_OK;
5906 : }
5907 :
5908 : // Determine movement direction relative to frame
5909 0 : static bool IsMovingInFrameDirection(nsIFrame* frame, nsDirection aDirection, bool aVisual)
5910 : {
5911 : bool isReverseDirection = aVisual ?
5912 0 : (NS_GET_EMBEDDING_LEVEL(frame) & 1) != (NS_GET_BASE_LEVEL(frame) & 1) : false;
5913 0 : return aDirection == (isReverseDirection ? eDirPrevious : eDirNext);
5914 : }
5915 :
5916 : NS_IMETHODIMP
5917 0 : nsIFrame::PeekOffset(nsPeekOffsetStruct* aPos)
5918 : {
5919 0 : if (!aPos)
5920 0 : return NS_ERROR_NULL_POINTER;
5921 0 : nsresult result = NS_ERROR_FAILURE;
5922 :
5923 0 : if (mState & NS_FRAME_IS_DIRTY)
5924 0 : return NS_ERROR_UNEXPECTED;
5925 :
5926 : // Translate content offset to be relative to frame
5927 0 : FrameContentRange range = GetRangeForFrame(this);
5928 0 : PRInt32 offset = aPos->mStartOffset - range.start;
5929 0 : nsIFrame* current = this;
5930 :
5931 0 : switch (aPos->mAmount) {
5932 : case eSelectCharacter:
5933 : case eSelectCluster:
5934 : {
5935 0 : bool eatingNonRenderableWS = false;
5936 0 : bool done = false;
5937 0 : bool jumpedLine = false;
5938 :
5939 0 : while (!done) {
5940 : bool movingInFrameDirection =
5941 0 : IsMovingInFrameDirection(current, aPos->mDirection, aPos->mVisual);
5942 :
5943 0 : if (eatingNonRenderableWS)
5944 0 : done = current->PeekOffsetNoAmount(movingInFrameDirection, &offset);
5945 : else
5946 : done = current->PeekOffsetCharacter(movingInFrameDirection, &offset,
5947 0 : aPos->mAmount == eSelectCluster);
5948 :
5949 0 : if (!done) {
5950 : result =
5951 : current->GetFrameFromDirection(aPos->mDirection, aPos->mVisual,
5952 : aPos->mJumpLines, aPos->mScrollViewStop,
5953 0 : ¤t, &offset, &jumpedLine);
5954 0 : if (NS_FAILED(result))
5955 0 : return result;
5956 :
5957 : // If we jumped lines, it's as if we found a character, but we still need
5958 : // to eat non-renderable content on the new line.
5959 0 : if (jumpedLine)
5960 0 : eatingNonRenderableWS = true;
5961 : }
5962 : }
5963 :
5964 : // Set outputs
5965 0 : range = GetRangeForFrame(current);
5966 0 : aPos->mResultFrame = current;
5967 0 : aPos->mResultContent = range.content;
5968 : // Output offset is relative to content, not frame
5969 0 : aPos->mContentOffset = offset < 0 ? range.end : range.start + offset;
5970 : // If we're dealing with a text frame and moving backward positions us at
5971 : // the end of that line, decrease the offset by one to make sure that
5972 : // we're placed before the linefeed character on the previous line.
5973 0 : if (offset < 0 && jumpedLine &&
5974 : aPos->mDirection == eDirPrevious &&
5975 0 : current->GetStyleText()->NewlineIsSignificant() &&
5976 0 : current->HasTerminalNewline()) {
5977 0 : --aPos->mContentOffset;
5978 : }
5979 :
5980 0 : break;
5981 : }
5982 : case eSelectWordNoSpace:
5983 : // eSelectWordNoSpace means that we should not be eating any whitespace when
5984 : // moving to the adjacent word. This means that we should set aPos->
5985 : // mWordMovementType to eEndWord if we're moving forwards, and to eStartWord
5986 : // if we're moving backwards.
5987 0 : if (aPos->mDirection == eDirPrevious) {
5988 0 : aPos->mWordMovementType = eStartWord;
5989 : } else {
5990 0 : aPos->mWordMovementType = eEndWord;
5991 : }
5992 : // Intentionally fall through the eSelectWord case.
5993 : case eSelectWord:
5994 : {
5995 : // wordSelectEatSpace means "are we looking for a boundary between whitespace
5996 : // and non-whitespace (in the direction we're moving in)".
5997 : // It is true when moving forward and looking for a beginning of a word, or
5998 : // when moving backwards and looking for an end of a word.
5999 : bool wordSelectEatSpace;
6000 0 : if (aPos->mWordMovementType != eDefaultBehavior) {
6001 : // aPos->mWordMovementType possible values:
6002 : // eEndWord: eat the space if we're moving backwards
6003 : // eStartWord: eat the space if we're moving forwards
6004 0 : wordSelectEatSpace = ((aPos->mWordMovementType == eEndWord) == (aPos->mDirection == eDirPrevious));
6005 : }
6006 : else {
6007 : // Use the hidden preference which is based on operating system behavior.
6008 : // This pref only affects whether moving forward by word should go to the end of this word or start of the next word.
6009 : // When going backwards, the start of the word is always used, on every operating system.
6010 : wordSelectEatSpace = aPos->mDirection == eDirNext &&
6011 0 : Preferences::GetBool("layout.word_select.eat_space_to_next_word");
6012 : }
6013 :
6014 : // mSawBeforeType means "we already saw characters of the type
6015 : // before the boundary we're looking for". Examples:
6016 : // 1. If we're moving forward, looking for a word beginning (i.e. a boundary
6017 : // between whitespace and non-whitespace), then eatingWS==true means
6018 : // "we already saw some whitespace".
6019 : // 2. If we're moving backward, looking for a word beginning (i.e. a boundary
6020 : // between non-whitespace and whitespace), then eatingWS==true means
6021 : // "we already saw some non-whitespace".
6022 0 : PeekWordState state;
6023 0 : PRInt32 offsetAdjustment = 0;
6024 0 : bool done = false;
6025 0 : while (!done) {
6026 : bool movingInFrameDirection =
6027 0 : IsMovingInFrameDirection(current, aPos->mDirection, aPos->mVisual);
6028 :
6029 : done = current->PeekOffsetWord(movingInFrameDirection, wordSelectEatSpace,
6030 0 : aPos->mIsKeyboardSelect, &offset, &state);
6031 :
6032 0 : if (!done) {
6033 : nsIFrame* nextFrame;
6034 : PRInt32 nextFrameOffset;
6035 : bool jumpedLine;
6036 : result =
6037 : current->GetFrameFromDirection(aPos->mDirection, aPos->mVisual,
6038 : aPos->mJumpLines, aPos->mScrollViewStop,
6039 0 : &nextFrame, &nextFrameOffset, &jumpedLine);
6040 : // We can't jump lines if we're looking for whitespace following
6041 : // non-whitespace, and we already encountered non-whitespace.
6042 0 : if (NS_FAILED(result) ||
6043 0 : (jumpedLine && !wordSelectEatSpace && state.mSawBeforeType)) {
6044 0 : done = true;
6045 : // If we've crossed the line boundary, check to make sure that we
6046 : // have not consumed a trailing newline as whitesapce if it's significant.
6047 0 : if (jumpedLine && wordSelectEatSpace &&
6048 0 : current->HasTerminalNewline() &&
6049 0 : current->GetStyleText()->NewlineIsSignificant()) {
6050 0 : offsetAdjustment = -1;
6051 : }
6052 : } else {
6053 0 : if (jumpedLine) {
6054 0 : state.mContext.Truncate();
6055 : }
6056 0 : current = nextFrame;
6057 0 : offset = nextFrameOffset;
6058 : // Jumping a line is equivalent to encountering whitespace
6059 0 : if (wordSelectEatSpace && jumpedLine)
6060 0 : state.SetSawBeforeType();
6061 : }
6062 : }
6063 : }
6064 :
6065 : // Set outputs
6066 0 : range = GetRangeForFrame(current);
6067 0 : aPos->mResultFrame = current;
6068 0 : aPos->mResultContent = range.content;
6069 : // Output offset is relative to content, not frame
6070 0 : aPos->mContentOffset = (offset < 0 ? range.end : range.start + offset) + offsetAdjustment;
6071 : break;
6072 : }
6073 : case eSelectLine :
6074 : {
6075 0 : nsAutoLineIterator iter;
6076 0 : nsIFrame *blockFrame = this;
6077 :
6078 0 : while (NS_FAILED(result)){
6079 0 : PRInt32 thisLine = nsFrame::GetLineNumber(blockFrame, aPos->mScrollViewStop, &blockFrame);
6080 0 : if (thisLine < 0)
6081 0 : return NS_ERROR_FAILURE;
6082 0 : iter = blockFrame->GetLineIterator();
6083 0 : NS_ASSERTION(iter, "GetLineNumber() succeeded but no block frame?");
6084 0 : result = NS_OK;
6085 :
6086 0 : int edgeCase = 0;//no edge case. this should look at thisLine
6087 :
6088 0 : bool doneLooping = false;//tells us when no more block frames hit.
6089 : //this part will find a frame or a block frame. if it's a block frame
6090 : //it will "drill down" to find a viable frame or it will return an error.
6091 0 : nsIFrame *lastFrame = this;
6092 0 : do {
6093 : result = nsFrame::GetNextPrevLineFromeBlockFrame(PresContext(),
6094 : aPos,
6095 : blockFrame,
6096 : thisLine,
6097 : edgeCase //start from thisLine
6098 0 : );
6099 0 : if (NS_SUCCEEDED(result) && (!aPos->mResultFrame || aPos->mResultFrame == lastFrame))//we came back to same spot! keep going
6100 : {
6101 0 : aPos->mResultFrame = nsnull;
6102 0 : if (aPos->mDirection == eDirPrevious)
6103 0 : thisLine--;
6104 : else
6105 0 : thisLine++;
6106 : }
6107 : else //if failure or success with different frame.
6108 0 : doneLooping = true; //do not continue with while loop
6109 :
6110 0 : lastFrame = aPos->mResultFrame; //set last frame
6111 :
6112 0 : if (NS_SUCCEEDED(result) && aPos->mResultFrame
6113 : && blockFrame != aPos->mResultFrame)// make sure block element is not the same as the one we had before
6114 : {
6115 : /* SPECIAL CHECK FOR TABLE NAVIGATION
6116 : tables need to navigate also and the frame that supports it is nsTableRowGroupFrame which is INSIDE
6117 : nsTableOuterFrame. if we have stumbled onto an nsTableOuter we need to drill into nsTableRowGroup
6118 : if we hit a header or footer that's ok just go into them,
6119 : */
6120 0 : bool searchTableBool = false;
6121 0 : if (aPos->mResultFrame->GetType() == nsGkAtoms::tableOuterFrame ||
6122 0 : aPos->mResultFrame->GetType() == nsGkAtoms::tableCellFrame)
6123 : {
6124 0 : nsIFrame *frame = aPos->mResultFrame->GetFirstPrincipalChild();
6125 : //got the table frame now
6126 0 : while(frame) //ok time to drill down to find iterator
6127 : {
6128 0 : iter = frame->GetLineIterator();
6129 0 : if (iter)
6130 : {
6131 0 : aPos->mResultFrame = frame;
6132 0 : searchTableBool = true;
6133 0 : result = NS_OK;
6134 0 : break; //while(frame)
6135 : }
6136 0 : result = NS_ERROR_FAILURE;
6137 0 : frame = frame->GetFirstPrincipalChild();
6138 : }
6139 : }
6140 :
6141 0 : if (!searchTableBool) {
6142 0 : iter = aPos->mResultFrame->GetLineIterator();
6143 0 : result = iter ? NS_OK : NS_ERROR_FAILURE;
6144 : }
6145 0 : if (NS_SUCCEEDED(result) && iter)//we've struck another block element!
6146 : {
6147 0 : doneLooping = false;
6148 0 : if (aPos->mDirection == eDirPrevious)
6149 0 : edgeCase = 1;//far edge, search from end backwards
6150 : else
6151 0 : edgeCase = -1;//near edge search from beginning onwards
6152 0 : thisLine=0;//this line means nothing now.
6153 : //everything else means something so keep looking "inside" the block
6154 0 : blockFrame = aPos->mResultFrame;
6155 :
6156 : }
6157 : else
6158 : {
6159 0 : result = NS_OK;//THIS is to mean that everything is ok to the containing while loop
6160 0 : break;
6161 : }
6162 : }
6163 0 : } while (!doneLooping);
6164 : }
6165 0 : return result;
6166 : }
6167 :
6168 : case eSelectParagraph:
6169 0 : return PeekOffsetParagraph(aPos);
6170 :
6171 : case eSelectBeginLine:
6172 : case eSelectEndLine:
6173 : {
6174 : // Adjusted so that the caret can't get confused when content changes
6175 0 : nsIFrame* blockFrame = AdjustFrameForSelectionStyles(this);
6176 0 : PRInt32 thisLine = nsFrame::GetLineNumber(blockFrame, aPos->mScrollViewStop, &blockFrame);
6177 0 : if (thisLine < 0)
6178 0 : return NS_ERROR_FAILURE;
6179 0 : nsAutoLineIterator it = blockFrame->GetLineIterator();
6180 0 : NS_ASSERTION(it, "GetLineNumber() succeeded but no block frame?");
6181 :
6182 : PRInt32 lineFrameCount;
6183 : nsIFrame *firstFrame;
6184 0 : nsRect usedRect;
6185 : PRUint32 lineFlags;
6186 0 : nsIFrame* baseFrame = nsnull;
6187 0 : bool endOfLine = (eSelectEndLine == aPos->mAmount);
6188 :
6189 : #ifdef IBMBIDI
6190 0 : if (aPos->mVisual && PresContext()->BidiEnabled()) {
6191 0 : bool lineIsRTL = it->GetDirection();
6192 : bool isReordered;
6193 : nsIFrame *lastFrame;
6194 0 : result = it->CheckLineOrder(thisLine, &isReordered, &firstFrame, &lastFrame);
6195 0 : baseFrame = endOfLine ? lastFrame : firstFrame;
6196 0 : if (baseFrame) {
6197 0 : nsBidiLevel embeddingLevel = nsBidiPresUtils::GetFrameEmbeddingLevel(baseFrame);
6198 : // If the direction of the frame on the edge is opposite to that of the line,
6199 : // we'll need to drill down to its opposite end, so reverse endOfLine.
6200 0 : if ((embeddingLevel & 1) == !lineIsRTL)
6201 0 : endOfLine = !endOfLine;
6202 : }
6203 : } else
6204 : #endif
6205 : {
6206 0 : it->GetLine(thisLine, &firstFrame, &lineFrameCount, usedRect, &lineFlags);
6207 :
6208 0 : nsIFrame* frame = firstFrame;
6209 0 : for (PRInt32 count = lineFrameCount; count;
6210 : --count, frame = frame->GetNextSibling()) {
6211 0 : if (!frame->IsGeneratedContentFrame()) {
6212 0 : baseFrame = frame;
6213 0 : if (!endOfLine)
6214 0 : break;
6215 : }
6216 : }
6217 : }
6218 0 : if (!baseFrame)
6219 0 : return NS_ERROR_FAILURE;
6220 : FrameTarget targetFrame = DrillDownToSelectionFrame(baseFrame,
6221 0 : endOfLine);
6222 0 : FrameContentRange range = GetRangeForFrame(targetFrame.frame);
6223 0 : aPos->mResultContent = range.content;
6224 0 : aPos->mContentOffset = endOfLine ? range.end : range.start;
6225 0 : if (endOfLine && targetFrame.frame->HasTerminalNewline()) {
6226 : // Do not position the caret after the terminating newline if we're
6227 : // trying to move to the end of line (see bug 596506)
6228 0 : --aPos->mContentOffset;
6229 : }
6230 0 : aPos->mResultFrame = targetFrame.frame;
6231 0 : aPos->mAttachForward = (aPos->mContentOffset == range.start);
6232 0 : if (!range.content)
6233 0 : return NS_ERROR_FAILURE;
6234 0 : return NS_OK;
6235 : }
6236 :
6237 : default:
6238 : {
6239 0 : NS_ASSERTION(false, "Invalid amount");
6240 0 : return NS_ERROR_FAILURE;
6241 : }
6242 : }
6243 0 : return NS_OK;
6244 : }
6245 :
6246 : bool
6247 0 : nsFrame::PeekOffsetNoAmount(bool aForward, PRInt32* aOffset)
6248 : {
6249 0 : NS_ASSERTION (aOffset && *aOffset <= 1, "aOffset out of range");
6250 : // Sure, we can stop right here.
6251 0 : return true;
6252 : }
6253 :
6254 : bool
6255 0 : nsFrame::PeekOffsetCharacter(bool aForward, PRInt32* aOffset,
6256 : bool aRespectClusters)
6257 : {
6258 0 : NS_ASSERTION (aOffset && *aOffset <= 1, "aOffset out of range");
6259 0 : PRInt32 startOffset = *aOffset;
6260 : // A negative offset means "end of frame", which in our case means offset 1.
6261 0 : if (startOffset < 0)
6262 0 : startOffset = 1;
6263 0 : if (aForward == (startOffset == 0)) {
6264 : // We're before the frame and moving forward, or after it and moving backwards:
6265 : // skip to the other side and we're done.
6266 0 : *aOffset = 1 - startOffset;
6267 0 : return true;
6268 : }
6269 0 : return false;
6270 : }
6271 :
6272 : bool
6273 0 : nsFrame::PeekOffsetWord(bool aForward, bool aWordSelectEatSpace, bool aIsKeyboardSelect,
6274 : PRInt32* aOffset, PeekWordState* aState)
6275 : {
6276 0 : NS_ASSERTION (aOffset && *aOffset <= 1, "aOffset out of range");
6277 0 : PRInt32 startOffset = *aOffset;
6278 : // This isn't text, so truncate the context
6279 0 : aState->mContext.Truncate();
6280 0 : if (startOffset < 0)
6281 0 : startOffset = 1;
6282 0 : if (aForward == (startOffset == 0)) {
6283 : // We're before the frame and moving forward, or after it and moving backwards.
6284 : // If we're looking for non-whitespace, we found it (without skipping this frame).
6285 0 : if (!aState->mAtStart) {
6286 0 : if (aState->mLastCharWasPunctuation) {
6287 : // We're not punctuation, so this is a punctuation boundary.
6288 0 : if (BreakWordBetweenPunctuation(aState, aForward, false, false, aIsKeyboardSelect))
6289 0 : return true;
6290 : } else {
6291 : // This is not a punctuation boundary.
6292 0 : if (aWordSelectEatSpace && aState->mSawBeforeType)
6293 0 : return true;
6294 : }
6295 : }
6296 : // Otherwise skip to the other side and note that we encountered non-whitespace.
6297 0 : *aOffset = 1 - startOffset;
6298 : aState->Update(false, // not punctuation
6299 : false // not whitespace
6300 0 : );
6301 0 : if (!aWordSelectEatSpace)
6302 0 : aState->SetSawBeforeType();
6303 : }
6304 0 : return false;
6305 : }
6306 :
6307 : bool
6308 0 : nsFrame::BreakWordBetweenPunctuation(const PeekWordState* aState,
6309 : bool aForward,
6310 : bool aPunctAfter, bool aWhitespaceAfter,
6311 : bool aIsKeyboardSelect)
6312 : {
6313 0 : NS_ASSERTION(aPunctAfter != aState->mLastCharWasPunctuation,
6314 : "Call this only at punctuation boundaries");
6315 0 : if (aState->mLastCharWasWhitespace) {
6316 : // We always stop between whitespace and punctuation
6317 0 : return true;
6318 : }
6319 0 : if (!Preferences::GetBool("layout.word_select.stop_at_punctuation")) {
6320 : // When this pref is false, we never stop at a punctuation boundary unless
6321 : // it's after whitespace
6322 0 : return false;
6323 : }
6324 0 : if (!aIsKeyboardSelect) {
6325 : // mouse caret movement (e.g. word selection) always stops at every punctuation boundary
6326 0 : return true;
6327 : }
6328 0 : bool afterPunct = aForward ? aState->mLastCharWasPunctuation : aPunctAfter;
6329 0 : if (!afterPunct) {
6330 : // keyboard caret movement only stops after punctuation (in content order)
6331 0 : return false;
6332 : }
6333 : // Stop only if we've seen some non-punctuation since the last whitespace;
6334 : // don't stop after punctuation that follows whitespace.
6335 0 : return aState->mSeenNonPunctuationSinceWhitespace;
6336 : }
6337 :
6338 : NS_IMETHODIMP
6339 0 : nsFrame::CheckVisibility(nsPresContext* , PRInt32 , PRInt32 , bool , bool *, bool *)
6340 : {
6341 0 : return NS_ERROR_NOT_IMPLEMENTED;
6342 : }
6343 :
6344 :
6345 : PRInt32
6346 0 : nsFrame::GetLineNumber(nsIFrame *aFrame, bool aLockScroll, nsIFrame** aContainingBlock)
6347 : {
6348 0 : NS_ASSERTION(aFrame, "null aFrame");
6349 0 : nsFrameManager* frameManager = aFrame->PresContext()->FrameManager();
6350 0 : nsIFrame *blockFrame = aFrame;
6351 : nsIFrame *thisBlock;
6352 0 : nsAutoLineIterator it;
6353 0 : nsresult result = NS_ERROR_FAILURE;
6354 0 : while (NS_FAILED(result) && blockFrame)
6355 : {
6356 0 : thisBlock = blockFrame;
6357 0 : if (thisBlock->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
6358 : //if we are searching for a frame that is not in flow we will not find it.
6359 : //we must instead look for its placeholder
6360 0 : if (thisBlock->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER) {
6361 : // abspos continuations don't have placeholders, get the fif
6362 0 : thisBlock = thisBlock->GetFirstInFlow();
6363 : }
6364 0 : thisBlock = frameManager->GetPlaceholderFrameFor(thisBlock);
6365 0 : if (!thisBlock)
6366 0 : return -1;
6367 : }
6368 0 : blockFrame = thisBlock->GetParent();
6369 0 : result = NS_OK;
6370 0 : if (blockFrame) {
6371 0 : if (aLockScroll && blockFrame->GetType() == nsGkAtoms::scrollFrame)
6372 0 : return -1;
6373 0 : it = blockFrame->GetLineIterator();
6374 0 : if (!it)
6375 0 : result = NS_ERROR_FAILURE;
6376 : }
6377 : }
6378 0 : if (!blockFrame || !it)
6379 0 : return -1;
6380 :
6381 0 : if (aContainingBlock)
6382 0 : *aContainingBlock = blockFrame;
6383 0 : return it->FindLineContaining(thisBlock);
6384 : }
6385 :
6386 : nsresult
6387 0 : nsIFrame::GetFrameFromDirection(nsDirection aDirection, bool aVisual,
6388 : bool aJumpLines, bool aScrollViewStop,
6389 : nsIFrame** aOutFrame, PRInt32* aOutOffset, bool* aOutJumpedLine)
6390 : {
6391 : nsresult result;
6392 :
6393 0 : if (!aOutFrame || !aOutOffset || !aOutJumpedLine)
6394 0 : return NS_ERROR_NULL_POINTER;
6395 :
6396 0 : nsPresContext* presContext = PresContext();
6397 0 : *aOutFrame = nsnull;
6398 0 : *aOutOffset = 0;
6399 0 : *aOutJumpedLine = false;
6400 :
6401 : // Find the prev/next selectable frame
6402 0 : bool selectable = false;
6403 0 : nsIFrame *traversedFrame = this;
6404 0 : while (!selectable) {
6405 : nsIFrame *blockFrame;
6406 :
6407 0 : PRInt32 thisLine = nsFrame::GetLineNumber(traversedFrame, aScrollViewStop, &blockFrame);
6408 0 : if (thisLine < 0)
6409 0 : return NS_ERROR_FAILURE;
6410 :
6411 0 : nsAutoLineIterator it = blockFrame->GetLineIterator();
6412 0 : NS_ASSERTION(it, "GetLineNumber() succeeded but no block frame?");
6413 :
6414 : bool atLineEdge;
6415 : nsIFrame *firstFrame;
6416 : nsIFrame *lastFrame;
6417 : #ifdef IBMBIDI
6418 0 : if (aVisual && presContext->BidiEnabled()) {
6419 0 : bool lineIsRTL = it->GetDirection();
6420 : bool isReordered;
6421 0 : result = it->CheckLineOrder(thisLine, &isReordered, &firstFrame, &lastFrame);
6422 0 : nsIFrame** framePtr = aDirection == eDirPrevious ? &firstFrame : &lastFrame;
6423 0 : if (*framePtr) {
6424 0 : nsBidiLevel embeddingLevel = nsBidiPresUtils::GetFrameEmbeddingLevel(*framePtr);
6425 0 : if ((((embeddingLevel & 1) && lineIsRTL) || (!(embeddingLevel & 1) && !lineIsRTL)) ==
6426 : (aDirection == eDirPrevious)) {
6427 0 : nsFrame::GetFirstLeaf(presContext, framePtr);
6428 : } else {
6429 0 : nsFrame::GetLastLeaf(presContext, framePtr);
6430 : }
6431 0 : atLineEdge = *framePtr == traversedFrame;
6432 : } else {
6433 0 : atLineEdge = true;
6434 : }
6435 : } else
6436 : #endif
6437 : {
6438 0 : nsRect nonUsedRect;
6439 : PRInt32 lineFrameCount;
6440 : PRUint32 lineFlags;
6441 0 : result = it->GetLine(thisLine, &firstFrame, &lineFrameCount,nonUsedRect,
6442 0 : &lineFlags);
6443 0 : if (NS_FAILED(result))
6444 0 : return result;
6445 :
6446 0 : if (aDirection == eDirPrevious) {
6447 0 : nsFrame::GetFirstLeaf(presContext, &firstFrame);
6448 0 : atLineEdge = firstFrame == traversedFrame;
6449 : } else { // eDirNext
6450 0 : lastFrame = firstFrame;
6451 0 : for (;lineFrameCount > 1;lineFrameCount --){
6452 0 : result = it->GetNextSiblingOnLine(lastFrame, thisLine);
6453 0 : if (NS_FAILED(result) || !lastFrame){
6454 0 : NS_ERROR("should not be reached nsFrame");
6455 0 : return NS_ERROR_FAILURE;
6456 : }
6457 : }
6458 0 : nsFrame::GetLastLeaf(presContext, &lastFrame);
6459 0 : atLineEdge = lastFrame == traversedFrame;
6460 : }
6461 : }
6462 :
6463 0 : if (atLineEdge) {
6464 0 : *aOutJumpedLine = true;
6465 0 : if (!aJumpLines)
6466 0 : return NS_ERROR_FAILURE; //we are done. cannot jump lines
6467 : }
6468 :
6469 0 : nsCOMPtr<nsIFrameEnumerator> frameTraversal;
6470 0 : result = NS_NewFrameTraversal(getter_AddRefs(frameTraversal),
6471 : presContext, traversedFrame,
6472 : eLeaf,
6473 0 : aVisual && presContext->BidiEnabled(),
6474 : aScrollViewStop,
6475 : true // aFollowOOFs
6476 0 : );
6477 0 : if (NS_FAILED(result))
6478 0 : return result;
6479 :
6480 0 : if (aDirection == eDirNext)
6481 0 : frameTraversal->Next();
6482 : else
6483 0 : frameTraversal->Prev();
6484 :
6485 0 : traversedFrame = frameTraversal->CurrentItem();
6486 0 : if (!traversedFrame)
6487 0 : return NS_ERROR_FAILURE;
6488 0 : traversedFrame->IsSelectable(&selectable, nsnull);
6489 : } // while (!selectable)
6490 :
6491 0 : *aOutOffset = (aDirection == eDirNext) ? 0 : -1;
6492 :
6493 : #ifdef IBMBIDI
6494 0 : if (aVisual) {
6495 0 : PRUint8 newLevel = NS_GET_EMBEDDING_LEVEL(traversedFrame);
6496 0 : PRUint8 newBaseLevel = NS_GET_BASE_LEVEL(traversedFrame);
6497 0 : if ((newLevel & 1) != (newBaseLevel & 1)) // The new frame is reverse-direction, go to the other end
6498 0 : *aOutOffset = -1 - *aOutOffset;
6499 : }
6500 : #endif
6501 0 : *aOutFrame = traversedFrame;
6502 0 : return NS_OK;
6503 : }
6504 :
6505 0 : nsIView* nsIFrame::GetClosestView(nsPoint* aOffset) const
6506 : {
6507 0 : nsPoint offset(0,0);
6508 0 : for (const nsIFrame *f = this; f; f = f->GetParent()) {
6509 0 : if (f->HasView()) {
6510 0 : if (aOffset)
6511 0 : *aOffset = offset;
6512 0 : return f->GetView();
6513 : }
6514 0 : offset += f->GetPosition();
6515 : }
6516 :
6517 0 : NS_NOTREACHED("No view on any parent? How did that happen?");
6518 0 : return nsnull;
6519 : }
6520 :
6521 :
6522 : /* virtual */ void
6523 0 : nsFrame::ChildIsDirty(nsIFrame* aChild)
6524 : {
6525 : NS_NOTREACHED("should never be called on a frame that doesn't inherit from "
6526 0 : "nsContainerFrame");
6527 0 : }
6528 :
6529 :
6530 : #ifdef ACCESSIBILITY
6531 : already_AddRefed<nsAccessible>
6532 0 : nsFrame::CreateAccessible()
6533 : {
6534 0 : return nsnull;
6535 : }
6536 : #endif
6537 :
6538 0 : NS_DECLARE_FRAME_PROPERTY(OverflowAreasProperty,
6539 : nsIFrame::DestroyOverflowAreas)
6540 :
6541 : bool
6542 0 : nsIFrame::ClearOverflowRects()
6543 : {
6544 0 : if (mOverflow.mType == NS_FRAME_OVERFLOW_NONE) {
6545 0 : return false;
6546 : }
6547 0 : if (mOverflow.mType == NS_FRAME_OVERFLOW_LARGE) {
6548 0 : Properties().Delete(OverflowAreasProperty());
6549 : }
6550 0 : mOverflow.mType = NS_FRAME_OVERFLOW_NONE;
6551 0 : return true;
6552 : }
6553 :
6554 : /** Create or retrieve the previously stored overflow area, if the frame does
6555 : * not overflow and no creation is required return nsnull.
6556 : * @return pointer to the overflow area rectangle
6557 : */
6558 : nsOverflowAreas*
6559 0 : nsIFrame::GetOverflowAreasProperty()
6560 : {
6561 0 : FrameProperties props = Properties();
6562 : nsOverflowAreas *overflow =
6563 0 : static_cast<nsOverflowAreas*>(props.Get(OverflowAreasProperty()));
6564 :
6565 0 : if (overflow) {
6566 0 : return overflow; // the property already exists
6567 : }
6568 :
6569 : // The property isn't set yet, so allocate a new rect, set the property,
6570 : // and return the newly allocated rect
6571 0 : overflow = new nsOverflowAreas;
6572 0 : props.Set(OverflowAreasProperty(), overflow);
6573 0 : return overflow;
6574 : }
6575 :
6576 : /** Set the overflowArea rect, storing it as deltas or a separate rect
6577 : * depending on its size in relation to the primary frame rect.
6578 : */
6579 : bool
6580 0 : nsIFrame::SetOverflowAreas(const nsOverflowAreas& aOverflowAreas)
6581 : {
6582 0 : if (mOverflow.mType == NS_FRAME_OVERFLOW_LARGE) {
6583 : nsOverflowAreas *overflow =
6584 0 : static_cast<nsOverflowAreas*>(Properties().Get(OverflowAreasProperty()));
6585 0 : bool changed = *overflow != aOverflowAreas;
6586 0 : *overflow = aOverflowAreas;
6587 :
6588 : // Don't bother with converting to the deltas form if we already
6589 : // have a property.
6590 0 : return changed;
6591 : }
6592 :
6593 0 : const nsRect& vis = aOverflowAreas.VisualOverflow();
6594 0 : PRUint32 l = -vis.x, // left edge: positive delta is leftwards
6595 0 : t = -vis.y, // top: positive is upwards
6596 0 : r = vis.XMost() - mRect.width, // right: positive is rightwards
6597 0 : b = vis.YMost() - mRect.height; // bottom: positive is downwards
6598 0 : if (aOverflowAreas.ScrollableOverflow().IsEqualEdges(nsRect(nsPoint(0, 0), GetSize())) &&
6599 : l <= NS_FRAME_OVERFLOW_DELTA_MAX &&
6600 : t <= NS_FRAME_OVERFLOW_DELTA_MAX &&
6601 : r <= NS_FRAME_OVERFLOW_DELTA_MAX &&
6602 : b <= NS_FRAME_OVERFLOW_DELTA_MAX &&
6603 : // we have to check these against zero because we *never* want to
6604 : // set a frame as having no overflow in this function. This is
6605 : // because FinishAndStoreOverflow calls this function prior to
6606 : // SetRect based on whether the overflow areas match aNewSize.
6607 : // In the case where the overflow areas exactly match mRect but
6608 : // do not match aNewSize, we need to store overflow in a property
6609 : // so that our eventual SetRect/SetSize will know that it has to
6610 : // reset our overflow areas.
6611 : (l | t | r | b) != 0) {
6612 0 : VisualDeltas oldDeltas = mOverflow.mVisualDeltas;
6613 : // It's a "small" overflow area so we store the deltas for each edge
6614 : // directly in the frame, rather than allocating a separate rect.
6615 : // If they're all zero, that's fine; we're setting things to
6616 : // no-overflow.
6617 0 : mOverflow.mVisualDeltas.mLeft = l;
6618 0 : mOverflow.mVisualDeltas.mTop = t;
6619 0 : mOverflow.mVisualDeltas.mRight = r;
6620 0 : mOverflow.mVisualDeltas.mBottom = b;
6621 : // There was no scrollable overflow before, and there isn't now.
6622 0 : return oldDeltas != mOverflow.mVisualDeltas;
6623 : } else {
6624 0 : bool changed = !aOverflowAreas.ScrollableOverflow().IsEqualEdges(nsRect(nsPoint(0, 0), GetSize())) ||
6625 0 : !aOverflowAreas.VisualOverflow().IsEqualEdges(GetVisualOverflowFromDeltas());
6626 :
6627 : // it's a large overflow area that we need to store as a property
6628 0 : mOverflow.mType = NS_FRAME_OVERFLOW_LARGE;
6629 0 : nsOverflowAreas* overflow = GetOverflowAreasProperty();
6630 0 : NS_ASSERTION(overflow, "should have created areas");
6631 0 : *overflow = aOverflowAreas;
6632 0 : return changed;
6633 : }
6634 : }
6635 :
6636 : inline bool
6637 0 : IsInlineFrame(nsIFrame *aFrame)
6638 : {
6639 0 : nsIAtom *type = aFrame->GetType();
6640 0 : return type == nsGkAtoms::inlineFrame;
6641 : }
6642 :
6643 : bool
6644 0 : nsIFrame::FinishAndStoreOverflow(nsOverflowAreas& aOverflowAreas,
6645 : nsSize aNewSize)
6646 : {
6647 0 : nsRect bounds(nsPoint(0, 0), aNewSize);
6648 : // Store the passed in overflow area if we are a preserve-3d frame,
6649 : // and it's not just the frame bounds.
6650 0 : if ((Preserves3D() || HasPerspective()) && (!aOverflowAreas.VisualOverflow().IsEqualEdges(bounds) ||
6651 0 : !aOverflowAreas.ScrollableOverflow().IsEqualEdges(bounds))) {
6652 : nsOverflowAreas* initial =
6653 0 : static_cast<nsOverflowAreas*>(Properties().Get(nsIFrame::InitialOverflowProperty()));
6654 0 : if (!initial) {
6655 : Properties().Set(nsIFrame::InitialOverflowProperty(),
6656 0 : new nsOverflowAreas(aOverflowAreas));
6657 0 : } else if (initial != &aOverflowAreas) {
6658 0 : *initial = aOverflowAreas;
6659 : }
6660 : }
6661 :
6662 : // This is now called FinishAndStoreOverflow() instead of
6663 : // StoreOverflow() because frame-generic ways of adding overflow
6664 : // can happen here, e.g. CSS2 outline and native theme.
6665 : // If the overflow area width or height is nscoord_MAX, then a
6666 : // saturating union may have encounted an overflow, so the overflow may not
6667 : // contain the frame border-box. Don't warn in that case.
6668 0 : NS_FOR_FRAME_OVERFLOW_TYPES(otype) {
6669 0 : DebugOnly<nsRect*> r = &aOverflowAreas.Overflow(otype);
6670 0 : NS_ASSERTION(aNewSize.width == 0 || aNewSize.height == 0 ||
6671 : r->width == nscoord_MAX || r->height == nscoord_MAX ||
6672 : r->Contains(nsRect(nsPoint(0,0), aNewSize)),
6673 : "Computed overflow area must contain frame bounds");
6674 : }
6675 :
6676 : // If we clip our children, clear accumulated overflow area. The
6677 : // children are actually clipped to the padding-box, but since the
6678 : // overflow area should include the entire border-box, just set it to
6679 : // the border-box here.
6680 0 : const nsStyleDisplay* disp = GetStyleDisplay();
6681 0 : NS_ASSERTION((disp->mOverflowY == NS_STYLE_OVERFLOW_CLIP) ==
6682 : (disp->mOverflowX == NS_STYLE_OVERFLOW_CLIP),
6683 : "If one overflow is clip, the other should be too");
6684 0 : if (nsFrame::ApplyOverflowClipping(this, disp)) {
6685 : // The contents are actually clipped to the padding area
6686 0 : aOverflowAreas.SetAllTo(bounds);
6687 : }
6688 :
6689 : // Overflow area must always include the frame's top-left and bottom-right,
6690 : // even if the frame rect is empty.
6691 : // Pending a real fix for bug 426879, don't do this for inline frames
6692 : // with zero width.
6693 0 : if (aNewSize.width != 0 || !IsInlineFrame(this)) {
6694 0 : NS_FOR_FRAME_OVERFLOW_TYPES(otype) {
6695 0 : nsRect& o = aOverflowAreas.Overflow(otype);
6696 0 : o.UnionRectEdges(o, bounds);
6697 : }
6698 : }
6699 :
6700 : // Note that NS_STYLE_OVERFLOW_CLIP doesn't clip the frame background,
6701 : // so we add theme background overflow here so it's not clipped.
6702 0 : if (!IsBoxWrapped() && IsThemed(disp)) {
6703 0 : nsRect r(bounds);
6704 0 : nsPresContext *presContext = PresContext();
6705 0 : if (presContext->GetTheme()->
6706 : GetWidgetOverflow(presContext->DeviceContext(), this,
6707 0 : disp->mAppearance, &r)) {
6708 0 : nsRect& vo = aOverflowAreas.VisualOverflow();
6709 0 : vo.UnionRectEdges(vo, r);
6710 : }
6711 : }
6712 :
6713 : // Nothing in here should affect scrollable overflow.
6714 : bool hasOutlineOrEffects;
6715 0 : aOverflowAreas.VisualOverflow() =
6716 : ComputeOutlineAndEffectsRect(this, &hasOutlineOrEffects,
6717 0 : aOverflowAreas.VisualOverflow(), aNewSize,
6718 0 : true);
6719 :
6720 : // Absolute position clipping
6721 0 : bool didHaveClipPropClip = (GetStateBits() & NS_FRAME_HAS_CLIP) != 0;
6722 0 : nsRect clipPropClipRect;
6723 0 : bool hasClipPropClip = GetClipPropClipRect(disp, &clipPropClipRect, aNewSize);
6724 0 : if (hasClipPropClip) {
6725 0 : NS_FOR_FRAME_OVERFLOW_TYPES(otype) {
6726 0 : nsRect& o = aOverflowAreas.Overflow(otype);
6727 0 : o.IntersectRect(o, clipPropClipRect);
6728 : }
6729 0 : AddStateBits(NS_FRAME_HAS_CLIP);
6730 : } else {
6731 0 : RemoveStateBits(NS_FRAME_HAS_CLIP);
6732 : }
6733 :
6734 : bool preTransformVisualOverflowChanged =
6735 0 : !GetVisualOverflowRectRelativeToSelf().IsEqualInterior(aOverflowAreas.VisualOverflow());
6736 :
6737 : /* If we're transformed, transform the overflow rect by the current transformation. */
6738 0 : bool hasTransform = IsTransformed();
6739 0 : if (hasTransform) {
6740 : Properties().Set(nsIFrame::PreTransformOverflowAreasProperty(),
6741 0 : new nsOverflowAreas(aOverflowAreas));
6742 : /* Since our size might not actually have been computed yet, we need to make sure that we use the
6743 : * correct dimensions by overriding the stored bounding rectangle with the value the caller has
6744 : * ensured us we'll use.
6745 : */
6746 0 : nsRect newBounds(nsPoint(0, 0), aNewSize);
6747 : // Transform affects both overflow areas.
6748 0 : NS_FOR_FRAME_OVERFLOW_TYPES(otype) {
6749 0 : nsRect& o = aOverflowAreas.Overflow(otype);
6750 0 : o = nsDisplayTransform::TransformRect(o, this, nsPoint(0, 0), &newBounds);
6751 : }
6752 0 : if (Preserves3DChildren()) {
6753 0 : ComputePreserve3DChildrenOverflow(aOverflowAreas, newBounds);
6754 0 : } else if (ChildrenHavePerspective()) {
6755 0 : RecomputePerspectiveChildrenOverflow(this->GetStyleContext(), &newBounds);
6756 : }
6757 : } else {
6758 0 : Properties().Delete(nsIFrame::PreTransformOverflowAreasProperty());
6759 0 : if (ChildrenHavePerspective()) {
6760 0 : nsRect newBounds(nsPoint(0, 0), aNewSize);
6761 0 : RecomputePerspectiveChildrenOverflow(this->GetStyleContext(), &newBounds);
6762 : }
6763 : }
6764 :
6765 :
6766 : bool anyOverflowChanged;
6767 0 : if (aOverflowAreas != nsOverflowAreas(bounds, bounds)) {
6768 0 : anyOverflowChanged = SetOverflowAreas(aOverflowAreas);
6769 : } else {
6770 0 : anyOverflowChanged = ClearOverflowRects();
6771 : }
6772 :
6773 0 : if (preTransformVisualOverflowChanged) {
6774 0 : if (hasOutlineOrEffects) {
6775 : // When there's an outline or box-shadow or SVG effects,
6776 : // changes to those styles might require repainting of the old and new
6777 : // overflow areas. Repainting of the old overflow area is handled in
6778 : // nsCSSFrameConstructor::DoApplyRenderingChangeToTree in response
6779 : // to nsChangeHint_RepaintFrame. Since the new overflow area is not
6780 : // known at that time, we have to handle it here.
6781 : // If the overflow area hasn't changed, then we don't have to do
6782 : // anything here since repainting the old overflow area was enough.
6783 : // If there is no outline or other effects now, then we don't have
6784 : // to do anything here since removing those styles can't require
6785 : // repainting of areas that weren't in the old overflow area.
6786 0 : Invalidate(aOverflowAreas.VisualOverflow());
6787 0 : } else if (hasClipPropClip || didHaveClipPropClip) {
6788 : // If we are (or were) clipped by the 'clip' property, and our
6789 : // overflow area changes, it might be because the clipping changed.
6790 : // The nsChangeHint_RepaintFrame for the style change will only
6791 : // repaint the old overflow area, so if the overflow area has
6792 : // changed (in particular, if it grows), we have to repaint the
6793 : // new area here.
6794 0 : Invalidate(aOverflowAreas.VisualOverflow());
6795 : }
6796 : }
6797 0 : if (anyOverflowChanged && hasTransform) {
6798 : // When there's a transform, changes to that style might require
6799 : // repainting of the old and new overflow areas in the widget.
6800 : // Repainting of the frame itself will not be required if there's
6801 : // a retained layer, so we can call InvalidateLayer here
6802 : // which will avoid repainting ThebesLayers if possible.
6803 : // nsCSSFrameConstructor::DoApplyRenderingChangeToTree repaints
6804 : // the old overflow area in the widget in response to
6805 : // nsChangeHint_UpdateTransformLayer. But since the new overflow
6806 : // area is not known at that time, we have to handle it here.
6807 : // If the overflow area hasn't changed, then it doesn't matter that
6808 : // we didn't reach here since repainting the old overflow area was enough.
6809 : // If there is no transform now, then the container layer for
6810 : // the transform will go away and the frame contents will change
6811 : // ThebesLayers, forcing it to be invalidated, so it doesn't matter
6812 : // that we didn't reach here.
6813 0 : InvalidateLayer(aOverflowAreas.VisualOverflow(),
6814 0 : nsDisplayItem::TYPE_TRANSFORM);
6815 : }
6816 :
6817 0 : return anyOverflowChanged;
6818 : }
6819 :
6820 : void
6821 0 : nsIFrame::RecomputePerspectiveChildrenOverflow(const nsStyleContext* aStartStyle, const nsRect* aBounds)
6822 : {
6823 : // Children may check our size when getting our transform, make sure it's valid.
6824 0 : nsSize oldSize = GetSize();
6825 0 : if (aBounds) {
6826 0 : SetSize(aBounds->Size());
6827 : }
6828 0 : nsIFrame::ChildListIterator lists(this);
6829 0 : for (; !lists.IsDone(); lists.Next()) {
6830 0 : nsFrameList::Enumerator childFrames(lists.CurrentList());
6831 0 : for (; !childFrames.AtEnd(); childFrames.Next()) {
6832 0 : nsIFrame* child = childFrames.get();
6833 0 : if (child->HasPerspective()) {
6834 : nsOverflowAreas* overflow =
6835 0 : static_cast<nsOverflowAreas*>(child->Properties().Get(nsIFrame::InitialOverflowProperty()));
6836 0 : nsRect bounds(nsPoint(0, 0), child->GetSize());
6837 0 : if (overflow) {
6838 0 : child->FinishAndStoreOverflow(*overflow, bounds.Size());
6839 : } else {
6840 0 : nsOverflowAreas boundsOverflow;
6841 0 : boundsOverflow.SetAllTo(bounds);
6842 0 : child->FinishAndStoreOverflow(boundsOverflow, bounds.Size());
6843 : }
6844 0 : } else if (child->GetStyleContext()->GetParent() == aStartStyle ||
6845 0 : child->GetStyleContext() == aStartStyle) {
6846 : // Recurse into frames with the same style context, or a direct
6847 : // child style context.
6848 0 : child->RecomputePerspectiveChildrenOverflow(aStartStyle, nsnull);
6849 : }
6850 : }
6851 : }
6852 : // Restore our old size just in case something depends on this elesewhere.
6853 0 : SetSize(oldSize);
6854 0 : }
6855 :
6856 : /* The overflow rects for leaf nodes in a preserve-3d hierarchy depends on
6857 : * the mRect value for their parents (since we use their transform, and transform
6858 : * depends on this for transform-origin etc). These weren't necessarily correct
6859 : * when we reflowed initially, so walk over all preserve-3d children and repeat the
6860 : * overflow calculation.
6861 : */
6862 : static void
6863 0 : RecomputePreserve3DChildrenOverflow(nsIFrame* aFrame, const nsRect* aBounds)
6864 : {
6865 : // Children may check our size when getting our transform, make sure it's valid.
6866 0 : nsSize oldSize = aFrame->GetSize();
6867 0 : if (aBounds) {
6868 0 : aFrame->SetSize(aBounds->Size());
6869 : }
6870 0 : nsIFrame::ChildListIterator lists(aFrame);
6871 0 : for (; !lists.IsDone(); lists.Next()) {
6872 0 : nsFrameList::Enumerator childFrames(lists.CurrentList());
6873 0 : for (; !childFrames.AtEnd(); childFrames.Next()) {
6874 0 : nsIFrame* child = childFrames.get();
6875 0 : if (child->Preserves3DChildren()) {
6876 0 : RecomputePreserve3DChildrenOverflow(child, NULL);
6877 0 : } else if (child->Preserves3D()) {
6878 : nsOverflowAreas* overflow =
6879 0 : static_cast<nsOverflowAreas*>(child->Properties().Get(nsIFrame::InitialOverflowProperty()));
6880 0 : nsRect bounds(nsPoint(0, 0), child->GetSize());
6881 0 : if (overflow) {
6882 0 : child->FinishAndStoreOverflow(*overflow, bounds.Size());
6883 : } else {
6884 0 : nsOverflowAreas boundsOverflow;
6885 0 : boundsOverflow.SetAllTo(bounds);
6886 0 : child->FinishAndStoreOverflow(boundsOverflow, bounds.Size());
6887 : }
6888 : }
6889 : }
6890 : }
6891 : // Restore our old size just in case something depends on this elesewhere.
6892 0 : aFrame->SetSize(oldSize);
6893 :
6894 : // Only repeat computing our overflow in recursive calls since the initial caller is still
6895 : // in the middle of doing this and we don't want an infinite loop.
6896 0 : if (!aBounds) {
6897 : nsOverflowAreas* overflow =
6898 0 : static_cast<nsOverflowAreas*>(aFrame->Properties().Get(nsIFrame::InitialOverflowProperty()));
6899 0 : nsRect bounds(nsPoint(0, 0), aFrame->GetSize());
6900 0 : if (overflow) {
6901 0 : overflow->UnionAllWith(bounds);
6902 0 : aFrame->FinishAndStoreOverflow(*overflow, bounds.Size());
6903 : } else {
6904 0 : nsOverflowAreas boundsOverflow;
6905 0 : boundsOverflow.SetAllTo(bounds);
6906 0 : aFrame->FinishAndStoreOverflow(boundsOverflow, bounds.Size());
6907 : }
6908 : }
6909 0 : }
6910 :
6911 : void
6912 0 : nsIFrame::ComputePreserve3DChildrenOverflow(nsOverflowAreas& aOverflowAreas, const nsRect& aBounds)
6913 : {
6914 : // When we are preserving 3d we need to iterate over all children separately.
6915 : // If the child also preserves 3d then their overflow will already been in our
6916 : // coordinate space, otherwise we need to transform.
6917 :
6918 : // If we're the top frame in a preserve 3d chain then we need to recalculate the overflow
6919 : // areas of all our children since they will have used our size/offset which was invalid at
6920 : // the time.
6921 0 : if (!Preserves3D()) {
6922 0 : RecomputePreserve3DChildrenOverflow(this, &aBounds);
6923 : }
6924 :
6925 0 : nsRect childVisual;
6926 0 : nsRect childScrollable;
6927 0 : nsIFrame::ChildListIterator lists(this);
6928 0 : for (; !lists.IsDone(); lists.Next()) {
6929 0 : nsFrameList::Enumerator childFrames(lists.CurrentList());
6930 0 : for (; !childFrames.AtEnd(); childFrames.Next()) {
6931 0 : nsIFrame* child = childFrames.get();
6932 0 : nsPoint offset = child->GetPosition();
6933 0 : nsRect visual = child->GetVisualOverflowRect();
6934 0 : nsRect scrollable = child->GetScrollableOverflowRect();
6935 0 : visual.MoveBy(offset);
6936 0 : scrollable.MoveBy(offset);
6937 0 : if (child->Preserves3D()) {
6938 0 : childVisual = childVisual.Union(visual);
6939 0 : childScrollable = childScrollable.Union(scrollable);
6940 : } else {
6941 : childVisual =
6942 : childVisual.Union(nsDisplayTransform::TransformRect(visual,
6943 0 : this, nsPoint(0,0), &aBounds));
6944 : childScrollable =
6945 : childScrollable.Union(nsDisplayTransform::TransformRect(scrollable,
6946 0 : this, nsPoint(0,0), &aBounds));
6947 : }
6948 : }
6949 : }
6950 :
6951 0 : aOverflowAreas.Overflow(eVisualOverflow) = aOverflowAreas.Overflow(eVisualOverflow).Union(childVisual);
6952 0 : aOverflowAreas.Overflow(eScrollableOverflow) = aOverflowAreas.Overflow(eScrollableOverflow).Union(childScrollable);
6953 0 : }
6954 :
6955 : void
6956 0 : nsFrame::ConsiderChildOverflow(nsOverflowAreas& aOverflowAreas,
6957 : nsIFrame* aChildFrame)
6958 : {
6959 0 : aOverflowAreas.UnionWith(aChildFrame->GetOverflowAreas() +
6960 0 : aChildFrame->GetPosition());
6961 0 : }
6962 :
6963 : /**
6964 : * This function takes a "special" frame and _if_ that frame is an anonymous
6965 : * block created by an ib split it returns the block's preceding inline. This
6966 : * is needed because the split inline's style context is the parent of the
6967 : * anonymous block's style context.
6968 : *
6969 : * If aFrame is not an anonymous block, null is returned.
6970 : */
6971 : static nsIFrame*
6972 0 : GetIBSpecialSiblingForAnonymousBlock(const nsIFrame* aFrame)
6973 : {
6974 0 : NS_PRECONDITION(aFrame, "Must have a non-null frame!");
6975 0 : NS_ASSERTION(aFrame->GetStateBits() & NS_FRAME_IS_SPECIAL,
6976 : "GetIBSpecialSibling should not be called on a non-special frame");
6977 :
6978 0 : nsIAtom* type = aFrame->GetStyleContext()->GetPseudo();
6979 0 : if (type != nsCSSAnonBoxes::mozAnonymousBlock &&
6980 : type != nsCSSAnonBoxes::mozAnonymousPositionedBlock) {
6981 : // it's not an anonymous block
6982 0 : return nsnull;
6983 : }
6984 :
6985 : // Find the first continuation of the frame. (Ugh. This ends up
6986 : // being O(N^2) when it is called O(N) times.)
6987 0 : aFrame = aFrame->GetFirstContinuation();
6988 :
6989 : /*
6990 : * Now look up the nsGkAtoms::IBSplitSpecialPrevSibling
6991 : * property.
6992 : */
6993 : nsIFrame *specialSibling = static_cast<nsIFrame*>
6994 0 : (aFrame->Properties().Get(nsIFrame::IBSplitSpecialPrevSibling()));
6995 0 : NS_ASSERTION(specialSibling, "Broken frame tree?");
6996 0 : return specialSibling;
6997 : }
6998 :
6999 : /**
7000 : * Get the parent, corrected for the mangled frame tree resulting from
7001 : * having a block within an inline. The result only differs from the
7002 : * result of |GetParent| when |GetParent| returns an anonymous block
7003 : * that was created for an element that was 'display: inline' because
7004 : * that element contained a block.
7005 : *
7006 : * Also skip anonymous scrolled-content parents; inherit directly from the
7007 : * outer scroll frame.
7008 : */
7009 : static nsIFrame*
7010 0 : GetCorrectedParent(const nsIFrame* aFrame)
7011 : {
7012 0 : nsIFrame *parent = aFrame->GetParent();
7013 0 : if (!parent) {
7014 0 : return nsnull;
7015 : }
7016 :
7017 : // Outer tables are always anon boxes; if we're in here for an outer
7018 : // table, that actually means its the _inner_ table that wants to
7019 : // know its parent. So get the pseudo of the inner in that case.
7020 0 : nsIAtom* pseudo = aFrame->GetStyleContext()->GetPseudo();
7021 0 : if (pseudo == nsCSSAnonBoxes::tableOuter) {
7022 0 : pseudo = aFrame->GetFirstPrincipalChild()->GetStyleContext()->GetPseudo();
7023 : }
7024 0 : return nsFrame::CorrectStyleParentFrame(parent, pseudo);
7025 : }
7026 :
7027 : /* static */
7028 : nsIFrame*
7029 0 : nsFrame::CorrectStyleParentFrame(nsIFrame* aProspectiveParent,
7030 : nsIAtom* aChildPseudo)
7031 : {
7032 0 : NS_PRECONDITION(aProspectiveParent, "Must have a prospective parent");
7033 :
7034 : // Anon boxes are parented to their actual parent already, except
7035 : // for non-elements. Those should not be treated as an anon box.
7036 0 : if (aChildPseudo && aChildPseudo != nsCSSAnonBoxes::mozNonElement &&
7037 0 : nsCSSAnonBoxes::IsAnonBox(aChildPseudo)) {
7038 0 : NS_ASSERTION(aChildPseudo != nsCSSAnonBoxes::mozAnonymousBlock &&
7039 : aChildPseudo != nsCSSAnonBoxes::mozAnonymousPositionedBlock,
7040 : "Should have dealt with kids that have NS_FRAME_IS_SPECIAL "
7041 : "elsewhere");
7042 0 : return aProspectiveParent;
7043 : }
7044 :
7045 : // Otherwise, walk up out of all anon boxes. For placeholder frames, walk out
7046 : // of all pseudo-elements as well. Otherwise ReparentStyleContext could cause
7047 : // style data to be out of sync with the frame tree.
7048 0 : nsIFrame* parent = aProspectiveParent;
7049 0 : do {
7050 0 : if (parent->GetStateBits() & NS_FRAME_IS_SPECIAL) {
7051 0 : nsIFrame* sibling = GetIBSpecialSiblingForAnonymousBlock(parent);
7052 :
7053 0 : if (sibling) {
7054 : // |parent| was a block in an {ib} split; use the inline as
7055 : // |the style parent.
7056 0 : parent = sibling;
7057 : }
7058 : }
7059 :
7060 0 : nsIAtom* parentPseudo = parent->GetStyleContext()->GetPseudo();
7061 0 : if (!parentPseudo ||
7062 0 : (!nsCSSAnonBoxes::IsAnonBox(parentPseudo) &&
7063 : // nsPlaceholderFrame pases in nsGkAtoms::placeholderFrame for
7064 : // aChildPseudo (even though that's not a valid pseudo-type) just to
7065 : // trigger this behavior of walking up to the nearest non-pseudo
7066 : // ancestor.
7067 : aChildPseudo != nsGkAtoms::placeholderFrame)) {
7068 0 : return parent;
7069 : }
7070 :
7071 0 : parent = parent->GetParent();
7072 : } while (parent);
7073 :
7074 0 : if (aProspectiveParent->GetStyleContext()->GetPseudo() ==
7075 : nsCSSAnonBoxes::viewportScroll) {
7076 : // aProspectiveParent is the scrollframe for a viewport
7077 : // and the kids are the anonymous scrollbars
7078 0 : return aProspectiveParent;
7079 : }
7080 :
7081 : // We can get here if the root element is absolutely positioned.
7082 : // We can't test for this very accurately, but it can only happen
7083 : // when the prospective parent is a canvas frame.
7084 0 : NS_ASSERTION(aProspectiveParent->GetType() == nsGkAtoms::canvasFrame,
7085 : "Should have found a parent before this");
7086 0 : return nsnull;
7087 : }
7088 :
7089 : nsIFrame*
7090 0 : nsFrame::DoGetParentStyleContextFrame() const
7091 : {
7092 0 : if (mContent && !mContent->GetParent() &&
7093 0 : !GetStyleContext()->GetPseudo()) {
7094 : // we're a frame for the root. We have no style context parent.
7095 0 : return nsnull;
7096 : }
7097 :
7098 0 : if (!(mState & NS_FRAME_OUT_OF_FLOW)) {
7099 : /*
7100 : * If this frame is an anonymous block created when an inline with a block
7101 : * inside it got split, then the parent style context is on its preceding
7102 : * inline. We can get to it using GetIBSpecialSiblingForAnonymousBlock.
7103 : */
7104 0 : if (mState & NS_FRAME_IS_SPECIAL) {
7105 0 : nsIFrame* specialSibling = GetIBSpecialSiblingForAnonymousBlock(this);
7106 0 : if (specialSibling) {
7107 0 : return specialSibling;
7108 : }
7109 : }
7110 :
7111 : // If this frame is one of the blocks that split an inline, we must
7112 : // return the "special" inline parent, i.e., the parent that this
7113 : // frame would have if we didn't mangle the frame structure.
7114 0 : return GetCorrectedParent(this);
7115 : }
7116 :
7117 : // For out-of-flow frames, we must resolve underneath the
7118 : // placeholder's parent.
7119 0 : const nsIFrame* oofFrame = this;
7120 0 : if ((oofFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) &&
7121 0 : GetPrevInFlow()) {
7122 : // Out of flows that are continuations do not
7123 : // have placeholders. Use their first-in-flow's placeholder.
7124 0 : oofFrame = oofFrame->GetFirstInFlow();
7125 : }
7126 : nsIFrame* placeholder = oofFrame->PresContext()->FrameManager()->
7127 0 : GetPlaceholderFrameFor(oofFrame);
7128 0 : if (!placeholder) {
7129 0 : NS_NOTREACHED("no placeholder frame for out-of-flow frame");
7130 0 : return GetCorrectedParent(this);
7131 : }
7132 0 : return placeholder->GetParentStyleContextFrame();
7133 : }
7134 :
7135 : void
7136 0 : nsFrame::GetLastLeaf(nsPresContext* aPresContext, nsIFrame **aFrame)
7137 : {
7138 0 : if (!aFrame || !*aFrame)
7139 0 : return;
7140 0 : nsIFrame *child = *aFrame;
7141 : //if we are a block frame then go for the last line of 'this'
7142 0 : while (1){
7143 0 : child = child->GetFirstPrincipalChild();
7144 0 : if (!child)
7145 0 : return;//nothing to do
7146 : nsIFrame* siblingFrame;
7147 : nsIContent* content;
7148 : //ignore anonymous elements, e.g. mozTableAdd* mozTableRemove*
7149 : //see bug 278197 comment #12 #13 for details
7150 0 : while ((siblingFrame = child->GetNextSibling()) &&
7151 : (content = siblingFrame->GetContent()) &&
7152 0 : !content->IsRootOfNativeAnonymousSubtree())
7153 0 : child = siblingFrame;
7154 0 : *aFrame = child;
7155 : }
7156 : }
7157 :
7158 : void
7159 0 : nsFrame::GetFirstLeaf(nsPresContext* aPresContext, nsIFrame **aFrame)
7160 : {
7161 0 : if (!aFrame || !*aFrame)
7162 0 : return;
7163 0 : nsIFrame *child = *aFrame;
7164 0 : while (1){
7165 0 : child = child->GetFirstPrincipalChild();
7166 0 : if (!child)
7167 0 : return;//nothing to do
7168 0 : *aFrame = child;
7169 : }
7170 : }
7171 :
7172 : /* virtual */ const void*
7173 0 : nsFrame::GetStyleDataExternal(nsStyleStructID aSID) const
7174 : {
7175 0 : NS_ASSERTION(mStyleContext, "unexpected null pointer");
7176 0 : return mStyleContext->GetStyleData(aSID);
7177 : }
7178 :
7179 : /* virtual */ bool
7180 0 : nsIFrame::IsFocusable(PRInt32 *aTabIndex, bool aWithMouse)
7181 : {
7182 0 : PRInt32 tabIndex = -1;
7183 0 : if (aTabIndex) {
7184 0 : *aTabIndex = -1; // Default for early return is not focusable
7185 : }
7186 0 : bool isFocusable = false;
7187 :
7188 0 : if (mContent && mContent->IsElement() && IsVisibleConsideringAncestors()) {
7189 0 : const nsStyleUserInterface* ui = GetStyleUserInterface();
7190 0 : if (ui->mUserFocus != NS_STYLE_USER_FOCUS_IGNORE &&
7191 : ui->mUserFocus != NS_STYLE_USER_FOCUS_NONE) {
7192 : // Pass in default tabindex of -1 for nonfocusable and 0 for focusable
7193 0 : tabIndex = 0;
7194 : }
7195 0 : isFocusable = mContent->IsFocusable(&tabIndex, aWithMouse);
7196 0 : if (!isFocusable && !aWithMouse &&
7197 0 : GetType() == nsGkAtoms::scrollFrame &&
7198 0 : mContent->IsHTML() &&
7199 0 : !mContent->IsRootOfNativeAnonymousSubtree() &&
7200 0 : mContent->GetParent() &&
7201 0 : !mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::tabindex)) {
7202 : // Elements with scrollable view are focusable with script & tabbable
7203 : // Otherwise you couldn't scroll them with keyboard, which is
7204 : // an accessibility issue (e.g. Section 508 rules)
7205 : // However, we don't make them to be focusable with the mouse,
7206 : // because the extra focus outlines are considered unnecessarily ugly.
7207 : // When clicked on, the selection position within the element
7208 : // will be enough to make them keyboard scrollable.
7209 0 : nsIScrollableFrame *scrollFrame = do_QueryFrame(this);
7210 0 : if (scrollFrame &&
7211 0 : scrollFrame->GetScrollbarStyles() != nsIScrollableFrame::ScrollbarStyles(NS_STYLE_OVERFLOW_HIDDEN, NS_STYLE_OVERFLOW_HIDDEN) &&
7212 0 : !scrollFrame->GetScrollRange().IsEqualEdges(nsRect(0, 0, 0, 0))) {
7213 : // Scroll bars will be used for overflow
7214 0 : isFocusable = true;
7215 0 : tabIndex = 0;
7216 : }
7217 : }
7218 : }
7219 :
7220 0 : if (aTabIndex) {
7221 0 : *aTabIndex = tabIndex;
7222 : }
7223 0 : return isFocusable;
7224 : }
7225 :
7226 : /**
7227 : * @return true if this text frame ends with a newline character. It
7228 : * should return false if this is not a text frame.
7229 : */
7230 : bool
7231 0 : nsIFrame::HasTerminalNewline() const
7232 : {
7233 0 : return false;
7234 : }
7235 :
7236 : /* static */
7237 0 : void nsFrame::FillCursorInformationFromStyle(const nsStyleUserInterface* ui,
7238 : nsIFrame::Cursor& aCursor)
7239 : {
7240 0 : aCursor.mCursor = ui->mCursor;
7241 0 : aCursor.mHaveHotspot = false;
7242 0 : aCursor.mHotspotX = aCursor.mHotspotY = 0.0f;
7243 :
7244 0 : for (nsCursorImage *item = ui->mCursorArray,
7245 0 : *item_end = ui->mCursorArray + ui->mCursorArrayLength;
7246 : item < item_end; ++item) {
7247 : PRUint32 status;
7248 0 : nsresult rv = item->GetImage()->GetImageStatus(&status);
7249 0 : if (NS_SUCCEEDED(rv) && (status & imgIRequest::STATUS_LOAD_COMPLETE)) {
7250 : // This is the one we want
7251 0 : item->GetImage()->GetImage(getter_AddRefs(aCursor.mContainer));
7252 0 : aCursor.mHaveHotspot = item->mHaveHotspot;
7253 0 : aCursor.mHotspotX = item->mHotspotX;
7254 0 : aCursor.mHotspotY = item->mHotspotY;
7255 0 : break;
7256 : }
7257 : }
7258 0 : }
7259 :
7260 : NS_IMETHODIMP
7261 0 : nsFrame::RefreshSizeCache(nsBoxLayoutState& aState)
7262 : {
7263 : // XXXbz this comment needs some rewriting to make sense in the
7264 : // post-reflow-branch world.
7265 :
7266 : // Ok we need to compute our minimum, preferred, and maximum sizes.
7267 : // 1) Maximum size. This is easy. Its infinite unless it is overloaded by CSS.
7268 : // 2) Preferred size. This is a little harder. This is the size the block would be
7269 : // if it were laid out on an infinite canvas. So we can get this by reflowing
7270 : // the block with and INTRINSIC width and height. We can also do a nice optimization
7271 : // for incremental reflow. If the reflow is incremental then we can pass a flag to
7272 : // have the block compute the preferred width for us! Preferred height can just be
7273 : // the minimum height;
7274 : // 3) Minimum size. This is a toughy. We can pass the block a flag asking for the max element
7275 : // size. That would give us the width. Unfortunately you can only ask for a maxElementSize
7276 : // during an incremental reflow. So on other reflows we will just have to use 0.
7277 : // The min height on the other hand is fairly easy we need to get the largest
7278 : // line height. This can be done with the line iterator.
7279 :
7280 : // if we do have a rendering context
7281 0 : nsresult rv = NS_OK;
7282 0 : nsRenderingContext* rendContext = aState.GetRenderingContext();
7283 0 : if (rendContext) {
7284 0 : nsPresContext* presContext = aState.PresContext();
7285 :
7286 : // If we don't have any HTML constraints and it's a resize, then nothing in the block
7287 : // could have changed, so no refresh is necessary.
7288 0 : nsBoxLayoutMetrics* metrics = BoxMetrics();
7289 0 : if (!DoesNeedRecalc(metrics->mBlockPrefSize))
7290 0 : return NS_OK;
7291 :
7292 : // get the old rect.
7293 0 : nsRect oldRect = GetRect();
7294 :
7295 : // the rect we plan to size to.
7296 0 : nsRect rect(oldRect);
7297 :
7298 0 : nsMargin bp(0,0,0,0);
7299 0 : GetBorderAndPadding(bp);
7300 :
7301 : {
7302 : // If we're a container for font size inflation, then shrink
7303 : // wrapping inside of us should not apply font size inflation.
7304 0 : AutoMaybeNullInflationContainer an(this);
7305 :
7306 : metrics->mBlockPrefSize.width =
7307 0 : GetPrefWidth(rendContext) + bp.LeftRight();
7308 : metrics->mBlockMinSize.width =
7309 0 : GetMinWidth(rendContext) + bp.LeftRight();
7310 : }
7311 :
7312 : // do the nasty.
7313 0 : nsHTMLReflowMetrics desiredSize;
7314 : rv = BoxReflow(aState, presContext, desiredSize, rendContext,
7315 : rect.x, rect.y,
7316 0 : metrics->mBlockPrefSize.width, NS_UNCONSTRAINEDSIZE);
7317 :
7318 0 : nsRect newRect = GetRect();
7319 :
7320 : // make sure we draw any size change
7321 0 : if (oldRect.width != newRect.width || oldRect.height != newRect.height) {
7322 0 : newRect.x = 0;
7323 0 : newRect.y = 0;
7324 0 : Redraw(aState, &newRect);
7325 : }
7326 :
7327 0 : metrics->mBlockMinSize.height = 0;
7328 : // ok we need the max ascent of the items on the line. So to do this
7329 : // ask the block for its line iterator. Get the max ascent.
7330 0 : nsAutoLineIterator lines = GetLineIterator();
7331 0 : if (lines)
7332 : {
7333 0 : metrics->mBlockMinSize.height = 0;
7334 0 : int count = 0;
7335 0 : nsIFrame* firstFrame = nsnull;
7336 : PRInt32 framesOnLine;
7337 0 : nsRect lineBounds;
7338 : PRUint32 lineFlags;
7339 :
7340 0 : do {
7341 0 : lines->GetLine(count, &firstFrame, &framesOnLine, lineBounds, &lineFlags);
7342 :
7343 0 : if (lineBounds.height > metrics->mBlockMinSize.height)
7344 0 : metrics->mBlockMinSize.height = lineBounds.height;
7345 :
7346 0 : count++;
7347 : } while(firstFrame);
7348 : } else {
7349 0 : metrics->mBlockMinSize.height = desiredSize.height;
7350 : }
7351 :
7352 0 : metrics->mBlockPrefSize.height = metrics->mBlockMinSize.height;
7353 :
7354 0 : if (desiredSize.ascent == nsHTMLReflowMetrics::ASK_FOR_BASELINE) {
7355 0 : if (!nsLayoutUtils::GetFirstLineBaseline(this, &metrics->mBlockAscent))
7356 0 : metrics->mBlockAscent = GetBaseline();
7357 : } else {
7358 0 : metrics->mBlockAscent = desiredSize.ascent;
7359 : }
7360 :
7361 : #ifdef DEBUG_adaptor
7362 : printf("min=(%d,%d), pref=(%d,%d), ascent=%d\n", metrics->mBlockMinSize.width,
7363 : metrics->mBlockMinSize.height,
7364 : metrics->mBlockPrefSize.width,
7365 : metrics->mBlockPrefSize.height,
7366 : metrics->mBlockAscent);
7367 : #endif
7368 : }
7369 :
7370 0 : return rv;
7371 : }
7372 :
7373 : /* virtual */ nsILineIterator*
7374 0 : nsFrame::GetLineIterator()
7375 : {
7376 0 : return nsnull;
7377 : }
7378 :
7379 : nsSize
7380 0 : nsFrame::GetPrefSize(nsBoxLayoutState& aState)
7381 : {
7382 0 : nsSize size(0,0);
7383 0 : DISPLAY_PREF_SIZE(this, size);
7384 : // If the size is cached, and there are no HTML constraints that we might
7385 : // be depending on, then we just return the cached size.
7386 0 : nsBoxLayoutMetrics *metrics = BoxMetrics();
7387 0 : if (!DoesNeedRecalc(metrics->mPrefSize)) {
7388 0 : return metrics->mPrefSize;
7389 : }
7390 :
7391 0 : if (IsCollapsed())
7392 0 : return size;
7393 :
7394 : // get our size in CSS.
7395 : bool widthSet, heightSet;
7396 0 : bool completelyRedefined = nsIBox::AddCSSPrefSize(this, size, widthSet, heightSet);
7397 :
7398 : // Refresh our caches with new sizes.
7399 0 : if (!completelyRedefined) {
7400 0 : RefreshSizeCache(aState);
7401 0 : nsSize blockSize = metrics->mBlockPrefSize;
7402 :
7403 : // notice we don't need to add our borders or padding
7404 : // in. That's because the block did it for us.
7405 0 : if (!widthSet)
7406 0 : size.width = blockSize.width;
7407 0 : if (!heightSet)
7408 0 : size.height = blockSize.height;
7409 : }
7410 :
7411 0 : metrics->mPrefSize = size;
7412 0 : return size;
7413 : }
7414 :
7415 : nsSize
7416 0 : nsFrame::GetMinSize(nsBoxLayoutState& aState)
7417 : {
7418 0 : nsSize size(0,0);
7419 0 : DISPLAY_MIN_SIZE(this, size);
7420 : // Don't use the cache if we have HTMLReflowState constraints --- they might have changed
7421 0 : nsBoxLayoutMetrics *metrics = BoxMetrics();
7422 0 : if (!DoesNeedRecalc(metrics->mMinSize)) {
7423 0 : size = metrics->mMinSize;
7424 : return size;
7425 : }
7426 :
7427 0 : if (IsCollapsed())
7428 : return size;
7429 :
7430 : // get our size in CSS.
7431 : bool widthSet, heightSet;
7432 : bool completelyRedefined =
7433 0 : nsIBox::AddCSSMinSize(aState, this, size, widthSet, heightSet);
7434 :
7435 : // Refresh our caches with new sizes.
7436 0 : if (!completelyRedefined) {
7437 0 : RefreshSizeCache(aState);
7438 0 : nsSize blockSize = metrics->mBlockMinSize;
7439 :
7440 0 : if (!widthSet)
7441 0 : size.width = blockSize.width;
7442 0 : if (!heightSet)
7443 0 : size.height = blockSize.height;
7444 : }
7445 :
7446 0 : metrics->mMinSize = size;
7447 : return size;
7448 : }
7449 :
7450 : nsSize
7451 0 : nsFrame::GetMaxSize(nsBoxLayoutState& aState)
7452 : {
7453 0 : nsSize size(NS_INTRINSICSIZE, NS_INTRINSICSIZE);
7454 0 : DISPLAY_MAX_SIZE(this, size);
7455 : // Don't use the cache if we have HTMLReflowState constraints --- they might have changed
7456 0 : nsBoxLayoutMetrics *metrics = BoxMetrics();
7457 0 : if (!DoesNeedRecalc(metrics->mMaxSize)) {
7458 0 : size = metrics->mMaxSize;
7459 : return size;
7460 : }
7461 :
7462 0 : if (IsCollapsed())
7463 : return size;
7464 :
7465 0 : size = nsBox::GetMaxSize(aState);
7466 0 : metrics->mMaxSize = size;
7467 :
7468 : return size;
7469 : }
7470 :
7471 : nscoord
7472 0 : nsFrame::GetFlex(nsBoxLayoutState& aState)
7473 : {
7474 0 : nsBoxLayoutMetrics *metrics = BoxMetrics();
7475 0 : if (!DoesNeedRecalc(metrics->mFlex))
7476 0 : return metrics->mFlex;
7477 :
7478 0 : metrics->mFlex = nsBox::GetFlex(aState);
7479 :
7480 0 : return metrics->mFlex;
7481 : }
7482 :
7483 : nscoord
7484 0 : nsFrame::GetBoxAscent(nsBoxLayoutState& aState)
7485 : {
7486 0 : nsBoxLayoutMetrics *metrics = BoxMetrics();
7487 0 : if (!DoesNeedRecalc(metrics->mAscent))
7488 0 : return metrics->mAscent;
7489 :
7490 0 : if (IsCollapsed()) {
7491 0 : metrics->mAscent = 0;
7492 : } else {
7493 : // Refresh our caches with new sizes.
7494 0 : RefreshSizeCache(aState);
7495 0 : metrics->mAscent = metrics->mBlockAscent;
7496 : }
7497 :
7498 0 : return metrics->mAscent;
7499 : }
7500 :
7501 : nsresult
7502 0 : nsFrame::DoLayout(nsBoxLayoutState& aState)
7503 : {
7504 0 : nsRect ourRect(mRect);
7505 :
7506 0 : nsRenderingContext* rendContext = aState.GetRenderingContext();
7507 0 : nsPresContext* presContext = aState.PresContext();
7508 0 : nsHTMLReflowMetrics desiredSize;
7509 0 : nsresult rv = NS_OK;
7510 :
7511 0 : if (rendContext) {
7512 :
7513 : rv = BoxReflow(aState, presContext, desiredSize, rendContext,
7514 0 : ourRect.x, ourRect.y, ourRect.width, ourRect.height);
7515 :
7516 0 : if (IsCollapsed()) {
7517 0 : SetSize(nsSize(0, 0));
7518 : } else {
7519 :
7520 : // if our child needs to be bigger. This might happend with
7521 : // wrapping text. There is no way to predict its height until we
7522 : // reflow it. Now that we know the height reshuffle upward.
7523 0 : if (desiredSize.width > ourRect.width ||
7524 : desiredSize.height > ourRect.height) {
7525 :
7526 : #ifdef DEBUG_GROW
7527 : DumpBox(stdout);
7528 : printf(" GREW from (%d,%d) -> (%d,%d)\n",
7529 : ourRect.width, ourRect.height,
7530 : desiredSize.width, desiredSize.height);
7531 : #endif
7532 :
7533 0 : if (desiredSize.width > ourRect.width)
7534 0 : ourRect.width = desiredSize.width;
7535 :
7536 0 : if (desiredSize.height > ourRect.height)
7537 0 : ourRect.height = desiredSize.height;
7538 : }
7539 :
7540 : // ensure our size is what we think is should be. Someone could have
7541 : // reset the frame to be smaller or something dumb like that.
7542 0 : SetSize(nsSize(ourRect.width, ourRect.height));
7543 : }
7544 : }
7545 :
7546 : // Should we do this if IsCollapsed() is true?
7547 0 : nsSize size(GetSize());
7548 0 : desiredSize.width = size.width;
7549 0 : desiredSize.height = size.height;
7550 0 : desiredSize.UnionOverflowAreasWithDesiredBounds();
7551 :
7552 0 : if (HasAbsolutelyPositionedChildren()) {
7553 : // Set up a |reflowState| to pass into ReflowAbsoluteFrames
7554 : nsHTMLReflowState reflowState(aState.PresContext(), this,
7555 : aState.GetRenderingContext(),
7556 0 : nsSize(size.width, NS_UNCONSTRAINEDSIZE));
7557 :
7558 : // Set up a |reflowStatus| to pass into ReflowAbsoluteFrames
7559 : // (just a dummy value; hopefully that's OK)
7560 0 : nsReflowStatus reflowStatus = NS_FRAME_COMPLETE;
7561 : ReflowAbsoluteFrames(aState.PresContext(), desiredSize,
7562 0 : reflowState, reflowStatus);
7563 : }
7564 :
7565 0 : FinishAndStoreOverflow(desiredSize.mOverflowAreas, size);
7566 :
7567 0 : SyncLayout(aState);
7568 :
7569 0 : return rv;
7570 : }
7571 :
7572 : nsresult
7573 0 : nsFrame::BoxReflow(nsBoxLayoutState& aState,
7574 : nsPresContext* aPresContext,
7575 : nsHTMLReflowMetrics& aDesiredSize,
7576 : nsRenderingContext* aRenderingContext,
7577 : nscoord aX,
7578 : nscoord aY,
7579 : nscoord aWidth,
7580 : nscoord aHeight,
7581 : bool aMoveFrame)
7582 : {
7583 0 : DO_GLOBAL_REFLOW_COUNT("nsBoxToBlockAdaptor");
7584 :
7585 : #ifdef DEBUG_REFLOW
7586 : nsAdaptorAddIndents();
7587 : printf("Reflowing: ");
7588 : nsFrame::ListTag(stdout, mFrame);
7589 : printf("\n");
7590 : gIndent2++;
7591 : #endif
7592 :
7593 : //printf("width=%d, height=%d\n", aWidth, aHeight);
7594 : /*
7595 : nsIBox* parent;
7596 : GetParentBox(&parent);
7597 :
7598 : // if (parent->GetStateBits() & NS_STATE_CURRENTLY_IN_DEBUG)
7599 : // printf("In debug\n");
7600 : */
7601 :
7602 0 : nsBoxLayoutMetrics *metrics = BoxMetrics();
7603 0 : nsReflowStatus status = NS_FRAME_COMPLETE;
7604 :
7605 0 : bool redrawAfterReflow = false;
7606 0 : bool redrawNow = false;
7607 :
7608 0 : bool needsReflow = NS_SUBTREE_DIRTY(this);
7609 :
7610 0 : if (redrawNow)
7611 0 : Redraw(aState);
7612 :
7613 : // if we don't need a reflow then
7614 : // lets see if we are already that size. Yes? then don't even reflow. We are done.
7615 0 : if (!needsReflow) {
7616 :
7617 0 : if (aWidth != NS_INTRINSICSIZE && aHeight != NS_INTRINSICSIZE) {
7618 :
7619 : // if the new calculated size has a 0 width or a 0 height
7620 0 : if ((metrics->mLastSize.width == 0 || metrics->mLastSize.height == 0) && (aWidth == 0 || aHeight == 0)) {
7621 0 : needsReflow = false;
7622 0 : aDesiredSize.width = aWidth;
7623 0 : aDesiredSize.height = aHeight;
7624 0 : SetSize(nsSize(aDesiredSize.width, aDesiredSize.height));
7625 : } else {
7626 0 : aDesiredSize.width = metrics->mLastSize.width;
7627 0 : aDesiredSize.height = metrics->mLastSize.height;
7628 :
7629 : // remove the margin. The rect of our child does not include it but our calculated size does.
7630 : // don't reflow if we are already the right size
7631 0 : if (metrics->mLastSize.width == aWidth && metrics->mLastSize.height == aHeight)
7632 0 : needsReflow = false;
7633 : else
7634 0 : needsReflow = true;
7635 :
7636 : }
7637 : } else {
7638 : // if the width or height are intrinsic alway reflow because
7639 : // we don't know what it should be.
7640 0 : needsReflow = true;
7641 : }
7642 : }
7643 :
7644 : // ok now reflow the child into the spacers calculated space
7645 0 : if (needsReflow) {
7646 :
7647 0 : aDesiredSize.width = 0;
7648 0 : aDesiredSize.height = 0;
7649 :
7650 : // create a reflow state to tell our child to flow at the given size.
7651 :
7652 : // Construct a bogus parent reflow state so that there's a usable
7653 : // containing block reflow state.
7654 0 : nsMargin margin(0,0,0,0);
7655 0 : GetMargin(margin);
7656 :
7657 0 : nsSize parentSize(aWidth, aHeight);
7658 0 : if (parentSize.height != NS_INTRINSICSIZE)
7659 0 : parentSize.height += margin.TopBottom();
7660 0 : if (parentSize.width != NS_INTRINSICSIZE)
7661 0 : parentSize.width += margin.LeftRight();
7662 :
7663 0 : nsIFrame *parentFrame = GetParent();
7664 0 : nsFrameState savedState = parentFrame->GetStateBits();
7665 : nsHTMLReflowState parentReflowState(aPresContext, parentFrame,
7666 : aRenderingContext,
7667 0 : parentSize);
7668 0 : parentFrame->RemoveStateBits(~nsFrameState(0));
7669 0 : parentFrame->AddStateBits(savedState);
7670 :
7671 : // This may not do very much useful, but it's probably worth trying.
7672 0 : if (parentSize.width != NS_INTRINSICSIZE)
7673 0 : parentReflowState.SetComputedWidth(NS_MAX(parentSize.width, 0));
7674 0 : if (parentSize.height != NS_INTRINSICSIZE)
7675 0 : parentReflowState.SetComputedHeight(NS_MAX(parentSize.height, 0));
7676 0 : parentReflowState.mComputedMargin.SizeTo(0, 0, 0, 0);
7677 : // XXX use box methods
7678 0 : parentFrame->GetPadding(parentReflowState.mComputedPadding);
7679 0 : parentFrame->GetBorder(parentReflowState.mComputedBorderPadding);
7680 : parentReflowState.mComputedBorderPadding +=
7681 0 : parentReflowState.mComputedPadding;
7682 :
7683 : // XXX Is it OK that this reflow state has no parent reflow state?
7684 : // (It used to have a bogus parent, skipping all the boxes).
7685 0 : nsSize availSize(aWidth, NS_INTRINSICSIZE);
7686 : nsHTMLReflowState reflowState(aPresContext, this, aRenderingContext,
7687 0 : availSize);
7688 :
7689 : // Construct the parent chain manually since constructing it normally
7690 : // messes up dimensions.
7691 0 : const nsHTMLReflowState *outerReflowState = aState.OuterReflowState();
7692 0 : NS_ASSERTION(!outerReflowState || outerReflowState->frame != this,
7693 : "in and out of XUL on a single frame?");
7694 0 : if (outerReflowState && outerReflowState->frame == parentFrame) {
7695 : // We're a frame (such as a text control frame) that jumps into
7696 : // box reflow and then straight out of it on the child frame.
7697 : // This means we actually have a real parent reflow state.
7698 : // nsLayoutUtils::InflationMinFontSizeFor used to need this to be
7699 : // linked up correctly for text control frames, so do so here).
7700 0 : reflowState.parentReflowState = outerReflowState;
7701 0 : reflowState.mCBReflowState = outerReflowState;
7702 : } else {
7703 0 : reflowState.parentReflowState = &parentReflowState;
7704 0 : reflowState.mCBReflowState = &parentReflowState;
7705 : }
7706 0 : reflowState.mReflowDepth = aState.GetReflowDepth();
7707 :
7708 : // mComputedWidth and mComputedHeight are content-box, not
7709 : // border-box
7710 0 : if (aWidth != NS_INTRINSICSIZE) {
7711 : nscoord computedWidth =
7712 0 : aWidth - reflowState.mComputedBorderPadding.LeftRight();
7713 0 : computedWidth = NS_MAX(computedWidth, 0);
7714 0 : reflowState.SetComputedWidth(computedWidth);
7715 : }
7716 :
7717 : // Most child frames of box frames (e.g. subdocument or scroll frames)
7718 : // need to be constrained to the provided size and overflow as necessary.
7719 : // The one exception are block frames, because we need to know their
7720 : // natural height excluding any overflow area which may be caused by
7721 : // various CSS effects such as shadow or outline.
7722 0 : if (!IsFrameOfType(eBlockFrame)) {
7723 0 : if (aHeight != NS_INTRINSICSIZE) {
7724 : nscoord computedHeight =
7725 0 : aHeight - reflowState.mComputedBorderPadding.TopBottom();
7726 0 : computedHeight = NS_MAX(computedHeight, 0);
7727 0 : reflowState.SetComputedHeight(computedHeight);
7728 : } else {
7729 : reflowState.SetComputedHeight(
7730 : ComputeSize(aRenderingContext, availSize, availSize.width,
7731 : nsSize(reflowState.mComputedMargin.LeftRight(),
7732 : reflowState.mComputedMargin.TopBottom()),
7733 0 : nsSize(reflowState.mComputedBorderPadding.LeftRight() -
7734 0 : reflowState.mComputedPadding.LeftRight(),
7735 0 : reflowState.mComputedBorderPadding.TopBottom() -
7736 0 : reflowState.mComputedPadding.TopBottom()),
7737 : nsSize(reflowState.mComputedPadding.LeftRight(),
7738 : reflowState.mComputedPadding.TopBottom()),
7739 0 : false).height
7740 0 : );
7741 : }
7742 : }
7743 :
7744 : // Box layout calls SetRect before Layout, whereas non-box layout
7745 : // calls SetRect after Reflow.
7746 : // XXX Perhaps we should be doing this by twiddling the rect back to
7747 : // mLastSize before calling Reflow and then switching it back, but
7748 : // However, mLastSize can also be the size passed to BoxReflow by
7749 : // RefreshSizeCache, so that doesn't really make sense.
7750 0 : if (metrics->mLastSize.width != aWidth) {
7751 0 : reflowState.mFlags.mHResize = true;
7752 :
7753 : // When font size inflation is enabled, a horizontal resize
7754 : // requires a full reflow. See nsHTMLReflowState::InitResizeFlags
7755 : // for more details.
7756 0 : if (nsLayoutUtils::FontSizeInflationEnabled(aPresContext)) {
7757 0 : AddStateBits(NS_FRAME_IS_DIRTY);
7758 : }
7759 : }
7760 0 : if (metrics->mLastSize.height != aHeight)
7761 0 : reflowState.mFlags.mVResize = true;
7762 :
7763 : #ifdef DEBUG_REFLOW
7764 : nsAdaptorAddIndents();
7765 : printf("Size=(%d,%d)\n",reflowState.ComputedWidth(),
7766 : reflowState.ComputedHeight());
7767 : nsAdaptorAddIndents();
7768 : nsAdaptorPrintReason(reflowState);
7769 : printf("\n");
7770 : #endif
7771 :
7772 : // place the child and reflow
7773 0 : WillReflow(aPresContext);
7774 :
7775 0 : Reflow(aPresContext, aDesiredSize, reflowState, status);
7776 :
7777 0 : NS_ASSERTION(NS_FRAME_IS_COMPLETE(status), "bad status");
7778 :
7779 0 : if (redrawAfterReflow) {
7780 0 : nsRect r = GetRect();
7781 0 : r.width = aDesiredSize.width;
7782 0 : r.height = aDesiredSize.height;
7783 0 : Redraw(aState, &r);
7784 : }
7785 :
7786 0 : PRUint32 layoutFlags = aState.LayoutFlags();
7787 : nsContainerFrame::FinishReflowChild(this, aPresContext, &reflowState,
7788 0 : aDesiredSize, aX, aY, layoutFlags | NS_FRAME_NO_MOVE_FRAME);
7789 :
7790 : // Save the ascent. (bug 103925)
7791 0 : if (IsCollapsed()) {
7792 0 : metrics->mAscent = 0;
7793 : } else {
7794 0 : if (aDesiredSize.ascent == nsHTMLReflowMetrics::ASK_FOR_BASELINE) {
7795 0 : if (!nsLayoutUtils::GetFirstLineBaseline(this, &metrics->mAscent))
7796 0 : metrics->mAscent = GetBaseline();
7797 : } else
7798 0 : metrics->mAscent = aDesiredSize.ascent;
7799 : }
7800 :
7801 : } else {
7802 0 : aDesiredSize.ascent = metrics->mBlockAscent;
7803 : }
7804 :
7805 : #ifdef DEBUG_REFLOW
7806 : if (aHeight != NS_INTRINSICSIZE && aDesiredSize.height != aHeight)
7807 : {
7808 : nsAdaptorAddIndents();
7809 : printf("*****got taller!*****\n");
7810 :
7811 : }
7812 : if (aWidth != NS_INTRINSICSIZE && aDesiredSize.width != aWidth)
7813 : {
7814 : nsAdaptorAddIndents();
7815 : printf("*****got wider!******\n");
7816 :
7817 : }
7818 : #endif
7819 :
7820 0 : if (aWidth == NS_INTRINSICSIZE)
7821 0 : aWidth = aDesiredSize.width;
7822 :
7823 0 : if (aHeight == NS_INTRINSICSIZE)
7824 0 : aHeight = aDesiredSize.height;
7825 :
7826 0 : metrics->mLastSize.width = aDesiredSize.width;
7827 0 : metrics->mLastSize.height = aDesiredSize.height;
7828 :
7829 : #ifdef DEBUG_REFLOW
7830 : gIndent2--;
7831 : #endif
7832 :
7833 0 : return NS_OK;
7834 : }
7835 :
7836 : static void
7837 0 : DestroyBoxMetrics(void* aPropertyValue)
7838 : {
7839 : delete static_cast<nsBoxLayoutMetrics*>(aPropertyValue);
7840 0 : }
7841 :
7842 0 : NS_DECLARE_FRAME_PROPERTY(BoxMetricsProperty, DestroyBoxMetrics)
7843 :
7844 : nsBoxLayoutMetrics*
7845 0 : nsFrame::BoxMetrics() const
7846 : {
7847 : nsBoxLayoutMetrics* metrics =
7848 0 : static_cast<nsBoxLayoutMetrics*>(Properties().Get(BoxMetricsProperty()));
7849 0 : NS_ASSERTION(metrics, "A box layout method was called but InitBoxMetrics was never called");
7850 0 : return metrics;
7851 : }
7852 :
7853 : void
7854 0 : nsFrame::SetParent(nsIFrame* aParent)
7855 : {
7856 0 : bool wasBoxWrapped = IsBoxWrapped();
7857 0 : mParent = aParent;
7858 0 : if (!wasBoxWrapped && IsBoxWrapped()) {
7859 0 : InitBoxMetrics(true);
7860 0 : } else if (wasBoxWrapped && !IsBoxWrapped()) {
7861 0 : Properties().Delete(BoxMetricsProperty());
7862 : }
7863 :
7864 0 : if (GetStateBits() & (NS_FRAME_HAS_VIEW | NS_FRAME_HAS_CHILD_WITH_VIEW)) {
7865 0 : for (nsIFrame* f = aParent;
7866 0 : f && !(f->GetStateBits() & NS_FRAME_HAS_CHILD_WITH_VIEW);
7867 : f = f->GetParent()) {
7868 0 : f->AddStateBits(NS_FRAME_HAS_CHILD_WITH_VIEW);
7869 : }
7870 : }
7871 :
7872 0 : if (GetStateBits() & NS_FRAME_HAS_CONTAINER_LAYER_DESCENDANT) {
7873 0 : for (nsIFrame* f = aParent;
7874 0 : f && !(f->GetStateBits() & NS_FRAME_HAS_CONTAINER_LAYER_DESCENDANT);
7875 : f = nsLayoutUtils::GetCrossDocParentFrame(f)) {
7876 0 : f->AddStateBits(NS_FRAME_HAS_CONTAINER_LAYER_DESCENDANT);
7877 : }
7878 : }
7879 0 : }
7880 :
7881 : void
7882 0 : nsFrame::InitBoxMetrics(bool aClear)
7883 : {
7884 0 : FrameProperties props = Properties();
7885 0 : if (aClear) {
7886 0 : props.Delete(BoxMetricsProperty());
7887 : }
7888 :
7889 0 : nsBoxLayoutMetrics *metrics = new nsBoxLayoutMetrics();
7890 0 : props.Set(BoxMetricsProperty(), metrics);
7891 :
7892 0 : nsFrame::MarkIntrinsicWidthsDirty();
7893 0 : metrics->mBlockAscent = 0;
7894 0 : metrics->mLastSize.SizeTo(0, 0);
7895 0 : }
7896 :
7897 : // Box layout debugging
7898 : #ifdef DEBUG_REFLOW
7899 : PRInt32 gIndent2 = 0;
7900 :
7901 : void
7902 : nsAdaptorAddIndents()
7903 : {
7904 : for(PRInt32 i=0; i < gIndent2; i++)
7905 : {
7906 : printf(" ");
7907 : }
7908 : }
7909 :
7910 : void
7911 : nsAdaptorPrintReason(nsHTMLReflowState& aReflowState)
7912 : {
7913 : char* reflowReasonString;
7914 :
7915 : switch(aReflowState.reason)
7916 : {
7917 : case eReflowReason_Initial:
7918 : reflowReasonString = "initial";
7919 : break;
7920 :
7921 : case eReflowReason_Resize:
7922 : reflowReasonString = "resize";
7923 : break;
7924 : case eReflowReason_Dirty:
7925 : reflowReasonString = "dirty";
7926 : break;
7927 : case eReflowReason_StyleChange:
7928 : reflowReasonString = "stylechange";
7929 : break;
7930 : case eReflowReason_Incremental:
7931 : {
7932 : switch (aReflowState.reflowCommand->Type()) {
7933 : case eReflowType_StyleChanged:
7934 : reflowReasonString = "incremental (StyleChanged)";
7935 : break;
7936 : case eReflowType_ReflowDirty:
7937 : reflowReasonString = "incremental (ReflowDirty)";
7938 : break;
7939 : default:
7940 : reflowReasonString = "incremental (Unknown)";
7941 : }
7942 : }
7943 : break;
7944 : default:
7945 : reflowReasonString = "unknown";
7946 : break;
7947 : }
7948 :
7949 : printf("%s",reflowReasonString);
7950 : }
7951 :
7952 : #endif
7953 : #ifdef DEBUG_LAYOUT
7954 : void
7955 : nsFrame::GetBoxName(nsAutoString& aName)
7956 : {
7957 : GetFrameName(aName);
7958 : }
7959 : #endif
7960 :
7961 : #ifdef NS_DEBUG
7962 : static void
7963 0 : GetTagName(nsFrame* aFrame, nsIContent* aContent, PRIntn aResultSize,
7964 : char* aResult)
7965 : {
7966 0 : if (aContent) {
7967 : PR_snprintf(aResult, aResultSize, "%s@%p",
7968 0 : nsAtomCString(aContent->Tag()).get(), aFrame);
7969 : }
7970 : else {
7971 0 : PR_snprintf(aResult, aResultSize, "@%p", aFrame);
7972 : }
7973 0 : }
7974 :
7975 : void
7976 0 : nsFrame::Trace(const char* aMethod, bool aEnter)
7977 : {
7978 0 : if (NS_FRAME_LOG_TEST(gLogModule, NS_FRAME_TRACE_CALLS)) {
7979 : char tagbuf[40];
7980 0 : GetTagName(this, mContent, sizeof(tagbuf), tagbuf);
7981 0 : PR_LogPrint("%s: %s %s", tagbuf, aEnter ? "enter" : "exit", aMethod);
7982 : }
7983 0 : }
7984 :
7985 : void
7986 0 : nsFrame::Trace(const char* aMethod, bool aEnter, nsReflowStatus aStatus)
7987 : {
7988 0 : if (NS_FRAME_LOG_TEST(gLogModule, NS_FRAME_TRACE_CALLS)) {
7989 : char tagbuf[40];
7990 0 : GetTagName(this, mContent, sizeof(tagbuf), tagbuf);
7991 : PR_LogPrint("%s: %s %s, status=%scomplete%s",
7992 : tagbuf, aEnter ? "enter" : "exit", aMethod,
7993 : NS_FRAME_IS_NOT_COMPLETE(aStatus) ? "not" : "",
7994 0 : (NS_FRAME_REFLOW_NEXTINFLOW & aStatus) ? "+reflow" : "");
7995 : }
7996 0 : }
7997 :
7998 : void
7999 0 : nsFrame::TraceMsg(const char* aFormatString, ...)
8000 : {
8001 0 : if (NS_FRAME_LOG_TEST(gLogModule, NS_FRAME_TRACE_CALLS)) {
8002 : // Format arguments into a buffer
8003 : char argbuf[200];
8004 : va_list ap;
8005 0 : va_start(ap, aFormatString);
8006 0 : PR_vsnprintf(argbuf, sizeof(argbuf), aFormatString, ap);
8007 0 : va_end(ap);
8008 :
8009 : char tagbuf[40];
8010 0 : GetTagName(this, mContent, sizeof(tagbuf), tagbuf);
8011 0 : PR_LogPrint("%s: %s", tagbuf, argbuf);
8012 : }
8013 0 : }
8014 :
8015 : void
8016 0 : nsFrame::VerifyDirtyBitSet(const nsFrameList& aFrameList)
8017 : {
8018 0 : for (nsFrameList::Enumerator e(aFrameList); !e.AtEnd(); e.Next()) {
8019 0 : NS_ASSERTION(e.get()->GetStateBits() & NS_FRAME_IS_DIRTY,
8020 : "dirty bit not set");
8021 : }
8022 0 : }
8023 :
8024 : // Start Display Reflow
8025 : #ifdef DEBUG
8026 :
8027 0 : DR_cookie::DR_cookie(nsPresContext* aPresContext,
8028 : nsIFrame* aFrame,
8029 : const nsHTMLReflowState& aReflowState,
8030 : nsHTMLReflowMetrics& aMetrics,
8031 : nsReflowStatus& aStatus)
8032 0 : :mPresContext(aPresContext), mFrame(aFrame), mReflowState(aReflowState), mMetrics(aMetrics), mStatus(aStatus)
8033 : {
8034 0 : MOZ_COUNT_CTOR(DR_cookie);
8035 0 : mValue = nsFrame::DisplayReflowEnter(aPresContext, mFrame, mReflowState);
8036 0 : }
8037 :
8038 0 : DR_cookie::~DR_cookie()
8039 : {
8040 0 : MOZ_COUNT_DTOR(DR_cookie);
8041 0 : nsFrame::DisplayReflowExit(mPresContext, mFrame, mMetrics, mStatus, mValue);
8042 0 : }
8043 :
8044 0 : DR_layout_cookie::DR_layout_cookie(nsIFrame* aFrame)
8045 0 : : mFrame(aFrame)
8046 : {
8047 0 : MOZ_COUNT_CTOR(DR_layout_cookie);
8048 0 : mValue = nsFrame::DisplayLayoutEnter(mFrame);
8049 0 : }
8050 :
8051 0 : DR_layout_cookie::~DR_layout_cookie()
8052 : {
8053 0 : MOZ_COUNT_DTOR(DR_layout_cookie);
8054 0 : nsFrame::DisplayLayoutExit(mFrame, mValue);
8055 0 : }
8056 :
8057 0 : DR_intrinsic_width_cookie::DR_intrinsic_width_cookie(
8058 : nsIFrame* aFrame,
8059 : const char* aType,
8060 : nscoord& aResult)
8061 : : mFrame(aFrame)
8062 : , mType(aType)
8063 0 : , mResult(aResult)
8064 : {
8065 0 : MOZ_COUNT_CTOR(DR_intrinsic_width_cookie);
8066 0 : mValue = nsFrame::DisplayIntrinsicWidthEnter(mFrame, mType);
8067 0 : }
8068 :
8069 0 : DR_intrinsic_width_cookie::~DR_intrinsic_width_cookie()
8070 : {
8071 0 : MOZ_COUNT_DTOR(DR_intrinsic_width_cookie);
8072 0 : nsFrame::DisplayIntrinsicWidthExit(mFrame, mType, mResult, mValue);
8073 0 : }
8074 :
8075 0 : DR_intrinsic_size_cookie::DR_intrinsic_size_cookie(
8076 : nsIFrame* aFrame,
8077 : const char* aType,
8078 : nsSize& aResult)
8079 : : mFrame(aFrame)
8080 : , mType(aType)
8081 0 : , mResult(aResult)
8082 : {
8083 0 : MOZ_COUNT_CTOR(DR_intrinsic_size_cookie);
8084 0 : mValue = nsFrame::DisplayIntrinsicSizeEnter(mFrame, mType);
8085 0 : }
8086 :
8087 0 : DR_intrinsic_size_cookie::~DR_intrinsic_size_cookie()
8088 : {
8089 0 : MOZ_COUNT_DTOR(DR_intrinsic_size_cookie);
8090 0 : nsFrame::DisplayIntrinsicSizeExit(mFrame, mType, mResult, mValue);
8091 0 : }
8092 :
8093 0 : DR_init_constraints_cookie::DR_init_constraints_cookie(
8094 : nsIFrame* aFrame,
8095 : nsHTMLReflowState* aState,
8096 : nscoord aCBWidth,
8097 : nscoord aCBHeight,
8098 : const nsMargin* aMargin,
8099 : const nsMargin* aPadding)
8100 : : mFrame(aFrame)
8101 0 : , mState(aState)
8102 : {
8103 0 : MOZ_COUNT_CTOR(DR_init_constraints_cookie);
8104 : mValue = nsHTMLReflowState::DisplayInitConstraintsEnter(mFrame, mState,
8105 : aCBWidth, aCBHeight,
8106 0 : aMargin, aPadding);
8107 0 : }
8108 :
8109 0 : DR_init_constraints_cookie::~DR_init_constraints_cookie()
8110 : {
8111 0 : MOZ_COUNT_DTOR(DR_init_constraints_cookie);
8112 0 : nsHTMLReflowState::DisplayInitConstraintsExit(mFrame, mState, mValue);
8113 0 : }
8114 :
8115 0 : DR_init_offsets_cookie::DR_init_offsets_cookie(
8116 : nsIFrame* aFrame,
8117 : nsCSSOffsetState* aState,
8118 : nscoord aCBWidth,
8119 : const nsMargin* aMargin,
8120 : const nsMargin* aPadding)
8121 : : mFrame(aFrame)
8122 0 : , mState(aState)
8123 : {
8124 0 : MOZ_COUNT_CTOR(DR_init_offsets_cookie);
8125 : mValue = nsCSSOffsetState::DisplayInitOffsetsEnter(mFrame, mState, aCBWidth,
8126 0 : aMargin, aPadding);
8127 0 : }
8128 :
8129 0 : DR_init_offsets_cookie::~DR_init_offsets_cookie()
8130 : {
8131 0 : MOZ_COUNT_DTOR(DR_init_offsets_cookie);
8132 0 : nsCSSOffsetState::DisplayInitOffsetsExit(mFrame, mState, mValue);
8133 0 : }
8134 :
8135 0 : DR_init_type_cookie::DR_init_type_cookie(
8136 : nsIFrame* aFrame,
8137 : nsHTMLReflowState* aState)
8138 : : mFrame(aFrame)
8139 0 : , mState(aState)
8140 : {
8141 0 : MOZ_COUNT_CTOR(DR_init_type_cookie);
8142 0 : mValue = nsHTMLReflowState::DisplayInitFrameTypeEnter(mFrame, mState);
8143 0 : }
8144 :
8145 0 : DR_init_type_cookie::~DR_init_type_cookie()
8146 : {
8147 0 : MOZ_COUNT_DTOR(DR_init_type_cookie);
8148 0 : nsHTMLReflowState::DisplayInitFrameTypeExit(mFrame, mState, mValue);
8149 0 : }
8150 :
8151 : struct DR_FrameTypeInfo;
8152 : struct DR_FrameTreeNode;
8153 : struct DR_Rule;
8154 :
8155 : struct DR_State
8156 : {
8157 : DR_State();
8158 : ~DR_State();
8159 : void Init();
8160 : void AddFrameTypeInfo(nsIAtom* aFrameType,
8161 : const char* aFrameNameAbbrev,
8162 : const char* aFrameName);
8163 : DR_FrameTypeInfo* GetFrameTypeInfo(nsIAtom* aFrameType);
8164 : DR_FrameTypeInfo* GetFrameTypeInfo(char* aFrameName);
8165 : void InitFrameTypeTable();
8166 : DR_FrameTreeNode* CreateTreeNode(nsIFrame* aFrame,
8167 : const nsHTMLReflowState* aReflowState);
8168 : void FindMatchingRule(DR_FrameTreeNode& aNode);
8169 : bool RuleMatches(DR_Rule& aRule,
8170 : DR_FrameTreeNode& aNode);
8171 : bool GetToken(FILE* aFile,
8172 : char* aBuf,
8173 : size_t aBufSize);
8174 : DR_Rule* ParseRule(FILE* aFile);
8175 : void ParseRulesFile();
8176 : void AddRule(nsTArray<DR_Rule*>& aRules,
8177 : DR_Rule& aRule);
8178 : bool IsWhiteSpace(int c);
8179 : bool GetNumber(char* aBuf,
8180 : PRInt32& aNumber);
8181 : void PrettyUC(nscoord aSize,
8182 : char* aBuf);
8183 : void PrintMargin(const char* tag, const nsMargin* aMargin);
8184 : void DisplayFrameTypeInfo(nsIFrame* aFrame,
8185 : PRInt32 aIndent);
8186 : void DeleteTreeNode(DR_FrameTreeNode& aNode);
8187 :
8188 : bool mInited;
8189 : bool mActive;
8190 : PRInt32 mCount;
8191 : PRInt32 mAssert;
8192 : PRInt32 mIndent;
8193 : bool mIndentUndisplayedFrames;
8194 : bool mDisplayPixelErrors;
8195 : nsTArray<DR_Rule*> mWildRules;
8196 : nsTArray<DR_FrameTypeInfo> mFrameTypeTable;
8197 : // reflow specific state
8198 : nsTArray<DR_FrameTreeNode*> mFrameTreeLeaves;
8199 : };
8200 :
8201 : static DR_State *DR_state; // the one and only DR_State
8202 :
8203 : struct DR_RulePart
8204 : {
8205 0 : DR_RulePart(nsIAtom* aFrameType) : mFrameType(aFrameType), mNext(0) {}
8206 : void Destroy();
8207 :
8208 : nsIAtom* mFrameType;
8209 : DR_RulePart* mNext;
8210 : };
8211 :
8212 0 : void DR_RulePart::Destroy()
8213 : {
8214 0 : if (mNext) {
8215 0 : mNext->Destroy();
8216 : }
8217 : delete this;
8218 0 : }
8219 :
8220 : struct DR_Rule
8221 : {
8222 0 : DR_Rule() : mLength(0), mTarget(nsnull), mDisplay(false) {
8223 0 : MOZ_COUNT_CTOR(DR_Rule);
8224 0 : }
8225 0 : ~DR_Rule() {
8226 0 : if (mTarget) mTarget->Destroy();
8227 0 : MOZ_COUNT_DTOR(DR_Rule);
8228 0 : }
8229 : void AddPart(nsIAtom* aFrameType);
8230 :
8231 : PRUint32 mLength;
8232 : DR_RulePart* mTarget;
8233 : bool mDisplay;
8234 : };
8235 :
8236 0 : void DR_Rule::AddPart(nsIAtom* aFrameType)
8237 : {
8238 0 : DR_RulePart* newPart = new DR_RulePart(aFrameType);
8239 0 : newPart->mNext = mTarget;
8240 0 : mTarget = newPart;
8241 0 : mLength++;
8242 0 : }
8243 :
8244 : struct DR_FrameTypeInfo
8245 0 : {
8246 : DR_FrameTypeInfo(nsIAtom* aFrmeType, const char* aFrameNameAbbrev, const char* aFrameName);
8247 0 : ~DR_FrameTypeInfo() {
8248 : PRInt32 numElements;
8249 0 : numElements = mRules.Length();
8250 0 : for (PRInt32 i = numElements - 1; i >= 0; i--) {
8251 0 : delete mRules.ElementAt(i);
8252 : }
8253 0 : }
8254 :
8255 : nsIAtom* mType;
8256 : char mNameAbbrev[16];
8257 : char mName[32];
8258 : nsTArray<DR_Rule*> mRules;
8259 : private:
8260 : DR_FrameTypeInfo& operator=(const DR_FrameTypeInfo&) MOZ_DELETE;
8261 : };
8262 :
8263 0 : DR_FrameTypeInfo::DR_FrameTypeInfo(nsIAtom* aFrameType,
8264 : const char* aFrameNameAbbrev,
8265 0 : const char* aFrameName)
8266 : {
8267 0 : mType = aFrameType;
8268 0 : PL_strncpyz(mNameAbbrev, aFrameNameAbbrev, sizeof(mNameAbbrev));
8269 0 : PL_strncpyz(mName, aFrameName, sizeof(mName));
8270 0 : }
8271 :
8272 : struct DR_FrameTreeNode
8273 : {
8274 0 : DR_FrameTreeNode(nsIFrame* aFrame, DR_FrameTreeNode* aParent) : mFrame(aFrame), mParent(aParent), mDisplay(0), mIndent(0)
8275 : {
8276 0 : MOZ_COUNT_CTOR(DR_FrameTreeNode);
8277 0 : }
8278 :
8279 0 : ~DR_FrameTreeNode()
8280 : {
8281 0 : MOZ_COUNT_DTOR(DR_FrameTreeNode);
8282 0 : }
8283 :
8284 : nsIFrame* mFrame;
8285 : DR_FrameTreeNode* mParent;
8286 : bool mDisplay;
8287 : PRUint32 mIndent;
8288 : };
8289 :
8290 : // DR_State implementation
8291 :
8292 1404 : DR_State::DR_State()
8293 : : mInited(false), mActive(false), mCount(0), mAssert(-1), mIndent(0),
8294 1404 : mIndentUndisplayedFrames(false), mDisplayPixelErrors(false)
8295 : {
8296 1404 : MOZ_COUNT_CTOR(DR_State);
8297 1404 : }
8298 :
8299 0 : void DR_State::Init()
8300 : {
8301 0 : char* env = PR_GetEnv("GECKO_DISPLAY_REFLOW_ASSERT");
8302 : PRInt32 num;
8303 0 : if (env) {
8304 0 : if (GetNumber(env, num))
8305 0 : mAssert = num;
8306 : else
8307 0 : printf("GECKO_DISPLAY_REFLOW_ASSERT - invalid value = %s", env);
8308 : }
8309 :
8310 0 : env = PR_GetEnv("GECKO_DISPLAY_REFLOW_INDENT_START");
8311 0 : if (env) {
8312 0 : if (GetNumber(env, num))
8313 0 : mIndent = num;
8314 : else
8315 0 : printf("GECKO_DISPLAY_REFLOW_INDENT_START - invalid value = %s", env);
8316 : }
8317 :
8318 0 : env = PR_GetEnv("GECKO_DISPLAY_REFLOW_INDENT_UNDISPLAYED_FRAMES");
8319 0 : if (env) {
8320 0 : if (GetNumber(env, num))
8321 0 : mIndentUndisplayedFrames = num;
8322 : else
8323 0 : printf("GECKO_DISPLAY_REFLOW_INDENT_UNDISPLAYED_FRAMES - invalid value = %s", env);
8324 : }
8325 :
8326 0 : env = PR_GetEnv("GECKO_DISPLAY_REFLOW_FLAG_PIXEL_ERRORS");
8327 0 : if (env) {
8328 0 : if (GetNumber(env, num))
8329 0 : mDisplayPixelErrors = num;
8330 : else
8331 0 : printf("GECKO_DISPLAY_REFLOW_FLAG_PIXEL_ERRORS - invalid value = %s", env);
8332 : }
8333 :
8334 0 : InitFrameTypeTable();
8335 0 : ParseRulesFile();
8336 0 : mInited = true;
8337 0 : }
8338 :
8339 2806 : DR_State::~DR_State()
8340 : {
8341 1403 : MOZ_COUNT_DTOR(DR_State);
8342 : PRInt32 numElements, i;
8343 1403 : numElements = mWildRules.Length();
8344 1403 : for (i = numElements - 1; i >= 0; i--) {
8345 0 : delete mWildRules.ElementAt(i);
8346 : }
8347 1403 : numElements = mFrameTreeLeaves.Length();
8348 1403 : for (i = numElements - 1; i >= 0; i--) {
8349 0 : delete mFrameTreeLeaves.ElementAt(i);
8350 : }
8351 1403 : }
8352 :
8353 0 : bool DR_State::GetNumber(char* aBuf,
8354 : PRInt32& aNumber)
8355 : {
8356 0 : if (sscanf(aBuf, "%d", &aNumber) > 0)
8357 0 : return true;
8358 : else
8359 0 : return false;
8360 : }
8361 :
8362 0 : bool DR_State::IsWhiteSpace(int c) {
8363 0 : return (c == ' ') || (c == '\t') || (c == '\n') || (c == '\r');
8364 : }
8365 :
8366 0 : bool DR_State::GetToken(FILE* aFile,
8367 : char* aBuf,
8368 : size_t aBufSize)
8369 : {
8370 0 : bool haveToken = false;
8371 0 : aBuf[0] = 0;
8372 : // get the 1st non whitespace char
8373 0 : int c = -1;
8374 0 : for (c = getc(aFile); (c > 0) && IsWhiteSpace(c); c = getc(aFile)) {
8375 : }
8376 :
8377 0 : if (c > 0) {
8378 0 : haveToken = true;
8379 0 : aBuf[0] = c;
8380 : // get everything up to the next whitespace char
8381 : size_t cX;
8382 0 : for (cX = 1; cX + 1 < aBufSize ; cX++) {
8383 0 : c = getc(aFile);
8384 0 : if (c < 0) { // EOF
8385 0 : ungetc(' ', aFile);
8386 0 : break;
8387 : }
8388 : else {
8389 0 : if (IsWhiteSpace(c)) {
8390 0 : break;
8391 : }
8392 : else {
8393 0 : aBuf[cX] = c;
8394 : }
8395 : }
8396 : }
8397 0 : aBuf[cX] = 0;
8398 : }
8399 0 : return haveToken;
8400 : }
8401 :
8402 0 : DR_Rule* DR_State::ParseRule(FILE* aFile)
8403 : {
8404 : char buf[128];
8405 : PRInt32 doDisplay;
8406 0 : DR_Rule* rule = nsnull;
8407 0 : while (GetToken(aFile, buf, sizeof(buf))) {
8408 0 : if (GetNumber(buf, doDisplay)) {
8409 0 : if (rule) {
8410 0 : rule->mDisplay = !!doDisplay;
8411 0 : break;
8412 : }
8413 : else {
8414 0 : printf("unexpected token - %s \n", buf);
8415 : }
8416 : }
8417 : else {
8418 0 : if (!rule) {
8419 0 : rule = new DR_Rule;
8420 : }
8421 0 : if (strcmp(buf, "*") == 0) {
8422 0 : rule->AddPart(nsnull);
8423 : }
8424 : else {
8425 0 : DR_FrameTypeInfo* info = GetFrameTypeInfo(buf);
8426 0 : if (info) {
8427 0 : rule->AddPart(info->mType);
8428 : }
8429 : else {
8430 0 : printf("invalid frame type - %s \n", buf);
8431 : }
8432 : }
8433 : }
8434 : }
8435 0 : return rule;
8436 : }
8437 :
8438 0 : void DR_State::AddRule(nsTArray<DR_Rule*>& aRules,
8439 : DR_Rule& aRule)
8440 : {
8441 0 : PRInt32 numRules = aRules.Length();
8442 0 : for (PRInt32 ruleX = 0; ruleX < numRules; ruleX++) {
8443 0 : DR_Rule* rule = aRules.ElementAt(ruleX);
8444 0 : NS_ASSERTION(rule, "program error");
8445 0 : if (aRule.mLength > rule->mLength) {
8446 0 : aRules.InsertElementAt(ruleX, &aRule);
8447 0 : return;
8448 : }
8449 : }
8450 0 : aRules.AppendElement(&aRule);
8451 : }
8452 :
8453 0 : void DR_State::ParseRulesFile()
8454 : {
8455 0 : char* path = PR_GetEnv("GECKO_DISPLAY_REFLOW_RULES_FILE");
8456 0 : if (path) {
8457 0 : FILE* inFile = fopen(path, "r");
8458 0 : if (inFile) {
8459 0 : for (DR_Rule* rule = ParseRule(inFile); rule; rule = ParseRule(inFile)) {
8460 0 : if (rule->mTarget) {
8461 0 : nsIAtom* fType = rule->mTarget->mFrameType;
8462 0 : if (fType) {
8463 0 : DR_FrameTypeInfo* info = GetFrameTypeInfo(fType);
8464 0 : if (info) {
8465 0 : AddRule(info->mRules, *rule);
8466 : }
8467 : }
8468 : else {
8469 0 : AddRule(mWildRules, *rule);
8470 : }
8471 0 : mActive = true;
8472 : }
8473 : }
8474 : }
8475 : }
8476 0 : }
8477 :
8478 :
8479 0 : void DR_State::AddFrameTypeInfo(nsIAtom* aFrameType,
8480 : const char* aFrameNameAbbrev,
8481 : const char* aFrameName)
8482 : {
8483 0 : mFrameTypeTable.AppendElement(DR_FrameTypeInfo(aFrameType, aFrameNameAbbrev, aFrameName));
8484 0 : }
8485 :
8486 0 : DR_FrameTypeInfo* DR_State::GetFrameTypeInfo(nsIAtom* aFrameType)
8487 : {
8488 0 : PRInt32 numEntries = mFrameTypeTable.Length();
8489 0 : NS_ASSERTION(numEntries != 0, "empty FrameTypeTable");
8490 0 : for (PRInt32 i = 0; i < numEntries; i++) {
8491 0 : DR_FrameTypeInfo& info = mFrameTypeTable.ElementAt(i);
8492 0 : if (info.mType == aFrameType) {
8493 0 : return &info;
8494 : }
8495 : }
8496 0 : return &mFrameTypeTable.ElementAt(numEntries - 1); // return unknown frame type
8497 : }
8498 :
8499 0 : DR_FrameTypeInfo* DR_State::GetFrameTypeInfo(char* aFrameName)
8500 : {
8501 0 : PRInt32 numEntries = mFrameTypeTable.Length();
8502 0 : NS_ASSERTION(numEntries != 0, "empty FrameTypeTable");
8503 0 : for (PRInt32 i = 0; i < numEntries; i++) {
8504 0 : DR_FrameTypeInfo& info = mFrameTypeTable.ElementAt(i);
8505 0 : if ((strcmp(aFrameName, info.mName) == 0) || (strcmp(aFrameName, info.mNameAbbrev) == 0)) {
8506 0 : return &info;
8507 : }
8508 : }
8509 0 : return &mFrameTypeTable.ElementAt(numEntries - 1); // return unknown frame type
8510 : }
8511 :
8512 0 : void DR_State::InitFrameTypeTable()
8513 : {
8514 0 : AddFrameTypeInfo(nsGkAtoms::blockFrame, "block", "block");
8515 0 : AddFrameTypeInfo(nsGkAtoms::brFrame, "br", "br");
8516 0 : AddFrameTypeInfo(nsGkAtoms::bulletFrame, "bullet", "bullet");
8517 0 : AddFrameTypeInfo(nsGkAtoms::gfxButtonControlFrame, "button", "gfxButtonControl");
8518 0 : AddFrameTypeInfo(nsGkAtoms::HTMLButtonControlFrame, "HTMLbutton", "HTMLButtonControl");
8519 0 : AddFrameTypeInfo(nsGkAtoms::HTMLCanvasFrame, "HTMLCanvas","HTMLCanvas");
8520 0 : AddFrameTypeInfo(nsGkAtoms::subDocumentFrame, "subdoc", "subDocument");
8521 0 : AddFrameTypeInfo(nsGkAtoms::imageFrame, "img", "image");
8522 0 : AddFrameTypeInfo(nsGkAtoms::inlineFrame, "inline", "inline");
8523 0 : AddFrameTypeInfo(nsGkAtoms::letterFrame, "letter", "letter");
8524 0 : AddFrameTypeInfo(nsGkAtoms::lineFrame, "line", "line");
8525 0 : AddFrameTypeInfo(nsGkAtoms::listControlFrame, "select", "select");
8526 0 : AddFrameTypeInfo(nsGkAtoms::objectFrame, "obj", "object");
8527 0 : AddFrameTypeInfo(nsGkAtoms::pageFrame, "page", "page");
8528 0 : AddFrameTypeInfo(nsGkAtoms::placeholderFrame, "place", "placeholder");
8529 0 : AddFrameTypeInfo(nsGkAtoms::canvasFrame, "canvas", "canvas");
8530 0 : AddFrameTypeInfo(nsGkAtoms::rootFrame, "root", "root");
8531 0 : AddFrameTypeInfo(nsGkAtoms::scrollFrame, "scroll", "scroll");
8532 0 : AddFrameTypeInfo(nsGkAtoms::tableCaptionFrame, "caption", "tableCaption");
8533 0 : AddFrameTypeInfo(nsGkAtoms::tableCellFrame, "cell", "tableCell");
8534 0 : AddFrameTypeInfo(nsGkAtoms::bcTableCellFrame, "bcCell", "bcTableCell");
8535 0 : AddFrameTypeInfo(nsGkAtoms::tableColFrame, "col", "tableCol");
8536 0 : AddFrameTypeInfo(nsGkAtoms::tableColGroupFrame, "colG", "tableColGroup");
8537 0 : AddFrameTypeInfo(nsGkAtoms::tableFrame, "tbl", "table");
8538 0 : AddFrameTypeInfo(nsGkAtoms::tableOuterFrame, "tblO", "tableOuter");
8539 0 : AddFrameTypeInfo(nsGkAtoms::tableRowGroupFrame, "rowG", "tableRowGroup");
8540 0 : AddFrameTypeInfo(nsGkAtoms::tableRowFrame, "row", "tableRow");
8541 0 : AddFrameTypeInfo(nsGkAtoms::textInputFrame, "textCtl", "textInput");
8542 0 : AddFrameTypeInfo(nsGkAtoms::textFrame, "text", "text");
8543 0 : AddFrameTypeInfo(nsGkAtoms::viewportFrame, "VP", "viewport");
8544 : #ifdef MOZ_XUL
8545 0 : AddFrameTypeInfo(nsGkAtoms::XULLabelFrame, "XULLabel", "XULLabel");
8546 0 : AddFrameTypeInfo(nsGkAtoms::boxFrame, "Box", "Box");
8547 0 : AddFrameTypeInfo(nsGkAtoms::sliderFrame, "Slider", "Slider");
8548 0 : AddFrameTypeInfo(nsGkAtoms::popupSetFrame, "PopupSet", "PopupSet");
8549 : #endif
8550 0 : AddFrameTypeInfo(nsnull, "unknown", "unknown");
8551 0 : }
8552 :
8553 :
8554 0 : void DR_State::DisplayFrameTypeInfo(nsIFrame* aFrame,
8555 : PRInt32 aIndent)
8556 : {
8557 0 : DR_FrameTypeInfo* frameTypeInfo = GetFrameTypeInfo(aFrame->GetType());
8558 0 : if (frameTypeInfo) {
8559 0 : for (PRInt32 i = 0; i < aIndent; i++) {
8560 0 : printf(" ");
8561 : }
8562 0 : if(!strcmp(frameTypeInfo->mNameAbbrev, "unknown")) {
8563 0 : if (aFrame) {
8564 0 : nsAutoString name;
8565 0 : aFrame->GetFrameName(name);
8566 0 : printf("%s %p ", NS_LossyConvertUTF16toASCII(name).get(), (void*)aFrame);
8567 : }
8568 : else {
8569 0 : printf("%s %p ", frameTypeInfo->mNameAbbrev, (void*)aFrame);
8570 : }
8571 : }
8572 : else {
8573 0 : printf("%s %p ", frameTypeInfo->mNameAbbrev, (void*)aFrame);
8574 : }
8575 : }
8576 0 : }
8577 :
8578 0 : bool DR_State::RuleMatches(DR_Rule& aRule,
8579 : DR_FrameTreeNode& aNode)
8580 : {
8581 0 : NS_ASSERTION(aRule.mTarget, "program error");
8582 :
8583 : DR_RulePart* rulePart;
8584 : DR_FrameTreeNode* parentNode;
8585 0 : for (rulePart = aRule.mTarget->mNext, parentNode = aNode.mParent;
8586 : rulePart && parentNode;
8587 : rulePart = rulePart->mNext, parentNode = parentNode->mParent) {
8588 0 : if (rulePart->mFrameType) {
8589 0 : if (parentNode->mFrame) {
8590 0 : if (rulePart->mFrameType != parentNode->mFrame->GetType()) {
8591 0 : return false;
8592 : }
8593 : }
8594 0 : else NS_ASSERTION(false, "program error");
8595 : }
8596 : // else wild card match
8597 : }
8598 0 : return true;
8599 : }
8600 :
8601 0 : void DR_State::FindMatchingRule(DR_FrameTreeNode& aNode)
8602 : {
8603 0 : if (!aNode.mFrame) {
8604 0 : NS_ASSERTION(false, "invalid DR_FrameTreeNode \n");
8605 0 : return;
8606 : }
8607 :
8608 0 : bool matchingRule = false;
8609 :
8610 0 : DR_FrameTypeInfo* info = GetFrameTypeInfo(aNode.mFrame->GetType());
8611 0 : NS_ASSERTION(info, "program error");
8612 0 : PRInt32 numRules = info->mRules.Length();
8613 0 : for (PRInt32 ruleX = 0; ruleX < numRules; ruleX++) {
8614 0 : DR_Rule* rule = info->mRules.ElementAt(ruleX);
8615 0 : if (rule && RuleMatches(*rule, aNode)) {
8616 0 : aNode.mDisplay = rule->mDisplay;
8617 0 : matchingRule = true;
8618 0 : break;
8619 : }
8620 : }
8621 0 : if (!matchingRule) {
8622 0 : PRInt32 numWildRules = mWildRules.Length();
8623 0 : for (PRInt32 ruleX = 0; ruleX < numWildRules; ruleX++) {
8624 0 : DR_Rule* rule = mWildRules.ElementAt(ruleX);
8625 0 : if (rule && RuleMatches(*rule, aNode)) {
8626 0 : aNode.mDisplay = rule->mDisplay;
8627 0 : break;
8628 : }
8629 : }
8630 : }
8631 : }
8632 :
8633 0 : DR_FrameTreeNode* DR_State::CreateTreeNode(nsIFrame* aFrame,
8634 : const nsHTMLReflowState* aReflowState)
8635 : {
8636 : // find the frame of the parent reflow state (usually just the parent of aFrame)
8637 : nsIFrame* parentFrame;
8638 0 : if (aReflowState) {
8639 0 : const nsHTMLReflowState* parentRS = aReflowState->parentReflowState;
8640 0 : parentFrame = (parentRS) ? parentRS->frame : nsnull;
8641 : } else {
8642 0 : parentFrame = aFrame->GetParent();
8643 : }
8644 :
8645 : // find the parent tree node leaf
8646 0 : DR_FrameTreeNode* parentNode = nsnull;
8647 :
8648 0 : DR_FrameTreeNode* lastLeaf = nsnull;
8649 0 : if(mFrameTreeLeaves.Length())
8650 0 : lastLeaf = mFrameTreeLeaves.ElementAt(mFrameTreeLeaves.Length() - 1);
8651 0 : if (lastLeaf) {
8652 0 : for (parentNode = lastLeaf; parentNode && (parentNode->mFrame != parentFrame); parentNode = parentNode->mParent) {
8653 : }
8654 : }
8655 0 : DR_FrameTreeNode* newNode = new DR_FrameTreeNode(aFrame, parentNode);
8656 0 : FindMatchingRule(*newNode);
8657 :
8658 0 : newNode->mIndent = mIndent;
8659 0 : if (newNode->mDisplay || mIndentUndisplayedFrames) {
8660 0 : ++mIndent;
8661 : }
8662 :
8663 0 : if (lastLeaf && (lastLeaf == parentNode)) {
8664 0 : mFrameTreeLeaves.RemoveElementAt(mFrameTreeLeaves.Length() - 1);
8665 : }
8666 0 : mFrameTreeLeaves.AppendElement(newNode);
8667 0 : mCount++;
8668 :
8669 0 : return newNode;
8670 : }
8671 :
8672 0 : void DR_State::PrettyUC(nscoord aSize,
8673 : char* aBuf)
8674 : {
8675 0 : if (NS_UNCONSTRAINEDSIZE == aSize) {
8676 0 : strcpy(aBuf, "UC");
8677 : }
8678 : else {
8679 0 : if ((nscoord)0xdeadbeefU == aSize)
8680 : {
8681 0 : strcpy(aBuf, "deadbeef");
8682 : }
8683 : else {
8684 0 : sprintf(aBuf, "%d", aSize);
8685 : }
8686 : }
8687 0 : }
8688 :
8689 0 : void DR_State::PrintMargin(const char *tag, const nsMargin* aMargin)
8690 : {
8691 0 : if (aMargin) {
8692 : char t[16], r[16], b[16], l[16];
8693 0 : PrettyUC(aMargin->top, t);
8694 0 : PrettyUC(aMargin->right, r);
8695 0 : PrettyUC(aMargin->bottom, b);
8696 0 : PrettyUC(aMargin->left, l);
8697 0 : printf(" %s=%s,%s,%s,%s", tag, t, r, b, l);
8698 : } else {
8699 : // use %p here for consistency with other null-pointer printouts
8700 0 : printf(" %s=%p", tag, (void*)aMargin);
8701 : }
8702 0 : }
8703 :
8704 0 : void DR_State::DeleteTreeNode(DR_FrameTreeNode& aNode)
8705 : {
8706 0 : mFrameTreeLeaves.RemoveElement(&aNode);
8707 0 : PRInt32 numLeaves = mFrameTreeLeaves.Length();
8708 0 : if ((0 == numLeaves) || (aNode.mParent != mFrameTreeLeaves.ElementAt(numLeaves - 1))) {
8709 0 : mFrameTreeLeaves.AppendElement(aNode.mParent);
8710 : }
8711 :
8712 0 : if (aNode.mDisplay || mIndentUndisplayedFrames) {
8713 0 : --mIndent;
8714 : }
8715 : // delete the tree node
8716 0 : delete &aNode;
8717 0 : }
8718 :
8719 : static void
8720 0 : CheckPixelError(nscoord aSize,
8721 : PRInt32 aPixelToTwips)
8722 : {
8723 0 : if (NS_UNCONSTRAINEDSIZE != aSize) {
8724 0 : if ((aSize % aPixelToTwips) > 0) {
8725 0 : printf("VALUE %d is not a whole pixel \n", aSize);
8726 : }
8727 : }
8728 0 : }
8729 :
8730 0 : static void DisplayReflowEnterPrint(nsPresContext* aPresContext,
8731 : nsIFrame* aFrame,
8732 : const nsHTMLReflowState& aReflowState,
8733 : DR_FrameTreeNode& aTreeNode,
8734 : bool aChanged)
8735 : {
8736 0 : if (aTreeNode.mDisplay) {
8737 0 : DR_state->DisplayFrameTypeInfo(aFrame, aTreeNode.mIndent);
8738 :
8739 : char width[16];
8740 : char height[16];
8741 :
8742 0 : DR_state->PrettyUC(aReflowState.availableWidth, width);
8743 0 : DR_state->PrettyUC(aReflowState.availableHeight, height);
8744 0 : printf("Reflow a=%s,%s ", width, height);
8745 :
8746 0 : DR_state->PrettyUC(aReflowState.ComputedWidth(), width);
8747 0 : DR_state->PrettyUC(aReflowState.ComputedHeight(), height);
8748 0 : printf("c=%s,%s ", width, height);
8749 :
8750 0 : if (aFrame->GetStateBits() & NS_FRAME_IS_DIRTY)
8751 0 : printf("dirty ");
8752 :
8753 0 : if (aFrame->GetStateBits() & NS_FRAME_HAS_DIRTY_CHILDREN)
8754 0 : printf("dirty-children ");
8755 :
8756 0 : if (aReflowState.mFlags.mSpecialHeightReflow)
8757 0 : printf("special-height ");
8758 :
8759 0 : if (aReflowState.mFlags.mHResize)
8760 0 : printf("h-resize ");
8761 :
8762 0 : if (aReflowState.mFlags.mVResize)
8763 0 : printf("v-resize ");
8764 :
8765 0 : nsIFrame* inFlow = aFrame->GetPrevInFlow();
8766 0 : if (inFlow) {
8767 0 : printf("pif=%p ", (void*)inFlow);
8768 : }
8769 0 : inFlow = aFrame->GetNextInFlow();
8770 0 : if (inFlow) {
8771 0 : printf("nif=%p ", (void*)inFlow);
8772 : }
8773 0 : if (aChanged)
8774 0 : printf("CHANGED \n");
8775 : else
8776 0 : printf("cnt=%d \n", DR_state->mCount);
8777 0 : if (DR_state->mDisplayPixelErrors) {
8778 0 : PRInt32 p2t = aPresContext->AppUnitsPerDevPixel();
8779 0 : CheckPixelError(aReflowState.availableWidth, p2t);
8780 0 : CheckPixelError(aReflowState.availableHeight, p2t);
8781 0 : CheckPixelError(aReflowState.ComputedWidth(), p2t);
8782 0 : CheckPixelError(aReflowState.ComputedHeight(), p2t);
8783 : }
8784 : }
8785 0 : }
8786 :
8787 0 : void* nsFrame::DisplayReflowEnter(nsPresContext* aPresContext,
8788 : nsIFrame* aFrame,
8789 : const nsHTMLReflowState& aReflowState)
8790 : {
8791 0 : if (!DR_state->mInited) DR_state->Init();
8792 0 : if (!DR_state->mActive) return nsnull;
8793 :
8794 0 : NS_ASSERTION(aFrame, "invalid call");
8795 :
8796 0 : DR_FrameTreeNode* treeNode = DR_state->CreateTreeNode(aFrame, &aReflowState);
8797 0 : if (treeNode) {
8798 0 : DisplayReflowEnterPrint(aPresContext, aFrame, aReflowState, *treeNode, false);
8799 : }
8800 0 : return treeNode;
8801 : }
8802 :
8803 0 : void* nsFrame::DisplayLayoutEnter(nsIFrame* aFrame)
8804 : {
8805 0 : if (!DR_state->mInited) DR_state->Init();
8806 0 : if (!DR_state->mActive) return nsnull;
8807 :
8808 0 : NS_ASSERTION(aFrame, "invalid call");
8809 :
8810 0 : DR_FrameTreeNode* treeNode = DR_state->CreateTreeNode(aFrame, nsnull);
8811 0 : if (treeNode && treeNode->mDisplay) {
8812 0 : DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
8813 0 : printf("Layout\n");
8814 : }
8815 0 : return treeNode;
8816 : }
8817 :
8818 0 : void* nsFrame::DisplayIntrinsicWidthEnter(nsIFrame* aFrame,
8819 : const char* aType)
8820 : {
8821 0 : if (!DR_state->mInited) DR_state->Init();
8822 0 : if (!DR_state->mActive) return nsnull;
8823 :
8824 0 : NS_ASSERTION(aFrame, "invalid call");
8825 :
8826 0 : DR_FrameTreeNode* treeNode = DR_state->CreateTreeNode(aFrame, nsnull);
8827 0 : if (treeNode && treeNode->mDisplay) {
8828 0 : DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
8829 0 : printf("Get%sWidth\n", aType);
8830 : }
8831 0 : return treeNode;
8832 : }
8833 :
8834 0 : void* nsFrame::DisplayIntrinsicSizeEnter(nsIFrame* aFrame,
8835 : const char* aType)
8836 : {
8837 0 : if (!DR_state->mInited) DR_state->Init();
8838 0 : if (!DR_state->mActive) return nsnull;
8839 :
8840 0 : NS_ASSERTION(aFrame, "invalid call");
8841 :
8842 0 : DR_FrameTreeNode* treeNode = DR_state->CreateTreeNode(aFrame, nsnull);
8843 0 : if (treeNode && treeNode->mDisplay) {
8844 0 : DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
8845 0 : printf("Get%sSize\n", aType);
8846 : }
8847 0 : return treeNode;
8848 : }
8849 :
8850 0 : void nsFrame::DisplayReflowExit(nsPresContext* aPresContext,
8851 : nsIFrame* aFrame,
8852 : nsHTMLReflowMetrics& aMetrics,
8853 : nsReflowStatus aStatus,
8854 : void* aFrameTreeNode)
8855 : {
8856 0 : if (!DR_state->mActive) return;
8857 :
8858 0 : NS_ASSERTION(aFrame, "DisplayReflowExit - invalid call");
8859 0 : if (!aFrameTreeNode) return;
8860 :
8861 0 : DR_FrameTreeNode* treeNode = (DR_FrameTreeNode*)aFrameTreeNode;
8862 0 : if (treeNode->mDisplay) {
8863 0 : DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
8864 :
8865 : char width[16];
8866 : char height[16];
8867 : char x[16];
8868 : char y[16];
8869 0 : DR_state->PrettyUC(aMetrics.width, width);
8870 0 : DR_state->PrettyUC(aMetrics.height, height);
8871 0 : printf("Reflow d=%s,%s", width, height);
8872 :
8873 0 : if (!NS_FRAME_IS_FULLY_COMPLETE(aStatus)) {
8874 0 : printf(" status=0x%x", aStatus);
8875 : }
8876 0 : if (aFrame->HasOverflowAreas()) {
8877 0 : DR_state->PrettyUC(aMetrics.VisualOverflow().x, x);
8878 0 : DR_state->PrettyUC(aMetrics.VisualOverflow().y, y);
8879 0 : DR_state->PrettyUC(aMetrics.VisualOverflow().width, width);
8880 0 : DR_state->PrettyUC(aMetrics.VisualOverflow().height, height);
8881 0 : printf(" vis-o=(%s,%s) %s x %s", x, y, width, height);
8882 :
8883 0 : nsRect storedOverflow = aFrame->GetVisualOverflowRect();
8884 0 : DR_state->PrettyUC(storedOverflow.x, x);
8885 0 : DR_state->PrettyUC(storedOverflow.y, y);
8886 0 : DR_state->PrettyUC(storedOverflow.width, width);
8887 0 : DR_state->PrettyUC(storedOverflow.height, height);
8888 0 : printf(" vis-sto=(%s,%s) %s x %s", x, y, width, height);
8889 :
8890 0 : DR_state->PrettyUC(aMetrics.ScrollableOverflow().x, x);
8891 0 : DR_state->PrettyUC(aMetrics.ScrollableOverflow().y, y);
8892 0 : DR_state->PrettyUC(aMetrics.ScrollableOverflow().width, width);
8893 0 : DR_state->PrettyUC(aMetrics.ScrollableOverflow().height, height);
8894 0 : printf(" scr-o=(%s,%s) %s x %s", x, y, width, height);
8895 :
8896 0 : storedOverflow = aFrame->GetScrollableOverflowRect();
8897 0 : DR_state->PrettyUC(storedOverflow.x, x);
8898 0 : DR_state->PrettyUC(storedOverflow.y, y);
8899 0 : DR_state->PrettyUC(storedOverflow.width, width);
8900 0 : DR_state->PrettyUC(storedOverflow.height, height);
8901 0 : printf(" scr-sto=(%s,%s) %s x %s", x, y, width, height);
8902 : }
8903 0 : printf("\n");
8904 0 : if (DR_state->mDisplayPixelErrors) {
8905 0 : PRInt32 p2t = aPresContext->AppUnitsPerDevPixel();
8906 0 : CheckPixelError(aMetrics.width, p2t);
8907 0 : CheckPixelError(aMetrics.height, p2t);
8908 : }
8909 : }
8910 0 : DR_state->DeleteTreeNode(*treeNode);
8911 : }
8912 :
8913 0 : void nsFrame::DisplayLayoutExit(nsIFrame* aFrame,
8914 : void* aFrameTreeNode)
8915 : {
8916 0 : if (!DR_state->mActive) return;
8917 :
8918 0 : NS_ASSERTION(aFrame, "non-null frame required");
8919 0 : if (!aFrameTreeNode) return;
8920 :
8921 0 : DR_FrameTreeNode* treeNode = (DR_FrameTreeNode*)aFrameTreeNode;
8922 0 : if (treeNode->mDisplay) {
8923 0 : DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
8924 0 : nsRect rect = aFrame->GetRect();
8925 0 : printf("Layout=%d,%d,%d,%d\n", rect.x, rect.y, rect.width, rect.height);
8926 : }
8927 0 : DR_state->DeleteTreeNode(*treeNode);
8928 : }
8929 :
8930 0 : void nsFrame::DisplayIntrinsicWidthExit(nsIFrame* aFrame,
8931 : const char* aType,
8932 : nscoord aResult,
8933 : void* aFrameTreeNode)
8934 : {
8935 0 : if (!DR_state->mActive) return;
8936 :
8937 0 : NS_ASSERTION(aFrame, "non-null frame required");
8938 0 : if (!aFrameTreeNode) return;
8939 :
8940 0 : DR_FrameTreeNode* treeNode = (DR_FrameTreeNode*)aFrameTreeNode;
8941 0 : if (treeNode->mDisplay) {
8942 0 : DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
8943 : char width[16];
8944 0 : DR_state->PrettyUC(aResult, width);
8945 0 : printf("Get%sWidth=%s\n", aType, width);
8946 : }
8947 0 : DR_state->DeleteTreeNode(*treeNode);
8948 : }
8949 :
8950 0 : void nsFrame::DisplayIntrinsicSizeExit(nsIFrame* aFrame,
8951 : const char* aType,
8952 : nsSize aResult,
8953 : void* aFrameTreeNode)
8954 : {
8955 0 : if (!DR_state->mActive) return;
8956 :
8957 0 : NS_ASSERTION(aFrame, "non-null frame required");
8958 0 : if (!aFrameTreeNode) return;
8959 :
8960 0 : DR_FrameTreeNode* treeNode = (DR_FrameTreeNode*)aFrameTreeNode;
8961 0 : if (treeNode->mDisplay) {
8962 0 : DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
8963 :
8964 : char width[16];
8965 : char height[16];
8966 0 : DR_state->PrettyUC(aResult.width, width);
8967 0 : DR_state->PrettyUC(aResult.height, height);
8968 0 : printf("Get%sSize=%s,%s\n", aType, width, height);
8969 : }
8970 0 : DR_state->DeleteTreeNode(*treeNode);
8971 : }
8972 :
8973 : /* static */ void
8974 1404 : nsFrame::DisplayReflowStartup()
8975 : {
8976 1404 : DR_state = new DR_State();
8977 1404 : }
8978 :
8979 : /* static */ void
8980 1403 : nsFrame::DisplayReflowShutdown()
8981 : {
8982 1403 : delete DR_state;
8983 1403 : DR_state = nsnull;
8984 1403 : }
8985 :
8986 0 : void DR_cookie::Change() const
8987 : {
8988 0 : DR_FrameTreeNode* treeNode = (DR_FrameTreeNode*)mValue;
8989 0 : if (treeNode && treeNode->mDisplay) {
8990 0 : DisplayReflowEnterPrint(mPresContext, mFrame, mReflowState, *treeNode, true);
8991 : }
8992 0 : }
8993 :
8994 : /* static */ void*
8995 0 : nsHTMLReflowState::DisplayInitConstraintsEnter(nsIFrame* aFrame,
8996 : nsHTMLReflowState* aState,
8997 : nscoord aContainingBlockWidth,
8998 : nscoord aContainingBlockHeight,
8999 : const nsMargin* aBorder,
9000 : const nsMargin* aPadding)
9001 : {
9002 0 : NS_PRECONDITION(aFrame, "non-null frame required");
9003 0 : NS_PRECONDITION(aState, "non-null state required");
9004 :
9005 0 : if (!DR_state->mInited) DR_state->Init();
9006 0 : if (!DR_state->mActive) return nsnull;
9007 :
9008 0 : DR_FrameTreeNode* treeNode = DR_state->CreateTreeNode(aFrame, aState);
9009 0 : if (treeNode && treeNode->mDisplay) {
9010 0 : DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
9011 :
9012 : printf("InitConstraints parent=%p",
9013 0 : (void*)aState->parentReflowState);
9014 :
9015 : char width[16];
9016 : char height[16];
9017 :
9018 0 : DR_state->PrettyUC(aContainingBlockWidth, width);
9019 0 : DR_state->PrettyUC(aContainingBlockHeight, height);
9020 0 : printf(" cb=%s,%s", width, height);
9021 :
9022 0 : DR_state->PrettyUC(aState->availableWidth, width);
9023 0 : DR_state->PrettyUC(aState->availableHeight, height);
9024 0 : printf(" as=%s,%s", width, height);
9025 :
9026 0 : DR_state->PrintMargin("b", aBorder);
9027 0 : DR_state->PrintMargin("p", aPadding);
9028 0 : putchar('\n');
9029 : }
9030 0 : return treeNode;
9031 : }
9032 :
9033 : /* static */ void
9034 0 : nsHTMLReflowState::DisplayInitConstraintsExit(nsIFrame* aFrame,
9035 : nsHTMLReflowState* aState,
9036 : void* aValue)
9037 : {
9038 0 : NS_PRECONDITION(aFrame, "non-null frame required");
9039 0 : NS_PRECONDITION(aState, "non-null state required");
9040 :
9041 0 : if (!DR_state->mActive) return;
9042 0 : if (!aValue) return;
9043 :
9044 0 : DR_FrameTreeNode* treeNode = (DR_FrameTreeNode*)aValue;
9045 0 : if (treeNode->mDisplay) {
9046 0 : DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
9047 : char cmiw[16], cw[16], cmxw[16], cmih[16], ch[16], cmxh[16];
9048 0 : DR_state->PrettyUC(aState->mComputedMinWidth, cmiw);
9049 0 : DR_state->PrettyUC(aState->mComputedWidth, cw);
9050 0 : DR_state->PrettyUC(aState->mComputedMaxWidth, cmxw);
9051 0 : DR_state->PrettyUC(aState->mComputedMinHeight, cmih);
9052 0 : DR_state->PrettyUC(aState->mComputedHeight, ch);
9053 0 : DR_state->PrettyUC(aState->mComputedMaxHeight, cmxh);
9054 : printf("InitConstraints= cw=(%s <= %s <= %s) ch=(%s <= %s <= %s)",
9055 0 : cmiw, cw, cmxw, cmih, ch, cmxh);
9056 0 : DR_state->PrintMargin("co", &aState->mComputedOffsets);
9057 0 : putchar('\n');
9058 : }
9059 0 : DR_state->DeleteTreeNode(*treeNode);
9060 : }
9061 :
9062 :
9063 : /* static */ void*
9064 0 : nsCSSOffsetState::DisplayInitOffsetsEnter(nsIFrame* aFrame,
9065 : nsCSSOffsetState* aState,
9066 : nscoord aContainingBlockWidth,
9067 : const nsMargin* aBorder,
9068 : const nsMargin* aPadding)
9069 : {
9070 0 : NS_PRECONDITION(aFrame, "non-null frame required");
9071 0 : NS_PRECONDITION(aState, "non-null state required");
9072 :
9073 0 : if (!DR_state->mInited) DR_state->Init();
9074 0 : if (!DR_state->mActive) return nsnull;
9075 :
9076 : // aState is not necessarily a nsHTMLReflowState
9077 0 : DR_FrameTreeNode* treeNode = DR_state->CreateTreeNode(aFrame, nsnull);
9078 0 : if (treeNode && treeNode->mDisplay) {
9079 0 : DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
9080 :
9081 : char width[16];
9082 0 : DR_state->PrettyUC(aContainingBlockWidth, width);
9083 0 : printf("InitOffsets cbw=%s", width);
9084 0 : DR_state->PrintMargin("b", aBorder);
9085 0 : DR_state->PrintMargin("p", aPadding);
9086 0 : putchar('\n');
9087 : }
9088 0 : return treeNode;
9089 : }
9090 :
9091 : /* static */ void
9092 0 : nsCSSOffsetState::DisplayInitOffsetsExit(nsIFrame* aFrame,
9093 : nsCSSOffsetState* aState,
9094 : void* aValue)
9095 : {
9096 0 : NS_PRECONDITION(aFrame, "non-null frame required");
9097 0 : NS_PRECONDITION(aState, "non-null state required");
9098 :
9099 0 : if (!DR_state->mActive) return;
9100 0 : if (!aValue) return;
9101 :
9102 0 : DR_FrameTreeNode* treeNode = (DR_FrameTreeNode*)aValue;
9103 0 : if (treeNode->mDisplay) {
9104 0 : DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
9105 0 : printf("InitOffsets=");
9106 0 : DR_state->PrintMargin("m", &aState->mComputedMargin);
9107 0 : DR_state->PrintMargin("p", &aState->mComputedPadding);
9108 0 : DR_state->PrintMargin("p+b", &aState->mComputedBorderPadding);
9109 0 : putchar('\n');
9110 : }
9111 0 : DR_state->DeleteTreeNode(*treeNode);
9112 : }
9113 :
9114 : /* static */ void*
9115 0 : nsHTMLReflowState::DisplayInitFrameTypeEnter(nsIFrame* aFrame,
9116 : nsHTMLReflowState* aState)
9117 : {
9118 0 : NS_PRECONDITION(aFrame, "non-null frame required");
9119 0 : NS_PRECONDITION(aState, "non-null state required");
9120 :
9121 0 : if (!DR_state->mInited) DR_state->Init();
9122 0 : if (!DR_state->mActive) return nsnull;
9123 :
9124 : // we don't print anything here
9125 0 : return DR_state->CreateTreeNode(aFrame, aState);
9126 : }
9127 :
9128 : /* static */ void
9129 0 : nsHTMLReflowState::DisplayInitFrameTypeExit(nsIFrame* aFrame,
9130 : nsHTMLReflowState* aState,
9131 : void* aValue)
9132 : {
9133 0 : NS_PRECONDITION(aFrame, "non-null frame required");
9134 0 : NS_PRECONDITION(aState, "non-null state required");
9135 :
9136 0 : if (!DR_state->mActive) return;
9137 0 : if (!aValue) return;
9138 :
9139 0 : DR_FrameTreeNode* treeNode = (DR_FrameTreeNode*)aValue;
9140 0 : if (treeNode->mDisplay) {
9141 0 : DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
9142 0 : printf("InitFrameType");
9143 :
9144 0 : const nsStyleDisplay *disp = aState->mStyleDisplay;
9145 :
9146 0 : if (aFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW)
9147 0 : printf(" out-of-flow");
9148 0 : if (aFrame->GetPrevInFlow())
9149 0 : printf(" prev-in-flow");
9150 0 : if (disp->IsAbsolutelyPositioned())
9151 0 : printf(" abspos");
9152 0 : if (disp->IsFloating())
9153 0 : printf(" float");
9154 :
9155 : // This array must exactly match the NS_STYLE_DISPLAY constants.
9156 : const char *const displayTypes[] = {
9157 : "none", "block", "inline", "inline-block", "list-item", "marker",
9158 : "run-in", "compact", "table", "inline-table", "table-row-group",
9159 : "table-column", "table-column-group", "table-header-group",
9160 : "table-footer-group", "table-row", "table-cell", "table-caption",
9161 : "box", "inline-box",
9162 : #ifdef MOZ_XUL
9163 : "grid", "inline-grid", "grid-group", "grid-line", "stack",
9164 : "inline-stack", "deck", "popup", "groupbox",
9165 : #endif
9166 0 : };
9167 0 : if (disp->mDisplay >= ArrayLength(displayTypes))
9168 0 : printf(" display=%u", disp->mDisplay);
9169 : else
9170 0 : printf(" display=%s", displayTypes[disp->mDisplay]);
9171 :
9172 : // This array must exactly match the NS_CSS_FRAME_TYPE constants.
9173 : const char *const cssFrameTypes[] = {
9174 : "unknown", "inline", "block", "floating", "absolute", "internal-table"
9175 0 : };
9176 0 : nsCSSFrameType bareType = NS_FRAME_GET_TYPE(aState->mFrameType);
9177 0 : bool repNoBlock = NS_FRAME_IS_REPLACED_NOBLOCK(aState->mFrameType);
9178 0 : bool repBlock = NS_FRAME_IS_REPLACED_CONTAINS_BLOCK(aState->mFrameType);
9179 :
9180 0 : if (bareType >= ArrayLength(cssFrameTypes)) {
9181 0 : printf(" result=type %u", bareType);
9182 : } else {
9183 0 : printf(" result=%s", cssFrameTypes[bareType]);
9184 : }
9185 0 : printf("%s%s\n", repNoBlock ? " +rep" : "", repBlock ? " +repBlk" : "");
9186 : }
9187 0 : DR_state->DeleteTreeNode(*treeNode);
9188 : }
9189 :
9190 : #endif
9191 : // End Display Reflow
9192 :
9193 : #endif
|