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 : {
3963 0 : ReflowAbsoluteFrames(aPresContext, aDesiredSize, aReflowState, aStatus);
3964 :
3965 0 : FinishAndStoreOverflow(&aDesiredSize);
3966 0 : }
3967 :
3968 : void
3969 0 : nsFrame::DestroyAbsoluteFrames(nsIFrame* aDestructRoot)
3970 : {
3971 0 : if (IsAbsoluteContainer()) {
3972 0 : GetAbsoluteContainingBlock()->DestroyFrames(this, aDestructRoot);
3973 : }
3974 0 : }
3975 :
3976 : void
3977 0 : nsFrame::ReflowAbsoluteFrames(nsPresContext* aPresContext,
3978 : nsHTMLReflowMetrics& aDesiredSize,
3979 : const nsHTMLReflowState& aReflowState,
3980 : nsReflowStatus& aStatus)
3981 : {
3982 0 : if (HasAbsolutelyPositionedChildren()) {
3983 0 : nsAbsoluteContainingBlock* absoluteContainer = GetAbsoluteContainingBlock();
3984 :
3985 : // Let the absolutely positioned container reflow any absolutely positioned
3986 : // child frames that need to be reflowed
3987 :
3988 : // The containing block for the abs pos kids is formed by our padding edge.
3989 : nsMargin computedBorder =
3990 0 : aReflowState.mComputedBorderPadding - aReflowState.mComputedPadding;
3991 : nscoord containingBlockWidth =
3992 0 : aDesiredSize.width - computedBorder.LeftRight();
3993 : nscoord containingBlockHeight =
3994 0 : aDesiredSize.height - computedBorder.TopBottom();
3995 :
3996 0 : nsContainerFrame* container = do_QueryFrame(this);
3997 0 : NS_ASSERTION(container, "Abs-pos children only supported on container frames for now");
3998 :
3999 : absoluteContainer->Reflow(container, aPresContext, aReflowState, aStatus,
4000 : containingBlockWidth, containingBlockHeight,
4001 : true, true, true, // XXX could be optimized
4002 0 : &aDesiredSize.mOverflowAreas);
4003 : }
4004 0 : }
4005 :
4006 : /* virtual */ bool
4007 0 : nsFrame::CanContinueTextRun() const
4008 : {
4009 : // By default, a frame will *not* allow a text run to be continued
4010 : // through it.
4011 0 : return false;
4012 : }
4013 :
4014 : NS_IMETHODIMP
4015 0 : nsFrame::Reflow(nsPresContext* aPresContext,
4016 : nsHTMLReflowMetrics& aDesiredSize,
4017 : const nsHTMLReflowState& aReflowState,
4018 : nsReflowStatus& aStatus)
4019 : {
4020 0 : DO_GLOBAL_REFLOW_COUNT("nsFrame");
4021 0 : aDesiredSize.width = 0;
4022 0 : aDesiredSize.height = 0;
4023 0 : aStatus = NS_FRAME_COMPLETE;
4024 0 : NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
4025 0 : return NS_OK;
4026 : }
4027 :
4028 : NS_IMETHODIMP
4029 0 : nsFrame::CharacterDataChanged(CharacterDataChangeInfo* aInfo)
4030 : {
4031 0 : NS_NOTREACHED("should only be called for text frames");
4032 0 : return NS_OK;
4033 : }
4034 :
4035 : NS_IMETHODIMP
4036 0 : nsFrame::AttributeChanged(PRInt32 aNameSpaceID,
4037 : nsIAtom* aAttribute,
4038 : PRInt32 aModType)
4039 : {
4040 0 : return NS_OK;
4041 : }
4042 :
4043 : // Flow member functions
4044 :
4045 : nsSplittableType
4046 0 : nsFrame::GetSplittableType() const
4047 : {
4048 0 : return NS_FRAME_NOT_SPLITTABLE;
4049 : }
4050 :
4051 0 : nsIFrame* nsFrame::GetPrevContinuation() const
4052 : {
4053 0 : return nsnull;
4054 : }
4055 :
4056 0 : NS_IMETHODIMP nsFrame::SetPrevContinuation(nsIFrame* aPrevContinuation)
4057 : {
4058 : // Ignore harmless requests to set it to NULL
4059 0 : if (aPrevContinuation) {
4060 0 : NS_ERROR("not splittable");
4061 0 : return NS_ERROR_NOT_IMPLEMENTED;
4062 : }
4063 :
4064 0 : return NS_OK;
4065 : }
4066 :
4067 0 : nsIFrame* nsFrame::GetNextContinuation() const
4068 : {
4069 0 : return nsnull;
4070 : }
4071 :
4072 0 : NS_IMETHODIMP nsFrame::SetNextContinuation(nsIFrame*)
4073 : {
4074 0 : NS_ERROR("not splittable");
4075 0 : return NS_ERROR_NOT_IMPLEMENTED;
4076 : }
4077 :
4078 0 : nsIFrame* nsFrame::GetPrevInFlowVirtual() const
4079 : {
4080 0 : return nsnull;
4081 : }
4082 :
4083 0 : NS_IMETHODIMP nsFrame::SetPrevInFlow(nsIFrame* aPrevInFlow)
4084 : {
4085 : // Ignore harmless requests to set it to NULL
4086 0 : if (aPrevInFlow) {
4087 0 : NS_ERROR("not splittable");
4088 0 : return NS_ERROR_NOT_IMPLEMENTED;
4089 : }
4090 :
4091 0 : return NS_OK;
4092 : }
4093 :
4094 0 : nsIFrame* nsFrame::GetNextInFlowVirtual() const
4095 : {
4096 0 : return nsnull;
4097 : }
4098 :
4099 0 : NS_IMETHODIMP nsFrame::SetNextInFlow(nsIFrame*)
4100 : {
4101 0 : NS_ERROR("not splittable");
4102 0 : return NS_ERROR_NOT_IMPLEMENTED;
4103 : }
4104 :
4105 0 : nsIFrame* nsIFrame::GetTailContinuation()
4106 : {
4107 0 : nsIFrame* frame = this;
4108 0 : while (frame->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER) {
4109 0 : frame = frame->GetPrevContinuation();
4110 0 : NS_ASSERTION(frame, "first continuation can't be overflow container");
4111 : }
4112 0 : for (nsIFrame* next = frame->GetNextContinuation();
4113 0 : next && !(next->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER);
4114 0 : next = frame->GetNextContinuation()) {
4115 0 : frame = next;
4116 : }
4117 0 : NS_POSTCONDITION(frame, "illegal state in continuation chain.");
4118 0 : return frame;
4119 : }
4120 :
4121 0 : NS_DECLARE_FRAME_PROPERTY(ViewProperty, nsnull)
4122 :
4123 : // Associated view object
4124 : nsIView*
4125 0 : nsIFrame::GetView() const
4126 : {
4127 : // Check the frame state bit and see if the frame has a view
4128 0 : if (!(GetStateBits() & NS_FRAME_HAS_VIEW))
4129 0 : return nsnull;
4130 :
4131 : // Check for a property on the frame
4132 0 : void* value = Properties().Get(ViewProperty());
4133 0 : NS_ASSERTION(value, "frame state bit was set but frame has no view");
4134 0 : return static_cast<nsIView*>(value);
4135 : }
4136 :
4137 : /* virtual */ nsIView*
4138 0 : nsIFrame::GetViewExternal() const
4139 : {
4140 0 : return GetView();
4141 : }
4142 :
4143 : nsresult
4144 0 : nsIFrame::SetView(nsIView* aView)
4145 : {
4146 0 : if (aView) {
4147 0 : aView->SetFrame(this);
4148 :
4149 : // Set a property on the frame
4150 0 : Properties().Set(ViewProperty(), aView);
4151 :
4152 : // Set the frame state bit that says the frame has a view
4153 0 : AddStateBits(NS_FRAME_HAS_VIEW);
4154 :
4155 : // Let all of the ancestors know they have a descendant with a view.
4156 0 : for (nsIFrame* f = GetParent();
4157 0 : f && !(f->GetStateBits() & NS_FRAME_HAS_CHILD_WITH_VIEW);
4158 : f = f->GetParent())
4159 0 : f->AddStateBits(NS_FRAME_HAS_CHILD_WITH_VIEW);
4160 : }
4161 :
4162 0 : return NS_OK;
4163 : }
4164 :
4165 0 : nsIFrame* nsIFrame::GetAncestorWithViewExternal() const
4166 : {
4167 0 : return GetAncestorWithView();
4168 : }
4169 :
4170 : // Find the first geometric parent that has a view
4171 0 : nsIFrame* nsIFrame::GetAncestorWithView() const
4172 : {
4173 0 : for (nsIFrame* f = mParent; nsnull != f; f = f->GetParent()) {
4174 0 : if (f->HasView()) {
4175 0 : return f;
4176 : }
4177 : }
4178 0 : return nsnull;
4179 : }
4180 :
4181 : // virtual
4182 0 : nsPoint nsIFrame::GetOffsetToExternal(const nsIFrame* aOther) const
4183 : {
4184 0 : return GetOffsetTo(aOther);
4185 : }
4186 :
4187 0 : nsPoint nsIFrame::GetOffsetTo(const nsIFrame* aOther) const
4188 : {
4189 0 : NS_PRECONDITION(aOther,
4190 : "Must have frame for destination coordinate system!");
4191 :
4192 0 : NS_ASSERTION(PresContext() == aOther->PresContext(),
4193 : "GetOffsetTo called on frames in different documents");
4194 :
4195 0 : nsPoint offset(0, 0);
4196 : const nsIFrame* f;
4197 0 : for (f = this; f != aOther && f; f = f->GetParent()) {
4198 0 : offset += f->GetPosition();
4199 : }
4200 :
4201 0 : if (f != aOther) {
4202 : // Looks like aOther wasn't an ancestor of |this|. So now we have
4203 : // the root-frame-relative position of |this| in |offset|. Convert back
4204 : // to the coordinates of aOther
4205 0 : while (aOther) {
4206 0 : offset -= aOther->GetPosition();
4207 0 : aOther = aOther->GetParent();
4208 : }
4209 : }
4210 :
4211 : return offset;
4212 : }
4213 :
4214 0 : nsPoint nsIFrame::GetOffsetToCrossDoc(const nsIFrame* aOther) const
4215 : {
4216 0 : return GetOffsetToCrossDoc(aOther, PresContext()->AppUnitsPerDevPixel());
4217 : }
4218 :
4219 : nsPoint
4220 0 : nsIFrame::GetOffsetToCrossDoc(const nsIFrame* aOther, const PRInt32 aAPD) const
4221 : {
4222 0 : NS_PRECONDITION(aOther,
4223 : "Must have frame for destination coordinate system!");
4224 0 : NS_ASSERTION(PresContext()->GetRootPresContext() ==
4225 : aOther->PresContext()->GetRootPresContext(),
4226 : "trying to get the offset between frames in different document "
4227 : "hierarchies?");
4228 0 : if (PresContext()->GetRootPresContext() !=
4229 0 : aOther->PresContext()->GetRootPresContext()) {
4230 : // crash right away, we are almost certainly going to crash anyway.
4231 : NS_RUNTIMEABORT("trying to get the offset between frames in different "
4232 0 : "document hierarchies?");
4233 : }
4234 :
4235 0 : const nsIFrame* root = nsnull;
4236 : // offset will hold the final offset
4237 : // docOffset holds the currently accumulated offset at the current APD, it
4238 : // will be converted and added to offset when the current APD changes.
4239 0 : nsPoint offset(0, 0), docOffset(0, 0);
4240 0 : const nsIFrame* f = this;
4241 0 : PRInt32 currAPD = PresContext()->AppUnitsPerDevPixel();
4242 0 : while (f && f != aOther) {
4243 0 : docOffset += f->GetPosition();
4244 0 : nsIFrame* parent = f->GetParent();
4245 0 : if (parent) {
4246 0 : f = parent;
4247 : } else {
4248 0 : nsPoint newOffset(0, 0);
4249 0 : root = f;
4250 0 : f = nsLayoutUtils::GetCrossDocParentFrame(f, &newOffset);
4251 0 : PRInt32 newAPD = f ? f->PresContext()->AppUnitsPerDevPixel() : 0;
4252 0 : if (!f || newAPD != currAPD) {
4253 : // Convert docOffset to the right APD and add it to offset.
4254 0 : offset += docOffset.ConvertAppUnits(currAPD, aAPD);
4255 0 : docOffset.x = docOffset.y = 0;
4256 : }
4257 0 : currAPD = newAPD;
4258 0 : docOffset += newOffset;
4259 : }
4260 : }
4261 0 : if (f == aOther) {
4262 0 : offset += docOffset.ConvertAppUnits(currAPD, aAPD);
4263 : } else {
4264 : // Looks like aOther wasn't an ancestor of |this|. So now we have
4265 : // the root-document-relative position of |this| in |offset|. Subtract the
4266 : // root-document-relative position of |aOther| from |offset|.
4267 : // This call won't try to recurse again because root is an ancestor of
4268 : // aOther.
4269 0 : nsPoint negOffset = aOther->GetOffsetToCrossDoc(root, aAPD);
4270 0 : offset -= negOffset;
4271 : }
4272 :
4273 : return offset;
4274 : }
4275 :
4276 : // virtual
4277 0 : nsIntRect nsIFrame::GetScreenRectExternal() const
4278 : {
4279 0 : return GetScreenRect();
4280 : }
4281 :
4282 0 : nsIntRect nsIFrame::GetScreenRect() const
4283 : {
4284 0 : return GetScreenRectInAppUnits().ToNearestPixels(PresContext()->AppUnitsPerCSSPixel());
4285 : }
4286 :
4287 : // virtual
4288 0 : nsRect nsIFrame::GetScreenRectInAppUnitsExternal() const
4289 : {
4290 0 : return GetScreenRectInAppUnits();
4291 : }
4292 :
4293 0 : nsRect nsIFrame::GetScreenRectInAppUnits() const
4294 : {
4295 0 : nsPresContext* presContext = PresContext();
4296 : nsIFrame* rootFrame =
4297 0 : presContext->PresShell()->FrameManager()->GetRootFrame();
4298 0 : nsPoint rootScreenPos(0, 0);
4299 0 : nsPoint rootFrameOffsetInParent(0, 0);
4300 : nsIFrame* rootFrameParent =
4301 0 : nsLayoutUtils::GetCrossDocParentFrame(rootFrame, &rootFrameOffsetInParent);
4302 0 : if (rootFrameParent) {
4303 0 : nsRect parentScreenRectAppUnits = rootFrameParent->GetScreenRectInAppUnits();
4304 0 : nsPresContext* parentPresContext = rootFrameParent->PresContext();
4305 0 : double parentScale = double(presContext->AppUnitsPerDevPixel())/
4306 0 : parentPresContext->AppUnitsPerDevPixel();
4307 0 : nsPoint rootPt = parentScreenRectAppUnits.TopLeft() + rootFrameOffsetInParent;
4308 0 : rootScreenPos.x = NS_round(parentScale*rootPt.x);
4309 0 : rootScreenPos.y = NS_round(parentScale*rootPt.y);
4310 : } else {
4311 0 : nsCOMPtr<nsIWidget> rootWidget;
4312 0 : presContext->PresShell()->GetViewManager()->GetRootWidget(getter_AddRefs(rootWidget));
4313 0 : if (rootWidget) {
4314 0 : nsIntPoint rootDevPx = rootWidget->WidgetToScreenOffset();
4315 0 : rootScreenPos.x = presContext->DevPixelsToAppUnits(rootDevPx.x);
4316 0 : rootScreenPos.y = presContext->DevPixelsToAppUnits(rootDevPx.y);
4317 : }
4318 : }
4319 :
4320 0 : return nsRect(rootScreenPos + GetOffsetTo(rootFrame), GetSize());
4321 : }
4322 :
4323 : // Returns the offset from this frame to the closest geometric parent that
4324 : // has a view. Also returns the containing view or null in case of error
4325 0 : NS_IMETHODIMP nsFrame::GetOffsetFromView(nsPoint& aOffset,
4326 : nsIView** aView) const
4327 : {
4328 0 : NS_PRECONDITION(nsnull != aView, "null OUT parameter pointer");
4329 0 : nsIFrame* frame = (nsIFrame*)this;
4330 :
4331 0 : *aView = nsnull;
4332 0 : aOffset.MoveTo(0, 0);
4333 0 : do {
4334 0 : aOffset += frame->GetPosition();
4335 0 : frame = frame->GetParent();
4336 0 : } while (frame && !frame->HasView());
4337 0 : if (frame)
4338 0 : *aView = frame->GetView();
4339 0 : return NS_OK;
4340 : }
4341 :
4342 : nsIWidget*
4343 0 : nsIFrame::GetNearestWidget() const
4344 : {
4345 0 : return GetClosestView()->GetNearestWidget(nsnull);
4346 : }
4347 :
4348 : nsIWidget*
4349 0 : nsIFrame::GetNearestWidget(nsPoint& aOffset) const
4350 : {
4351 0 : nsPoint offsetToView;
4352 0 : nsPoint offsetToWidget;
4353 : nsIWidget* widget =
4354 0 : GetClosestView(&offsetToView)->GetNearestWidget(&offsetToWidget);
4355 0 : aOffset = offsetToView + offsetToWidget;
4356 0 : return widget;
4357 : }
4358 :
4359 : nsIAtom*
4360 0 : nsFrame::GetType() const
4361 : {
4362 0 : return nsnull;
4363 : }
4364 :
4365 : bool
4366 0 : nsIFrame::IsLeaf() const
4367 : {
4368 0 : return true;
4369 : }
4370 :
4371 : Layer*
4372 0 : nsIFrame::InvalidateLayer(const nsRect& aDamageRect, PRUint32 aDisplayItemKey)
4373 : {
4374 0 : NS_ASSERTION(aDisplayItemKey > 0, "Need a key");
4375 :
4376 0 : Layer* layer = FrameLayerBuilder::GetDedicatedLayer(this, aDisplayItemKey);
4377 0 : if (!layer) {
4378 0 : Invalidate(aDamageRect);
4379 0 : return nsnull;
4380 : }
4381 :
4382 0 : PRUint32 flags = INVALIDATE_NO_THEBES_LAYERS;
4383 0 : if (aDisplayItemKey == nsDisplayItem::TYPE_VIDEO ||
4384 : aDisplayItemKey == nsDisplayItem::TYPE_PLUGIN ||
4385 : aDisplayItemKey == nsDisplayItem::TYPE_CANVAS) {
4386 0 : flags |= INVALIDATE_NO_UPDATE_LAYER_TREE;
4387 : }
4388 :
4389 0 : InvalidateWithFlags(aDamageRect, flags);
4390 0 : return layer;
4391 : }
4392 :
4393 : void
4394 0 : nsIFrame::InvalidateTransformLayer()
4395 : {
4396 0 : NS_ASSERTION(mParent, "How can a viewport frame have a transform?");
4397 :
4398 : bool hasLayer =
4399 0 : FrameLayerBuilder::GetDedicatedLayer(this, nsDisplayItem::TYPE_TRANSFORM) != nsnull;
4400 : // Invalidate post-transform area in the parent. We have to invalidate
4401 : // in the parent because our transform style may have changed from what was
4402 : // used to paint this frame.
4403 : // It's OK to bypass the SVG effects processing and other processing
4404 : // performed if we called this->InvalidateWithFlags, because those effects
4405 : // are performed before applying transforms.
4406 0 : mParent->InvalidateInternal(GetVisualOverflowRect() + GetPosition(),
4407 : 0, 0, this,
4408 0 : hasLayer ? INVALIDATE_NO_THEBES_LAYERS : 0);
4409 0 : }
4410 :
4411 : class LayerActivity {
4412 : public:
4413 0 : LayerActivity(nsIFrame* aFrame) : mFrame(aFrame), mChangeHint(nsChangeHint(0)) {}
4414 : ~LayerActivity();
4415 0 : nsExpirationState* GetExpirationState() { return &mState; }
4416 :
4417 : nsIFrame* mFrame;
4418 : nsExpirationState mState;
4419 : // mChangeHint can be some combination of nsChangeHint_UpdateOpacityLayer and
4420 : // nsChangeHint_UpdateTransformLayer (or neither)
4421 : // The presence of those bits indicates whether opacity or transform
4422 : // changes have been detected.
4423 : nsChangeHint mChangeHint;
4424 : };
4425 :
4426 : class LayerActivityTracker MOZ_FINAL : public nsExpirationTracker<LayerActivity,4> {
4427 : public:
4428 : // 75-100ms is a good timeout period. We use 4 generations of 25ms each.
4429 : enum { GENERATION_MS = 100 };
4430 0 : LayerActivityTracker()
4431 0 : : nsExpirationTracker<LayerActivity,4>(GENERATION_MS) {}
4432 0 : ~LayerActivityTracker() {
4433 0 : AgeAllGenerations();
4434 0 : }
4435 :
4436 : virtual void NotifyExpired(LayerActivity* aObject);
4437 : };
4438 :
4439 : static LayerActivityTracker* gLayerActivityTracker = nsnull;
4440 :
4441 0 : LayerActivity::~LayerActivity()
4442 : {
4443 0 : if (mFrame) {
4444 0 : NS_ASSERTION(gLayerActivityTracker, "Should still have a tracker");
4445 0 : gLayerActivityTracker->RemoveObject(this);
4446 : }
4447 0 : }
4448 :
4449 0 : static void DestroyLayerActivity(void* aPropertyValue)
4450 : {
4451 0 : delete static_cast<LayerActivity*>(aPropertyValue);
4452 0 : }
4453 :
4454 0 : NS_DECLARE_FRAME_PROPERTY(LayerActivityProperty, DestroyLayerActivity)
4455 :
4456 : void
4457 0 : LayerActivityTracker::NotifyExpired(LayerActivity* aObject)
4458 : {
4459 0 : RemoveObject(aObject);
4460 :
4461 0 : nsIFrame* f = aObject->mFrame;
4462 0 : aObject->mFrame = nsnull;
4463 0 : f->Properties().Delete(LayerActivityProperty());
4464 0 : f->InvalidateFrameSubtree();
4465 0 : }
4466 :
4467 : void
4468 0 : nsIFrame::MarkLayersActive(nsChangeHint aChangeHint)
4469 : {
4470 0 : FrameProperties properties = Properties();
4471 : LayerActivity* layerActivity =
4472 0 : static_cast<LayerActivity*>(properties.Get(LayerActivityProperty()));
4473 0 : if (layerActivity) {
4474 0 : gLayerActivityTracker->MarkUsed(layerActivity);
4475 : } else {
4476 0 : if (!gLayerActivityTracker) {
4477 0 : gLayerActivityTracker = new LayerActivityTracker();
4478 : }
4479 0 : layerActivity = new LayerActivity(this);
4480 0 : gLayerActivityTracker->AddObject(layerActivity);
4481 0 : properties.Set(LayerActivityProperty(), layerActivity);
4482 : }
4483 0 : NS_UpdateHint(layerActivity->mChangeHint, aChangeHint);
4484 0 : }
4485 :
4486 : bool
4487 0 : nsIFrame::AreLayersMarkedActive()
4488 : {
4489 0 : return Properties().Get(LayerActivityProperty()) != nsnull;
4490 : }
4491 :
4492 : bool
4493 0 : nsIFrame::AreLayersMarkedActive(nsChangeHint aChangeHint)
4494 : {
4495 : LayerActivity* layerActivity =
4496 0 : static_cast<LayerActivity*>(Properties().Get(LayerActivityProperty()));
4497 0 : return layerActivity && (layerActivity->mChangeHint & aChangeHint);
4498 : }
4499 :
4500 : /* static */ void
4501 1403 : nsFrame::ShutdownLayerActivityTimer()
4502 : {
4503 1403 : delete gLayerActivityTracker;
4504 1403 : gLayerActivityTracker = nsnull;
4505 1403 : }
4506 :
4507 : void
4508 0 : nsIFrame::InvalidateWithFlags(const nsRect& aDamageRect, PRUint32 aFlags)
4509 : {
4510 0 : if (aDamageRect.IsEmpty()) {
4511 0 : return;
4512 : }
4513 :
4514 : // Don't allow invalidates to do anything when
4515 : // painting is suppressed.
4516 0 : nsIPresShell *shell = PresContext()->GetPresShell();
4517 0 : if (shell) {
4518 0 : if (shell->IsPaintingSuppressed())
4519 0 : return;
4520 : }
4521 :
4522 0 : InvalidateInternal(aDamageRect, 0, 0, nsnull, aFlags);
4523 : }
4524 :
4525 : /**
4526 : * Helper function that funnels an InvalidateInternal request up to the
4527 : * parent. This function is used so that if MOZ_SVG is not defined, we still
4528 : * have unified control paths in the InvalidateInternal chain.
4529 : *
4530 : * @param aDamageRect The rect to invalidate.
4531 : * @param aX The x offset from the origin of this frame to the rectangle.
4532 : * @param aY The y offset from the origin of this frame to the rectangle.
4533 : * @param aImmediate Whether to redraw immediately.
4534 : * @return None, though this funnels the request up to the parent frame.
4535 : */
4536 : void
4537 0 : nsIFrame::InvalidateInternalAfterResize(const nsRect& aDamageRect, nscoord aX,
4538 : nscoord aY, PRUint32 aFlags)
4539 : {
4540 : /* If we're a transformed frame, then we need to apply our transform to the
4541 : * damage rectangle so that the redraw correctly redraws the transformed
4542 : * region. We're moved over aX and aY from our origin, but since this aX
4543 : * and aY is contained within our border, we need to scoot back by -aX and
4544 : * -aY to get back to the origin of the transform.
4545 : *
4546 : * There's one more problem, though, and that's that we don't know what
4547 : * coordinate space this rectangle is in. Sometimes it's in the local
4548 : * coordinate space for the frame, and sometimes its in the transformed
4549 : * coordinate space. If we get it wrong, we'll display incorrectly. Until I
4550 : * find a better fix for this problem, we'll invalidate the union of the two
4551 : * rectangles (original rectangle and transformed rectangle). At least one of
4552 : * these will be correct.
4553 : *
4554 : * When we are preserving-3d, we can have arbitrary hierarchies of preserved 3d
4555 : * children. The computed transform on these children is relative to the root
4556 : * transform object in the hierarchy, not necessarily their direct ancestor.
4557 : * In this case we transform by the child's transform, and mark the rectangle
4558 : * as being transformed until it is passed up to the root of the hierarchy.
4559 : *
4560 : * See bug #452496 for more details.
4561 : */
4562 :
4563 : // Check the transformed flags and remove it
4564 0 : bool rectIsTransformed = (aFlags & INVALIDATE_ALREADY_TRANSFORMED);
4565 0 : if (!Preserves3D()) {
4566 : // We only want to remove the flag if we aren't preserving 3d. Otherwise
4567 : // the rect will already have been transformed into the root preserve-3d
4568 : // frame coordinate space, and we should continue passing it up without
4569 : // further transforms.
4570 0 : aFlags &= ~INVALIDATE_ALREADY_TRANSFORMED;
4571 : }
4572 :
4573 0 : if ((mState & NS_FRAME_HAS_CONTAINER_LAYER) &&
4574 0 : !(aFlags & INVALIDATE_NO_THEBES_LAYERS)) {
4575 : // XXX for now I'm going to assume this is in the local coordinate space
4576 : // This only matters for frames with transforms and retained layers,
4577 : // which can't happen right now since transforms trigger fallback
4578 : // rendering and the display items that trigger layers are nested inside
4579 : // the nsDisplayTransform
4580 : // XXX need to set INVALIDATE_NO_THEBES_LAYERS for certain kinds of
4581 : // invalidation, e.g. video update, 'opacity' change
4582 : FrameLayerBuilder::InvalidateThebesLayerContents(this,
4583 0 : aDamageRect + nsPoint(aX, aY));
4584 : // Don't need to invalidate any more Thebes layers
4585 0 : aFlags |= INVALIDATE_NO_THEBES_LAYERS;
4586 0 : if (aFlags & INVALIDATE_ONLY_THEBES_LAYERS) {
4587 0 : return;
4588 : }
4589 : }
4590 0 : if (IsTransformed() && !rectIsTransformed) {
4591 0 : nsRect newDamageRect;
4592 : newDamageRect.UnionRect(nsDisplayTransform::TransformRectOut
4593 0 : (aDamageRect, this, nsPoint(-aX, -aY)), aDamageRect);
4594 :
4595 : // If we are preserving 3d, then our computed transform includes that of any
4596 : // ancestor frames that also preserve 3d. Mark the rectangle as already being
4597 : // transformed into the parent's coordinate space.
4598 0 : if (Preserves3D()) {
4599 0 : aFlags |= INVALIDATE_ALREADY_TRANSFORMED;
4600 : }
4601 :
4602 0 : GetParent()->
4603 : InvalidateInternal(newDamageRect, aX + mRect.x, aY + mRect.y, this,
4604 0 : aFlags);
4605 : }
4606 : else
4607 0 : GetParent()->
4608 0 : InvalidateInternal(aDamageRect, aX + mRect.x, aY + mRect.y, this, aFlags);
4609 : }
4610 :
4611 : void
4612 0 : nsIFrame::InvalidateInternal(const nsRect& aDamageRect, nscoord aX, nscoord aY,
4613 : nsIFrame* aForChild, PRUint32 aFlags)
4614 : {
4615 0 : nsSVGEffects::InvalidateDirectRenderingObservers(this);
4616 0 : if (nsSVGIntegrationUtils::UsingEffectsForFrame(this)) {
4617 : nsRect r = nsSVGIntegrationUtils::GetInvalidAreaForChangedSource(this,
4618 0 : aDamageRect + nsPoint(aX, aY));
4619 : /* Rectangle is now in our own local space, so aX and aY are effectively
4620 : * zero. Thus we'll pretend that the entire time this was in our own
4621 : * local coordinate space and do any remaining processing.
4622 : */
4623 0 : InvalidateInternalAfterResize(r, 0, 0, aFlags);
4624 : return;
4625 : }
4626 :
4627 0 : InvalidateInternalAfterResize(aDamageRect, aX, aY, aFlags);
4628 : }
4629 :
4630 : gfx3DMatrix
4631 0 : nsIFrame::GetTransformMatrix(nsIFrame* aStopAtAncestor,
4632 : nsIFrame** aOutAncestor)
4633 : {
4634 0 : NS_PRECONDITION(aOutAncestor, "Need a place to put the ancestor!");
4635 :
4636 : /* If we're transformed, we want to hand back the combination
4637 : * transform/translate matrix that will apply our current transform, then
4638 : * shift us to our parent.
4639 : */
4640 0 : if (IsTransformed()) {
4641 : /* Compute the delta to the parent, which we need because we are converting
4642 : * coordinates to our parent.
4643 : */
4644 0 : NS_ASSERTION(nsLayoutUtils::GetCrossDocParentFrame(this),
4645 : "Cannot transform the viewport frame!");
4646 0 : PRInt32 scaleFactor = PresContext()->AppUnitsPerDevPixel();
4647 :
4648 : gfx3DMatrix result =
4649 : nsDisplayTransform::GetResultingTransformMatrix(this, nsPoint(0, 0),
4650 0 : scaleFactor, nsnull, aOutAncestor);
4651 0 : nsPoint delta = GetOffsetToCrossDoc(*aOutAncestor);
4652 : /* Combine the raw transform with a translation to our parent. */
4653 : result *= gfx3DMatrix::Translation
4654 : (NSAppUnitsToFloatPixels(delta.x, scaleFactor),
4655 : NSAppUnitsToFloatPixels(delta.y, scaleFactor),
4656 0 : 0.0f);
4657 0 : return result;
4658 : }
4659 :
4660 0 : *aOutAncestor = nsLayoutUtils::GetCrossDocParentFrame(this);
4661 :
4662 : /* Otherwise, we're not transformed. In that case, we'll walk up the frame
4663 : * tree until we either hit the root frame or something that may be
4664 : * transformed. We'll then change coordinates into that frame, since we're
4665 : * guaranteed that nothing in-between can be transformed. First, however,
4666 : * we have to check to see if we have a parent. If not, we'll set the
4667 : * outparam to null (indicating that there's nothing left) and will hand back
4668 : * the identity matrix.
4669 : */
4670 0 : if (!*aOutAncestor)
4671 0 : return gfx3DMatrix();
4672 :
4673 : /* Keep iterating while the frame can't possibly be transformed. */
4674 0 : while (!(*aOutAncestor)->IsTransformed() && *aOutAncestor != aStopAtAncestor) {
4675 : /* If no parent, stop iterating. Otherwise, update the ancestor. */
4676 0 : nsIFrame* parent = nsLayoutUtils::GetCrossDocParentFrame(*aOutAncestor);
4677 0 : if (!parent)
4678 0 : break;
4679 :
4680 0 : *aOutAncestor = parent;
4681 : }
4682 :
4683 0 : NS_ASSERTION(*aOutAncestor, "Somehow ended up with a null ancestor...?");
4684 :
4685 : /* Translate from this frame to our ancestor, if it exists. That's the
4686 : * entire transform, so we're done.
4687 : */
4688 0 : nsPoint delta = GetOffsetToCrossDoc(*aOutAncestor);
4689 0 : PRInt32 scaleFactor = PresContext()->AppUnitsPerDevPixel();
4690 : return gfx3DMatrix().Translation
4691 : (NSAppUnitsToFloatPixels(delta.x, scaleFactor),
4692 : NSAppUnitsToFloatPixels(delta.y, scaleFactor),
4693 0 : 0.0f);
4694 : }
4695 :
4696 : void
4697 0 : nsIFrame::InvalidateRectDifference(const nsRect& aR1, const nsRect& aR2)
4698 : {
4699 0 : nsRect sizeHStrip, sizeVStrip;
4700 0 : nsLayoutUtils::GetRectDifferenceStrips(aR1, aR2, &sizeHStrip, &sizeVStrip);
4701 0 : Invalidate(sizeVStrip);
4702 0 : Invalidate(sizeHStrip);
4703 0 : }
4704 :
4705 : void
4706 0 : nsIFrame::InvalidateFrameSubtree()
4707 : {
4708 0 : Invalidate(GetVisualOverflowRectRelativeToSelf());
4709 0 : FrameLayerBuilder::InvalidateThebesLayersInSubtree(this);
4710 0 : }
4711 :
4712 : void
4713 0 : nsIFrame::InvalidateOverflowRect()
4714 : {
4715 0 : Invalidate(GetVisualOverflowRectRelativeToSelf());
4716 0 : }
4717 :
4718 0 : NS_DECLARE_FRAME_PROPERTY(DeferInvalidatesProperty, nsIFrame::DestroyRegion)
4719 :
4720 : void
4721 0 : nsIFrame::InvalidateRoot(const nsRect& aDamageRect, PRUint32 aFlags)
4722 : {
4723 0 : NS_ASSERTION(nsLayoutUtils::GetDisplayRootFrame(this) == this,
4724 : "Can only call this on display roots");
4725 :
4726 0 : if ((mState & NS_FRAME_HAS_CONTAINER_LAYER) &&
4727 0 : !(aFlags & INVALIDATE_NO_THEBES_LAYERS)) {
4728 0 : FrameLayerBuilder::InvalidateThebesLayerContents(this, aDamageRect);
4729 0 : if (aFlags & INVALIDATE_ONLY_THEBES_LAYERS) {
4730 0 : return;
4731 : }
4732 : }
4733 :
4734 0 : nsRect rect = aDamageRect;
4735 : nsRegion* excludeRegion = static_cast<nsRegion*>
4736 0 : (Properties().Get(DeferInvalidatesProperty()));
4737 0 : if (excludeRegion && (aFlags & INVALIDATE_EXCLUDE_CURRENT_PAINT)) {
4738 0 : nsRegion r;
4739 0 : r.Sub(rect, *excludeRegion);
4740 0 : if (r.IsEmpty())
4741 : return;
4742 0 : rect = r.GetBounds();
4743 : }
4744 :
4745 0 : if (!(aFlags & INVALIDATE_NO_UPDATE_LAYER_TREE)) {
4746 0 : AddStateBits(NS_FRAME_UPDATE_LAYER_TREE);
4747 : }
4748 :
4749 0 : nsIView* view = GetView();
4750 0 : NS_ASSERTION(view, "This can only be called on frames with views");
4751 0 : view->GetViewManager()->InvalidateViewNoSuppression(view, rect);
4752 : }
4753 :
4754 : void
4755 0 : nsIFrame::BeginDeferringInvalidatesForDisplayRoot(const nsRegion& aExcludeRegion)
4756 : {
4757 0 : NS_ASSERTION(nsLayoutUtils::GetDisplayRootFrame(this) == this,
4758 : "Can only call this on display roots");
4759 0 : Properties().Set(DeferInvalidatesProperty(), new nsRegion(aExcludeRegion));
4760 0 : }
4761 :
4762 : void
4763 0 : nsIFrame::EndDeferringInvalidatesForDisplayRoot()
4764 : {
4765 0 : NS_ASSERTION(nsLayoutUtils::GetDisplayRootFrame(this) == this,
4766 : "Can only call this on display roots");
4767 0 : Properties().Delete(DeferInvalidatesProperty());
4768 0 : }
4769 :
4770 : /**
4771 : * @param aAnyOutlineOrEffects set to true if this frame has any
4772 : * outline, SVG effects or box shadows that mean we need to invalidate
4773 : * the whole overflow area if the frame's size changes.
4774 : */
4775 : static nsRect
4776 0 : ComputeOutlineAndEffectsRect(nsIFrame* aFrame, bool* aAnyOutlineOrEffects,
4777 : const nsRect& aOverflowRect,
4778 : const nsSize& aNewSize,
4779 : bool aStoreRectProperties) {
4780 0 : nsRect r = aOverflowRect;
4781 0 : *aAnyOutlineOrEffects = false;
4782 :
4783 : // box-shadow
4784 0 : nsCSSShadowArray* boxShadows = aFrame->GetStyleBorder()->mBoxShadow;
4785 0 : if (boxShadows) {
4786 0 : nsRect shadows;
4787 0 : PRInt32 A2D = aFrame->PresContext()->AppUnitsPerDevPixel();
4788 0 : for (PRUint32 i = 0; i < boxShadows->Length(); ++i) {
4789 0 : nsRect tmpRect(nsPoint(0, 0), aNewSize);
4790 0 : nsCSSShadowItem* shadow = boxShadows->ShadowAt(i);
4791 :
4792 : // inset shadows are never painted outside the frame
4793 0 : if (shadow->mInset)
4794 0 : continue;
4795 :
4796 0 : tmpRect.MoveBy(nsPoint(shadow->mXOffset, shadow->mYOffset));
4797 0 : tmpRect.Inflate(shadow->mSpread, shadow->mSpread);
4798 : tmpRect.Inflate(
4799 0 : nsContextBoxBlur::GetBlurRadiusMargin(shadow->mRadius, A2D));
4800 :
4801 0 : shadows.UnionRect(shadows, tmpRect);
4802 : }
4803 0 : r.UnionRect(r, shadows);
4804 0 : *aAnyOutlineOrEffects = true;
4805 : }
4806 :
4807 0 : const nsStyleOutline* outline = aFrame->GetStyleOutline();
4808 0 : PRUint8 outlineStyle = outline->GetOutlineStyle();
4809 0 : if (outlineStyle != NS_STYLE_BORDER_STYLE_NONE) {
4810 : nscoord width;
4811 : #ifdef DEBUG
4812 : bool result =
4813 : #endif
4814 0 : outline->GetOutlineWidth(width);
4815 0 : NS_ASSERTION(result, "GetOutlineWidth had no cached outline width");
4816 0 : if (width > 0) {
4817 0 : if (aStoreRectProperties) {
4818 : aFrame->Properties().
4819 0 : Set(nsIFrame::OutlineInnerRectProperty(), new nsRect(r));
4820 : }
4821 :
4822 0 : nscoord offset = outline->mOutlineOffset;
4823 0 : nscoord inflateBy = NS_MAX(width + offset, 0);
4824 : // FIXME (bug 599652): We probably want outline to be drawn around
4825 : // something smaller than the visual overflow rect (perhaps the
4826 : // scrollable overflow rect is correct). When we change that, we
4827 : // need to keep this code (and the storing of properties just
4828 : // above) in sync with GetOutlineInnerRect in nsCSSRendering.cpp.
4829 0 : r.Inflate(inflateBy, inflateBy);
4830 0 : *aAnyOutlineOrEffects = true;
4831 : }
4832 : }
4833 :
4834 : // Note that we don't remove the outlineInnerRect if a frame loses outline
4835 : // style. That would require an extra property lookup for every frame,
4836 : // or a new frame state bit to track whether a property had been stored,
4837 : // or something like that. It's not worth doing that here. At most it's
4838 : // only one heap-allocated rect per frame and it will be cleaned up when
4839 : // the frame dies.
4840 :
4841 0 : if (nsSVGIntegrationUtils::UsingEffectsForFrame(aFrame)) {
4842 0 : *aAnyOutlineOrEffects = true;
4843 0 : if (aStoreRectProperties) {
4844 : aFrame->Properties().
4845 0 : Set(nsIFrame::PreEffectsBBoxProperty(), new nsRect(r));
4846 : }
4847 0 : r = nsSVGIntegrationUtils::ComputeFrameEffectsRect(aFrame, r);
4848 : }
4849 :
4850 : return r;
4851 : }
4852 :
4853 : nsPoint
4854 0 : nsIFrame::GetRelativeOffset(const nsStyleDisplay* aDisplay) const
4855 : {
4856 0 : if (!aDisplay || NS_STYLE_POSITION_RELATIVE == aDisplay->mPosition) {
4857 : nsPoint *offsets = static_cast<nsPoint*>
4858 0 : (Properties().Get(ComputedOffsetProperty()));
4859 0 : if (offsets) {
4860 0 : return *offsets;
4861 : }
4862 : }
4863 0 : return nsPoint(0,0);
4864 : }
4865 :
4866 : nsRect
4867 0 : nsIFrame::GetOverflowRect(nsOverflowType aType) const
4868 : {
4869 0 : NS_ABORT_IF_FALSE(aType == eVisualOverflow || aType == eScrollableOverflow,
4870 : "unexpected type");
4871 :
4872 : // Note that in some cases the overflow area might not have been
4873 : // updated (yet) to reflect any outline set on the frame or the area
4874 : // of child frames. That's OK because any reflow that updates these
4875 : // areas will invalidate the appropriate area, so any (mis)uses of
4876 : // this method will be fixed up.
4877 :
4878 0 : if (mOverflow.mType == NS_FRAME_OVERFLOW_LARGE) {
4879 : // there is an overflow rect, and it's not stored as deltas but as
4880 : // a separately-allocated rect
4881 : return static_cast<nsOverflowAreas*>(const_cast<nsIFrame*>(this)->
4882 0 : GetOverflowAreasProperty())->Overflow(aType);
4883 : }
4884 :
4885 0 : if (aType == eVisualOverflow &&
4886 : mOverflow.mType != NS_FRAME_OVERFLOW_NONE) {
4887 0 : return GetVisualOverflowFromDeltas();
4888 : }
4889 :
4890 0 : return nsRect(nsPoint(0, 0), GetSize());
4891 : }
4892 :
4893 : nsOverflowAreas
4894 0 : nsIFrame::GetOverflowAreas() const
4895 : {
4896 0 : if (mOverflow.mType == NS_FRAME_OVERFLOW_LARGE) {
4897 : // there is an overflow rect, and it's not stored as deltas but as
4898 : // a separately-allocated rect
4899 0 : return *const_cast<nsIFrame*>(this)->GetOverflowAreasProperty();
4900 : }
4901 :
4902 0 : return nsOverflowAreas(GetVisualOverflowFromDeltas(),
4903 0 : nsRect(nsPoint(0, 0), GetSize()));
4904 : }
4905 :
4906 : nsRect
4907 0 : nsIFrame::GetScrollableOverflowRectRelativeToParent() const
4908 : {
4909 0 : return GetScrollableOverflowRect() + mRect.TopLeft();
4910 : }
4911 :
4912 : nsRect
4913 0 : nsIFrame::GetVisualOverflowRectRelativeToSelf() const
4914 : {
4915 0 : if (IsTransformed()) {
4916 : nsOverflowAreas* preTransformOverflows = static_cast<nsOverflowAreas*>
4917 0 : (Properties().Get(PreTransformOverflowAreasProperty()));
4918 0 : if (preTransformOverflows)
4919 0 : return preTransformOverflows->VisualOverflow();
4920 : }
4921 0 : return GetVisualOverflowRect();
4922 : }
4923 :
4924 : /* virtual */ bool
4925 0 : nsFrame::UpdateOverflow()
4926 : {
4927 0 : nsRect rect(nsPoint(0, 0), GetSize());
4928 0 : nsOverflowAreas overflowAreas(rect, rect);
4929 :
4930 0 : bool isBox = IsBoxFrame() || IsBoxWrapped();
4931 0 : if (!isBox || (!IsCollapsed() && !DoesClipChildren())) {
4932 0 : nsLayoutUtils::UnionChildOverflow(this, overflowAreas);
4933 : }
4934 :
4935 0 : if (FinishAndStoreOverflow(overflowAreas, GetSize())) {
4936 0 : nsIView* view = GetView();
4937 0 : if (view) {
4938 0 : PRUint32 flags = 0;
4939 0 : GetLayoutFlags(flags);
4940 :
4941 0 : if ((flags & NS_FRAME_NO_SIZE_VIEW) == 0) {
4942 : // Make sure the frame's view is properly sized.
4943 0 : nsIViewManager* vm = view->GetViewManager();
4944 0 : vm->ResizeView(view, overflowAreas.VisualOverflow(), true);
4945 : }
4946 : }
4947 :
4948 0 : return true;
4949 : }
4950 :
4951 0 : return false;
4952 : }
4953 :
4954 : void
4955 0 : nsFrame::CheckInvalidateSizeChange(nsHTMLReflowMetrics& aNewDesiredSize)
4956 : {
4957 0 : nsIFrame::CheckInvalidateSizeChange(mRect, GetVisualOverflowRect(),
4958 0 : nsSize(aNewDesiredSize.width, aNewDesiredSize.height));
4959 0 : }
4960 :
4961 : static void
4962 0 : InvalidateRectForFrameSizeChange(nsIFrame* aFrame, const nsRect& aRect)
4963 : {
4964 : nsStyleContext *bgSC;
4965 0 : if (!nsCSSRendering::FindBackground(aFrame->PresContext(), aFrame, &bgSC)) {
4966 : nsIFrame* rootFrame =
4967 0 : aFrame->PresContext()->PresShell()->FrameManager()->GetRootFrame();
4968 0 : rootFrame->Invalidate(nsRect(nsPoint(0, 0), rootFrame->GetSize()));
4969 : }
4970 :
4971 0 : aFrame->Invalidate(aRect);
4972 0 : }
4973 :
4974 : void
4975 0 : nsIFrame::CheckInvalidateSizeChange(const nsRect& aOldRect,
4976 : const nsRect& aOldVisualOverflowRect,
4977 : const nsSize& aNewDesiredSize)
4978 : {
4979 0 : if (aNewDesiredSize == aOldRect.Size())
4980 0 : return;
4981 :
4982 : // Below, we invalidate the old frame area (or, in the case of
4983 : // outline, combined area) if the outline, border or background
4984 : // settings indicate that something other than the difference
4985 : // between the old and new areas needs to be painted. We are
4986 : // assuming that the difference between the old and new areas will
4987 : // be invalidated by some other means. That also means invalidating
4988 : // the old frame area is the same as invalidating the new frame area
4989 : // (since in either case the UNION of old and new areas will be
4990 : // invalidated)
4991 :
4992 : // We use InvalidateRectForFrameSizeChange throughout this method, even
4993 : // though root-invalidation is technically only needed in the case where
4994 : // layer.RenderingMightDependOnFrameSize(). This allows us to simplify the
4995 : // code somewhat and return immediately after invalidation in the earlier
4996 : // cases.
4997 :
4998 : // Invalidate the entire old frame+outline if the frame has an outline
4999 : bool anyOutlineOrEffects;
5000 : nsRect r = ComputeOutlineAndEffectsRect(this, &anyOutlineOrEffects,
5001 : aOldVisualOverflowRect,
5002 : aNewDesiredSize,
5003 0 : false);
5004 0 : if (anyOutlineOrEffects) {
5005 0 : r.UnionRect(aOldVisualOverflowRect, r);
5006 0 : InvalidateRectForFrameSizeChange(this, r);
5007 : return;
5008 : }
5009 :
5010 : // Invalidate the old frame border box if the frame has borders. Those
5011 : // borders may be moving.
5012 0 : const nsStyleBorder* border = GetStyleBorder();
5013 0 : NS_FOR_CSS_SIDES(side) {
5014 0 : if (border->GetActualBorderWidth(side) != 0) {
5015 0 : if ((side == NS_SIDE_LEFT || side == NS_SIDE_TOP) &&
5016 0 : !nsLayoutUtils::HasNonZeroCornerOnSide(border->mBorderRadius, side) &&
5017 0 : !border->GetBorderImage() &&
5018 0 : border->GetBorderStyle(side) == NS_STYLE_BORDER_STYLE_SOLID) {
5019 : // We also need to be sure that the bottom-left or top-right
5020 : // corner is simple. For example, if the bottom or right border
5021 : // has a different color, we would need to invalidate the corner
5022 : // area. But that's OK because if there is a right or bottom border,
5023 : // we'll invalidate the entire border-box here anyway.
5024 0 : continue;
5025 : }
5026 0 : InvalidateRectForFrameSizeChange(this, nsRect(0, 0, aOldRect.width, aOldRect.height));
5027 : return;
5028 : }
5029 : }
5030 :
5031 0 : const nsStyleBackground *bg = GetStyleBackground();
5032 0 : if (!bg->IsTransparent()) {
5033 : // Invalidate the old frame background if the frame has a background
5034 : // whose position depends on the size of the frame
5035 0 : NS_FOR_VISIBLE_BACKGROUND_LAYERS_BACK_TO_FRONT(i, bg) {
5036 0 : const nsStyleBackground::Layer &layer = bg->mLayers[i];
5037 0 : if (layer.RenderingMightDependOnFrameSize()) {
5038 0 : InvalidateRectForFrameSizeChange(this, nsRect(0, 0, aOldRect.width, aOldRect.height));
5039 : return;
5040 : }
5041 : }
5042 :
5043 : // Invalidate the old frame background if the frame has a background
5044 : // that is being clipped by border-radius, since the old or new area
5045 : // clipped off by the radius is not necessarily in the area that has
5046 : // already been invalidated (even if only the top-left corner has a
5047 : // border radius).
5048 0 : if (nsLayoutUtils::HasNonZeroCorner(border->mBorderRadius)) {
5049 0 : InvalidateRectForFrameSizeChange(this, nsRect(0, 0, aOldRect.width, aOldRect.height));
5050 : return;
5051 : }
5052 : }
5053 : }
5054 :
5055 : // Define the MAX_FRAME_DEPTH to be the ContentSink's MAX_REFLOW_DEPTH plus
5056 : // 4 for the frames above the document's frames:
5057 : // the Viewport, GFXScroll, ScrollPort, and Canvas
5058 : #define MAX_FRAME_DEPTH (MAX_REFLOW_DEPTH+4)
5059 :
5060 : bool
5061 0 : nsFrame::IsFrameTreeTooDeep(const nsHTMLReflowState& aReflowState,
5062 : nsHTMLReflowMetrics& aMetrics,
5063 : nsReflowStatus& aStatus)
5064 : {
5065 0 : if (aReflowState.mReflowDepth > MAX_FRAME_DEPTH) {
5066 0 : NS_WARNING("frame tree too deep; setting zero size and returning");
5067 0 : mState |= NS_FRAME_TOO_DEEP_IN_FRAME_TREE;
5068 0 : ClearOverflowRects();
5069 0 : aMetrics.width = 0;
5070 0 : aMetrics.height = 0;
5071 0 : aMetrics.ascent = 0;
5072 0 : aMetrics.mCarriedOutBottomMargin.Zero();
5073 0 : aMetrics.mOverflowAreas.Clear();
5074 :
5075 0 : if (GetNextInFlow()) {
5076 : // Reflow depth might vary between reflows, so we might have
5077 : // successfully reflowed and split this frame before. If so, we
5078 : // shouldn't delete its continuations.
5079 0 : aStatus = NS_FRAME_NOT_COMPLETE;
5080 : } else {
5081 0 : aStatus = NS_FRAME_COMPLETE;
5082 : }
5083 :
5084 0 : return true;
5085 : }
5086 0 : mState &= ~NS_FRAME_TOO_DEEP_IN_FRAME_TREE;
5087 0 : return false;
5088 : }
5089 :
5090 : bool
5091 0 : nsIFrame::IsBlockWrapper() const
5092 : {
5093 0 : nsIAtom *pseudoType = GetStyleContext()->GetPseudo();
5094 : return (pseudoType == nsCSSAnonBoxes::mozAnonymousBlock ||
5095 : pseudoType == nsCSSAnonBoxes::mozAnonymousPositionedBlock ||
5096 0 : pseudoType == nsCSSAnonBoxes::cellContent);
5097 : }
5098 :
5099 : static nsIFrame*
5100 0 : GetNearestBlockContainer(nsIFrame* frame)
5101 : {
5102 : // The block wrappers we use to wrap blocks inside inlines aren't
5103 : // described in the CSS spec. We need to make them not be containing
5104 : // blocks.
5105 : // Since the parent of such a block is either a normal block or
5106 : // another such pseudo, this shouldn't cause anything bad to happen.
5107 : // Also the anonymous blocks inside table cells are not containing blocks.
5108 0 : while (frame->IsFrameOfType(nsIFrame::eLineParticipant) ||
5109 0 : frame->IsBlockWrapper() ||
5110 : // Table rows are not containing blocks either
5111 0 : frame->GetType() == nsGkAtoms::tableRowFrame) {
5112 0 : frame = frame->GetParent();
5113 0 : NS_ASSERTION(frame, "How come we got to the root frame without seeing a containing block?");
5114 : }
5115 0 : return frame;
5116 : }
5117 :
5118 : nsIFrame*
5119 0 : nsIFrame::GetContainingBlock() const
5120 : {
5121 : // MathML frames might have absolute positioning style, but they would
5122 : // still be in-flow. So we have to check to make sure that the frame
5123 : // is really out-of-flow too.
5124 0 : if (GetStyleDisplay()->IsAbsolutelyPositioned() &&
5125 0 : (GetStateBits() & NS_FRAME_OUT_OF_FLOW)) {
5126 0 : return GetParent(); // the parent is always the containing block
5127 : }
5128 0 : return GetNearestBlockContainer(GetParent());
5129 : }
5130 :
5131 : #ifdef NS_DEBUG
5132 :
5133 0 : PRInt32 nsFrame::ContentIndexInContainer(const nsIFrame* aFrame)
5134 : {
5135 0 : PRInt32 result = -1;
5136 :
5137 0 : nsIContent* content = aFrame->GetContent();
5138 0 : if (content) {
5139 0 : nsIContent* parentContent = content->GetParent();
5140 0 : if (parentContent) {
5141 0 : result = parentContent->IndexOf(content);
5142 : }
5143 : }
5144 :
5145 0 : return result;
5146 : }
5147 :
5148 : /**
5149 : * List a frame tree to stdout. Meant to be called from gdb.
5150 : */
5151 : void
5152 0 : DebugListFrameTree(nsIFrame* aFrame)
5153 : {
5154 0 : ((nsFrame*)aFrame)->List(stdout, 0);
5155 0 : }
5156 :
5157 :
5158 : // Debugging
5159 : NS_IMETHODIMP
5160 0 : nsFrame::List(FILE* out, PRInt32 aIndent) const
5161 : {
5162 0 : IndentBy(out, aIndent);
5163 0 : ListTag(out);
5164 : #ifdef DEBUG_waterson
5165 : fprintf(out, " [parent=%p]", static_cast<void*>(mParent));
5166 : #endif
5167 0 : if (HasView()) {
5168 0 : fprintf(out, " [view=%p]", static_cast<void*>(GetView()));
5169 : }
5170 0 : fprintf(out, " {%d,%d,%d,%d}", mRect.x, mRect.y, mRect.width, mRect.height);
5171 0 : if (0 != mState) {
5172 0 : fprintf(out, " [state=%016llx]", (unsigned long long)mState);
5173 : }
5174 0 : nsIFrame* prevInFlow = GetPrevInFlow();
5175 0 : nsIFrame* nextInFlow = GetNextInFlow();
5176 0 : if (nsnull != prevInFlow) {
5177 0 : fprintf(out, " prev-in-flow=%p", static_cast<void*>(prevInFlow));
5178 : }
5179 0 : if (nsnull != nextInFlow) {
5180 0 : fprintf(out, " next-in-flow=%p", static_cast<void*>(nextInFlow));
5181 : }
5182 0 : fprintf(out, " [content=%p]", static_cast<void*>(mContent));
5183 0 : nsFrame* f = const_cast<nsFrame*>(this);
5184 0 : if (f->HasOverflowAreas()) {
5185 0 : nsRect overflowArea = f->GetVisualOverflowRect();
5186 : fprintf(out, " [vis-overflow=%d,%d,%d,%d]", overflowArea.x, overflowArea.y,
5187 0 : overflowArea.width, overflowArea.height);
5188 0 : overflowArea = f->GetScrollableOverflowRect();
5189 : fprintf(out, " [scr-overflow=%d,%d,%d,%d]", overflowArea.x, overflowArea.y,
5190 0 : overflowArea.width, overflowArea.height);
5191 : }
5192 0 : fprintf(out, " [sc=%p]", static_cast<void*>(mStyleContext));
5193 0 : fputs("\n", out);
5194 0 : return NS_OK;
5195 : }
5196 :
5197 : NS_IMETHODIMP
5198 0 : nsFrame::GetFrameName(nsAString& aResult) const
5199 : {
5200 0 : return MakeFrameName(NS_LITERAL_STRING("Frame"), aResult);
5201 : }
5202 :
5203 : NS_IMETHODIMP_(nsFrameState)
5204 0 : nsFrame::GetDebugStateBits() const
5205 : {
5206 : // We'll ignore these flags for the purposes of comparing frame state:
5207 : //
5208 : // NS_FRAME_EXTERNAL_REFERENCE
5209 : // because this is set by the event state manager or the
5210 : // caret code when a frame is focused. Depending on whether
5211 : // or not the regression tests are run as the focused window
5212 : // will make this value vary randomly.
5213 : #define IRRELEVANT_FRAME_STATE_FLAGS NS_FRAME_EXTERNAL_REFERENCE
5214 :
5215 : #define FRAME_STATE_MASK (~(IRRELEVANT_FRAME_STATE_FLAGS))
5216 :
5217 0 : return GetStateBits() & FRAME_STATE_MASK;
5218 : }
5219 :
5220 : nsresult
5221 0 : nsFrame::MakeFrameName(const nsAString& aType, nsAString& aResult) const
5222 : {
5223 0 : aResult = aType;
5224 0 : if (mContent && !mContent->IsNodeOfType(nsINode::eTEXT)) {
5225 0 : nsAutoString buf;
5226 0 : mContent->Tag()->ToString(buf);
5227 0 : aResult.Append(NS_LITERAL_STRING("(") + buf + NS_LITERAL_STRING(")"));
5228 : }
5229 : char buf[40];
5230 0 : PR_snprintf(buf, sizeof(buf), "(%d)", ContentIndexInContainer(this));
5231 0 : AppendASCIItoUTF16(buf, aResult);
5232 0 : return NS_OK;
5233 : }
5234 :
5235 : void
5236 0 : nsFrame::XMLQuote(nsString& aString)
5237 : {
5238 0 : PRInt32 i, len = aString.Length();
5239 0 : for (i = 0; i < len; i++) {
5240 0 : PRUnichar ch = aString.CharAt(i);
5241 0 : if (ch == '<') {
5242 0 : nsAutoString tmp(NS_LITERAL_STRING("<"));
5243 0 : aString.Cut(i, 1);
5244 0 : aString.Insert(tmp, i);
5245 0 : len += 3;
5246 0 : i += 3;
5247 : }
5248 0 : else if (ch == '>') {
5249 0 : nsAutoString tmp(NS_LITERAL_STRING(">"));
5250 0 : aString.Cut(i, 1);
5251 0 : aString.Insert(tmp, i);
5252 0 : len += 3;
5253 0 : i += 3;
5254 : }
5255 0 : else if (ch == '\"') {
5256 0 : nsAutoString tmp(NS_LITERAL_STRING("""));
5257 0 : aString.Cut(i, 1);
5258 0 : aString.Insert(tmp, i);
5259 0 : len += 5;
5260 0 : i += 5;
5261 : }
5262 : }
5263 0 : }
5264 : #endif
5265 :
5266 : bool
5267 0 : nsIFrame::IsVisibleForPainting(nsDisplayListBuilder* aBuilder) {
5268 0 : if (!GetStyleVisibility()->IsVisible())
5269 0 : return false;
5270 0 : nsISelection* sel = aBuilder->GetBoundingSelection();
5271 0 : return !sel || IsVisibleInSelection(sel);
5272 : }
5273 :
5274 : bool
5275 0 : nsIFrame::IsVisibleForPainting() {
5276 0 : if (!GetStyleVisibility()->IsVisible())
5277 0 : return false;
5278 :
5279 0 : nsPresContext* pc = PresContext();
5280 0 : if (!pc->IsRenderingOnlySelection())
5281 0 : return true;
5282 :
5283 0 : nsCOMPtr<nsISelectionController> selcon(do_QueryInterface(pc->PresShell()));
5284 0 : if (selcon) {
5285 0 : nsCOMPtr<nsISelection> sel;
5286 0 : selcon->GetSelection(nsISelectionController::SELECTION_NORMAL,
5287 0 : getter_AddRefs(sel));
5288 0 : if (sel)
5289 0 : return IsVisibleInSelection(sel);
5290 : }
5291 0 : return true;
5292 : }
5293 :
5294 : bool
5295 0 : nsIFrame::IsVisibleInSelection(nsDisplayListBuilder* aBuilder) {
5296 0 : nsISelection* sel = aBuilder->GetBoundingSelection();
5297 0 : return !sel || IsVisibleInSelection(sel);
5298 : }
5299 :
5300 : bool
5301 0 : nsIFrame::IsVisibleOrCollapsedForPainting(nsDisplayListBuilder* aBuilder) {
5302 0 : if (!GetStyleVisibility()->IsVisibleOrCollapsed())
5303 0 : return false;
5304 0 : nsISelection* sel = aBuilder->GetBoundingSelection();
5305 0 : return !sel || IsVisibleInSelection(sel);
5306 : }
5307 :
5308 : bool
5309 0 : nsIFrame::IsVisibleInSelection(nsISelection* aSelection)
5310 : {
5311 0 : if (!GetContent() || !GetContent()->IsSelectionDescendant()) {
5312 0 : return false;
5313 : }
5314 :
5315 0 : nsCOMPtr<nsIDOMNode> node(do_QueryInterface(mContent));
5316 : bool vis;
5317 0 : nsresult rv = aSelection->ContainsNode(node, true, &vis);
5318 0 : return NS_FAILED(rv) || vis;
5319 : }
5320 :
5321 : /* virtual */ bool
5322 0 : nsFrame::IsEmpty()
5323 : {
5324 0 : return false;
5325 : }
5326 :
5327 : bool
5328 0 : nsIFrame::CachedIsEmpty()
5329 : {
5330 0 : NS_PRECONDITION(!(GetStateBits() & NS_FRAME_IS_DIRTY),
5331 : "Must only be called on reflowed lines");
5332 0 : return IsEmpty();
5333 : }
5334 :
5335 : /* virtual */ bool
5336 0 : nsFrame::IsSelfEmpty()
5337 : {
5338 0 : return false;
5339 : }
5340 :
5341 : NS_IMETHODIMP
5342 0 : nsFrame::GetSelectionController(nsPresContext *aPresContext, nsISelectionController **aSelCon)
5343 : {
5344 0 : if (!aPresContext || !aSelCon)
5345 0 : return NS_ERROR_INVALID_ARG;
5346 :
5347 0 : nsIFrame *frame = this;
5348 0 : while (frame && (frame->GetStateBits() & NS_FRAME_INDEPENDENT_SELECTION)) {
5349 0 : nsITextControlFrame *tcf = do_QueryFrame(frame);
5350 0 : if (tcf) {
5351 0 : return tcf->GetOwnedSelectionController(aSelCon);
5352 : }
5353 0 : frame = frame->GetParent();
5354 : }
5355 :
5356 0 : return CallQueryInterface(aPresContext->GetPresShell(), aSelCon);
5357 : }
5358 :
5359 : already_AddRefed<nsFrameSelection>
5360 0 : nsIFrame::GetFrameSelection()
5361 : {
5362 : nsFrameSelection* fs =
5363 0 : const_cast<nsFrameSelection*>(GetConstFrameSelection());
5364 0 : NS_IF_ADDREF(fs);
5365 0 : return fs;
5366 : }
5367 :
5368 : const nsFrameSelection*
5369 0 : nsIFrame::GetConstFrameSelection() const
5370 : {
5371 0 : nsIFrame* frame = const_cast<nsIFrame*>(this);
5372 0 : while (frame && (frame->GetStateBits() & NS_FRAME_INDEPENDENT_SELECTION)) {
5373 0 : nsITextControlFrame* tcf = do_QueryFrame(frame);
5374 0 : if (tcf) {
5375 0 : return tcf->GetOwnedFrameSelection();
5376 : }
5377 0 : frame = frame->GetParent();
5378 : }
5379 :
5380 0 : return PresContext()->PresShell()->ConstFrameSelection();
5381 : }
5382 :
5383 : #ifdef NS_DEBUG
5384 : NS_IMETHODIMP
5385 0 : nsFrame::DumpRegressionData(nsPresContext* aPresContext, FILE* out, PRInt32 aIndent)
5386 : {
5387 0 : IndentBy(out, aIndent);
5388 0 : fprintf(out, "<frame va=\"%ld\" type=\"", PRUptrdiff(this));
5389 0 : nsAutoString name;
5390 0 : GetFrameName(name);
5391 0 : XMLQuote(name);
5392 0 : fputs(NS_LossyConvertUTF16toASCII(name).get(), out);
5393 : fprintf(out, "\" state=\"%016llx\" parent=\"%ld\">\n",
5394 0 : (unsigned long long)GetDebugStateBits(), PRUptrdiff(mParent));
5395 :
5396 0 : aIndent++;
5397 0 : DumpBaseRegressionData(aPresContext, out, aIndent);
5398 0 : aIndent--;
5399 :
5400 0 : IndentBy(out, aIndent);
5401 0 : fprintf(out, "</frame>\n");
5402 :
5403 0 : return NS_OK;
5404 : }
5405 :
5406 : void
5407 0 : nsFrame::DumpBaseRegressionData(nsPresContext* aPresContext, FILE* out, PRInt32 aIndent)
5408 : {
5409 0 : if (GetNextSibling()) {
5410 0 : IndentBy(out, aIndent);
5411 0 : fprintf(out, "<next-sibling va=\"%ld\"/>\n", PRUptrdiff(GetNextSibling()));
5412 : }
5413 :
5414 0 : if (HasView()) {
5415 0 : IndentBy(out, aIndent);
5416 0 : fprintf(out, "<view va=\"%ld\">\n", PRUptrdiff(GetView()));
5417 0 : aIndent++;
5418 : // XXX add in code to dump out view state too...
5419 0 : aIndent--;
5420 0 : IndentBy(out, aIndent);
5421 0 : fprintf(out, "</view>\n");
5422 : }
5423 :
5424 0 : IndentBy(out, aIndent);
5425 : fprintf(out, "<bbox x=\"%d\" y=\"%d\" w=\"%d\" h=\"%d\"/>\n",
5426 0 : mRect.x, mRect.y, mRect.width, mRect.height);
5427 :
5428 : // Now dump all of the children on all of the child lists
5429 0 : ChildListIterator lists(this);
5430 0 : for (; !lists.IsDone(); lists.Next()) {
5431 0 : IndentBy(out, aIndent);
5432 0 : if (lists.CurrentID() != kPrincipalList) {
5433 0 : fprintf(out, "<child-list name=\"%s\">\n", mozilla::layout::ChildListName(lists.CurrentID()));
5434 : }
5435 : else {
5436 0 : fprintf(out, "<child-list>\n");
5437 : }
5438 0 : aIndent++;
5439 0 : nsFrameList::Enumerator childFrames(lists.CurrentList());
5440 0 : for (; !childFrames.AtEnd(); childFrames.Next()) {
5441 0 : nsIFrame* kid = childFrames.get();
5442 0 : kid->DumpRegressionData(aPresContext, out, aIndent);
5443 : }
5444 0 : aIndent--;
5445 0 : IndentBy(out, aIndent);
5446 0 : fprintf(out, "</child-list>\n");
5447 : }
5448 0 : }
5449 : #endif
5450 :
5451 : bool
5452 0 : nsIFrame::IsFrameSelected() const
5453 : {
5454 0 : NS_ASSERTION(!GetContent() || GetContent()->IsSelectionDescendant(),
5455 : "use the public IsSelected() instead");
5456 0 : return nsRange::IsNodeSelected(GetContent(), 0,
5457 0 : GetContent()->GetChildCount());
5458 : }
5459 :
5460 : NS_IMETHODIMP
5461 0 : nsFrame::GetPointFromOffset(PRInt32 inOffset, nsPoint* outPoint)
5462 : {
5463 0 : NS_PRECONDITION(outPoint != nsnull, "Null parameter");
5464 0 : nsRect contentRect = GetContentRect() - GetPosition();
5465 0 : nsPoint pt = contentRect.TopLeft();
5466 0 : if (mContent)
5467 : {
5468 0 : nsIContent* newContent = mContent->GetParent();
5469 0 : if (newContent){
5470 0 : PRInt32 newOffset = newContent->IndexOf(mContent);
5471 :
5472 0 : bool isRTL = (NS_GET_EMBEDDING_LEVEL(this) & 1) == 1;
5473 0 : if ((!isRTL && inOffset > newOffset) ||
5474 : (isRTL && inOffset <= newOffset)) {
5475 0 : pt = contentRect.TopRight();
5476 : }
5477 : }
5478 : }
5479 0 : *outPoint = pt;
5480 0 : return NS_OK;
5481 : }
5482 :
5483 : NS_IMETHODIMP
5484 0 : nsFrame::GetChildFrameContainingOffset(PRInt32 inContentOffset, bool inHint, PRInt32* outFrameContentOffset, nsIFrame **outChildFrame)
5485 : {
5486 0 : NS_PRECONDITION(outChildFrame && outFrameContentOffset, "Null parameter");
5487 0 : *outFrameContentOffset = (PRInt32)inHint;
5488 : //the best frame to reflect any given offset would be a visible frame if possible
5489 : //i.e. we are looking for a valid frame to place the blinking caret
5490 0 : nsRect rect = GetRect();
5491 0 : if (!rect.width || !rect.height)
5492 : {
5493 : //if we have a 0 width or height then lets look for another frame that possibly has
5494 : //the same content. If we have no frames in flow then just let us return 'this' frame
5495 0 : nsIFrame* nextFlow = GetNextInFlow();
5496 0 : if (nextFlow)
5497 0 : return nextFlow->GetChildFrameContainingOffset(inContentOffset, inHint, outFrameContentOffset, outChildFrame);
5498 : }
5499 0 : *outChildFrame = this;
5500 0 : return NS_OK;
5501 : }
5502 :
5503 : //
5504 : // What I've pieced together about this routine:
5505 : // Starting with a block frame (from which a line frame can be gotten)
5506 : // and a line number, drill down and get the first/last selectable
5507 : // frame on that line, depending on aPos->mDirection.
5508 : // aOutSideLimit != 0 means ignore aLineStart, instead work from
5509 : // the end (if > 0) or beginning (if < 0).
5510 : //
5511 : nsresult
5512 0 : nsFrame::GetNextPrevLineFromeBlockFrame(nsPresContext* aPresContext,
5513 : nsPeekOffsetStruct *aPos,
5514 : nsIFrame *aBlockFrame,
5515 : PRInt32 aLineStart,
5516 : PRInt8 aOutSideLimit
5517 : )
5518 : {
5519 : //magic numbers aLineStart will be -1 for end of block 0 will be start of block
5520 0 : if (!aBlockFrame || !aPos)
5521 0 : return NS_ERROR_NULL_POINTER;
5522 :
5523 0 : aPos->mResultFrame = nsnull;
5524 0 : aPos->mResultContent = nsnull;
5525 0 : aPos->mAttachForward = (aPos->mDirection == eDirNext);
5526 :
5527 0 : nsAutoLineIterator it = aBlockFrame->GetLineIterator();
5528 0 : if (!it)
5529 0 : return NS_ERROR_FAILURE;
5530 0 : PRInt32 searchingLine = aLineStart;
5531 0 : PRInt32 countLines = it->GetNumLines();
5532 0 : if (aOutSideLimit > 0) //start at end
5533 0 : searchingLine = countLines;
5534 0 : else if (aOutSideLimit <0)//start at beginning
5535 0 : searchingLine = -1;//"next" will be 0
5536 : else
5537 0 : if ((aPos->mDirection == eDirPrevious && searchingLine == 0) ||
5538 : (aPos->mDirection == eDirNext && searchingLine >= (countLines -1) )){
5539 : //we need to jump to new block frame.
5540 0 : return NS_ERROR_FAILURE;
5541 : }
5542 : PRInt32 lineFrameCount;
5543 0 : nsIFrame *resultFrame = nsnull;
5544 0 : nsIFrame *farStoppingFrame = nsnull; //we keep searching until we find a "this" frame then we go to next line
5545 0 : nsIFrame *nearStoppingFrame = nsnull; //if we are backing up from edge, stop here
5546 : nsIFrame *firstFrame;
5547 : nsIFrame *lastFrame;
5548 0 : nsRect rect;
5549 : bool isBeforeFirstFrame, isAfterLastFrame;
5550 0 : bool found = false;
5551 :
5552 0 : nsresult result = NS_OK;
5553 0 : while (!found)
5554 : {
5555 0 : if (aPos->mDirection == eDirPrevious)
5556 0 : searchingLine --;
5557 : else
5558 0 : searchingLine ++;
5559 0 : if ((aPos->mDirection == eDirPrevious && searchingLine < 0) ||
5560 : (aPos->mDirection == eDirNext && searchingLine >= countLines ))
5561 : {
5562 : //we need to jump to new block frame.
5563 0 : return NS_ERROR_FAILURE;
5564 : }
5565 : PRUint32 lineFlags;
5566 0 : result = it->GetLine(searchingLine, &firstFrame, &lineFrameCount,
5567 0 : rect, &lineFlags);
5568 0 : if (!lineFrameCount)
5569 0 : continue;
5570 0 : if (NS_SUCCEEDED(result)){
5571 0 : lastFrame = firstFrame;
5572 0 : for (;lineFrameCount > 1;lineFrameCount --){
5573 : //result = lastFrame->GetNextSibling(&lastFrame, searchingLine);
5574 0 : result = it->GetNextSiblingOnLine(lastFrame, searchingLine);
5575 0 : if (NS_FAILED(result) || !lastFrame){
5576 0 : NS_ERROR("GetLine promised more frames than could be found");
5577 0 : return NS_ERROR_FAILURE;
5578 : }
5579 : }
5580 0 : GetLastLeaf(aPresContext, &lastFrame);
5581 :
5582 0 : if (aPos->mDirection == eDirNext){
5583 0 : nearStoppingFrame = firstFrame;
5584 0 : farStoppingFrame = lastFrame;
5585 : }
5586 : else{
5587 0 : nearStoppingFrame = lastFrame;
5588 0 : farStoppingFrame = firstFrame;
5589 : }
5590 0 : nsPoint offset;
5591 : nsIView * view; //used for call of get offset from view
5592 0 : aBlockFrame->GetOffsetFromView(offset,&view);
5593 0 : nscoord newDesiredX = aPos->mDesiredX - offset.x;//get desired x into blockframe coordinates!
5594 0 : result = it->FindFrameAt(searchingLine, newDesiredX, &resultFrame, &isBeforeFirstFrame, &isAfterLastFrame);
5595 0 : if(NS_FAILED(result))
5596 0 : continue;
5597 : }
5598 :
5599 0 : if (NS_SUCCEEDED(result) && resultFrame)
5600 : {
5601 : //check to see if this is ANOTHER blockframe inside the other one if so then call into its lines
5602 0 : nsAutoLineIterator newIt = resultFrame->GetLineIterator();
5603 0 : if (newIt)
5604 : {
5605 0 : aPos->mResultFrame = resultFrame;
5606 0 : return NS_OK;
5607 : }
5608 : //resultFrame is not a block frame
5609 0 : result = NS_ERROR_FAILURE;
5610 :
5611 0 : nsCOMPtr<nsIFrameEnumerator> frameTraversal;
5612 0 : result = NS_NewFrameTraversal(getter_AddRefs(frameTraversal),
5613 : aPresContext, resultFrame,
5614 : ePostOrder,
5615 : false, // aVisual
5616 : aPos->mScrollViewStop,
5617 : false // aFollowOOFs
5618 0 : );
5619 0 : if (NS_FAILED(result))
5620 0 : return result;
5621 0 : nsIFrame *storeOldResultFrame = resultFrame;
5622 0 : while ( !found ){
5623 0 : nsPoint point;
5624 0 : point.x = aPos->mDesiredX;
5625 :
5626 0 : nsRect tempRect = resultFrame->GetRect();
5627 0 : nsPoint offset;
5628 : nsIView * view; //used for call of get offset from view
5629 0 : result = resultFrame->GetOffsetFromView(offset, &view);
5630 0 : if (NS_FAILED(result))
5631 0 : return result;
5632 0 : point.y = tempRect.height + offset.y;
5633 :
5634 : //special check. if we allow non-text selection then we can allow a hit location to fall before a table.
5635 : //otherwise there is no way to get and click signal to fall before a table (it being a line iterator itself)
5636 0 : nsIPresShell *shell = aPresContext->GetPresShell();
5637 0 : if (!shell)
5638 0 : return NS_ERROR_FAILURE;
5639 0 : PRInt16 isEditor = shell->GetSelectionFlags();
5640 0 : isEditor = isEditor == nsISelectionDisplay::DISPLAY_ALL;
5641 0 : if ( isEditor )
5642 : {
5643 0 : if (resultFrame->GetType() == nsGkAtoms::tableOuterFrame)
5644 : {
5645 0 : if (((point.x - offset.x + tempRect.x)<0) || ((point.x - offset.x+ tempRect.x)>tempRect.width))//off left/right side
5646 : {
5647 0 : nsIContent* content = resultFrame->GetContent();
5648 0 : if (content)
5649 : {
5650 0 : nsIContent* parent = content->GetParent();
5651 0 : if (parent)
5652 : {
5653 0 : aPos->mResultContent = parent;
5654 0 : aPos->mContentOffset = parent->IndexOf(content);
5655 0 : aPos->mAttachForward = false;
5656 0 : if ((point.x - offset.x+ tempRect.x)>tempRect.width)
5657 : {
5658 0 : aPos->mContentOffset++;//go to end of this frame
5659 0 : aPos->mAttachForward = true;
5660 : }
5661 : //result frame is the result frames parent.
5662 0 : aPos->mResultFrame = resultFrame->GetParent();
5663 0 : return NS_POSITION_BEFORE_TABLE;
5664 : }
5665 : }
5666 : }
5667 : }
5668 : }
5669 :
5670 0 : if (!resultFrame->HasView())
5671 : {
5672 : nsIView* view;
5673 0 : nsPoint offset;
5674 0 : resultFrame->GetOffsetFromView(offset, &view);
5675 : ContentOffsets offsets =
5676 0 : resultFrame->GetContentOffsetsFromPoint(point - offset);
5677 0 : aPos->mResultContent = offsets.content;
5678 0 : aPos->mContentOffset = offsets.offset;
5679 0 : aPos->mAttachForward = offsets.associateWithNext;
5680 0 : if (offsets.content)
5681 : {
5682 : bool selectable;
5683 0 : resultFrame->IsSelectable(&selectable, nsnull);
5684 0 : if (selectable)
5685 : {
5686 0 : found = true;
5687 : break;
5688 : }
5689 : }
5690 : }
5691 :
5692 0 : if (aPos->mDirection == eDirPrevious && (resultFrame == farStoppingFrame))
5693 : break;
5694 0 : if (aPos->mDirection == eDirNext && (resultFrame == nearStoppingFrame))
5695 : break;
5696 : //always try previous on THAT line if that fails go the other way
5697 0 : frameTraversal->Prev();
5698 0 : resultFrame = frameTraversal->CurrentItem();
5699 0 : if (!resultFrame)
5700 0 : return NS_ERROR_FAILURE;
5701 : }
5702 :
5703 0 : if (!found){
5704 0 : resultFrame = storeOldResultFrame;
5705 0 : result = NS_NewFrameTraversal(getter_AddRefs(frameTraversal),
5706 : aPresContext, resultFrame,
5707 : eLeaf,
5708 : false, // aVisual
5709 : aPos->mScrollViewStop,
5710 : false // aFollowOOFs
5711 0 : );
5712 : }
5713 0 : while ( !found ){
5714 0 : nsPoint point(aPos->mDesiredX, 0);
5715 : nsIView* view;
5716 0 : nsPoint offset;
5717 0 : resultFrame->GetOffsetFromView(offset, &view);
5718 : ContentOffsets offsets =
5719 0 : resultFrame->GetContentOffsetsFromPoint(point - offset);
5720 0 : aPos->mResultContent = offsets.content;
5721 0 : aPos->mContentOffset = offsets.offset;
5722 0 : aPos->mAttachForward = offsets.associateWithNext;
5723 0 : if (offsets.content)
5724 : {
5725 : bool selectable;
5726 0 : resultFrame->IsSelectable(&selectable, nsnull);
5727 0 : if (selectable)
5728 : {
5729 0 : found = true;
5730 0 : if (resultFrame == farStoppingFrame)
5731 0 : aPos->mAttachForward = false;
5732 : else
5733 0 : aPos->mAttachForward = true;
5734 : break;
5735 : }
5736 : }
5737 0 : if (aPos->mDirection == eDirPrevious && (resultFrame == nearStoppingFrame))
5738 : break;
5739 0 : if (aPos->mDirection == eDirNext && (resultFrame == farStoppingFrame))
5740 : break;
5741 : //previous didnt work now we try "next"
5742 0 : frameTraversal->Next();
5743 0 : nsIFrame *tempFrame = frameTraversal->CurrentItem();
5744 0 : if (!tempFrame)
5745 : break;
5746 0 : resultFrame = tempFrame;
5747 : }
5748 0 : aPos->mResultFrame = resultFrame;
5749 : }
5750 : else {
5751 : //we need to jump to new block frame.
5752 0 : aPos->mAmount = eSelectLine;
5753 0 : aPos->mStartOffset = 0;
5754 0 : aPos->mAttachForward = !(aPos->mDirection == eDirNext);
5755 0 : if (aPos->mDirection == eDirPrevious)
5756 0 : aPos->mStartOffset = -1;//start from end
5757 0 : return aBlockFrame->PeekOffset(aPos);
5758 : }
5759 : }
5760 0 : return NS_OK;
5761 : }
5762 :
5763 0 : nsPeekOffsetStruct nsIFrame::GetExtremeCaretPosition(bool aStart)
5764 : {
5765 0 : nsPeekOffsetStruct result;
5766 :
5767 0 : FrameTarget targetFrame = DrillDownToSelectionFrame(this, !aStart);
5768 0 : FrameContentRange range = GetRangeForFrame(targetFrame.frame);
5769 0 : result.mResultContent = range.content;
5770 0 : result.mContentOffset = aStart ? range.start : range.end;
5771 0 : result.mAttachForward = (result.mContentOffset == range.start);
5772 : return result;
5773 : }
5774 :
5775 : // Find the first (or last) descendant of the given frame
5776 : // which is either a block frame or a BRFrame.
5777 : static nsContentAndOffset
5778 0 : FindBlockFrameOrBR(nsIFrame* aFrame, nsDirection aDirection)
5779 : {
5780 : nsContentAndOffset result;
5781 0 : result.mContent = nsnull;
5782 0 : result.mOffset = 0;
5783 :
5784 0 : if (aFrame->IsGeneratedContentFrame())
5785 0 : return result;
5786 :
5787 : // Treat form controls as inline leaves
5788 : // XXX we really need a way to determine whether a frame is inline-level
5789 0 : nsIFormControlFrame* fcf = do_QueryFrame(aFrame);
5790 0 : if (fcf)
5791 0 : return result;
5792 :
5793 : // Check the frame itself
5794 : // Fall through "special" block frames because their mContent is the content
5795 : // of the inline frames they were created from. The first/last child of
5796 : // such frames is the real block frame we're looking for.
5797 0 : if ((nsLayoutUtils::GetAsBlock(aFrame) && !(aFrame->GetStateBits() & NS_FRAME_IS_SPECIAL)) ||
5798 0 : aFrame->GetType() == nsGkAtoms::brFrame) {
5799 0 : nsIContent* content = aFrame->GetContent();
5800 0 : result.mContent = content->GetParent();
5801 : // In some cases (bug 310589, bug 370174) we end up here with a null content.
5802 : // This probably shouldn't ever happen, but since it sometimes does, we want
5803 : // to avoid crashing here.
5804 0 : NS_ASSERTION(result.mContent, "Unexpected orphan content");
5805 0 : if (result.mContent)
5806 0 : result.mOffset = result.mContent->IndexOf(content) +
5807 0 : (aDirection == eDirPrevious ? 1 : 0);
5808 0 : return result;
5809 : }
5810 :
5811 : // If this is a preformatted text frame, see if it ends with a newline
5812 0 : if (aFrame->HasTerminalNewline() &&
5813 0 : aFrame->GetStyleContext()->GetStyleText()->NewlineIsSignificant()) {
5814 : PRInt32 startOffset, endOffset;
5815 0 : aFrame->GetOffsets(startOffset, endOffset);
5816 0 : result.mContent = aFrame->GetContent();
5817 0 : result.mOffset = endOffset - (aDirection == eDirPrevious ? 0 : 1);
5818 0 : return result;
5819 : }
5820 :
5821 : // Iterate over children and call ourselves recursively
5822 0 : if (aDirection == eDirPrevious) {
5823 0 : nsIFrame* child = aFrame->GetLastChild(nsIFrame::kPrincipalList);
5824 0 : while(child && !result.mContent) {
5825 0 : result = FindBlockFrameOrBR(child, aDirection);
5826 0 : child = child->GetPrevSibling();
5827 : }
5828 : } else { // eDirNext
5829 0 : nsIFrame* child = aFrame->GetFirstPrincipalChild();
5830 0 : while(child && !result.mContent) {
5831 0 : result = FindBlockFrameOrBR(child, aDirection);
5832 0 : child = child->GetNextSibling();
5833 : }
5834 : }
5835 0 : return result;
5836 : }
5837 :
5838 : nsresult
5839 0 : nsIFrame::PeekOffsetParagraph(nsPeekOffsetStruct *aPos)
5840 : {
5841 0 : nsIFrame* frame = this;
5842 : nsContentAndOffset blockFrameOrBR;
5843 0 : blockFrameOrBR.mContent = nsnull;
5844 0 : bool reachedBlockAncestor = false;
5845 :
5846 : // Go through containing frames until reaching a block frame.
5847 : // In each step, search the previous (or next) siblings for the closest
5848 : // "stop frame" (a block frame or a BRFrame).
5849 : // If found, set it to be the selection boundray and abort.
5850 :
5851 0 : if (aPos->mDirection == eDirPrevious) {
5852 0 : while (!reachedBlockAncestor) {
5853 0 : nsIFrame* parent = frame->GetParent();
5854 : // Treat a frame associated with the root content as if it were a block frame.
5855 0 : if (!frame->mContent || !frame->mContent->GetParent()) {
5856 0 : reachedBlockAncestor = true;
5857 0 : break;
5858 : }
5859 0 : nsIFrame* sibling = frame->GetPrevSibling();
5860 0 : while (sibling && !blockFrameOrBR.mContent) {
5861 0 : blockFrameOrBR = FindBlockFrameOrBR(sibling, eDirPrevious);
5862 0 : sibling = sibling->GetPrevSibling();
5863 : }
5864 0 : if (blockFrameOrBR.mContent) {
5865 0 : aPos->mResultContent = blockFrameOrBR.mContent;
5866 0 : aPos->mContentOffset = blockFrameOrBR.mOffset;
5867 0 : break;
5868 : }
5869 0 : frame = parent;
5870 0 : reachedBlockAncestor = (nsLayoutUtils::GetAsBlock(frame) != nsnull);
5871 : }
5872 0 : if (reachedBlockAncestor) { // no "stop frame" found
5873 0 : aPos->mResultContent = frame->GetContent();
5874 0 : aPos->mContentOffset = 0;
5875 : }
5876 : } else { // eDirNext
5877 0 : while (!reachedBlockAncestor) {
5878 0 : nsIFrame* parent = frame->GetParent();
5879 : // Treat a frame associated with the root content as if it were a block frame.
5880 0 : if (!frame->mContent || !frame->mContent->GetParent()) {
5881 0 : reachedBlockAncestor = true;
5882 0 : break;
5883 : }
5884 0 : nsIFrame* sibling = frame;
5885 0 : while (sibling && !blockFrameOrBR.mContent) {
5886 0 : blockFrameOrBR = FindBlockFrameOrBR(sibling, eDirNext);
5887 0 : sibling = sibling->GetNextSibling();
5888 : }
5889 0 : if (blockFrameOrBR.mContent) {
5890 0 : aPos->mResultContent = blockFrameOrBR.mContent;
5891 0 : aPos->mContentOffset = blockFrameOrBR.mOffset;
5892 0 : break;
5893 : }
5894 0 : frame = parent;
5895 0 : reachedBlockAncestor = (nsLayoutUtils::GetAsBlock(frame) != nsnull);
5896 : }
5897 0 : if (reachedBlockAncestor) { // no "stop frame" found
5898 0 : aPos->mResultContent = frame->GetContent();
5899 0 : if (aPos->mResultContent)
5900 0 : aPos->mContentOffset = aPos->mResultContent->GetChildCount();
5901 : }
5902 : }
5903 0 : return NS_OK;
5904 : }
5905 :
5906 : // Determine movement direction relative to frame
5907 0 : static bool IsMovingInFrameDirection(nsIFrame* frame, nsDirection aDirection, bool aVisual)
5908 : {
5909 : bool isReverseDirection = aVisual ?
5910 0 : (NS_GET_EMBEDDING_LEVEL(frame) & 1) != (NS_GET_BASE_LEVEL(frame) & 1) : false;
5911 0 : return aDirection == (isReverseDirection ? eDirPrevious : eDirNext);
5912 : }
5913 :
5914 : NS_IMETHODIMP
5915 0 : nsIFrame::PeekOffset(nsPeekOffsetStruct* aPos)
5916 : {
5917 0 : if (!aPos)
5918 0 : return NS_ERROR_NULL_POINTER;
5919 0 : nsresult result = NS_ERROR_FAILURE;
5920 :
5921 0 : if (mState & NS_FRAME_IS_DIRTY)
5922 0 : return NS_ERROR_UNEXPECTED;
5923 :
5924 : // Translate content offset to be relative to frame
5925 0 : FrameContentRange range = GetRangeForFrame(this);
5926 0 : PRInt32 offset = aPos->mStartOffset - range.start;
5927 0 : nsIFrame* current = this;
5928 :
5929 0 : switch (aPos->mAmount) {
5930 : case eSelectCharacter:
5931 : case eSelectCluster:
5932 : {
5933 0 : bool eatingNonRenderableWS = false;
5934 0 : bool done = false;
5935 0 : bool jumpedLine = false;
5936 :
5937 0 : while (!done) {
5938 : bool movingInFrameDirection =
5939 0 : IsMovingInFrameDirection(current, aPos->mDirection, aPos->mVisual);
5940 :
5941 0 : if (eatingNonRenderableWS)
5942 0 : done = current->PeekOffsetNoAmount(movingInFrameDirection, &offset);
5943 : else
5944 : done = current->PeekOffsetCharacter(movingInFrameDirection, &offset,
5945 0 : aPos->mAmount == eSelectCluster);
5946 :
5947 0 : if (!done) {
5948 : result =
5949 : current->GetFrameFromDirection(aPos->mDirection, aPos->mVisual,
5950 : aPos->mJumpLines, aPos->mScrollViewStop,
5951 0 : ¤t, &offset, &jumpedLine);
5952 0 : if (NS_FAILED(result))
5953 0 : return result;
5954 :
5955 : // If we jumped lines, it's as if we found a character, but we still need
5956 : // to eat non-renderable content on the new line.
5957 0 : if (jumpedLine)
5958 0 : eatingNonRenderableWS = true;
5959 : }
5960 : }
5961 :
5962 : // Set outputs
5963 0 : range = GetRangeForFrame(current);
5964 0 : aPos->mResultFrame = current;
5965 0 : aPos->mResultContent = range.content;
5966 : // Output offset is relative to content, not frame
5967 0 : aPos->mContentOffset = offset < 0 ? range.end : range.start + offset;
5968 : // If we're dealing with a text frame and moving backward positions us at
5969 : // the end of that line, decrease the offset by one to make sure that
5970 : // we're placed before the linefeed character on the previous line.
5971 0 : if (offset < 0 && jumpedLine &&
5972 : aPos->mDirection == eDirPrevious &&
5973 0 : current->GetStyleText()->NewlineIsSignificant() &&
5974 0 : current->HasTerminalNewline()) {
5975 0 : --aPos->mContentOffset;
5976 : }
5977 :
5978 0 : break;
5979 : }
5980 : case eSelectWordNoSpace:
5981 : // eSelectWordNoSpace means that we should not be eating any whitespace when
5982 : // moving to the adjacent word. This means that we should set aPos->
5983 : // mWordMovementType to eEndWord if we're moving forwards, and to eStartWord
5984 : // if we're moving backwards.
5985 0 : if (aPos->mDirection == eDirPrevious) {
5986 0 : aPos->mWordMovementType = eStartWord;
5987 : } else {
5988 0 : aPos->mWordMovementType = eEndWord;
5989 : }
5990 : // Intentionally fall through the eSelectWord case.
5991 : case eSelectWord:
5992 : {
5993 : // wordSelectEatSpace means "are we looking for a boundary between whitespace
5994 : // and non-whitespace (in the direction we're moving in)".
5995 : // It is true when moving forward and looking for a beginning of a word, or
5996 : // when moving backwards and looking for an end of a word.
5997 : bool wordSelectEatSpace;
5998 0 : if (aPos->mWordMovementType != eDefaultBehavior) {
5999 : // aPos->mWordMovementType possible values:
6000 : // eEndWord: eat the space if we're moving backwards
6001 : // eStartWord: eat the space if we're moving forwards
6002 0 : wordSelectEatSpace = ((aPos->mWordMovementType == eEndWord) == (aPos->mDirection == eDirPrevious));
6003 : }
6004 : else {
6005 : // Use the hidden preference which is based on operating system behavior.
6006 : // This pref only affects whether moving forward by word should go to the end of this word or start of the next word.
6007 : // When going backwards, the start of the word is always used, on every operating system.
6008 : wordSelectEatSpace = aPos->mDirection == eDirNext &&
6009 0 : Preferences::GetBool("layout.word_select.eat_space_to_next_word");
6010 : }
6011 :
6012 : // mSawBeforeType means "we already saw characters of the type
6013 : // before the boundary we're looking for". Examples:
6014 : // 1. If we're moving forward, looking for a word beginning (i.e. a boundary
6015 : // between whitespace and non-whitespace), then eatingWS==true means
6016 : // "we already saw some whitespace".
6017 : // 2. If we're moving backward, looking for a word beginning (i.e. a boundary
6018 : // between non-whitespace and whitespace), then eatingWS==true means
6019 : // "we already saw some non-whitespace".
6020 0 : PeekWordState state;
6021 0 : PRInt32 offsetAdjustment = 0;
6022 0 : bool done = false;
6023 0 : while (!done) {
6024 : bool movingInFrameDirection =
6025 0 : IsMovingInFrameDirection(current, aPos->mDirection, aPos->mVisual);
6026 :
6027 : done = current->PeekOffsetWord(movingInFrameDirection, wordSelectEatSpace,
6028 0 : aPos->mIsKeyboardSelect, &offset, &state);
6029 :
6030 0 : if (!done) {
6031 : nsIFrame* nextFrame;
6032 : PRInt32 nextFrameOffset;
6033 : bool jumpedLine;
6034 : result =
6035 : current->GetFrameFromDirection(aPos->mDirection, aPos->mVisual,
6036 : aPos->mJumpLines, aPos->mScrollViewStop,
6037 0 : &nextFrame, &nextFrameOffset, &jumpedLine);
6038 : // We can't jump lines if we're looking for whitespace following
6039 : // non-whitespace, and we already encountered non-whitespace.
6040 0 : if (NS_FAILED(result) ||
6041 0 : (jumpedLine && !wordSelectEatSpace && state.mSawBeforeType)) {
6042 0 : done = true;
6043 : // If we've crossed the line boundary, check to make sure that we
6044 : // have not consumed a trailing newline as whitesapce if it's significant.
6045 0 : if (jumpedLine && wordSelectEatSpace &&
6046 0 : current->HasTerminalNewline() &&
6047 0 : current->GetStyleText()->NewlineIsSignificant()) {
6048 0 : offsetAdjustment = -1;
6049 : }
6050 : } else {
6051 0 : if (jumpedLine) {
6052 0 : state.mContext.Truncate();
6053 : }
6054 0 : current = nextFrame;
6055 0 : offset = nextFrameOffset;
6056 : // Jumping a line is equivalent to encountering whitespace
6057 0 : if (wordSelectEatSpace && jumpedLine)
6058 0 : state.SetSawBeforeType();
6059 : }
6060 : }
6061 : }
6062 :
6063 : // Set outputs
6064 0 : range = GetRangeForFrame(current);
6065 0 : aPos->mResultFrame = current;
6066 0 : aPos->mResultContent = range.content;
6067 : // Output offset is relative to content, not frame
6068 0 : aPos->mContentOffset = (offset < 0 ? range.end : range.start + offset) + offsetAdjustment;
6069 : break;
6070 : }
6071 : case eSelectLine :
6072 : {
6073 0 : nsAutoLineIterator iter;
6074 0 : nsIFrame *blockFrame = this;
6075 :
6076 0 : while (NS_FAILED(result)){
6077 0 : PRInt32 thisLine = nsFrame::GetLineNumber(blockFrame, aPos->mScrollViewStop, &blockFrame);
6078 0 : if (thisLine < 0)
6079 0 : return NS_ERROR_FAILURE;
6080 0 : iter = blockFrame->GetLineIterator();
6081 0 : NS_ASSERTION(iter, "GetLineNumber() succeeded but no block frame?");
6082 0 : result = NS_OK;
6083 :
6084 0 : int edgeCase = 0;//no edge case. this should look at thisLine
6085 :
6086 0 : bool doneLooping = false;//tells us when no more block frames hit.
6087 : //this part will find a frame or a block frame. if it's a block frame
6088 : //it will "drill down" to find a viable frame or it will return an error.
6089 0 : nsIFrame *lastFrame = this;
6090 0 : do {
6091 : result = nsFrame::GetNextPrevLineFromeBlockFrame(PresContext(),
6092 : aPos,
6093 : blockFrame,
6094 : thisLine,
6095 : edgeCase //start from thisLine
6096 0 : );
6097 0 : if (NS_SUCCEEDED(result) && (!aPos->mResultFrame || aPos->mResultFrame == lastFrame))//we came back to same spot! keep going
6098 : {
6099 0 : aPos->mResultFrame = nsnull;
6100 0 : if (aPos->mDirection == eDirPrevious)
6101 0 : thisLine--;
6102 : else
6103 0 : thisLine++;
6104 : }
6105 : else //if failure or success with different frame.
6106 0 : doneLooping = true; //do not continue with while loop
6107 :
6108 0 : lastFrame = aPos->mResultFrame; //set last frame
6109 :
6110 0 : if (NS_SUCCEEDED(result) && aPos->mResultFrame
6111 : && blockFrame != aPos->mResultFrame)// make sure block element is not the same as the one we had before
6112 : {
6113 : /* SPECIAL CHECK FOR TABLE NAVIGATION
6114 : tables need to navigate also and the frame that supports it is nsTableRowGroupFrame which is INSIDE
6115 : nsTableOuterFrame. if we have stumbled onto an nsTableOuter we need to drill into nsTableRowGroup
6116 : if we hit a header or footer that's ok just go into them,
6117 : */
6118 0 : bool searchTableBool = false;
6119 0 : if (aPos->mResultFrame->GetType() == nsGkAtoms::tableOuterFrame ||
6120 0 : aPos->mResultFrame->GetType() == nsGkAtoms::tableCellFrame)
6121 : {
6122 0 : nsIFrame *frame = aPos->mResultFrame->GetFirstPrincipalChild();
6123 : //got the table frame now
6124 0 : while(frame) //ok time to drill down to find iterator
6125 : {
6126 0 : iter = frame->GetLineIterator();
6127 0 : if (iter)
6128 : {
6129 0 : aPos->mResultFrame = frame;
6130 0 : searchTableBool = true;
6131 0 : result = NS_OK;
6132 0 : break; //while(frame)
6133 : }
6134 0 : result = NS_ERROR_FAILURE;
6135 0 : frame = frame->GetFirstPrincipalChild();
6136 : }
6137 : }
6138 :
6139 0 : if (!searchTableBool) {
6140 0 : iter = aPos->mResultFrame->GetLineIterator();
6141 0 : result = iter ? NS_OK : NS_ERROR_FAILURE;
6142 : }
6143 0 : if (NS_SUCCEEDED(result) && iter)//we've struck another block element!
6144 : {
6145 0 : doneLooping = false;
6146 0 : if (aPos->mDirection == eDirPrevious)
6147 0 : edgeCase = 1;//far edge, search from end backwards
6148 : else
6149 0 : edgeCase = -1;//near edge search from beginning onwards
6150 0 : thisLine=0;//this line means nothing now.
6151 : //everything else means something so keep looking "inside" the block
6152 0 : blockFrame = aPos->mResultFrame;
6153 :
6154 : }
6155 : else
6156 : {
6157 0 : result = NS_OK;//THIS is to mean that everything is ok to the containing while loop
6158 0 : break;
6159 : }
6160 : }
6161 0 : } while (!doneLooping);
6162 : }
6163 0 : return result;
6164 : }
6165 :
6166 : case eSelectParagraph:
6167 0 : return PeekOffsetParagraph(aPos);
6168 :
6169 : case eSelectBeginLine:
6170 : case eSelectEndLine:
6171 : {
6172 : // Adjusted so that the caret can't get confused when content changes
6173 0 : nsIFrame* blockFrame = AdjustFrameForSelectionStyles(this);
6174 0 : PRInt32 thisLine = nsFrame::GetLineNumber(blockFrame, aPos->mScrollViewStop, &blockFrame);
6175 0 : if (thisLine < 0)
6176 0 : return NS_ERROR_FAILURE;
6177 0 : nsAutoLineIterator it = blockFrame->GetLineIterator();
6178 0 : NS_ASSERTION(it, "GetLineNumber() succeeded but no block frame?");
6179 :
6180 : PRInt32 lineFrameCount;
6181 : nsIFrame *firstFrame;
6182 0 : nsRect usedRect;
6183 : PRUint32 lineFlags;
6184 0 : nsIFrame* baseFrame = nsnull;
6185 0 : bool endOfLine = (eSelectEndLine == aPos->mAmount);
6186 :
6187 : #ifdef IBMBIDI
6188 0 : if (aPos->mVisual && PresContext()->BidiEnabled()) {
6189 0 : bool lineIsRTL = it->GetDirection();
6190 : bool isReordered;
6191 : nsIFrame *lastFrame;
6192 0 : result = it->CheckLineOrder(thisLine, &isReordered, &firstFrame, &lastFrame);
6193 0 : baseFrame = endOfLine ? lastFrame : firstFrame;
6194 0 : if (baseFrame) {
6195 0 : nsBidiLevel embeddingLevel = nsBidiPresUtils::GetFrameEmbeddingLevel(baseFrame);
6196 : // If the direction of the frame on the edge is opposite to that of the line,
6197 : // we'll need to drill down to its opposite end, so reverse endOfLine.
6198 0 : if ((embeddingLevel & 1) == !lineIsRTL)
6199 0 : endOfLine = !endOfLine;
6200 : }
6201 : } else
6202 : #endif
6203 : {
6204 0 : it->GetLine(thisLine, &firstFrame, &lineFrameCount, usedRect, &lineFlags);
6205 :
6206 0 : nsIFrame* frame = firstFrame;
6207 0 : for (PRInt32 count = lineFrameCount; count;
6208 : --count, frame = frame->GetNextSibling()) {
6209 0 : if (!frame->IsGeneratedContentFrame()) {
6210 0 : baseFrame = frame;
6211 0 : if (!endOfLine)
6212 0 : break;
6213 : }
6214 : }
6215 : }
6216 0 : if (!baseFrame)
6217 0 : return NS_ERROR_FAILURE;
6218 : FrameTarget targetFrame = DrillDownToSelectionFrame(baseFrame,
6219 0 : endOfLine);
6220 0 : FrameContentRange range = GetRangeForFrame(targetFrame.frame);
6221 0 : aPos->mResultContent = range.content;
6222 0 : aPos->mContentOffset = endOfLine ? range.end : range.start;
6223 0 : if (endOfLine && targetFrame.frame->HasTerminalNewline()) {
6224 : // Do not position the caret after the terminating newline if we're
6225 : // trying to move to the end of line (see bug 596506)
6226 0 : --aPos->mContentOffset;
6227 : }
6228 0 : aPos->mResultFrame = targetFrame.frame;
6229 0 : aPos->mAttachForward = (aPos->mContentOffset == range.start);
6230 0 : if (!range.content)
6231 0 : return NS_ERROR_FAILURE;
6232 0 : return NS_OK;
6233 : }
6234 :
6235 : default:
6236 : {
6237 0 : NS_ASSERTION(false, "Invalid amount");
6238 0 : return NS_ERROR_FAILURE;
6239 : }
6240 : }
6241 0 : return NS_OK;
6242 : }
6243 :
6244 : bool
6245 0 : nsFrame::PeekOffsetNoAmount(bool aForward, PRInt32* aOffset)
6246 : {
6247 0 : NS_ASSERTION (aOffset && *aOffset <= 1, "aOffset out of range");
6248 : // Sure, we can stop right here.
6249 0 : return true;
6250 : }
6251 :
6252 : bool
6253 0 : nsFrame::PeekOffsetCharacter(bool aForward, PRInt32* aOffset,
6254 : bool aRespectClusters)
6255 : {
6256 0 : NS_ASSERTION (aOffset && *aOffset <= 1, "aOffset out of range");
6257 0 : PRInt32 startOffset = *aOffset;
6258 : // A negative offset means "end of frame", which in our case means offset 1.
6259 0 : if (startOffset < 0)
6260 0 : startOffset = 1;
6261 0 : if (aForward == (startOffset == 0)) {
6262 : // We're before the frame and moving forward, or after it and moving backwards:
6263 : // skip to the other side and we're done.
6264 0 : *aOffset = 1 - startOffset;
6265 0 : return true;
6266 : }
6267 0 : return false;
6268 : }
6269 :
6270 : bool
6271 0 : nsFrame::PeekOffsetWord(bool aForward, bool aWordSelectEatSpace, bool aIsKeyboardSelect,
6272 : PRInt32* aOffset, PeekWordState* aState)
6273 : {
6274 0 : NS_ASSERTION (aOffset && *aOffset <= 1, "aOffset out of range");
6275 0 : PRInt32 startOffset = *aOffset;
6276 : // This isn't text, so truncate the context
6277 0 : aState->mContext.Truncate();
6278 0 : if (startOffset < 0)
6279 0 : startOffset = 1;
6280 0 : if (aForward == (startOffset == 0)) {
6281 : // We're before the frame and moving forward, or after it and moving backwards.
6282 : // If we're looking for non-whitespace, we found it (without skipping this frame).
6283 0 : if (!aState->mAtStart) {
6284 0 : if (aState->mLastCharWasPunctuation) {
6285 : // We're not punctuation, so this is a punctuation boundary.
6286 0 : if (BreakWordBetweenPunctuation(aState, aForward, false, false, aIsKeyboardSelect))
6287 0 : return true;
6288 : } else {
6289 : // This is not a punctuation boundary.
6290 0 : if (aWordSelectEatSpace && aState->mSawBeforeType)
6291 0 : return true;
6292 : }
6293 : }
6294 : // Otherwise skip to the other side and note that we encountered non-whitespace.
6295 0 : *aOffset = 1 - startOffset;
6296 : aState->Update(false, // not punctuation
6297 : false // not whitespace
6298 0 : );
6299 0 : if (!aWordSelectEatSpace)
6300 0 : aState->SetSawBeforeType();
6301 : }
6302 0 : return false;
6303 : }
6304 :
6305 : bool
6306 0 : nsFrame::BreakWordBetweenPunctuation(const PeekWordState* aState,
6307 : bool aForward,
6308 : bool aPunctAfter, bool aWhitespaceAfter,
6309 : bool aIsKeyboardSelect)
6310 : {
6311 0 : NS_ASSERTION(aPunctAfter != aState->mLastCharWasPunctuation,
6312 : "Call this only at punctuation boundaries");
6313 0 : if (aState->mLastCharWasWhitespace) {
6314 : // We always stop between whitespace and punctuation
6315 0 : return true;
6316 : }
6317 0 : if (!Preferences::GetBool("layout.word_select.stop_at_punctuation")) {
6318 : // When this pref is false, we never stop at a punctuation boundary unless
6319 : // it's after whitespace
6320 0 : return false;
6321 : }
6322 0 : if (!aIsKeyboardSelect) {
6323 : // mouse caret movement (e.g. word selection) always stops at every punctuation boundary
6324 0 : return true;
6325 : }
6326 0 : bool afterPunct = aForward ? aState->mLastCharWasPunctuation : aPunctAfter;
6327 0 : if (!afterPunct) {
6328 : // keyboard caret movement only stops after punctuation (in content order)
6329 0 : return false;
6330 : }
6331 : // Stop only if we've seen some non-punctuation since the last whitespace;
6332 : // don't stop after punctuation that follows whitespace.
6333 0 : return aState->mSeenNonPunctuationSinceWhitespace;
6334 : }
6335 :
6336 : NS_IMETHODIMP
6337 0 : nsFrame::CheckVisibility(nsPresContext* , PRInt32 , PRInt32 , bool , bool *, bool *)
6338 : {
6339 0 : return NS_ERROR_NOT_IMPLEMENTED;
6340 : }
6341 :
6342 :
6343 : PRInt32
6344 0 : nsFrame::GetLineNumber(nsIFrame *aFrame, bool aLockScroll, nsIFrame** aContainingBlock)
6345 : {
6346 0 : NS_ASSERTION(aFrame, "null aFrame");
6347 0 : nsFrameManager* frameManager = aFrame->PresContext()->FrameManager();
6348 0 : nsIFrame *blockFrame = aFrame;
6349 : nsIFrame *thisBlock;
6350 0 : nsAutoLineIterator it;
6351 0 : nsresult result = NS_ERROR_FAILURE;
6352 0 : while (NS_FAILED(result) && blockFrame)
6353 : {
6354 0 : thisBlock = blockFrame;
6355 0 : if (thisBlock->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
6356 : //if we are searching for a frame that is not in flow we will not find it.
6357 : //we must instead look for its placeholder
6358 0 : if (thisBlock->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER) {
6359 : // abspos continuations don't have placeholders, get the fif
6360 0 : thisBlock = thisBlock->GetFirstInFlow();
6361 : }
6362 0 : thisBlock = frameManager->GetPlaceholderFrameFor(thisBlock);
6363 0 : if (!thisBlock)
6364 0 : return -1;
6365 : }
6366 0 : blockFrame = thisBlock->GetParent();
6367 0 : result = NS_OK;
6368 0 : if (blockFrame) {
6369 0 : if (aLockScroll && blockFrame->GetType() == nsGkAtoms::scrollFrame)
6370 0 : return -1;
6371 0 : it = blockFrame->GetLineIterator();
6372 0 : if (!it)
6373 0 : result = NS_ERROR_FAILURE;
6374 : }
6375 : }
6376 0 : if (!blockFrame || !it)
6377 0 : return -1;
6378 :
6379 0 : if (aContainingBlock)
6380 0 : *aContainingBlock = blockFrame;
6381 0 : return it->FindLineContaining(thisBlock);
6382 : }
6383 :
6384 : nsresult
6385 0 : nsIFrame::GetFrameFromDirection(nsDirection aDirection, bool aVisual,
6386 : bool aJumpLines, bool aScrollViewStop,
6387 : nsIFrame** aOutFrame, PRInt32* aOutOffset, bool* aOutJumpedLine)
6388 : {
6389 : nsresult result;
6390 :
6391 0 : if (!aOutFrame || !aOutOffset || !aOutJumpedLine)
6392 0 : return NS_ERROR_NULL_POINTER;
6393 :
6394 0 : nsPresContext* presContext = PresContext();
6395 0 : *aOutFrame = nsnull;
6396 0 : *aOutOffset = 0;
6397 0 : *aOutJumpedLine = false;
6398 :
6399 : // Find the prev/next selectable frame
6400 0 : bool selectable = false;
6401 0 : nsIFrame *traversedFrame = this;
6402 0 : while (!selectable) {
6403 : nsIFrame *blockFrame;
6404 :
6405 0 : PRInt32 thisLine = nsFrame::GetLineNumber(traversedFrame, aScrollViewStop, &blockFrame);
6406 0 : if (thisLine < 0)
6407 0 : return NS_ERROR_FAILURE;
6408 :
6409 0 : nsAutoLineIterator it = blockFrame->GetLineIterator();
6410 0 : NS_ASSERTION(it, "GetLineNumber() succeeded but no block frame?");
6411 :
6412 : bool atLineEdge;
6413 : nsIFrame *firstFrame;
6414 : nsIFrame *lastFrame;
6415 : #ifdef IBMBIDI
6416 0 : if (aVisual && presContext->BidiEnabled()) {
6417 0 : bool lineIsRTL = it->GetDirection();
6418 : bool isReordered;
6419 0 : result = it->CheckLineOrder(thisLine, &isReordered, &firstFrame, &lastFrame);
6420 0 : nsIFrame** framePtr = aDirection == eDirPrevious ? &firstFrame : &lastFrame;
6421 0 : if (*framePtr) {
6422 0 : nsBidiLevel embeddingLevel = nsBidiPresUtils::GetFrameEmbeddingLevel(*framePtr);
6423 0 : if ((((embeddingLevel & 1) && lineIsRTL) || (!(embeddingLevel & 1) && !lineIsRTL)) ==
6424 : (aDirection == eDirPrevious)) {
6425 0 : nsFrame::GetFirstLeaf(presContext, framePtr);
6426 : } else {
6427 0 : nsFrame::GetLastLeaf(presContext, framePtr);
6428 : }
6429 0 : atLineEdge = *framePtr == traversedFrame;
6430 : } else {
6431 0 : atLineEdge = true;
6432 : }
6433 : } else
6434 : #endif
6435 : {
6436 0 : nsRect nonUsedRect;
6437 : PRInt32 lineFrameCount;
6438 : PRUint32 lineFlags;
6439 0 : result = it->GetLine(thisLine, &firstFrame, &lineFrameCount,nonUsedRect,
6440 0 : &lineFlags);
6441 0 : if (NS_FAILED(result))
6442 0 : return result;
6443 :
6444 0 : if (aDirection == eDirPrevious) {
6445 0 : nsFrame::GetFirstLeaf(presContext, &firstFrame);
6446 0 : atLineEdge = firstFrame == traversedFrame;
6447 : } else { // eDirNext
6448 0 : lastFrame = firstFrame;
6449 0 : for (;lineFrameCount > 1;lineFrameCount --){
6450 0 : result = it->GetNextSiblingOnLine(lastFrame, thisLine);
6451 0 : if (NS_FAILED(result) || !lastFrame){
6452 0 : NS_ERROR("should not be reached nsFrame");
6453 0 : return NS_ERROR_FAILURE;
6454 : }
6455 : }
6456 0 : nsFrame::GetLastLeaf(presContext, &lastFrame);
6457 0 : atLineEdge = lastFrame == traversedFrame;
6458 : }
6459 : }
6460 :
6461 0 : if (atLineEdge) {
6462 0 : *aOutJumpedLine = true;
6463 0 : if (!aJumpLines)
6464 0 : return NS_ERROR_FAILURE; //we are done. cannot jump lines
6465 : }
6466 :
6467 0 : nsCOMPtr<nsIFrameEnumerator> frameTraversal;
6468 0 : result = NS_NewFrameTraversal(getter_AddRefs(frameTraversal),
6469 : presContext, traversedFrame,
6470 : eLeaf,
6471 0 : aVisual && presContext->BidiEnabled(),
6472 : aScrollViewStop,
6473 : true // aFollowOOFs
6474 0 : );
6475 0 : if (NS_FAILED(result))
6476 0 : return result;
6477 :
6478 0 : if (aDirection == eDirNext)
6479 0 : frameTraversal->Next();
6480 : else
6481 0 : frameTraversal->Prev();
6482 :
6483 0 : traversedFrame = frameTraversal->CurrentItem();
6484 0 : if (!traversedFrame)
6485 0 : return NS_ERROR_FAILURE;
6486 0 : traversedFrame->IsSelectable(&selectable, nsnull);
6487 : } // while (!selectable)
6488 :
6489 0 : *aOutOffset = (aDirection == eDirNext) ? 0 : -1;
6490 :
6491 : #ifdef IBMBIDI
6492 0 : if (aVisual) {
6493 0 : PRUint8 newLevel = NS_GET_EMBEDDING_LEVEL(traversedFrame);
6494 0 : PRUint8 newBaseLevel = NS_GET_BASE_LEVEL(traversedFrame);
6495 0 : if ((newLevel & 1) != (newBaseLevel & 1)) // The new frame is reverse-direction, go to the other end
6496 0 : *aOutOffset = -1 - *aOutOffset;
6497 : }
6498 : #endif
6499 0 : *aOutFrame = traversedFrame;
6500 0 : return NS_OK;
6501 : }
6502 :
6503 0 : nsIView* nsIFrame::GetClosestView(nsPoint* aOffset) const
6504 : {
6505 0 : nsPoint offset(0,0);
6506 0 : for (const nsIFrame *f = this; f; f = f->GetParent()) {
6507 0 : if (f->HasView()) {
6508 0 : if (aOffset)
6509 0 : *aOffset = offset;
6510 0 : return f->GetView();
6511 : }
6512 0 : offset += f->GetPosition();
6513 : }
6514 :
6515 0 : NS_NOTREACHED("No view on any parent? How did that happen?");
6516 0 : return nsnull;
6517 : }
6518 :
6519 :
6520 : /* virtual */ void
6521 0 : nsFrame::ChildIsDirty(nsIFrame* aChild)
6522 : {
6523 : NS_NOTREACHED("should never be called on a frame that doesn't inherit from "
6524 0 : "nsContainerFrame");
6525 0 : }
6526 :
6527 :
6528 : #ifdef ACCESSIBILITY
6529 : already_AddRefed<nsAccessible>
6530 0 : nsFrame::CreateAccessible()
6531 : {
6532 0 : return nsnull;
6533 : }
6534 : #endif
6535 :
6536 0 : NS_DECLARE_FRAME_PROPERTY(OverflowAreasProperty,
6537 : nsIFrame::DestroyOverflowAreas)
6538 :
6539 : bool
6540 0 : nsIFrame::ClearOverflowRects()
6541 : {
6542 0 : if (mOverflow.mType == NS_FRAME_OVERFLOW_NONE) {
6543 0 : return false;
6544 : }
6545 0 : if (mOverflow.mType == NS_FRAME_OVERFLOW_LARGE) {
6546 0 : Properties().Delete(OverflowAreasProperty());
6547 : }
6548 0 : mOverflow.mType = NS_FRAME_OVERFLOW_NONE;
6549 0 : return true;
6550 : }
6551 :
6552 : /** Create or retrieve the previously stored overflow area, if the frame does
6553 : * not overflow and no creation is required return nsnull.
6554 : * @return pointer to the overflow area rectangle
6555 : */
6556 : nsOverflowAreas*
6557 0 : nsIFrame::GetOverflowAreasProperty()
6558 : {
6559 0 : FrameProperties props = Properties();
6560 : nsOverflowAreas *overflow =
6561 0 : static_cast<nsOverflowAreas*>(props.Get(OverflowAreasProperty()));
6562 :
6563 0 : if (overflow) {
6564 0 : return overflow; // the property already exists
6565 : }
6566 :
6567 : // The property isn't set yet, so allocate a new rect, set the property,
6568 : // and return the newly allocated rect
6569 0 : overflow = new nsOverflowAreas;
6570 0 : props.Set(OverflowAreasProperty(), overflow);
6571 0 : return overflow;
6572 : }
6573 :
6574 : /** Set the overflowArea rect, storing it as deltas or a separate rect
6575 : * depending on its size in relation to the primary frame rect.
6576 : */
6577 : bool
6578 0 : nsIFrame::SetOverflowAreas(const nsOverflowAreas& aOverflowAreas)
6579 : {
6580 0 : if (mOverflow.mType == NS_FRAME_OVERFLOW_LARGE) {
6581 : nsOverflowAreas *overflow =
6582 0 : static_cast<nsOverflowAreas*>(Properties().Get(OverflowAreasProperty()));
6583 0 : bool changed = *overflow != aOverflowAreas;
6584 0 : *overflow = aOverflowAreas;
6585 :
6586 : // Don't bother with converting to the deltas form if we already
6587 : // have a property.
6588 0 : return changed;
6589 : }
6590 :
6591 0 : const nsRect& vis = aOverflowAreas.VisualOverflow();
6592 0 : PRUint32 l = -vis.x, // left edge: positive delta is leftwards
6593 0 : t = -vis.y, // top: positive is upwards
6594 0 : r = vis.XMost() - mRect.width, // right: positive is rightwards
6595 0 : b = vis.YMost() - mRect.height; // bottom: positive is downwards
6596 0 : if (aOverflowAreas.ScrollableOverflow().IsEqualEdges(nsRect(nsPoint(0, 0), GetSize())) &&
6597 : l <= NS_FRAME_OVERFLOW_DELTA_MAX &&
6598 : t <= NS_FRAME_OVERFLOW_DELTA_MAX &&
6599 : r <= NS_FRAME_OVERFLOW_DELTA_MAX &&
6600 : b <= NS_FRAME_OVERFLOW_DELTA_MAX &&
6601 : // we have to check these against zero because we *never* want to
6602 : // set a frame as having no overflow in this function. This is
6603 : // because FinishAndStoreOverflow calls this function prior to
6604 : // SetRect based on whether the overflow areas match aNewSize.
6605 : // In the case where the overflow areas exactly match mRect but
6606 : // do not match aNewSize, we need to store overflow in a property
6607 : // so that our eventual SetRect/SetSize will know that it has to
6608 : // reset our overflow areas.
6609 : (l | t | r | b) != 0) {
6610 0 : VisualDeltas oldDeltas = mOverflow.mVisualDeltas;
6611 : // It's a "small" overflow area so we store the deltas for each edge
6612 : // directly in the frame, rather than allocating a separate rect.
6613 : // If they're all zero, that's fine; we're setting things to
6614 : // no-overflow.
6615 0 : mOverflow.mVisualDeltas.mLeft = l;
6616 0 : mOverflow.mVisualDeltas.mTop = t;
6617 0 : mOverflow.mVisualDeltas.mRight = r;
6618 0 : mOverflow.mVisualDeltas.mBottom = b;
6619 : // There was no scrollable overflow before, and there isn't now.
6620 0 : return oldDeltas != mOverflow.mVisualDeltas;
6621 : } else {
6622 0 : bool changed = !aOverflowAreas.ScrollableOverflow().IsEqualEdges(nsRect(nsPoint(0, 0), GetSize())) ||
6623 0 : !aOverflowAreas.VisualOverflow().IsEqualEdges(GetVisualOverflowFromDeltas());
6624 :
6625 : // it's a large overflow area that we need to store as a property
6626 0 : mOverflow.mType = NS_FRAME_OVERFLOW_LARGE;
6627 0 : nsOverflowAreas* overflow = GetOverflowAreasProperty();
6628 0 : NS_ASSERTION(overflow, "should have created areas");
6629 0 : *overflow = aOverflowAreas;
6630 0 : return changed;
6631 : }
6632 : }
6633 :
6634 : inline bool
6635 0 : IsInlineFrame(nsIFrame *aFrame)
6636 : {
6637 0 : nsIAtom *type = aFrame->GetType();
6638 0 : return type == nsGkAtoms::inlineFrame;
6639 : }
6640 :
6641 : bool
6642 0 : nsIFrame::FinishAndStoreOverflow(nsOverflowAreas& aOverflowAreas,
6643 : nsSize aNewSize)
6644 : {
6645 0 : nsRect bounds(nsPoint(0, 0), aNewSize);
6646 : // Store the passed in overflow area if we are a preserve-3d frame,
6647 : // and it's not just the frame bounds.
6648 0 : if ((Preserves3D() || HasPerspective()) && (!aOverflowAreas.VisualOverflow().IsEqualEdges(bounds) ||
6649 0 : !aOverflowAreas.ScrollableOverflow().IsEqualEdges(bounds))) {
6650 : nsOverflowAreas* initial =
6651 0 : static_cast<nsOverflowAreas*>(Properties().Get(nsIFrame::InitialOverflowProperty()));
6652 0 : if (!initial) {
6653 : Properties().Set(nsIFrame::InitialOverflowProperty(),
6654 0 : new nsOverflowAreas(aOverflowAreas));
6655 0 : } else if (initial != &aOverflowAreas) {
6656 0 : *initial = aOverflowAreas;
6657 : }
6658 : }
6659 :
6660 : // This is now called FinishAndStoreOverflow() instead of
6661 : // StoreOverflow() because frame-generic ways of adding overflow
6662 : // can happen here, e.g. CSS2 outline and native theme.
6663 : // If the overflow area width or height is nscoord_MAX, then a
6664 : // saturating union may have encounted an overflow, so the overflow may not
6665 : // contain the frame border-box. Don't warn in that case.
6666 0 : NS_FOR_FRAME_OVERFLOW_TYPES(otype) {
6667 0 : DebugOnly<nsRect*> r = &aOverflowAreas.Overflow(otype);
6668 0 : NS_ASSERTION(aNewSize.width == 0 || aNewSize.height == 0 ||
6669 : r->width == nscoord_MAX || r->height == nscoord_MAX ||
6670 : r->Contains(nsRect(nsPoint(0,0), aNewSize)),
6671 : "Computed overflow area must contain frame bounds");
6672 : }
6673 :
6674 : // If we clip our children, clear accumulated overflow area. The
6675 : // children are actually clipped to the padding-box, but since the
6676 : // overflow area should include the entire border-box, just set it to
6677 : // the border-box here.
6678 0 : const nsStyleDisplay* disp = GetStyleDisplay();
6679 0 : NS_ASSERTION((disp->mOverflowY == NS_STYLE_OVERFLOW_CLIP) ==
6680 : (disp->mOverflowX == NS_STYLE_OVERFLOW_CLIP),
6681 : "If one overflow is clip, the other should be too");
6682 0 : if (nsFrame::ApplyOverflowClipping(this, disp)) {
6683 : // The contents are actually clipped to the padding area
6684 0 : aOverflowAreas.SetAllTo(bounds);
6685 : }
6686 :
6687 : // Overflow area must always include the frame's top-left and bottom-right,
6688 : // even if the frame rect is empty.
6689 : // Pending a real fix for bug 426879, don't do this for inline frames
6690 : // with zero width.
6691 0 : if (aNewSize.width != 0 || !IsInlineFrame(this)) {
6692 0 : NS_FOR_FRAME_OVERFLOW_TYPES(otype) {
6693 0 : nsRect& o = aOverflowAreas.Overflow(otype);
6694 0 : o.UnionRectEdges(o, bounds);
6695 : }
6696 : }
6697 :
6698 : // Note that NS_STYLE_OVERFLOW_CLIP doesn't clip the frame background,
6699 : // so we add theme background overflow here so it's not clipped.
6700 0 : if (!IsBoxWrapped() && IsThemed(disp)) {
6701 0 : nsRect r(bounds);
6702 0 : nsPresContext *presContext = PresContext();
6703 0 : if (presContext->GetTheme()->
6704 : GetWidgetOverflow(presContext->DeviceContext(), this,
6705 0 : disp->mAppearance, &r)) {
6706 0 : nsRect& vo = aOverflowAreas.VisualOverflow();
6707 0 : vo.UnionRectEdges(vo, r);
6708 : }
6709 : }
6710 :
6711 : // Nothing in here should affect scrollable overflow.
6712 : bool hasOutlineOrEffects;
6713 0 : aOverflowAreas.VisualOverflow() =
6714 : ComputeOutlineAndEffectsRect(this, &hasOutlineOrEffects,
6715 0 : aOverflowAreas.VisualOverflow(), aNewSize,
6716 0 : true);
6717 :
6718 : // Absolute position clipping
6719 0 : bool didHaveClipPropClip = (GetStateBits() & NS_FRAME_HAS_CLIP) != 0;
6720 0 : nsRect clipPropClipRect;
6721 0 : bool hasClipPropClip = GetClipPropClipRect(disp, &clipPropClipRect, aNewSize);
6722 0 : if (hasClipPropClip) {
6723 0 : NS_FOR_FRAME_OVERFLOW_TYPES(otype) {
6724 0 : nsRect& o = aOverflowAreas.Overflow(otype);
6725 0 : o.IntersectRect(o, clipPropClipRect);
6726 : }
6727 0 : AddStateBits(NS_FRAME_HAS_CLIP);
6728 : } else {
6729 0 : RemoveStateBits(NS_FRAME_HAS_CLIP);
6730 : }
6731 :
6732 : bool preTransformVisualOverflowChanged =
6733 0 : !GetVisualOverflowRectRelativeToSelf().IsEqualInterior(aOverflowAreas.VisualOverflow());
6734 :
6735 : /* If we're transformed, transform the overflow rect by the current transformation. */
6736 0 : bool hasTransform = IsTransformed();
6737 0 : if (hasTransform) {
6738 : Properties().Set(nsIFrame::PreTransformOverflowAreasProperty(),
6739 0 : new nsOverflowAreas(aOverflowAreas));
6740 : /* Since our size might not actually have been computed yet, we need to make sure that we use the
6741 : * correct dimensions by overriding the stored bounding rectangle with the value the caller has
6742 : * ensured us we'll use.
6743 : */
6744 0 : nsRect newBounds(nsPoint(0, 0), aNewSize);
6745 : // Transform affects both overflow areas.
6746 0 : NS_FOR_FRAME_OVERFLOW_TYPES(otype) {
6747 0 : nsRect& o = aOverflowAreas.Overflow(otype);
6748 0 : o = nsDisplayTransform::TransformRect(o, this, nsPoint(0, 0), &newBounds);
6749 : }
6750 0 : if (Preserves3DChildren()) {
6751 0 : ComputePreserve3DChildrenOverflow(aOverflowAreas, newBounds);
6752 0 : } else if (ChildrenHavePerspective()) {
6753 0 : RecomputePerspectiveChildrenOverflow(this->GetStyleContext(), &newBounds);
6754 : }
6755 : } else {
6756 0 : Properties().Delete(nsIFrame::PreTransformOverflowAreasProperty());
6757 0 : if (ChildrenHavePerspective()) {
6758 0 : nsRect newBounds(nsPoint(0, 0), aNewSize);
6759 0 : RecomputePerspectiveChildrenOverflow(this->GetStyleContext(), &newBounds);
6760 : }
6761 : }
6762 :
6763 :
6764 : bool anyOverflowChanged;
6765 0 : if (aOverflowAreas != nsOverflowAreas(bounds, bounds)) {
6766 0 : anyOverflowChanged = SetOverflowAreas(aOverflowAreas);
6767 : } else {
6768 0 : anyOverflowChanged = ClearOverflowRects();
6769 : }
6770 :
6771 0 : if (preTransformVisualOverflowChanged) {
6772 0 : if (hasOutlineOrEffects) {
6773 : // When there's an outline or box-shadow or SVG effects,
6774 : // changes to those styles might require repainting of the old and new
6775 : // overflow areas. Repainting of the old overflow area is handled in
6776 : // nsCSSFrameConstructor::DoApplyRenderingChangeToTree in response
6777 : // to nsChangeHint_RepaintFrame. Since the new overflow area is not
6778 : // known at that time, we have to handle it here.
6779 : // If the overflow area hasn't changed, then we don't have to do
6780 : // anything here since repainting the old overflow area was enough.
6781 : // If there is no outline or other effects now, then we don't have
6782 : // to do anything here since removing those styles can't require
6783 : // repainting of areas that weren't in the old overflow area.
6784 0 : Invalidate(aOverflowAreas.VisualOverflow());
6785 0 : } else if (hasClipPropClip || didHaveClipPropClip) {
6786 : // If we are (or were) clipped by the 'clip' property, and our
6787 : // overflow area changes, it might be because the clipping changed.
6788 : // The nsChangeHint_RepaintFrame for the style change will only
6789 : // repaint the old overflow area, so if the overflow area has
6790 : // changed (in particular, if it grows), we have to repaint the
6791 : // new area here.
6792 0 : Invalidate(aOverflowAreas.VisualOverflow());
6793 : }
6794 : }
6795 0 : if (anyOverflowChanged && hasTransform) {
6796 : // When there's a transform, changes to that style might require
6797 : // repainting of the old and new overflow areas in the widget.
6798 : // Repainting of the frame itself will not be required if there's
6799 : // a retained layer, so we can call InvalidateLayer here
6800 : // which will avoid repainting ThebesLayers if possible.
6801 : // nsCSSFrameConstructor::DoApplyRenderingChangeToTree repaints
6802 : // the old overflow area in the widget in response to
6803 : // nsChangeHint_UpdateTransformLayer. But since the new overflow
6804 : // area is not known at that time, we have to handle it here.
6805 : // If the overflow area hasn't changed, then it doesn't matter that
6806 : // we didn't reach here since repainting the old overflow area was enough.
6807 : // If there is no transform now, then the container layer for
6808 : // the transform will go away and the frame contents will change
6809 : // ThebesLayers, forcing it to be invalidated, so it doesn't matter
6810 : // that we didn't reach here.
6811 0 : InvalidateLayer(aOverflowAreas.VisualOverflow(),
6812 0 : nsDisplayItem::TYPE_TRANSFORM);
6813 : }
6814 :
6815 0 : return anyOverflowChanged;
6816 : }
6817 :
6818 : void
6819 0 : nsIFrame::RecomputePerspectiveChildrenOverflow(const nsStyleContext* aStartStyle, const nsRect* aBounds)
6820 : {
6821 : // Children may check our size when getting our transform, make sure it's valid.
6822 0 : nsSize oldSize = GetSize();
6823 0 : if (aBounds) {
6824 0 : SetSize(aBounds->Size());
6825 : }
6826 0 : nsIFrame::ChildListIterator lists(this);
6827 0 : for (; !lists.IsDone(); lists.Next()) {
6828 0 : nsFrameList::Enumerator childFrames(lists.CurrentList());
6829 0 : for (; !childFrames.AtEnd(); childFrames.Next()) {
6830 0 : nsIFrame* child = childFrames.get();
6831 0 : if (child->HasPerspective()) {
6832 : nsOverflowAreas* overflow =
6833 0 : static_cast<nsOverflowAreas*>(child->Properties().Get(nsIFrame::InitialOverflowProperty()));
6834 0 : nsRect bounds(nsPoint(0, 0), child->GetSize());
6835 0 : if (overflow) {
6836 0 : child->FinishAndStoreOverflow(*overflow, bounds.Size());
6837 : } else {
6838 0 : nsOverflowAreas boundsOverflow;
6839 0 : boundsOverflow.SetAllTo(bounds);
6840 0 : child->FinishAndStoreOverflow(boundsOverflow, bounds.Size());
6841 : }
6842 0 : } else if (child->GetStyleContext()->GetParent() == aStartStyle ||
6843 0 : child->GetStyleContext() == aStartStyle) {
6844 : // Recurse into frames with the same style context, or a direct
6845 : // child style context.
6846 0 : child->RecomputePerspectiveChildrenOverflow(aStartStyle, nsnull);
6847 : }
6848 : }
6849 : }
6850 : // Restore our old size just in case something depends on this elesewhere.
6851 0 : SetSize(oldSize);
6852 0 : }
6853 :
6854 : /* The overflow rects for leaf nodes in a preserve-3d hierarchy depends on
6855 : * the mRect value for their parents (since we use their transform, and transform
6856 : * depends on this for transform-origin etc). These weren't necessarily correct
6857 : * when we reflowed initially, so walk over all preserve-3d children and repeat the
6858 : * overflow calculation.
6859 : */
6860 : static void
6861 0 : RecomputePreserve3DChildrenOverflow(nsIFrame* aFrame, const nsRect* aBounds)
6862 : {
6863 : // Children may check our size when getting our transform, make sure it's valid.
6864 0 : nsSize oldSize = aFrame->GetSize();
6865 0 : if (aBounds) {
6866 0 : aFrame->SetSize(aBounds->Size());
6867 : }
6868 0 : nsIFrame::ChildListIterator lists(aFrame);
6869 0 : for (; !lists.IsDone(); lists.Next()) {
6870 0 : nsFrameList::Enumerator childFrames(lists.CurrentList());
6871 0 : for (; !childFrames.AtEnd(); childFrames.Next()) {
6872 0 : nsIFrame* child = childFrames.get();
6873 0 : if (child->Preserves3DChildren()) {
6874 0 : RecomputePreserve3DChildrenOverflow(child, NULL);
6875 0 : } else if (child->Preserves3D()) {
6876 : nsOverflowAreas* overflow =
6877 0 : static_cast<nsOverflowAreas*>(child->Properties().Get(nsIFrame::InitialOverflowProperty()));
6878 0 : nsRect bounds(nsPoint(0, 0), child->GetSize());
6879 0 : if (overflow) {
6880 0 : child->FinishAndStoreOverflow(*overflow, bounds.Size());
6881 : } else {
6882 0 : nsOverflowAreas boundsOverflow;
6883 0 : boundsOverflow.SetAllTo(bounds);
6884 0 : child->FinishAndStoreOverflow(boundsOverflow, bounds.Size());
6885 : }
6886 : }
6887 : }
6888 : }
6889 : // Restore our old size just in case something depends on this elesewhere.
6890 0 : aFrame->SetSize(oldSize);
6891 :
6892 : // Only repeat computing our overflow in recursive calls since the initial caller is still
6893 : // in the middle of doing this and we don't want an infinite loop.
6894 0 : if (!aBounds) {
6895 : nsOverflowAreas* overflow =
6896 0 : static_cast<nsOverflowAreas*>(aFrame->Properties().Get(nsIFrame::InitialOverflowProperty()));
6897 0 : nsRect bounds(nsPoint(0, 0), aFrame->GetSize());
6898 0 : if (overflow) {
6899 0 : overflow->UnionAllWith(bounds);
6900 0 : aFrame->FinishAndStoreOverflow(*overflow, bounds.Size());
6901 : } else {
6902 0 : nsOverflowAreas boundsOverflow;
6903 0 : boundsOverflow.SetAllTo(bounds);
6904 0 : aFrame->FinishAndStoreOverflow(boundsOverflow, bounds.Size());
6905 : }
6906 : }
6907 0 : }
6908 :
6909 : void
6910 0 : nsIFrame::ComputePreserve3DChildrenOverflow(nsOverflowAreas& aOverflowAreas, const nsRect& aBounds)
6911 : {
6912 : // When we are preserving 3d we need to iterate over all children separately.
6913 : // If the child also preserves 3d then their overflow will already been in our
6914 : // coordinate space, otherwise we need to transform.
6915 :
6916 : // If we're the top frame in a preserve 3d chain then we need to recalculate the overflow
6917 : // areas of all our children since they will have used our size/offset which was invalid at
6918 : // the time.
6919 0 : if (!Preserves3D()) {
6920 0 : RecomputePreserve3DChildrenOverflow(this, &aBounds);
6921 : }
6922 :
6923 0 : nsRect childVisual;
6924 0 : nsRect childScrollable;
6925 0 : nsIFrame::ChildListIterator lists(this);
6926 0 : for (; !lists.IsDone(); lists.Next()) {
6927 0 : nsFrameList::Enumerator childFrames(lists.CurrentList());
6928 0 : for (; !childFrames.AtEnd(); childFrames.Next()) {
6929 0 : nsIFrame* child = childFrames.get();
6930 0 : nsPoint offset = child->GetPosition();
6931 0 : nsRect visual = child->GetVisualOverflowRect();
6932 0 : nsRect scrollable = child->GetScrollableOverflowRect();
6933 0 : visual.MoveBy(offset);
6934 0 : scrollable.MoveBy(offset);
6935 0 : if (child->Preserves3D()) {
6936 0 : childVisual = childVisual.Union(visual);
6937 0 : childScrollable = childScrollable.Union(scrollable);
6938 : } else {
6939 : childVisual =
6940 : childVisual.Union(nsDisplayTransform::TransformRect(visual,
6941 0 : this, nsPoint(0,0), &aBounds));
6942 : childScrollable =
6943 : childScrollable.Union(nsDisplayTransform::TransformRect(scrollable,
6944 0 : this, nsPoint(0,0), &aBounds));
6945 : }
6946 : }
6947 : }
6948 :
6949 0 : aOverflowAreas.Overflow(eVisualOverflow) = aOverflowAreas.Overflow(eVisualOverflow).Union(childVisual);
6950 0 : aOverflowAreas.Overflow(eScrollableOverflow) = aOverflowAreas.Overflow(eScrollableOverflow).Union(childScrollable);
6951 0 : }
6952 :
6953 : void
6954 0 : nsFrame::ConsiderChildOverflow(nsOverflowAreas& aOverflowAreas,
6955 : nsIFrame* aChildFrame)
6956 : {
6957 0 : aOverflowAreas.UnionWith(aChildFrame->GetOverflowAreas() +
6958 0 : aChildFrame->GetPosition());
6959 0 : }
6960 :
6961 : /**
6962 : * This function takes a "special" frame and _if_ that frame is an anonymous
6963 : * block created by an ib split it returns the block's preceding inline. This
6964 : * is needed because the split inline's style context is the parent of the
6965 : * anonymous block's style context.
6966 : *
6967 : * If aFrame is not an anonymous block, null is returned.
6968 : */
6969 : static nsIFrame*
6970 0 : GetIBSpecialSiblingForAnonymousBlock(const nsIFrame* aFrame)
6971 : {
6972 0 : NS_PRECONDITION(aFrame, "Must have a non-null frame!");
6973 0 : NS_ASSERTION(aFrame->GetStateBits() & NS_FRAME_IS_SPECIAL,
6974 : "GetIBSpecialSibling should not be called on a non-special frame");
6975 :
6976 0 : nsIAtom* type = aFrame->GetStyleContext()->GetPseudo();
6977 0 : if (type != nsCSSAnonBoxes::mozAnonymousBlock &&
6978 : type != nsCSSAnonBoxes::mozAnonymousPositionedBlock) {
6979 : // it's not an anonymous block
6980 0 : return nsnull;
6981 : }
6982 :
6983 : // Find the first continuation of the frame. (Ugh. This ends up
6984 : // being O(N^2) when it is called O(N) times.)
6985 0 : aFrame = aFrame->GetFirstContinuation();
6986 :
6987 : /*
6988 : * Now look up the nsGkAtoms::IBSplitSpecialPrevSibling
6989 : * property.
6990 : */
6991 : nsIFrame *specialSibling = static_cast<nsIFrame*>
6992 0 : (aFrame->Properties().Get(nsIFrame::IBSplitSpecialPrevSibling()));
6993 0 : NS_ASSERTION(specialSibling, "Broken frame tree?");
6994 0 : return specialSibling;
6995 : }
6996 :
6997 : /**
6998 : * Get the parent, corrected for the mangled frame tree resulting from
6999 : * having a block within an inline. The result only differs from the
7000 : * result of |GetParent| when |GetParent| returns an anonymous block
7001 : * that was created for an element that was 'display: inline' because
7002 : * that element contained a block.
7003 : *
7004 : * Also skip anonymous scrolled-content parents; inherit directly from the
7005 : * outer scroll frame.
7006 : */
7007 : static nsIFrame*
7008 0 : GetCorrectedParent(const nsIFrame* aFrame)
7009 : {
7010 0 : nsIFrame *parent = aFrame->GetParent();
7011 0 : if (!parent) {
7012 0 : return nsnull;
7013 : }
7014 :
7015 : // Outer tables are always anon boxes; if we're in here for an outer
7016 : // table, that actually means its the _inner_ table that wants to
7017 : // know its parent. So get the pseudo of the inner in that case.
7018 0 : nsIAtom* pseudo = aFrame->GetStyleContext()->GetPseudo();
7019 0 : if (pseudo == nsCSSAnonBoxes::tableOuter) {
7020 0 : pseudo = aFrame->GetFirstPrincipalChild()->GetStyleContext()->GetPseudo();
7021 : }
7022 0 : return nsFrame::CorrectStyleParentFrame(parent, pseudo);
7023 : }
7024 :
7025 : /* static */
7026 : nsIFrame*
7027 0 : nsFrame::CorrectStyleParentFrame(nsIFrame* aProspectiveParent,
7028 : nsIAtom* aChildPseudo)
7029 : {
7030 0 : NS_PRECONDITION(aProspectiveParent, "Must have a prospective parent");
7031 :
7032 : // Anon boxes are parented to their actual parent already, except
7033 : // for non-elements. Those should not be treated as an anon box.
7034 0 : if (aChildPseudo && aChildPseudo != nsCSSAnonBoxes::mozNonElement &&
7035 0 : nsCSSAnonBoxes::IsAnonBox(aChildPseudo)) {
7036 0 : NS_ASSERTION(aChildPseudo != nsCSSAnonBoxes::mozAnonymousBlock &&
7037 : aChildPseudo != nsCSSAnonBoxes::mozAnonymousPositionedBlock,
7038 : "Should have dealt with kids that have NS_FRAME_IS_SPECIAL "
7039 : "elsewhere");
7040 0 : return aProspectiveParent;
7041 : }
7042 :
7043 : // Otherwise, walk up out of all anon boxes. For placeholder frames, walk out
7044 : // of all pseudo-elements as well. Otherwise ReparentStyleContext could cause
7045 : // style data to be out of sync with the frame tree.
7046 0 : nsIFrame* parent = aProspectiveParent;
7047 0 : do {
7048 0 : if (parent->GetStateBits() & NS_FRAME_IS_SPECIAL) {
7049 0 : nsIFrame* sibling = GetIBSpecialSiblingForAnonymousBlock(parent);
7050 :
7051 0 : if (sibling) {
7052 : // |parent| was a block in an {ib} split; use the inline as
7053 : // |the style parent.
7054 0 : parent = sibling;
7055 : }
7056 : }
7057 :
7058 0 : nsIAtom* parentPseudo = parent->GetStyleContext()->GetPseudo();
7059 0 : if (!parentPseudo ||
7060 0 : (!nsCSSAnonBoxes::IsAnonBox(parentPseudo) &&
7061 : // nsPlaceholderFrame pases in nsGkAtoms::placeholderFrame for
7062 : // aChildPseudo (even though that's not a valid pseudo-type) just to
7063 : // trigger this behavior of walking up to the nearest non-pseudo
7064 : // ancestor.
7065 : aChildPseudo != nsGkAtoms::placeholderFrame)) {
7066 0 : return parent;
7067 : }
7068 :
7069 0 : parent = parent->GetParent();
7070 : } while (parent);
7071 :
7072 0 : if (aProspectiveParent->GetStyleContext()->GetPseudo() ==
7073 : nsCSSAnonBoxes::viewportScroll) {
7074 : // aProspectiveParent is the scrollframe for a viewport
7075 : // and the kids are the anonymous scrollbars
7076 0 : return aProspectiveParent;
7077 : }
7078 :
7079 : // We can get here if the root element is absolutely positioned.
7080 : // We can't test for this very accurately, but it can only happen
7081 : // when the prospective parent is a canvas frame.
7082 0 : NS_ASSERTION(aProspectiveParent->GetType() == nsGkAtoms::canvasFrame,
7083 : "Should have found a parent before this");
7084 0 : return nsnull;
7085 : }
7086 :
7087 : nsIFrame*
7088 0 : nsFrame::DoGetParentStyleContextFrame() const
7089 : {
7090 0 : if (mContent && !mContent->GetParent() &&
7091 0 : !GetStyleContext()->GetPseudo()) {
7092 : // we're a frame for the root. We have no style context parent.
7093 0 : return nsnull;
7094 : }
7095 :
7096 0 : if (!(mState & NS_FRAME_OUT_OF_FLOW)) {
7097 : /*
7098 : * If this frame is an anonymous block created when an inline with a block
7099 : * inside it got split, then the parent style context is on its preceding
7100 : * inline. We can get to it using GetIBSpecialSiblingForAnonymousBlock.
7101 : */
7102 0 : if (mState & NS_FRAME_IS_SPECIAL) {
7103 0 : nsIFrame* specialSibling = GetIBSpecialSiblingForAnonymousBlock(this);
7104 0 : if (specialSibling) {
7105 0 : return specialSibling;
7106 : }
7107 : }
7108 :
7109 : // If this frame is one of the blocks that split an inline, we must
7110 : // return the "special" inline parent, i.e., the parent that this
7111 : // frame would have if we didn't mangle the frame structure.
7112 0 : return GetCorrectedParent(this);
7113 : }
7114 :
7115 : // For out-of-flow frames, we must resolve underneath the
7116 : // placeholder's parent.
7117 0 : const nsIFrame* oofFrame = this;
7118 0 : if ((oofFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) &&
7119 0 : GetPrevInFlow()) {
7120 : // Out of flows that are continuations do not
7121 : // have placeholders. Use their first-in-flow's placeholder.
7122 0 : oofFrame = oofFrame->GetFirstInFlow();
7123 : }
7124 : nsIFrame* placeholder = oofFrame->PresContext()->FrameManager()->
7125 0 : GetPlaceholderFrameFor(oofFrame);
7126 0 : if (!placeholder) {
7127 0 : NS_NOTREACHED("no placeholder frame for out-of-flow frame");
7128 0 : return GetCorrectedParent(this);
7129 : }
7130 0 : return placeholder->GetParentStyleContextFrame();
7131 : }
7132 :
7133 : void
7134 0 : nsFrame::GetLastLeaf(nsPresContext* aPresContext, nsIFrame **aFrame)
7135 : {
7136 0 : if (!aFrame || !*aFrame)
7137 0 : return;
7138 0 : nsIFrame *child = *aFrame;
7139 : //if we are a block frame then go for the last line of 'this'
7140 0 : while (1){
7141 0 : child = child->GetFirstPrincipalChild();
7142 0 : if (!child)
7143 0 : return;//nothing to do
7144 : nsIFrame* siblingFrame;
7145 : nsIContent* content;
7146 : //ignore anonymous elements, e.g. mozTableAdd* mozTableRemove*
7147 : //see bug 278197 comment #12 #13 for details
7148 0 : while ((siblingFrame = child->GetNextSibling()) &&
7149 : (content = siblingFrame->GetContent()) &&
7150 0 : !content->IsRootOfNativeAnonymousSubtree())
7151 0 : child = siblingFrame;
7152 0 : *aFrame = child;
7153 : }
7154 : }
7155 :
7156 : void
7157 0 : nsFrame::GetFirstLeaf(nsPresContext* aPresContext, nsIFrame **aFrame)
7158 : {
7159 0 : if (!aFrame || !*aFrame)
7160 0 : return;
7161 0 : nsIFrame *child = *aFrame;
7162 0 : while (1){
7163 0 : child = child->GetFirstPrincipalChild();
7164 0 : if (!child)
7165 0 : return;//nothing to do
7166 0 : *aFrame = child;
7167 : }
7168 : }
7169 :
7170 : /* virtual */ const void*
7171 0 : nsFrame::GetStyleDataExternal(nsStyleStructID aSID) const
7172 : {
7173 0 : NS_ASSERTION(mStyleContext, "unexpected null pointer");
7174 0 : return mStyleContext->GetStyleData(aSID);
7175 : }
7176 :
7177 : /* virtual */ bool
7178 0 : nsIFrame::IsFocusable(PRInt32 *aTabIndex, bool aWithMouse)
7179 : {
7180 0 : PRInt32 tabIndex = -1;
7181 0 : if (aTabIndex) {
7182 0 : *aTabIndex = -1; // Default for early return is not focusable
7183 : }
7184 0 : bool isFocusable = false;
7185 :
7186 0 : if (mContent && mContent->IsElement() && IsVisibleConsideringAncestors()) {
7187 0 : const nsStyleUserInterface* ui = GetStyleUserInterface();
7188 0 : if (ui->mUserFocus != NS_STYLE_USER_FOCUS_IGNORE &&
7189 : ui->mUserFocus != NS_STYLE_USER_FOCUS_NONE) {
7190 : // Pass in default tabindex of -1 for nonfocusable and 0 for focusable
7191 0 : tabIndex = 0;
7192 : }
7193 0 : isFocusable = mContent->IsFocusable(&tabIndex, aWithMouse);
7194 0 : if (!isFocusable && !aWithMouse &&
7195 0 : GetType() == nsGkAtoms::scrollFrame &&
7196 0 : mContent->IsHTML() &&
7197 0 : !mContent->IsRootOfNativeAnonymousSubtree() &&
7198 0 : mContent->GetParent() &&
7199 0 : !mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::tabindex)) {
7200 : // Elements with scrollable view are focusable with script & tabbable
7201 : // Otherwise you couldn't scroll them with keyboard, which is
7202 : // an accessibility issue (e.g. Section 508 rules)
7203 : // However, we don't make them to be focusable with the mouse,
7204 : // because the extra focus outlines are considered unnecessarily ugly.
7205 : // When clicked on, the selection position within the element
7206 : // will be enough to make them keyboard scrollable.
7207 0 : nsIScrollableFrame *scrollFrame = do_QueryFrame(this);
7208 0 : if (scrollFrame &&
7209 0 : scrollFrame->GetScrollbarStyles() != nsIScrollableFrame::ScrollbarStyles(NS_STYLE_OVERFLOW_HIDDEN, NS_STYLE_OVERFLOW_HIDDEN) &&
7210 0 : !scrollFrame->GetScrollRange().IsEqualEdges(nsRect(0, 0, 0, 0))) {
7211 : // Scroll bars will be used for overflow
7212 0 : isFocusable = true;
7213 0 : tabIndex = 0;
7214 : }
7215 : }
7216 : }
7217 :
7218 0 : if (aTabIndex) {
7219 0 : *aTabIndex = tabIndex;
7220 : }
7221 0 : return isFocusable;
7222 : }
7223 :
7224 : /**
7225 : * @return true if this text frame ends with a newline character. It
7226 : * should return false if this is not a text frame.
7227 : */
7228 : bool
7229 0 : nsIFrame::HasTerminalNewline() const
7230 : {
7231 0 : return false;
7232 : }
7233 :
7234 : /* static */
7235 0 : void nsFrame::FillCursorInformationFromStyle(const nsStyleUserInterface* ui,
7236 : nsIFrame::Cursor& aCursor)
7237 : {
7238 0 : aCursor.mCursor = ui->mCursor;
7239 0 : aCursor.mHaveHotspot = false;
7240 0 : aCursor.mHotspotX = aCursor.mHotspotY = 0.0f;
7241 :
7242 0 : for (nsCursorImage *item = ui->mCursorArray,
7243 0 : *item_end = ui->mCursorArray + ui->mCursorArrayLength;
7244 : item < item_end; ++item) {
7245 : PRUint32 status;
7246 0 : nsresult rv = item->GetImage()->GetImageStatus(&status);
7247 0 : if (NS_SUCCEEDED(rv) && (status & imgIRequest::STATUS_LOAD_COMPLETE)) {
7248 : // This is the one we want
7249 0 : item->GetImage()->GetImage(getter_AddRefs(aCursor.mContainer));
7250 0 : aCursor.mHaveHotspot = item->mHaveHotspot;
7251 0 : aCursor.mHotspotX = item->mHotspotX;
7252 0 : aCursor.mHotspotY = item->mHotspotY;
7253 0 : break;
7254 : }
7255 : }
7256 0 : }
7257 :
7258 : NS_IMETHODIMP
7259 0 : nsFrame::RefreshSizeCache(nsBoxLayoutState& aState)
7260 : {
7261 : // XXXbz this comment needs some rewriting to make sense in the
7262 : // post-reflow-branch world.
7263 :
7264 : // Ok we need to compute our minimum, preferred, and maximum sizes.
7265 : // 1) Maximum size. This is easy. Its infinite unless it is overloaded by CSS.
7266 : // 2) Preferred size. This is a little harder. This is the size the block would be
7267 : // if it were laid out on an infinite canvas. So we can get this by reflowing
7268 : // the block with and INTRINSIC width and height. We can also do a nice optimization
7269 : // for incremental reflow. If the reflow is incremental then we can pass a flag to
7270 : // have the block compute the preferred width for us! Preferred height can just be
7271 : // the minimum height;
7272 : // 3) Minimum size. This is a toughy. We can pass the block a flag asking for the max element
7273 : // size. That would give us the width. Unfortunately you can only ask for a maxElementSize
7274 : // during an incremental reflow. So on other reflows we will just have to use 0.
7275 : // The min height on the other hand is fairly easy we need to get the largest
7276 : // line height. This can be done with the line iterator.
7277 :
7278 : // if we do have a rendering context
7279 0 : nsresult rv = NS_OK;
7280 0 : nsRenderingContext* rendContext = aState.GetRenderingContext();
7281 0 : if (rendContext) {
7282 0 : nsPresContext* presContext = aState.PresContext();
7283 :
7284 : // If we don't have any HTML constraints and it's a resize, then nothing in the block
7285 : // could have changed, so no refresh is necessary.
7286 0 : nsBoxLayoutMetrics* metrics = BoxMetrics();
7287 0 : if (!DoesNeedRecalc(metrics->mBlockPrefSize))
7288 0 : return NS_OK;
7289 :
7290 : // get the old rect.
7291 0 : nsRect oldRect = GetRect();
7292 :
7293 : // the rect we plan to size to.
7294 0 : nsRect rect(oldRect);
7295 :
7296 0 : nsMargin bp(0,0,0,0);
7297 0 : GetBorderAndPadding(bp);
7298 :
7299 : {
7300 : // If we're a container for font size inflation, then shrink
7301 : // wrapping inside of us should not apply font size inflation.
7302 0 : AutoMaybeNullInflationContainer an(this);
7303 :
7304 : metrics->mBlockPrefSize.width =
7305 0 : GetPrefWidth(rendContext) + bp.LeftRight();
7306 : metrics->mBlockMinSize.width =
7307 0 : GetMinWidth(rendContext) + bp.LeftRight();
7308 : }
7309 :
7310 : // do the nasty.
7311 0 : nsHTMLReflowMetrics desiredSize;
7312 : rv = BoxReflow(aState, presContext, desiredSize, rendContext,
7313 : rect.x, rect.y,
7314 0 : metrics->mBlockPrefSize.width, NS_UNCONSTRAINEDSIZE);
7315 :
7316 0 : nsRect newRect = GetRect();
7317 :
7318 : // make sure we draw any size change
7319 0 : if (oldRect.width != newRect.width || oldRect.height != newRect.height) {
7320 0 : newRect.x = 0;
7321 0 : newRect.y = 0;
7322 0 : Redraw(aState, &newRect);
7323 : }
7324 :
7325 0 : metrics->mBlockMinSize.height = 0;
7326 : // ok we need the max ascent of the items on the line. So to do this
7327 : // ask the block for its line iterator. Get the max ascent.
7328 0 : nsAutoLineIterator lines = GetLineIterator();
7329 0 : if (lines)
7330 : {
7331 0 : metrics->mBlockMinSize.height = 0;
7332 0 : int count = 0;
7333 0 : nsIFrame* firstFrame = nsnull;
7334 : PRInt32 framesOnLine;
7335 0 : nsRect lineBounds;
7336 : PRUint32 lineFlags;
7337 :
7338 0 : do {
7339 0 : lines->GetLine(count, &firstFrame, &framesOnLine, lineBounds, &lineFlags);
7340 :
7341 0 : if (lineBounds.height > metrics->mBlockMinSize.height)
7342 0 : metrics->mBlockMinSize.height = lineBounds.height;
7343 :
7344 0 : count++;
7345 : } while(firstFrame);
7346 : } else {
7347 0 : metrics->mBlockMinSize.height = desiredSize.height;
7348 : }
7349 :
7350 0 : metrics->mBlockPrefSize.height = metrics->mBlockMinSize.height;
7351 :
7352 0 : if (desiredSize.ascent == nsHTMLReflowMetrics::ASK_FOR_BASELINE) {
7353 0 : if (!nsLayoutUtils::GetFirstLineBaseline(this, &metrics->mBlockAscent))
7354 0 : metrics->mBlockAscent = GetBaseline();
7355 : } else {
7356 0 : metrics->mBlockAscent = desiredSize.ascent;
7357 : }
7358 :
7359 : #ifdef DEBUG_adaptor
7360 : printf("min=(%d,%d), pref=(%d,%d), ascent=%d\n", metrics->mBlockMinSize.width,
7361 : metrics->mBlockMinSize.height,
7362 : metrics->mBlockPrefSize.width,
7363 : metrics->mBlockPrefSize.height,
7364 : metrics->mBlockAscent);
7365 : #endif
7366 : }
7367 :
7368 0 : return rv;
7369 : }
7370 :
7371 : /* virtual */ nsILineIterator*
7372 0 : nsFrame::GetLineIterator()
7373 : {
7374 0 : return nsnull;
7375 : }
7376 :
7377 : nsSize
7378 0 : nsFrame::GetPrefSize(nsBoxLayoutState& aState)
7379 : {
7380 0 : nsSize size(0,0);
7381 0 : DISPLAY_PREF_SIZE(this, size);
7382 : // If the size is cached, and there are no HTML constraints that we might
7383 : // be depending on, then we just return the cached size.
7384 0 : nsBoxLayoutMetrics *metrics = BoxMetrics();
7385 0 : if (!DoesNeedRecalc(metrics->mPrefSize)) {
7386 0 : return metrics->mPrefSize;
7387 : }
7388 :
7389 0 : if (IsCollapsed())
7390 0 : return size;
7391 :
7392 : // get our size in CSS.
7393 : bool widthSet, heightSet;
7394 0 : bool completelyRedefined = nsIBox::AddCSSPrefSize(this, size, widthSet, heightSet);
7395 :
7396 : // Refresh our caches with new sizes.
7397 0 : if (!completelyRedefined) {
7398 0 : RefreshSizeCache(aState);
7399 0 : nsSize blockSize = metrics->mBlockPrefSize;
7400 :
7401 : // notice we don't need to add our borders or padding
7402 : // in. That's because the block did it for us.
7403 0 : if (!widthSet)
7404 0 : size.width = blockSize.width;
7405 0 : if (!heightSet)
7406 0 : size.height = blockSize.height;
7407 : }
7408 :
7409 0 : metrics->mPrefSize = size;
7410 0 : return size;
7411 : }
7412 :
7413 : nsSize
7414 0 : nsFrame::GetMinSize(nsBoxLayoutState& aState)
7415 : {
7416 0 : nsSize size(0,0);
7417 0 : DISPLAY_MIN_SIZE(this, size);
7418 : // Don't use the cache if we have HTMLReflowState constraints --- they might have changed
7419 0 : nsBoxLayoutMetrics *metrics = BoxMetrics();
7420 0 : if (!DoesNeedRecalc(metrics->mMinSize)) {
7421 0 : size = metrics->mMinSize;
7422 : return size;
7423 : }
7424 :
7425 0 : if (IsCollapsed())
7426 : return size;
7427 :
7428 : // get our size in CSS.
7429 : bool widthSet, heightSet;
7430 : bool completelyRedefined =
7431 0 : nsIBox::AddCSSMinSize(aState, this, size, widthSet, heightSet);
7432 :
7433 : // Refresh our caches with new sizes.
7434 0 : if (!completelyRedefined) {
7435 0 : RefreshSizeCache(aState);
7436 0 : nsSize blockSize = metrics->mBlockMinSize;
7437 :
7438 0 : if (!widthSet)
7439 0 : size.width = blockSize.width;
7440 0 : if (!heightSet)
7441 0 : size.height = blockSize.height;
7442 : }
7443 :
7444 0 : metrics->mMinSize = size;
7445 : return size;
7446 : }
7447 :
7448 : nsSize
7449 0 : nsFrame::GetMaxSize(nsBoxLayoutState& aState)
7450 : {
7451 0 : nsSize size(NS_INTRINSICSIZE, NS_INTRINSICSIZE);
7452 0 : DISPLAY_MAX_SIZE(this, size);
7453 : // Don't use the cache if we have HTMLReflowState constraints --- they might have changed
7454 0 : nsBoxLayoutMetrics *metrics = BoxMetrics();
7455 0 : if (!DoesNeedRecalc(metrics->mMaxSize)) {
7456 0 : size = metrics->mMaxSize;
7457 : return size;
7458 : }
7459 :
7460 0 : if (IsCollapsed())
7461 : return size;
7462 :
7463 0 : size = nsBox::GetMaxSize(aState);
7464 0 : metrics->mMaxSize = size;
7465 :
7466 : return size;
7467 : }
7468 :
7469 : nscoord
7470 0 : nsFrame::GetFlex(nsBoxLayoutState& aState)
7471 : {
7472 0 : nsBoxLayoutMetrics *metrics = BoxMetrics();
7473 0 : if (!DoesNeedRecalc(metrics->mFlex))
7474 0 : return metrics->mFlex;
7475 :
7476 0 : metrics->mFlex = nsBox::GetFlex(aState);
7477 :
7478 0 : return metrics->mFlex;
7479 : }
7480 :
7481 : nscoord
7482 0 : nsFrame::GetBoxAscent(nsBoxLayoutState& aState)
7483 : {
7484 0 : nsBoxLayoutMetrics *metrics = BoxMetrics();
7485 0 : if (!DoesNeedRecalc(metrics->mAscent))
7486 0 : return metrics->mAscent;
7487 :
7488 0 : if (IsCollapsed()) {
7489 0 : metrics->mAscent = 0;
7490 : } else {
7491 : // Refresh our caches with new sizes.
7492 0 : RefreshSizeCache(aState);
7493 0 : metrics->mAscent = metrics->mBlockAscent;
7494 : }
7495 :
7496 0 : return metrics->mAscent;
7497 : }
7498 :
7499 : nsresult
7500 0 : nsFrame::DoLayout(nsBoxLayoutState& aState)
7501 : {
7502 0 : nsRect ourRect(mRect);
7503 :
7504 0 : nsRenderingContext* rendContext = aState.GetRenderingContext();
7505 0 : nsPresContext* presContext = aState.PresContext();
7506 0 : nsHTMLReflowMetrics desiredSize;
7507 0 : nsresult rv = NS_OK;
7508 :
7509 0 : if (rendContext) {
7510 :
7511 : rv = BoxReflow(aState, presContext, desiredSize, rendContext,
7512 0 : ourRect.x, ourRect.y, ourRect.width, ourRect.height);
7513 :
7514 0 : if (IsCollapsed()) {
7515 0 : SetSize(nsSize(0, 0));
7516 : } else {
7517 :
7518 : // if our child needs to be bigger. This might happend with
7519 : // wrapping text. There is no way to predict its height until we
7520 : // reflow it. Now that we know the height reshuffle upward.
7521 0 : if (desiredSize.width > ourRect.width ||
7522 : desiredSize.height > ourRect.height) {
7523 :
7524 : #ifdef DEBUG_GROW
7525 : DumpBox(stdout);
7526 : printf(" GREW from (%d,%d) -> (%d,%d)\n",
7527 : ourRect.width, ourRect.height,
7528 : desiredSize.width, desiredSize.height);
7529 : #endif
7530 :
7531 0 : if (desiredSize.width > ourRect.width)
7532 0 : ourRect.width = desiredSize.width;
7533 :
7534 0 : if (desiredSize.height > ourRect.height)
7535 0 : ourRect.height = desiredSize.height;
7536 : }
7537 :
7538 : // ensure our size is what we think is should be. Someone could have
7539 : // reset the frame to be smaller or something dumb like that.
7540 0 : SetSize(nsSize(ourRect.width, ourRect.height));
7541 : }
7542 : }
7543 :
7544 : // Should we do this if IsCollapsed() is true?
7545 0 : nsSize size(GetSize());
7546 0 : desiredSize.width = size.width;
7547 0 : desiredSize.height = size.height;
7548 0 : desiredSize.UnionOverflowAreasWithDesiredBounds();
7549 :
7550 0 : if (HasAbsolutelyPositionedChildren()) {
7551 : // Set up a |reflowState| to pass into ReflowAbsoluteFrames
7552 : nsHTMLReflowState reflowState(aState.PresContext(), this,
7553 : aState.GetRenderingContext(),
7554 0 : nsSize(size.width, NS_UNCONSTRAINEDSIZE));
7555 :
7556 : // Set up a |reflowStatus| to pass into ReflowAbsoluteFrames
7557 : // (just a dummy value; hopefully that's OK)
7558 0 : nsReflowStatus reflowStatus = NS_FRAME_COMPLETE;
7559 : ReflowAbsoluteFrames(aState.PresContext(), desiredSize,
7560 0 : reflowState, reflowStatus);
7561 : }
7562 :
7563 0 : FinishAndStoreOverflow(desiredSize.mOverflowAreas, size);
7564 :
7565 0 : SyncLayout(aState);
7566 :
7567 0 : return rv;
7568 : }
7569 :
7570 : nsresult
7571 0 : nsFrame::BoxReflow(nsBoxLayoutState& aState,
7572 : nsPresContext* aPresContext,
7573 : nsHTMLReflowMetrics& aDesiredSize,
7574 : nsRenderingContext* aRenderingContext,
7575 : nscoord aX,
7576 : nscoord aY,
7577 : nscoord aWidth,
7578 : nscoord aHeight,
7579 : bool aMoveFrame)
7580 : {
7581 0 : DO_GLOBAL_REFLOW_COUNT("nsBoxToBlockAdaptor");
7582 :
7583 : #ifdef DEBUG_REFLOW
7584 : nsAdaptorAddIndents();
7585 : printf("Reflowing: ");
7586 : nsFrame::ListTag(stdout, mFrame);
7587 : printf("\n");
7588 : gIndent2++;
7589 : #endif
7590 :
7591 : //printf("width=%d, height=%d\n", aWidth, aHeight);
7592 : /*
7593 : nsIBox* parent;
7594 : GetParentBox(&parent);
7595 :
7596 : // if (parent->GetStateBits() & NS_STATE_CURRENTLY_IN_DEBUG)
7597 : // printf("In debug\n");
7598 : */
7599 :
7600 0 : nsBoxLayoutMetrics *metrics = BoxMetrics();
7601 0 : nsReflowStatus status = NS_FRAME_COMPLETE;
7602 :
7603 0 : bool redrawAfterReflow = false;
7604 0 : bool redrawNow = false;
7605 :
7606 0 : bool needsReflow = NS_SUBTREE_DIRTY(this);
7607 :
7608 0 : if (redrawNow)
7609 0 : Redraw(aState);
7610 :
7611 : // if we don't need a reflow then
7612 : // lets see if we are already that size. Yes? then don't even reflow. We are done.
7613 0 : if (!needsReflow) {
7614 :
7615 0 : if (aWidth != NS_INTRINSICSIZE && aHeight != NS_INTRINSICSIZE) {
7616 :
7617 : // if the new calculated size has a 0 width or a 0 height
7618 0 : if ((metrics->mLastSize.width == 0 || metrics->mLastSize.height == 0) && (aWidth == 0 || aHeight == 0)) {
7619 0 : needsReflow = false;
7620 0 : aDesiredSize.width = aWidth;
7621 0 : aDesiredSize.height = aHeight;
7622 0 : SetSize(nsSize(aDesiredSize.width, aDesiredSize.height));
7623 : } else {
7624 0 : aDesiredSize.width = metrics->mLastSize.width;
7625 0 : aDesiredSize.height = metrics->mLastSize.height;
7626 :
7627 : // remove the margin. The rect of our child does not include it but our calculated size does.
7628 : // don't reflow if we are already the right size
7629 0 : if (metrics->mLastSize.width == aWidth && metrics->mLastSize.height == aHeight)
7630 0 : needsReflow = false;
7631 : else
7632 0 : needsReflow = true;
7633 :
7634 : }
7635 : } else {
7636 : // if the width or height are intrinsic alway reflow because
7637 : // we don't know what it should be.
7638 0 : needsReflow = true;
7639 : }
7640 : }
7641 :
7642 : // ok now reflow the child into the spacers calculated space
7643 0 : if (needsReflow) {
7644 :
7645 0 : aDesiredSize.width = 0;
7646 0 : aDesiredSize.height = 0;
7647 :
7648 : // create a reflow state to tell our child to flow at the given size.
7649 :
7650 : // Construct a bogus parent reflow state so that there's a usable
7651 : // containing block reflow state.
7652 0 : nsMargin margin(0,0,0,0);
7653 0 : GetMargin(margin);
7654 :
7655 0 : nsSize parentSize(aWidth, aHeight);
7656 0 : if (parentSize.height != NS_INTRINSICSIZE)
7657 0 : parentSize.height += margin.TopBottom();
7658 0 : if (parentSize.width != NS_INTRINSICSIZE)
7659 0 : parentSize.width += margin.LeftRight();
7660 :
7661 0 : nsIFrame *parentFrame = GetParent();
7662 0 : nsFrameState savedState = parentFrame->GetStateBits();
7663 : nsHTMLReflowState parentReflowState(aPresContext, parentFrame,
7664 : aRenderingContext,
7665 0 : parentSize);
7666 0 : parentFrame->RemoveStateBits(~nsFrameState(0));
7667 0 : parentFrame->AddStateBits(savedState);
7668 :
7669 : // This may not do very much useful, but it's probably worth trying.
7670 0 : if (parentSize.width != NS_INTRINSICSIZE)
7671 0 : parentReflowState.SetComputedWidth(NS_MAX(parentSize.width, 0));
7672 0 : if (parentSize.height != NS_INTRINSICSIZE)
7673 0 : parentReflowState.SetComputedHeight(NS_MAX(parentSize.height, 0));
7674 0 : parentReflowState.mComputedMargin.SizeTo(0, 0, 0, 0);
7675 : // XXX use box methods
7676 0 : parentFrame->GetPadding(parentReflowState.mComputedPadding);
7677 0 : parentFrame->GetBorder(parentReflowState.mComputedBorderPadding);
7678 : parentReflowState.mComputedBorderPadding +=
7679 0 : parentReflowState.mComputedPadding;
7680 :
7681 : // XXX Is it OK that this reflow state has no parent reflow state?
7682 : // (It used to have a bogus parent, skipping all the boxes).
7683 0 : nsSize availSize(aWidth, NS_INTRINSICSIZE);
7684 : nsHTMLReflowState reflowState(aPresContext, this, aRenderingContext,
7685 0 : availSize);
7686 :
7687 : // Construct the parent chain manually since constructing it normally
7688 : // messes up dimensions.
7689 0 : const nsHTMLReflowState *outerReflowState = aState.OuterReflowState();
7690 0 : NS_ASSERTION(!outerReflowState || outerReflowState->frame != this,
7691 : "in and out of XUL on a single frame?");
7692 0 : if (outerReflowState && outerReflowState->frame == parentFrame) {
7693 : // We're a frame (such as a text control frame) that jumps into
7694 : // box reflow and then straight out of it on the child frame.
7695 : // This means we actually have a real parent reflow state.
7696 : // nsLayoutUtils::InflationMinFontSizeFor used to need this to be
7697 : // linked up correctly for text control frames, so do so here).
7698 0 : reflowState.parentReflowState = outerReflowState;
7699 0 : reflowState.mCBReflowState = outerReflowState;
7700 : } else {
7701 0 : reflowState.parentReflowState = &parentReflowState;
7702 0 : reflowState.mCBReflowState = &parentReflowState;
7703 : }
7704 0 : reflowState.mReflowDepth = aState.GetReflowDepth();
7705 :
7706 : // mComputedWidth and mComputedHeight are content-box, not
7707 : // border-box
7708 0 : if (aWidth != NS_INTRINSICSIZE) {
7709 : nscoord computedWidth =
7710 0 : aWidth - reflowState.mComputedBorderPadding.LeftRight();
7711 0 : computedWidth = NS_MAX(computedWidth, 0);
7712 0 : reflowState.SetComputedWidth(computedWidth);
7713 : }
7714 :
7715 : // Most child frames of box frames (e.g. subdocument or scroll frames)
7716 : // need to be constrained to the provided size and overflow as necessary.
7717 : // The one exception are block frames, because we need to know their
7718 : // natural height excluding any overflow area which may be caused by
7719 : // various CSS effects such as shadow or outline.
7720 0 : if (!IsFrameOfType(eBlockFrame)) {
7721 0 : if (aHeight != NS_INTRINSICSIZE) {
7722 : nscoord computedHeight =
7723 0 : aHeight - reflowState.mComputedBorderPadding.TopBottom();
7724 0 : computedHeight = NS_MAX(computedHeight, 0);
7725 0 : reflowState.SetComputedHeight(computedHeight);
7726 : } else {
7727 : reflowState.SetComputedHeight(
7728 : ComputeSize(aRenderingContext, availSize, availSize.width,
7729 : nsSize(reflowState.mComputedMargin.LeftRight(),
7730 : reflowState.mComputedMargin.TopBottom()),
7731 0 : nsSize(reflowState.mComputedBorderPadding.LeftRight() -
7732 0 : reflowState.mComputedPadding.LeftRight(),
7733 0 : reflowState.mComputedBorderPadding.TopBottom() -
7734 0 : reflowState.mComputedPadding.TopBottom()),
7735 : nsSize(reflowState.mComputedPadding.LeftRight(),
7736 : reflowState.mComputedPadding.TopBottom()),
7737 0 : false).height
7738 0 : );
7739 : }
7740 : }
7741 :
7742 : // Box layout calls SetRect before Layout, whereas non-box layout
7743 : // calls SetRect after Reflow.
7744 : // XXX Perhaps we should be doing this by twiddling the rect back to
7745 : // mLastSize before calling Reflow and then switching it back, but
7746 : // However, mLastSize can also be the size passed to BoxReflow by
7747 : // RefreshSizeCache, so that doesn't really make sense.
7748 0 : if (metrics->mLastSize.width != aWidth) {
7749 0 : reflowState.mFlags.mHResize = true;
7750 :
7751 : // When font size inflation is enabled, a horizontal resize
7752 : // requires a full reflow. See nsHTMLReflowState::InitResizeFlags
7753 : // for more details.
7754 0 : if (nsLayoutUtils::FontSizeInflationEnabled(aPresContext)) {
7755 0 : AddStateBits(NS_FRAME_IS_DIRTY);
7756 : }
7757 : }
7758 0 : if (metrics->mLastSize.height != aHeight)
7759 0 : reflowState.mFlags.mVResize = true;
7760 :
7761 : #ifdef DEBUG_REFLOW
7762 : nsAdaptorAddIndents();
7763 : printf("Size=(%d,%d)\n",reflowState.ComputedWidth(),
7764 : reflowState.ComputedHeight());
7765 : nsAdaptorAddIndents();
7766 : nsAdaptorPrintReason(reflowState);
7767 : printf("\n");
7768 : #endif
7769 :
7770 : // place the child and reflow
7771 0 : WillReflow(aPresContext);
7772 :
7773 0 : Reflow(aPresContext, aDesiredSize, reflowState, status);
7774 :
7775 0 : NS_ASSERTION(NS_FRAME_IS_COMPLETE(status), "bad status");
7776 :
7777 0 : if (redrawAfterReflow) {
7778 0 : nsRect r = GetRect();
7779 0 : r.width = aDesiredSize.width;
7780 0 : r.height = aDesiredSize.height;
7781 0 : Redraw(aState, &r);
7782 : }
7783 :
7784 0 : PRUint32 layoutFlags = aState.LayoutFlags();
7785 : nsContainerFrame::FinishReflowChild(this, aPresContext, &reflowState,
7786 0 : aDesiredSize, aX, aY, layoutFlags | NS_FRAME_NO_MOVE_FRAME);
7787 :
7788 : // Save the ascent. (bug 103925)
7789 0 : if (IsCollapsed()) {
7790 0 : metrics->mAscent = 0;
7791 : } else {
7792 0 : if (aDesiredSize.ascent == nsHTMLReflowMetrics::ASK_FOR_BASELINE) {
7793 0 : if (!nsLayoutUtils::GetFirstLineBaseline(this, &metrics->mAscent))
7794 0 : metrics->mAscent = GetBaseline();
7795 : } else
7796 0 : metrics->mAscent = aDesiredSize.ascent;
7797 : }
7798 :
7799 : } else {
7800 0 : aDesiredSize.ascent = metrics->mBlockAscent;
7801 : }
7802 :
7803 : #ifdef DEBUG_REFLOW
7804 : if (aHeight != NS_INTRINSICSIZE && aDesiredSize.height != aHeight)
7805 : {
7806 : nsAdaptorAddIndents();
7807 : printf("*****got taller!*****\n");
7808 :
7809 : }
7810 : if (aWidth != NS_INTRINSICSIZE && aDesiredSize.width != aWidth)
7811 : {
7812 : nsAdaptorAddIndents();
7813 : printf("*****got wider!******\n");
7814 :
7815 : }
7816 : #endif
7817 :
7818 0 : if (aWidth == NS_INTRINSICSIZE)
7819 0 : aWidth = aDesiredSize.width;
7820 :
7821 0 : if (aHeight == NS_INTRINSICSIZE)
7822 0 : aHeight = aDesiredSize.height;
7823 :
7824 0 : metrics->mLastSize.width = aDesiredSize.width;
7825 0 : metrics->mLastSize.height = aDesiredSize.height;
7826 :
7827 : #ifdef DEBUG_REFLOW
7828 : gIndent2--;
7829 : #endif
7830 :
7831 0 : return NS_OK;
7832 : }
7833 :
7834 : static void
7835 0 : DestroyBoxMetrics(void* aPropertyValue)
7836 : {
7837 : delete static_cast<nsBoxLayoutMetrics*>(aPropertyValue);
7838 0 : }
7839 :
7840 0 : NS_DECLARE_FRAME_PROPERTY(BoxMetricsProperty, DestroyBoxMetrics)
7841 :
7842 : nsBoxLayoutMetrics*
7843 0 : nsFrame::BoxMetrics() const
7844 : {
7845 : nsBoxLayoutMetrics* metrics =
7846 0 : static_cast<nsBoxLayoutMetrics*>(Properties().Get(BoxMetricsProperty()));
7847 0 : NS_ASSERTION(metrics, "A box layout method was called but InitBoxMetrics was never called");
7848 0 : return metrics;
7849 : }
7850 :
7851 : void
7852 0 : nsFrame::SetParent(nsIFrame* aParent)
7853 : {
7854 0 : bool wasBoxWrapped = IsBoxWrapped();
7855 0 : mParent = aParent;
7856 0 : if (!wasBoxWrapped && IsBoxWrapped()) {
7857 0 : InitBoxMetrics(true);
7858 0 : } else if (wasBoxWrapped && !IsBoxWrapped()) {
7859 0 : Properties().Delete(BoxMetricsProperty());
7860 : }
7861 :
7862 0 : if (GetStateBits() & (NS_FRAME_HAS_VIEW | NS_FRAME_HAS_CHILD_WITH_VIEW)) {
7863 0 : for (nsIFrame* f = aParent;
7864 0 : f && !(f->GetStateBits() & NS_FRAME_HAS_CHILD_WITH_VIEW);
7865 : f = f->GetParent()) {
7866 0 : f->AddStateBits(NS_FRAME_HAS_CHILD_WITH_VIEW);
7867 : }
7868 : }
7869 :
7870 0 : if (GetStateBits() & NS_FRAME_HAS_CONTAINER_LAYER_DESCENDANT) {
7871 0 : for (nsIFrame* f = aParent;
7872 0 : f && !(f->GetStateBits() & NS_FRAME_HAS_CONTAINER_LAYER_DESCENDANT);
7873 : f = nsLayoutUtils::GetCrossDocParentFrame(f)) {
7874 0 : f->AddStateBits(NS_FRAME_HAS_CONTAINER_LAYER_DESCENDANT);
7875 : }
7876 : }
7877 0 : }
7878 :
7879 : void
7880 0 : nsFrame::InitBoxMetrics(bool aClear)
7881 : {
7882 0 : FrameProperties props = Properties();
7883 0 : if (aClear) {
7884 0 : props.Delete(BoxMetricsProperty());
7885 : }
7886 :
7887 0 : nsBoxLayoutMetrics *metrics = new nsBoxLayoutMetrics();
7888 0 : props.Set(BoxMetricsProperty(), metrics);
7889 :
7890 0 : nsFrame::MarkIntrinsicWidthsDirty();
7891 0 : metrics->mBlockAscent = 0;
7892 0 : metrics->mLastSize.SizeTo(0, 0);
7893 0 : }
7894 :
7895 : // Box layout debugging
7896 : #ifdef DEBUG_REFLOW
7897 : PRInt32 gIndent2 = 0;
7898 :
7899 : void
7900 : nsAdaptorAddIndents()
7901 : {
7902 : for(PRInt32 i=0; i < gIndent2; i++)
7903 : {
7904 : printf(" ");
7905 : }
7906 : }
7907 :
7908 : void
7909 : nsAdaptorPrintReason(nsHTMLReflowState& aReflowState)
7910 : {
7911 : char* reflowReasonString;
7912 :
7913 : switch(aReflowState.reason)
7914 : {
7915 : case eReflowReason_Initial:
7916 : reflowReasonString = "initial";
7917 : break;
7918 :
7919 : case eReflowReason_Resize:
7920 : reflowReasonString = "resize";
7921 : break;
7922 : case eReflowReason_Dirty:
7923 : reflowReasonString = "dirty";
7924 : break;
7925 : case eReflowReason_StyleChange:
7926 : reflowReasonString = "stylechange";
7927 : break;
7928 : case eReflowReason_Incremental:
7929 : {
7930 : switch (aReflowState.reflowCommand->Type()) {
7931 : case eReflowType_StyleChanged:
7932 : reflowReasonString = "incremental (StyleChanged)";
7933 : break;
7934 : case eReflowType_ReflowDirty:
7935 : reflowReasonString = "incremental (ReflowDirty)";
7936 : break;
7937 : default:
7938 : reflowReasonString = "incremental (Unknown)";
7939 : }
7940 : }
7941 : break;
7942 : default:
7943 : reflowReasonString = "unknown";
7944 : break;
7945 : }
7946 :
7947 : printf("%s",reflowReasonString);
7948 : }
7949 :
7950 : #endif
7951 : #ifdef DEBUG_LAYOUT
7952 : void
7953 : nsFrame::GetBoxName(nsAutoString& aName)
7954 : {
7955 : GetFrameName(aName);
7956 : }
7957 : #endif
7958 :
7959 : #ifdef NS_DEBUG
7960 : static void
7961 0 : GetTagName(nsFrame* aFrame, nsIContent* aContent, PRIntn aResultSize,
7962 : char* aResult)
7963 : {
7964 0 : if (aContent) {
7965 : PR_snprintf(aResult, aResultSize, "%s@%p",
7966 0 : nsAtomCString(aContent->Tag()).get(), aFrame);
7967 : }
7968 : else {
7969 0 : PR_snprintf(aResult, aResultSize, "@%p", aFrame);
7970 : }
7971 0 : }
7972 :
7973 : void
7974 0 : nsFrame::Trace(const char* aMethod, bool aEnter)
7975 : {
7976 0 : if (NS_FRAME_LOG_TEST(gLogModule, NS_FRAME_TRACE_CALLS)) {
7977 : char tagbuf[40];
7978 0 : GetTagName(this, mContent, sizeof(tagbuf), tagbuf);
7979 0 : PR_LogPrint("%s: %s %s", tagbuf, aEnter ? "enter" : "exit", aMethod);
7980 : }
7981 0 : }
7982 :
7983 : void
7984 0 : nsFrame::Trace(const char* aMethod, bool aEnter, nsReflowStatus aStatus)
7985 : {
7986 0 : if (NS_FRAME_LOG_TEST(gLogModule, NS_FRAME_TRACE_CALLS)) {
7987 : char tagbuf[40];
7988 0 : GetTagName(this, mContent, sizeof(tagbuf), tagbuf);
7989 : PR_LogPrint("%s: %s %s, status=%scomplete%s",
7990 : tagbuf, aEnter ? "enter" : "exit", aMethod,
7991 : NS_FRAME_IS_NOT_COMPLETE(aStatus) ? "not" : "",
7992 0 : (NS_FRAME_REFLOW_NEXTINFLOW & aStatus) ? "+reflow" : "");
7993 : }
7994 0 : }
7995 :
7996 : void
7997 0 : nsFrame::TraceMsg(const char* aFormatString, ...)
7998 : {
7999 0 : if (NS_FRAME_LOG_TEST(gLogModule, NS_FRAME_TRACE_CALLS)) {
8000 : // Format arguments into a buffer
8001 : char argbuf[200];
8002 : va_list ap;
8003 0 : va_start(ap, aFormatString);
8004 0 : PR_vsnprintf(argbuf, sizeof(argbuf), aFormatString, ap);
8005 0 : va_end(ap);
8006 :
8007 : char tagbuf[40];
8008 0 : GetTagName(this, mContent, sizeof(tagbuf), tagbuf);
8009 0 : PR_LogPrint("%s: %s", tagbuf, argbuf);
8010 : }
8011 0 : }
8012 :
8013 : void
8014 0 : nsFrame::VerifyDirtyBitSet(const nsFrameList& aFrameList)
8015 : {
8016 0 : for (nsFrameList::Enumerator e(aFrameList); !e.AtEnd(); e.Next()) {
8017 0 : NS_ASSERTION(e.get()->GetStateBits() & NS_FRAME_IS_DIRTY,
8018 : "dirty bit not set");
8019 : }
8020 0 : }
8021 :
8022 : // Start Display Reflow
8023 : #ifdef DEBUG
8024 :
8025 0 : DR_cookie::DR_cookie(nsPresContext* aPresContext,
8026 : nsIFrame* aFrame,
8027 : const nsHTMLReflowState& aReflowState,
8028 : nsHTMLReflowMetrics& aMetrics,
8029 : nsReflowStatus& aStatus)
8030 0 : :mPresContext(aPresContext), mFrame(aFrame), mReflowState(aReflowState), mMetrics(aMetrics), mStatus(aStatus)
8031 : {
8032 0 : MOZ_COUNT_CTOR(DR_cookie);
8033 0 : mValue = nsFrame::DisplayReflowEnter(aPresContext, mFrame, mReflowState);
8034 0 : }
8035 :
8036 0 : DR_cookie::~DR_cookie()
8037 : {
8038 0 : MOZ_COUNT_DTOR(DR_cookie);
8039 0 : nsFrame::DisplayReflowExit(mPresContext, mFrame, mMetrics, mStatus, mValue);
8040 0 : }
8041 :
8042 0 : DR_layout_cookie::DR_layout_cookie(nsIFrame* aFrame)
8043 0 : : mFrame(aFrame)
8044 : {
8045 0 : MOZ_COUNT_CTOR(DR_layout_cookie);
8046 0 : mValue = nsFrame::DisplayLayoutEnter(mFrame);
8047 0 : }
8048 :
8049 0 : DR_layout_cookie::~DR_layout_cookie()
8050 : {
8051 0 : MOZ_COUNT_DTOR(DR_layout_cookie);
8052 0 : nsFrame::DisplayLayoutExit(mFrame, mValue);
8053 0 : }
8054 :
8055 0 : DR_intrinsic_width_cookie::DR_intrinsic_width_cookie(
8056 : nsIFrame* aFrame,
8057 : const char* aType,
8058 : nscoord& aResult)
8059 : : mFrame(aFrame)
8060 : , mType(aType)
8061 0 : , mResult(aResult)
8062 : {
8063 0 : MOZ_COUNT_CTOR(DR_intrinsic_width_cookie);
8064 0 : mValue = nsFrame::DisplayIntrinsicWidthEnter(mFrame, mType);
8065 0 : }
8066 :
8067 0 : DR_intrinsic_width_cookie::~DR_intrinsic_width_cookie()
8068 : {
8069 0 : MOZ_COUNT_DTOR(DR_intrinsic_width_cookie);
8070 0 : nsFrame::DisplayIntrinsicWidthExit(mFrame, mType, mResult, mValue);
8071 0 : }
8072 :
8073 0 : DR_intrinsic_size_cookie::DR_intrinsic_size_cookie(
8074 : nsIFrame* aFrame,
8075 : const char* aType,
8076 : nsSize& aResult)
8077 : : mFrame(aFrame)
8078 : , mType(aType)
8079 0 : , mResult(aResult)
8080 : {
8081 0 : MOZ_COUNT_CTOR(DR_intrinsic_size_cookie);
8082 0 : mValue = nsFrame::DisplayIntrinsicSizeEnter(mFrame, mType);
8083 0 : }
8084 :
8085 0 : DR_intrinsic_size_cookie::~DR_intrinsic_size_cookie()
8086 : {
8087 0 : MOZ_COUNT_DTOR(DR_intrinsic_size_cookie);
8088 0 : nsFrame::DisplayIntrinsicSizeExit(mFrame, mType, mResult, mValue);
8089 0 : }
8090 :
8091 0 : DR_init_constraints_cookie::DR_init_constraints_cookie(
8092 : nsIFrame* aFrame,
8093 : nsHTMLReflowState* aState,
8094 : nscoord aCBWidth,
8095 : nscoord aCBHeight,
8096 : const nsMargin* aMargin,
8097 : const nsMargin* aPadding)
8098 : : mFrame(aFrame)
8099 0 : , mState(aState)
8100 : {
8101 0 : MOZ_COUNT_CTOR(DR_init_constraints_cookie);
8102 : mValue = nsHTMLReflowState::DisplayInitConstraintsEnter(mFrame, mState,
8103 : aCBWidth, aCBHeight,
8104 0 : aMargin, aPadding);
8105 0 : }
8106 :
8107 0 : DR_init_constraints_cookie::~DR_init_constraints_cookie()
8108 : {
8109 0 : MOZ_COUNT_DTOR(DR_init_constraints_cookie);
8110 0 : nsHTMLReflowState::DisplayInitConstraintsExit(mFrame, mState, mValue);
8111 0 : }
8112 :
8113 0 : DR_init_offsets_cookie::DR_init_offsets_cookie(
8114 : nsIFrame* aFrame,
8115 : nsCSSOffsetState* aState,
8116 : nscoord aCBWidth,
8117 : const nsMargin* aMargin,
8118 : const nsMargin* aPadding)
8119 : : mFrame(aFrame)
8120 0 : , mState(aState)
8121 : {
8122 0 : MOZ_COUNT_CTOR(DR_init_offsets_cookie);
8123 : mValue = nsCSSOffsetState::DisplayInitOffsetsEnter(mFrame, mState, aCBWidth,
8124 0 : aMargin, aPadding);
8125 0 : }
8126 :
8127 0 : DR_init_offsets_cookie::~DR_init_offsets_cookie()
8128 : {
8129 0 : MOZ_COUNT_DTOR(DR_init_offsets_cookie);
8130 0 : nsCSSOffsetState::DisplayInitOffsetsExit(mFrame, mState, mValue);
8131 0 : }
8132 :
8133 0 : DR_init_type_cookie::DR_init_type_cookie(
8134 : nsIFrame* aFrame,
8135 : nsHTMLReflowState* aState)
8136 : : mFrame(aFrame)
8137 0 : , mState(aState)
8138 : {
8139 0 : MOZ_COUNT_CTOR(DR_init_type_cookie);
8140 0 : mValue = nsHTMLReflowState::DisplayInitFrameTypeEnter(mFrame, mState);
8141 0 : }
8142 :
8143 0 : DR_init_type_cookie::~DR_init_type_cookie()
8144 : {
8145 0 : MOZ_COUNT_DTOR(DR_init_type_cookie);
8146 0 : nsHTMLReflowState::DisplayInitFrameTypeExit(mFrame, mState, mValue);
8147 0 : }
8148 :
8149 : struct DR_FrameTypeInfo;
8150 : struct DR_FrameTreeNode;
8151 : struct DR_Rule;
8152 :
8153 : struct DR_State
8154 : {
8155 : DR_State();
8156 : ~DR_State();
8157 : void Init();
8158 : void AddFrameTypeInfo(nsIAtom* aFrameType,
8159 : const char* aFrameNameAbbrev,
8160 : const char* aFrameName);
8161 : DR_FrameTypeInfo* GetFrameTypeInfo(nsIAtom* aFrameType);
8162 : DR_FrameTypeInfo* GetFrameTypeInfo(char* aFrameName);
8163 : void InitFrameTypeTable();
8164 : DR_FrameTreeNode* CreateTreeNode(nsIFrame* aFrame,
8165 : const nsHTMLReflowState* aReflowState);
8166 : void FindMatchingRule(DR_FrameTreeNode& aNode);
8167 : bool RuleMatches(DR_Rule& aRule,
8168 : DR_FrameTreeNode& aNode);
8169 : bool GetToken(FILE* aFile,
8170 : char* aBuf,
8171 : size_t aBufSize);
8172 : DR_Rule* ParseRule(FILE* aFile);
8173 : void ParseRulesFile();
8174 : void AddRule(nsTArray<DR_Rule*>& aRules,
8175 : DR_Rule& aRule);
8176 : bool IsWhiteSpace(int c);
8177 : bool GetNumber(char* aBuf,
8178 : PRInt32& aNumber);
8179 : void PrettyUC(nscoord aSize,
8180 : char* aBuf);
8181 : void PrintMargin(const char* tag, const nsMargin* aMargin);
8182 : void DisplayFrameTypeInfo(nsIFrame* aFrame,
8183 : PRInt32 aIndent);
8184 : void DeleteTreeNode(DR_FrameTreeNode& aNode);
8185 :
8186 : bool mInited;
8187 : bool mActive;
8188 : PRInt32 mCount;
8189 : PRInt32 mAssert;
8190 : PRInt32 mIndent;
8191 : bool mIndentUndisplayedFrames;
8192 : bool mDisplayPixelErrors;
8193 : nsTArray<DR_Rule*> mWildRules;
8194 : nsTArray<DR_FrameTypeInfo> mFrameTypeTable;
8195 : // reflow specific state
8196 : nsTArray<DR_FrameTreeNode*> mFrameTreeLeaves;
8197 : };
8198 :
8199 : static DR_State *DR_state; // the one and only DR_State
8200 :
8201 : struct DR_RulePart
8202 : {
8203 0 : DR_RulePart(nsIAtom* aFrameType) : mFrameType(aFrameType), mNext(0) {}
8204 : void Destroy();
8205 :
8206 : nsIAtom* mFrameType;
8207 : DR_RulePart* mNext;
8208 : };
8209 :
8210 0 : void DR_RulePart::Destroy()
8211 : {
8212 0 : if (mNext) {
8213 0 : mNext->Destroy();
8214 : }
8215 : delete this;
8216 0 : }
8217 :
8218 : struct DR_Rule
8219 : {
8220 0 : DR_Rule() : mLength(0), mTarget(nsnull), mDisplay(false) {
8221 0 : MOZ_COUNT_CTOR(DR_Rule);
8222 0 : }
8223 0 : ~DR_Rule() {
8224 0 : if (mTarget) mTarget->Destroy();
8225 0 : MOZ_COUNT_DTOR(DR_Rule);
8226 0 : }
8227 : void AddPart(nsIAtom* aFrameType);
8228 :
8229 : PRUint32 mLength;
8230 : DR_RulePart* mTarget;
8231 : bool mDisplay;
8232 : };
8233 :
8234 0 : void DR_Rule::AddPart(nsIAtom* aFrameType)
8235 : {
8236 0 : DR_RulePart* newPart = new DR_RulePart(aFrameType);
8237 0 : newPart->mNext = mTarget;
8238 0 : mTarget = newPart;
8239 0 : mLength++;
8240 0 : }
8241 :
8242 : struct DR_FrameTypeInfo
8243 0 : {
8244 : DR_FrameTypeInfo(nsIAtom* aFrmeType, const char* aFrameNameAbbrev, const char* aFrameName);
8245 0 : ~DR_FrameTypeInfo() {
8246 : PRInt32 numElements;
8247 0 : numElements = mRules.Length();
8248 0 : for (PRInt32 i = numElements - 1; i >= 0; i--) {
8249 0 : delete mRules.ElementAt(i);
8250 : }
8251 0 : }
8252 :
8253 : nsIAtom* mType;
8254 : char mNameAbbrev[16];
8255 : char mName[32];
8256 : nsTArray<DR_Rule*> mRules;
8257 : private:
8258 : DR_FrameTypeInfo& operator=(const DR_FrameTypeInfo&) MOZ_DELETE;
8259 : };
8260 :
8261 0 : DR_FrameTypeInfo::DR_FrameTypeInfo(nsIAtom* aFrameType,
8262 : const char* aFrameNameAbbrev,
8263 0 : const char* aFrameName)
8264 : {
8265 0 : mType = aFrameType;
8266 0 : PL_strncpyz(mNameAbbrev, aFrameNameAbbrev, sizeof(mNameAbbrev));
8267 0 : PL_strncpyz(mName, aFrameName, sizeof(mName));
8268 0 : }
8269 :
8270 : struct DR_FrameTreeNode
8271 : {
8272 0 : DR_FrameTreeNode(nsIFrame* aFrame, DR_FrameTreeNode* aParent) : mFrame(aFrame), mParent(aParent), mDisplay(0), mIndent(0)
8273 : {
8274 0 : MOZ_COUNT_CTOR(DR_FrameTreeNode);
8275 0 : }
8276 :
8277 0 : ~DR_FrameTreeNode()
8278 : {
8279 0 : MOZ_COUNT_DTOR(DR_FrameTreeNode);
8280 0 : }
8281 :
8282 : nsIFrame* mFrame;
8283 : DR_FrameTreeNode* mParent;
8284 : bool mDisplay;
8285 : PRUint32 mIndent;
8286 : };
8287 :
8288 : // DR_State implementation
8289 :
8290 1404 : DR_State::DR_State()
8291 : : mInited(false), mActive(false), mCount(0), mAssert(-1), mIndent(0),
8292 1404 : mIndentUndisplayedFrames(false), mDisplayPixelErrors(false)
8293 : {
8294 1404 : MOZ_COUNT_CTOR(DR_State);
8295 1404 : }
8296 :
8297 0 : void DR_State::Init()
8298 : {
8299 0 : char* env = PR_GetEnv("GECKO_DISPLAY_REFLOW_ASSERT");
8300 : PRInt32 num;
8301 0 : if (env) {
8302 0 : if (GetNumber(env, num))
8303 0 : mAssert = num;
8304 : else
8305 0 : printf("GECKO_DISPLAY_REFLOW_ASSERT - invalid value = %s", env);
8306 : }
8307 :
8308 0 : env = PR_GetEnv("GECKO_DISPLAY_REFLOW_INDENT_START");
8309 0 : if (env) {
8310 0 : if (GetNumber(env, num))
8311 0 : mIndent = num;
8312 : else
8313 0 : printf("GECKO_DISPLAY_REFLOW_INDENT_START - invalid value = %s", env);
8314 : }
8315 :
8316 0 : env = PR_GetEnv("GECKO_DISPLAY_REFLOW_INDENT_UNDISPLAYED_FRAMES");
8317 0 : if (env) {
8318 0 : if (GetNumber(env, num))
8319 0 : mIndentUndisplayedFrames = num;
8320 : else
8321 0 : printf("GECKO_DISPLAY_REFLOW_INDENT_UNDISPLAYED_FRAMES - invalid value = %s", env);
8322 : }
8323 :
8324 0 : env = PR_GetEnv("GECKO_DISPLAY_REFLOW_FLAG_PIXEL_ERRORS");
8325 0 : if (env) {
8326 0 : if (GetNumber(env, num))
8327 0 : mDisplayPixelErrors = num;
8328 : else
8329 0 : printf("GECKO_DISPLAY_REFLOW_FLAG_PIXEL_ERRORS - invalid value = %s", env);
8330 : }
8331 :
8332 0 : InitFrameTypeTable();
8333 0 : ParseRulesFile();
8334 0 : mInited = true;
8335 0 : }
8336 :
8337 2806 : DR_State::~DR_State()
8338 : {
8339 1403 : MOZ_COUNT_DTOR(DR_State);
8340 : PRInt32 numElements, i;
8341 1403 : numElements = mWildRules.Length();
8342 1403 : for (i = numElements - 1; i >= 0; i--) {
8343 0 : delete mWildRules.ElementAt(i);
8344 : }
8345 1403 : numElements = mFrameTreeLeaves.Length();
8346 1403 : for (i = numElements - 1; i >= 0; i--) {
8347 0 : delete mFrameTreeLeaves.ElementAt(i);
8348 : }
8349 1403 : }
8350 :
8351 0 : bool DR_State::GetNumber(char* aBuf,
8352 : PRInt32& aNumber)
8353 : {
8354 0 : if (sscanf(aBuf, "%d", &aNumber) > 0)
8355 0 : return true;
8356 : else
8357 0 : return false;
8358 : }
8359 :
8360 0 : bool DR_State::IsWhiteSpace(int c) {
8361 0 : return (c == ' ') || (c == '\t') || (c == '\n') || (c == '\r');
8362 : }
8363 :
8364 0 : bool DR_State::GetToken(FILE* aFile,
8365 : char* aBuf,
8366 : size_t aBufSize)
8367 : {
8368 0 : bool haveToken = false;
8369 0 : aBuf[0] = 0;
8370 : // get the 1st non whitespace char
8371 0 : int c = -1;
8372 0 : for (c = getc(aFile); (c > 0) && IsWhiteSpace(c); c = getc(aFile)) {
8373 : }
8374 :
8375 0 : if (c > 0) {
8376 0 : haveToken = true;
8377 0 : aBuf[0] = c;
8378 : // get everything up to the next whitespace char
8379 : size_t cX;
8380 0 : for (cX = 1; cX + 1 < aBufSize ; cX++) {
8381 0 : c = getc(aFile);
8382 0 : if (c < 0) { // EOF
8383 0 : ungetc(' ', aFile);
8384 0 : break;
8385 : }
8386 : else {
8387 0 : if (IsWhiteSpace(c)) {
8388 0 : break;
8389 : }
8390 : else {
8391 0 : aBuf[cX] = c;
8392 : }
8393 : }
8394 : }
8395 0 : aBuf[cX] = 0;
8396 : }
8397 0 : return haveToken;
8398 : }
8399 :
8400 0 : DR_Rule* DR_State::ParseRule(FILE* aFile)
8401 : {
8402 : char buf[128];
8403 : PRInt32 doDisplay;
8404 0 : DR_Rule* rule = nsnull;
8405 0 : while (GetToken(aFile, buf, sizeof(buf))) {
8406 0 : if (GetNumber(buf, doDisplay)) {
8407 0 : if (rule) {
8408 0 : rule->mDisplay = !!doDisplay;
8409 0 : break;
8410 : }
8411 : else {
8412 0 : printf("unexpected token - %s \n", buf);
8413 : }
8414 : }
8415 : else {
8416 0 : if (!rule) {
8417 0 : rule = new DR_Rule;
8418 : }
8419 0 : if (strcmp(buf, "*") == 0) {
8420 0 : rule->AddPart(nsnull);
8421 : }
8422 : else {
8423 0 : DR_FrameTypeInfo* info = GetFrameTypeInfo(buf);
8424 0 : if (info) {
8425 0 : rule->AddPart(info->mType);
8426 : }
8427 : else {
8428 0 : printf("invalid frame type - %s \n", buf);
8429 : }
8430 : }
8431 : }
8432 : }
8433 0 : return rule;
8434 : }
8435 :
8436 0 : void DR_State::AddRule(nsTArray<DR_Rule*>& aRules,
8437 : DR_Rule& aRule)
8438 : {
8439 0 : PRInt32 numRules = aRules.Length();
8440 0 : for (PRInt32 ruleX = 0; ruleX < numRules; ruleX++) {
8441 0 : DR_Rule* rule = aRules.ElementAt(ruleX);
8442 0 : NS_ASSERTION(rule, "program error");
8443 0 : if (aRule.mLength > rule->mLength) {
8444 0 : aRules.InsertElementAt(ruleX, &aRule);
8445 0 : return;
8446 : }
8447 : }
8448 0 : aRules.AppendElement(&aRule);
8449 : }
8450 :
8451 0 : void DR_State::ParseRulesFile()
8452 : {
8453 0 : char* path = PR_GetEnv("GECKO_DISPLAY_REFLOW_RULES_FILE");
8454 0 : if (path) {
8455 0 : FILE* inFile = fopen(path, "r");
8456 0 : if (inFile) {
8457 0 : for (DR_Rule* rule = ParseRule(inFile); rule; rule = ParseRule(inFile)) {
8458 0 : if (rule->mTarget) {
8459 0 : nsIAtom* fType = rule->mTarget->mFrameType;
8460 0 : if (fType) {
8461 0 : DR_FrameTypeInfo* info = GetFrameTypeInfo(fType);
8462 0 : if (info) {
8463 0 : AddRule(info->mRules, *rule);
8464 : }
8465 : }
8466 : else {
8467 0 : AddRule(mWildRules, *rule);
8468 : }
8469 0 : mActive = true;
8470 : }
8471 : }
8472 : }
8473 : }
8474 0 : }
8475 :
8476 :
8477 0 : void DR_State::AddFrameTypeInfo(nsIAtom* aFrameType,
8478 : const char* aFrameNameAbbrev,
8479 : const char* aFrameName)
8480 : {
8481 0 : mFrameTypeTable.AppendElement(DR_FrameTypeInfo(aFrameType, aFrameNameAbbrev, aFrameName));
8482 0 : }
8483 :
8484 0 : DR_FrameTypeInfo* DR_State::GetFrameTypeInfo(nsIAtom* aFrameType)
8485 : {
8486 0 : PRInt32 numEntries = mFrameTypeTable.Length();
8487 0 : NS_ASSERTION(numEntries != 0, "empty FrameTypeTable");
8488 0 : for (PRInt32 i = 0; i < numEntries; i++) {
8489 0 : DR_FrameTypeInfo& info = mFrameTypeTable.ElementAt(i);
8490 0 : if (info.mType == aFrameType) {
8491 0 : return &info;
8492 : }
8493 : }
8494 0 : return &mFrameTypeTable.ElementAt(numEntries - 1); // return unknown frame type
8495 : }
8496 :
8497 0 : DR_FrameTypeInfo* DR_State::GetFrameTypeInfo(char* aFrameName)
8498 : {
8499 0 : PRInt32 numEntries = mFrameTypeTable.Length();
8500 0 : NS_ASSERTION(numEntries != 0, "empty FrameTypeTable");
8501 0 : for (PRInt32 i = 0; i < numEntries; i++) {
8502 0 : DR_FrameTypeInfo& info = mFrameTypeTable.ElementAt(i);
8503 0 : if ((strcmp(aFrameName, info.mName) == 0) || (strcmp(aFrameName, info.mNameAbbrev) == 0)) {
8504 0 : return &info;
8505 : }
8506 : }
8507 0 : return &mFrameTypeTable.ElementAt(numEntries - 1); // return unknown frame type
8508 : }
8509 :
8510 0 : void DR_State::InitFrameTypeTable()
8511 : {
8512 0 : AddFrameTypeInfo(nsGkAtoms::blockFrame, "block", "block");
8513 0 : AddFrameTypeInfo(nsGkAtoms::brFrame, "br", "br");
8514 0 : AddFrameTypeInfo(nsGkAtoms::bulletFrame, "bullet", "bullet");
8515 0 : AddFrameTypeInfo(nsGkAtoms::gfxButtonControlFrame, "button", "gfxButtonControl");
8516 0 : AddFrameTypeInfo(nsGkAtoms::HTMLButtonControlFrame, "HTMLbutton", "HTMLButtonControl");
8517 0 : AddFrameTypeInfo(nsGkAtoms::HTMLCanvasFrame, "HTMLCanvas","HTMLCanvas");
8518 0 : AddFrameTypeInfo(nsGkAtoms::subDocumentFrame, "subdoc", "subDocument");
8519 0 : AddFrameTypeInfo(nsGkAtoms::imageFrame, "img", "image");
8520 0 : AddFrameTypeInfo(nsGkAtoms::inlineFrame, "inline", "inline");
8521 0 : AddFrameTypeInfo(nsGkAtoms::letterFrame, "letter", "letter");
8522 0 : AddFrameTypeInfo(nsGkAtoms::lineFrame, "line", "line");
8523 0 : AddFrameTypeInfo(nsGkAtoms::listControlFrame, "select", "select");
8524 0 : AddFrameTypeInfo(nsGkAtoms::objectFrame, "obj", "object");
8525 0 : AddFrameTypeInfo(nsGkAtoms::pageFrame, "page", "page");
8526 0 : AddFrameTypeInfo(nsGkAtoms::placeholderFrame, "place", "placeholder");
8527 0 : AddFrameTypeInfo(nsGkAtoms::canvasFrame, "canvas", "canvas");
8528 0 : AddFrameTypeInfo(nsGkAtoms::rootFrame, "root", "root");
8529 0 : AddFrameTypeInfo(nsGkAtoms::scrollFrame, "scroll", "scroll");
8530 0 : AddFrameTypeInfo(nsGkAtoms::tableCaptionFrame, "caption", "tableCaption");
8531 0 : AddFrameTypeInfo(nsGkAtoms::tableCellFrame, "cell", "tableCell");
8532 0 : AddFrameTypeInfo(nsGkAtoms::bcTableCellFrame, "bcCell", "bcTableCell");
8533 0 : AddFrameTypeInfo(nsGkAtoms::tableColFrame, "col", "tableCol");
8534 0 : AddFrameTypeInfo(nsGkAtoms::tableColGroupFrame, "colG", "tableColGroup");
8535 0 : AddFrameTypeInfo(nsGkAtoms::tableFrame, "tbl", "table");
8536 0 : AddFrameTypeInfo(nsGkAtoms::tableOuterFrame, "tblO", "tableOuter");
8537 0 : AddFrameTypeInfo(nsGkAtoms::tableRowGroupFrame, "rowG", "tableRowGroup");
8538 0 : AddFrameTypeInfo(nsGkAtoms::tableRowFrame, "row", "tableRow");
8539 0 : AddFrameTypeInfo(nsGkAtoms::textInputFrame, "textCtl", "textInput");
8540 0 : AddFrameTypeInfo(nsGkAtoms::textFrame, "text", "text");
8541 0 : AddFrameTypeInfo(nsGkAtoms::viewportFrame, "VP", "viewport");
8542 : #ifdef MOZ_XUL
8543 0 : AddFrameTypeInfo(nsGkAtoms::XULLabelFrame, "XULLabel", "XULLabel");
8544 0 : AddFrameTypeInfo(nsGkAtoms::boxFrame, "Box", "Box");
8545 0 : AddFrameTypeInfo(nsGkAtoms::sliderFrame, "Slider", "Slider");
8546 0 : AddFrameTypeInfo(nsGkAtoms::popupSetFrame, "PopupSet", "PopupSet");
8547 : #endif
8548 0 : AddFrameTypeInfo(nsnull, "unknown", "unknown");
8549 0 : }
8550 :
8551 :
8552 0 : void DR_State::DisplayFrameTypeInfo(nsIFrame* aFrame,
8553 : PRInt32 aIndent)
8554 : {
8555 0 : DR_FrameTypeInfo* frameTypeInfo = GetFrameTypeInfo(aFrame->GetType());
8556 0 : if (frameTypeInfo) {
8557 0 : for (PRInt32 i = 0; i < aIndent; i++) {
8558 0 : printf(" ");
8559 : }
8560 0 : if(!strcmp(frameTypeInfo->mNameAbbrev, "unknown")) {
8561 0 : if (aFrame) {
8562 0 : nsAutoString name;
8563 0 : aFrame->GetFrameName(name);
8564 0 : printf("%s %p ", NS_LossyConvertUTF16toASCII(name).get(), (void*)aFrame);
8565 : }
8566 : else {
8567 0 : printf("%s %p ", frameTypeInfo->mNameAbbrev, (void*)aFrame);
8568 : }
8569 : }
8570 : else {
8571 0 : printf("%s %p ", frameTypeInfo->mNameAbbrev, (void*)aFrame);
8572 : }
8573 : }
8574 0 : }
8575 :
8576 0 : bool DR_State::RuleMatches(DR_Rule& aRule,
8577 : DR_FrameTreeNode& aNode)
8578 : {
8579 0 : NS_ASSERTION(aRule.mTarget, "program error");
8580 :
8581 : DR_RulePart* rulePart;
8582 : DR_FrameTreeNode* parentNode;
8583 0 : for (rulePart = aRule.mTarget->mNext, parentNode = aNode.mParent;
8584 : rulePart && parentNode;
8585 : rulePart = rulePart->mNext, parentNode = parentNode->mParent) {
8586 0 : if (rulePart->mFrameType) {
8587 0 : if (parentNode->mFrame) {
8588 0 : if (rulePart->mFrameType != parentNode->mFrame->GetType()) {
8589 0 : return false;
8590 : }
8591 : }
8592 0 : else NS_ASSERTION(false, "program error");
8593 : }
8594 : // else wild card match
8595 : }
8596 0 : return true;
8597 : }
8598 :
8599 0 : void DR_State::FindMatchingRule(DR_FrameTreeNode& aNode)
8600 : {
8601 0 : if (!aNode.mFrame) {
8602 0 : NS_ASSERTION(false, "invalid DR_FrameTreeNode \n");
8603 0 : return;
8604 : }
8605 :
8606 0 : bool matchingRule = false;
8607 :
8608 0 : DR_FrameTypeInfo* info = GetFrameTypeInfo(aNode.mFrame->GetType());
8609 0 : NS_ASSERTION(info, "program error");
8610 0 : PRInt32 numRules = info->mRules.Length();
8611 0 : for (PRInt32 ruleX = 0; ruleX < numRules; ruleX++) {
8612 0 : DR_Rule* rule = info->mRules.ElementAt(ruleX);
8613 0 : if (rule && RuleMatches(*rule, aNode)) {
8614 0 : aNode.mDisplay = rule->mDisplay;
8615 0 : matchingRule = true;
8616 0 : break;
8617 : }
8618 : }
8619 0 : if (!matchingRule) {
8620 0 : PRInt32 numWildRules = mWildRules.Length();
8621 0 : for (PRInt32 ruleX = 0; ruleX < numWildRules; ruleX++) {
8622 0 : DR_Rule* rule = mWildRules.ElementAt(ruleX);
8623 0 : if (rule && RuleMatches(*rule, aNode)) {
8624 0 : aNode.mDisplay = rule->mDisplay;
8625 0 : break;
8626 : }
8627 : }
8628 : }
8629 : }
8630 :
8631 0 : DR_FrameTreeNode* DR_State::CreateTreeNode(nsIFrame* aFrame,
8632 : const nsHTMLReflowState* aReflowState)
8633 : {
8634 : // find the frame of the parent reflow state (usually just the parent of aFrame)
8635 : nsIFrame* parentFrame;
8636 0 : if (aReflowState) {
8637 0 : const nsHTMLReflowState* parentRS = aReflowState->parentReflowState;
8638 0 : parentFrame = (parentRS) ? parentRS->frame : nsnull;
8639 : } else {
8640 0 : parentFrame = aFrame->GetParent();
8641 : }
8642 :
8643 : // find the parent tree node leaf
8644 0 : DR_FrameTreeNode* parentNode = nsnull;
8645 :
8646 0 : DR_FrameTreeNode* lastLeaf = nsnull;
8647 0 : if(mFrameTreeLeaves.Length())
8648 0 : lastLeaf = mFrameTreeLeaves.ElementAt(mFrameTreeLeaves.Length() - 1);
8649 0 : if (lastLeaf) {
8650 0 : for (parentNode = lastLeaf; parentNode && (parentNode->mFrame != parentFrame); parentNode = parentNode->mParent) {
8651 : }
8652 : }
8653 0 : DR_FrameTreeNode* newNode = new DR_FrameTreeNode(aFrame, parentNode);
8654 0 : FindMatchingRule(*newNode);
8655 :
8656 0 : newNode->mIndent = mIndent;
8657 0 : if (newNode->mDisplay || mIndentUndisplayedFrames) {
8658 0 : ++mIndent;
8659 : }
8660 :
8661 0 : if (lastLeaf && (lastLeaf == parentNode)) {
8662 0 : mFrameTreeLeaves.RemoveElementAt(mFrameTreeLeaves.Length() - 1);
8663 : }
8664 0 : mFrameTreeLeaves.AppendElement(newNode);
8665 0 : mCount++;
8666 :
8667 0 : return newNode;
8668 : }
8669 :
8670 0 : void DR_State::PrettyUC(nscoord aSize,
8671 : char* aBuf)
8672 : {
8673 0 : if (NS_UNCONSTRAINEDSIZE == aSize) {
8674 0 : strcpy(aBuf, "UC");
8675 : }
8676 : else {
8677 0 : if ((nscoord)0xdeadbeefU == aSize)
8678 : {
8679 0 : strcpy(aBuf, "deadbeef");
8680 : }
8681 : else {
8682 0 : sprintf(aBuf, "%d", aSize);
8683 : }
8684 : }
8685 0 : }
8686 :
8687 0 : void DR_State::PrintMargin(const char *tag, const nsMargin* aMargin)
8688 : {
8689 0 : if (aMargin) {
8690 : char t[16], r[16], b[16], l[16];
8691 0 : PrettyUC(aMargin->top, t);
8692 0 : PrettyUC(aMargin->right, r);
8693 0 : PrettyUC(aMargin->bottom, b);
8694 0 : PrettyUC(aMargin->left, l);
8695 0 : printf(" %s=%s,%s,%s,%s", tag, t, r, b, l);
8696 : } else {
8697 : // use %p here for consistency with other null-pointer printouts
8698 0 : printf(" %s=%p", tag, (void*)aMargin);
8699 : }
8700 0 : }
8701 :
8702 0 : void DR_State::DeleteTreeNode(DR_FrameTreeNode& aNode)
8703 : {
8704 0 : mFrameTreeLeaves.RemoveElement(&aNode);
8705 0 : PRInt32 numLeaves = mFrameTreeLeaves.Length();
8706 0 : if ((0 == numLeaves) || (aNode.mParent != mFrameTreeLeaves.ElementAt(numLeaves - 1))) {
8707 0 : mFrameTreeLeaves.AppendElement(aNode.mParent);
8708 : }
8709 :
8710 0 : if (aNode.mDisplay || mIndentUndisplayedFrames) {
8711 0 : --mIndent;
8712 : }
8713 : // delete the tree node
8714 0 : delete &aNode;
8715 0 : }
8716 :
8717 : static void
8718 0 : CheckPixelError(nscoord aSize,
8719 : PRInt32 aPixelToTwips)
8720 : {
8721 0 : if (NS_UNCONSTRAINEDSIZE != aSize) {
8722 0 : if ((aSize % aPixelToTwips) > 0) {
8723 0 : printf("VALUE %d is not a whole pixel \n", aSize);
8724 : }
8725 : }
8726 0 : }
8727 :
8728 0 : static void DisplayReflowEnterPrint(nsPresContext* aPresContext,
8729 : nsIFrame* aFrame,
8730 : const nsHTMLReflowState& aReflowState,
8731 : DR_FrameTreeNode& aTreeNode,
8732 : bool aChanged)
8733 : {
8734 0 : if (aTreeNode.mDisplay) {
8735 0 : DR_state->DisplayFrameTypeInfo(aFrame, aTreeNode.mIndent);
8736 :
8737 : char width[16];
8738 : char height[16];
8739 :
8740 0 : DR_state->PrettyUC(aReflowState.availableWidth, width);
8741 0 : DR_state->PrettyUC(aReflowState.availableHeight, height);
8742 0 : printf("Reflow a=%s,%s ", width, height);
8743 :
8744 0 : DR_state->PrettyUC(aReflowState.ComputedWidth(), width);
8745 0 : DR_state->PrettyUC(aReflowState.ComputedHeight(), height);
8746 0 : printf("c=%s,%s ", width, height);
8747 :
8748 0 : if (aFrame->GetStateBits() & NS_FRAME_IS_DIRTY)
8749 0 : printf("dirty ");
8750 :
8751 0 : if (aFrame->GetStateBits() & NS_FRAME_HAS_DIRTY_CHILDREN)
8752 0 : printf("dirty-children ");
8753 :
8754 0 : if (aReflowState.mFlags.mSpecialHeightReflow)
8755 0 : printf("special-height ");
8756 :
8757 0 : if (aReflowState.mFlags.mHResize)
8758 0 : printf("h-resize ");
8759 :
8760 0 : if (aReflowState.mFlags.mVResize)
8761 0 : printf("v-resize ");
8762 :
8763 0 : nsIFrame* inFlow = aFrame->GetPrevInFlow();
8764 0 : if (inFlow) {
8765 0 : printf("pif=%p ", (void*)inFlow);
8766 : }
8767 0 : inFlow = aFrame->GetNextInFlow();
8768 0 : if (inFlow) {
8769 0 : printf("nif=%p ", (void*)inFlow);
8770 : }
8771 0 : if (aChanged)
8772 0 : printf("CHANGED \n");
8773 : else
8774 0 : printf("cnt=%d \n", DR_state->mCount);
8775 0 : if (DR_state->mDisplayPixelErrors) {
8776 0 : PRInt32 p2t = aPresContext->AppUnitsPerDevPixel();
8777 0 : CheckPixelError(aReflowState.availableWidth, p2t);
8778 0 : CheckPixelError(aReflowState.availableHeight, p2t);
8779 0 : CheckPixelError(aReflowState.ComputedWidth(), p2t);
8780 0 : CheckPixelError(aReflowState.ComputedHeight(), p2t);
8781 : }
8782 : }
8783 0 : }
8784 :
8785 0 : void* nsFrame::DisplayReflowEnter(nsPresContext* aPresContext,
8786 : nsIFrame* aFrame,
8787 : const nsHTMLReflowState& aReflowState)
8788 : {
8789 0 : if (!DR_state->mInited) DR_state->Init();
8790 0 : if (!DR_state->mActive) return nsnull;
8791 :
8792 0 : NS_ASSERTION(aFrame, "invalid call");
8793 :
8794 0 : DR_FrameTreeNode* treeNode = DR_state->CreateTreeNode(aFrame, &aReflowState);
8795 0 : if (treeNode) {
8796 0 : DisplayReflowEnterPrint(aPresContext, aFrame, aReflowState, *treeNode, false);
8797 : }
8798 0 : return treeNode;
8799 : }
8800 :
8801 0 : void* nsFrame::DisplayLayoutEnter(nsIFrame* aFrame)
8802 : {
8803 0 : if (!DR_state->mInited) DR_state->Init();
8804 0 : if (!DR_state->mActive) return nsnull;
8805 :
8806 0 : NS_ASSERTION(aFrame, "invalid call");
8807 :
8808 0 : DR_FrameTreeNode* treeNode = DR_state->CreateTreeNode(aFrame, nsnull);
8809 0 : if (treeNode && treeNode->mDisplay) {
8810 0 : DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
8811 0 : printf("Layout\n");
8812 : }
8813 0 : return treeNode;
8814 : }
8815 :
8816 0 : void* nsFrame::DisplayIntrinsicWidthEnter(nsIFrame* aFrame,
8817 : const char* aType)
8818 : {
8819 0 : if (!DR_state->mInited) DR_state->Init();
8820 0 : if (!DR_state->mActive) return nsnull;
8821 :
8822 0 : NS_ASSERTION(aFrame, "invalid call");
8823 :
8824 0 : DR_FrameTreeNode* treeNode = DR_state->CreateTreeNode(aFrame, nsnull);
8825 0 : if (treeNode && treeNode->mDisplay) {
8826 0 : DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
8827 0 : printf("Get%sWidth\n", aType);
8828 : }
8829 0 : return treeNode;
8830 : }
8831 :
8832 0 : void* nsFrame::DisplayIntrinsicSizeEnter(nsIFrame* aFrame,
8833 : const char* aType)
8834 : {
8835 0 : if (!DR_state->mInited) DR_state->Init();
8836 0 : if (!DR_state->mActive) return nsnull;
8837 :
8838 0 : NS_ASSERTION(aFrame, "invalid call");
8839 :
8840 0 : DR_FrameTreeNode* treeNode = DR_state->CreateTreeNode(aFrame, nsnull);
8841 0 : if (treeNode && treeNode->mDisplay) {
8842 0 : DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
8843 0 : printf("Get%sSize\n", aType);
8844 : }
8845 0 : return treeNode;
8846 : }
8847 :
8848 0 : void nsFrame::DisplayReflowExit(nsPresContext* aPresContext,
8849 : nsIFrame* aFrame,
8850 : nsHTMLReflowMetrics& aMetrics,
8851 : nsReflowStatus aStatus,
8852 : void* aFrameTreeNode)
8853 : {
8854 0 : if (!DR_state->mActive) return;
8855 :
8856 0 : NS_ASSERTION(aFrame, "DisplayReflowExit - invalid call");
8857 0 : if (!aFrameTreeNode) return;
8858 :
8859 0 : DR_FrameTreeNode* treeNode = (DR_FrameTreeNode*)aFrameTreeNode;
8860 0 : if (treeNode->mDisplay) {
8861 0 : DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
8862 :
8863 : char width[16];
8864 : char height[16];
8865 : char x[16];
8866 : char y[16];
8867 0 : DR_state->PrettyUC(aMetrics.width, width);
8868 0 : DR_state->PrettyUC(aMetrics.height, height);
8869 0 : printf("Reflow d=%s,%s", width, height);
8870 :
8871 0 : if (!NS_FRAME_IS_FULLY_COMPLETE(aStatus)) {
8872 0 : printf(" status=0x%x", aStatus);
8873 : }
8874 0 : if (aFrame->HasOverflowAreas()) {
8875 0 : DR_state->PrettyUC(aMetrics.VisualOverflow().x, x);
8876 0 : DR_state->PrettyUC(aMetrics.VisualOverflow().y, y);
8877 0 : DR_state->PrettyUC(aMetrics.VisualOverflow().width, width);
8878 0 : DR_state->PrettyUC(aMetrics.VisualOverflow().height, height);
8879 0 : printf(" vis-o=(%s,%s) %s x %s", x, y, width, height);
8880 :
8881 0 : nsRect storedOverflow = aFrame->GetVisualOverflowRect();
8882 0 : DR_state->PrettyUC(storedOverflow.x, x);
8883 0 : DR_state->PrettyUC(storedOverflow.y, y);
8884 0 : DR_state->PrettyUC(storedOverflow.width, width);
8885 0 : DR_state->PrettyUC(storedOverflow.height, height);
8886 0 : printf(" vis-sto=(%s,%s) %s x %s", x, y, width, height);
8887 :
8888 0 : DR_state->PrettyUC(aMetrics.ScrollableOverflow().x, x);
8889 0 : DR_state->PrettyUC(aMetrics.ScrollableOverflow().y, y);
8890 0 : DR_state->PrettyUC(aMetrics.ScrollableOverflow().width, width);
8891 0 : DR_state->PrettyUC(aMetrics.ScrollableOverflow().height, height);
8892 0 : printf(" scr-o=(%s,%s) %s x %s", x, y, width, height);
8893 :
8894 0 : storedOverflow = aFrame->GetScrollableOverflowRect();
8895 0 : DR_state->PrettyUC(storedOverflow.x, x);
8896 0 : DR_state->PrettyUC(storedOverflow.y, y);
8897 0 : DR_state->PrettyUC(storedOverflow.width, width);
8898 0 : DR_state->PrettyUC(storedOverflow.height, height);
8899 0 : printf(" scr-sto=(%s,%s) %s x %s", x, y, width, height);
8900 : }
8901 0 : printf("\n");
8902 0 : if (DR_state->mDisplayPixelErrors) {
8903 0 : PRInt32 p2t = aPresContext->AppUnitsPerDevPixel();
8904 0 : CheckPixelError(aMetrics.width, p2t);
8905 0 : CheckPixelError(aMetrics.height, p2t);
8906 : }
8907 : }
8908 0 : DR_state->DeleteTreeNode(*treeNode);
8909 : }
8910 :
8911 0 : void nsFrame::DisplayLayoutExit(nsIFrame* aFrame,
8912 : void* aFrameTreeNode)
8913 : {
8914 0 : if (!DR_state->mActive) return;
8915 :
8916 0 : NS_ASSERTION(aFrame, "non-null frame required");
8917 0 : if (!aFrameTreeNode) return;
8918 :
8919 0 : DR_FrameTreeNode* treeNode = (DR_FrameTreeNode*)aFrameTreeNode;
8920 0 : if (treeNode->mDisplay) {
8921 0 : DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
8922 0 : nsRect rect = aFrame->GetRect();
8923 0 : printf("Layout=%d,%d,%d,%d\n", rect.x, rect.y, rect.width, rect.height);
8924 : }
8925 0 : DR_state->DeleteTreeNode(*treeNode);
8926 : }
8927 :
8928 0 : void nsFrame::DisplayIntrinsicWidthExit(nsIFrame* aFrame,
8929 : const char* aType,
8930 : nscoord aResult,
8931 : void* aFrameTreeNode)
8932 : {
8933 0 : if (!DR_state->mActive) return;
8934 :
8935 0 : NS_ASSERTION(aFrame, "non-null frame required");
8936 0 : if (!aFrameTreeNode) return;
8937 :
8938 0 : DR_FrameTreeNode* treeNode = (DR_FrameTreeNode*)aFrameTreeNode;
8939 0 : if (treeNode->mDisplay) {
8940 0 : DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
8941 : char width[16];
8942 0 : DR_state->PrettyUC(aResult, width);
8943 0 : printf("Get%sWidth=%s\n", aType, width);
8944 : }
8945 0 : DR_state->DeleteTreeNode(*treeNode);
8946 : }
8947 :
8948 0 : void nsFrame::DisplayIntrinsicSizeExit(nsIFrame* aFrame,
8949 : const char* aType,
8950 : nsSize aResult,
8951 : void* aFrameTreeNode)
8952 : {
8953 0 : if (!DR_state->mActive) return;
8954 :
8955 0 : NS_ASSERTION(aFrame, "non-null frame required");
8956 0 : if (!aFrameTreeNode) return;
8957 :
8958 0 : DR_FrameTreeNode* treeNode = (DR_FrameTreeNode*)aFrameTreeNode;
8959 0 : if (treeNode->mDisplay) {
8960 0 : DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
8961 :
8962 : char width[16];
8963 : char height[16];
8964 0 : DR_state->PrettyUC(aResult.width, width);
8965 0 : DR_state->PrettyUC(aResult.height, height);
8966 0 : printf("Get%sSize=%s,%s\n", aType, width, height);
8967 : }
8968 0 : DR_state->DeleteTreeNode(*treeNode);
8969 : }
8970 :
8971 : /* static */ void
8972 1404 : nsFrame::DisplayReflowStartup()
8973 : {
8974 1404 : DR_state = new DR_State();
8975 1404 : }
8976 :
8977 : /* static */ void
8978 1403 : nsFrame::DisplayReflowShutdown()
8979 : {
8980 1403 : delete DR_state;
8981 1403 : DR_state = nsnull;
8982 1403 : }
8983 :
8984 0 : void DR_cookie::Change() const
8985 : {
8986 0 : DR_FrameTreeNode* treeNode = (DR_FrameTreeNode*)mValue;
8987 0 : if (treeNode && treeNode->mDisplay) {
8988 0 : DisplayReflowEnterPrint(mPresContext, mFrame, mReflowState, *treeNode, true);
8989 : }
8990 0 : }
8991 :
8992 : /* static */ void*
8993 0 : nsHTMLReflowState::DisplayInitConstraintsEnter(nsIFrame* aFrame,
8994 : nsHTMLReflowState* aState,
8995 : nscoord aContainingBlockWidth,
8996 : nscoord aContainingBlockHeight,
8997 : const nsMargin* aBorder,
8998 : const nsMargin* aPadding)
8999 : {
9000 0 : NS_PRECONDITION(aFrame, "non-null frame required");
9001 0 : NS_PRECONDITION(aState, "non-null state required");
9002 :
9003 0 : if (!DR_state->mInited) DR_state->Init();
9004 0 : if (!DR_state->mActive) return nsnull;
9005 :
9006 0 : DR_FrameTreeNode* treeNode = DR_state->CreateTreeNode(aFrame, aState);
9007 0 : if (treeNode && treeNode->mDisplay) {
9008 0 : DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
9009 :
9010 : printf("InitConstraints parent=%p",
9011 0 : (void*)aState->parentReflowState);
9012 :
9013 : char width[16];
9014 : char height[16];
9015 :
9016 0 : DR_state->PrettyUC(aContainingBlockWidth, width);
9017 0 : DR_state->PrettyUC(aContainingBlockHeight, height);
9018 0 : printf(" cb=%s,%s", width, height);
9019 :
9020 0 : DR_state->PrettyUC(aState->availableWidth, width);
9021 0 : DR_state->PrettyUC(aState->availableHeight, height);
9022 0 : printf(" as=%s,%s", width, height);
9023 :
9024 0 : DR_state->PrintMargin("b", aBorder);
9025 0 : DR_state->PrintMargin("p", aPadding);
9026 0 : putchar('\n');
9027 : }
9028 0 : return treeNode;
9029 : }
9030 :
9031 : /* static */ void
9032 0 : nsHTMLReflowState::DisplayInitConstraintsExit(nsIFrame* aFrame,
9033 : nsHTMLReflowState* aState,
9034 : void* aValue)
9035 : {
9036 0 : NS_PRECONDITION(aFrame, "non-null frame required");
9037 0 : NS_PRECONDITION(aState, "non-null state required");
9038 :
9039 0 : if (!DR_state->mActive) return;
9040 0 : if (!aValue) return;
9041 :
9042 0 : DR_FrameTreeNode* treeNode = (DR_FrameTreeNode*)aValue;
9043 0 : if (treeNode->mDisplay) {
9044 0 : DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
9045 : char cmiw[16], cw[16], cmxw[16], cmih[16], ch[16], cmxh[16];
9046 0 : DR_state->PrettyUC(aState->mComputedMinWidth, cmiw);
9047 0 : DR_state->PrettyUC(aState->mComputedWidth, cw);
9048 0 : DR_state->PrettyUC(aState->mComputedMaxWidth, cmxw);
9049 0 : DR_state->PrettyUC(aState->mComputedMinHeight, cmih);
9050 0 : DR_state->PrettyUC(aState->mComputedHeight, ch);
9051 0 : DR_state->PrettyUC(aState->mComputedMaxHeight, cmxh);
9052 : printf("InitConstraints= cw=(%s <= %s <= %s) ch=(%s <= %s <= %s)",
9053 0 : cmiw, cw, cmxw, cmih, ch, cmxh);
9054 0 : DR_state->PrintMargin("co", &aState->mComputedOffsets);
9055 0 : putchar('\n');
9056 : }
9057 0 : DR_state->DeleteTreeNode(*treeNode);
9058 : }
9059 :
9060 :
9061 : /* static */ void*
9062 0 : nsCSSOffsetState::DisplayInitOffsetsEnter(nsIFrame* aFrame,
9063 : nsCSSOffsetState* aState,
9064 : nscoord aContainingBlockWidth,
9065 : const nsMargin* aBorder,
9066 : const nsMargin* aPadding)
9067 : {
9068 0 : NS_PRECONDITION(aFrame, "non-null frame required");
9069 0 : NS_PRECONDITION(aState, "non-null state required");
9070 :
9071 0 : if (!DR_state->mInited) DR_state->Init();
9072 0 : if (!DR_state->mActive) return nsnull;
9073 :
9074 : // aState is not necessarily a nsHTMLReflowState
9075 0 : DR_FrameTreeNode* treeNode = DR_state->CreateTreeNode(aFrame, nsnull);
9076 0 : if (treeNode && treeNode->mDisplay) {
9077 0 : DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
9078 :
9079 : char width[16];
9080 0 : DR_state->PrettyUC(aContainingBlockWidth, width);
9081 0 : printf("InitOffsets cbw=%s", width);
9082 0 : DR_state->PrintMargin("b", aBorder);
9083 0 : DR_state->PrintMargin("p", aPadding);
9084 0 : putchar('\n');
9085 : }
9086 0 : return treeNode;
9087 : }
9088 :
9089 : /* static */ void
9090 0 : nsCSSOffsetState::DisplayInitOffsetsExit(nsIFrame* aFrame,
9091 : nsCSSOffsetState* aState,
9092 : void* aValue)
9093 : {
9094 0 : NS_PRECONDITION(aFrame, "non-null frame required");
9095 0 : NS_PRECONDITION(aState, "non-null state required");
9096 :
9097 0 : if (!DR_state->mActive) return;
9098 0 : if (!aValue) return;
9099 :
9100 0 : DR_FrameTreeNode* treeNode = (DR_FrameTreeNode*)aValue;
9101 0 : if (treeNode->mDisplay) {
9102 0 : DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
9103 0 : printf("InitOffsets=");
9104 0 : DR_state->PrintMargin("m", &aState->mComputedMargin);
9105 0 : DR_state->PrintMargin("p", &aState->mComputedPadding);
9106 0 : DR_state->PrintMargin("p+b", &aState->mComputedBorderPadding);
9107 0 : putchar('\n');
9108 : }
9109 0 : DR_state->DeleteTreeNode(*treeNode);
9110 : }
9111 :
9112 : /* static */ void*
9113 0 : nsHTMLReflowState::DisplayInitFrameTypeEnter(nsIFrame* aFrame,
9114 : nsHTMLReflowState* aState)
9115 : {
9116 0 : NS_PRECONDITION(aFrame, "non-null frame required");
9117 0 : NS_PRECONDITION(aState, "non-null state required");
9118 :
9119 0 : if (!DR_state->mInited) DR_state->Init();
9120 0 : if (!DR_state->mActive) return nsnull;
9121 :
9122 : // we don't print anything here
9123 0 : return DR_state->CreateTreeNode(aFrame, aState);
9124 : }
9125 :
9126 : /* static */ void
9127 0 : nsHTMLReflowState::DisplayInitFrameTypeExit(nsIFrame* aFrame,
9128 : nsHTMLReflowState* aState,
9129 : void* aValue)
9130 : {
9131 0 : NS_PRECONDITION(aFrame, "non-null frame required");
9132 0 : NS_PRECONDITION(aState, "non-null state required");
9133 :
9134 0 : if (!DR_state->mActive) return;
9135 0 : if (!aValue) return;
9136 :
9137 0 : DR_FrameTreeNode* treeNode = (DR_FrameTreeNode*)aValue;
9138 0 : if (treeNode->mDisplay) {
9139 0 : DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
9140 0 : printf("InitFrameType");
9141 :
9142 0 : const nsStyleDisplay *disp = aState->mStyleDisplay;
9143 :
9144 0 : if (aFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW)
9145 0 : printf(" out-of-flow");
9146 0 : if (aFrame->GetPrevInFlow())
9147 0 : printf(" prev-in-flow");
9148 0 : if (disp->IsAbsolutelyPositioned())
9149 0 : printf(" abspos");
9150 0 : if (disp->IsFloating())
9151 0 : printf(" float");
9152 :
9153 : // This array must exactly match the NS_STYLE_DISPLAY constants.
9154 : const char *const displayTypes[] = {
9155 : "none", "block", "inline", "inline-block", "list-item", "marker",
9156 : "run-in", "compact", "table", "inline-table", "table-row-group",
9157 : "table-column", "table-column-group", "table-header-group",
9158 : "table-footer-group", "table-row", "table-cell", "table-caption",
9159 : "box", "inline-box",
9160 : #ifdef MOZ_XUL
9161 : "grid", "inline-grid", "grid-group", "grid-line", "stack",
9162 : "inline-stack", "deck", "popup", "groupbox",
9163 : #endif
9164 0 : };
9165 0 : if (disp->mDisplay >= ArrayLength(displayTypes))
9166 0 : printf(" display=%u", disp->mDisplay);
9167 : else
9168 0 : printf(" display=%s", displayTypes[disp->mDisplay]);
9169 :
9170 : // This array must exactly match the NS_CSS_FRAME_TYPE constants.
9171 : const char *const cssFrameTypes[] = {
9172 : "unknown", "inline", "block", "floating", "absolute", "internal-table"
9173 0 : };
9174 0 : nsCSSFrameType bareType = NS_FRAME_GET_TYPE(aState->mFrameType);
9175 0 : bool repNoBlock = NS_FRAME_IS_REPLACED_NOBLOCK(aState->mFrameType);
9176 0 : bool repBlock = NS_FRAME_IS_REPLACED_CONTAINS_BLOCK(aState->mFrameType);
9177 :
9178 0 : if (bareType >= ArrayLength(cssFrameTypes)) {
9179 0 : printf(" result=type %u", bareType);
9180 : } else {
9181 0 : printf(" result=%s", cssFrameTypes[bareType]);
9182 : }
9183 0 : printf("%s%s\n", repNoBlock ? " +rep" : "", repBlock ? " +repBlk" : "");
9184 : }
9185 0 : DR_state->DeleteTreeNode(*treeNode);
9186 : }
9187 :
9188 : #endif
9189 : // End Display Reflow
9190 :
9191 : #endif
|