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