1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/layout/generic/nsFrame.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,9892 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +// vim:cindent:ts=2:et:sw=2: 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +/* base class of all rendering objects */ 1.11 + 1.12 +#include "nsFrame.h" 1.13 + 1.14 +#include "mozilla/Attributes.h" 1.15 +#include "mozilla/DebugOnly.h" 1.16 + 1.17 +#include "nsCOMPtr.h" 1.18 +#include "nsFrameList.h" 1.19 +#include "nsPlaceholderFrame.h" 1.20 +#include "nsIContent.h" 1.21 +#include "nsContentUtils.h" 1.22 +#include "nsIAtom.h" 1.23 +#include "nsString.h" 1.24 +#include "nsReadableUtils.h" 1.25 +#include "nsStyleContext.h" 1.26 +#include "nsTableOuterFrame.h" 1.27 +#include "nsView.h" 1.28 +#include "nsViewManager.h" 1.29 +#include "nsIScrollableFrame.h" 1.30 +#include "nsPresContext.h" 1.31 +#include "nsStyleConsts.h" 1.32 +#include "nsIPresShell.h" 1.33 +#include "prlog.h" 1.34 +#include "prprf.h" 1.35 +#include <stdarg.h> 1.36 +#include "nsFrameManager.h" 1.37 +#include "nsLayoutUtils.h" 1.38 + 1.39 +#include "nsIDOMNode.h" 1.40 +#include "nsISelection.h" 1.41 +#include "nsISelectionPrivate.h" 1.42 +#include "nsFrameSelection.h" 1.43 +#include "nsGkAtoms.h" 1.44 +#include "nsCSSAnonBoxes.h" 1.45 + 1.46 +#include "nsFrameTraversal.h" 1.47 +#include "nsRange.h" 1.48 +#include "nsITextControlFrame.h" 1.49 +#include "nsNameSpaceManager.h" 1.50 +#include "nsIPercentHeightObserver.h" 1.51 +#include "nsStyleStructInlines.h" 1.52 +#include <algorithm> 1.53 + 1.54 +#include "nsBidiPresUtils.h" 1.55 + 1.56 +// For triple-click pref 1.57 +#include "imgIContainer.h" 1.58 +#include "imgIRequest.h" 1.59 +#include "nsError.h" 1.60 +#include "nsContainerFrame.h" 1.61 +#include "nsBoxLayoutState.h" 1.62 +#include "nsBlockFrame.h" 1.63 +#include "nsDisplayList.h" 1.64 +#include "nsSVGIntegrationUtils.h" 1.65 +#include "nsSVGEffects.h" 1.66 +#include "nsChangeHint.h" 1.67 +#include "nsDeckFrame.h" 1.68 +#include "nsSubDocumentFrame.h" 1.69 +#include "SVGTextFrame.h" 1.70 + 1.71 +#include "gfxContext.h" 1.72 +#include "nsRenderingContext.h" 1.73 +#include "nsAbsoluteContainingBlock.h" 1.74 +#include "StickyScrollContainer.h" 1.75 +#include "nsFontInflationData.h" 1.76 +#include "gfxASurface.h" 1.77 +#include "nsRegion.h" 1.78 +#include "nsIFrameInlines.h" 1.79 + 1.80 +#include "mozilla/AsyncEventDispatcher.h" 1.81 +#include "mozilla/EventListenerManager.h" 1.82 +#include "mozilla/EventStateManager.h" 1.83 +#include "mozilla/EventStates.h" 1.84 +#include "mozilla/Preferences.h" 1.85 +#include "mozilla/LookAndFeel.h" 1.86 +#include "mozilla/MouseEvents.h" 1.87 +#include "mozilla/css/ImageLoader.h" 1.88 +#include "mozilla/gfx/Tools.h" 1.89 +#include "nsPrintfCString.h" 1.90 + 1.91 +using namespace mozilla; 1.92 +using namespace mozilla::css; 1.93 +using namespace mozilla::dom; 1.94 +using namespace mozilla::layers; 1.95 +using namespace mozilla::layout; 1.96 + 1.97 +// Struct containing cached metrics for box-wrapped frames. 1.98 +struct nsBoxLayoutMetrics 1.99 +{ 1.100 + nsSize mPrefSize; 1.101 + nsSize mMinSize; 1.102 + nsSize mMaxSize; 1.103 + 1.104 + nsSize mBlockMinSize; 1.105 + nsSize mBlockPrefSize; 1.106 + nscoord mBlockAscent; 1.107 + 1.108 + nscoord mFlex; 1.109 + nscoord mAscent; 1.110 + 1.111 + nsSize mLastSize; 1.112 +}; 1.113 + 1.114 +struct nsContentAndOffset 1.115 +{ 1.116 + nsIContent* mContent; 1.117 + int32_t mOffset; 1.118 +}; 1.119 + 1.120 +// Some Misc #defines 1.121 +#define SELECTION_DEBUG 0 1.122 +#define FORCE_SELECTION_UPDATE 1 1.123 +#define CALC_DEBUG 0 1.124 + 1.125 + 1.126 +#include "nsILineIterator.h" 1.127 + 1.128 +//non Hack prototypes 1.129 +#if 0 1.130 +static void RefreshContentFrames(nsPresContext* aPresContext, nsIContent * aStartContent, nsIContent * aEndContent); 1.131 +#endif 1.132 + 1.133 +#include "prenv.h" 1.134 + 1.135 +// Formerly the nsIFrameDebug interface 1.136 + 1.137 +#ifdef DEBUG 1.138 +static bool gShowFrameBorders = false; 1.139 + 1.140 +void nsFrame::ShowFrameBorders(bool aEnable) 1.141 +{ 1.142 + gShowFrameBorders = aEnable; 1.143 +} 1.144 + 1.145 +bool nsFrame::GetShowFrameBorders() 1.146 +{ 1.147 + return gShowFrameBorders; 1.148 +} 1.149 + 1.150 +static bool gShowEventTargetFrameBorder = false; 1.151 + 1.152 +void nsFrame::ShowEventTargetFrameBorder(bool aEnable) 1.153 +{ 1.154 + gShowEventTargetFrameBorder = aEnable; 1.155 +} 1.156 + 1.157 +bool nsFrame::GetShowEventTargetFrameBorder() 1.158 +{ 1.159 + return gShowEventTargetFrameBorder; 1.160 +} 1.161 + 1.162 +/** 1.163 + * Note: the log module is created during library initialization which 1.164 + * means that you cannot perform logging before then. 1.165 + */ 1.166 +static PRLogModuleInfo* gLogModule; 1.167 + 1.168 +static PRLogModuleInfo* gStyleVerifyTreeLogModuleInfo; 1.169 + 1.170 +static uint32_t gStyleVerifyTreeEnable = 0x55; 1.171 + 1.172 +bool 1.173 +nsFrame::GetVerifyStyleTreeEnable() 1.174 +{ 1.175 + if (gStyleVerifyTreeEnable == 0x55) { 1.176 + if (nullptr == gStyleVerifyTreeLogModuleInfo) { 1.177 + gStyleVerifyTreeLogModuleInfo = PR_NewLogModule("styleverifytree"); 1.178 + gStyleVerifyTreeEnable = 0 != gStyleVerifyTreeLogModuleInfo->level; 1.179 + } 1.180 + } 1.181 + return gStyleVerifyTreeEnable; 1.182 +} 1.183 + 1.184 +void 1.185 +nsFrame::SetVerifyStyleTreeEnable(bool aEnabled) 1.186 +{ 1.187 + gStyleVerifyTreeEnable = aEnabled; 1.188 +} 1.189 + 1.190 +PRLogModuleInfo* 1.191 +nsFrame::GetLogModuleInfo() 1.192 +{ 1.193 + if (nullptr == gLogModule) { 1.194 + gLogModule = PR_NewLogModule("frame"); 1.195 + } 1.196 + return gLogModule; 1.197 +} 1.198 + 1.199 +#endif 1.200 + 1.201 +static void 1.202 +DestroyAbsoluteContainingBlock(void* aPropertyValue) 1.203 +{ 1.204 + delete static_cast<nsAbsoluteContainingBlock*>(aPropertyValue); 1.205 +} 1.206 + 1.207 +NS_DECLARE_FRAME_PROPERTY(AbsoluteContainingBlockProperty, DestroyAbsoluteContainingBlock) 1.208 + 1.209 +bool 1.210 +nsIFrame::HasAbsolutelyPositionedChildren() const { 1.211 + return IsAbsoluteContainer() && GetAbsoluteContainingBlock()->HasAbsoluteFrames(); 1.212 +} 1.213 + 1.214 +nsAbsoluteContainingBlock* 1.215 +nsIFrame::GetAbsoluteContainingBlock() const { 1.216 + NS_ASSERTION(IsAbsoluteContainer(), "The frame is not marked as an abspos container correctly"); 1.217 + nsAbsoluteContainingBlock* absCB = static_cast<nsAbsoluteContainingBlock*> 1.218 + (Properties().Get(AbsoluteContainingBlockProperty())); 1.219 + NS_ASSERTION(absCB, "The frame is marked as an abspos container but doesn't have the property"); 1.220 + return absCB; 1.221 +} 1.222 + 1.223 +void 1.224 +nsIFrame::MarkAsAbsoluteContainingBlock() 1.225 +{ 1.226 + MOZ_ASSERT(GetStateBits() & NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN); 1.227 + NS_ASSERTION(!Properties().Get(AbsoluteContainingBlockProperty()), 1.228 + "Already has an abs-pos containing block property?"); 1.229 + NS_ASSERTION(!HasAnyStateBits(NS_FRAME_HAS_ABSPOS_CHILDREN), 1.230 + "Already has NS_FRAME_HAS_ABSPOS_CHILDREN state bit?"); 1.231 + AddStateBits(NS_FRAME_HAS_ABSPOS_CHILDREN); 1.232 + Properties().Set(AbsoluteContainingBlockProperty(), new nsAbsoluteContainingBlock(GetAbsoluteListID())); 1.233 +} 1.234 + 1.235 +void 1.236 +nsIFrame::MarkAsNotAbsoluteContainingBlock() 1.237 +{ 1.238 + NS_ASSERTION(!HasAbsolutelyPositionedChildren(), "Think of the children!"); 1.239 + NS_ASSERTION(Properties().Get(AbsoluteContainingBlockProperty()), 1.240 + "Should have an abs-pos containing block property"); 1.241 + NS_ASSERTION(HasAnyStateBits(NS_FRAME_HAS_ABSPOS_CHILDREN), 1.242 + "Should have NS_FRAME_HAS_ABSPOS_CHILDREN state bit"); 1.243 + MOZ_ASSERT(HasAnyStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN)); 1.244 + RemoveStateBits(NS_FRAME_HAS_ABSPOS_CHILDREN); 1.245 + Properties().Delete(AbsoluteContainingBlockProperty()); 1.246 +} 1.247 + 1.248 +bool 1.249 +nsIFrame::CheckAndClearPaintedState() 1.250 +{ 1.251 + bool result = (GetStateBits() & NS_FRAME_PAINTED_THEBES); 1.252 + RemoveStateBits(NS_FRAME_PAINTED_THEBES); 1.253 + 1.254 + nsIFrame::ChildListIterator lists(this); 1.255 + for (; !lists.IsDone(); lists.Next()) { 1.256 + nsFrameList::Enumerator childFrames(lists.CurrentList()); 1.257 + for (; !childFrames.AtEnd(); childFrames.Next()) { 1.258 + nsIFrame* child = childFrames.get(); 1.259 + if (child->CheckAndClearPaintedState()) { 1.260 + result = true; 1.261 + } 1.262 + } 1.263 + } 1.264 + return result; 1.265 +} 1.266 + 1.267 +bool 1.268 +nsIFrame::IsVisibleConsideringAncestors(uint32_t aFlags) const 1.269 +{ 1.270 + if (!StyleVisibility()->IsVisible()) { 1.271 + return false; 1.272 + } 1.273 + 1.274 + const nsIFrame* frame = this; 1.275 + while (frame) { 1.276 + nsView* view = frame->GetView(); 1.277 + if (view && view->GetVisibility() == nsViewVisibility_kHide) 1.278 + return false; 1.279 + 1.280 + nsIFrame* parent = frame->GetParent(); 1.281 + nsDeckFrame* deck = do_QueryFrame(parent); 1.282 + if (deck) { 1.283 + if (deck->GetSelectedBox() != frame) 1.284 + return false; 1.285 + } 1.286 + 1.287 + if (parent) { 1.288 + frame = parent; 1.289 + } else { 1.290 + parent = nsLayoutUtils::GetCrossDocParentFrame(frame); 1.291 + if (!parent) 1.292 + break; 1.293 + 1.294 + if ((aFlags & nsIFrame::VISIBILITY_CROSS_CHROME_CONTENT_BOUNDARY) == 0 && 1.295 + parent->PresContext()->IsChrome() && !frame->PresContext()->IsChrome()) { 1.296 + break; 1.297 + } 1.298 + 1.299 + if (!parent->StyleVisibility()->IsVisible()) 1.300 + return false; 1.301 + 1.302 + frame = parent; 1.303 + } 1.304 + } 1.305 + 1.306 + return true; 1.307 +} 1.308 + 1.309 +void 1.310 +nsIFrame::FindCloserFrameForSelection( 1.311 + nsPoint aPoint, 1.312 + nsIFrame::FrameWithDistance* aCurrentBestFrame) 1.313 +{ 1.314 + if (nsLayoutUtils::PointIsCloserToRect(aPoint, mRect, 1.315 + aCurrentBestFrame->mXDistance, 1.316 + aCurrentBestFrame->mYDistance)) { 1.317 + aCurrentBestFrame->mFrame = this; 1.318 + } 1.319 +} 1.320 + 1.321 +void 1.322 +nsIFrame::ContentStatesChanged(mozilla::EventStates aStates) 1.323 +{ 1.324 +} 1.325 + 1.326 +void 1.327 +NS_MergeReflowStatusInto(nsReflowStatus* aPrimary, nsReflowStatus aSecondary) 1.328 +{ 1.329 + *aPrimary |= aSecondary & 1.330 + (NS_FRAME_NOT_COMPLETE | NS_FRAME_OVERFLOW_INCOMPLETE | 1.331 + NS_FRAME_TRUNCATED | NS_FRAME_REFLOW_NEXTINFLOW); 1.332 + if (*aPrimary & NS_FRAME_NOT_COMPLETE) { 1.333 + *aPrimary &= ~NS_FRAME_OVERFLOW_INCOMPLETE; 1.334 + } 1.335 +} 1.336 + 1.337 +void 1.338 +nsWeakFrame::Init(nsIFrame* aFrame) 1.339 +{ 1.340 + Clear(mFrame ? mFrame->PresContext()->GetPresShell() : nullptr); 1.341 + mFrame = aFrame; 1.342 + if (mFrame) { 1.343 + nsIPresShell* shell = mFrame->PresContext()->GetPresShell(); 1.344 + NS_WARN_IF_FALSE(shell, "Null PresShell in nsWeakFrame!"); 1.345 + if (shell) { 1.346 + shell->AddWeakFrame(this); 1.347 + } else { 1.348 + mFrame = nullptr; 1.349 + } 1.350 + } 1.351 +} 1.352 + 1.353 +nsIFrame* 1.354 +NS_NewEmptyFrame(nsIPresShell* aPresShell, nsStyleContext* aContext) 1.355 +{ 1.356 + return new (aPresShell) nsFrame(aContext); 1.357 +} 1.358 + 1.359 +nsFrame::nsFrame(nsStyleContext* aContext) 1.360 +{ 1.361 + MOZ_COUNT_CTOR(nsFrame); 1.362 + 1.363 + mState = NS_FRAME_FIRST_REFLOW | NS_FRAME_IS_DIRTY; 1.364 + mStyleContext = aContext; 1.365 + mStyleContext->AddRef(); 1.366 +} 1.367 + 1.368 +nsFrame::~nsFrame() 1.369 +{ 1.370 + MOZ_COUNT_DTOR(nsFrame); 1.371 + 1.372 + NS_IF_RELEASE(mContent); 1.373 + mStyleContext->Release(); 1.374 +} 1.375 + 1.376 +NS_IMPL_FRAMEARENA_HELPERS(nsFrame) 1.377 + 1.378 +// Dummy operator delete. Will never be called, but must be defined 1.379 +// to satisfy some C++ ABIs. 1.380 +void 1.381 +nsFrame::operator delete(void *, size_t) 1.382 +{ 1.383 + NS_RUNTIMEABORT("nsFrame::operator delete should never be called"); 1.384 +} 1.385 + 1.386 +NS_QUERYFRAME_HEAD(nsFrame) 1.387 + NS_QUERYFRAME_ENTRY(nsIFrame) 1.388 +NS_QUERYFRAME_TAIL_INHERITANCE_ROOT 1.389 + 1.390 +///////////////////////////////////////////////////////////////////////////// 1.391 +// nsIFrame 1.392 + 1.393 +static bool 1.394 +IsFontSizeInflationContainer(nsIFrame* aFrame, 1.395 + const nsStyleDisplay* aStyleDisplay) 1.396 +{ 1.397 + /* 1.398 + * Font size inflation is built around the idea that we're inflating 1.399 + * the fonts for a pan-and-zoom UI so that when the user scales up a 1.400 + * block or other container to fill the width of the device, the fonts 1.401 + * will be readable. To do this, we need to pick what counts as a 1.402 + * container. 1.403 + * 1.404 + * From a code perspective, the only hard requirement is that frames 1.405 + * that are line participants 1.406 + * (nsIFrame::IsFrameOfType(nsIFrame::eLineParticipant)) are never 1.407 + * containers, since line layout assumes that the inflation is 1.408 + * consistent within a line. 1.409 + * 1.410 + * This is not an imposition, since we obviously want a bunch of text 1.411 + * (possibly with inline elements) flowing within a block to count the 1.412 + * block (or higher) as its container. 1.413 + * 1.414 + * We also want form controls, including the text in the anonymous 1.415 + * content inside of them, to match each other and the text next to 1.416 + * them, so they and their anonymous content should also not be a 1.417 + * container. 1.418 + * 1.419 + * However, because we can't reliably compute sizes across XUL during 1.420 + * reflow, any XUL frame with a XUL parent is always a container. 1.421 + * 1.422 + * There are contexts where it would be nice if some blocks didn't 1.423 + * count as a container, so that, for example, an indented quotation 1.424 + * didn't end up with a smaller font size. However, it's hard to 1.425 + * distinguish these situations where we really do want the indented 1.426 + * thing to count as a container, so we don't try, and blocks are 1.427 + * always containers. 1.428 + */ 1.429 + 1.430 + // The root frame should always be an inflation container. 1.431 + if (!aFrame->GetParent()) { 1.432 + return true; 1.433 + } 1.434 + 1.435 + nsIContent *content = aFrame->GetContent(); 1.436 + bool isInline = (aFrame->GetDisplay() == NS_STYLE_DISPLAY_INLINE || 1.437 + (aFrame->IsFloating() && 1.438 + aFrame->GetType() == nsGkAtoms::letterFrame) || 1.439 + // Given multiple frames for the same node, only the 1.440 + // outer one should be considered a container. 1.441 + // (Important, e.g., for nsSelectsAreaFrame.) 1.442 + (aFrame->GetParent()->GetContent() == content) || 1.443 + (content && (content->IsHTML(nsGkAtoms::option) || 1.444 + content->IsHTML(nsGkAtoms::optgroup) || 1.445 + content->IsHTML(nsGkAtoms::select) || 1.446 + content->IsInNativeAnonymousSubtree()))) && 1.447 + !(aFrame->IsBoxFrame() && aFrame->GetParent()->IsBoxFrame()); 1.448 + NS_ASSERTION(!aFrame->IsFrameOfType(nsIFrame::eLineParticipant) || 1.449 + isInline || 1.450 + // br frames and mathml frames report being line 1.451 + // participants even when their position or display is 1.452 + // set 1.453 + aFrame->GetType() == nsGkAtoms::brFrame || 1.454 + aFrame->IsFrameOfType(nsIFrame::eMathML), 1.455 + "line participants must not be containers"); 1.456 + NS_ASSERTION(aFrame->GetType() != nsGkAtoms::bulletFrame || isInline, 1.457 + "bullets should not be containers"); 1.458 + return !isInline; 1.459 +} 1.460 + 1.461 +void 1.462 +nsFrame::Init(nsIContent* aContent, 1.463 + nsIFrame* aParent, 1.464 + nsIFrame* aPrevInFlow) 1.465 +{ 1.466 + NS_PRECONDITION(!mContent, "Double-initing a frame?"); 1.467 + NS_ASSERTION(IsFrameOfType(eDEBUGAllFrames) && 1.468 + !IsFrameOfType(eDEBUGNoFrames), 1.469 + "IsFrameOfType implementation that doesn't call base class"); 1.470 + 1.471 + mContent = aContent; 1.472 + mParent = aParent; 1.473 + 1.474 + if (aContent) { 1.475 + NS_ADDREF(aContent); 1.476 + } 1.477 + 1.478 + if (aPrevInFlow) { 1.479 + // Make sure the general flags bits are the same 1.480 + nsFrameState state = aPrevInFlow->GetStateBits(); 1.481 + 1.482 + // Make bits that are currently off (see constructor) the same: 1.483 + mState |= state & (NS_FRAME_INDEPENDENT_SELECTION | 1.484 + NS_FRAME_PART_OF_IBSPLIT | 1.485 + NS_FRAME_MAY_BE_TRANSFORMED | 1.486 + NS_FRAME_MAY_HAVE_GENERATED_CONTENT | 1.487 + NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN); 1.488 + } 1.489 + if (mParent) { 1.490 + nsFrameState state = mParent->GetStateBits(); 1.491 + 1.492 + // Make bits that are currently off (see constructor) the same: 1.493 + mState |= state & (NS_FRAME_INDEPENDENT_SELECTION | 1.494 + NS_FRAME_GENERATED_CONTENT | 1.495 + NS_FRAME_IS_SVG_TEXT | 1.496 + NS_FRAME_IN_POPUP | 1.497 + NS_FRAME_IS_NONDISPLAY); 1.498 + } 1.499 + const nsStyleDisplay *disp = StyleDisplay(); 1.500 + if (disp->HasTransform(this)) { 1.501 + // The frame gets reconstructed if we toggle the -moz-transform 1.502 + // property, so we can set this bit here and then ignore it. 1.503 + mState |= NS_FRAME_MAY_BE_TRANSFORMED; 1.504 + } 1.505 + if (disp->mPosition == NS_STYLE_POSITION_STICKY && 1.506 + !aPrevInFlow && 1.507 + !(mState & NS_FRAME_IS_NONDISPLAY) && 1.508 + !disp->IsInnerTableStyle()) { 1.509 + // Note that we only add first continuations, but we really only 1.510 + // want to add first continuation-or-ib-split-siblings. But since we 1.511 + // don't yet know if we're a later part of a block-in-inline split, 1.512 + // we'll just add later members of a block-in-inline split here, and 1.513 + // then StickyScrollContainer will remove them later. 1.514 + // We don't currently support relative positioning of inner table 1.515 + // elements (bug 35168), so exclude them from sticky positioning too. 1.516 + StickyScrollContainer* ssc = 1.517 + StickyScrollContainer::GetStickyScrollContainerForFrame(this); 1.518 + if (ssc) { 1.519 + ssc->AddFrame(this); 1.520 + } 1.521 + } 1.522 + 1.523 + if (nsLayoutUtils::FontSizeInflationEnabled(PresContext()) || !GetParent() 1.524 +#ifdef DEBUG 1.525 + // We have assertions that check inflation invariants even when 1.526 + // font size inflation is not enabled. 1.527 + || true 1.528 +#endif 1.529 + ) { 1.530 + if (IsFontSizeInflationContainer(this, disp)) { 1.531 + AddStateBits(NS_FRAME_FONT_INFLATION_CONTAINER); 1.532 + if (!GetParent() || 1.533 + // I'd use NS_FRAME_OUT_OF_FLOW, but it's not set yet. 1.534 + disp->IsFloating(this) || disp->IsAbsolutelyPositioned(this)) { 1.535 + AddStateBits(NS_FRAME_FONT_INFLATION_FLOW_ROOT); 1.536 + } 1.537 + } 1.538 + NS_ASSERTION(GetParent() || 1.539 + (GetStateBits() & NS_FRAME_FONT_INFLATION_CONTAINER), 1.540 + "root frame should always be a container"); 1.541 + } 1.542 + 1.543 + DidSetStyleContext(nullptr); 1.544 + 1.545 + if (IsBoxWrapped()) 1.546 + InitBoxMetrics(false); 1.547 +} 1.548 + 1.549 +nsresult nsFrame::SetInitialChildList(ChildListID aListID, 1.550 + nsFrameList& aChildList) 1.551 +{ 1.552 + // XXX This shouldn't be getting called at all, but currently is for backwards 1.553 + // compatility reasons... 1.554 +#if 0 1.555 + NS_ERROR("not a container"); 1.556 + return NS_ERROR_UNEXPECTED; 1.557 +#else 1.558 + NS_ASSERTION(aChildList.IsEmpty(), "not a container"); 1.559 + return NS_OK; 1.560 +#endif 1.561 +} 1.562 + 1.563 +nsresult 1.564 +nsFrame::AppendFrames(ChildListID aListID, 1.565 + nsFrameList& aFrameList) 1.566 +{ 1.567 + NS_PRECONDITION(false, "not a container"); 1.568 + return NS_ERROR_UNEXPECTED; 1.569 +} 1.570 + 1.571 +nsresult 1.572 +nsFrame::InsertFrames(ChildListID aListID, 1.573 + nsIFrame* aPrevFrame, 1.574 + nsFrameList& aFrameList) 1.575 +{ 1.576 + NS_PRECONDITION(false, "not a container"); 1.577 + return NS_ERROR_UNEXPECTED; 1.578 +} 1.579 + 1.580 +nsresult 1.581 +nsFrame::RemoveFrame(ChildListID aListID, 1.582 + nsIFrame* aOldFrame) 1.583 +{ 1.584 + NS_PRECONDITION(false, "not a container"); 1.585 + return NS_ERROR_UNEXPECTED; 1.586 +} 1.587 + 1.588 +void 1.589 +nsFrame::DestroyFrom(nsIFrame* aDestructRoot) 1.590 +{ 1.591 + NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(), 1.592 + "destroy called on frame while scripts not blocked"); 1.593 + NS_ASSERTION(!GetNextSibling() && !GetPrevSibling(), 1.594 + "Frames should be removed before destruction."); 1.595 + NS_ASSERTION(aDestructRoot, "Must specify destruct root"); 1.596 + MOZ_ASSERT(!HasAbsolutelyPositionedChildren()); 1.597 + 1.598 + nsSVGEffects::InvalidateDirectRenderingObservers(this); 1.599 + 1.600 + if (StyleDisplay()->mPosition == NS_STYLE_POSITION_STICKY) { 1.601 + StickyScrollContainer* ssc = 1.602 + StickyScrollContainer::GetStickyScrollContainerForFrame(this); 1.603 + if (ssc) { 1.604 + ssc->RemoveFrame(this); 1.605 + } 1.606 + } 1.607 + 1.608 + // Get the view pointer now before the frame properties disappear 1.609 + // when we call NotifyDestroyingFrame() 1.610 + nsView* view = GetView(); 1.611 + nsPresContext* presContext = PresContext(); 1.612 + 1.613 + nsIPresShell *shell = presContext->GetPresShell(); 1.614 + if (mState & NS_FRAME_OUT_OF_FLOW) { 1.615 + nsPlaceholderFrame* placeholder = 1.616 + shell->FrameManager()->GetPlaceholderFrameFor(this); 1.617 + NS_ASSERTION(!placeholder || (aDestructRoot != this), 1.618 + "Don't call Destroy() on OOFs, call Destroy() on the placeholder."); 1.619 + NS_ASSERTION(!placeholder || 1.620 + nsLayoutUtils::IsProperAncestorFrame(aDestructRoot, placeholder), 1.621 + "Placeholder relationship should have been torn down already; " 1.622 + "this might mean we have a stray placeholder in the tree."); 1.623 + if (placeholder) { 1.624 + shell->FrameManager()->UnregisterPlaceholderFrame(placeholder); 1.625 + placeholder->SetOutOfFlowFrame(nullptr); 1.626 + } 1.627 + } 1.628 + 1.629 + // If we have any IB split siblings, clear their references to us. 1.630 + // (Note: This has to happen before we call shell->NotifyDestroyingFrame, 1.631 + // because that clears our Properties() table.) 1.632 + if (mState & NS_FRAME_PART_OF_IBSPLIT) { 1.633 + // Delete previous sibling's reference to me. 1.634 + nsIFrame* prevSib = static_cast<nsIFrame*> 1.635 + (Properties().Get(nsIFrame::IBSplitPrevSibling())); 1.636 + if (prevSib) { 1.637 + NS_WARN_IF_FALSE(this == 1.638 + prevSib->Properties().Get(nsIFrame::IBSplitSibling()), 1.639 + "IB sibling chain is inconsistent"); 1.640 + prevSib->Properties().Delete(nsIFrame::IBSplitSibling()); 1.641 + } 1.642 + 1.643 + // Delete next sibling's reference to me. 1.644 + nsIFrame* nextSib = static_cast<nsIFrame*> 1.645 + (Properties().Get(nsIFrame::IBSplitSibling())); 1.646 + if (nextSib) { 1.647 + NS_WARN_IF_FALSE(this == 1.648 + nextSib->Properties().Get(nsIFrame::IBSplitPrevSibling()), 1.649 + "IB sibling chain is inconsistent"); 1.650 + nextSib->Properties().Delete(nsIFrame::IBSplitPrevSibling()); 1.651 + } 1.652 + } 1.653 + 1.654 + shell->NotifyDestroyingFrame(this); 1.655 + 1.656 + if (mState & NS_FRAME_EXTERNAL_REFERENCE) { 1.657 + shell->ClearFrameRefs(this); 1.658 + } 1.659 + 1.660 + if (view) { 1.661 + // Break association between view and frame 1.662 + view->SetFrame(nullptr); 1.663 + 1.664 + // Destroy the view 1.665 + view->Destroy(); 1.666 + } 1.667 + 1.668 + // Make sure that our deleted frame can't be returned from GetPrimaryFrame() 1.669 + if (mContent && mContent->GetPrimaryFrame() == this) { 1.670 + mContent->SetPrimaryFrame(nullptr); 1.671 + } 1.672 + 1.673 + // Must retrieve the object ID before calling destructors, so the 1.674 + // vtable is still valid. 1.675 + // 1.676 + // Note to future tweakers: having the method that returns the 1.677 + // object size call the destructor will not avoid an indirect call; 1.678 + // the compiler cannot devirtualize the call to the destructor even 1.679 + // if it's from a method defined in the same class. 1.680 + 1.681 + nsQueryFrame::FrameIID id = GetFrameId(); 1.682 + this->~nsFrame(); 1.683 + 1.684 + // Now that we're totally cleaned out, we need to add ourselves to 1.685 + // the presshell's recycler. 1.686 + shell->FreeFrame(id, this); 1.687 +} 1.688 + 1.689 +nsresult 1.690 +nsFrame::GetOffsets(int32_t &aStart, int32_t &aEnd) const 1.691 +{ 1.692 + aStart = 0; 1.693 + aEnd = 0; 1.694 + return NS_OK; 1.695 +} 1.696 + 1.697 +// Subclass hook for style post processing 1.698 +/* virtual */ void 1.699 +nsFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext) 1.700 +{ 1.701 + if (IsSVGText()) { 1.702 + SVGTextFrame* svgTextFrame = static_cast<SVGTextFrame*>( 1.703 + nsLayoutUtils::GetClosestFrameOfType(this, nsGkAtoms::svgTextFrame)); 1.704 + nsIFrame* anonBlock = svgTextFrame->GetFirstPrincipalChild(); 1.705 + // Just as in SVGTextFrame::DidSetStyleContext, we need to ensure that 1.706 + // any non-display SVGTextFrames get reflowed when a child text frame 1.707 + // gets new style. 1.708 + // 1.709 + // Note that we must check NS_FRAME_FIRST_REFLOW on our SVGTextFrame's 1.710 + // anonymous block frame rather than our self, since NS_FRAME_FIRST_REFLOW 1.711 + // may be set on us if we're a new frame that has been inserted after the 1.712 + // document's first reflow. (In which case this DidSetStyleContext call may 1.713 + // be happening under frame construction under a Reflow() call.) 1.714 + if (anonBlock && !(anonBlock->GetStateBits() & NS_FRAME_FIRST_REFLOW) && 1.715 + (svgTextFrame->GetStateBits() & NS_FRAME_IS_NONDISPLAY) && 1.716 + !(svgTextFrame->GetStateBits() & NS_STATE_SVG_TEXT_IN_REFLOW)) { 1.717 + svgTextFrame->ScheduleReflowSVGNonDisplayText(); 1.718 + } 1.719 + } 1.720 + 1.721 + ImageLoader* imageLoader = PresContext()->Document()->StyleImageLoader(); 1.722 + 1.723 + // If the old context had a background image image and new context 1.724 + // does not have the same image, clear the image load notifier 1.725 + // (which keeps the image loading, if it still is) for the frame. 1.726 + // We want to do this conservatively because some frames paint their 1.727 + // backgrounds from some other frame's style data, and we don't want 1.728 + // to clear those notifiers unless we have to. (They'll be reset 1.729 + // when we paint, although we could miss a notification in that 1.730 + // interval.) 1.731 + const nsStyleBackground *oldBG = aOldStyleContext ? 1.732 + aOldStyleContext->StyleBackground() : 1.733 + nullptr; 1.734 + const nsStyleBackground *newBG = StyleBackground(); 1.735 + if (oldBG) { 1.736 + NS_FOR_VISIBLE_BACKGROUND_LAYERS_BACK_TO_FRONT(i, oldBG) { 1.737 + // If there is an image in oldBG that's not in newBG, drop it. 1.738 + if (i >= newBG->mImageCount || 1.739 + !oldBG->mLayers[i].mImage.ImageDataEquals(newBG->mLayers[i].mImage)) { 1.740 + const nsStyleImage& oldImage = oldBG->mLayers[i].mImage; 1.741 + if (oldImage.GetType() != eStyleImageType_Image) { 1.742 + continue; 1.743 + } 1.744 + 1.745 + imageLoader->DisassociateRequestFromFrame(oldImage.GetImageData(), 1.746 + this); 1.747 + } 1.748 + } 1.749 + } 1.750 + 1.751 + NS_FOR_VISIBLE_BACKGROUND_LAYERS_BACK_TO_FRONT(i, newBG) { 1.752 + // If there is an image in newBG that's not in oldBG, add it. 1.753 + if (!oldBG || i >= oldBG->mImageCount || 1.754 + !newBG->mLayers[i].mImage.ImageDataEquals(oldBG->mLayers[i].mImage)) { 1.755 + const nsStyleImage& newImage = newBG->mLayers[i].mImage; 1.756 + if (newImage.GetType() != eStyleImageType_Image) { 1.757 + continue; 1.758 + } 1.759 + 1.760 + imageLoader->AssociateRequestToFrame(newImage.GetImageData(), this); 1.761 + } 1.762 + } 1.763 + 1.764 + if (aOldStyleContext) { 1.765 + // If we detect a change on margin, padding or border, we store the old 1.766 + // values on the frame itself between now and reflow, so if someone 1.767 + // calls GetUsed(Margin|Border|Padding)() before the next reflow, we 1.768 + // can give an accurate answer. 1.769 + // We don't want to set the property if one already exists. 1.770 + FrameProperties props = Properties(); 1.771 + nsMargin oldValue(0, 0, 0, 0); 1.772 + nsMargin newValue(0, 0, 0, 0); 1.773 + const nsStyleMargin* oldMargin = aOldStyleContext->PeekStyleMargin(); 1.774 + if (oldMargin && oldMargin->GetMargin(oldValue)) { 1.775 + if ((!StyleMargin()->GetMargin(newValue) || oldValue != newValue) && 1.776 + !props.Get(UsedMarginProperty())) { 1.777 + props.Set(UsedMarginProperty(), new nsMargin(oldValue)); 1.778 + } 1.779 + } 1.780 + 1.781 + const nsStylePadding* oldPadding = aOldStyleContext->PeekStylePadding(); 1.782 + if (oldPadding && oldPadding->GetPadding(oldValue)) { 1.783 + if ((!StylePadding()->GetPadding(newValue) || oldValue != newValue) && 1.784 + !props.Get(UsedPaddingProperty())) { 1.785 + props.Set(UsedPaddingProperty(), new nsMargin(oldValue)); 1.786 + } 1.787 + } 1.788 + 1.789 + const nsStyleBorder* oldBorder = aOldStyleContext->PeekStyleBorder(); 1.790 + if (oldBorder) { 1.791 + oldValue = oldBorder->GetComputedBorder(); 1.792 + newValue = StyleBorder()->GetComputedBorder(); 1.793 + if (oldValue != newValue && 1.794 + !props.Get(UsedBorderProperty())) { 1.795 + props.Set(UsedBorderProperty(), new nsMargin(oldValue)); 1.796 + } 1.797 + } 1.798 + } 1.799 + 1.800 + imgIRequest *oldBorderImage = aOldStyleContext 1.801 + ? aOldStyleContext->StyleBorder()->GetBorderImageRequest() 1.802 + : nullptr; 1.803 + imgIRequest *newBorderImage = StyleBorder()->GetBorderImageRequest(); 1.804 + // FIXME (Bug 759996): The following is no longer true. 1.805 + // For border-images, we can't be as conservative (we need to set the 1.806 + // new loaders if there has been any change) since the CalcDifference 1.807 + // call depended on the result of GetComputedBorder() and that result 1.808 + // depends on whether the image has loaded, start the image load now 1.809 + // so that we'll get notified when it completes loading and can do a 1.810 + // restyle. Otherwise, the image might finish loading from the 1.811 + // network before we start listening to its notifications, and then 1.812 + // we'll never know that it's finished loading. Likewise, we want to 1.813 + // do this for freshly-created frames to prevent a similar race if the 1.814 + // image loads between reflow (which can depend on whether the image 1.815 + // is loaded) and paint. We also don't really care about any callers 1.816 + // who try to paint borders with a different style context, because 1.817 + // they won't have the correct size for the border either. 1.818 + if (oldBorderImage != newBorderImage) { 1.819 + // stop and restart the image loading/notification 1.820 + if (oldBorderImage) { 1.821 + imageLoader->DisassociateRequestFromFrame(oldBorderImage, this); 1.822 + } 1.823 + if (newBorderImage) { 1.824 + imageLoader->AssociateRequestToFrame(newBorderImage, this); 1.825 + } 1.826 + } 1.827 + 1.828 + // If the page contains markup that overrides text direction, and 1.829 + // does not contain any characters that would activate the Unicode 1.830 + // bidi algorithm, we need to call |SetBidiEnabled| on the pres 1.831 + // context before reflow starts. See bug 115921. 1.832 + if (StyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL) { 1.833 + PresContext()->SetBidiEnabled(); 1.834 + } 1.835 +} 1.836 + 1.837 +// MSVC fails with link error "one or more multiply defined symbols found", 1.838 +// gcc fails with "hidden symbol `nsIFrame::kPrincipalList' isn't defined" 1.839 +// etc if they are not defined. 1.840 +#ifndef _MSC_VER 1.841 +// static nsIFrame constants; initialized in the header file. 1.842 +const nsIFrame::ChildListID nsIFrame::kPrincipalList; 1.843 +const nsIFrame::ChildListID nsIFrame::kAbsoluteList; 1.844 +const nsIFrame::ChildListID nsIFrame::kBulletList; 1.845 +const nsIFrame::ChildListID nsIFrame::kCaptionList; 1.846 +const nsIFrame::ChildListID nsIFrame::kColGroupList; 1.847 +const nsIFrame::ChildListID nsIFrame::kExcessOverflowContainersList; 1.848 +const nsIFrame::ChildListID nsIFrame::kFixedList; 1.849 +const nsIFrame::ChildListID nsIFrame::kFloatList; 1.850 +const nsIFrame::ChildListID nsIFrame::kOverflowContainersList; 1.851 +const nsIFrame::ChildListID nsIFrame::kOverflowList; 1.852 +const nsIFrame::ChildListID nsIFrame::kOverflowOutOfFlowList; 1.853 +const nsIFrame::ChildListID nsIFrame::kPopupList; 1.854 +const nsIFrame::ChildListID nsIFrame::kPushedFloatsList; 1.855 +const nsIFrame::ChildListID nsIFrame::kSelectPopupList; 1.856 +const nsIFrame::ChildListID nsIFrame::kNoReflowPrincipalList; 1.857 +#endif 1.858 + 1.859 +/* virtual */ nsMargin 1.860 +nsIFrame::GetUsedMargin() const 1.861 +{ 1.862 + nsMargin margin(0, 0, 0, 0); 1.863 + if (((mState & NS_FRAME_FIRST_REFLOW) && 1.864 + !(mState & NS_FRAME_IN_REFLOW)) || 1.865 + IsSVGText()) 1.866 + return margin; 1.867 + 1.868 + nsMargin *m = static_cast<nsMargin*> 1.869 + (Properties().Get(UsedMarginProperty())); 1.870 + if (m) { 1.871 + margin = *m; 1.872 + } else { 1.873 + DebugOnly<bool> hasMargin = StyleMargin()->GetMargin(margin); 1.874 + NS_ASSERTION(hasMargin, "We should have a margin here! (out of memory?)"); 1.875 + } 1.876 + return margin; 1.877 +} 1.878 + 1.879 +/* virtual */ nsMargin 1.880 +nsIFrame::GetUsedBorder() const 1.881 +{ 1.882 + nsMargin border(0, 0, 0, 0); 1.883 + if (((mState & NS_FRAME_FIRST_REFLOW) && 1.884 + !(mState & NS_FRAME_IN_REFLOW)) || 1.885 + IsSVGText()) 1.886 + return border; 1.887 + 1.888 + // Theme methods don't use const-ness. 1.889 + nsIFrame *mutable_this = const_cast<nsIFrame*>(this); 1.890 + 1.891 + const nsStyleDisplay *disp = StyleDisplay(); 1.892 + if (mutable_this->IsThemed(disp)) { 1.893 + nsIntMargin result; 1.894 + nsPresContext *presContext = PresContext(); 1.895 + presContext->GetTheme()->GetWidgetBorder(presContext->DeviceContext(), 1.896 + mutable_this, disp->mAppearance, 1.897 + &result); 1.898 + border.left = presContext->DevPixelsToAppUnits(result.left); 1.899 + border.top = presContext->DevPixelsToAppUnits(result.top); 1.900 + border.right = presContext->DevPixelsToAppUnits(result.right); 1.901 + border.bottom = presContext->DevPixelsToAppUnits(result.bottom); 1.902 + return border; 1.903 + } 1.904 + 1.905 + nsMargin *b = static_cast<nsMargin*> 1.906 + (Properties().Get(UsedBorderProperty())); 1.907 + if (b) { 1.908 + border = *b; 1.909 + } else { 1.910 + border = StyleBorder()->GetComputedBorder(); 1.911 + } 1.912 + return border; 1.913 +} 1.914 + 1.915 +/* virtual */ nsMargin 1.916 +nsIFrame::GetUsedPadding() const 1.917 +{ 1.918 + nsMargin padding(0, 0, 0, 0); 1.919 + if (((mState & NS_FRAME_FIRST_REFLOW) && 1.920 + !(mState & NS_FRAME_IN_REFLOW)) || 1.921 + IsSVGText()) 1.922 + return padding; 1.923 + 1.924 + // Theme methods don't use const-ness. 1.925 + nsIFrame *mutable_this = const_cast<nsIFrame*>(this); 1.926 + 1.927 + const nsStyleDisplay *disp = StyleDisplay(); 1.928 + if (mutable_this->IsThemed(disp)) { 1.929 + nsPresContext *presContext = PresContext(); 1.930 + nsIntMargin widget; 1.931 + if (presContext->GetTheme()->GetWidgetPadding(presContext->DeviceContext(), 1.932 + mutable_this, 1.933 + disp->mAppearance, 1.934 + &widget)) { 1.935 + padding.top = presContext->DevPixelsToAppUnits(widget.top); 1.936 + padding.right = presContext->DevPixelsToAppUnits(widget.right); 1.937 + padding.bottom = presContext->DevPixelsToAppUnits(widget.bottom); 1.938 + padding.left = presContext->DevPixelsToAppUnits(widget.left); 1.939 + return padding; 1.940 + } 1.941 + } 1.942 + 1.943 + nsMargin *p = static_cast<nsMargin*> 1.944 + (Properties().Get(UsedPaddingProperty())); 1.945 + if (p) { 1.946 + padding = *p; 1.947 + } else { 1.948 + DebugOnly<bool> hasPadding = StylePadding()->GetPadding(padding); 1.949 + NS_ASSERTION(hasPadding, "We should have padding here! (out of memory?)"); 1.950 + } 1.951 + return padding; 1.952 +} 1.953 + 1.954 +int 1.955 +nsIFrame::GetSkipSides(const nsHTMLReflowState* aReflowState) const 1.956 +{ 1.957 + // Convert the logical skip sides to physical sides using the frame's 1.958 + // writing mode 1.959 + WritingMode writingMode = GetWritingMode(); 1.960 + int logicalSkip = GetLogicalSkipSides(aReflowState); 1.961 + int skip = 0; 1.962 + 1.963 + if (logicalSkip & LOGICAL_SIDE_B_START) { 1.964 + if (writingMode.IsVertical()) { 1.965 + skip |= 1 << (writingMode.IsVerticalLR() ? NS_SIDE_LEFT : NS_SIDE_RIGHT); 1.966 + } else { 1.967 + skip |= 1 << NS_SIDE_TOP; 1.968 + } 1.969 + } 1.970 + 1.971 + if (logicalSkip & LOGICAL_SIDE_B_END) { 1.972 + if (writingMode.IsVertical()) { 1.973 + skip |= 1 << (writingMode.IsVerticalLR() ? NS_SIDE_RIGHT : NS_SIDE_LEFT); 1.974 + } else { 1.975 + skip |= 1 << NS_SIDE_BOTTOM; 1.976 + } 1.977 + } 1.978 + 1.979 + if (logicalSkip & LOGICAL_SIDE_I_START) { 1.980 + if (writingMode.IsVertical()) { 1.981 + skip |= 1 << NS_SIDE_TOP; 1.982 + } else { 1.983 + skip |= 1 << (writingMode.IsBidiLTR() ? NS_SIDE_LEFT : NS_SIDE_RIGHT); 1.984 + } 1.985 + } 1.986 + 1.987 + if (logicalSkip & LOGICAL_SIDE_I_END) { 1.988 + if (writingMode.IsVertical()) { 1.989 + skip |= 1 << NS_SIDE_BOTTOM; 1.990 + } else { 1.991 + skip |= 1 << (writingMode.IsBidiLTR() ? NS_SIDE_RIGHT : NS_SIDE_LEFT); 1.992 + } 1.993 + } 1.994 + 1.995 + return skip; 1.996 +} 1.997 + 1.998 + 1.999 +void 1.1000 +nsIFrame::ApplySkipSides(nsMargin& aMargin, 1.1001 + const nsHTMLReflowState* aReflowState) const 1.1002 +{ 1.1003 + int skipSides = GetSkipSides(aReflowState); 1.1004 + if (skipSides & (1 << NS_SIDE_TOP)) { 1.1005 + aMargin.top = 0; 1.1006 + } 1.1007 + if (skipSides & (1 << NS_SIDE_RIGHT)) { 1.1008 + aMargin.right = 0; 1.1009 + } 1.1010 + if (skipSides & (1 << NS_SIDE_BOTTOM)) { 1.1011 + aMargin.bottom = 0; 1.1012 + } 1.1013 + if (skipSides & (1 << NS_SIDE_LEFT)) { 1.1014 + aMargin.left = 0; 1.1015 + } 1.1016 +} 1.1017 + 1.1018 +void 1.1019 +nsIFrame::ApplyLogicalSkipSides(LogicalMargin& aMargin, 1.1020 + const nsHTMLReflowState* aReflowState) const 1.1021 +{ 1.1022 + int skipSides = GetLogicalSkipSides(aReflowState); 1.1023 + if (skipSides & (LOGICAL_SIDE_B_START)) { 1.1024 + aMargin.BStart(GetWritingMode()) = 0; 1.1025 + } 1.1026 + if (skipSides & (LOGICAL_SIDE_I_END)) { 1.1027 + aMargin.IEnd(GetWritingMode()) = 0; 1.1028 + } 1.1029 + if (skipSides & (LOGICAL_SIDE_B_END)) { 1.1030 + aMargin.BEnd(GetWritingMode()) = 0; 1.1031 + } 1.1032 + if (skipSides & (LOGICAL_SIDE_I_START)) { 1.1033 + aMargin.IStart(GetWritingMode()) = 0; 1.1034 + } 1.1035 +} 1.1036 + 1.1037 +nsRect 1.1038 +nsIFrame::GetPaddingRectRelativeToSelf() const 1.1039 +{ 1.1040 + nsMargin border(GetUsedBorder()); 1.1041 + ApplySkipSides(border); 1.1042 + nsRect r(0, 0, mRect.width, mRect.height); 1.1043 + r.Deflate(border); 1.1044 + return r; 1.1045 +} 1.1046 + 1.1047 +nsRect 1.1048 +nsIFrame::GetPaddingRect() const 1.1049 +{ 1.1050 + return GetPaddingRectRelativeToSelf() + GetPosition(); 1.1051 +} 1.1052 + 1.1053 +WritingMode 1.1054 +nsIFrame::GetWritingMode(nsIFrame* aSubFrame) const 1.1055 +{ 1.1056 + WritingMode writingMode = GetWritingMode(); 1.1057 + 1.1058 + if (!writingMode.IsVertical() && 1.1059 + (StyleTextReset()->mUnicodeBidi & NS_STYLE_UNICODE_BIDI_PLAINTEXT)) { 1.1060 + nsBidiLevel frameLevel = nsBidiPresUtils::GetFrameBaseLevel(aSubFrame); 1.1061 + writingMode.SetDirectionFromBidiLevel(frameLevel); 1.1062 + } 1.1063 + 1.1064 + return writingMode; 1.1065 +} 1.1066 + 1.1067 +nsRect 1.1068 +nsIFrame::GetMarginRectRelativeToSelf() const 1.1069 +{ 1.1070 + nsMargin m = GetUsedMargin(); 1.1071 + ApplySkipSides(m); 1.1072 + nsRect r(0, 0, mRect.width, mRect.height); 1.1073 + r.Inflate(m); 1.1074 + return r; 1.1075 +} 1.1076 + 1.1077 +bool 1.1078 +nsIFrame::IsTransformed() const 1.1079 +{ 1.1080 + return ((mState & NS_FRAME_MAY_BE_TRANSFORMED) && 1.1081 + (StyleDisplay()->HasTransform(this) || 1.1082 + IsSVGTransformed() || 1.1083 + (mContent && 1.1084 + nsLayoutUtils::HasAnimationsForCompositor(mContent, 1.1085 + eCSSProperty_transform) && 1.1086 + IsFrameOfType(eSupportsCSSTransforms) && 1.1087 + mContent->GetPrimaryFrame() == this))); 1.1088 +} 1.1089 + 1.1090 +bool 1.1091 +nsIFrame::HasOpacityInternal(float aThreshold) const 1.1092 +{ 1.1093 + MOZ_ASSERT(0.0 <= aThreshold && aThreshold <= 1.0, "Invalid argument"); 1.1094 + const nsStyleDisplay* displayStyle = StyleDisplay(); 1.1095 + return StyleDisplay()->mOpacity < aThreshold || 1.1096 + (displayStyle->mWillChangeBitField & NS_STYLE_WILL_CHANGE_OPACITY) || 1.1097 + (mContent && 1.1098 + nsLayoutUtils::HasAnimationsForCompositor(mContent, 1.1099 + eCSSProperty_opacity) && 1.1100 + mContent->GetPrimaryFrame() == this); 1.1101 +} 1.1102 + 1.1103 +bool 1.1104 +nsIFrame::IsSVGTransformed(gfx::Matrix *aOwnTransforms, 1.1105 + gfx::Matrix *aFromParentTransforms) const 1.1106 +{ 1.1107 + return false; 1.1108 +} 1.1109 + 1.1110 +bool 1.1111 +nsIFrame::Preserves3DChildren() const 1.1112 +{ 1.1113 + const nsStyleDisplay* disp = StyleDisplay(); 1.1114 + if (disp->mTransformStyle != NS_STYLE_TRANSFORM_STYLE_PRESERVE_3D || 1.1115 + !IsFrameOfType(nsIFrame::eSupportsCSSTransforms)) { 1.1116 + return false; 1.1117 + } 1.1118 + 1.1119 + // If we're all scroll frame, then all descendants will be clipped, so we can't preserve 3d. 1.1120 + if (GetType() == nsGkAtoms::scrollFrame) { 1.1121 + return false; 1.1122 + } 1.1123 + 1.1124 + nsRect temp; 1.1125 + return !nsFrame::ShouldApplyOverflowClipping(this, disp) && 1.1126 + !GetClipPropClipRect(disp, &temp, GetSize()) && 1.1127 + !nsSVGIntegrationUtils::UsingEffectsForFrame(this); 1.1128 +} 1.1129 + 1.1130 +bool 1.1131 +nsIFrame::Preserves3D() const 1.1132 +{ 1.1133 + if (!GetParent() || !GetParent()->Preserves3DChildren()) { 1.1134 + return false; 1.1135 + } 1.1136 + return StyleDisplay()->HasTransform(this) || StyleDisplay()->BackfaceIsHidden(); 1.1137 +} 1.1138 + 1.1139 +bool 1.1140 +nsIFrame::HasPerspective() const 1.1141 +{ 1.1142 + if (!IsTransformed()) { 1.1143 + return false; 1.1144 + } 1.1145 + nsStyleContext* parentStyleContext = StyleContext()->GetParent(); 1.1146 + if (!parentStyleContext) { 1.1147 + return false; 1.1148 + } 1.1149 + const nsStyleDisplay* parentDisp = parentStyleContext->StyleDisplay(); 1.1150 + return parentDisp->mChildPerspective.GetUnit() == eStyleUnit_Coord; 1.1151 +} 1.1152 + 1.1153 +bool 1.1154 +nsIFrame::ChildrenHavePerspective() const 1.1155 +{ 1.1156 + return StyleDisplay()->HasPerspectiveStyle(); 1.1157 +} 1.1158 + 1.1159 +nsRect 1.1160 +nsIFrame::GetContentRectRelativeToSelf() const 1.1161 +{ 1.1162 + nsMargin bp(GetUsedBorderAndPadding()); 1.1163 + ApplySkipSides(bp); 1.1164 + nsRect r(0, 0, mRect.width, mRect.height); 1.1165 + r.Deflate(bp); 1.1166 + return r; 1.1167 +} 1.1168 + 1.1169 +nsRect 1.1170 +nsIFrame::GetContentRect() const 1.1171 +{ 1.1172 + return GetContentRectRelativeToSelf() + GetPosition(); 1.1173 +} 1.1174 + 1.1175 +bool 1.1176 +nsIFrame::ComputeBorderRadii(const nsStyleCorners& aBorderRadius, 1.1177 + const nsSize& aFrameSize, 1.1178 + const nsSize& aBorderArea, 1.1179 + int aSkipSides, 1.1180 + nscoord aRadii[8]) 1.1181 +{ 1.1182 + // Percentages are relative to whichever side they're on. 1.1183 + NS_FOR_CSS_HALF_CORNERS(i) { 1.1184 + const nsStyleCoord c = aBorderRadius.Get(i); 1.1185 + nscoord axis = 1.1186 + NS_HALF_CORNER_IS_X(i) ? aFrameSize.width : aFrameSize.height; 1.1187 + 1.1188 + if (c.IsCoordPercentCalcUnit()) { 1.1189 + aRadii[i] = nsRuleNode::ComputeCoordPercentCalc(c, axis); 1.1190 + if (aRadii[i] < 0) { 1.1191 + // clamp calc() 1.1192 + aRadii[i] = 0; 1.1193 + } 1.1194 + } else { 1.1195 + NS_NOTREACHED("ComputeBorderRadii: bad unit"); 1.1196 + aRadii[i] = 0; 1.1197 + } 1.1198 + } 1.1199 + 1.1200 + if (aSkipSides & (1 << NS_SIDE_TOP)) { 1.1201 + aRadii[NS_CORNER_TOP_LEFT_X] = 0; 1.1202 + aRadii[NS_CORNER_TOP_LEFT_Y] = 0; 1.1203 + aRadii[NS_CORNER_TOP_RIGHT_X] = 0; 1.1204 + aRadii[NS_CORNER_TOP_RIGHT_Y] = 0; 1.1205 + } 1.1206 + 1.1207 + if (aSkipSides & (1 << NS_SIDE_RIGHT)) { 1.1208 + aRadii[NS_CORNER_TOP_RIGHT_X] = 0; 1.1209 + aRadii[NS_CORNER_TOP_RIGHT_Y] = 0; 1.1210 + aRadii[NS_CORNER_BOTTOM_RIGHT_X] = 0; 1.1211 + aRadii[NS_CORNER_BOTTOM_RIGHT_Y] = 0; 1.1212 + } 1.1213 + 1.1214 + if (aSkipSides & (1 << NS_SIDE_BOTTOM)) { 1.1215 + aRadii[NS_CORNER_BOTTOM_RIGHT_X] = 0; 1.1216 + aRadii[NS_CORNER_BOTTOM_RIGHT_Y] = 0; 1.1217 + aRadii[NS_CORNER_BOTTOM_LEFT_X] = 0; 1.1218 + aRadii[NS_CORNER_BOTTOM_LEFT_Y] = 0; 1.1219 + } 1.1220 + 1.1221 + if (aSkipSides & (1 << NS_SIDE_LEFT)) { 1.1222 + aRadii[NS_CORNER_BOTTOM_LEFT_X] = 0; 1.1223 + aRadii[NS_CORNER_BOTTOM_LEFT_Y] = 0; 1.1224 + aRadii[NS_CORNER_TOP_LEFT_X] = 0; 1.1225 + aRadii[NS_CORNER_TOP_LEFT_Y] = 0; 1.1226 + } 1.1227 + 1.1228 + // css3-background specifies this algorithm for reducing 1.1229 + // corner radii when they are too big. 1.1230 + bool haveRadius = false; 1.1231 + double ratio = 1.0f; 1.1232 + NS_FOR_CSS_SIDES(side) { 1.1233 + uint32_t hc1 = NS_SIDE_TO_HALF_CORNER(side, false, true); 1.1234 + uint32_t hc2 = NS_SIDE_TO_HALF_CORNER(side, true, true); 1.1235 + nscoord length = 1.1236 + NS_SIDE_IS_VERTICAL(side) ? aBorderArea.height : aBorderArea.width; 1.1237 + nscoord sum = aRadii[hc1] + aRadii[hc2]; 1.1238 + if (sum) 1.1239 + haveRadius = true; 1.1240 + 1.1241 + // avoid floating point division in the normal case 1.1242 + if (length < sum) 1.1243 + ratio = std::min(ratio, double(length)/sum); 1.1244 + } 1.1245 + if (ratio < 1.0) { 1.1246 + NS_FOR_CSS_HALF_CORNERS(corner) { 1.1247 + aRadii[corner] *= ratio; 1.1248 + } 1.1249 + } 1.1250 + 1.1251 + return haveRadius; 1.1252 +} 1.1253 + 1.1254 +/* static */ void 1.1255 +nsIFrame::InsetBorderRadii(nscoord aRadii[8], const nsMargin &aOffsets) 1.1256 +{ 1.1257 + NS_FOR_CSS_SIDES(side) { 1.1258 + nscoord offset = aOffsets.Side(side); 1.1259 + uint32_t hc1 = NS_SIDE_TO_HALF_CORNER(side, false, false); 1.1260 + uint32_t hc2 = NS_SIDE_TO_HALF_CORNER(side, true, false); 1.1261 + aRadii[hc1] = std::max(0, aRadii[hc1] - offset); 1.1262 + aRadii[hc2] = std::max(0, aRadii[hc2] - offset); 1.1263 + } 1.1264 +} 1.1265 + 1.1266 +/* static */ void 1.1267 +nsIFrame::OutsetBorderRadii(nscoord aRadii[8], const nsMargin &aOffsets) 1.1268 +{ 1.1269 + NS_FOR_CSS_SIDES(side) { 1.1270 + nscoord offset = aOffsets.Side(side); 1.1271 + uint32_t hc1 = NS_SIDE_TO_HALF_CORNER(side, false, false); 1.1272 + uint32_t hc2 = NS_SIDE_TO_HALF_CORNER(side, true, false); 1.1273 + if (aRadii[hc1] > 0) 1.1274 + aRadii[hc1] += offset; 1.1275 + if (aRadii[hc2] > 0) 1.1276 + aRadii[hc2] += offset; 1.1277 + } 1.1278 +} 1.1279 + 1.1280 +/* virtual */ bool 1.1281 +nsIFrame::GetBorderRadii(nscoord aRadii[8]) const 1.1282 +{ 1.1283 + if (IsThemed()) { 1.1284 + // When we're themed, the native theme code draws the border and 1.1285 + // background, and therefore it doesn't make sense to tell other 1.1286 + // code that's interested in border-radius that we have any radii. 1.1287 + // 1.1288 + // In an ideal world, we might have a way for the them to tell us an 1.1289 + // border radius, but since we don't, we're better off assuming 1.1290 + // zero. 1.1291 + NS_FOR_CSS_HALF_CORNERS(corner) { 1.1292 + aRadii[corner] = 0; 1.1293 + } 1.1294 + return false; 1.1295 + } 1.1296 + nsSize size = GetSize(); 1.1297 + return ComputeBorderRadii(StyleBorder()->mBorderRadius, size, size, 1.1298 + GetSkipSides(), aRadii); 1.1299 +} 1.1300 + 1.1301 +bool 1.1302 +nsIFrame::GetPaddingBoxBorderRadii(nscoord aRadii[8]) const 1.1303 +{ 1.1304 + if (!GetBorderRadii(aRadii)) 1.1305 + return false; 1.1306 + InsetBorderRadii(aRadii, GetUsedBorder()); 1.1307 + NS_FOR_CSS_HALF_CORNERS(corner) { 1.1308 + if (aRadii[corner]) 1.1309 + return true; 1.1310 + } 1.1311 + return false; 1.1312 +} 1.1313 + 1.1314 +bool 1.1315 +nsIFrame::GetContentBoxBorderRadii(nscoord aRadii[8]) const 1.1316 +{ 1.1317 + if (!GetBorderRadii(aRadii)) 1.1318 + return false; 1.1319 + InsetBorderRadii(aRadii, GetUsedBorderAndPadding()); 1.1320 + NS_FOR_CSS_HALF_CORNERS(corner) { 1.1321 + if (aRadii[corner]) 1.1322 + return true; 1.1323 + } 1.1324 + return false; 1.1325 +} 1.1326 + 1.1327 +nsStyleContext* 1.1328 +nsFrame::GetAdditionalStyleContext(int32_t aIndex) const 1.1329 +{ 1.1330 + NS_PRECONDITION(aIndex >= 0, "invalid index number"); 1.1331 + return nullptr; 1.1332 +} 1.1333 + 1.1334 +void 1.1335 +nsFrame::SetAdditionalStyleContext(int32_t aIndex, 1.1336 + nsStyleContext* aStyleContext) 1.1337 +{ 1.1338 + NS_PRECONDITION(aIndex >= 0, "invalid index number"); 1.1339 +} 1.1340 + 1.1341 +nscoord 1.1342 +nsFrame::GetBaseline() const 1.1343 +{ 1.1344 + NS_ASSERTION(!NS_SUBTREE_DIRTY(this), 1.1345 + "frame must not be dirty"); 1.1346 + // Default to the bottom margin edge, per CSS2.1's definition of the 1.1347 + // 'baseline' value of 'vertical-align'. 1.1348 + return mRect.height + GetUsedMargin().bottom; 1.1349 +} 1.1350 + 1.1351 +const nsFrameList& 1.1352 +nsFrame::GetChildList(ChildListID aListID) const 1.1353 +{ 1.1354 + if (IsAbsoluteContainer() && 1.1355 + aListID == GetAbsoluteListID()) { 1.1356 + return GetAbsoluteContainingBlock()->GetChildList(); 1.1357 + } else { 1.1358 + return nsFrameList::EmptyList(); 1.1359 + } 1.1360 +} 1.1361 + 1.1362 +void 1.1363 +nsFrame::GetChildLists(nsTArray<ChildList>* aLists) const 1.1364 +{ 1.1365 + if (IsAbsoluteContainer()) { 1.1366 + nsFrameList absoluteList = GetAbsoluteContainingBlock()->GetChildList(); 1.1367 + absoluteList.AppendIfNonempty(aLists, GetAbsoluteListID()); 1.1368 + } 1.1369 +} 1.1370 + 1.1371 +void 1.1372 +nsIFrame::GetCrossDocChildLists(nsTArray<ChildList>* aLists) 1.1373 +{ 1.1374 + nsSubDocumentFrame* subdocumentFrame = do_QueryFrame(this); 1.1375 + if (subdocumentFrame) { 1.1376 + // Descend into the subdocument 1.1377 + nsIFrame* root = subdocumentFrame->GetSubdocumentRootFrame(); 1.1378 + if (root) { 1.1379 + aLists->AppendElement(nsIFrame::ChildList( 1.1380 + nsFrameList(root, nsLayoutUtils::GetLastSibling(root)), 1.1381 + nsIFrame::kPrincipalList)); 1.1382 + } 1.1383 + } 1.1384 + 1.1385 + GetChildLists(aLists); 1.1386 +} 1.1387 + 1.1388 +static nsIFrame* 1.1389 +GetActiveSelectionFrame(nsPresContext* aPresContext, nsIFrame* aFrame) 1.1390 +{ 1.1391 + nsIContent* capturingContent = nsIPresShell::GetCapturingContent(); 1.1392 + if (capturingContent) { 1.1393 + nsIFrame* activeFrame = aPresContext->GetPrimaryFrameFor(capturingContent); 1.1394 + return activeFrame ? activeFrame : aFrame; 1.1395 + } 1.1396 + 1.1397 + return aFrame; 1.1398 +} 1.1399 + 1.1400 +int16_t 1.1401 +nsFrame::DisplaySelection(nsPresContext* aPresContext, bool isOkToTurnOn) 1.1402 +{ 1.1403 + int16_t selType = nsISelectionController::SELECTION_OFF; 1.1404 + 1.1405 + nsCOMPtr<nsISelectionController> selCon; 1.1406 + nsresult result = GetSelectionController(aPresContext, getter_AddRefs(selCon)); 1.1407 + if (NS_SUCCEEDED(result) && selCon) { 1.1408 + result = selCon->GetDisplaySelection(&selType); 1.1409 + if (NS_SUCCEEDED(result) && (selType != nsISelectionController::SELECTION_OFF)) { 1.1410 + // Check whether style allows selection. 1.1411 + bool selectable; 1.1412 + IsSelectable(&selectable, nullptr); 1.1413 + if (!selectable) { 1.1414 + selType = nsISelectionController::SELECTION_OFF; 1.1415 + isOkToTurnOn = false; 1.1416 + } 1.1417 + } 1.1418 + if (isOkToTurnOn && (selType == nsISelectionController::SELECTION_OFF)) { 1.1419 + selCon->SetDisplaySelection(nsISelectionController::SELECTION_ON); 1.1420 + selType = nsISelectionController::SELECTION_ON; 1.1421 + } 1.1422 + } 1.1423 + return selType; 1.1424 +} 1.1425 + 1.1426 +class nsDisplaySelectionOverlay : public nsDisplayItem { 1.1427 +public: 1.1428 + nsDisplaySelectionOverlay(nsDisplayListBuilder* aBuilder, 1.1429 + nsFrame* aFrame, int16_t aSelectionValue) 1.1430 + : nsDisplayItem(aBuilder, aFrame), mSelectionValue(aSelectionValue) { 1.1431 + MOZ_COUNT_CTOR(nsDisplaySelectionOverlay); 1.1432 + } 1.1433 +#ifdef NS_BUILD_REFCNT_LOGGING 1.1434 + virtual ~nsDisplaySelectionOverlay() { 1.1435 + MOZ_COUNT_DTOR(nsDisplaySelectionOverlay); 1.1436 + } 1.1437 +#endif 1.1438 + 1.1439 + virtual void Paint(nsDisplayListBuilder* aBuilder, 1.1440 + nsRenderingContext* aCtx) MOZ_OVERRIDE; 1.1441 + NS_DISPLAY_DECL_NAME("SelectionOverlay", TYPE_SELECTION_OVERLAY) 1.1442 +private: 1.1443 + int16_t mSelectionValue; 1.1444 +}; 1.1445 + 1.1446 +void nsDisplaySelectionOverlay::Paint(nsDisplayListBuilder* aBuilder, 1.1447 + nsRenderingContext* aCtx) 1.1448 +{ 1.1449 + LookAndFeel::ColorID colorID; 1.1450 + if (mSelectionValue == nsISelectionController::SELECTION_ON) { 1.1451 + colorID = LookAndFeel::eColorID_TextSelectBackground; 1.1452 + } else if (mSelectionValue == nsISelectionController::SELECTION_ATTENTION) { 1.1453 + colorID = LookAndFeel::eColorID_TextSelectBackgroundAttention; 1.1454 + } else { 1.1455 + colorID = LookAndFeel::eColorID_TextSelectBackgroundDisabled; 1.1456 + } 1.1457 + 1.1458 + nscolor color = LookAndFeel::GetColor(colorID, NS_RGB(255, 255, 255)); 1.1459 + 1.1460 + gfxRGBA c(color); 1.1461 + c.a = .5; 1.1462 + 1.1463 + gfxContext *ctx = aCtx->ThebesContext(); 1.1464 + ctx->SetColor(c); 1.1465 + 1.1466 + nsIntRect pxRect = 1.1467 + mVisibleRect.ToOutsidePixels(mFrame->PresContext()->AppUnitsPerDevPixel()); 1.1468 + ctx->NewPath(); 1.1469 + ctx->Rectangle(gfxRect(pxRect.x, pxRect.y, pxRect.width, pxRect.height), true); 1.1470 + ctx->Fill(); 1.1471 +} 1.1472 + 1.1473 +/******************************************************** 1.1474 +* Refreshes each content's frame 1.1475 +*********************************************************/ 1.1476 + 1.1477 +void 1.1478 +nsFrame::DisplaySelectionOverlay(nsDisplayListBuilder* aBuilder, 1.1479 + nsDisplayList* aList, 1.1480 + uint16_t aContentType) 1.1481 +{ 1.1482 + if (!IsSelected() || !IsVisibleForPainting(aBuilder)) 1.1483 + return; 1.1484 + 1.1485 + nsPresContext* presContext = PresContext(); 1.1486 + nsIPresShell *shell = presContext->PresShell(); 1.1487 + if (!shell) 1.1488 + return; 1.1489 + 1.1490 + int16_t displaySelection = shell->GetSelectionFlags(); 1.1491 + if (!(displaySelection & aContentType)) 1.1492 + return; 1.1493 + 1.1494 + const nsFrameSelection* frameSelection = GetConstFrameSelection(); 1.1495 + int16_t selectionValue = frameSelection->GetDisplaySelection(); 1.1496 + 1.1497 + if (selectionValue <= nsISelectionController::SELECTION_HIDDEN) 1.1498 + return; // selection is hidden or off 1.1499 + 1.1500 + nsIContent *newContent = mContent->GetParent(); 1.1501 + 1.1502 + //check to see if we are anonymous content 1.1503 + int32_t offset = 0; 1.1504 + if (newContent) { 1.1505 + // XXXbz there has GOT to be a better way of determining this! 1.1506 + offset = newContent->IndexOf(mContent); 1.1507 + } 1.1508 + 1.1509 + SelectionDetails *details; 1.1510 + //look up to see what selection(s) are on this frame 1.1511 + details = frameSelection->LookUpSelection(newContent, offset, 1, false); 1.1512 + if (!details) 1.1513 + return; 1.1514 + 1.1515 + bool normal = false; 1.1516 + while (details) { 1.1517 + if (details->mType == nsISelectionController::SELECTION_NORMAL) { 1.1518 + normal = true; 1.1519 + } 1.1520 + SelectionDetails *next = details->mNext; 1.1521 + delete details; 1.1522 + details = next; 1.1523 + } 1.1524 + 1.1525 + if (!normal && aContentType == nsISelectionDisplay::DISPLAY_IMAGES) { 1.1526 + // Don't overlay an image if it's not in the primary selection. 1.1527 + return; 1.1528 + } 1.1529 + 1.1530 + aList->AppendNewToTop(new (aBuilder) 1.1531 + nsDisplaySelectionOverlay(aBuilder, this, selectionValue)); 1.1532 +} 1.1533 + 1.1534 +void 1.1535 +nsFrame::DisplayOutlineUnconditional(nsDisplayListBuilder* aBuilder, 1.1536 + const nsDisplayListSet& aLists) 1.1537 +{ 1.1538 + if (StyleOutline()->GetOutlineStyle() == NS_STYLE_BORDER_STYLE_NONE) 1.1539 + return; 1.1540 + 1.1541 + aLists.Outlines()->AppendNewToTop( 1.1542 + new (aBuilder) nsDisplayOutline(aBuilder, this)); 1.1543 +} 1.1544 + 1.1545 +void 1.1546 +nsFrame::DisplayOutline(nsDisplayListBuilder* aBuilder, 1.1547 + const nsDisplayListSet& aLists) 1.1548 +{ 1.1549 + if (!IsVisibleForPainting(aBuilder)) 1.1550 + return; 1.1551 + 1.1552 + DisplayOutlineUnconditional(aBuilder, aLists); 1.1553 +} 1.1554 + 1.1555 +void 1.1556 +nsIFrame::DisplayCaret(nsDisplayListBuilder* aBuilder, 1.1557 + const nsRect& aDirtyRect, nsDisplayList* aList) 1.1558 +{ 1.1559 + if (!IsVisibleForPainting(aBuilder)) 1.1560 + return; 1.1561 + 1.1562 + aList->AppendNewToTop( 1.1563 + new (aBuilder) nsDisplayCaret(aBuilder, this, aBuilder->GetCaret())); 1.1564 +} 1.1565 + 1.1566 +nscolor 1.1567 +nsIFrame::GetCaretColorAt(int32_t aOffset) 1.1568 +{ 1.1569 + nscolor color = NS_RGB(0, 0, 0); 1.1570 + if (nsLayoutUtils::GetNativeTextColor(this, color)) 1.1571 + return color; 1.1572 + 1.1573 + // Use CSS text color. 1.1574 + return StyleColor()->mColor; 1.1575 +} 1.1576 + 1.1577 +bool 1.1578 +nsFrame::DisplayBackgroundUnconditional(nsDisplayListBuilder* aBuilder, 1.1579 + const nsDisplayListSet& aLists, 1.1580 + bool aForceBackground) 1.1581 +{ 1.1582 + // Here we don't try to detect background propagation. Frames that might 1.1583 + // receive a propagated background should just set aForceBackground to 1.1584 + // true. 1.1585 + if (aBuilder->IsForEventDelivery() || aForceBackground || 1.1586 + !StyleBackground()->IsTransparent() || StyleDisplay()->mAppearance) { 1.1587 + return nsDisplayBackgroundImage::AppendBackgroundItemsToTop( 1.1588 + aBuilder, this, aLists.BorderBackground()); 1.1589 + } 1.1590 + return false; 1.1591 +} 1.1592 + 1.1593 +void 1.1594 +nsFrame::DisplayBorderBackgroundOutline(nsDisplayListBuilder* aBuilder, 1.1595 + const nsDisplayListSet& aLists, 1.1596 + bool aForceBackground) 1.1597 +{ 1.1598 + // The visibility check belongs here since child elements have the 1.1599 + // opportunity to override the visibility property and display even if 1.1600 + // their parent is hidden. 1.1601 + if (!IsVisibleForPainting(aBuilder)) 1.1602 + return; 1.1603 + 1.1604 + nsCSSShadowArray* shadows = StyleBorder()->mBoxShadow; 1.1605 + if (shadows && shadows->HasShadowWithInset(false)) { 1.1606 + aLists.BorderBackground()->AppendNewToTop(new (aBuilder) 1.1607 + nsDisplayBoxShadowOuter(aBuilder, this)); 1.1608 + } 1.1609 + 1.1610 + bool bgIsThemed = DisplayBackgroundUnconditional(aBuilder, aLists, 1.1611 + aForceBackground); 1.1612 + 1.1613 + if (shadows && shadows->HasShadowWithInset(true)) { 1.1614 + aLists.BorderBackground()->AppendNewToTop(new (aBuilder) 1.1615 + nsDisplayBoxShadowInner(aBuilder, this)); 1.1616 + } 1.1617 + 1.1618 + // If there's a themed background, we should not create a border item. 1.1619 + // It won't be rendered. 1.1620 + if (!bgIsThemed && StyleBorder()->HasBorder()) { 1.1621 + aLists.BorderBackground()->AppendNewToTop(new (aBuilder) 1.1622 + nsDisplayBorder(aBuilder, this)); 1.1623 + } 1.1624 + 1.1625 + DisplayOutlineUnconditional(aBuilder, aLists); 1.1626 +} 1.1627 + 1.1628 +inline static bool IsSVGContentWithCSSClip(const nsIFrame *aFrame) 1.1629 +{ 1.1630 + // The CSS spec says that the 'clip' property only applies to absolutely 1.1631 + // positioned elements, whereas the SVG spec says that it applies to SVG 1.1632 + // elements regardless of the value of the 'position' property. Here we obey 1.1633 + // the CSS spec for outer-<svg> (since that's what we generally do), but 1.1634 + // obey the SVG spec for other SVG elements to which 'clip' applies. 1.1635 + nsIAtom *tag = aFrame->GetContent()->Tag(); 1.1636 + return (aFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT) && 1.1637 + (tag == nsGkAtoms::svg || tag == nsGkAtoms::foreignObject); 1.1638 +} 1.1639 + 1.1640 +bool 1.1641 +nsIFrame::GetClipPropClipRect(const nsStyleDisplay* aDisp, nsRect* aRect, 1.1642 + const nsSize& aSize) const 1.1643 +{ 1.1644 + NS_PRECONDITION(aRect, "Must have aRect out parameter"); 1.1645 + 1.1646 + if (!(aDisp->mClipFlags & NS_STYLE_CLIP_RECT) || 1.1647 + !(aDisp->IsAbsolutelyPositioned(this) || IsSVGContentWithCSSClip(this))) { 1.1648 + return false; 1.1649 + } 1.1650 + 1.1651 + *aRect = aDisp->mClip; 1.1652 + if (NS_STYLE_CLIP_RIGHT_AUTO & aDisp->mClipFlags) { 1.1653 + aRect->width = aSize.width - aRect->x; 1.1654 + } 1.1655 + if (NS_STYLE_CLIP_BOTTOM_AUTO & aDisp->mClipFlags) { 1.1656 + aRect->height = aSize.height - aRect->y; 1.1657 + } 1.1658 + return true; 1.1659 +} 1.1660 + 1.1661 +/** 1.1662 + * If the CSS 'clip' property applies to this frame, set it up 1.1663 + * in aBuilder->ClipState() to clip all content descendants. Returns true 1.1664 + * if the property applies, and if so also returns the clip rect (relative 1.1665 + * to aFrame) in *aRect. 1.1666 + */ 1.1667 +static bool 1.1668 +ApplyClipPropClipping(nsDisplayListBuilder* aBuilder, 1.1669 + const nsIFrame* aFrame, 1.1670 + const nsStyleDisplay* aDisp, 1.1671 + nsRect* aRect, 1.1672 + DisplayListClipState::AutoSaveRestore& aClipState) 1.1673 +{ 1.1674 + if (!aFrame->GetClipPropClipRect(aDisp, aRect, aFrame->GetSize())) 1.1675 + return false; 1.1676 + 1.1677 + nsRect clipRect = *aRect + aBuilder->ToReferenceFrame(aFrame); 1.1678 + aClipState.ClipContentDescendants(clipRect); 1.1679 + return true; 1.1680 +} 1.1681 + 1.1682 +/** 1.1683 + * If the CSS 'overflow' property applies to this frame, and is not 1.1684 + * handled by constructing a dedicated nsHTML/XULScrollFrame, set up clipping 1.1685 + * for that overflow in aBuilder->ClipState() to clip all containing-block 1.1686 + * descendants. 1.1687 + */ 1.1688 +static void 1.1689 +ApplyOverflowClipping(nsDisplayListBuilder* aBuilder, 1.1690 + const nsIFrame* aFrame, 1.1691 + const nsStyleDisplay* aDisp, 1.1692 + DisplayListClipState::AutoClipMultiple& aClipState) 1.1693 +{ 1.1694 + // Only -moz-hidden-unscrollable is handled here (and 'hidden' for table 1.1695 + // frames, and any non-visible value for blocks in a paginated context). 1.1696 + // We allow -moz-hidden-unscrollable to apply to any kind of frame. This 1.1697 + // is required by comboboxes which make their display text (an inline frame) 1.1698 + // have clipping. 1.1699 + if (!nsFrame::ShouldApplyOverflowClipping(aFrame, aDisp)) { 1.1700 + return; 1.1701 + } 1.1702 + nsRect clipRect; 1.1703 + bool haveRadii = false; 1.1704 + nscoord radii[8]; 1.1705 + if (aFrame->StyleDisplay()->mOverflowClipBox == 1.1706 + NS_STYLE_OVERFLOW_CLIP_BOX_PADDING_BOX) { 1.1707 + clipRect = aFrame->GetPaddingRectRelativeToSelf() + 1.1708 + aBuilder->ToReferenceFrame(aFrame); 1.1709 + haveRadii = aFrame->GetPaddingBoxBorderRadii(radii); 1.1710 + } else { 1.1711 + clipRect = aFrame->GetContentRectRelativeToSelf() + 1.1712 + aBuilder->ToReferenceFrame(aFrame); 1.1713 + // XXX border-radius 1.1714 + } 1.1715 + aClipState.ClipContainingBlockDescendantsExtra(clipRect, haveRadii ? radii : nullptr); 1.1716 +} 1.1717 + 1.1718 +#ifdef DEBUG 1.1719 +static void PaintDebugBorder(nsIFrame* aFrame, nsRenderingContext* aCtx, 1.1720 + const nsRect& aDirtyRect, nsPoint aPt) { 1.1721 + nsRect r(aPt, aFrame->GetSize()); 1.1722 + if (aFrame->HasView()) { 1.1723 + aCtx->SetColor(NS_RGB(0,0,255)); 1.1724 + } else { 1.1725 + aCtx->SetColor(NS_RGB(255,0,0)); 1.1726 + } 1.1727 + aCtx->DrawRect(r); 1.1728 +} 1.1729 + 1.1730 +static void PaintEventTargetBorder(nsIFrame* aFrame, nsRenderingContext* aCtx, 1.1731 + const nsRect& aDirtyRect, nsPoint aPt) { 1.1732 + nsRect r(aPt, aFrame->GetSize()); 1.1733 + aCtx->SetColor(NS_RGB(128,0,128)); 1.1734 + aCtx->DrawRect(r); 1.1735 +} 1.1736 + 1.1737 +static void 1.1738 +DisplayDebugBorders(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, 1.1739 + const nsDisplayListSet& aLists) { 1.1740 + // Draw a border around the child 1.1741 + // REVIEW: From nsContainerFrame::PaintChild 1.1742 + if (nsFrame::GetShowFrameBorders() && !aFrame->GetRect().IsEmpty()) { 1.1743 + aLists.Outlines()->AppendNewToTop(new (aBuilder) 1.1744 + nsDisplayGeneric(aBuilder, aFrame, PaintDebugBorder, "DebugBorder", 1.1745 + nsDisplayItem::TYPE_DEBUG_BORDER)); 1.1746 + } 1.1747 + // Draw a border around the current event target 1.1748 + if (nsFrame::GetShowEventTargetFrameBorder() && 1.1749 + aFrame->PresContext()->PresShell()->GetDrawEventTargetFrame() == aFrame) { 1.1750 + aLists.Outlines()->AppendNewToTop(new (aBuilder) 1.1751 + nsDisplayGeneric(aBuilder, aFrame, PaintEventTargetBorder, "EventTargetBorder", 1.1752 + nsDisplayItem::TYPE_EVENT_TARGET_BORDER)); 1.1753 + } 1.1754 +} 1.1755 +#endif 1.1756 + 1.1757 +static nsresult 1.1758 +WrapPreserve3DListInternal(nsIFrame* aFrame, nsDisplayListBuilder *aBuilder, nsDisplayList *aList, nsDisplayList *aOutput, uint32_t& aIndex, nsDisplayList* aTemp) 1.1759 +{ 1.1760 + if (aIndex > nsDisplayTransform::INDEX_MAX) { 1.1761 + return NS_OK; 1.1762 + } 1.1763 + 1.1764 + nsresult rv = NS_OK; 1.1765 + while (nsDisplayItem *item = aList->RemoveBottom()) { 1.1766 + nsIFrame *childFrame = item->Frame(); 1.1767 + 1.1768 + // We accumulate sequential items that aren't transforms into the 'temp' list 1.1769 + // and then flush this list into aOutput by wrapping the whole lot with a single 1.1770 + // nsDisplayTransform. 1.1771 + 1.1772 + if (childFrame->GetParent() && 1.1773 + (childFrame->GetParent()->Preserves3DChildren() || childFrame == aFrame)) { 1.1774 + switch (item->GetType()) { 1.1775 + case nsDisplayItem::TYPE_TRANSFORM: { 1.1776 + if (!aTemp->IsEmpty()) { 1.1777 + aOutput->AppendToTop(new (aBuilder) nsDisplayTransform(aBuilder, aFrame, aTemp, aIndex++)); 1.1778 + } 1.1779 + // Override item's clipping with our current clip state (if any). Since we're 1.1780 + // bubbling up a preserve-3d transformed child to a preserve-3d parent, 1.1781 + // we can be sure the child doesn't have clip state of its own. 1.1782 + NS_ASSERTION(!item->GetClip().HasClip(), "Unexpected clip on item"); 1.1783 + const DisplayItemClip* clip = aBuilder->ClipState().GetCurrentCombinedClip(aBuilder); 1.1784 + if (clip) { 1.1785 + item->SetClip(aBuilder, *clip); 1.1786 + } 1.1787 + aOutput->AppendToTop(item); 1.1788 + break; 1.1789 + } 1.1790 + case nsDisplayItem::TYPE_WRAP_LIST: { 1.1791 + nsDisplayWrapList *list = static_cast<nsDisplayWrapList*>(item); 1.1792 + rv = WrapPreserve3DListInternal(aFrame, aBuilder, 1.1793 + list->GetChildren(), aOutput, aIndex, aTemp); 1.1794 + list->~nsDisplayWrapList(); 1.1795 + break; 1.1796 + } 1.1797 + case nsDisplayItem::TYPE_OPACITY: { 1.1798 + if (!aTemp->IsEmpty()) { 1.1799 + aOutput->AppendToTop(new (aBuilder) nsDisplayTransform(aBuilder, aFrame, aTemp, aIndex++)); 1.1800 + } 1.1801 + nsDisplayOpacity *opacity = static_cast<nsDisplayOpacity*>(item); 1.1802 + nsDisplayList output; 1.1803 + // Call GetChildren, not GetSameCoordinateSystemChildren, because 1.1804 + // the preserve-3d children of 'opacity' are temporarily not in the 1.1805 + // same coordinate system as the opacity --- until this wrapping is done. 1.1806 + rv = WrapPreserve3DListInternal(aFrame, aBuilder, 1.1807 + opacity->GetChildren(), &output, aIndex, aTemp); 1.1808 + if (!aTemp->IsEmpty()) { 1.1809 + output.AppendToTop(new (aBuilder) nsDisplayTransform(aBuilder, aFrame, aTemp, aIndex++)); 1.1810 + } 1.1811 + opacity->GetChildren()->AppendToTop(&output); 1.1812 + opacity->UpdateBounds(aBuilder); 1.1813 + aOutput->AppendToTop(item); 1.1814 + break; 1.1815 + } 1.1816 + default: { 1.1817 + if (childFrame->StyleDisplay()->BackfaceIsHidden()) { 1.1818 + if (!aTemp->IsEmpty()) { 1.1819 + aOutput->AppendToTop(new (aBuilder) nsDisplayTransform(aBuilder, aFrame, aTemp, aIndex++)); 1.1820 + } 1.1821 + 1.1822 + aOutput->AppendToTop(new (aBuilder) nsDisplayTransform(aBuilder, childFrame, item, aIndex++)); 1.1823 + } else { 1.1824 + aTemp->AppendToTop(item); 1.1825 + } 1.1826 + break; 1.1827 + } 1.1828 + } 1.1829 + } else { 1.1830 + aTemp->AppendToTop(item); 1.1831 + } 1.1832 + 1.1833 + if (NS_FAILED(rv) || !item || aIndex > nsDisplayTransform::INDEX_MAX) 1.1834 + return rv; 1.1835 + } 1.1836 + 1.1837 + return NS_OK; 1.1838 +} 1.1839 + 1.1840 +static bool 1.1841 +IsScrollFrameActive(nsIScrollableFrame* aScrollableFrame) 1.1842 +{ 1.1843 + return aScrollableFrame && aScrollableFrame->IsScrollingActive(); 1.1844 +} 1.1845 + 1.1846 +static nsresult 1.1847 +WrapPreserve3DList(nsIFrame* aFrame, nsDisplayListBuilder* aBuilder, nsDisplayList *aList) 1.1848 +{ 1.1849 + uint32_t index = 0; 1.1850 + nsDisplayList temp; 1.1851 + nsDisplayList output; 1.1852 + nsresult rv = WrapPreserve3DListInternal(aFrame, aBuilder, aList, &output, index, &temp); 1.1853 + 1.1854 + if (!temp.IsEmpty()) { 1.1855 + output.AppendToTop(new (aBuilder) nsDisplayTransform(aBuilder, aFrame, &temp, index++)); 1.1856 + } 1.1857 + 1.1858 + aList->AppendToTop(&output); 1.1859 + return rv; 1.1860 +} 1.1861 + 1.1862 +class AutoSaveRestoreBlendMode 1.1863 +{ 1.1864 + nsDisplayListBuilder& mBuilder; 1.1865 + bool AutoResetContainsBlendMode; 1.1866 +public: 1.1867 + AutoSaveRestoreBlendMode(nsDisplayListBuilder& aBuilder) 1.1868 + : mBuilder(aBuilder), 1.1869 + AutoResetContainsBlendMode(aBuilder.ContainsBlendMode()) { 1.1870 + } 1.1871 + 1.1872 + ~AutoSaveRestoreBlendMode() { 1.1873 + mBuilder.SetContainsBlendMode(AutoResetContainsBlendMode); 1.1874 + } 1.1875 +}; 1.1876 + 1.1877 +static void 1.1878 +CheckForTouchEventHandler(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame) 1.1879 +{ 1.1880 + nsIContent* content = aFrame->GetContent(); 1.1881 + if (!content) { 1.1882 + return; 1.1883 + } 1.1884 + EventListenerManager* elm = nsContentUtils::GetExistingListenerManagerForNode(content); 1.1885 + if (!elm) { 1.1886 + return; 1.1887 + } 1.1888 + if (elm->HasListenersFor(nsGkAtoms::ontouchstart) || 1.1889 + elm->HasListenersFor(nsGkAtoms::ontouchmove)) { 1.1890 + aBuilder->SetAncestorHasTouchEventHandler(true); 1.1891 + } 1.1892 +} 1.1893 + 1.1894 +void 1.1895 +nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder, 1.1896 + const nsRect& aDirtyRect, 1.1897 + nsDisplayList* aList) { 1.1898 + if (GetStateBits() & NS_FRAME_TOO_DEEP_IN_FRAME_TREE) 1.1899 + return; 1.1900 + 1.1901 + // Replaced elements have their visibility handled here, because 1.1902 + // they're visually atomic 1.1903 + if (IsFrameOfType(eReplaced) && !IsVisibleForPainting(aBuilder)) 1.1904 + return; 1.1905 + 1.1906 + const nsStyleDisplay* disp = StyleDisplay(); 1.1907 + // We can stop right away if this is a zero-opacity stacking context and 1.1908 + // we're painting, and we're not animating opacity. Don't do this 1.1909 + // if we're going to compute plugin geometry, since opacity-0 plugins 1.1910 + // need to have display items built for them. 1.1911 + if (disp->mOpacity == 0.0 && aBuilder->IsForPainting() && 1.1912 + !aBuilder->WillComputePluginGeometry() && 1.1913 + !(disp->mWillChangeBitField & NS_STYLE_WILL_CHANGE_OPACITY) && 1.1914 + !nsLayoutUtils::HasAnimations(mContent, eCSSProperty_opacity)) { 1.1915 + return; 1.1916 + } 1.1917 + 1.1918 + nsRect dirtyRect = aDirtyRect; 1.1919 + 1.1920 + bool inTransform = aBuilder->IsInTransform(); 1.1921 + bool isTransformed = IsTransformed(); 1.1922 + // reset blend mode so we can keep track if this stacking context needs have 1.1923 + // a nsDisplayBlendContainer. Set the blend mode back when the routine exits 1.1924 + // so we keep track if the parent stacking context needs a container too. 1.1925 + AutoSaveRestoreBlendMode autoRestoreBlendMode(*aBuilder); 1.1926 + aBuilder->SetContainsBlendMode(false); 1.1927 + 1.1928 + if (isTransformed) { 1.1929 + const nsRect overflow = GetVisualOverflowRectRelativeToSelf(); 1.1930 + if (aBuilder->IsForPainting() && 1.1931 + nsDisplayTransform::ShouldPrerenderTransformedContent(aBuilder, this)) { 1.1932 + dirtyRect = overflow; 1.1933 + } else { 1.1934 + if (overflow.IsEmpty() && !Preserves3DChildren()) { 1.1935 + return; 1.1936 + } 1.1937 + 1.1938 + nsPoint offset = aBuilder->ToReferenceFrame(this); 1.1939 + dirtyRect += offset; 1.1940 + 1.1941 + nsRect untransformedDirtyRect; 1.1942 + if (nsDisplayTransform::UntransformRect(dirtyRect, overflow, this, offset, &untransformedDirtyRect)) { 1.1943 + dirtyRect = untransformedDirtyRect; 1.1944 + } else { 1.1945 + NS_WARNING("Unable to untransform dirty rect!"); 1.1946 + // This should only happen if the transform is singular, in which case nothing is visible anyway 1.1947 + dirtyRect.SetEmpty(); 1.1948 + } 1.1949 + } 1.1950 + inTransform = true; 1.1951 + } 1.1952 + 1.1953 + bool useOpacity = HasVisualOpacity() && !nsSVGUtils::CanOptimizeOpacity(this); 1.1954 + bool useBlendMode = disp->mMixBlendMode != NS_STYLE_BLEND_NORMAL; 1.1955 + bool usingSVGEffects = nsSVGIntegrationUtils::UsingEffectsForFrame(this); 1.1956 + bool useStickyPosition = disp->mPosition == NS_STYLE_POSITION_STICKY && 1.1957 + IsScrollFrameActive(nsLayoutUtils::GetNearestScrollableFrame(GetParent(), 1.1958 + nsLayoutUtils::SCROLLABLE_SAME_DOC | 1.1959 + nsLayoutUtils::SCROLLABLE_INCLUDE_HIDDEN)); 1.1960 + 1.1961 + DisplayListClipState::AutoSaveRestore clipState(aBuilder); 1.1962 + 1.1963 + if (isTransformed || useOpacity || useBlendMode || usingSVGEffects || useStickyPosition) { 1.1964 + // We don't need to pass ancestor clipping down to our children; 1.1965 + // everything goes inside a display item's child list, and the display 1.1966 + // item itself will be clipped. 1.1967 + // For transforms we also need to clear ancestor clipping because it's 1.1968 + // relative to the wrong display item reference frame anyway. 1.1969 + clipState.Clear(); 1.1970 + } 1.1971 + 1.1972 + nsDisplayListCollection set; 1.1973 + { 1.1974 + nsDisplayListBuilder::AutoBuildingDisplayList rootSetter(aBuilder, true); 1.1975 + DisplayListClipState::AutoSaveRestore nestedClipState(aBuilder); 1.1976 + nsDisplayListBuilder::AutoInTransformSetter 1.1977 + inTransformSetter(aBuilder, inTransform); 1.1978 + CheckForTouchEventHandler(aBuilder, this); 1.1979 + 1.1980 + if (usingSVGEffects) { 1.1981 + dirtyRect = 1.1982 + nsSVGIntegrationUtils::GetRequiredSourceForInvalidArea(this, dirtyRect); 1.1983 + } 1.1984 + 1.1985 + nsRect clipPropClip; 1.1986 + if (ApplyClipPropClipping(aBuilder, this, disp, &clipPropClip, 1.1987 + nestedClipState)) { 1.1988 + dirtyRect.IntersectRect(dirtyRect, clipPropClip); 1.1989 + } 1.1990 + 1.1991 + MarkAbsoluteFramesForDisplayList(aBuilder, dirtyRect); 1.1992 + 1.1993 + // Preserve3DChildren() also guarantees that applyAbsPosClipping and usingSVGEffects are false 1.1994 + // We only modify the preserve-3d rect if we are the top of a preserve-3d heirarchy 1.1995 + if (Preserves3DChildren()) { 1.1996 + aBuilder->MarkPreserve3DFramesForDisplayList(this, aDirtyRect); 1.1997 + } 1.1998 + 1.1999 + if (aBuilder->IsBuildingLayerEventRegions()) { 1.2000 + nsDisplayLayerEventRegions* eventRegions = 1.2001 + new (aBuilder) nsDisplayLayerEventRegions(aBuilder, this); 1.2002 + aBuilder->SetLayerEventRegions(eventRegions); 1.2003 + set.BorderBackground()->AppendNewToTop(eventRegions); 1.2004 + } 1.2005 + BuildDisplayList(aBuilder, dirtyRect, set); 1.2006 + } 1.2007 + 1.2008 + if (aBuilder->IsBackgroundOnly()) { 1.2009 + set.BlockBorderBackgrounds()->DeleteAll(); 1.2010 + set.Floats()->DeleteAll(); 1.2011 + set.Content()->DeleteAll(); 1.2012 + set.PositionedDescendants()->DeleteAll(); 1.2013 + set.Outlines()->DeleteAll(); 1.2014 + } 1.2015 + 1.2016 + // This z-order sort also sorts secondarily by content order. We need to do 1.2017 + // this so that boxes produced by the same element are placed together 1.2018 + // in the sort. Consider a position:relative inline element that breaks 1.2019 + // across lines and has absolutely positioned children; all the abs-pos 1.2020 + // children should be z-ordered after all the boxes for the position:relative 1.2021 + // element itself. 1.2022 + set.PositionedDescendants()->SortByZOrder(aBuilder, GetContent()); 1.2023 + 1.2024 + nsDisplayList resultList; 1.2025 + // Now follow the rules of http://www.w3.org/TR/CSS21/zindex.html 1.2026 + // 1,2: backgrounds and borders 1.2027 + resultList.AppendToTop(set.BorderBackground()); 1.2028 + // 3: negative z-index children. 1.2029 + for (;;) { 1.2030 + nsDisplayItem* item = set.PositionedDescendants()->GetBottom(); 1.2031 + if (item && item->ZIndex() < 0) { 1.2032 + set.PositionedDescendants()->RemoveBottom(); 1.2033 + resultList.AppendToTop(item); 1.2034 + continue; 1.2035 + } 1.2036 + break; 1.2037 + } 1.2038 + // 4: block backgrounds 1.2039 + resultList.AppendToTop(set.BlockBorderBackgrounds()); 1.2040 + // 5: floats 1.2041 + resultList.AppendToTop(set.Floats()); 1.2042 + // 7: general content 1.2043 + resultList.AppendToTop(set.Content()); 1.2044 + // 7.5: outlines, in content tree order. We need to sort by content order 1.2045 + // because an element with outline that breaks and has children with outline 1.2046 + // might have placed child outline items between its own outline items. 1.2047 + // The element's outline items need to all come before any child outline 1.2048 + // items. 1.2049 + nsIContent* content = GetContent(); 1.2050 + if (!content) { 1.2051 + content = PresContext()->Document()->GetRootElement(); 1.2052 + } 1.2053 + if (content) { 1.2054 + set.Outlines()->SortByContentOrder(aBuilder, content); 1.2055 + } 1.2056 +#ifdef DEBUG 1.2057 + DisplayDebugBorders(aBuilder, this, set); 1.2058 +#endif 1.2059 + resultList.AppendToTop(set.Outlines()); 1.2060 + // 8, 9: non-negative z-index children 1.2061 + resultList.AppendToTop(set.PositionedDescendants()); 1.2062 + 1.2063 + if (!isTransformed) { 1.2064 + // Restore saved clip state now so that any display items we create below 1.2065 + // are clipped properly. 1.2066 + clipState.Restore(); 1.2067 + } 1.2068 + 1.2069 + /* If there are any SVG effects, wrap the list up in an SVG effects item 1.2070 + * (which also handles CSS group opacity). Note that we create an SVG effects 1.2071 + * item even if resultList is empty, since a filter can produce graphical 1.2072 + * output even if the element being filtered wouldn't otherwise do so. 1.2073 + */ 1.2074 + if (usingSVGEffects) { 1.2075 + /* List now emptied, so add the new list to the top. */ 1.2076 + resultList.AppendNewToTop( 1.2077 + new (aBuilder) nsDisplaySVGEffects(aBuilder, this, &resultList)); 1.2078 + } 1.2079 + /* Else, if the list is non-empty and there is CSS group opacity without SVG 1.2080 + * effects, wrap it up in an opacity item. 1.2081 + */ 1.2082 + else if (useOpacity && !resultList.IsEmpty()) { 1.2083 + resultList.AppendNewToTop( 1.2084 + new (aBuilder) nsDisplayOpacity(aBuilder, this, &resultList)); 1.2085 + } 1.2086 + /* If we have sticky positioning, wrap it in a sticky position item. 1.2087 + */ 1.2088 + if (useStickyPosition) { 1.2089 + resultList.AppendNewToTop( 1.2090 + new (aBuilder) nsDisplayStickyPosition(aBuilder, this, &resultList)); 1.2091 + } 1.2092 + 1.2093 + /* If we're going to apply a transformation and don't have preserve-3d set, wrap 1.2094 + * everything in an nsDisplayTransform. If there's nothing in the list, don't add 1.2095 + * anything. 1.2096 + * 1.2097 + * For the preserve-3d case we want to individually wrap every child in the list with 1.2098 + * a separate nsDisplayTransform instead. When the child is already an nsDisplayTransform, 1.2099 + * we can skip this step, as the computed transform will already include our own. 1.2100 + * 1.2101 + * We also traverse into sublists created by nsDisplayWrapList or nsDisplayOpacity, so that 1.2102 + * we find all the correct children. 1.2103 + */ 1.2104 + if (isTransformed && !resultList.IsEmpty()) { 1.2105 + // Restore clip state now so nsDisplayTransform is clipped properly. 1.2106 + clipState.Restore(); 1.2107 + 1.2108 + if (Preserves3DChildren()) { 1.2109 + WrapPreserve3DList(this, aBuilder, &resultList); 1.2110 + } else { 1.2111 + resultList.AppendNewToTop( 1.2112 + new (aBuilder) nsDisplayTransform(aBuilder, this, &resultList)); 1.2113 + } 1.2114 + } 1.2115 + 1.2116 + /* If adding both a nsDisplayBlendContainer and a nsDisplayMixBlendMode to the 1.2117 + * same list, the nsDisplayBlendContainer should be added first. This only 1.2118 + * happens when the element creating this stacking context has mix-blend-mode 1.2119 + * and also contains a child which has mix-blend-mode. 1.2120 + * The nsDisplayBlendContainer must be added to the list first, so it does not 1.2121 + * isolate the containing element blending as well. 1.2122 + */ 1.2123 + 1.2124 + if (aBuilder->ContainsBlendMode()) { 1.2125 + resultList.AppendNewToTop( 1.2126 + new (aBuilder) nsDisplayBlendContainer(aBuilder, this, &resultList)); 1.2127 + } 1.2128 + 1.2129 + /* If there's blending, wrap up the list in a blend-mode item. Note 1.2130 + * that opacity can be applied before blending as the blend color is 1.2131 + * not affected by foreground opacity (only background alpha). 1.2132 + */ 1.2133 + 1.2134 + if (useBlendMode && !resultList.IsEmpty()) { 1.2135 + resultList.AppendNewToTop( 1.2136 + new (aBuilder) nsDisplayMixBlendMode(aBuilder, this, &resultList)); 1.2137 + } 1.2138 + 1.2139 + CreateOwnLayerIfNeeded(aBuilder, &resultList); 1.2140 + 1.2141 + aList->AppendToTop(&resultList); 1.2142 +} 1.2143 + 1.2144 +static nsDisplayItem* 1.2145 +WrapInWrapList(nsDisplayListBuilder* aBuilder, 1.2146 + nsIFrame* aFrame, nsDisplayList* aList) 1.2147 +{ 1.2148 + nsDisplayItem* item = aList->GetBottom(); 1.2149 + if (!item || item->GetAbove() || item->Frame() != aFrame) { 1.2150 + return new (aBuilder) nsDisplayWrapList(aBuilder, aFrame, aList); 1.2151 + } 1.2152 + aList->RemoveBottom(); 1.2153 + return item; 1.2154 +} 1.2155 + 1.2156 +void 1.2157 +nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder, 1.2158 + nsIFrame* aChild, 1.2159 + const nsRect& aDirtyRect, 1.2160 + const nsDisplayListSet& aLists, 1.2161 + uint32_t aFlags) { 1.2162 + // If painting is restricted to just the background of the top level frame, 1.2163 + // then we have nothing to do here. 1.2164 + if (aBuilder->IsBackgroundOnly()) 1.2165 + return; 1.2166 + 1.2167 + nsIFrame* child = aChild; 1.2168 + if (child->GetStateBits() & NS_FRAME_TOO_DEEP_IN_FRAME_TREE) 1.2169 + return; 1.2170 + 1.2171 + bool isSVG = (child->GetStateBits() & NS_FRAME_SVG_LAYOUT); 1.2172 + 1.2173 + // true if this is a real or pseudo stacking context 1.2174 + bool pseudoStackingContext = 1.2175 + (aFlags & DISPLAY_CHILD_FORCE_PSEUDO_STACKING_CONTEXT) != 0; 1.2176 + if (!isSVG && 1.2177 + (aFlags & DISPLAY_CHILD_INLINE) && 1.2178 + !child->IsFrameOfType(eLineParticipant)) { 1.2179 + // child is a non-inline frame in an inline context, i.e., 1.2180 + // it acts like inline-block or inline-table. Therefore it is a 1.2181 + // pseudo-stacking-context. 1.2182 + pseudoStackingContext = true; 1.2183 + } 1.2184 + 1.2185 + // dirty rect in child-relative coordinates 1.2186 + nsRect dirty = aDirtyRect - child->GetOffsetTo(this); 1.2187 + 1.2188 + nsIAtom* childType = child->GetType(); 1.2189 + nsDisplayListBuilder::OutOfFlowDisplayData* savedOutOfFlowData = nullptr; 1.2190 + if (childType == nsGkAtoms::placeholderFrame) { 1.2191 + nsPlaceholderFrame* placeholder = static_cast<nsPlaceholderFrame*>(child); 1.2192 + child = placeholder->GetOutOfFlowFrame(); 1.2193 + NS_ASSERTION(child, "No out of flow frame?"); 1.2194 + // If 'child' is a pushed float then it's owned by a block that's not an 1.2195 + // ancestor of the placeholder, and it will be painted by that block and 1.2196 + // should not be painted through the placeholder. 1.2197 + if (!child || nsLayoutUtils::IsPopup(child) || 1.2198 + (child->GetStateBits() & NS_FRAME_IS_PUSHED_FLOAT)) 1.2199 + return; 1.2200 + // Make sure that any attempt to use childType below is disappointed. We 1.2201 + // could call GetType again but since we don't currently need it, let's 1.2202 + // avoid the virtual call. 1.2203 + childType = nullptr; 1.2204 + // Recheck NS_FRAME_TOO_DEEP_IN_FRAME_TREE 1.2205 + if (child->GetStateBits() & NS_FRAME_TOO_DEEP_IN_FRAME_TREE) 1.2206 + return; 1.2207 + savedOutOfFlowData = static_cast<nsDisplayListBuilder::OutOfFlowDisplayData*> 1.2208 + (child->Properties().Get(nsDisplayListBuilder::OutOfFlowDisplayDataProperty())); 1.2209 + if (savedOutOfFlowData) { 1.2210 + dirty = savedOutOfFlowData->mDirtyRect; 1.2211 + } else { 1.2212 + // The out-of-flow frame did not intersect the dirty area. We may still 1.2213 + // need to traverse into it, since it may contain placeholders we need 1.2214 + // to enter to reach other out-of-flow frames that are visible. 1.2215 + dirty.SetEmpty(); 1.2216 + } 1.2217 + pseudoStackingContext = true; 1.2218 + } 1.2219 + if (child->Preserves3D()) { 1.2220 + nsRect* savedDirty = static_cast<nsRect*> 1.2221 + (child->Properties().Get(nsDisplayListBuilder::Preserve3DDirtyRectProperty())); 1.2222 + if (savedDirty) { 1.2223 + dirty = *savedDirty; 1.2224 + } else { 1.2225 + dirty.SetEmpty(); 1.2226 + } 1.2227 + } 1.2228 + 1.2229 + NS_ASSERTION(childType != nsGkAtoms::placeholderFrame, 1.2230 + "Should have dealt with placeholders already"); 1.2231 + if (aBuilder->GetSelectedFramesOnly() && 1.2232 + child->IsLeaf() && 1.2233 + !aChild->IsSelected()) { 1.2234 + return; 1.2235 + } 1.2236 + 1.2237 + if (aBuilder->GetIncludeAllOutOfFlows() && 1.2238 + (child->GetStateBits() & NS_FRAME_OUT_OF_FLOW)) { 1.2239 + dirty = child->GetVisualOverflowRect(); 1.2240 + } else if (!(child->GetStateBits() & NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO)) { 1.2241 + // No need to descend into child to catch placeholders for visible 1.2242 + // positioned stuff. So see if we can short-circuit frame traversal here. 1.2243 + 1.2244 + // We can stop if child's frame subtree's intersection with the 1.2245 + // dirty area is empty. 1.2246 + // If the child is a scrollframe that we want to ignore, then we need 1.2247 + // to descend into it because its scrolled child may intersect the dirty 1.2248 + // area even if the scrollframe itself doesn't. 1.2249 + // There are cases where the "ignore scroll frame" on the builder is not set 1.2250 + // correctly, and so we additionally want to catch cases where the child is 1.2251 + // a root scrollframe and we are ignoring scrolling on the viewport. 1.2252 + nsIPresShell* shell = PresContext()->PresShell(); 1.2253 + bool keepDescending = child == aBuilder->GetIgnoreScrollFrame() || 1.2254 + (shell->IgnoringViewportScrolling() && child == shell->GetRootScrollFrame()); 1.2255 + if (!keepDescending) { 1.2256 + nsRect childDirty; 1.2257 + if (!childDirty.IntersectRect(dirty, child->GetVisualOverflowRect())) 1.2258 + return; 1.2259 + // Usually we could set dirty to childDirty now but there's no 1.2260 + // benefit, and it can be confusing. It can especially confuse 1.2261 + // situations where we're going to ignore a scrollframe's clipping; 1.2262 + // we wouldn't want to clip the dirty area to the scrollframe's 1.2263 + // bounds in that case. 1.2264 + } 1.2265 + } 1.2266 + 1.2267 + // XXX need to have inline-block and inline-table set pseudoStackingContext 1.2268 + 1.2269 + const nsStyleDisplay* ourDisp = StyleDisplay(); 1.2270 + // REVIEW: Taken from nsBoxFrame::Paint 1.2271 + // Don't paint our children if the theme object is a leaf. 1.2272 + if (IsThemed(ourDisp) && 1.2273 + !PresContext()->GetTheme()->WidgetIsContainer(ourDisp->mAppearance)) 1.2274 + return; 1.2275 + 1.2276 + // Child is composited if it's transformed, partially transparent, or has 1.2277 + // SVG effects or a blend mode.. 1.2278 + const nsStyleDisplay* disp = child->StyleDisplay(); 1.2279 + const nsStylePosition* pos = child->StylePosition(); 1.2280 + bool isVisuallyAtomic = child->HasOpacity() 1.2281 + || child->IsTransformed() 1.2282 + // strictly speaking, 'perspective' doesn't require visual atomicity, 1.2283 + // but the spec says it acts like the rest of these 1.2284 + || disp->mChildPerspective.GetUnit() == eStyleUnit_Coord 1.2285 + || disp->mMixBlendMode != NS_STYLE_BLEND_NORMAL 1.2286 + || nsSVGIntegrationUtils::UsingEffectsForFrame(child); 1.2287 + 1.2288 + bool isPositioned = disp->IsPositioned(child); 1.2289 + bool isStackingContext = 1.2290 + (isPositioned && (disp->mPosition == NS_STYLE_POSITION_STICKY || 1.2291 + pos->mZIndex.GetUnit() == eStyleUnit_Integer)) || 1.2292 + (disp->mWillChangeBitField & NS_STYLE_WILL_CHANGE_STACKING_CONTEXT) || 1.2293 + isVisuallyAtomic || (aFlags & DISPLAY_CHILD_FORCE_STACKING_CONTEXT); 1.2294 + 1.2295 + if (isVisuallyAtomic || isPositioned || (!isSVG && disp->IsFloating(child)) || 1.2296 + ((disp->mClipFlags & NS_STYLE_CLIP_RECT) && 1.2297 + IsSVGContentWithCSSClip(child)) || 1.2298 + (disp->mWillChangeBitField & NS_STYLE_WILL_CHANGE_STACKING_CONTEXT) || 1.2299 + (aFlags & DISPLAY_CHILD_FORCE_STACKING_CONTEXT)) { 1.2300 + // If you change this, also change IsPseudoStackingContextFromStyle() 1.2301 + pseudoStackingContext = true; 1.2302 + } 1.2303 + NS_ASSERTION(!isStackingContext || pseudoStackingContext, 1.2304 + "Stacking contexts must also be pseudo-stacking-contexts"); 1.2305 + 1.2306 + bool isInFixedPos = aBuilder->IsInFixedPos() || 1.2307 + (isPositioned && 1.2308 + disp->mPosition == NS_STYLE_POSITION_FIXED && 1.2309 + nsLayoutUtils::IsReallyFixedPos(child)); 1.2310 + nsDisplayListBuilder::AutoInFixedPosSetter 1.2311 + buildingInFixedPos(aBuilder, isInFixedPos); 1.2312 + 1.2313 + nsDisplayListBuilder::AutoBuildingDisplayList 1.2314 + buildingForChild(aBuilder, child, pseudoStackingContext); 1.2315 + DisplayListClipState::AutoClipMultiple clipState(aBuilder); 1.2316 + CheckForTouchEventHandler(aBuilder, child); 1.2317 + 1.2318 + if (savedOutOfFlowData) { 1.2319 + clipState.SetClipForContainingBlockDescendants( 1.2320 + &savedOutOfFlowData->mContainingBlockClip); 1.2321 + } 1.2322 + 1.2323 + // Setup clipping for the parent's overflow:-moz-hidden-unscrollable, 1.2324 + // or overflow:hidden on elements that don't support scrolling (and therefore 1.2325 + // don't create nsHTML/XULScrollFrame). This clipping needs to not clip 1.2326 + // anything directly rendered by the parent, only the rendering of its 1.2327 + // children. 1.2328 + // Don't use overflowClip to restrict the dirty rect, since some of the 1.2329 + // descendants may not be clipped by it. Even if we end up with unnecessary 1.2330 + // display items, they'll be pruned during ComputeVisibility. 1.2331 + nsIFrame* parent = child->GetParent(); 1.2332 + const nsStyleDisplay* parentDisp = 1.2333 + parent == this ? ourDisp : parent->StyleDisplay(); 1.2334 + ApplyOverflowClipping(aBuilder, parent, parentDisp, clipState); 1.2335 + 1.2336 + nsDisplayList list; 1.2337 + nsDisplayList extraPositionedDescendants; 1.2338 + if (isStackingContext) { 1.2339 + if (disp->mMixBlendMode != NS_STYLE_BLEND_NORMAL) { 1.2340 + aBuilder->SetContainsBlendMode(true); 1.2341 + } 1.2342 + // True stacking context. 1.2343 + // For stacking contexts, BuildDisplayListForStackingContext handles 1.2344 + // clipping and MarkAbsoluteFramesForDisplayList. 1.2345 + child->BuildDisplayListForStackingContext(aBuilder, dirty, &list); 1.2346 + aBuilder->DisplayCaret(child, dirty, &list); 1.2347 + } else { 1.2348 + nsRect clipRect; 1.2349 + if (ApplyClipPropClipping(aBuilder, child, disp, &clipRect, clipState)) { 1.2350 + // clipRect is in builder-reference-frame coordinates, 1.2351 + // dirty/clippedDirtyRect are in child coordinates 1.2352 + dirty.IntersectRect(dirty, clipRect); 1.2353 + } 1.2354 + 1.2355 + child->MarkAbsoluteFramesForDisplayList(aBuilder, dirty); 1.2356 + 1.2357 + if (!pseudoStackingContext) { 1.2358 + // THIS IS THE COMMON CASE. 1.2359 + // Not a pseudo or real stacking context. Do the simple thing and 1.2360 + // return early. 1.2361 + nsDisplayLayerEventRegions* eventRegions = aBuilder->GetLayerEventRegions(); 1.2362 + if (eventRegions) { 1.2363 + eventRegions->AddFrame(aBuilder, child); 1.2364 + } 1.2365 + child->BuildDisplayList(aBuilder, dirty, aLists); 1.2366 + aBuilder->DisplayCaret(child, dirty, aLists.Content()); 1.2367 +#ifdef DEBUG 1.2368 + DisplayDebugBorders(aBuilder, child, aLists); 1.2369 +#endif 1.2370 + return; 1.2371 + } 1.2372 + 1.2373 + // A pseudo-stacking context (e.g., a positioned element with z-index auto). 1.2374 + // We allow positioned descendants of the child to escape to our parent 1.2375 + // stacking context's positioned descendant list, because they might be 1.2376 + // z-index:non-auto 1.2377 + nsDisplayListCollection pseudoStack; 1.2378 + if (aBuilder->IsBuildingLayerEventRegions()) { 1.2379 + nsDisplayLayerEventRegions* eventRegions = 1.2380 + new (aBuilder) nsDisplayLayerEventRegions(aBuilder, this); 1.2381 + aBuilder->SetLayerEventRegions(eventRegions); 1.2382 + pseudoStack.BorderBackground()->AppendNewToTop(eventRegions); 1.2383 + } 1.2384 + child->BuildDisplayList(aBuilder, dirty, pseudoStack); 1.2385 + aBuilder->DisplayCaret(child, dirty, pseudoStack.Content()); 1.2386 + 1.2387 + list.AppendToTop(pseudoStack.BorderBackground()); 1.2388 + list.AppendToTop(pseudoStack.BlockBorderBackgrounds()); 1.2389 + list.AppendToTop(pseudoStack.Floats()); 1.2390 + list.AppendToTop(pseudoStack.Content()); 1.2391 + list.AppendToTop(pseudoStack.Outlines()); 1.2392 + extraPositionedDescendants.AppendToTop(pseudoStack.PositionedDescendants()); 1.2393 +#ifdef DEBUG 1.2394 + DisplayDebugBorders(aBuilder, child, aLists); 1.2395 +#endif 1.2396 + } 1.2397 + 1.2398 + // Clear clip rect for the construction of the items below. Since we're 1.2399 + // clipping all their contents, they themselves don't need to be clipped. 1.2400 + clipState.Clear(); 1.2401 + 1.2402 + if (isPositioned || isVisuallyAtomic || 1.2403 + (aFlags & DISPLAY_CHILD_FORCE_STACKING_CONTEXT)) { 1.2404 + // Genuine stacking contexts, and positioned pseudo-stacking-contexts, 1.2405 + // go in this level. 1.2406 + if (!list.IsEmpty()) { 1.2407 + nsDisplayItem* item = WrapInWrapList(aBuilder, child, &list); 1.2408 + if (isSVG) { 1.2409 + aLists.Content()->AppendNewToTop(item); 1.2410 + } else { 1.2411 + aLists.PositionedDescendants()->AppendNewToTop(item); 1.2412 + } 1.2413 + } 1.2414 + } else if (!isSVG && disp->IsFloating(child)) { 1.2415 + if (!list.IsEmpty()) { 1.2416 + aLists.Floats()->AppendNewToTop(WrapInWrapList(aBuilder, child, &list)); 1.2417 + } 1.2418 + } else { 1.2419 + aLists.Content()->AppendToTop(&list); 1.2420 + } 1.2421 + // We delay placing the positioned descendants of positioned frames to here, 1.2422 + // because in the absence of z-index this is the correct order for them. 1.2423 + // This doesn't affect correctness because the positioned descendants list 1.2424 + // is sorted by z-order and content in BuildDisplayListForStackingContext, 1.2425 + // but it means that sort routine needs to do less work. 1.2426 + aLists.PositionedDescendants()->AppendToTop(&extraPositionedDescendants); 1.2427 +} 1.2428 + 1.2429 +void 1.2430 +nsIFrame::MarkAbsoluteFramesForDisplayList(nsDisplayListBuilder* aBuilder, 1.2431 + const nsRect& aDirtyRect) 1.2432 +{ 1.2433 + if (IsAbsoluteContainer()) { 1.2434 + aBuilder->MarkFramesForDisplayList(this, GetAbsoluteContainingBlock()->GetChildList(), aDirtyRect); 1.2435 + } 1.2436 +} 1.2437 + 1.2438 +nsresult 1.2439 +nsFrame::GetContentForEvent(WidgetEvent* aEvent, 1.2440 + nsIContent** aContent) 1.2441 +{ 1.2442 + nsIFrame* f = nsLayoutUtils::GetNonGeneratedAncestor(this); 1.2443 + *aContent = f->GetContent(); 1.2444 + NS_IF_ADDREF(*aContent); 1.2445 + return NS_OK; 1.2446 +} 1.2447 + 1.2448 +void 1.2449 +nsFrame::FireDOMEvent(const nsAString& aDOMEventName, nsIContent *aContent) 1.2450 +{ 1.2451 + nsIContent* target = aContent ? aContent : mContent; 1.2452 + 1.2453 + if (target) { 1.2454 + nsRefPtr<AsyncEventDispatcher> asyncDispatcher = 1.2455 + new AsyncEventDispatcher(target, aDOMEventName, true, false); 1.2456 + DebugOnly<nsresult> rv = asyncDispatcher->PostDOMEvent(); 1.2457 + NS_ASSERTION(NS_SUCCEEDED(rv), "AsyncEventDispatcher failed to dispatch"); 1.2458 + } 1.2459 +} 1.2460 + 1.2461 +nsresult 1.2462 +nsFrame::HandleEvent(nsPresContext* aPresContext, 1.2463 + WidgetGUIEvent* aEvent, 1.2464 + nsEventStatus* aEventStatus) 1.2465 +{ 1.2466 + 1.2467 + if (aEvent->message == NS_MOUSE_MOVE) { 1.2468 + // XXX If the second argument of HandleDrag() is WidgetMouseEvent, 1.2469 + // the implementation becomes simpler. 1.2470 + return HandleDrag(aPresContext, aEvent, aEventStatus); 1.2471 + } 1.2472 + 1.2473 + if ((aEvent->eventStructType == NS_MOUSE_EVENT && 1.2474 + aEvent->AsMouseEvent()->button == WidgetMouseEvent::eLeftButton) || 1.2475 + aEvent->eventStructType == NS_TOUCH_EVENT) { 1.2476 + if (aEvent->message == NS_MOUSE_BUTTON_DOWN || aEvent->message == NS_TOUCH_START) { 1.2477 + HandlePress(aPresContext, aEvent, aEventStatus); 1.2478 + } else if (aEvent->message == NS_MOUSE_BUTTON_UP || aEvent->message == NS_TOUCH_END) { 1.2479 + HandleRelease(aPresContext, aEvent, aEventStatus); 1.2480 + } 1.2481 + } 1.2482 + return NS_OK; 1.2483 +} 1.2484 + 1.2485 +NS_IMETHODIMP 1.2486 +nsFrame::GetDataForTableSelection(const nsFrameSelection* aFrameSelection, 1.2487 + nsIPresShell* aPresShell, 1.2488 + WidgetMouseEvent* aMouseEvent, 1.2489 + nsIContent** aParentContent, 1.2490 + int32_t* aContentOffset, 1.2491 + int32_t* aTarget) 1.2492 +{ 1.2493 + if (!aFrameSelection || !aPresShell || !aMouseEvent || !aParentContent || !aContentOffset || !aTarget) 1.2494 + return NS_ERROR_NULL_POINTER; 1.2495 + 1.2496 + *aParentContent = nullptr; 1.2497 + *aContentOffset = 0; 1.2498 + *aTarget = 0; 1.2499 + 1.2500 + int16_t displaySelection = aPresShell->GetSelectionFlags(); 1.2501 + 1.2502 + bool selectingTableCells = aFrameSelection->GetTableCellSelection(); 1.2503 + 1.2504 + // DISPLAY_ALL means we're in an editor. 1.2505 + // If already in cell selection mode, 1.2506 + // continue selecting with mouse drag or end on mouse up, 1.2507 + // or when using shift key to extend block of cells 1.2508 + // (Mouse down does normal selection unless Ctrl/Cmd is pressed) 1.2509 + bool doTableSelection = 1.2510 + displaySelection == nsISelectionDisplay::DISPLAY_ALL && selectingTableCells && 1.2511 + (aMouseEvent->message == NS_MOUSE_MOVE || 1.2512 + (aMouseEvent->message == NS_MOUSE_BUTTON_UP && 1.2513 + aMouseEvent->button == WidgetMouseEvent::eLeftButton) || 1.2514 + aMouseEvent->IsShift()); 1.2515 + 1.2516 + if (!doTableSelection) 1.2517 + { 1.2518 + // In Browser, special 'table selection' key must be pressed for table selection 1.2519 + // or when just Shift is pressed and we're already in table/cell selection mode 1.2520 +#ifdef XP_MACOSX 1.2521 + doTableSelection = aMouseEvent->IsMeta() || (aMouseEvent->IsShift() && selectingTableCells); 1.2522 +#else 1.2523 + doTableSelection = aMouseEvent->IsControl() || (aMouseEvent->IsShift() && selectingTableCells); 1.2524 +#endif 1.2525 + } 1.2526 + if (!doTableSelection) 1.2527 + return NS_OK; 1.2528 + 1.2529 + // Get the cell frame or table frame (or parent) of the current content node 1.2530 + nsIFrame *frame = this; 1.2531 + bool foundCell = false; 1.2532 + bool foundTable = false; 1.2533 + 1.2534 + // Get the limiting node to stop parent frame search 1.2535 + nsIContent* limiter = aFrameSelection->GetLimiter(); 1.2536 + 1.2537 + // If our content node is an ancestor of the limiting node, 1.2538 + // we should stop the search right now. 1.2539 + if (limiter && nsContentUtils::ContentIsDescendantOf(limiter, GetContent())) 1.2540 + return NS_OK; 1.2541 + 1.2542 + //We don't initiate row/col selection from here now, 1.2543 + // but we may in future 1.2544 + //bool selectColumn = false; 1.2545 + //bool selectRow = false; 1.2546 + 1.2547 + while (frame) 1.2548 + { 1.2549 + // Check for a table cell by querying to a known CellFrame interface 1.2550 + nsITableCellLayout *cellElement = do_QueryFrame(frame); 1.2551 + if (cellElement) 1.2552 + { 1.2553 + foundCell = true; 1.2554 + //TODO: If we want to use proximity to top or left border 1.2555 + // for row and column selection, this is the place to do it 1.2556 + break; 1.2557 + } 1.2558 + else 1.2559 + { 1.2560 + // If not a cell, check for table 1.2561 + // This will happen when starting frame is the table or child of a table, 1.2562 + // such as a row (we were inbetween cells or in table border) 1.2563 + nsTableOuterFrame *tableFrame = do_QueryFrame(frame); 1.2564 + if (tableFrame) 1.2565 + { 1.2566 + foundTable = true; 1.2567 + //TODO: How can we select row when along left table edge 1.2568 + // or select column when along top edge? 1.2569 + break; 1.2570 + } else { 1.2571 + frame = frame->GetParent(); 1.2572 + // Stop if we have hit the selection's limiting content node 1.2573 + if (frame && frame->GetContent() == limiter) 1.2574 + break; 1.2575 + } 1.2576 + } 1.2577 + } 1.2578 + // We aren't in a cell or table 1.2579 + if (!foundCell && !foundTable) return NS_OK; 1.2580 + 1.2581 + nsIContent* tableOrCellContent = frame->GetContent(); 1.2582 + if (!tableOrCellContent) return NS_ERROR_FAILURE; 1.2583 + 1.2584 + nsCOMPtr<nsIContent> parentContent = tableOrCellContent->GetParent(); 1.2585 + if (!parentContent) return NS_ERROR_FAILURE; 1.2586 + 1.2587 + int32_t offset = parentContent->IndexOf(tableOrCellContent); 1.2588 + // Not likely? 1.2589 + if (offset < 0) return NS_ERROR_FAILURE; 1.2590 + 1.2591 + // Everything is OK -- set the return values 1.2592 + *aParentContent = parentContent; 1.2593 + NS_ADDREF(*aParentContent); 1.2594 + 1.2595 + *aContentOffset = offset; 1.2596 + 1.2597 +#if 0 1.2598 + if (selectRow) 1.2599 + *aTarget = nsISelectionPrivate::TABLESELECTION_ROW; 1.2600 + else if (selectColumn) 1.2601 + *aTarget = nsISelectionPrivate::TABLESELECTION_COLUMN; 1.2602 + else 1.2603 +#endif 1.2604 + if (foundCell) 1.2605 + *aTarget = nsISelectionPrivate::TABLESELECTION_CELL; 1.2606 + else if (foundTable) 1.2607 + *aTarget = nsISelectionPrivate::TABLESELECTION_TABLE; 1.2608 + 1.2609 + return NS_OK; 1.2610 +} 1.2611 + 1.2612 +nsresult 1.2613 +nsFrame::IsSelectable(bool* aSelectable, uint8_t* aSelectStyle) const 1.2614 +{ 1.2615 + if (!aSelectable) //it's ok if aSelectStyle is null 1.2616 + return NS_ERROR_NULL_POINTER; 1.2617 + 1.2618 + // Like 'visibility', we must check all the parents: if a parent 1.2619 + // is not selectable, none of its children is selectable. 1.2620 + // 1.2621 + // The -moz-all value acts similarly: if a frame has 'user-select:-moz-all', 1.2622 + // all its children are selectable, even those with 'user-select:none'. 1.2623 + // 1.2624 + // As a result, if 'none' and '-moz-all' are not present in the frame hierarchy, 1.2625 + // aSelectStyle returns the first style that is not AUTO. If these values 1.2626 + // are present in the frame hierarchy, aSelectStyle returns the style of the 1.2627 + // topmost parent that has either 'none' or '-moz-all'. 1.2628 + // 1.2629 + // For instance, if the frame hierarchy is: 1.2630 + // AUTO -> _MOZ_ALL -> NONE -> TEXT, the returned value is _MOZ_ALL 1.2631 + // TEXT -> NONE -> AUTO -> _MOZ_ALL, the returned value is TEXT 1.2632 + // _MOZ_ALL -> TEXT -> AUTO -> AUTO, the returned value is _MOZ_ALL 1.2633 + // AUTO -> CELL -> TEXT -> AUTO, the returned value is TEXT 1.2634 + // 1.2635 + uint8_t selectStyle = NS_STYLE_USER_SELECT_AUTO; 1.2636 + nsIFrame* frame = const_cast<nsFrame*>(this); 1.2637 + 1.2638 + while (frame) { 1.2639 + const nsStyleUIReset* userinterface = frame->StyleUIReset(); 1.2640 + switch (userinterface->mUserSelect) { 1.2641 + case NS_STYLE_USER_SELECT_ALL: 1.2642 + case NS_STYLE_USER_SELECT_MOZ_ALL: 1.2643 + // override the previous values 1.2644 + selectStyle = userinterface->mUserSelect; 1.2645 + break; 1.2646 + default: 1.2647 + // otherwise return the first value which is not 'auto' 1.2648 + if (selectStyle == NS_STYLE_USER_SELECT_AUTO) { 1.2649 + selectStyle = userinterface->mUserSelect; 1.2650 + } 1.2651 + break; 1.2652 + } 1.2653 + frame = frame->GetParent(); 1.2654 + } 1.2655 + 1.2656 + // convert internal values to standard values 1.2657 + if (selectStyle == NS_STYLE_USER_SELECT_AUTO) 1.2658 + selectStyle = NS_STYLE_USER_SELECT_TEXT; 1.2659 + else 1.2660 + if (selectStyle == NS_STYLE_USER_SELECT_MOZ_ALL) 1.2661 + selectStyle = NS_STYLE_USER_SELECT_ALL; 1.2662 + 1.2663 + // return stuff 1.2664 + if (aSelectStyle) 1.2665 + *aSelectStyle = selectStyle; 1.2666 + if (mState & NS_FRAME_GENERATED_CONTENT) 1.2667 + *aSelectable = false; 1.2668 + else 1.2669 + *aSelectable = (selectStyle != NS_STYLE_USER_SELECT_NONE); 1.2670 + return NS_OK; 1.2671 +} 1.2672 + 1.2673 +/** 1.2674 + * Handles the Mouse Press Event for the frame 1.2675 + */ 1.2676 +NS_IMETHODIMP 1.2677 +nsFrame::HandlePress(nsPresContext* aPresContext, 1.2678 + WidgetGUIEvent* aEvent, 1.2679 + nsEventStatus* aEventStatus) 1.2680 +{ 1.2681 + NS_ENSURE_ARG_POINTER(aEventStatus); 1.2682 + if (nsEventStatus_eConsumeNoDefault == *aEventStatus) { 1.2683 + return NS_OK; 1.2684 + } 1.2685 + 1.2686 + NS_ENSURE_ARG_POINTER(aEvent); 1.2687 + if (aEvent->eventStructType == NS_TOUCH_EVENT) { 1.2688 + return NS_OK; 1.2689 + } 1.2690 + 1.2691 + //We often get out of sync state issues with mousedown events that 1.2692 + //get interrupted by alerts/dialogs. 1.2693 + //Check with the ESM to see if we should process this one 1.2694 + if (!aPresContext->EventStateManager()->EventStatusOK(aEvent)) 1.2695 + return NS_OK; 1.2696 + 1.2697 + nsresult rv; 1.2698 + nsIPresShell *shell = aPresContext->GetPresShell(); 1.2699 + if (!shell) 1.2700 + return NS_ERROR_FAILURE; 1.2701 + 1.2702 + // if we are in Navigator and the click is in a draggable node, we don't want 1.2703 + // to start selection because we don't want to interfere with a potential 1.2704 + // drag of said node and steal all its glory. 1.2705 + int16_t isEditor = shell->GetSelectionFlags(); 1.2706 + //weaaak. only the editor can display frame selection not just text and images 1.2707 + isEditor = isEditor == nsISelectionDisplay::DISPLAY_ALL; 1.2708 + 1.2709 + WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent(); 1.2710 + 1.2711 + if (!mouseEvent->IsAlt()) { 1.2712 + for (nsIContent* content = mContent; content; 1.2713 + content = content->GetParent()) { 1.2714 + if (nsContentUtils::ContentIsDraggable(content) && 1.2715 + !content->IsEditable()) { 1.2716 + // coordinate stuff is the fix for bug #55921 1.2717 + if ((mRect - GetPosition()).Contains( 1.2718 + nsLayoutUtils::GetEventCoordinatesRelativeTo(mouseEvent, this))) { 1.2719 + return NS_OK; 1.2720 + } 1.2721 + } 1.2722 + } 1.2723 + } 1.2724 + 1.2725 + // check whether style allows selection 1.2726 + // if not, don't tell selection the mouse event even occurred. 1.2727 + bool selectable; 1.2728 + uint8_t selectStyle; 1.2729 + rv = IsSelectable(&selectable, &selectStyle); 1.2730 + if (NS_FAILED(rv)) return rv; 1.2731 + 1.2732 + // check for select: none 1.2733 + if (!selectable) 1.2734 + return NS_OK; 1.2735 + 1.2736 + // When implementing NS_STYLE_USER_SELECT_ELEMENT, NS_STYLE_USER_SELECT_ELEMENTS and 1.2737 + // NS_STYLE_USER_SELECT_TOGGLE, need to change this logic 1.2738 + bool useFrameSelection = (selectStyle == NS_STYLE_USER_SELECT_TEXT); 1.2739 + 1.2740 + // If the mouse is dragged outside the nearest enclosing scrollable area 1.2741 + // while making a selection, the area will be scrolled. To do this, capture 1.2742 + // the mouse on the nearest scrollable frame. If there isn't a scrollable 1.2743 + // frame, or something else is already capturing the mouse, there's no 1.2744 + // reason to capture. 1.2745 + bool hasCapturedContent = false; 1.2746 + if (!nsIPresShell::GetCapturingContent()) { 1.2747 + nsIScrollableFrame* scrollFrame = 1.2748 + nsLayoutUtils::GetNearestScrollableFrame(this, 1.2749 + nsLayoutUtils::SCROLLABLE_SAME_DOC | 1.2750 + nsLayoutUtils::SCROLLABLE_INCLUDE_HIDDEN); 1.2751 + if (scrollFrame) { 1.2752 + nsIFrame* capturingFrame = do_QueryFrame(scrollFrame); 1.2753 + nsIPresShell::SetCapturingContent(capturingFrame->GetContent(), 1.2754 + CAPTURE_IGNOREALLOWED); 1.2755 + hasCapturedContent = true; 1.2756 + } 1.2757 + } 1.2758 + 1.2759 + // XXX This is screwy; it really should use the selection frame, not the 1.2760 + // event frame 1.2761 + const nsFrameSelection* frameselection = nullptr; 1.2762 + if (useFrameSelection) 1.2763 + frameselection = GetConstFrameSelection(); 1.2764 + else 1.2765 + frameselection = shell->ConstFrameSelection(); 1.2766 + 1.2767 + if (!frameselection || frameselection->GetDisplaySelection() == nsISelectionController::SELECTION_OFF) 1.2768 + return NS_OK;//nothing to do we cannot affect selection from here 1.2769 + 1.2770 +#ifdef XP_MACOSX 1.2771 + if (mouseEvent->IsControl()) 1.2772 + return NS_OK;//short circuit. hard coded for mac due to time restraints. 1.2773 + bool control = mouseEvent->IsMeta(); 1.2774 +#else 1.2775 + bool control = mouseEvent->IsControl(); 1.2776 +#endif 1.2777 + 1.2778 + nsRefPtr<nsFrameSelection> fc = const_cast<nsFrameSelection*>(frameselection); 1.2779 + if (mouseEvent->clickCount > 1) { 1.2780 + // These methods aren't const but can't actually delete anything, 1.2781 + // so no need for nsWeakFrame. 1.2782 + fc->SetMouseDownState(true); 1.2783 + fc->SetMouseDoubleDown(true); 1.2784 + return HandleMultiplePress(aPresContext, mouseEvent, aEventStatus, control); 1.2785 + } 1.2786 + 1.2787 + nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(mouseEvent, this); 1.2788 + ContentOffsets offsets = GetContentOffsetsFromPoint(pt, SKIP_HIDDEN); 1.2789 + 1.2790 + if (!offsets.content) 1.2791 + return NS_ERROR_FAILURE; 1.2792 + 1.2793 + // On touchables devices, touch the screen is usually a pan action, 1.2794 + // so let's reposition the caret if needed but do not select text 1.2795 + // if the touch did not happen over an editable element. Otherwise, 1.2796 + // let the user move the caret by tapping and dragging. 1.2797 + if (!offsets.content->IsEditable() && 1.2798 + Preferences::GetBool("browser.ignoreNativeFrameTextSelection", false)) { 1.2799 + // On touchables devices, mouse events are generated if the gesture is a tap. 1.2800 + // Such events are never going to generate a drag action, so let's release 1.2801 + // captured content if any. 1.2802 + if (hasCapturedContent) { 1.2803 + nsIPresShell::SetCapturingContent(nullptr, 0); 1.2804 + } 1.2805 + 1.2806 + return fc->HandleClick(offsets.content, offsets.StartOffset(), 1.2807 + offsets.EndOffset(), false, false, 1.2808 + offsets.associateWithNext); 1.2809 + } 1.2810 + 1.2811 + // Let Ctrl/Cmd+mouse down do table selection instead of drag initiation 1.2812 + nsCOMPtr<nsIContent>parentContent; 1.2813 + int32_t contentOffset; 1.2814 + int32_t target; 1.2815 + rv = GetDataForTableSelection(frameselection, shell, mouseEvent, 1.2816 + getter_AddRefs(parentContent), &contentOffset, 1.2817 + &target); 1.2818 + if (NS_SUCCEEDED(rv) && parentContent) 1.2819 + { 1.2820 + fc->SetMouseDownState(true); 1.2821 + return fc->HandleTableSelection(parentContent, contentOffset, target, 1.2822 + mouseEvent); 1.2823 + } 1.2824 + 1.2825 + fc->SetDelayedCaretData(0); 1.2826 + 1.2827 + // Check if any part of this frame is selected, and if the 1.2828 + // user clicked inside the selected region. If so, we delay 1.2829 + // starting a new selection since the user may be trying to 1.2830 + // drag the selected region to some other app. 1.2831 + 1.2832 + SelectionDetails *details = 0; 1.2833 + if (GetContent()->IsSelectionDescendant()) 1.2834 + { 1.2835 + bool inSelection = false; 1.2836 + details = frameselection->LookUpSelection(offsets.content, 0, 1.2837 + offsets.EndOffset(), false); 1.2838 + 1.2839 + // 1.2840 + // If there are any details, check to see if the user clicked 1.2841 + // within any selected region of the frame. 1.2842 + // 1.2843 + 1.2844 + SelectionDetails *curDetail = details; 1.2845 + 1.2846 + while (curDetail) 1.2847 + { 1.2848 + // 1.2849 + // If the user clicked inside a selection, then just 1.2850 + // return without doing anything. We will handle placing 1.2851 + // the caret later on when the mouse is released. We ignore 1.2852 + // the spellcheck, find and url formatting selections. 1.2853 + // 1.2854 + if (curDetail->mType != nsISelectionController::SELECTION_SPELLCHECK && 1.2855 + curDetail->mType != nsISelectionController::SELECTION_FIND && 1.2856 + curDetail->mType != nsISelectionController::SELECTION_URLSECONDARY && 1.2857 + curDetail->mStart <= offsets.StartOffset() && 1.2858 + offsets.EndOffset() <= curDetail->mEnd) 1.2859 + { 1.2860 + inSelection = true; 1.2861 + } 1.2862 + 1.2863 + SelectionDetails *nextDetail = curDetail->mNext; 1.2864 + delete curDetail; 1.2865 + curDetail = nextDetail; 1.2866 + } 1.2867 + 1.2868 + if (inSelection) { 1.2869 + fc->SetMouseDownState(false); 1.2870 + fc->SetDelayedCaretData(mouseEvent); 1.2871 + return NS_OK; 1.2872 + } 1.2873 + } 1.2874 + 1.2875 + fc->SetMouseDownState(true); 1.2876 + 1.2877 + // Do not touch any nsFrame members after this point without adding 1.2878 + // weakFrame checks. 1.2879 + rv = fc->HandleClick(offsets.content, offsets.StartOffset(), 1.2880 + offsets.EndOffset(), mouseEvent->IsShift(), control, 1.2881 + offsets.associateWithNext); 1.2882 + 1.2883 + if (NS_FAILED(rv)) 1.2884 + return rv; 1.2885 + 1.2886 + if (offsets.offset != offsets.secondaryOffset) 1.2887 + fc->MaintainSelection(); 1.2888 + 1.2889 + if (isEditor && !mouseEvent->IsShift() && 1.2890 + (offsets.EndOffset() - offsets.StartOffset()) == 1) 1.2891 + { 1.2892 + // A single node is selected and we aren't extending an existing 1.2893 + // selection, which means the user clicked directly on an object (either 1.2894 + // -moz-user-select: all or a non-text node without children). 1.2895 + // Therefore, disable selection extension during mouse moves. 1.2896 + // XXX This is a bit hacky; shouldn't editor be able to deal with this? 1.2897 + fc->SetMouseDownState(false); 1.2898 + } 1.2899 + 1.2900 + return rv; 1.2901 +} 1.2902 + 1.2903 +/* 1.2904 + * SelectByTypeAtPoint 1.2905 + * 1.2906 + * Search for selectable content at point and attempt to select 1.2907 + * based on the start and end selection behaviours. 1.2908 + * 1.2909 + * @param aPresContext Presentation context 1.2910 + * @param aPoint Point at which selection will occur. Coordinates 1.2911 + * should be relaitve to this frame. 1.2912 + * @param aBeginAmountType, aEndAmountType Selection behavior, see 1.2913 + * nsIFrame for definitions. 1.2914 + * @param aSelectFlags Selection flags defined in nsFame.h. 1.2915 + * @return success or failure at finding suitable content to select. 1.2916 + */ 1.2917 +nsresult 1.2918 +nsFrame::SelectByTypeAtPoint(nsPresContext* aPresContext, 1.2919 + const nsPoint& aPoint, 1.2920 + nsSelectionAmount aBeginAmountType, 1.2921 + nsSelectionAmount aEndAmountType, 1.2922 + uint32_t aSelectFlags) 1.2923 +{ 1.2924 + NS_ENSURE_ARG_POINTER(aPresContext); 1.2925 + 1.2926 + // No point in selecting if selection is turned off 1.2927 + if (DisplaySelection(aPresContext) == nsISelectionController::SELECTION_OFF) 1.2928 + return NS_OK; 1.2929 + 1.2930 + ContentOffsets offsets = GetContentOffsetsFromPoint(aPoint, SKIP_HIDDEN); 1.2931 + if (!offsets.content) 1.2932 + return NS_ERROR_FAILURE; 1.2933 + 1.2934 + int32_t offset; 1.2935 + const nsFrameSelection* frameSelection = 1.2936 + PresContext()->GetPresShell()->ConstFrameSelection(); 1.2937 + nsIFrame* theFrame = frameSelection-> 1.2938 + GetFrameForNodeOffset(offsets.content, offsets.offset, 1.2939 + nsFrameSelection::HINT(offsets.associateWithNext), 1.2940 + &offset); 1.2941 + if (!theFrame) 1.2942 + return NS_ERROR_FAILURE; 1.2943 + 1.2944 + nsFrame* frame = static_cast<nsFrame*>(theFrame); 1.2945 + return frame->PeekBackwardAndForward(aBeginAmountType, aEndAmountType, 1.2946 + offset, aPresContext, 1.2947 + aBeginAmountType != eSelectWord, 1.2948 + aSelectFlags); 1.2949 +} 1.2950 + 1.2951 +/** 1.2952 + * Multiple Mouse Press -- line or paragraph selection -- for the frame. 1.2953 + * Wouldn't it be nice if this didn't have to be hardwired into Frame code? 1.2954 + */ 1.2955 +NS_IMETHODIMP 1.2956 +nsFrame::HandleMultiplePress(nsPresContext* aPresContext, 1.2957 + WidgetGUIEvent* aEvent, 1.2958 + nsEventStatus* aEventStatus, 1.2959 + bool aControlHeld) 1.2960 +{ 1.2961 + NS_ENSURE_ARG_POINTER(aEvent); 1.2962 + NS_ENSURE_ARG_POINTER(aEventStatus); 1.2963 + 1.2964 + if (nsEventStatus_eConsumeNoDefault == *aEventStatus || 1.2965 + DisplaySelection(aPresContext) == nsISelectionController::SELECTION_OFF) { 1.2966 + return NS_OK; 1.2967 + } 1.2968 + 1.2969 + // Find out whether we're doing line or paragraph selection. 1.2970 + // If browser.triple_click_selects_paragraph is true, triple-click selects paragraph. 1.2971 + // Otherwise, triple-click selects line, and quadruple-click selects paragraph 1.2972 + // (on platforms that support quadruple-click). 1.2973 + nsSelectionAmount beginAmount, endAmount; 1.2974 + WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent(); 1.2975 + if (!mouseEvent) { 1.2976 + return NS_OK; 1.2977 + } 1.2978 + 1.2979 + if (mouseEvent->clickCount == 4) { 1.2980 + beginAmount = endAmount = eSelectParagraph; 1.2981 + } else if (mouseEvent->clickCount == 3) { 1.2982 + if (Preferences::GetBool("browser.triple_click_selects_paragraph")) { 1.2983 + beginAmount = endAmount = eSelectParagraph; 1.2984 + } else { 1.2985 + beginAmount = eSelectBeginLine; 1.2986 + endAmount = eSelectEndLine; 1.2987 + } 1.2988 + } else if (mouseEvent->clickCount == 2) { 1.2989 + // We only want inline frames; PeekBackwardAndForward dislikes blocks 1.2990 + beginAmount = endAmount = eSelectWord; 1.2991 + } else { 1.2992 + return NS_OK; 1.2993 + } 1.2994 + 1.2995 + nsPoint relPoint = 1.2996 + nsLayoutUtils::GetEventCoordinatesRelativeTo(mouseEvent, this); 1.2997 + return SelectByTypeAtPoint(aPresContext, relPoint, beginAmount, endAmount, 1.2998 + (aControlHeld ? SELECT_ACCUMULATE : 0)); 1.2999 +} 1.3000 + 1.3001 +nsresult 1.3002 +nsFrame::PeekBackwardAndForward(nsSelectionAmount aAmountBack, 1.3003 + nsSelectionAmount aAmountForward, 1.3004 + int32_t aStartPos, 1.3005 + nsPresContext* aPresContext, 1.3006 + bool aJumpLines, 1.3007 + uint32_t aSelectFlags) 1.3008 +{ 1.3009 + nsIFrame* baseFrame = this; 1.3010 + int32_t baseOffset = aStartPos; 1.3011 + nsresult rv; 1.3012 + 1.3013 + if (aAmountBack == eSelectWord) { 1.3014 + // To avoid selecting the previous word when at start of word, 1.3015 + // first move one character forward. 1.3016 + nsPeekOffsetStruct pos(eSelectCharacter, 1.3017 + eDirNext, 1.3018 + aStartPos, 1.3019 + 0, 1.3020 + aJumpLines, 1.3021 + true, //limit on scrolled views 1.3022 + false, 1.3023 + false); 1.3024 + rv = PeekOffset(&pos); 1.3025 + if (NS_SUCCEEDED(rv)) { 1.3026 + baseFrame = pos.mResultFrame; 1.3027 + baseOffset = pos.mContentOffset; 1.3028 + } 1.3029 + } 1.3030 + 1.3031 + // Use peek offset one way then the other: 1.3032 + nsPeekOffsetStruct startpos(aAmountBack, 1.3033 + eDirPrevious, 1.3034 + baseOffset, 1.3035 + 0, 1.3036 + aJumpLines, 1.3037 + true, //limit on scrolled views 1.3038 + false, 1.3039 + false); 1.3040 + rv = baseFrame->PeekOffset(&startpos); 1.3041 + if (NS_FAILED(rv)) 1.3042 + return rv; 1.3043 + 1.3044 + nsPeekOffsetStruct endpos(aAmountForward, 1.3045 + eDirNext, 1.3046 + aStartPos, 1.3047 + 0, 1.3048 + aJumpLines, 1.3049 + true, //limit on scrolled views 1.3050 + false, 1.3051 + false); 1.3052 + rv = PeekOffset(&endpos); 1.3053 + if (NS_FAILED(rv)) 1.3054 + return rv; 1.3055 + 1.3056 + // Keep frameSelection alive. 1.3057 + nsRefPtr<nsFrameSelection> frameSelection = GetFrameSelection(); 1.3058 + 1.3059 + rv = frameSelection->HandleClick(startpos.mResultContent, 1.3060 + startpos.mContentOffset, startpos.mContentOffset, 1.3061 + false, (aSelectFlags & SELECT_ACCUMULATE), 1.3062 + nsFrameSelection::HINTRIGHT); 1.3063 + if (NS_FAILED(rv)) 1.3064 + return rv; 1.3065 + 1.3066 + rv = frameSelection->HandleClick(endpos.mResultContent, 1.3067 + endpos.mContentOffset, endpos.mContentOffset, 1.3068 + true, false, 1.3069 + nsFrameSelection::HINTLEFT); 1.3070 + if (NS_FAILED(rv)) 1.3071 + return rv; 1.3072 + 1.3073 + // maintain selection 1.3074 + return frameSelection->MaintainSelection(aAmountBack); 1.3075 +} 1.3076 + 1.3077 +NS_IMETHODIMP nsFrame::HandleDrag(nsPresContext* aPresContext, 1.3078 + WidgetGUIEvent* aEvent, 1.3079 + nsEventStatus* aEventStatus) 1.3080 +{ 1.3081 + MOZ_ASSERT(aEvent->eventStructType == NS_MOUSE_EVENT, "HandleDrag can only handle mouse event"); 1.3082 + 1.3083 + bool selectable; 1.3084 + IsSelectable(&selectable, nullptr); 1.3085 + 1.3086 + // XXX Do we really need to exclude non-selectable content here? 1.3087 + // GetContentOffsetsFromPoint can handle it just fine, although some 1.3088 + // other stuff might not like it. 1.3089 + if (!selectable) 1.3090 + return NS_OK; 1.3091 + if (DisplaySelection(aPresContext) == nsISelectionController::SELECTION_OFF) { 1.3092 + return NS_OK; 1.3093 + } 1.3094 + nsIPresShell *presShell = aPresContext->PresShell(); 1.3095 + 1.3096 + nsRefPtr<nsFrameSelection> frameselection = GetFrameSelection(); 1.3097 + bool mouseDown = frameselection->GetMouseDownState(); 1.3098 + if (!mouseDown) 1.3099 + return NS_OK; 1.3100 + 1.3101 + frameselection->StopAutoScrollTimer(); 1.3102 + 1.3103 + // Check if we are dragging in a table cell 1.3104 + nsCOMPtr<nsIContent> parentContent; 1.3105 + int32_t contentOffset; 1.3106 + int32_t target; 1.3107 + WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent(); 1.3108 + nsresult result; 1.3109 + result = GetDataForTableSelection(frameselection, presShell, mouseEvent, 1.3110 + getter_AddRefs(parentContent), 1.3111 + &contentOffset, &target); 1.3112 + 1.3113 + nsWeakFrame weakThis = this; 1.3114 + if (NS_SUCCEEDED(result) && parentContent) { 1.3115 + frameselection->HandleTableSelection(parentContent, contentOffset, target, 1.3116 + mouseEvent); 1.3117 + } else { 1.3118 + nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(mouseEvent, this); 1.3119 + frameselection->HandleDrag(this, pt); 1.3120 + } 1.3121 + 1.3122 + // The frameselection object notifies selection listeners synchronously above 1.3123 + // which might have killed us. 1.3124 + if (!weakThis.IsAlive()) { 1.3125 + return NS_OK; 1.3126 + } 1.3127 + 1.3128 + // get the nearest scrollframe 1.3129 + nsIScrollableFrame* scrollFrame = 1.3130 + nsLayoutUtils::GetNearestScrollableFrame(this, 1.3131 + nsLayoutUtils::SCROLLABLE_SAME_DOC | 1.3132 + nsLayoutUtils::SCROLLABLE_INCLUDE_HIDDEN); 1.3133 + 1.3134 + if (scrollFrame) { 1.3135 + nsIFrame* capturingFrame = scrollFrame->GetScrolledFrame(); 1.3136 + if (capturingFrame) { 1.3137 + nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(mouseEvent, 1.3138 + capturingFrame); 1.3139 + frameselection->StartAutoScrollTimer(capturingFrame, pt, 30); 1.3140 + } 1.3141 + } 1.3142 + 1.3143 + return NS_OK; 1.3144 +} 1.3145 + 1.3146 +/** 1.3147 + * This static method handles part of the nsFrame::HandleRelease in a way 1.3148 + * which doesn't rely on the nsFrame object to stay alive. 1.3149 + */ 1.3150 +static nsresult 1.3151 +HandleFrameSelection(nsFrameSelection* aFrameSelection, 1.3152 + nsIFrame::ContentOffsets& aOffsets, 1.3153 + bool aHandleTableSel, 1.3154 + int32_t aContentOffsetForTableSel, 1.3155 + int32_t aTargetForTableSel, 1.3156 + nsIContent* aParentContentForTableSel, 1.3157 + WidgetGUIEvent* aEvent, 1.3158 + nsEventStatus* aEventStatus) 1.3159 +{ 1.3160 + if (!aFrameSelection) { 1.3161 + return NS_OK; 1.3162 + } 1.3163 + 1.3164 + nsresult rv = NS_OK; 1.3165 + 1.3166 + if (nsEventStatus_eConsumeNoDefault != *aEventStatus) { 1.3167 + if (!aHandleTableSel) { 1.3168 + if (!aOffsets.content || !aFrameSelection->HasDelayedCaretData()) { 1.3169 + return NS_ERROR_FAILURE; 1.3170 + } 1.3171 + 1.3172 + // We are doing this to simulate what we would have done on HandlePress. 1.3173 + // We didn't do it there to give the user an opportunity to drag 1.3174 + // the text, but since they didn't drag, we want to place the 1.3175 + // caret. 1.3176 + // However, we'll use the mouse position from the release, since: 1.3177 + // * it's easier 1.3178 + // * that's the normal click position to use (although really, in 1.3179 + // the normal case, small movements that don't count as a drag 1.3180 + // can do selection) 1.3181 + aFrameSelection->SetMouseDownState(true); 1.3182 + 1.3183 + rv = aFrameSelection->HandleClick(aOffsets.content, 1.3184 + aOffsets.StartOffset(), 1.3185 + aOffsets.EndOffset(), 1.3186 + aFrameSelection->IsShiftDownInDelayedCaretData(), 1.3187 + false, 1.3188 + aOffsets.associateWithNext); 1.3189 + if (NS_FAILED(rv)) { 1.3190 + return rv; 1.3191 + } 1.3192 + } else if (aParentContentForTableSel) { 1.3193 + aFrameSelection->SetMouseDownState(false); 1.3194 + rv = aFrameSelection->HandleTableSelection( 1.3195 + aParentContentForTableSel, 1.3196 + aContentOffsetForTableSel, 1.3197 + aTargetForTableSel, 1.3198 + aEvent->AsMouseEvent()); 1.3199 + if (NS_FAILED(rv)) { 1.3200 + return rv; 1.3201 + } 1.3202 + } 1.3203 + aFrameSelection->SetDelayedCaretData(0); 1.3204 + } 1.3205 + 1.3206 + aFrameSelection->SetMouseDownState(false); 1.3207 + aFrameSelection->StopAutoScrollTimer(); 1.3208 + 1.3209 + return NS_OK; 1.3210 +} 1.3211 + 1.3212 +NS_IMETHODIMP nsFrame::HandleRelease(nsPresContext* aPresContext, 1.3213 + WidgetGUIEvent* aEvent, 1.3214 + nsEventStatus* aEventStatus) 1.3215 +{ 1.3216 + if (aEvent->eventStructType != NS_MOUSE_EVENT) { 1.3217 + return NS_OK; 1.3218 + } 1.3219 + 1.3220 + nsIFrame* activeFrame = GetActiveSelectionFrame(aPresContext, this); 1.3221 + 1.3222 + nsCOMPtr<nsIContent> captureContent = nsIPresShell::GetCapturingContent(); 1.3223 + 1.3224 + // We can unconditionally stop capturing because 1.3225 + // we should never be capturing when the mouse button is up 1.3226 + nsIPresShell::SetCapturingContent(nullptr, 0); 1.3227 + 1.3228 + bool selectionOff = 1.3229 + (DisplaySelection(aPresContext) == nsISelectionController::SELECTION_OFF); 1.3230 + 1.3231 + nsRefPtr<nsFrameSelection> frameselection; 1.3232 + ContentOffsets offsets; 1.3233 + nsCOMPtr<nsIContent> parentContent; 1.3234 + int32_t contentOffsetForTableSel = 0; 1.3235 + int32_t targetForTableSel = 0; 1.3236 + bool handleTableSelection = true; 1.3237 + 1.3238 + if (!selectionOff) { 1.3239 + frameselection = GetFrameSelection(); 1.3240 + if (nsEventStatus_eConsumeNoDefault != *aEventStatus && frameselection) { 1.3241 + // Check if the frameselection recorded the mouse going down. 1.3242 + // If not, the user must have clicked in a part of the selection. 1.3243 + // Place the caret before continuing! 1.3244 + 1.3245 + bool mouseDown = frameselection->GetMouseDownState(); 1.3246 + 1.3247 + if (!mouseDown && frameselection->HasDelayedCaretData() && 1.3248 + frameselection->GetClickCountInDelayedCaretData() < 2) { 1.3249 + nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, this); 1.3250 + offsets = GetContentOffsetsFromPoint(pt, SKIP_HIDDEN); 1.3251 + handleTableSelection = false; 1.3252 + } else { 1.3253 + GetDataForTableSelection(frameselection, PresContext()->PresShell(), 1.3254 + aEvent->AsMouseEvent(), 1.3255 + getter_AddRefs(parentContent), 1.3256 + &contentOffsetForTableSel, 1.3257 + &targetForTableSel); 1.3258 + } 1.3259 + } 1.3260 + } 1.3261 + 1.3262 + // We might be capturing in some other document and the event just happened to 1.3263 + // trickle down here. Make sure that document's frame selection is notified. 1.3264 + // Note, this may cause the current nsFrame object to be deleted, bug 336592. 1.3265 + nsRefPtr<nsFrameSelection> frameSelection; 1.3266 + if (activeFrame != this && 1.3267 + static_cast<nsFrame*>(activeFrame)->DisplaySelection(activeFrame->PresContext()) 1.3268 + != nsISelectionController::SELECTION_OFF) { 1.3269 + frameSelection = activeFrame->GetFrameSelection(); 1.3270 + } 1.3271 + 1.3272 + // Also check the selection of the capturing content which might be in a 1.3273 + // different document. 1.3274 + if (!frameSelection && captureContent) { 1.3275 + nsIDocument* doc = captureContent->GetCurrentDoc(); 1.3276 + if (doc) { 1.3277 + nsIPresShell* capturingShell = doc->GetShell(); 1.3278 + if (capturingShell && capturingShell != PresContext()->GetPresShell()) { 1.3279 + frameSelection = capturingShell->FrameSelection(); 1.3280 + } 1.3281 + } 1.3282 + } 1.3283 + 1.3284 + if (frameSelection) { 1.3285 + frameSelection->SetMouseDownState(false); 1.3286 + frameSelection->StopAutoScrollTimer(); 1.3287 + } 1.3288 + 1.3289 + // Do not call any methods of the current object after this point!!! 1.3290 + // The object is perhaps dead! 1.3291 + 1.3292 + return selectionOff 1.3293 + ? NS_OK 1.3294 + : HandleFrameSelection(frameselection, offsets, handleTableSelection, 1.3295 + contentOffsetForTableSel, targetForTableSel, 1.3296 + parentContent, aEvent, aEventStatus); 1.3297 +} 1.3298 + 1.3299 +struct MOZ_STACK_CLASS FrameContentRange { 1.3300 + FrameContentRange(nsIContent* aContent, int32_t aStart, int32_t aEnd) : 1.3301 + content(aContent), start(aStart), end(aEnd) { } 1.3302 + nsCOMPtr<nsIContent> content; 1.3303 + int32_t start; 1.3304 + int32_t end; 1.3305 +}; 1.3306 + 1.3307 +// Retrieve the content offsets of a frame 1.3308 +static FrameContentRange GetRangeForFrame(nsIFrame* aFrame) { 1.3309 + nsCOMPtr<nsIContent> content, parent; 1.3310 + content = aFrame->GetContent(); 1.3311 + if (!content) { 1.3312 + NS_WARNING("Frame has no content"); 1.3313 + return FrameContentRange(nullptr, -1, -1); 1.3314 + } 1.3315 + nsIAtom* type = aFrame->GetType(); 1.3316 + if (type == nsGkAtoms::textFrame) { 1.3317 + int32_t offset, offsetEnd; 1.3318 + aFrame->GetOffsets(offset, offsetEnd); 1.3319 + return FrameContentRange(content, offset, offsetEnd); 1.3320 + } 1.3321 + if (type == nsGkAtoms::brFrame) { 1.3322 + parent = content->GetParent(); 1.3323 + int32_t beginOffset = parent->IndexOf(content); 1.3324 + return FrameContentRange(parent, beginOffset, beginOffset); 1.3325 + } 1.3326 + // Loop to deal with anonymous content, which has no index; this loop 1.3327 + // probably won't run more than twice under normal conditions 1.3328 + do { 1.3329 + parent = content->GetParent(); 1.3330 + if (parent) { 1.3331 + int32_t beginOffset = parent->IndexOf(content); 1.3332 + if (beginOffset >= 0) 1.3333 + return FrameContentRange(parent, beginOffset, beginOffset + 1); 1.3334 + content = parent; 1.3335 + } 1.3336 + } while (parent); 1.3337 + 1.3338 + // The root content node must act differently 1.3339 + return FrameContentRange(content, 0, content->GetChildCount()); 1.3340 +} 1.3341 + 1.3342 +// The FrameTarget represents the closest frame to a point that can be selected 1.3343 +// The frame is the frame represented, frameEdge says whether one end of the 1.3344 +// frame is the result (in which case different handling is needed), and 1.3345 +// afterFrame says which end is repersented if frameEdge is true 1.3346 +struct FrameTarget { 1.3347 + FrameTarget(nsIFrame* aFrame, bool aFrameEdge, bool aAfterFrame, 1.3348 + bool aEmptyBlock = false) : 1.3349 + frame(aFrame), frameEdge(aFrameEdge), afterFrame(aAfterFrame), 1.3350 + emptyBlock(aEmptyBlock) { } 1.3351 + static FrameTarget Null() { 1.3352 + return FrameTarget(nullptr, false, false); 1.3353 + } 1.3354 + bool IsNull() { 1.3355 + return !frame; 1.3356 + } 1.3357 + nsIFrame* frame; 1.3358 + bool frameEdge; 1.3359 + bool afterFrame; 1.3360 + bool emptyBlock; 1.3361 +}; 1.3362 + 1.3363 +// See function implementation for information 1.3364 +static FrameTarget GetSelectionClosestFrame(nsIFrame* aFrame, nsPoint aPoint, 1.3365 + uint32_t aFlags); 1.3366 + 1.3367 +static bool SelfIsSelectable(nsIFrame* aFrame, uint32_t aFlags) 1.3368 +{ 1.3369 + if ((aFlags & nsIFrame::SKIP_HIDDEN) && 1.3370 + !aFrame->StyleVisibility()->IsVisible()) { 1.3371 + return false; 1.3372 + } 1.3373 + return !aFrame->IsGeneratedContentFrame() && 1.3374 + aFrame->StyleUIReset()->mUserSelect != NS_STYLE_USER_SELECT_NONE; 1.3375 +} 1.3376 + 1.3377 +static bool SelectionDescendToKids(nsIFrame* aFrame) { 1.3378 + uint8_t style = aFrame->StyleUIReset()->mUserSelect; 1.3379 + nsIFrame* parent = aFrame->GetParent(); 1.3380 + // If we are only near (not directly over) then don't traverse 1.3381 + // frames with independent selection (e.g. text and list controls) 1.3382 + // unless we're already inside such a frame (see bug 268497). Note that this 1.3383 + // prevents any of the users of this method from entering form controls. 1.3384 + // XXX We might want some way to allow using the up-arrow to go into a form 1.3385 + // control, but the focus didn't work right anyway; it'd probably be enough 1.3386 + // if the left and right arrows could enter textboxes (which I don't believe 1.3387 + // they can at the moment) 1.3388 + return !aFrame->IsGeneratedContentFrame() && 1.3389 + style != NS_STYLE_USER_SELECT_ALL && 1.3390 + style != NS_STYLE_USER_SELECT_NONE && 1.3391 + ((parent->GetStateBits() & NS_FRAME_INDEPENDENT_SELECTION) || 1.3392 + !(aFrame->GetStateBits() & NS_FRAME_INDEPENDENT_SELECTION)); 1.3393 +} 1.3394 + 1.3395 +static FrameTarget GetSelectionClosestFrameForChild(nsIFrame* aChild, 1.3396 + nsPoint aPoint, 1.3397 + uint32_t aFlags) 1.3398 +{ 1.3399 + nsIFrame* parent = aChild->GetParent(); 1.3400 + if (SelectionDescendToKids(aChild)) { 1.3401 + nsPoint pt = aPoint - aChild->GetOffsetTo(parent); 1.3402 + return GetSelectionClosestFrame(aChild, pt, aFlags); 1.3403 + } 1.3404 + return FrameTarget(aChild, false, false); 1.3405 +} 1.3406 + 1.3407 +// When the cursor needs to be at the beginning of a block, it shouldn't be 1.3408 +// before the first child. A click on a block whose first child is a block 1.3409 +// should put the cursor in the child. The cursor shouldn't be between the 1.3410 +// blocks, because that's not where it's expected. 1.3411 +// Note that this method is guaranteed to succeed. 1.3412 +static FrameTarget DrillDownToSelectionFrame(nsIFrame* aFrame, 1.3413 + bool aEndFrame, uint32_t aFlags) { 1.3414 + if (SelectionDescendToKids(aFrame)) { 1.3415 + nsIFrame* result = nullptr; 1.3416 + nsIFrame *frame = aFrame->GetFirstPrincipalChild(); 1.3417 + if (!aEndFrame) { 1.3418 + while (frame && (!SelfIsSelectable(frame, aFlags) || 1.3419 + frame->IsEmpty())) 1.3420 + frame = frame->GetNextSibling(); 1.3421 + if (frame) 1.3422 + result = frame; 1.3423 + } else { 1.3424 + // Because the frame tree is singly linked, to find the last frame, 1.3425 + // we have to iterate through all the frames 1.3426 + // XXX I have a feeling this could be slow for long blocks, although 1.3427 + // I can't find any slowdowns 1.3428 + while (frame) { 1.3429 + if (!frame->IsEmpty() && SelfIsSelectable(frame, aFlags)) 1.3430 + result = frame; 1.3431 + frame = frame->GetNextSibling(); 1.3432 + } 1.3433 + } 1.3434 + if (result) 1.3435 + return DrillDownToSelectionFrame(result, aEndFrame, aFlags); 1.3436 + } 1.3437 + // If the current frame has no targetable children, target the current frame 1.3438 + return FrameTarget(aFrame, true, aEndFrame); 1.3439 +} 1.3440 + 1.3441 +// This method finds the closest valid FrameTarget on a given line; if there is 1.3442 +// no valid FrameTarget on the line, it returns a null FrameTarget 1.3443 +static FrameTarget GetSelectionClosestFrameForLine( 1.3444 + nsBlockFrame* aParent, 1.3445 + nsBlockFrame::line_iterator aLine, 1.3446 + nsPoint aPoint, 1.3447 + uint32_t aFlags) 1.3448 +{ 1.3449 + nsIFrame *frame = aLine->mFirstChild; 1.3450 + // Account for end of lines (any iterator from the block is valid) 1.3451 + if (aLine == aParent->end_lines()) 1.3452 + return DrillDownToSelectionFrame(aParent, true, aFlags); 1.3453 + nsIFrame *closestFromIStart = nullptr, *closestFromIEnd = nullptr; 1.3454 + nscoord closestIStart = aLine->IStart(), closestIEnd = aLine->IEnd(); 1.3455 + WritingMode wm = aLine->mWritingMode; 1.3456 + LogicalPoint pt(wm, aPoint, aLine->mContainerWidth); 1.3457 + for (int32_t n = aLine->GetChildCount(); n; 1.3458 + --n, frame = frame->GetNextSibling()) { 1.3459 + if (!SelfIsSelectable(frame, aFlags) || frame->IsEmpty()) 1.3460 + continue; 1.3461 + LogicalRect frameRect = LogicalRect(wm, frame->GetRect(), 1.3462 + aLine->mContainerWidth); 1.3463 + if (pt.I(wm) >= frameRect.IStart(wm)) { 1.3464 + if (pt.I(wm) < frameRect.IEnd(wm)) { 1.3465 + return GetSelectionClosestFrameForChild(frame, aPoint, aFlags); 1.3466 + } 1.3467 + if (frameRect.IEnd(wm) >= closestIStart) { 1.3468 + closestFromIStart = frame; 1.3469 + closestIStart = frameRect.IEnd(wm); 1.3470 + } 1.3471 + } else { 1.3472 + if (frameRect.IStart(wm) <= closestIEnd) { 1.3473 + closestFromIEnd = frame; 1.3474 + closestIEnd = frameRect.IStart(wm); 1.3475 + } 1.3476 + } 1.3477 + } 1.3478 + if (!closestFromIStart && !closestFromIEnd) { 1.3479 + // We should only get here if there are no selectable frames on a line 1.3480 + // XXX Do we need more elaborate handling here? 1.3481 + return FrameTarget::Null(); 1.3482 + } 1.3483 + if (closestFromIStart && 1.3484 + (!closestFromIEnd || 1.3485 + (abs(pt.I(wm) - closestIStart) <= abs(pt.I(wm) - closestIEnd)))) { 1.3486 + return GetSelectionClosestFrameForChild(closestFromIStart, aPoint, 1.3487 + aFlags); 1.3488 + } 1.3489 + return GetSelectionClosestFrameForChild(closestFromIEnd, aPoint, aFlags); 1.3490 +} 1.3491 + 1.3492 +// This method is for the special handling we do for block frames; they're 1.3493 +// special because they represent paragraphs and because they are organized 1.3494 +// into lines, which have bounds that are not stored elsewhere in the 1.3495 +// frame tree. Returns a null FrameTarget for frames which are not 1.3496 +// blocks or blocks with no lines except editable one. 1.3497 +static FrameTarget GetSelectionClosestFrameForBlock(nsIFrame* aFrame, 1.3498 + nsPoint aPoint, 1.3499 + uint32_t aFlags) 1.3500 +{ 1.3501 + nsBlockFrame* bf = nsLayoutUtils::GetAsBlock(aFrame); // used only for QI 1.3502 + if (!bf) 1.3503 + return FrameTarget::Null(); 1.3504 + 1.3505 + // This code searches for the correct line 1.3506 + nsBlockFrame::line_iterator firstLine = bf->begin_lines(); 1.3507 + nsBlockFrame::line_iterator end = bf->end_lines(); 1.3508 + if (firstLine == end) { 1.3509 + nsIContent *blockContent = aFrame->GetContent(); 1.3510 + if (blockContent) { 1.3511 + // Return with empty flag true. 1.3512 + return FrameTarget(aFrame, false, false, true); 1.3513 + } 1.3514 + return FrameTarget::Null(); 1.3515 + } 1.3516 + nsBlockFrame::line_iterator curLine = firstLine; 1.3517 + nsBlockFrame::line_iterator closestLine = end; 1.3518 + // Convert aPoint into a LogicalPoint in the writing-mode of this block 1.3519 + WritingMode wm = curLine->mWritingMode; 1.3520 + LogicalPoint pt(wm, aPoint, curLine->mContainerWidth); 1.3521 + while (curLine != end) { 1.3522 + // Check to see if our point lies within the line's block-direction bounds 1.3523 + nscoord BCoord = pt.B(wm) - curLine->BStart(); 1.3524 + nscoord BSize = curLine->BSize(); 1.3525 + if (BCoord >= 0 && BCoord < BSize) { 1.3526 + closestLine = curLine; 1.3527 + break; // We found the line; stop looking 1.3528 + } 1.3529 + if (BCoord < 0) 1.3530 + break; 1.3531 + ++curLine; 1.3532 + } 1.3533 + 1.3534 + if (closestLine == end) { 1.3535 + nsBlockFrame::line_iterator prevLine = curLine.prev(); 1.3536 + nsBlockFrame::line_iterator nextLine = curLine; 1.3537 + // Avoid empty lines 1.3538 + while (nextLine != end && nextLine->IsEmpty()) 1.3539 + ++nextLine; 1.3540 + while (prevLine != end && prevLine->IsEmpty()) 1.3541 + --prevLine; 1.3542 + 1.3543 + // This hidden pref dictates whether a point above or below all lines comes 1.3544 + // up with a line or the beginning or end of the frame; 0 on Windows, 1.3545 + // 1 on other platforms by default at the writing of this code 1.3546 + int32_t dragOutOfFrame = 1.3547 + Preferences::GetInt("browser.drag_out_of_frame_style"); 1.3548 + 1.3549 + if (prevLine == end) { 1.3550 + if (dragOutOfFrame == 1 || nextLine == end) 1.3551 + return DrillDownToSelectionFrame(aFrame, false, aFlags); 1.3552 + closestLine = nextLine; 1.3553 + } else if (nextLine == end) { 1.3554 + if (dragOutOfFrame == 1) 1.3555 + return DrillDownToSelectionFrame(aFrame, true, aFlags); 1.3556 + closestLine = prevLine; 1.3557 + } else { // Figure out which line is closer 1.3558 + if (pt.B(wm) - prevLine->BEnd() < nextLine->BStart() - pt.B(wm)) 1.3559 + closestLine = prevLine; 1.3560 + else 1.3561 + closestLine = nextLine; 1.3562 + } 1.3563 + } 1.3564 + 1.3565 + do { 1.3566 + FrameTarget target = GetSelectionClosestFrameForLine(bf, closestLine, 1.3567 + aPoint, aFlags); 1.3568 + if (!target.IsNull()) 1.3569 + return target; 1.3570 + ++closestLine; 1.3571 + } while (closestLine != end); 1.3572 + // Fall back to just targeting the last targetable place 1.3573 + return DrillDownToSelectionFrame(aFrame, true, aFlags); 1.3574 +} 1.3575 + 1.3576 +// GetSelectionClosestFrame is the helper function that calculates the closest 1.3577 +// frame to the given point. 1.3578 +// It doesn't completely account for offset styles, so needs to be used in 1.3579 +// restricted environments. 1.3580 +// Cannot handle overlapping frames correctly, so it should receive the output 1.3581 +// of GetFrameForPoint 1.3582 +// Guaranteed to return a valid FrameTarget 1.3583 +static FrameTarget GetSelectionClosestFrame(nsIFrame* aFrame, nsPoint aPoint, 1.3584 + uint32_t aFlags) 1.3585 +{ 1.3586 + { 1.3587 + // Handle blocks; if the frame isn't a block, the method fails 1.3588 + FrameTarget target = GetSelectionClosestFrameForBlock(aFrame, aPoint, aFlags); 1.3589 + if (!target.IsNull()) 1.3590 + return target; 1.3591 + } 1.3592 + 1.3593 + nsIFrame *kid = aFrame->GetFirstPrincipalChild(); 1.3594 + 1.3595 + if (kid) { 1.3596 + // Go through all the child frames to find the closest one 1.3597 + nsIFrame::FrameWithDistance closest = { nullptr, nscoord_MAX, nscoord_MAX }; 1.3598 + for (; kid; kid = kid->GetNextSibling()) { 1.3599 + if (!SelfIsSelectable(kid, aFlags) || kid->IsEmpty()) 1.3600 + continue; 1.3601 + 1.3602 + kid->FindCloserFrameForSelection(aPoint, &closest); 1.3603 + } 1.3604 + if (closest.mFrame) { 1.3605 + if (closest.mFrame->IsSVGText()) 1.3606 + return FrameTarget(closest.mFrame, false, false); 1.3607 + return GetSelectionClosestFrameForChild(closest.mFrame, aPoint, aFlags); 1.3608 + } 1.3609 + } 1.3610 + return FrameTarget(aFrame, false, false); 1.3611 +} 1.3612 + 1.3613 +nsIFrame::ContentOffsets OffsetsForSingleFrame(nsIFrame* aFrame, nsPoint aPoint) 1.3614 +{ 1.3615 + nsIFrame::ContentOffsets offsets; 1.3616 + FrameContentRange range = GetRangeForFrame(aFrame); 1.3617 + offsets.content = range.content; 1.3618 + // If there are continuations (meaning it's not one rectangle), this is the 1.3619 + // best this function can do 1.3620 + if (aFrame->GetNextContinuation() || aFrame->GetPrevContinuation()) { 1.3621 + offsets.offset = range.start; 1.3622 + offsets.secondaryOffset = range.end; 1.3623 + offsets.associateWithNext = true; 1.3624 + return offsets; 1.3625 + } 1.3626 + 1.3627 + // Figure out whether the offsets should be over, after, or before the frame 1.3628 + nsRect rect(nsPoint(0, 0), aFrame->GetSize()); 1.3629 + 1.3630 + bool isBlock = aFrame->GetDisplay() != NS_STYLE_DISPLAY_INLINE; 1.3631 + bool isRtl = (aFrame->StyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL); 1.3632 + if ((isBlock && rect.y < aPoint.y) || 1.3633 + (!isBlock && ((isRtl && rect.x + rect.width / 2 > aPoint.x) || 1.3634 + (!isRtl && rect.x + rect.width / 2 < aPoint.x)))) { 1.3635 + offsets.offset = range.end; 1.3636 + if (rect.Contains(aPoint)) 1.3637 + offsets.secondaryOffset = range.start; 1.3638 + else 1.3639 + offsets.secondaryOffset = range.end; 1.3640 + } else { 1.3641 + offsets.offset = range.start; 1.3642 + if (rect.Contains(aPoint)) 1.3643 + offsets.secondaryOffset = range.end; 1.3644 + else 1.3645 + offsets.secondaryOffset = range.start; 1.3646 + } 1.3647 + offsets.associateWithNext = (offsets.offset == range.start); 1.3648 + return offsets; 1.3649 +} 1.3650 + 1.3651 +static nsIFrame* AdjustFrameForSelectionStyles(nsIFrame* aFrame) { 1.3652 + nsIFrame* adjustedFrame = aFrame; 1.3653 + for (nsIFrame* frame = aFrame; frame; frame = frame->GetParent()) 1.3654 + { 1.3655 + // These are the conditions that make all children not able to handle 1.3656 + // a cursor. 1.3657 + if (frame->StyleUIReset()->mUserSelect == NS_STYLE_USER_SELECT_ALL || 1.3658 + frame->IsGeneratedContentFrame()) { 1.3659 + adjustedFrame = frame; 1.3660 + } 1.3661 + } 1.3662 + return adjustedFrame; 1.3663 +} 1.3664 + 1.3665 +nsIFrame::ContentOffsets nsIFrame::GetContentOffsetsFromPoint(nsPoint aPoint, 1.3666 + uint32_t aFlags) 1.3667 +{ 1.3668 + nsIFrame *adjustedFrame; 1.3669 + if (aFlags & IGNORE_SELECTION_STYLE) { 1.3670 + adjustedFrame = this; 1.3671 + } 1.3672 + else { 1.3673 + // This section of code deals with special selection styles. Note that 1.3674 + // -moz-all exists, even though it doesn't need to be explicitly handled. 1.3675 + // 1.3676 + // The offset is forced not to end up in generated content; content offsets 1.3677 + // cannot represent content outside of the document's content tree. 1.3678 + 1.3679 + adjustedFrame = AdjustFrameForSelectionStyles(this); 1.3680 + 1.3681 + // -moz-user-select: all needs special handling, because clicking on it 1.3682 + // should lead to the whole frame being selected 1.3683 + if (adjustedFrame && adjustedFrame->StyleUIReset()->mUserSelect == 1.3684 + NS_STYLE_USER_SELECT_ALL) { 1.3685 + nsPoint adjustedPoint = aPoint + this->GetOffsetTo(adjustedFrame); 1.3686 + return OffsetsForSingleFrame(adjustedFrame, adjustedPoint); 1.3687 + } 1.3688 + 1.3689 + // For other cases, try to find a closest frame starting from the parent of 1.3690 + // the unselectable frame 1.3691 + if (adjustedFrame != this) 1.3692 + adjustedFrame = adjustedFrame->GetParent(); 1.3693 + } 1.3694 + 1.3695 + nsPoint adjustedPoint = aPoint + this->GetOffsetTo(adjustedFrame); 1.3696 + 1.3697 + FrameTarget closest = 1.3698 + GetSelectionClosestFrame(adjustedFrame, adjustedPoint, aFlags); 1.3699 + 1.3700 + if (closest.emptyBlock) { 1.3701 + ContentOffsets offsets; 1.3702 + NS_ASSERTION(closest.frame, 1.3703 + "closest.frame must not be null when it's empty"); 1.3704 + offsets.content = closest.frame->GetContent(); 1.3705 + offsets.offset = 0; 1.3706 + offsets.secondaryOffset = 0; 1.3707 + offsets.associateWithNext = true; 1.3708 + return offsets; 1.3709 + } 1.3710 + 1.3711 + // If the correct offset is at one end of a frame, use offset-based 1.3712 + // calculation method 1.3713 + if (closest.frameEdge) { 1.3714 + ContentOffsets offsets; 1.3715 + FrameContentRange range = GetRangeForFrame(closest.frame); 1.3716 + offsets.content = range.content; 1.3717 + if (closest.afterFrame) 1.3718 + offsets.offset = range.end; 1.3719 + else 1.3720 + offsets.offset = range.start; 1.3721 + offsets.secondaryOffset = offsets.offset; 1.3722 + offsets.associateWithNext = (offsets.offset == range.start); 1.3723 + return offsets; 1.3724 + } 1.3725 + 1.3726 + nsPoint pt; 1.3727 + if (closest.frame != this) { 1.3728 + if (closest.frame->IsSVGText()) { 1.3729 + pt = nsLayoutUtils::TransformAncestorPointToFrame(closest.frame, 1.3730 + aPoint, this); 1.3731 + } else { 1.3732 + pt = aPoint - closest.frame->GetOffsetTo(this); 1.3733 + } 1.3734 + } else { 1.3735 + pt = aPoint; 1.3736 + } 1.3737 + return static_cast<nsFrame*>(closest.frame)->CalcContentOffsetsFromFramePoint(pt); 1.3738 + 1.3739 + // XXX should I add some kind of offset standardization? 1.3740 + // consider <b>xxxxx</b><i>zzzzz</i>; should any click between the last 1.3741 + // x and first z put the cursor in the same logical position in addition 1.3742 + // to the same visual position? 1.3743 +} 1.3744 + 1.3745 +nsIFrame::ContentOffsets nsFrame::CalcContentOffsetsFromFramePoint(nsPoint aPoint) 1.3746 +{ 1.3747 + return OffsetsForSingleFrame(this, aPoint); 1.3748 +} 1.3749 + 1.3750 +void 1.3751 +nsIFrame::AssociateImage(const nsStyleImage& aImage, nsPresContext* aPresContext) 1.3752 +{ 1.3753 + if (aImage.GetType() != eStyleImageType_Image) { 1.3754 + return; 1.3755 + } 1.3756 + 1.3757 + imgIRequest *req = aImage.GetImageData(); 1.3758 + mozilla::css::ImageLoader* loader = 1.3759 + aPresContext->Document()->StyleImageLoader(); 1.3760 + 1.3761 + // If this fails there's not much we can do ... 1.3762 + loader->AssociateRequestToFrame(req, this); 1.3763 +} 1.3764 + 1.3765 +nsresult 1.3766 +nsFrame::GetCursor(const nsPoint& aPoint, 1.3767 + nsIFrame::Cursor& aCursor) 1.3768 +{ 1.3769 + FillCursorInformationFromStyle(StyleUserInterface(), aCursor); 1.3770 + if (NS_STYLE_CURSOR_AUTO == aCursor.mCursor) { 1.3771 + // If this is editable, I-beam cursor is better for most elements. 1.3772 + aCursor.mCursor = 1.3773 + (mContent && mContent->IsEditable()) ? NS_STYLE_CURSOR_TEXT : 1.3774 + NS_STYLE_CURSOR_DEFAULT; 1.3775 + } 1.3776 + 1.3777 + 1.3778 + return NS_OK; 1.3779 +} 1.3780 + 1.3781 +// Resize and incremental reflow 1.3782 + 1.3783 +/* virtual */ void 1.3784 +nsFrame::MarkIntrinsicWidthsDirty() 1.3785 +{ 1.3786 + // This version is meant only for what used to be box-to-block adaptors. 1.3787 + // It should not be called by other derived classes. 1.3788 + if (IsBoxWrapped()) { 1.3789 + nsBoxLayoutMetrics *metrics = BoxMetrics(); 1.3790 + 1.3791 + SizeNeedsRecalc(metrics->mPrefSize); 1.3792 + SizeNeedsRecalc(metrics->mMinSize); 1.3793 + SizeNeedsRecalc(metrics->mMaxSize); 1.3794 + SizeNeedsRecalc(metrics->mBlockPrefSize); 1.3795 + SizeNeedsRecalc(metrics->mBlockMinSize); 1.3796 + CoordNeedsRecalc(metrics->mFlex); 1.3797 + CoordNeedsRecalc(metrics->mAscent); 1.3798 + } 1.3799 + 1.3800 + if (GetStateBits() & NS_FRAME_FONT_INFLATION_FLOW_ROOT) { 1.3801 + nsFontInflationData::MarkFontInflationDataTextDirty(this); 1.3802 + } 1.3803 +} 1.3804 + 1.3805 +/* virtual */ nscoord 1.3806 +nsFrame::GetMinWidth(nsRenderingContext *aRenderingContext) 1.3807 +{ 1.3808 + nscoord result = 0; 1.3809 + DISPLAY_MIN_WIDTH(this, result); 1.3810 + return result; 1.3811 +} 1.3812 + 1.3813 +/* virtual */ nscoord 1.3814 +nsFrame::GetPrefWidth(nsRenderingContext *aRenderingContext) 1.3815 +{ 1.3816 + nscoord result = 0; 1.3817 + DISPLAY_PREF_WIDTH(this, result); 1.3818 + return result; 1.3819 +} 1.3820 + 1.3821 +/* virtual */ void 1.3822 +nsFrame::AddInlineMinWidth(nsRenderingContext *aRenderingContext, 1.3823 + nsIFrame::InlineMinWidthData *aData) 1.3824 +{ 1.3825 + NS_ASSERTION(GetParent(), "Must have a parent if we get here!"); 1.3826 + nsIFrame* parent = GetParent(); 1.3827 + bool canBreak = !CanContinueTextRun() && 1.3828 + parent->StyleText()->WhiteSpaceCanWrap(parent); 1.3829 + 1.3830 + if (canBreak) 1.3831 + aData->OptionallyBreak(aRenderingContext); 1.3832 + aData->trailingWhitespace = 0; 1.3833 + aData->skipWhitespace = false; 1.3834 + aData->trailingTextFrame = nullptr; 1.3835 + aData->currentLine += nsLayoutUtils::IntrinsicForContainer(aRenderingContext, 1.3836 + this, nsLayoutUtils::MIN_WIDTH); 1.3837 + aData->atStartOfLine = false; 1.3838 + if (canBreak) 1.3839 + aData->OptionallyBreak(aRenderingContext); 1.3840 +} 1.3841 + 1.3842 +/* virtual */ void 1.3843 +nsFrame::AddInlinePrefWidth(nsRenderingContext *aRenderingContext, 1.3844 + nsIFrame::InlinePrefWidthData *aData) 1.3845 +{ 1.3846 + aData->trailingWhitespace = 0; 1.3847 + aData->skipWhitespace = false; 1.3848 + nscoord myPref = nsLayoutUtils::IntrinsicForContainer(aRenderingContext, 1.3849 + this, nsLayoutUtils::PREF_WIDTH); 1.3850 + aData->currentLine = NSCoordSaturatingAdd(aData->currentLine, myPref); 1.3851 +} 1.3852 + 1.3853 +void 1.3854 +nsIFrame::InlineMinWidthData::ForceBreak(nsRenderingContext *aRenderingContext) 1.3855 +{ 1.3856 + currentLine -= trailingWhitespace; 1.3857 + prevLines = std::max(prevLines, currentLine); 1.3858 + currentLine = trailingWhitespace = 0; 1.3859 + 1.3860 + for (uint32_t i = 0, i_end = floats.Length(); i != i_end; ++i) { 1.3861 + nscoord float_min = floats[i].Width(); 1.3862 + if (float_min > prevLines) 1.3863 + prevLines = float_min; 1.3864 + } 1.3865 + floats.Clear(); 1.3866 + trailingTextFrame = nullptr; 1.3867 + skipWhitespace = true; 1.3868 +} 1.3869 + 1.3870 +void 1.3871 +nsIFrame::InlineMinWidthData::OptionallyBreak(nsRenderingContext *aRenderingContext, 1.3872 + nscoord aHyphenWidth) 1.3873 +{ 1.3874 + trailingTextFrame = nullptr; 1.3875 + 1.3876 + // If we can fit more content into a smaller width by staying on this 1.3877 + // line (because we're still at a negative offset due to negative 1.3878 + // text-indent or negative margin), don't break. Otherwise, do the 1.3879 + // same as ForceBreak. it doesn't really matter when we accumulate 1.3880 + // floats. 1.3881 + if (currentLine + aHyphenWidth < 0 || atStartOfLine) 1.3882 + return; 1.3883 + currentLine += aHyphenWidth; 1.3884 + ForceBreak(aRenderingContext); 1.3885 +} 1.3886 + 1.3887 +void 1.3888 +nsIFrame::InlinePrefWidthData::ForceBreak(nsRenderingContext *aRenderingContext) 1.3889 +{ 1.3890 + if (floats.Length() != 0) { 1.3891 + // preferred widths accumulated for floats that have already 1.3892 + // been cleared past 1.3893 + nscoord floats_done = 0, 1.3894 + // preferred widths accumulated for floats that have not yet 1.3895 + // been cleared past 1.3896 + floats_cur_left = 0, 1.3897 + floats_cur_right = 0; 1.3898 + 1.3899 + for (uint32_t i = 0, i_end = floats.Length(); i != i_end; ++i) { 1.3900 + const FloatInfo& floatInfo = floats[i]; 1.3901 + const nsStyleDisplay *floatDisp = floatInfo.Frame()->StyleDisplay(); 1.3902 + if (floatDisp->mBreakType == NS_STYLE_CLEAR_LEFT || 1.3903 + floatDisp->mBreakType == NS_STYLE_CLEAR_RIGHT || 1.3904 + floatDisp->mBreakType == NS_STYLE_CLEAR_BOTH) { 1.3905 + nscoord floats_cur = NSCoordSaturatingAdd(floats_cur_left, 1.3906 + floats_cur_right); 1.3907 + if (floats_cur > floats_done) 1.3908 + floats_done = floats_cur; 1.3909 + if (floatDisp->mBreakType != NS_STYLE_CLEAR_RIGHT) 1.3910 + floats_cur_left = 0; 1.3911 + if (floatDisp->mBreakType != NS_STYLE_CLEAR_LEFT) 1.3912 + floats_cur_right = 0; 1.3913 + } 1.3914 + 1.3915 + nscoord &floats_cur = floatDisp->mFloats == NS_STYLE_FLOAT_LEFT 1.3916 + ? floats_cur_left : floats_cur_right; 1.3917 + nscoord floatWidth = floatInfo.Width(); 1.3918 + // Negative-width floats don't change the available space so they 1.3919 + // shouldn't change our intrinsic line width either. 1.3920 + floats_cur = 1.3921 + NSCoordSaturatingAdd(floats_cur, std::max(0, floatWidth)); 1.3922 + } 1.3923 + 1.3924 + nscoord floats_cur = 1.3925 + NSCoordSaturatingAdd(floats_cur_left, floats_cur_right); 1.3926 + if (floats_cur > floats_done) 1.3927 + floats_done = floats_cur; 1.3928 + 1.3929 + currentLine = NSCoordSaturatingAdd(currentLine, floats_done); 1.3930 + 1.3931 + floats.Clear(); 1.3932 + } 1.3933 + 1.3934 + currentLine = 1.3935 + NSCoordSaturatingSubtract(currentLine, trailingWhitespace, nscoord_MAX); 1.3936 + prevLines = std::max(prevLines, currentLine); 1.3937 + currentLine = trailingWhitespace = 0; 1.3938 + skipWhitespace = true; 1.3939 +} 1.3940 + 1.3941 +static void 1.3942 +AddCoord(const nsStyleCoord& aStyle, 1.3943 + nsRenderingContext* aRenderingContext, 1.3944 + nsIFrame* aFrame, 1.3945 + nscoord* aCoord, float* aPercent, 1.3946 + bool aClampNegativeToZero) 1.3947 +{ 1.3948 + switch (aStyle.GetUnit()) { 1.3949 + case eStyleUnit_Coord: { 1.3950 + NS_ASSERTION(!aClampNegativeToZero || aStyle.GetCoordValue() >= 0, 1.3951 + "unexpected negative value"); 1.3952 + *aCoord += aStyle.GetCoordValue(); 1.3953 + return; 1.3954 + } 1.3955 + case eStyleUnit_Percent: { 1.3956 + NS_ASSERTION(!aClampNegativeToZero || aStyle.GetPercentValue() >= 0.0f, 1.3957 + "unexpected negative value"); 1.3958 + *aPercent += aStyle.GetPercentValue(); 1.3959 + return; 1.3960 + } 1.3961 + case eStyleUnit_Calc: { 1.3962 + const nsStyleCoord::Calc *calc = aStyle.GetCalcValue(); 1.3963 + if (aClampNegativeToZero) { 1.3964 + // This is far from ideal when one is negative and one is positive. 1.3965 + *aCoord += std::max(calc->mLength, 0); 1.3966 + *aPercent += std::max(calc->mPercent, 0.0f); 1.3967 + } else { 1.3968 + *aCoord += calc->mLength; 1.3969 + *aPercent += calc->mPercent; 1.3970 + } 1.3971 + return; 1.3972 + } 1.3973 + default: { 1.3974 + return; 1.3975 + } 1.3976 + } 1.3977 +} 1.3978 + 1.3979 +/* virtual */ nsIFrame::IntrinsicWidthOffsetData 1.3980 +nsFrame::IntrinsicWidthOffsets(nsRenderingContext* aRenderingContext) 1.3981 +{ 1.3982 + IntrinsicWidthOffsetData result; 1.3983 + 1.3984 + const nsStyleMargin *styleMargin = StyleMargin(); 1.3985 + AddCoord(styleMargin->mMargin.GetLeft(), aRenderingContext, this, 1.3986 + &result.hMargin, &result.hPctMargin, false); 1.3987 + AddCoord(styleMargin->mMargin.GetRight(), aRenderingContext, this, 1.3988 + &result.hMargin, &result.hPctMargin, false); 1.3989 + 1.3990 + const nsStylePadding *stylePadding = StylePadding(); 1.3991 + AddCoord(stylePadding->mPadding.GetLeft(), aRenderingContext, this, 1.3992 + &result.hPadding, &result.hPctPadding, true); 1.3993 + AddCoord(stylePadding->mPadding.GetRight(), aRenderingContext, this, 1.3994 + &result.hPadding, &result.hPctPadding, true); 1.3995 + 1.3996 + const nsStyleBorder *styleBorder = StyleBorder(); 1.3997 + result.hBorder += styleBorder->GetComputedBorderWidth(NS_SIDE_LEFT); 1.3998 + result.hBorder += styleBorder->GetComputedBorderWidth(NS_SIDE_RIGHT); 1.3999 + 1.4000 + const nsStyleDisplay *disp = StyleDisplay(); 1.4001 + if (IsThemed(disp)) { 1.4002 + nsPresContext *presContext = PresContext(); 1.4003 + 1.4004 + nsIntMargin border; 1.4005 + presContext->GetTheme()->GetWidgetBorder(presContext->DeviceContext(), 1.4006 + this, disp->mAppearance, 1.4007 + &border); 1.4008 + result.hBorder = presContext->DevPixelsToAppUnits(border.LeftRight()); 1.4009 + 1.4010 + nsIntMargin padding; 1.4011 + if (presContext->GetTheme()->GetWidgetPadding(presContext->DeviceContext(), 1.4012 + this, disp->mAppearance, 1.4013 + &padding)) { 1.4014 + result.hPadding = presContext->DevPixelsToAppUnits(padding.LeftRight()); 1.4015 + result.hPctPadding = 0; 1.4016 + } 1.4017 + } 1.4018 + 1.4019 + return result; 1.4020 +} 1.4021 + 1.4022 +/* virtual */ IntrinsicSize 1.4023 +nsFrame::GetIntrinsicSize() 1.4024 +{ 1.4025 + return IntrinsicSize(); // default is width/height set to eStyleUnit_None 1.4026 +} 1.4027 + 1.4028 +/* virtual */ nsSize 1.4029 +nsFrame::GetIntrinsicRatio() 1.4030 +{ 1.4031 + return nsSize(0, 0); 1.4032 +} 1.4033 + 1.4034 +/* virtual */ nsSize 1.4035 +nsFrame::ComputeSize(nsRenderingContext *aRenderingContext, 1.4036 + nsSize aCBSize, nscoord aAvailableWidth, 1.4037 + nsSize aMargin, nsSize aBorder, nsSize aPadding, 1.4038 + uint32_t aFlags) 1.4039 +{ 1.4040 + nsSize result = ComputeAutoSize(aRenderingContext, aCBSize, aAvailableWidth, 1.4041 + aMargin, aBorder, aPadding, 1.4042 + aFlags & eShrinkWrap); 1.4043 + nsSize boxSizingAdjust(0,0); 1.4044 + const nsStylePosition *stylePos = StylePosition(); 1.4045 + 1.4046 + switch (stylePos->mBoxSizing) { 1.4047 + case NS_STYLE_BOX_SIZING_BORDER: 1.4048 + boxSizingAdjust += aBorder; 1.4049 + // fall through 1.4050 + case NS_STYLE_BOX_SIZING_PADDING: 1.4051 + boxSizingAdjust += aPadding; 1.4052 + } 1.4053 + nscoord boxSizingToMarginEdgeWidth = 1.4054 + aMargin.width + aBorder.width + aPadding.width - boxSizingAdjust.width; 1.4055 + const nsStyleCoord* widthStyleCoord = &(stylePos->mWidth); 1.4056 + const nsStyleCoord* heightStyleCoord = &(stylePos->mHeight); 1.4057 + 1.4058 + bool isFlexItem = IsFlexItem(); 1.4059 + bool isHorizontalFlexItem = false; 1.4060 + 1.4061 + if (isFlexItem) { 1.4062 + // Flex items use their "flex-basis" property in place of their main-size 1.4063 + // property (e.g. "width") for sizing purposes, *unless* they have 1.4064 + // "flex-basis:auto", in which case they use their main-size property after 1.4065 + // all. 1.4066 + uint32_t flexDirection = mParent->StylePosition()->mFlexDirection; 1.4067 + isHorizontalFlexItem = 1.4068 + flexDirection == NS_STYLE_FLEX_DIRECTION_ROW || 1.4069 + flexDirection == NS_STYLE_FLEX_DIRECTION_ROW_REVERSE; 1.4070 + 1.4071 + // NOTE: The logic here should match the similar chunk for determining 1.4072 + // widthStyleCoord and heightStyleCoord in 1.4073 + // nsLayoutUtils::ComputeSizeWithIntrinsicDimensions(). 1.4074 + const nsStyleCoord* flexBasis = &(stylePos->mFlexBasis); 1.4075 + if (flexBasis->GetUnit() != eStyleUnit_Auto) { 1.4076 + if (isHorizontalFlexItem) { 1.4077 + widthStyleCoord = flexBasis; 1.4078 + } else { 1.4079 + // One caveat for vertical flex items: We don't support enumerated 1.4080 + // values (e.g. "max-content") for height properties yet. So, if our 1.4081 + // computed flex-basis is an enumerated value, we'll just behave as if 1.4082 + // it were "auto", which means "use the main-size property after all" 1.4083 + // (which is "height", in this case). 1.4084 + // NOTE: Once we support intrinsic sizing keywords for "height", 1.4085 + // we should remove this check. 1.4086 + if (flexBasis->GetUnit() != eStyleUnit_Enumerated) { 1.4087 + heightStyleCoord = flexBasis; 1.4088 + } 1.4089 + } 1.4090 + } 1.4091 + } 1.4092 + 1.4093 + // Compute width 1.4094 + 1.4095 + if (widthStyleCoord->GetUnit() != eStyleUnit_Auto) { 1.4096 + result.width = 1.4097 + nsLayoutUtils::ComputeWidthValue(aRenderingContext, this, 1.4098 + aCBSize.width, boxSizingAdjust.width, boxSizingToMarginEdgeWidth, 1.4099 + *widthStyleCoord); 1.4100 + } 1.4101 + 1.4102 + // Flex items ignore their min & max sizing properties in their 1.4103 + // flex container's main-axis. (Those properties get applied later in 1.4104 + // the flexbox algorithm.) 1.4105 + if (stylePos->mMaxWidth.GetUnit() != eStyleUnit_None && 1.4106 + !(isFlexItem && isHorizontalFlexItem)) { 1.4107 + nscoord maxWidth = 1.4108 + nsLayoutUtils::ComputeWidthValue(aRenderingContext, this, 1.4109 + aCBSize.width, boxSizingAdjust.width, boxSizingToMarginEdgeWidth, 1.4110 + stylePos->mMaxWidth); 1.4111 + result.width = std::min(maxWidth, result.width); 1.4112 + } 1.4113 + 1.4114 + nscoord minWidth; 1.4115 + if (!(isFlexItem && isHorizontalFlexItem)) { 1.4116 + minWidth = 1.4117 + nsLayoutUtils::ComputeWidthValue(aRenderingContext, this, 1.4118 + aCBSize.width, boxSizingAdjust.width, boxSizingToMarginEdgeWidth, 1.4119 + stylePos->mMinWidth); 1.4120 + } else { 1.4121 + minWidth = 0; 1.4122 + } 1.4123 + result.width = std::max(minWidth, result.width); 1.4124 + 1.4125 + // Compute height 1.4126 + // (but not if we're auto-height or if we recieved the "eUseAutoHeight" 1.4127 + // flag -- then, we'll just stick with the height that we already calculated 1.4128 + // in the initial ComputeAutoSize() call.) 1.4129 + if (!nsLayoutUtils::IsAutoHeight(*heightStyleCoord, aCBSize.height) && 1.4130 + !(aFlags & nsIFrame::eUseAutoHeight)) { 1.4131 + result.height = 1.4132 + nsLayoutUtils::ComputeHeightValue(aCBSize.height, 1.4133 + boxSizingAdjust.height, 1.4134 + *heightStyleCoord); 1.4135 + } 1.4136 + 1.4137 + if (result.height != NS_UNCONSTRAINEDSIZE) { 1.4138 + if (!nsLayoutUtils::IsAutoHeight(stylePos->mMaxHeight, aCBSize.height) && 1.4139 + !(isFlexItem && !isHorizontalFlexItem)) { 1.4140 + nscoord maxHeight = 1.4141 + nsLayoutUtils::ComputeHeightValue(aCBSize.height, 1.4142 + boxSizingAdjust.height, 1.4143 + stylePos->mMaxHeight); 1.4144 + result.height = std::min(maxHeight, result.height); 1.4145 + } 1.4146 + 1.4147 + if (!nsLayoutUtils::IsAutoHeight(stylePos->mMinHeight, aCBSize.height) && 1.4148 + !(isFlexItem && !isHorizontalFlexItem)) { 1.4149 + nscoord minHeight = 1.4150 + nsLayoutUtils::ComputeHeightValue(aCBSize.height, 1.4151 + boxSizingAdjust.height, 1.4152 + stylePos->mMinHeight); 1.4153 + result.height = std::max(minHeight, result.height); 1.4154 + } 1.4155 + } 1.4156 + 1.4157 + const nsStyleDisplay *disp = StyleDisplay(); 1.4158 + if (IsThemed(disp)) { 1.4159 + nsIntSize widget(0, 0); 1.4160 + bool canOverride = true; 1.4161 + nsPresContext *presContext = PresContext(); 1.4162 + presContext->GetTheme()-> 1.4163 + GetMinimumWidgetSize(aRenderingContext, this, disp->mAppearance, 1.4164 + &widget, &canOverride); 1.4165 + 1.4166 + nsSize size; 1.4167 + size.width = presContext->DevPixelsToAppUnits(widget.width); 1.4168 + size.height = presContext->DevPixelsToAppUnits(widget.height); 1.4169 + 1.4170 + // GMWS() returns border-box; we need content-box 1.4171 + size.width -= aBorder.width + aPadding.width; 1.4172 + size.height -= aBorder.height + aPadding.height; 1.4173 + 1.4174 + if (size.height > result.height || !canOverride) 1.4175 + result.height = size.height; 1.4176 + if (size.width > result.width || !canOverride) 1.4177 + result.width = size.width; 1.4178 + } 1.4179 + 1.4180 + result.width = std::max(0, result.width); 1.4181 + result.height = std::max(0, result.height); 1.4182 + 1.4183 + return result; 1.4184 +} 1.4185 + 1.4186 +nsRect 1.4187 +nsIFrame::ComputeTightBounds(gfxContext* aContext) const 1.4188 +{ 1.4189 + return GetVisualOverflowRect(); 1.4190 +} 1.4191 + 1.4192 +nsRect 1.4193 +nsFrame::ComputeSimpleTightBounds(gfxContext* aContext) const 1.4194 +{ 1.4195 + if (StyleOutline()->GetOutlineStyle() != NS_STYLE_BORDER_STYLE_NONE || 1.4196 + StyleBorder()->HasBorder() || !StyleBackground()->IsTransparent() || 1.4197 + StyleDisplay()->mAppearance) { 1.4198 + // Not necessarily tight, due to clipping, negative 1.4199 + // outline-offset, and lots of other issues, but that's OK 1.4200 + return GetVisualOverflowRect(); 1.4201 + } 1.4202 + 1.4203 + nsRect r(0, 0, 0, 0); 1.4204 + ChildListIterator lists(this); 1.4205 + for (; !lists.IsDone(); lists.Next()) { 1.4206 + nsFrameList::Enumerator childFrames(lists.CurrentList()); 1.4207 + for (; !childFrames.AtEnd(); childFrames.Next()) { 1.4208 + nsIFrame* child = childFrames.get(); 1.4209 + r.UnionRect(r, child->ComputeTightBounds(aContext) + child->GetPosition()); 1.4210 + } 1.4211 + } 1.4212 + return r; 1.4213 +} 1.4214 + 1.4215 +/* virtual */ nsresult 1.4216 +nsIFrame::GetPrefWidthTightBounds(nsRenderingContext* aContext, 1.4217 + nscoord* aX, 1.4218 + nscoord* aXMost) 1.4219 +{ 1.4220 + return NS_ERROR_NOT_IMPLEMENTED; 1.4221 +} 1.4222 + 1.4223 +/* virtual */ nsSize 1.4224 +nsFrame::ComputeAutoSize(nsRenderingContext *aRenderingContext, 1.4225 + nsSize aCBSize, nscoord aAvailableWidth, 1.4226 + nsSize aMargin, nsSize aBorder, nsSize aPadding, 1.4227 + bool aShrinkWrap) 1.4228 +{ 1.4229 + // Use basic shrink-wrapping as a default implementation. 1.4230 + nsSize result(0xdeadbeef, NS_UNCONSTRAINEDSIZE); 1.4231 + 1.4232 + // don't bother setting it if the result won't be used 1.4233 + if (StylePosition()->mWidth.GetUnit() == eStyleUnit_Auto) { 1.4234 + nscoord availBased = aAvailableWidth - aMargin.width - aBorder.width - 1.4235 + aPadding.width; 1.4236 + result.width = ShrinkWidthToFit(aRenderingContext, availBased); 1.4237 + } 1.4238 + return result; 1.4239 +} 1.4240 + 1.4241 +nscoord 1.4242 +nsFrame::ShrinkWidthToFit(nsRenderingContext *aRenderingContext, 1.4243 + nscoord aWidthInCB) 1.4244 +{ 1.4245 + // If we're a container for font size inflation, then shrink 1.4246 + // wrapping inside of us should not apply font size inflation. 1.4247 + AutoMaybeDisableFontInflation an(this); 1.4248 + 1.4249 + nscoord result; 1.4250 + nscoord minWidth = GetMinWidth(aRenderingContext); 1.4251 + if (minWidth > aWidthInCB) { 1.4252 + result = minWidth; 1.4253 + } else { 1.4254 + nscoord prefWidth = GetPrefWidth(aRenderingContext); 1.4255 + if (prefWidth > aWidthInCB) { 1.4256 + result = aWidthInCB; 1.4257 + } else { 1.4258 + result = prefWidth; 1.4259 + } 1.4260 + } 1.4261 + return result; 1.4262 +} 1.4263 + 1.4264 +nsresult 1.4265 +nsFrame::WillReflow(nsPresContext* aPresContext) 1.4266 +{ 1.4267 +#ifdef DEBUG_dbaron_off 1.4268 + // bug 81268 1.4269 + NS_ASSERTION(!(mState & NS_FRAME_IN_REFLOW), 1.4270 + "nsFrame::WillReflow: frame is already in reflow"); 1.4271 +#endif 1.4272 + 1.4273 + NS_FRAME_TRACE_MSG(NS_FRAME_TRACE_CALLS, 1.4274 + ("WillReflow: oldState=%x", mState)); 1.4275 + mState |= NS_FRAME_IN_REFLOW; 1.4276 + return NS_OK; 1.4277 +} 1.4278 + 1.4279 +nsresult 1.4280 +nsFrame::DidReflow(nsPresContext* aPresContext, 1.4281 + const nsHTMLReflowState* aReflowState, 1.4282 + nsDidReflowStatus aStatus) 1.4283 +{ 1.4284 + NS_FRAME_TRACE_MSG(NS_FRAME_TRACE_CALLS, 1.4285 + ("nsFrame::DidReflow: aStatus=%d", static_cast<uint32_t>(aStatus))); 1.4286 + 1.4287 + nsSVGEffects::InvalidateDirectRenderingObservers(this, nsSVGEffects::INVALIDATE_REFLOW); 1.4288 + 1.4289 + if (nsDidReflowStatus::FINISHED == aStatus) { 1.4290 + mState &= ~(NS_FRAME_IN_REFLOW | NS_FRAME_FIRST_REFLOW | NS_FRAME_IS_DIRTY | 1.4291 + NS_FRAME_HAS_DIRTY_CHILDREN); 1.4292 + } 1.4293 + 1.4294 + // Notify the percent height observer if there is a percent height. 1.4295 + // The observer may be able to initiate another reflow with a computed 1.4296 + // height. This happens in the case where a table cell has no computed 1.4297 + // height but can fabricate one when the cell height is known. 1.4298 + if (aReflowState && aReflowState->mPercentHeightObserver && 1.4299 + !GetPrevInFlow()) { 1.4300 + const nsStyleCoord &height = aReflowState->mStylePosition->mHeight; 1.4301 + if (height.HasPercent()) { 1.4302 + aReflowState->mPercentHeightObserver->NotifyPercentHeight(*aReflowState); 1.4303 + } 1.4304 + } 1.4305 + 1.4306 + return NS_OK; 1.4307 +} 1.4308 + 1.4309 +void 1.4310 +nsFrame::FinishReflowWithAbsoluteFrames(nsPresContext* aPresContext, 1.4311 + nsHTMLReflowMetrics& aDesiredSize, 1.4312 + const nsHTMLReflowState& aReflowState, 1.4313 + nsReflowStatus& aStatus, 1.4314 + bool aConstrainHeight) 1.4315 +{ 1.4316 + ReflowAbsoluteFrames(aPresContext, aDesiredSize, aReflowState, aStatus, aConstrainHeight); 1.4317 + 1.4318 + FinishAndStoreOverflow(&aDesiredSize); 1.4319 +} 1.4320 + 1.4321 +void 1.4322 +nsFrame::ReflowAbsoluteFrames(nsPresContext* aPresContext, 1.4323 + nsHTMLReflowMetrics& aDesiredSize, 1.4324 + const nsHTMLReflowState& aReflowState, 1.4325 + nsReflowStatus& aStatus, 1.4326 + bool aConstrainHeight) 1.4327 +{ 1.4328 + if (HasAbsolutelyPositionedChildren()) { 1.4329 + nsAbsoluteContainingBlock* absoluteContainer = GetAbsoluteContainingBlock(); 1.4330 + 1.4331 + // Let the absolutely positioned container reflow any absolutely positioned 1.4332 + // child frames that need to be reflowed 1.4333 + 1.4334 + // The containing block for the abs pos kids is formed by our padding edge. 1.4335 + nsMargin computedBorder = 1.4336 + aReflowState.ComputedPhysicalBorderPadding() - aReflowState.ComputedPhysicalPadding(); 1.4337 + nscoord containingBlockWidth = 1.4338 + aDesiredSize.Width() - computedBorder.LeftRight(); 1.4339 + nscoord containingBlockHeight = 1.4340 + aDesiredSize.Height() - computedBorder.TopBottom(); 1.4341 + 1.4342 + nsContainerFrame* container = do_QueryFrame(this); 1.4343 + NS_ASSERTION(container, "Abs-pos children only supported on container frames for now"); 1.4344 + 1.4345 + nsRect containingBlock(0, 0, containingBlockWidth, containingBlockHeight); 1.4346 + absoluteContainer->Reflow(container, aPresContext, aReflowState, aStatus, 1.4347 + containingBlock, 1.4348 + aConstrainHeight, true, true, // XXX could be optimized 1.4349 + &aDesiredSize.mOverflowAreas); 1.4350 + } 1.4351 +} 1.4352 + 1.4353 +/* virtual */ bool 1.4354 +nsFrame::CanContinueTextRun() const 1.4355 +{ 1.4356 + // By default, a frame will *not* allow a text run to be continued 1.4357 + // through it. 1.4358 + return false; 1.4359 +} 1.4360 + 1.4361 +nsresult 1.4362 +nsFrame::Reflow(nsPresContext* aPresContext, 1.4363 + nsHTMLReflowMetrics& aDesiredSize, 1.4364 + const nsHTMLReflowState& aReflowState, 1.4365 + nsReflowStatus& aStatus) 1.4366 +{ 1.4367 + DO_GLOBAL_REFLOW_COUNT("nsFrame"); 1.4368 + aDesiredSize.Width() = 0; 1.4369 + aDesiredSize.Height() = 0; 1.4370 + aStatus = NS_FRAME_COMPLETE; 1.4371 + NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize); 1.4372 + return NS_OK; 1.4373 +} 1.4374 + 1.4375 +nsresult 1.4376 +nsFrame::CharacterDataChanged(CharacterDataChangeInfo* aInfo) 1.4377 +{ 1.4378 + NS_NOTREACHED("should only be called for text frames"); 1.4379 + return NS_OK; 1.4380 +} 1.4381 + 1.4382 +nsresult 1.4383 +nsFrame::AttributeChanged(int32_t aNameSpaceID, 1.4384 + nsIAtom* aAttribute, 1.4385 + int32_t aModType) 1.4386 +{ 1.4387 + return NS_OK; 1.4388 +} 1.4389 + 1.4390 +// Flow member functions 1.4391 + 1.4392 +nsSplittableType 1.4393 +nsFrame::GetSplittableType() const 1.4394 +{ 1.4395 + return NS_FRAME_NOT_SPLITTABLE; 1.4396 +} 1.4397 + 1.4398 +nsIFrame* nsFrame::GetPrevContinuation() const 1.4399 +{ 1.4400 + return nullptr; 1.4401 +} 1.4402 + 1.4403 +void 1.4404 +nsFrame::SetPrevContinuation(nsIFrame* aPrevContinuation) 1.4405 +{ 1.4406 + MOZ_ASSERT(false, "not splittable"); 1.4407 +} 1.4408 + 1.4409 +nsIFrame* nsFrame::GetNextContinuation() const 1.4410 +{ 1.4411 + return nullptr; 1.4412 +} 1.4413 + 1.4414 +void 1.4415 +nsFrame::SetNextContinuation(nsIFrame*) 1.4416 +{ 1.4417 + MOZ_ASSERT(false, "not splittable"); 1.4418 +} 1.4419 + 1.4420 +nsIFrame* nsFrame::GetPrevInFlowVirtual() const 1.4421 +{ 1.4422 + return nullptr; 1.4423 +} 1.4424 + 1.4425 +void 1.4426 +nsFrame::SetPrevInFlow(nsIFrame* aPrevInFlow) 1.4427 +{ 1.4428 + MOZ_ASSERT(false, "not splittable"); 1.4429 +} 1.4430 + 1.4431 +nsIFrame* nsFrame::GetNextInFlowVirtual() const 1.4432 +{ 1.4433 + return nullptr; 1.4434 +} 1.4435 + 1.4436 +void 1.4437 +nsFrame::SetNextInFlow(nsIFrame*) 1.4438 +{ 1.4439 + MOZ_ASSERT(false, "not splittable"); 1.4440 +} 1.4441 + 1.4442 +nsIFrame* nsIFrame::GetTailContinuation() 1.4443 +{ 1.4444 + nsIFrame* frame = this; 1.4445 + while (frame->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER) { 1.4446 + frame = frame->GetPrevContinuation(); 1.4447 + NS_ASSERTION(frame, "first continuation can't be overflow container"); 1.4448 + } 1.4449 + for (nsIFrame* next = frame->GetNextContinuation(); 1.4450 + next && !(next->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER); 1.4451 + next = frame->GetNextContinuation()) { 1.4452 + frame = next; 1.4453 + } 1.4454 + NS_POSTCONDITION(frame, "illegal state in continuation chain."); 1.4455 + return frame; 1.4456 +} 1.4457 + 1.4458 +NS_DECLARE_FRAME_PROPERTY(ViewProperty, nullptr) 1.4459 + 1.4460 +// Associated view object 1.4461 +nsView* 1.4462 +nsIFrame::GetView() const 1.4463 +{ 1.4464 + // Check the frame state bit and see if the frame has a view 1.4465 + if (!(GetStateBits() & NS_FRAME_HAS_VIEW)) 1.4466 + return nullptr; 1.4467 + 1.4468 + // Check for a property on the frame 1.4469 + void* value = Properties().Get(ViewProperty()); 1.4470 + NS_ASSERTION(value, "frame state bit was set but frame has no view"); 1.4471 + return static_cast<nsView*>(value); 1.4472 +} 1.4473 + 1.4474 +/* virtual */ nsView* 1.4475 +nsIFrame::GetViewExternal() const 1.4476 +{ 1.4477 + return GetView(); 1.4478 +} 1.4479 + 1.4480 +nsresult 1.4481 +nsIFrame::SetView(nsView* aView) 1.4482 +{ 1.4483 + if (aView) { 1.4484 + aView->SetFrame(this); 1.4485 + 1.4486 +#ifdef DEBUG 1.4487 + nsIAtom* frameType = GetType(); 1.4488 + NS_ASSERTION(frameType == nsGkAtoms::scrollFrame || 1.4489 + frameType == nsGkAtoms::subDocumentFrame || 1.4490 + frameType == nsGkAtoms::listControlFrame || 1.4491 + frameType == nsGkAtoms::objectFrame || 1.4492 + frameType == nsGkAtoms::viewportFrame || 1.4493 + frameType == nsGkAtoms::menuPopupFrame, 1.4494 + "Only specific frame types can have an nsView"); 1.4495 +#endif 1.4496 + 1.4497 + // Set a property on the frame 1.4498 + Properties().Set(ViewProperty(), aView); 1.4499 + 1.4500 + // Set the frame state bit that says the frame has a view 1.4501 + AddStateBits(NS_FRAME_HAS_VIEW); 1.4502 + 1.4503 + // Let all of the ancestors know they have a descendant with a view. 1.4504 + for (nsIFrame* f = GetParent(); 1.4505 + f && !(f->GetStateBits() & NS_FRAME_HAS_CHILD_WITH_VIEW); 1.4506 + f = f->GetParent()) 1.4507 + f->AddStateBits(NS_FRAME_HAS_CHILD_WITH_VIEW); 1.4508 + } 1.4509 + 1.4510 + return NS_OK; 1.4511 +} 1.4512 + 1.4513 +nsIFrame* nsIFrame::GetAncestorWithViewExternal() const 1.4514 +{ 1.4515 + return GetAncestorWithView(); 1.4516 +} 1.4517 + 1.4518 +// Find the first geometric parent that has a view 1.4519 +nsIFrame* nsIFrame::GetAncestorWithView() const 1.4520 +{ 1.4521 + for (nsIFrame* f = mParent; nullptr != f; f = f->GetParent()) { 1.4522 + if (f->HasView()) { 1.4523 + return f; 1.4524 + } 1.4525 + } 1.4526 + return nullptr; 1.4527 +} 1.4528 + 1.4529 +// virtual 1.4530 +nsPoint nsIFrame::GetOffsetToExternal(const nsIFrame* aOther) const 1.4531 +{ 1.4532 + return GetOffsetTo(aOther); 1.4533 +} 1.4534 + 1.4535 +nsPoint nsIFrame::GetOffsetTo(const nsIFrame* aOther) const 1.4536 +{ 1.4537 + NS_PRECONDITION(aOther, 1.4538 + "Must have frame for destination coordinate system!"); 1.4539 + 1.4540 + NS_ASSERTION(PresContext() == aOther->PresContext(), 1.4541 + "GetOffsetTo called on frames in different documents"); 1.4542 + 1.4543 + nsPoint offset(0, 0); 1.4544 + const nsIFrame* f; 1.4545 + for (f = this; f != aOther && f; f = f->GetParent()) { 1.4546 + offset += f->GetPosition(); 1.4547 + } 1.4548 + 1.4549 + if (f != aOther) { 1.4550 + // Looks like aOther wasn't an ancestor of |this|. So now we have 1.4551 + // the root-frame-relative position of |this| in |offset|. Convert back 1.4552 + // to the coordinates of aOther 1.4553 + while (aOther) { 1.4554 + offset -= aOther->GetPosition(); 1.4555 + aOther = aOther->GetParent(); 1.4556 + } 1.4557 + } 1.4558 + 1.4559 + return offset; 1.4560 +} 1.4561 + 1.4562 +nsPoint nsIFrame::GetOffsetToCrossDoc(const nsIFrame* aOther) const 1.4563 +{ 1.4564 + return GetOffsetToCrossDoc(aOther, PresContext()->AppUnitsPerDevPixel()); 1.4565 +} 1.4566 + 1.4567 +nsPoint 1.4568 +nsIFrame::GetOffsetToCrossDoc(const nsIFrame* aOther, const int32_t aAPD) const 1.4569 +{ 1.4570 + NS_PRECONDITION(aOther, 1.4571 + "Must have frame for destination coordinate system!"); 1.4572 + NS_ASSERTION(PresContext()->GetRootPresContext() == 1.4573 + aOther->PresContext()->GetRootPresContext(), 1.4574 + "trying to get the offset between frames in different document " 1.4575 + "hierarchies?"); 1.4576 + if (PresContext()->GetRootPresContext() != 1.4577 + aOther->PresContext()->GetRootPresContext()) { 1.4578 + // crash right away, we are almost certainly going to crash anyway. 1.4579 + NS_RUNTIMEABORT("trying to get the offset between frames in different " 1.4580 + "document hierarchies?"); 1.4581 + } 1.4582 + 1.4583 + const nsIFrame* root = nullptr; 1.4584 + // offset will hold the final offset 1.4585 + // docOffset holds the currently accumulated offset at the current APD, it 1.4586 + // will be converted and added to offset when the current APD changes. 1.4587 + nsPoint offset(0, 0), docOffset(0, 0); 1.4588 + const nsIFrame* f = this; 1.4589 + int32_t currAPD = PresContext()->AppUnitsPerDevPixel(); 1.4590 + while (f && f != aOther) { 1.4591 + docOffset += f->GetPosition(); 1.4592 + nsIFrame* parent = f->GetParent(); 1.4593 + if (parent) { 1.4594 + f = parent; 1.4595 + } else { 1.4596 + nsPoint newOffset(0, 0); 1.4597 + root = f; 1.4598 + f = nsLayoutUtils::GetCrossDocParentFrame(f, &newOffset); 1.4599 + int32_t newAPD = f ? f->PresContext()->AppUnitsPerDevPixel() : 0; 1.4600 + if (!f || newAPD != currAPD) { 1.4601 + // Convert docOffset to the right APD and add it to offset. 1.4602 + offset += docOffset.ConvertAppUnits(currAPD, aAPD); 1.4603 + docOffset.x = docOffset.y = 0; 1.4604 + } 1.4605 + currAPD = newAPD; 1.4606 + docOffset += newOffset; 1.4607 + } 1.4608 + } 1.4609 + if (f == aOther) { 1.4610 + offset += docOffset.ConvertAppUnits(currAPD, aAPD); 1.4611 + } else { 1.4612 + // Looks like aOther wasn't an ancestor of |this|. So now we have 1.4613 + // the root-document-relative position of |this| in |offset|. Subtract the 1.4614 + // root-document-relative position of |aOther| from |offset|. 1.4615 + // This call won't try to recurse again because root is an ancestor of 1.4616 + // aOther. 1.4617 + nsPoint negOffset = aOther->GetOffsetToCrossDoc(root, aAPD); 1.4618 + offset -= negOffset; 1.4619 + } 1.4620 + 1.4621 + return offset; 1.4622 +} 1.4623 + 1.4624 +// virtual 1.4625 +nsIntRect nsIFrame::GetScreenRectExternal() const 1.4626 +{ 1.4627 + return GetScreenRect(); 1.4628 +} 1.4629 + 1.4630 +nsIntRect nsIFrame::GetScreenRect() const 1.4631 +{ 1.4632 + return GetScreenRectInAppUnits().ToNearestPixels(PresContext()->AppUnitsPerCSSPixel()); 1.4633 +} 1.4634 + 1.4635 +// virtual 1.4636 +nsRect nsIFrame::GetScreenRectInAppUnitsExternal() const 1.4637 +{ 1.4638 + return GetScreenRectInAppUnits(); 1.4639 +} 1.4640 + 1.4641 +nsRect nsIFrame::GetScreenRectInAppUnits() const 1.4642 +{ 1.4643 + nsPresContext* presContext = PresContext(); 1.4644 + nsIFrame* rootFrame = 1.4645 + presContext->PresShell()->FrameManager()->GetRootFrame(); 1.4646 + nsPoint rootScreenPos(0, 0); 1.4647 + nsPoint rootFrameOffsetInParent(0, 0); 1.4648 + nsIFrame* rootFrameParent = 1.4649 + nsLayoutUtils::GetCrossDocParentFrame(rootFrame, &rootFrameOffsetInParent); 1.4650 + if (rootFrameParent) { 1.4651 + nsRect parentScreenRectAppUnits = rootFrameParent->GetScreenRectInAppUnits(); 1.4652 + nsPresContext* parentPresContext = rootFrameParent->PresContext(); 1.4653 + double parentScale = double(presContext->AppUnitsPerDevPixel())/ 1.4654 + parentPresContext->AppUnitsPerDevPixel(); 1.4655 + nsPoint rootPt = parentScreenRectAppUnits.TopLeft() + rootFrameOffsetInParent; 1.4656 + rootScreenPos.x = NS_round(parentScale*rootPt.x); 1.4657 + rootScreenPos.y = NS_round(parentScale*rootPt.y); 1.4658 + } else { 1.4659 + nsCOMPtr<nsIWidget> rootWidget; 1.4660 + presContext->PresShell()->GetViewManager()->GetRootWidget(getter_AddRefs(rootWidget)); 1.4661 + if (rootWidget) { 1.4662 + nsIntPoint rootDevPx = rootWidget->WidgetToScreenOffset(); 1.4663 + rootScreenPos.x = presContext->DevPixelsToAppUnits(rootDevPx.x); 1.4664 + rootScreenPos.y = presContext->DevPixelsToAppUnits(rootDevPx.y); 1.4665 + } 1.4666 + } 1.4667 + 1.4668 + return nsRect(rootScreenPos + GetOffsetTo(rootFrame), GetSize()); 1.4669 +} 1.4670 + 1.4671 +// Returns the offset from this frame to the closest geometric parent that 1.4672 +// has a view. Also returns the containing view or null in case of error 1.4673 +void 1.4674 +nsIFrame::GetOffsetFromView(nsPoint& aOffset, nsView** aView) const 1.4675 +{ 1.4676 + NS_PRECONDITION(nullptr != aView, "null OUT parameter pointer"); 1.4677 + nsIFrame* frame = const_cast<nsIFrame*>(this); 1.4678 + 1.4679 + *aView = nullptr; 1.4680 + aOffset.MoveTo(0, 0); 1.4681 + do { 1.4682 + aOffset += frame->GetPosition(); 1.4683 + frame = frame->GetParent(); 1.4684 + } while (frame && !frame->HasView()); 1.4685 + 1.4686 + if (frame) { 1.4687 + *aView = frame->GetView(); 1.4688 + } 1.4689 +} 1.4690 + 1.4691 +nsIWidget* 1.4692 +nsIFrame::GetNearestWidget() const 1.4693 +{ 1.4694 + return GetClosestView()->GetNearestWidget(nullptr); 1.4695 +} 1.4696 + 1.4697 +nsIWidget* 1.4698 +nsIFrame::GetNearestWidget(nsPoint& aOffset) const 1.4699 +{ 1.4700 + nsPoint offsetToView; 1.4701 + nsPoint offsetToWidget; 1.4702 + nsIWidget* widget = 1.4703 + GetClosestView(&offsetToView)->GetNearestWidget(&offsetToWidget); 1.4704 + aOffset = offsetToView + offsetToWidget; 1.4705 + return widget; 1.4706 +} 1.4707 + 1.4708 +nsIAtom* 1.4709 +nsFrame::GetType() const 1.4710 +{ 1.4711 + return nullptr; 1.4712 +} 1.4713 + 1.4714 +bool 1.4715 +nsIFrame::IsLeaf() const 1.4716 +{ 1.4717 + return true; 1.4718 +} 1.4719 + 1.4720 +gfx3DMatrix 1.4721 +nsIFrame::GetTransformMatrix(const nsIFrame* aStopAtAncestor, 1.4722 + nsIFrame** aOutAncestor) 1.4723 +{ 1.4724 + NS_PRECONDITION(aOutAncestor, "Need a place to put the ancestor!"); 1.4725 + 1.4726 + /* If we're transformed, we want to hand back the combination 1.4727 + * transform/translate matrix that will apply our current transform, then 1.4728 + * shift us to our parent. 1.4729 + */ 1.4730 + if (IsTransformed()) { 1.4731 + /* Compute the delta to the parent, which we need because we are converting 1.4732 + * coordinates to our parent. 1.4733 + */ 1.4734 + NS_ASSERTION(nsLayoutUtils::GetCrossDocParentFrame(this), 1.4735 + "Cannot transform the viewport frame!"); 1.4736 + int32_t scaleFactor = PresContext()->AppUnitsPerDevPixel(); 1.4737 + 1.4738 + gfx3DMatrix result = 1.4739 + nsDisplayTransform::GetResultingTransformMatrix(this, nsPoint(0, 0), scaleFactor, nullptr, aOutAncestor); 1.4740 + // XXXjwatt: seems like this will double count offsets in the face of preserve-3d: 1.4741 + nsPoint delta = GetOffsetToCrossDoc(*aOutAncestor); 1.4742 + /* Combine the raw transform with a translation to our parent. */ 1.4743 + result *= gfx3DMatrix::Translation 1.4744 + (NSAppUnitsToFloatPixels(delta.x, scaleFactor), 1.4745 + NSAppUnitsToFloatPixels(delta.y, scaleFactor), 1.4746 + 0.0f); 1.4747 + return result; 1.4748 + } 1.4749 + 1.4750 + if (nsLayoutUtils::IsPopup(this) && 1.4751 + GetType() == nsGkAtoms::listControlFrame) { 1.4752 + nsPresContext* presContext = PresContext(); 1.4753 + nsIFrame* docRootFrame = presContext->PresShell()->GetRootFrame(); 1.4754 + 1.4755 + // Compute a matrix that transforms from the popup widget to the toplevel 1.4756 + // widget. We use the widgets because they're the simplest and most 1.4757 + // accurate approach --- this should work no matter how the widget position 1.4758 + // was chosen. 1.4759 + nsIWidget* widget = GetView()->GetWidget(); 1.4760 + nsPresContext* rootPresContext = PresContext()->GetRootPresContext(); 1.4761 + // Maybe the widget hasn't been created yet? Popups without widgets are 1.4762 + // treated as regular frames. That should work since they'll be rendered 1.4763 + // as part of the page if they're rendered at all. 1.4764 + if (widget && rootPresContext) { 1.4765 + nsIWidget* toplevel = rootPresContext->GetNearestWidget(); 1.4766 + if (toplevel) { 1.4767 + nsIntRect screenBounds; 1.4768 + widget->GetClientBounds(screenBounds); 1.4769 + nsIntRect toplevelScreenBounds; 1.4770 + toplevel->GetClientBounds(toplevelScreenBounds); 1.4771 + nsIntPoint translation = screenBounds.TopLeft() - toplevelScreenBounds.TopLeft(); 1.4772 + 1.4773 + gfx3DMatrix transformToTop; 1.4774 + transformToTop._41 = translation.x; 1.4775 + transformToTop._42 = translation.y; 1.4776 + 1.4777 + *aOutAncestor = docRootFrame; 1.4778 + gfx3DMatrix docRootTransformToTop = 1.4779 + nsLayoutUtils::GetTransformToAncestor(docRootFrame, nullptr); 1.4780 + if (docRootTransformToTop.IsSingular()) { 1.4781 + NS_WARNING("Containing document is invisible, we can't compute a valid transform"); 1.4782 + } else { 1.4783 + gfx3DMatrix topToDocRootTransform = docRootTransformToTop.Inverse(); 1.4784 + return transformToTop*topToDocRootTransform; 1.4785 + } 1.4786 + } 1.4787 + } 1.4788 + } 1.4789 + 1.4790 + *aOutAncestor = nsLayoutUtils::GetCrossDocParentFrame(this); 1.4791 + 1.4792 + /* Otherwise, we're not transformed. In that case, we'll walk up the frame 1.4793 + * tree until we either hit the root frame or something that may be 1.4794 + * transformed. We'll then change coordinates into that frame, since we're 1.4795 + * guaranteed that nothing in-between can be transformed. First, however, 1.4796 + * we have to check to see if we have a parent. If not, we'll set the 1.4797 + * outparam to null (indicating that there's nothing left) and will hand back 1.4798 + * the identity matrix. 1.4799 + */ 1.4800 + if (!*aOutAncestor) 1.4801 + return gfx3DMatrix(); 1.4802 + 1.4803 + /* Keep iterating while the frame can't possibly be transformed. */ 1.4804 + while (!(*aOutAncestor)->IsTransformed() && 1.4805 + !nsLayoutUtils::IsPopup(*aOutAncestor) && 1.4806 + *aOutAncestor != aStopAtAncestor) { 1.4807 + /* If no parent, stop iterating. Otherwise, update the ancestor. */ 1.4808 + nsIFrame* parent = nsLayoutUtils::GetCrossDocParentFrame(*aOutAncestor); 1.4809 + if (!parent) 1.4810 + break; 1.4811 + 1.4812 + *aOutAncestor = parent; 1.4813 + } 1.4814 + 1.4815 + NS_ASSERTION(*aOutAncestor, "Somehow ended up with a null ancestor...?"); 1.4816 + 1.4817 + /* Translate from this frame to our ancestor, if it exists. That's the 1.4818 + * entire transform, so we're done. 1.4819 + */ 1.4820 + nsPoint delta = GetOffsetToCrossDoc(*aOutAncestor); 1.4821 + int32_t scaleFactor = PresContext()->AppUnitsPerDevPixel(); 1.4822 + return gfx3DMatrix().Translation 1.4823 + (NSAppUnitsToFloatPixels(delta.x, scaleFactor), 1.4824 + NSAppUnitsToFloatPixels(delta.y, scaleFactor), 1.4825 + 0.0f); 1.4826 +} 1.4827 + 1.4828 +static void InvalidateFrameInternal(nsIFrame *aFrame, bool aHasDisplayItem = true) 1.4829 +{ 1.4830 + if (aHasDisplayItem) { 1.4831 + aFrame->AddStateBits(NS_FRAME_NEEDS_PAINT); 1.4832 + } 1.4833 + nsSVGEffects::InvalidateDirectRenderingObservers(aFrame); 1.4834 + bool needsSchedulePaint = false; 1.4835 + if (nsLayoutUtils::IsPopup(aFrame)) { 1.4836 + needsSchedulePaint = true; 1.4837 + } else { 1.4838 + nsIFrame *parent = nsLayoutUtils::GetCrossDocParentFrame(aFrame); 1.4839 + while (parent && !parent->HasAnyStateBits(NS_FRAME_DESCENDANT_NEEDS_PAINT)) { 1.4840 + if (aHasDisplayItem) { 1.4841 + parent->AddStateBits(NS_FRAME_DESCENDANT_NEEDS_PAINT); 1.4842 + } 1.4843 + nsSVGEffects::InvalidateDirectRenderingObservers(parent); 1.4844 + 1.4845 + // If we're inside a popup, then we need to make sure that we 1.4846 + // call schedule paint so that the NS_FRAME_UPDATE_LAYER_TREE 1.4847 + // flag gets added to the popup display root frame. 1.4848 + if (nsLayoutUtils::IsPopup(parent)) { 1.4849 + needsSchedulePaint = true; 1.4850 + break; 1.4851 + } 1.4852 + parent = nsLayoutUtils::GetCrossDocParentFrame(parent); 1.4853 + } 1.4854 + if (!parent) { 1.4855 + needsSchedulePaint = true; 1.4856 + } 1.4857 + } 1.4858 + if (!aHasDisplayItem) { 1.4859 + return; 1.4860 + } 1.4861 + if (needsSchedulePaint) { 1.4862 + aFrame->SchedulePaint(); 1.4863 + } 1.4864 + if (aFrame->HasAnyStateBits(NS_FRAME_HAS_INVALID_RECT)) { 1.4865 + aFrame->Properties().Delete(nsIFrame::InvalidationRect()); 1.4866 + aFrame->RemoveStateBits(NS_FRAME_HAS_INVALID_RECT); 1.4867 + } 1.4868 +} 1.4869 + 1.4870 +void 1.4871 +nsIFrame::InvalidateFrameSubtree(uint32_t aDisplayItemKey) 1.4872 +{ 1.4873 + bool hasDisplayItem = 1.4874 + !aDisplayItemKey || FrameLayerBuilder::HasRetainedDataFor(this, aDisplayItemKey); 1.4875 + InvalidateFrame(aDisplayItemKey); 1.4876 + 1.4877 + if (HasAnyStateBits(NS_FRAME_ALL_DESCENDANTS_NEED_PAINT) || !hasDisplayItem) { 1.4878 + return; 1.4879 + } 1.4880 + 1.4881 + AddStateBits(NS_FRAME_ALL_DESCENDANTS_NEED_PAINT); 1.4882 + 1.4883 + nsAutoTArray<nsIFrame::ChildList,4> childListArray; 1.4884 + GetCrossDocChildLists(&childListArray); 1.4885 + 1.4886 + nsIFrame::ChildListArrayIterator lists(childListArray); 1.4887 + for (; !lists.IsDone(); lists.Next()) { 1.4888 + nsFrameList::Enumerator childFrames(lists.CurrentList()); 1.4889 + for (; !childFrames.AtEnd(); childFrames.Next()) { 1.4890 + childFrames.get()->InvalidateFrameSubtree(); 1.4891 + } 1.4892 + } 1.4893 +} 1.4894 + 1.4895 +void 1.4896 +nsIFrame::ClearInvalidationStateBits() 1.4897 +{ 1.4898 + if (HasAnyStateBits(NS_FRAME_DESCENDANT_NEEDS_PAINT)) { 1.4899 + nsAutoTArray<nsIFrame::ChildList,4> childListArray; 1.4900 + GetCrossDocChildLists(&childListArray); 1.4901 + 1.4902 + nsIFrame::ChildListArrayIterator lists(childListArray); 1.4903 + for (; !lists.IsDone(); lists.Next()) { 1.4904 + nsFrameList::Enumerator childFrames(lists.CurrentList()); 1.4905 + for (; !childFrames.AtEnd(); childFrames.Next()) { 1.4906 + childFrames.get()->ClearInvalidationStateBits(); 1.4907 + } 1.4908 + } 1.4909 + } 1.4910 + 1.4911 + RemoveStateBits(NS_FRAME_NEEDS_PAINT | 1.4912 + NS_FRAME_DESCENDANT_NEEDS_PAINT | 1.4913 + NS_FRAME_ALL_DESCENDANTS_NEED_PAINT); 1.4914 +} 1.4915 + 1.4916 +void 1.4917 +nsIFrame::InvalidateFrame(uint32_t aDisplayItemKey) 1.4918 +{ 1.4919 + bool hasDisplayItem = 1.4920 + !aDisplayItemKey || FrameLayerBuilder::HasRetainedDataFor(this, aDisplayItemKey); 1.4921 + InvalidateFrameInternal(this, hasDisplayItem); 1.4922 +} 1.4923 + 1.4924 +void 1.4925 +nsIFrame::InvalidateFrameWithRect(const nsRect& aRect, uint32_t aDisplayItemKey) 1.4926 +{ 1.4927 + bool hasDisplayItem = 1.4928 + !aDisplayItemKey || FrameLayerBuilder::HasRetainedDataFor(this, aDisplayItemKey); 1.4929 + bool alreadyInvalid = false; 1.4930 + if (!HasAnyStateBits(NS_FRAME_NEEDS_PAINT)) { 1.4931 + InvalidateFrameInternal(this, hasDisplayItem); 1.4932 + } else { 1.4933 + alreadyInvalid = true; 1.4934 + } 1.4935 + 1.4936 + if (!hasDisplayItem) { 1.4937 + return; 1.4938 + } 1.4939 + 1.4940 + nsRect *rect = static_cast<nsRect*>(Properties().Get(InvalidationRect())); 1.4941 + if (!rect) { 1.4942 + if (alreadyInvalid) { 1.4943 + return; 1.4944 + } 1.4945 + rect = new nsRect(); 1.4946 + Properties().Set(InvalidationRect(), rect); 1.4947 + AddStateBits(NS_FRAME_HAS_INVALID_RECT); 1.4948 + } 1.4949 + 1.4950 + *rect = rect->Union(aRect); 1.4951 +} 1.4952 + 1.4953 +/*static*/ uint8_t nsIFrame::sLayerIsPrerenderedDataKey; 1.4954 + 1.4955 +bool 1.4956 +nsIFrame::TryUpdateTransformOnly(Layer** aLayerResult) 1.4957 +{ 1.4958 + Layer* layer = FrameLayerBuilder::GetDedicatedLayer( 1.4959 + this, nsDisplayItem::TYPE_TRANSFORM); 1.4960 + if (!layer || !layer->HasUserData(LayerIsPrerenderedDataKey())) { 1.4961 + // If this layer isn't prerendered or we clip composites to our OS 1.4962 + // window, then we can't correctly optimize to an empty 1.4963 + // transaction in general. 1.4964 + return false; 1.4965 + } 1.4966 + 1.4967 + gfx3DMatrix transform3d; 1.4968 + if (!nsLayoutUtils::GetLayerTransformForFrame(this, &transform3d)) { 1.4969 + // We're not able to compute a layer transform that we know would 1.4970 + // be used at the next layers transaction, so we can't only update 1.4971 + // the transform and will need to schedule an invalidating paint. 1.4972 + return false; 1.4973 + } 1.4974 + gfxMatrix transform; 1.4975 + gfx::Matrix previousTransform; 1.4976 + // FIXME/bug 796690 and 796705: in general, changes to 3D 1.4977 + // transforms, or transform changes to properties other than 1.4978 + // translation, may lead us to choose a different rendering 1.4979 + // resolution for our layer. So if the transform is 3D or has a 1.4980 + // non-translation change, bail and schedule an invalidating paint. 1.4981 + // (We can often do better than this, for example for scale-down 1.4982 + // changes.) 1.4983 + static const gfx::Float kError = 0.0001f; 1.4984 + if (!transform3d.Is2D(&transform) || 1.4985 + !layer->GetBaseTransform().Is2D(&previousTransform) || 1.4986 + !gfx::FuzzyEqual(transform.xx, previousTransform._11, kError) || 1.4987 + !gfx::FuzzyEqual(transform.yy, previousTransform._22, kError) || 1.4988 + !gfx::FuzzyEqual(transform.xy, previousTransform._21, kError) || 1.4989 + !gfx::FuzzyEqual(transform.yx, previousTransform._12, kError)) { 1.4990 + return false; 1.4991 + } 1.4992 + gfx::Matrix4x4 matrix; 1.4993 + gfx::ToMatrix4x4(transform3d, matrix); 1.4994 + layer->SetBaseTransformForNextTransaction(matrix); 1.4995 + *aLayerResult = layer; 1.4996 + return true; 1.4997 +} 1.4998 + 1.4999 +bool 1.5000 +nsIFrame::IsInvalid(nsRect& aRect) 1.5001 +{ 1.5002 + if (!HasAnyStateBits(NS_FRAME_NEEDS_PAINT)) { 1.5003 + return false; 1.5004 + } 1.5005 + 1.5006 + if (HasAnyStateBits(NS_FRAME_HAS_INVALID_RECT)) { 1.5007 + nsRect *rect = static_cast<nsRect*>(Properties().Get(InvalidationRect())); 1.5008 + NS_ASSERTION(rect, "Must have an invalid rect if NS_FRAME_HAS_INVALID_RECT is set!"); 1.5009 + aRect = *rect; 1.5010 + } else { 1.5011 + aRect.SetEmpty(); 1.5012 + } 1.5013 + return true; 1.5014 +} 1.5015 + 1.5016 +void 1.5017 +nsIFrame::SchedulePaint(PaintType aType) 1.5018 +{ 1.5019 + nsIFrame *displayRoot = nsLayoutUtils::GetDisplayRootFrame(this); 1.5020 + nsPresContext *pres = displayRoot->PresContext()->GetRootPresContext(); 1.5021 + 1.5022 + // No need to schedule a paint for an external document since they aren't 1.5023 + // painted directly. 1.5024 + if (!pres || (pres->Document() && pres->Document()->IsResourceDoc())) { 1.5025 + return; 1.5026 + } 1.5027 + if (!pres->GetContainerWeak()) { 1.5028 + NS_WARNING("Shouldn't call SchedulePaint in a detached pres context"); 1.5029 + return; 1.5030 + } 1.5031 + 1.5032 + pres->PresShell()->ScheduleViewManagerFlush(aType == PAINT_DELAYED_COMPRESS ? 1.5033 + nsIPresShell::PAINT_DELAYED_COMPRESS : 1.5034 + nsIPresShell::PAINT_DEFAULT); 1.5035 + 1.5036 + if (aType == PAINT_DELAYED_COMPRESS) { 1.5037 + return; 1.5038 + } 1.5039 + 1.5040 + if (aType == PAINT_DEFAULT) { 1.5041 + displayRoot->AddStateBits(NS_FRAME_UPDATE_LAYER_TREE); 1.5042 + } 1.5043 + nsIPresShell* shell = PresContext()->PresShell(); 1.5044 + if (shell) { 1.5045 + shell->AddInvalidateHiddenPresShellObserver(pres->RefreshDriver()); 1.5046 + } 1.5047 +} 1.5048 + 1.5049 +Layer* 1.5050 +nsIFrame::InvalidateLayer(uint32_t aDisplayItemKey, 1.5051 + const nsIntRect* aDamageRect, 1.5052 + uint32_t aFlags /* = 0 */) 1.5053 +{ 1.5054 + NS_ASSERTION(aDisplayItemKey > 0, "Need a key"); 1.5055 + 1.5056 + Layer* layer = FrameLayerBuilder::GetDedicatedLayer(this, aDisplayItemKey); 1.5057 + 1.5058 + // If the layer is being updated asynchronously, and it's being forwarded 1.5059 + // to a compositor, then we don't need to invalidate. 1.5060 + if ((aFlags & UPDATE_IS_ASYNC) && layer && 1.5061 + layer->Manager()->GetBackendType() == LayersBackend::LAYERS_CLIENT) { 1.5062 + return layer; 1.5063 + } 1.5064 + 1.5065 + if (aDamageRect && aDamageRect->IsEmpty()) { 1.5066 + return layer; 1.5067 + } 1.5068 + 1.5069 + if (!layer) { 1.5070 + // Plugins can transition from not rendering anything to rendering, 1.5071 + // and still only call this. So always invalidate, with specifying 1.5072 + // the display item type just in case. 1.5073 + // 1.5074 + // In the bug 930056, dialer app startup but not shown on the 1.5075 + // screen because sometimes we don't have any retainned data 1.5076 + // for remote type displayitem and thus Repaint event is not 1.5077 + // triggered. So, always invalidate here as well. 1.5078 + if (aDisplayItemKey == nsDisplayItem::TYPE_PLUGIN || 1.5079 + aDisplayItemKey == nsDisplayItem::TYPE_REMOTE) { 1.5080 + InvalidateFrame(); 1.5081 + } else { 1.5082 + InvalidateFrame(aDisplayItemKey); 1.5083 + } 1.5084 + return nullptr; 1.5085 + } 1.5086 + 1.5087 + if (aDamageRect) { 1.5088 + layer->AddInvalidRect(*aDamageRect); 1.5089 + } else { 1.5090 + layer->SetInvalidRectToVisibleRegion(); 1.5091 + } 1.5092 + 1.5093 + SchedulePaint(PAINT_COMPOSITE_ONLY); 1.5094 + return layer; 1.5095 +} 1.5096 + 1.5097 +static nsRect 1.5098 +ComputeEffectsRect(nsIFrame* aFrame, const nsRect& aOverflowRect, 1.5099 + const nsSize& aNewSize) 1.5100 +{ 1.5101 + nsRect r = aOverflowRect; 1.5102 + 1.5103 + if (aFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT) { 1.5104 + // For SVG frames, we only need to account for filters. 1.5105 + // TODO: We could also take account of clipPath and mask to reduce the 1.5106 + // visual overflow, but that's not essential. 1.5107 + if (aFrame->StyleSVGReset()->HasFilters()) { 1.5108 + aFrame->Properties(). 1.5109 + Set(nsIFrame::PreEffectsBBoxProperty(), new nsRect(r)); 1.5110 + r = nsSVGUtils::GetPostFilterVisualOverflowRect(aFrame, aOverflowRect); 1.5111 + } 1.5112 + return r; 1.5113 + } 1.5114 + 1.5115 + // box-shadow 1.5116 + r.UnionRect(r, nsLayoutUtils::GetBoxShadowRectForFrame(aFrame, aNewSize)); 1.5117 + 1.5118 + // border-image-outset. 1.5119 + // We need to include border-image-outset because it can cause the 1.5120 + // border image to be drawn beyond the border box. 1.5121 + 1.5122 + // (1) It's important we not check whether there's a border-image 1.5123 + // since the style hint for a change in border image doesn't cause 1.5124 + // reflow, and that's probably more important than optimizing the 1.5125 + // overflow areas for the silly case of border-image-outset without 1.5126 + // border-image 1.5127 + // (2) It's important that we not check whether the border-image 1.5128 + // is actually loaded, since that would require us to reflow when 1.5129 + // the image loads. 1.5130 + const nsStyleBorder* styleBorder = aFrame->StyleBorder(); 1.5131 + nsMargin outsetMargin = styleBorder->GetImageOutset(); 1.5132 + 1.5133 + if (outsetMargin != nsMargin(0, 0, 0, 0)) { 1.5134 + nsRect outsetRect(nsPoint(0, 0), aNewSize); 1.5135 + outsetRect.Inflate(outsetMargin); 1.5136 + r.UnionRect(r, outsetRect); 1.5137 + } 1.5138 + 1.5139 + // Note that we don't remove the outlineInnerRect if a frame loses outline 1.5140 + // style. That would require an extra property lookup for every frame, 1.5141 + // or a new frame state bit to track whether a property had been stored, 1.5142 + // or something like that. It's not worth doing that here. At most it's 1.5143 + // only one heap-allocated rect per frame and it will be cleaned up when 1.5144 + // the frame dies. 1.5145 + 1.5146 + if (nsSVGIntegrationUtils::UsingEffectsForFrame(aFrame)) { 1.5147 + aFrame->Properties(). 1.5148 + Set(nsIFrame::PreEffectsBBoxProperty(), new nsRect(r)); 1.5149 + r = nsSVGIntegrationUtils::ComputePostEffectsVisualOverflowRect(aFrame, r); 1.5150 + } 1.5151 + 1.5152 + return r; 1.5153 +} 1.5154 + 1.5155 +void 1.5156 +nsIFrame::MovePositionBy(const nsPoint& aTranslation) 1.5157 +{ 1.5158 + nsPoint position = GetNormalPosition() + aTranslation; 1.5159 + 1.5160 + const nsMargin* computedOffsets = nullptr; 1.5161 + if (IsRelativelyPositioned()) { 1.5162 + computedOffsets = static_cast<nsMargin*> 1.5163 + (Properties().Get(nsIFrame::ComputedOffsetProperty())); 1.5164 + } 1.5165 + nsHTMLReflowState::ApplyRelativePositioning(this, computedOffsets ? 1.5166 + *computedOffsets : nsMargin(), 1.5167 + &position); 1.5168 + NS_ASSERTION(StyleDisplay()->mPosition == NS_STYLE_POSITION_STICKY || 1.5169 + GetPosition() + aTranslation == position, 1.5170 + "MovePositionBy should always lead to the movement " 1.5171 + "specified, unless the frame is position:sticky"); 1.5172 + SetPosition(position); 1.5173 +} 1.5174 + 1.5175 +nsPoint 1.5176 +nsIFrame::GetNormalPosition() const 1.5177 +{ 1.5178 + // It might be faster to first check 1.5179 + // StyleDisplay()->IsRelativelyPositionedStyle(). 1.5180 + nsPoint* normalPosition = static_cast<nsPoint*> 1.5181 + (Properties().Get(NormalPositionProperty())); 1.5182 + if (normalPosition) { 1.5183 + return *normalPosition; 1.5184 + } 1.5185 + return GetPosition(); 1.5186 +} 1.5187 + 1.5188 +nsRect 1.5189 +nsIFrame::GetOverflowRect(nsOverflowType aType) const 1.5190 +{ 1.5191 + NS_ABORT_IF_FALSE(aType == eVisualOverflow || aType == eScrollableOverflow, 1.5192 + "unexpected type"); 1.5193 + 1.5194 + // Note that in some cases the overflow area might not have been 1.5195 + // updated (yet) to reflect any outline set on the frame or the area 1.5196 + // of child frames. That's OK because any reflow that updates these 1.5197 + // areas will invalidate the appropriate area, so any (mis)uses of 1.5198 + // this method will be fixed up. 1.5199 + 1.5200 + if (mOverflow.mType == NS_FRAME_OVERFLOW_LARGE) { 1.5201 + // there is an overflow rect, and it's not stored as deltas but as 1.5202 + // a separately-allocated rect 1.5203 + return static_cast<nsOverflowAreas*>(const_cast<nsIFrame*>(this)-> 1.5204 + GetOverflowAreasProperty())->Overflow(aType); 1.5205 + } 1.5206 + 1.5207 + if (aType == eVisualOverflow && 1.5208 + mOverflow.mType != NS_FRAME_OVERFLOW_NONE) { 1.5209 + return GetVisualOverflowFromDeltas(); 1.5210 + } 1.5211 + 1.5212 + return nsRect(nsPoint(0, 0), GetSize()); 1.5213 +} 1.5214 + 1.5215 +nsOverflowAreas 1.5216 +nsIFrame::GetOverflowAreas() const 1.5217 +{ 1.5218 + if (mOverflow.mType == NS_FRAME_OVERFLOW_LARGE) { 1.5219 + // there is an overflow rect, and it's not stored as deltas but as 1.5220 + // a separately-allocated rect 1.5221 + return *const_cast<nsIFrame*>(this)->GetOverflowAreasProperty(); 1.5222 + } 1.5223 + 1.5224 + return nsOverflowAreas(GetVisualOverflowFromDeltas(), 1.5225 + nsRect(nsPoint(0, 0), GetSize())); 1.5226 +} 1.5227 + 1.5228 +nsOverflowAreas 1.5229 +nsIFrame::GetOverflowAreasRelativeToSelf() const 1.5230 +{ 1.5231 + if (IsTransformed()) { 1.5232 + nsOverflowAreas* preTransformOverflows = static_cast<nsOverflowAreas*> 1.5233 + (Properties().Get(PreTransformOverflowAreasProperty())); 1.5234 + if (preTransformOverflows) { 1.5235 + return nsOverflowAreas(preTransformOverflows->VisualOverflow(), 1.5236 + preTransformOverflows->ScrollableOverflow()); 1.5237 + } 1.5238 + } 1.5239 + return nsOverflowAreas(GetVisualOverflowRect(), 1.5240 + GetScrollableOverflowRect()); 1.5241 +} 1.5242 + 1.5243 +nsRect 1.5244 +nsIFrame::GetScrollableOverflowRectRelativeToParent() const 1.5245 +{ 1.5246 + return GetScrollableOverflowRect() + mRect.TopLeft(); 1.5247 +} 1.5248 + 1.5249 +nsRect 1.5250 +nsIFrame::GetScrollableOverflowRectRelativeToSelf() const 1.5251 +{ 1.5252 + if (IsTransformed()) { 1.5253 + nsOverflowAreas* preTransformOverflows = static_cast<nsOverflowAreas*> 1.5254 + (Properties().Get(PreTransformOverflowAreasProperty())); 1.5255 + if (preTransformOverflows) 1.5256 + return preTransformOverflows->ScrollableOverflow(); 1.5257 + } 1.5258 + return GetScrollableOverflowRect(); 1.5259 +} 1.5260 + 1.5261 +nsRect 1.5262 +nsIFrame::GetVisualOverflowRectRelativeToSelf() const 1.5263 +{ 1.5264 + if (IsTransformed()) { 1.5265 + nsOverflowAreas* preTransformOverflows = static_cast<nsOverflowAreas*> 1.5266 + (Properties().Get(PreTransformOverflowAreasProperty())); 1.5267 + if (preTransformOverflows) 1.5268 + return preTransformOverflows->VisualOverflow(); 1.5269 + } 1.5270 + return GetVisualOverflowRect(); 1.5271 +} 1.5272 + 1.5273 +nsRect 1.5274 +nsIFrame::GetPreEffectsVisualOverflowRect() const 1.5275 +{ 1.5276 + nsRect* r = static_cast<nsRect*> 1.5277 + (Properties().Get(nsIFrame::PreEffectsBBoxProperty())); 1.5278 + return r ? *r : GetVisualOverflowRectRelativeToSelf(); 1.5279 +} 1.5280 + 1.5281 +inline static bool 1.5282 +FrameMaintainsOverflow(nsIFrame* aFrame) 1.5283 +{ 1.5284 + return (aFrame->GetStateBits() & 1.5285 + (NS_FRAME_SVG_LAYOUT | NS_FRAME_IS_NONDISPLAY)) != 1.5286 + (NS_FRAME_SVG_LAYOUT | NS_FRAME_IS_NONDISPLAY); 1.5287 +} 1.5288 + 1.5289 +/* virtual */ bool 1.5290 +nsFrame::UpdateOverflow() 1.5291 +{ 1.5292 + MOZ_ASSERT(FrameMaintainsOverflow(this), 1.5293 + "Non-display SVG do not maintain visual overflow rects"); 1.5294 + 1.5295 + nsRect rect(nsPoint(0, 0), GetSize()); 1.5296 + nsOverflowAreas overflowAreas(rect, rect); 1.5297 + 1.5298 + if (!DoesClipChildren() && 1.5299 + !(IsCollapsed() && (IsBoxFrame() || IsBoxWrapped()))) { 1.5300 + nsLayoutUtils::UnionChildOverflow(this, overflowAreas); 1.5301 + } 1.5302 + 1.5303 + if (FinishAndStoreOverflow(overflowAreas, GetSize())) { 1.5304 + nsView* view = GetView(); 1.5305 + if (view) { 1.5306 + uint32_t flags = 0; 1.5307 + GetLayoutFlags(flags); 1.5308 + 1.5309 + if ((flags & NS_FRAME_NO_SIZE_VIEW) == 0) { 1.5310 + // Make sure the frame's view is properly sized. 1.5311 + nsViewManager* vm = view->GetViewManager(); 1.5312 + vm->ResizeView(view, overflowAreas.VisualOverflow(), true); 1.5313 + } 1.5314 + } 1.5315 + 1.5316 + return true; 1.5317 + } 1.5318 + 1.5319 + return false; 1.5320 +} 1.5321 + 1.5322 +// Define the MAX_FRAME_DEPTH to be the ContentSink's MAX_REFLOW_DEPTH plus 1.5323 +// 4 for the frames above the document's frames: 1.5324 +// the Viewport, GFXScroll, ScrollPort, and Canvas 1.5325 +#define MAX_FRAME_DEPTH (MAX_REFLOW_DEPTH+4) 1.5326 + 1.5327 +bool 1.5328 +nsFrame::IsFrameTreeTooDeep(const nsHTMLReflowState& aReflowState, 1.5329 + nsHTMLReflowMetrics& aMetrics, 1.5330 + nsReflowStatus& aStatus) 1.5331 +{ 1.5332 + if (aReflowState.mReflowDepth > MAX_FRAME_DEPTH) { 1.5333 + NS_WARNING("frame tree too deep; setting zero size and returning"); 1.5334 + mState |= NS_FRAME_TOO_DEEP_IN_FRAME_TREE; 1.5335 + ClearOverflowRects(); 1.5336 + aMetrics.Width() = 0; 1.5337 + aMetrics.Height() = 0; 1.5338 + aMetrics.SetTopAscent(0); 1.5339 + aMetrics.mCarriedOutBottomMargin.Zero(); 1.5340 + aMetrics.mOverflowAreas.Clear(); 1.5341 + 1.5342 + if (GetNextInFlow()) { 1.5343 + // Reflow depth might vary between reflows, so we might have 1.5344 + // successfully reflowed and split this frame before. If so, we 1.5345 + // shouldn't delete its continuations. 1.5346 + aStatus = NS_FRAME_NOT_COMPLETE; 1.5347 + } else { 1.5348 + aStatus = NS_FRAME_COMPLETE; 1.5349 + } 1.5350 + 1.5351 + return true; 1.5352 + } 1.5353 + mState &= ~NS_FRAME_TOO_DEEP_IN_FRAME_TREE; 1.5354 + return false; 1.5355 +} 1.5356 + 1.5357 +bool 1.5358 +nsIFrame::IsBlockWrapper() const 1.5359 +{ 1.5360 + nsIAtom *pseudoType = StyleContext()->GetPseudo(); 1.5361 + return (pseudoType == nsCSSAnonBoxes::mozAnonymousBlock || 1.5362 + pseudoType == nsCSSAnonBoxes::mozAnonymousPositionedBlock || 1.5363 + pseudoType == nsCSSAnonBoxes::buttonContent || 1.5364 + pseudoType == nsCSSAnonBoxes::cellContent); 1.5365 +} 1.5366 + 1.5367 +static nsIFrame* 1.5368 +GetNearestBlockContainer(nsIFrame* frame) 1.5369 +{ 1.5370 + // The block wrappers we use to wrap blocks inside inlines aren't 1.5371 + // described in the CSS spec. We need to make them not be containing 1.5372 + // blocks. 1.5373 + // Since the parent of such a block is either a normal block or 1.5374 + // another such pseudo, this shouldn't cause anything bad to happen. 1.5375 + // Also the anonymous blocks inside table cells are not containing blocks. 1.5376 + while (frame->IsFrameOfType(nsIFrame::eLineParticipant) || 1.5377 + frame->IsBlockWrapper() || 1.5378 + // Table rows are not containing blocks either 1.5379 + frame->GetType() == nsGkAtoms::tableRowFrame) { 1.5380 + frame = frame->GetParent(); 1.5381 + NS_ASSERTION(frame, "How come we got to the root frame without seeing a containing block?"); 1.5382 + } 1.5383 + return frame; 1.5384 +} 1.5385 + 1.5386 +nsIFrame* 1.5387 +nsIFrame::GetContainingBlock() const 1.5388 +{ 1.5389 + // MathML frames might have absolute positioning style, but they would 1.5390 + // still be in-flow. So we have to check to make sure that the frame 1.5391 + // is really out-of-flow too. 1.5392 + if (IsAbsolutelyPositioned() && 1.5393 + (GetStateBits() & NS_FRAME_OUT_OF_FLOW)) { 1.5394 + return GetParent(); // the parent is always the containing block 1.5395 + } 1.5396 + return GetNearestBlockContainer(GetParent()); 1.5397 +} 1.5398 + 1.5399 +#ifdef DEBUG_FRAME_DUMP 1.5400 + 1.5401 +int32_t nsFrame::ContentIndexInContainer(const nsIFrame* aFrame) 1.5402 +{ 1.5403 + int32_t result = -1; 1.5404 + 1.5405 + nsIContent* content = aFrame->GetContent(); 1.5406 + if (content) { 1.5407 + nsIContent* parentContent = content->GetParent(); 1.5408 + if (parentContent) { 1.5409 + result = parentContent->IndexOf(content); 1.5410 + } 1.5411 + } 1.5412 + 1.5413 + return result; 1.5414 +} 1.5415 + 1.5416 +/** 1.5417 + * List a frame tree to stderr. Meant to be called from gdb. 1.5418 + */ 1.5419 +void 1.5420 +DebugListFrameTree(nsIFrame* aFrame) 1.5421 +{ 1.5422 + ((nsFrame*)aFrame)->List(stderr); 1.5423 +} 1.5424 + 1.5425 +void 1.5426 +nsIFrame::ListTag(nsACString& aTo) const 1.5427 +{ 1.5428 + ListTag(aTo, this); 1.5429 +} 1.5430 + 1.5431 +/* static */ 1.5432 +void 1.5433 +nsIFrame::ListTag(nsACString& aTo, const nsIFrame* aFrame) { 1.5434 + nsAutoString tmp; 1.5435 + aFrame->GetFrameName(tmp); 1.5436 + aTo += NS_ConvertUTF16toUTF8(tmp).get(); 1.5437 + aTo += nsPrintfCString("@%p", static_cast<const void*>(aFrame)); 1.5438 +} 1.5439 + 1.5440 +// Debugging 1.5441 +void 1.5442 +nsIFrame::ListGeneric(nsACString& aTo, const char* aPrefix, uint32_t aFlags) const 1.5443 +{ 1.5444 + aTo =+ aPrefix; 1.5445 + ListTag(aTo); 1.5446 + if (HasView()) { 1.5447 + aTo += nsPrintfCString(" [view=%p]", static_cast<void*>(GetView())); 1.5448 + } 1.5449 + if (GetNextSibling()) { 1.5450 + aTo += nsPrintfCString(" next=%p", static_cast<void*>(GetNextSibling())); 1.5451 + } 1.5452 + if (GetPrevContinuation()) { 1.5453 + bool fluid = GetPrevInFlow() == GetPrevContinuation(); 1.5454 + aTo += nsPrintfCString(" prev-%s=%p", fluid?"in-flow":"continuation", 1.5455 + static_cast<void*>(GetPrevContinuation())); 1.5456 + } 1.5457 + if (GetNextContinuation()) { 1.5458 + bool fluid = GetNextInFlow() == GetNextContinuation(); 1.5459 + aTo += nsPrintfCString(" next-%s=%p", fluid?"in-flow":"continuation", 1.5460 + static_cast<void*>(GetNextContinuation())); 1.5461 + } 1.5462 + void* IBsibling = Properties().Get(IBSplitSibling()); 1.5463 + if (IBsibling) { 1.5464 + aTo += nsPrintfCString(" IBSplitSibling=%p", IBsibling); 1.5465 + } 1.5466 + void* IBprevsibling = Properties().Get(IBSplitPrevSibling()); 1.5467 + if (IBprevsibling) { 1.5468 + aTo += nsPrintfCString(" IBSplitPrevSibling=%p", IBprevsibling); 1.5469 + } 1.5470 + aTo += nsPrintfCString(" {%d,%d,%d,%d}", mRect.x, mRect.y, mRect.width, mRect.height); 1.5471 + nsIFrame* f = const_cast<nsIFrame*>(this); 1.5472 + if (f->HasOverflowAreas()) { 1.5473 + nsRect vo = f->GetVisualOverflowRect(); 1.5474 + if (!vo.IsEqualEdges(mRect)) { 1.5475 + aTo += nsPrintfCString(" vis-overflow=%d,%d,%d,%d", vo.x, vo.y, vo.width, vo.height); 1.5476 + } 1.5477 + nsRect so = f->GetScrollableOverflowRect(); 1.5478 + if (!so.IsEqualEdges(mRect)) { 1.5479 + aTo += nsPrintfCString(" scr-overflow=%d,%d,%d,%d", so.x, so.y, so.width, so.height); 1.5480 + } 1.5481 + } 1.5482 + if (0 != mState) { 1.5483 + aTo += nsPrintfCString(" [state=%016llx]", (unsigned long long)mState); 1.5484 + } 1.5485 + if (IsTransformed()) { 1.5486 + aTo += nsPrintfCString(" transformed"); 1.5487 + } 1.5488 + if (ChildrenHavePerspective()) { 1.5489 + aTo += nsPrintfCString(" perspective"); 1.5490 + } 1.5491 + if (Preserves3DChildren()) { 1.5492 + aTo += nsPrintfCString(" preserves-3d-children"); 1.5493 + } 1.5494 + if (Preserves3D()) { 1.5495 + aTo += nsPrintfCString(" preserves-3d"); 1.5496 + } 1.5497 + if (mContent) { 1.5498 + aTo += nsPrintfCString(" [content=%p]", static_cast<void*>(mContent)); 1.5499 + } 1.5500 + aTo += nsPrintfCString(" [sc=%p", static_cast<void*>(mStyleContext)); 1.5501 + if (mStyleContext) { 1.5502 + nsIAtom* pseudoTag = mStyleContext->GetPseudo(); 1.5503 + if (pseudoTag) { 1.5504 + nsAutoString atomString; 1.5505 + pseudoTag->ToString(atomString); 1.5506 + aTo += nsPrintfCString("%s", NS_LossyConvertUTF16toASCII(atomString).get()); 1.5507 + } 1.5508 + if (mParent && mStyleContext->GetParent() != mParent->StyleContext()) { 1.5509 + aTo += nsPrintfCString(",parent=%p", mStyleContext->GetParent()); 1.5510 + } 1.5511 + } 1.5512 + aTo += "]"; 1.5513 +} 1.5514 + 1.5515 +void 1.5516 +nsIFrame::List(FILE* out, const char* aPrefix, uint32_t aFlags) const 1.5517 +{ 1.5518 + nsCString str; 1.5519 + ListGeneric(str, aPrefix, aFlags); 1.5520 + fprintf_stderr(out, "%s\n", str.get()); 1.5521 +} 1.5522 + 1.5523 +nsresult 1.5524 +nsFrame::GetFrameName(nsAString& aResult) const 1.5525 +{ 1.5526 + return MakeFrameName(NS_LITERAL_STRING("Frame"), aResult); 1.5527 +} 1.5528 + 1.5529 +nsresult 1.5530 +nsFrame::MakeFrameName(const nsAString& aType, nsAString& aResult) const 1.5531 +{ 1.5532 + aResult = aType; 1.5533 + if (mContent && !mContent->IsNodeOfType(nsINode::eTEXT)) { 1.5534 + nsAutoString buf; 1.5535 + mContent->Tag()->ToString(buf); 1.5536 + if (GetType() == nsGkAtoms::subDocumentFrame) { 1.5537 + nsAutoString src; 1.5538 + mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::src, src); 1.5539 + buf.Append(NS_LITERAL_STRING(" src=") + src); 1.5540 + } 1.5541 + aResult.Append(NS_LITERAL_STRING("(") + buf + NS_LITERAL_STRING(")")); 1.5542 + } 1.5543 + char buf[40]; 1.5544 + PR_snprintf(buf, sizeof(buf), "(%d)", ContentIndexInContainer(this)); 1.5545 + AppendASCIItoUTF16(buf, aResult); 1.5546 + return NS_OK; 1.5547 +} 1.5548 + 1.5549 +void 1.5550 +nsIFrame::DumpFrameTree() 1.5551 +{ 1.5552 + RootFrameList(PresContext(), stderr); 1.5553 +} 1.5554 + 1.5555 +void 1.5556 +nsIFrame::DumpFrameTreeLimited() 1.5557 +{ 1.5558 + List(stderr); 1.5559 +} 1.5560 + 1.5561 +void 1.5562 +nsIFrame::RootFrameList(nsPresContext* aPresContext, FILE* out, const char* aPrefix) 1.5563 +{ 1.5564 + if (!aPresContext || !out) 1.5565 + return; 1.5566 + 1.5567 + nsIPresShell *shell = aPresContext->GetPresShell(); 1.5568 + if (shell) { 1.5569 + nsIFrame* frame = shell->FrameManager()->GetRootFrame(); 1.5570 + if(frame) { 1.5571 + frame->List(out, aPrefix); 1.5572 + } 1.5573 + } 1.5574 +} 1.5575 +#endif 1.5576 + 1.5577 +#ifdef DEBUG 1.5578 +nsFrameState 1.5579 +nsFrame::GetDebugStateBits() const 1.5580 +{ 1.5581 + // We'll ignore these flags for the purposes of comparing frame state: 1.5582 + // 1.5583 + // NS_FRAME_EXTERNAL_REFERENCE 1.5584 + // because this is set by the event state manager or the 1.5585 + // caret code when a frame is focused. Depending on whether 1.5586 + // or not the regression tests are run as the focused window 1.5587 + // will make this value vary randomly. 1.5588 +#define IRRELEVANT_FRAME_STATE_FLAGS NS_FRAME_EXTERNAL_REFERENCE 1.5589 + 1.5590 +#define FRAME_STATE_MASK (~(IRRELEVANT_FRAME_STATE_FLAGS)) 1.5591 + 1.5592 + return GetStateBits() & FRAME_STATE_MASK; 1.5593 +} 1.5594 + 1.5595 +void 1.5596 +nsFrame::XMLQuote(nsString& aString) 1.5597 +{ 1.5598 + int32_t i, len = aString.Length(); 1.5599 + for (i = 0; i < len; i++) { 1.5600 + char16_t ch = aString.CharAt(i); 1.5601 + if (ch == '<') { 1.5602 + nsAutoString tmp(NS_LITERAL_STRING("<")); 1.5603 + aString.Cut(i, 1); 1.5604 + aString.Insert(tmp, i); 1.5605 + len += 3; 1.5606 + i += 3; 1.5607 + } 1.5608 + else if (ch == '>') { 1.5609 + nsAutoString tmp(NS_LITERAL_STRING(">")); 1.5610 + aString.Cut(i, 1); 1.5611 + aString.Insert(tmp, i); 1.5612 + len += 3; 1.5613 + i += 3; 1.5614 + } 1.5615 + else if (ch == '\"') { 1.5616 + nsAutoString tmp(NS_LITERAL_STRING(""")); 1.5617 + aString.Cut(i, 1); 1.5618 + aString.Insert(tmp, i); 1.5619 + len += 5; 1.5620 + i += 5; 1.5621 + } 1.5622 + } 1.5623 +} 1.5624 +#endif 1.5625 + 1.5626 +bool 1.5627 +nsIFrame::IsVisibleForPainting(nsDisplayListBuilder* aBuilder) { 1.5628 + if (!StyleVisibility()->IsVisible()) 1.5629 + return false; 1.5630 + nsISelection* sel = aBuilder->GetBoundingSelection(); 1.5631 + return !sel || IsVisibleInSelection(sel); 1.5632 +} 1.5633 + 1.5634 +bool 1.5635 +nsIFrame::IsVisibleForPainting() { 1.5636 + if (!StyleVisibility()->IsVisible()) 1.5637 + return false; 1.5638 + 1.5639 + nsPresContext* pc = PresContext(); 1.5640 + if (!pc->IsRenderingOnlySelection()) 1.5641 + return true; 1.5642 + 1.5643 + nsCOMPtr<nsISelectionController> selcon(do_QueryInterface(pc->PresShell())); 1.5644 + if (selcon) { 1.5645 + nsCOMPtr<nsISelection> sel; 1.5646 + selcon->GetSelection(nsISelectionController::SELECTION_NORMAL, 1.5647 + getter_AddRefs(sel)); 1.5648 + if (sel) 1.5649 + return IsVisibleInSelection(sel); 1.5650 + } 1.5651 + return true; 1.5652 +} 1.5653 + 1.5654 +bool 1.5655 +nsIFrame::IsVisibleInSelection(nsDisplayListBuilder* aBuilder) { 1.5656 + nsISelection* sel = aBuilder->GetBoundingSelection(); 1.5657 + return !sel || IsVisibleInSelection(sel); 1.5658 +} 1.5659 + 1.5660 +bool 1.5661 +nsIFrame::IsVisibleOrCollapsedForPainting(nsDisplayListBuilder* aBuilder) { 1.5662 + if (!StyleVisibility()->IsVisibleOrCollapsed()) 1.5663 + return false; 1.5664 + nsISelection* sel = aBuilder->GetBoundingSelection(); 1.5665 + return !sel || IsVisibleInSelection(sel); 1.5666 +} 1.5667 + 1.5668 +bool 1.5669 +nsIFrame::IsVisibleInSelection(nsISelection* aSelection) 1.5670 +{ 1.5671 + if (!GetContent() || !GetContent()->IsSelectionDescendant()) { 1.5672 + return false; 1.5673 + } 1.5674 + 1.5675 + nsCOMPtr<nsIDOMNode> node(do_QueryInterface(mContent)); 1.5676 + bool vis; 1.5677 + nsresult rv = aSelection->ContainsNode(node, true, &vis); 1.5678 + return NS_FAILED(rv) || vis; 1.5679 +} 1.5680 + 1.5681 +/* virtual */ bool 1.5682 +nsFrame::IsEmpty() 1.5683 +{ 1.5684 + return false; 1.5685 +} 1.5686 + 1.5687 +bool 1.5688 +nsIFrame::CachedIsEmpty() 1.5689 +{ 1.5690 + NS_PRECONDITION(!(GetStateBits() & NS_FRAME_IS_DIRTY), 1.5691 + "Must only be called on reflowed lines"); 1.5692 + return IsEmpty(); 1.5693 +} 1.5694 + 1.5695 +/* virtual */ bool 1.5696 +nsFrame::IsSelfEmpty() 1.5697 +{ 1.5698 + return false; 1.5699 +} 1.5700 + 1.5701 +nsresult 1.5702 +nsFrame::GetSelectionController(nsPresContext *aPresContext, nsISelectionController **aSelCon) 1.5703 +{ 1.5704 + if (!aPresContext || !aSelCon) 1.5705 + return NS_ERROR_INVALID_ARG; 1.5706 + 1.5707 + nsIFrame *frame = this; 1.5708 + while (frame && (frame->GetStateBits() & NS_FRAME_INDEPENDENT_SELECTION)) { 1.5709 + nsITextControlFrame *tcf = do_QueryFrame(frame); 1.5710 + if (tcf) { 1.5711 + return tcf->GetOwnedSelectionController(aSelCon); 1.5712 + } 1.5713 + frame = frame->GetParent(); 1.5714 + } 1.5715 + 1.5716 + return CallQueryInterface(aPresContext->GetPresShell(), aSelCon); 1.5717 +} 1.5718 + 1.5719 +already_AddRefed<nsFrameSelection> 1.5720 +nsIFrame::GetFrameSelection() 1.5721 +{ 1.5722 + nsRefPtr<nsFrameSelection> fs = 1.5723 + const_cast<nsFrameSelection*>(GetConstFrameSelection()); 1.5724 + return fs.forget(); 1.5725 +} 1.5726 + 1.5727 +const nsFrameSelection* 1.5728 +nsIFrame::GetConstFrameSelection() const 1.5729 +{ 1.5730 + nsIFrame* frame = const_cast<nsIFrame*>(this); 1.5731 + while (frame && (frame->GetStateBits() & NS_FRAME_INDEPENDENT_SELECTION)) { 1.5732 + nsITextControlFrame* tcf = do_QueryFrame(frame); 1.5733 + if (tcf) { 1.5734 + return tcf->GetOwnedFrameSelection(); 1.5735 + } 1.5736 + frame = frame->GetParent(); 1.5737 + } 1.5738 + 1.5739 + return PresContext()->PresShell()->ConstFrameSelection(); 1.5740 +} 1.5741 + 1.5742 +#ifdef DEBUG 1.5743 +nsresult 1.5744 +nsFrame::DumpRegressionData(nsPresContext* aPresContext, FILE* out, int32_t aIndent) 1.5745 +{ 1.5746 + IndentBy(out, aIndent); 1.5747 + fprintf(out, "<frame va=\"%p\" type=\"", (void*)this); 1.5748 + nsAutoString name; 1.5749 + GetFrameName(name); 1.5750 + XMLQuote(name); 1.5751 + fputs(NS_LossyConvertUTF16toASCII(name).get(), out); 1.5752 + fprintf(out, "\" state=\"%016llx\" parent=\"%p\">\n", 1.5753 + (unsigned long long)GetDebugStateBits(), (void*)mParent); 1.5754 + 1.5755 + aIndent++; 1.5756 + DumpBaseRegressionData(aPresContext, out, aIndent); 1.5757 + aIndent--; 1.5758 + 1.5759 + IndentBy(out, aIndent); 1.5760 + fprintf(out, "</frame>\n"); 1.5761 + 1.5762 + return NS_OK; 1.5763 +} 1.5764 + 1.5765 +void 1.5766 +nsFrame::DumpBaseRegressionData(nsPresContext* aPresContext, FILE* out, int32_t aIndent) 1.5767 +{ 1.5768 + if (GetNextSibling()) { 1.5769 + IndentBy(out, aIndent); 1.5770 + fprintf(out, "<next-sibling va=\"%p\"/>\n", (void*)GetNextSibling()); 1.5771 + } 1.5772 + 1.5773 + if (HasView()) { 1.5774 + IndentBy(out, aIndent); 1.5775 + fprintf(out, "<view va=\"%p\">\n", (void*)GetView()); 1.5776 + aIndent++; 1.5777 + // XXX add in code to dump out view state too... 1.5778 + aIndent--; 1.5779 + IndentBy(out, aIndent); 1.5780 + fprintf(out, "</view>\n"); 1.5781 + } 1.5782 + 1.5783 + IndentBy(out, aIndent); 1.5784 + fprintf(out, "<bbox x=\"%d\" y=\"%d\" w=\"%d\" h=\"%d\"/>\n", 1.5785 + mRect.x, mRect.y, mRect.width, mRect.height); 1.5786 + 1.5787 + // Now dump all of the children on all of the child lists 1.5788 + ChildListIterator lists(this); 1.5789 + for (; !lists.IsDone(); lists.Next()) { 1.5790 + IndentBy(out, aIndent); 1.5791 + if (lists.CurrentID() != kPrincipalList) { 1.5792 + fprintf(out, "<child-list name=\"%s\">\n", mozilla::layout::ChildListName(lists.CurrentID())); 1.5793 + } 1.5794 + else { 1.5795 + fprintf(out, "<child-list>\n"); 1.5796 + } 1.5797 + aIndent++; 1.5798 + nsFrameList::Enumerator childFrames(lists.CurrentList()); 1.5799 + for (; !childFrames.AtEnd(); childFrames.Next()) { 1.5800 + nsIFrame* kid = childFrames.get(); 1.5801 + kid->DumpRegressionData(aPresContext, out, aIndent); 1.5802 + } 1.5803 + aIndent--; 1.5804 + IndentBy(out, aIndent); 1.5805 + fprintf(out, "</child-list>\n"); 1.5806 + } 1.5807 +} 1.5808 +#endif 1.5809 + 1.5810 +bool 1.5811 +nsIFrame::IsFrameSelected() const 1.5812 +{ 1.5813 + NS_ASSERTION(!GetContent() || GetContent()->IsSelectionDescendant(), 1.5814 + "use the public IsSelected() instead"); 1.5815 + return nsRange::IsNodeSelected(GetContent(), 0, 1.5816 + GetContent()->GetChildCount()); 1.5817 +} 1.5818 + 1.5819 +nsresult 1.5820 +nsFrame::GetPointFromOffset(int32_t inOffset, nsPoint* outPoint) 1.5821 +{ 1.5822 + NS_PRECONDITION(outPoint != nullptr, "Null parameter"); 1.5823 + nsRect contentRect = GetContentRect() - GetPosition(); 1.5824 + nsPoint pt = contentRect.TopLeft(); 1.5825 + if (mContent) 1.5826 + { 1.5827 + nsIContent* newContent = mContent->GetParent(); 1.5828 + if (newContent){ 1.5829 + int32_t newOffset = newContent->IndexOf(mContent); 1.5830 + 1.5831 + bool isRTL = (NS_GET_EMBEDDING_LEVEL(this) & 1) == 1; 1.5832 + if ((!isRTL && inOffset > newOffset) || 1.5833 + (isRTL && inOffset <= newOffset)) { 1.5834 + pt = contentRect.TopRight(); 1.5835 + } 1.5836 + } 1.5837 + } 1.5838 + *outPoint = pt; 1.5839 + return NS_OK; 1.5840 +} 1.5841 + 1.5842 +nsresult 1.5843 +nsFrame::GetChildFrameContainingOffset(int32_t inContentOffset, bool inHint, int32_t* outFrameContentOffset, nsIFrame **outChildFrame) 1.5844 +{ 1.5845 + NS_PRECONDITION(outChildFrame && outFrameContentOffset, "Null parameter"); 1.5846 + *outFrameContentOffset = (int32_t)inHint; 1.5847 + //the best frame to reflect any given offset would be a visible frame if possible 1.5848 + //i.e. we are looking for a valid frame to place the blinking caret 1.5849 + nsRect rect = GetRect(); 1.5850 + if (!rect.width || !rect.height) 1.5851 + { 1.5852 + //if we have a 0 width or height then lets look for another frame that possibly has 1.5853 + //the same content. If we have no frames in flow then just let us return 'this' frame 1.5854 + nsIFrame* nextFlow = GetNextInFlow(); 1.5855 + if (nextFlow) 1.5856 + return nextFlow->GetChildFrameContainingOffset(inContentOffset, inHint, outFrameContentOffset, outChildFrame); 1.5857 + } 1.5858 + *outChildFrame = this; 1.5859 + return NS_OK; 1.5860 +} 1.5861 + 1.5862 +// 1.5863 +// What I've pieced together about this routine: 1.5864 +// Starting with a block frame (from which a line frame can be gotten) 1.5865 +// and a line number, drill down and get the first/last selectable 1.5866 +// frame on that line, depending on aPos->mDirection. 1.5867 +// aOutSideLimit != 0 means ignore aLineStart, instead work from 1.5868 +// the end (if > 0) or beginning (if < 0). 1.5869 +// 1.5870 +nsresult 1.5871 +nsFrame::GetNextPrevLineFromeBlockFrame(nsPresContext* aPresContext, 1.5872 + nsPeekOffsetStruct *aPos, 1.5873 + nsIFrame *aBlockFrame, 1.5874 + int32_t aLineStart, 1.5875 + int8_t aOutSideLimit 1.5876 + ) 1.5877 +{ 1.5878 + //magic numbers aLineStart will be -1 for end of block 0 will be start of block 1.5879 + if (!aBlockFrame || !aPos) 1.5880 + return NS_ERROR_NULL_POINTER; 1.5881 + 1.5882 + aPos->mResultFrame = nullptr; 1.5883 + aPos->mResultContent = nullptr; 1.5884 + aPos->mAttachForward = (aPos->mDirection == eDirNext); 1.5885 + 1.5886 + nsAutoLineIterator it = aBlockFrame->GetLineIterator(); 1.5887 + if (!it) 1.5888 + return NS_ERROR_FAILURE; 1.5889 + int32_t searchingLine = aLineStart; 1.5890 + int32_t countLines = it->GetNumLines(); 1.5891 + if (aOutSideLimit > 0) //start at end 1.5892 + searchingLine = countLines; 1.5893 + else if (aOutSideLimit <0)//start at beginning 1.5894 + searchingLine = -1;//"next" will be 0 1.5895 + else 1.5896 + if ((aPos->mDirection == eDirPrevious && searchingLine == 0) || 1.5897 + (aPos->mDirection == eDirNext && searchingLine >= (countLines -1) )){ 1.5898 + //we need to jump to new block frame. 1.5899 + return NS_ERROR_FAILURE; 1.5900 + } 1.5901 + int32_t lineFrameCount; 1.5902 + nsIFrame *resultFrame = nullptr; 1.5903 + nsIFrame *farStoppingFrame = nullptr; //we keep searching until we find a "this" frame then we go to next line 1.5904 + nsIFrame *nearStoppingFrame = nullptr; //if we are backing up from edge, stop here 1.5905 + nsIFrame *firstFrame; 1.5906 + nsIFrame *lastFrame; 1.5907 + nsRect rect; 1.5908 + bool isBeforeFirstFrame, isAfterLastFrame; 1.5909 + bool found = false; 1.5910 + 1.5911 + nsresult result = NS_OK; 1.5912 + while (!found) 1.5913 + { 1.5914 + if (aPos->mDirection == eDirPrevious) 1.5915 + searchingLine --; 1.5916 + else 1.5917 + searchingLine ++; 1.5918 + if ((aPos->mDirection == eDirPrevious && searchingLine < 0) || 1.5919 + (aPos->mDirection == eDirNext && searchingLine >= countLines )) 1.5920 + { 1.5921 + //we need to jump to new block frame. 1.5922 + return NS_ERROR_FAILURE; 1.5923 + } 1.5924 + uint32_t lineFlags; 1.5925 + result = it->GetLine(searchingLine, &firstFrame, &lineFrameCount, 1.5926 + rect, &lineFlags); 1.5927 + if (!lineFrameCount) 1.5928 + continue; 1.5929 + if (NS_SUCCEEDED(result)){ 1.5930 + lastFrame = firstFrame; 1.5931 + for (;lineFrameCount > 1;lineFrameCount --){ 1.5932 + //result = lastFrame->GetNextSibling(&lastFrame, searchingLine); 1.5933 + result = it->GetNextSiblingOnLine(lastFrame, searchingLine); 1.5934 + if (NS_FAILED(result) || !lastFrame){ 1.5935 + NS_ERROR("GetLine promised more frames than could be found"); 1.5936 + return NS_ERROR_FAILURE; 1.5937 + } 1.5938 + } 1.5939 + GetLastLeaf(aPresContext, &lastFrame); 1.5940 + 1.5941 + if (aPos->mDirection == eDirNext){ 1.5942 + nearStoppingFrame = firstFrame; 1.5943 + farStoppingFrame = lastFrame; 1.5944 + } 1.5945 + else{ 1.5946 + nearStoppingFrame = lastFrame; 1.5947 + farStoppingFrame = firstFrame; 1.5948 + } 1.5949 + nsPoint offset; 1.5950 + nsView * view; //used for call of get offset from view 1.5951 + aBlockFrame->GetOffsetFromView(offset,&view); 1.5952 + nscoord newDesiredX = aPos->mDesiredX - offset.x;//get desired x into blockframe coordinates! 1.5953 + result = it->FindFrameAt(searchingLine, newDesiredX, &resultFrame, &isBeforeFirstFrame, &isAfterLastFrame); 1.5954 + if(NS_FAILED(result)) 1.5955 + continue; 1.5956 + } 1.5957 + 1.5958 + if (NS_SUCCEEDED(result) && resultFrame) 1.5959 + { 1.5960 + //check to see if this is ANOTHER blockframe inside the other one if so then call into its lines 1.5961 + nsAutoLineIterator newIt = resultFrame->GetLineIterator(); 1.5962 + if (newIt) 1.5963 + { 1.5964 + aPos->mResultFrame = resultFrame; 1.5965 + return NS_OK; 1.5966 + } 1.5967 + //resultFrame is not a block frame 1.5968 + result = NS_ERROR_FAILURE; 1.5969 + 1.5970 + nsCOMPtr<nsIFrameEnumerator> frameTraversal; 1.5971 + result = NS_NewFrameTraversal(getter_AddRefs(frameTraversal), 1.5972 + aPresContext, resultFrame, 1.5973 + ePostOrder, 1.5974 + false, // aVisual 1.5975 + aPos->mScrollViewStop, 1.5976 + false // aFollowOOFs 1.5977 + ); 1.5978 + if (NS_FAILED(result)) 1.5979 + return result; 1.5980 + 1.5981 + nsIFrame *storeOldResultFrame = resultFrame; 1.5982 + while ( !found ){ 1.5983 + nsPoint point; 1.5984 + point.x = aPos->mDesiredX; 1.5985 + 1.5986 + nsRect tempRect = resultFrame->GetRect(); 1.5987 + nsPoint offset; 1.5988 + nsView * view; //used for call of get offset from view 1.5989 + resultFrame->GetOffsetFromView(offset, &view); 1.5990 + if (!view) { 1.5991 + return NS_ERROR_FAILURE; 1.5992 + } 1.5993 + point.y = tempRect.height + offset.y; 1.5994 + 1.5995 + //special check. if we allow non-text selection then we can allow a hit location to fall before a table. 1.5996 + //otherwise there is no way to get and click signal to fall before a table (it being a line iterator itself) 1.5997 + nsIPresShell *shell = aPresContext->GetPresShell(); 1.5998 + if (!shell) 1.5999 + return NS_ERROR_FAILURE; 1.6000 + int16_t isEditor = shell->GetSelectionFlags(); 1.6001 + isEditor = isEditor == nsISelectionDisplay::DISPLAY_ALL; 1.6002 + if ( isEditor ) 1.6003 + { 1.6004 + if (resultFrame->GetType() == nsGkAtoms::tableOuterFrame) 1.6005 + { 1.6006 + if (((point.x - offset.x + tempRect.x)<0) || ((point.x - offset.x+ tempRect.x)>tempRect.width))//off left/right side 1.6007 + { 1.6008 + nsIContent* content = resultFrame->GetContent(); 1.6009 + if (content) 1.6010 + { 1.6011 + nsIContent* parent = content->GetParent(); 1.6012 + if (parent) 1.6013 + { 1.6014 + aPos->mResultContent = parent; 1.6015 + aPos->mContentOffset = parent->IndexOf(content); 1.6016 + aPos->mAttachForward = false; 1.6017 + if ((point.x - offset.x+ tempRect.x)>tempRect.width) 1.6018 + { 1.6019 + aPos->mContentOffset++;//go to end of this frame 1.6020 + aPos->mAttachForward = true; 1.6021 + } 1.6022 + //result frame is the result frames parent. 1.6023 + aPos->mResultFrame = resultFrame->GetParent(); 1.6024 + return NS_POSITION_BEFORE_TABLE; 1.6025 + } 1.6026 + } 1.6027 + } 1.6028 + } 1.6029 + } 1.6030 + 1.6031 + if (!resultFrame->HasView()) 1.6032 + { 1.6033 + nsView* view; 1.6034 + nsPoint offset; 1.6035 + resultFrame->GetOffsetFromView(offset, &view); 1.6036 + ContentOffsets offsets = 1.6037 + resultFrame->GetContentOffsetsFromPoint(point - offset); 1.6038 + aPos->mResultContent = offsets.content; 1.6039 + aPos->mContentOffset = offsets.offset; 1.6040 + aPos->mAttachForward = offsets.associateWithNext; 1.6041 + if (offsets.content) 1.6042 + { 1.6043 + bool selectable; 1.6044 + resultFrame->IsSelectable(&selectable, nullptr); 1.6045 + if (selectable) 1.6046 + { 1.6047 + found = true; 1.6048 + break; 1.6049 + } 1.6050 + } 1.6051 + } 1.6052 + 1.6053 + if (aPos->mDirection == eDirPrevious && (resultFrame == farStoppingFrame)) 1.6054 + break; 1.6055 + if (aPos->mDirection == eDirNext && (resultFrame == nearStoppingFrame)) 1.6056 + break; 1.6057 + //always try previous on THAT line if that fails go the other way 1.6058 + frameTraversal->Prev(); 1.6059 + resultFrame = frameTraversal->CurrentItem(); 1.6060 + if (!resultFrame) 1.6061 + return NS_ERROR_FAILURE; 1.6062 + } 1.6063 + 1.6064 + if (!found){ 1.6065 + resultFrame = storeOldResultFrame; 1.6066 + 1.6067 + result = NS_NewFrameTraversal(getter_AddRefs(frameTraversal), 1.6068 + aPresContext, resultFrame, 1.6069 + eLeaf, 1.6070 + false, // aVisual 1.6071 + aPos->mScrollViewStop, 1.6072 + false // aFollowOOFs 1.6073 + ); 1.6074 + } 1.6075 + while ( !found ){ 1.6076 + nsPoint point(aPos->mDesiredX, 0); 1.6077 + nsView* view; 1.6078 + nsPoint offset; 1.6079 + resultFrame->GetOffsetFromView(offset, &view); 1.6080 + ContentOffsets offsets = 1.6081 + resultFrame->GetContentOffsetsFromPoint(point - offset); 1.6082 + aPos->mResultContent = offsets.content; 1.6083 + aPos->mContentOffset = offsets.offset; 1.6084 + aPos->mAttachForward = offsets.associateWithNext; 1.6085 + if (offsets.content) 1.6086 + { 1.6087 + bool selectable; 1.6088 + resultFrame->IsSelectable(&selectable, nullptr); 1.6089 + if (selectable) 1.6090 + { 1.6091 + found = true; 1.6092 + if (resultFrame == farStoppingFrame) 1.6093 + aPos->mAttachForward = false; 1.6094 + else 1.6095 + aPos->mAttachForward = true; 1.6096 + break; 1.6097 + } 1.6098 + } 1.6099 + if (aPos->mDirection == eDirPrevious && (resultFrame == nearStoppingFrame)) 1.6100 + break; 1.6101 + if (aPos->mDirection == eDirNext && (resultFrame == farStoppingFrame)) 1.6102 + break; 1.6103 + //previous didnt work now we try "next" 1.6104 + frameTraversal->Next(); 1.6105 + nsIFrame *tempFrame = frameTraversal->CurrentItem(); 1.6106 + if (!tempFrame) 1.6107 + break; 1.6108 + resultFrame = tempFrame; 1.6109 + } 1.6110 + aPos->mResultFrame = resultFrame; 1.6111 + } 1.6112 + else { 1.6113 + //we need to jump to new block frame. 1.6114 + aPos->mAmount = eSelectLine; 1.6115 + aPos->mStartOffset = 0; 1.6116 + aPos->mAttachForward = !(aPos->mDirection == eDirNext); 1.6117 + if (aPos->mDirection == eDirPrevious) 1.6118 + aPos->mStartOffset = -1;//start from end 1.6119 + return aBlockFrame->PeekOffset(aPos); 1.6120 + } 1.6121 + } 1.6122 + return NS_OK; 1.6123 +} 1.6124 + 1.6125 +nsIFrame::CaretPosition 1.6126 +nsIFrame::GetExtremeCaretPosition(bool aStart) 1.6127 +{ 1.6128 + CaretPosition result; 1.6129 + 1.6130 + FrameTarget targetFrame = DrillDownToSelectionFrame(this, !aStart, 0); 1.6131 + FrameContentRange range = GetRangeForFrame(targetFrame.frame); 1.6132 + result.mResultContent = range.content; 1.6133 + result.mContentOffset = aStart ? range.start : range.end; 1.6134 + return result; 1.6135 +} 1.6136 + 1.6137 +// Find the first (or last) descendant of the given frame 1.6138 +// which is either a block frame or a BRFrame. 1.6139 +static nsContentAndOffset 1.6140 +FindBlockFrameOrBR(nsIFrame* aFrame, nsDirection aDirection) 1.6141 +{ 1.6142 + nsContentAndOffset result; 1.6143 + result.mContent = nullptr; 1.6144 + result.mOffset = 0; 1.6145 + 1.6146 + if (aFrame->IsGeneratedContentFrame()) 1.6147 + return result; 1.6148 + 1.6149 + // Treat form controls as inline leaves 1.6150 + // XXX we really need a way to determine whether a frame is inline-level 1.6151 + nsIFormControlFrame* fcf = do_QueryFrame(aFrame); 1.6152 + if (fcf) 1.6153 + return result; 1.6154 + 1.6155 + // Check the frame itself 1.6156 + // Fall through block-in-inline split frames because their mContent is 1.6157 + // the content of the inline frames they were created from. The 1.6158 + // first/last child of such frames is the real block frame we're 1.6159 + // looking for. 1.6160 + if ((nsLayoutUtils::GetAsBlock(aFrame) && 1.6161 + !(aFrame->GetStateBits() & NS_FRAME_PART_OF_IBSPLIT)) || 1.6162 + aFrame->GetType() == nsGkAtoms::brFrame) { 1.6163 + nsIContent* content = aFrame->GetContent(); 1.6164 + result.mContent = content->GetParent(); 1.6165 + // In some cases (bug 310589, bug 370174) we end up here with a null content. 1.6166 + // This probably shouldn't ever happen, but since it sometimes does, we want 1.6167 + // to avoid crashing here. 1.6168 + NS_ASSERTION(result.mContent, "Unexpected orphan content"); 1.6169 + if (result.mContent) 1.6170 + result.mOffset = result.mContent->IndexOf(content) + 1.6171 + (aDirection == eDirPrevious ? 1 : 0); 1.6172 + return result; 1.6173 + } 1.6174 + 1.6175 + // If this is a preformatted text frame, see if it ends with a newline 1.6176 + if (aFrame->HasSignificantTerminalNewline()) { 1.6177 + int32_t startOffset, endOffset; 1.6178 + aFrame->GetOffsets(startOffset, endOffset); 1.6179 + result.mContent = aFrame->GetContent(); 1.6180 + result.mOffset = endOffset - (aDirection == eDirPrevious ? 0 : 1); 1.6181 + return result; 1.6182 + } 1.6183 + 1.6184 + // Iterate over children and call ourselves recursively 1.6185 + if (aDirection == eDirPrevious) { 1.6186 + nsIFrame* child = aFrame->GetLastChild(nsIFrame::kPrincipalList); 1.6187 + while(child && !result.mContent) { 1.6188 + result = FindBlockFrameOrBR(child, aDirection); 1.6189 + child = child->GetPrevSibling(); 1.6190 + } 1.6191 + } else { // eDirNext 1.6192 + nsIFrame* child = aFrame->GetFirstPrincipalChild(); 1.6193 + while(child && !result.mContent) { 1.6194 + result = FindBlockFrameOrBR(child, aDirection); 1.6195 + child = child->GetNextSibling(); 1.6196 + } 1.6197 + } 1.6198 + return result; 1.6199 +} 1.6200 + 1.6201 +nsresult 1.6202 +nsIFrame::PeekOffsetParagraph(nsPeekOffsetStruct *aPos) 1.6203 +{ 1.6204 + nsIFrame* frame = this; 1.6205 + nsContentAndOffset blockFrameOrBR; 1.6206 + blockFrameOrBR.mContent = nullptr; 1.6207 + bool reachedBlockAncestor = false; 1.6208 + 1.6209 + // Go through containing frames until reaching a block frame. 1.6210 + // In each step, search the previous (or next) siblings for the closest 1.6211 + // "stop frame" (a block frame or a BRFrame). 1.6212 + // If found, set it to be the selection boundray and abort. 1.6213 + 1.6214 + if (aPos->mDirection == eDirPrevious) { 1.6215 + while (!reachedBlockAncestor) { 1.6216 + nsIFrame* parent = frame->GetParent(); 1.6217 + // Treat a frame associated with the root content as if it were a block frame. 1.6218 + if (!frame->mContent || !frame->mContent->GetParent()) { 1.6219 + reachedBlockAncestor = true; 1.6220 + break; 1.6221 + } 1.6222 + nsIFrame* sibling = frame->GetPrevSibling(); 1.6223 + while (sibling && !blockFrameOrBR.mContent) { 1.6224 + blockFrameOrBR = FindBlockFrameOrBR(sibling, eDirPrevious); 1.6225 + sibling = sibling->GetPrevSibling(); 1.6226 + } 1.6227 + if (blockFrameOrBR.mContent) { 1.6228 + aPos->mResultContent = blockFrameOrBR.mContent; 1.6229 + aPos->mContentOffset = blockFrameOrBR.mOffset; 1.6230 + break; 1.6231 + } 1.6232 + frame = parent; 1.6233 + reachedBlockAncestor = (nsLayoutUtils::GetAsBlock(frame) != nullptr); 1.6234 + } 1.6235 + if (reachedBlockAncestor) { // no "stop frame" found 1.6236 + aPos->mResultContent = frame->GetContent(); 1.6237 + aPos->mContentOffset = 0; 1.6238 + } 1.6239 + } else { // eDirNext 1.6240 + while (!reachedBlockAncestor) { 1.6241 + nsIFrame* parent = frame->GetParent(); 1.6242 + // Treat a frame associated with the root content as if it were a block frame. 1.6243 + if (!frame->mContent || !frame->mContent->GetParent()) { 1.6244 + reachedBlockAncestor = true; 1.6245 + break; 1.6246 + } 1.6247 + nsIFrame* sibling = frame; 1.6248 + while (sibling && !blockFrameOrBR.mContent) { 1.6249 + blockFrameOrBR = FindBlockFrameOrBR(sibling, eDirNext); 1.6250 + sibling = sibling->GetNextSibling(); 1.6251 + } 1.6252 + if (blockFrameOrBR.mContent) { 1.6253 + aPos->mResultContent = blockFrameOrBR.mContent; 1.6254 + aPos->mContentOffset = blockFrameOrBR.mOffset; 1.6255 + break; 1.6256 + } 1.6257 + frame = parent; 1.6258 + reachedBlockAncestor = (nsLayoutUtils::GetAsBlock(frame) != nullptr); 1.6259 + } 1.6260 + if (reachedBlockAncestor) { // no "stop frame" found 1.6261 + aPos->mResultContent = frame->GetContent(); 1.6262 + if (aPos->mResultContent) 1.6263 + aPos->mContentOffset = aPos->mResultContent->GetChildCount(); 1.6264 + } 1.6265 + } 1.6266 + return NS_OK; 1.6267 +} 1.6268 + 1.6269 +// Determine movement direction relative to frame 1.6270 +static bool IsMovingInFrameDirection(nsIFrame* frame, nsDirection aDirection, bool aVisual) 1.6271 +{ 1.6272 + bool isReverseDirection = aVisual ? 1.6273 + (NS_GET_EMBEDDING_LEVEL(frame) & 1) != (NS_GET_BASE_LEVEL(frame) & 1) : false; 1.6274 + return aDirection == (isReverseDirection ? eDirPrevious : eDirNext); 1.6275 +} 1.6276 + 1.6277 +nsresult 1.6278 +nsIFrame::PeekOffset(nsPeekOffsetStruct* aPos) 1.6279 +{ 1.6280 + if (!aPos) 1.6281 + return NS_ERROR_NULL_POINTER; 1.6282 + nsresult result = NS_ERROR_FAILURE; 1.6283 + 1.6284 + if (mState & NS_FRAME_IS_DIRTY) 1.6285 + return NS_ERROR_UNEXPECTED; 1.6286 + 1.6287 + // Translate content offset to be relative to frame 1.6288 + FrameContentRange range = GetRangeForFrame(this); 1.6289 + int32_t offset = aPos->mStartOffset - range.start; 1.6290 + nsIFrame* current = this; 1.6291 + 1.6292 + switch (aPos->mAmount) { 1.6293 + case eSelectCharacter: 1.6294 + case eSelectCluster: 1.6295 + { 1.6296 + bool eatingNonRenderableWS = false; 1.6297 + nsIFrame::FrameSearchResult peekSearchState = CONTINUE; 1.6298 + bool jumpedLine = false; 1.6299 + bool movedOverNonSelectableText = false; 1.6300 + 1.6301 + while (peekSearchState != FOUND) { 1.6302 + bool movingInFrameDirection = 1.6303 + IsMovingInFrameDirection(current, aPos->mDirection, aPos->mVisual); 1.6304 + 1.6305 + if (eatingNonRenderableWS) 1.6306 + peekSearchState = current->PeekOffsetNoAmount(movingInFrameDirection, &offset); 1.6307 + else 1.6308 + peekSearchState = current->PeekOffsetCharacter(movingInFrameDirection, &offset, 1.6309 + aPos->mAmount == eSelectCluster); 1.6310 + 1.6311 + movedOverNonSelectableText |= (peekSearchState == CONTINUE_UNSELECTABLE); 1.6312 + 1.6313 + if (peekSearchState != FOUND) { 1.6314 + result = 1.6315 + current->GetFrameFromDirection(aPos->mDirection, aPos->mVisual, 1.6316 + aPos->mJumpLines, aPos->mScrollViewStop, 1.6317 + ¤t, &offset, &jumpedLine); 1.6318 + if (NS_FAILED(result)) 1.6319 + return result; 1.6320 + 1.6321 + // If we jumped lines, it's as if we found a character, but we still need 1.6322 + // to eat non-renderable content on the new line. 1.6323 + if (jumpedLine) 1.6324 + eatingNonRenderableWS = true; 1.6325 + } 1.6326 + 1.6327 + // Found frame, but because we moved over non selectable text we want the offset 1.6328 + // to be at the frame edge. 1.6329 + if (peekSearchState == FOUND && movedOverNonSelectableText) 1.6330 + { 1.6331 + int32_t start, end; 1.6332 + current->GetOffsets(start, end); 1.6333 + offset = aPos->mDirection == eDirNext ? 0 : end - start; 1.6334 + } 1.6335 + } 1.6336 + 1.6337 + // Set outputs 1.6338 + range = GetRangeForFrame(current); 1.6339 + aPos->mResultFrame = current; 1.6340 + aPos->mResultContent = range.content; 1.6341 + // Output offset is relative to content, not frame 1.6342 + aPos->mContentOffset = offset < 0 ? range.end : range.start + offset; 1.6343 + // If we're dealing with a text frame and moving backward positions us at 1.6344 + // the end of that line, decrease the offset by one to make sure that 1.6345 + // we're placed before the linefeed character on the previous line. 1.6346 + if (offset < 0 && jumpedLine && 1.6347 + aPos->mDirection == eDirPrevious && 1.6348 + current->HasSignificantTerminalNewline()) { 1.6349 + --aPos->mContentOffset; 1.6350 + } 1.6351 + 1.6352 + break; 1.6353 + } 1.6354 + case eSelectWordNoSpace: 1.6355 + // eSelectWordNoSpace means that we should not be eating any whitespace when 1.6356 + // moving to the adjacent word. This means that we should set aPos-> 1.6357 + // mWordMovementType to eEndWord if we're moving forwards, and to eStartWord 1.6358 + // if we're moving backwards. 1.6359 + if (aPos->mDirection == eDirPrevious) { 1.6360 + aPos->mWordMovementType = eStartWord; 1.6361 + } else { 1.6362 + aPos->mWordMovementType = eEndWord; 1.6363 + } 1.6364 + // Intentionally fall through the eSelectWord case. 1.6365 + case eSelectWord: 1.6366 + { 1.6367 + // wordSelectEatSpace means "are we looking for a boundary between whitespace 1.6368 + // and non-whitespace (in the direction we're moving in)". 1.6369 + // It is true when moving forward and looking for a beginning of a word, or 1.6370 + // when moving backwards and looking for an end of a word. 1.6371 + bool wordSelectEatSpace; 1.6372 + if (aPos->mWordMovementType != eDefaultBehavior) { 1.6373 + // aPos->mWordMovementType possible values: 1.6374 + // eEndWord: eat the space if we're moving backwards 1.6375 + // eStartWord: eat the space if we're moving forwards 1.6376 + wordSelectEatSpace = ((aPos->mWordMovementType == eEndWord) == (aPos->mDirection == eDirPrevious)); 1.6377 + } 1.6378 + else { 1.6379 + // Use the hidden preference which is based on operating system behavior. 1.6380 + // This pref only affects whether moving forward by word should go to the end of this word or start of the next word. 1.6381 + // When going backwards, the start of the word is always used, on every operating system. 1.6382 + wordSelectEatSpace = aPos->mDirection == eDirNext && 1.6383 + Preferences::GetBool("layout.word_select.eat_space_to_next_word"); 1.6384 + } 1.6385 + 1.6386 + // mSawBeforeType means "we already saw characters of the type 1.6387 + // before the boundary we're looking for". Examples: 1.6388 + // 1. If we're moving forward, looking for a word beginning (i.e. a boundary 1.6389 + // between whitespace and non-whitespace), then eatingWS==true means 1.6390 + // "we already saw some whitespace". 1.6391 + // 2. If we're moving backward, looking for a word beginning (i.e. a boundary 1.6392 + // between non-whitespace and whitespace), then eatingWS==true means 1.6393 + // "we already saw some non-whitespace". 1.6394 + PeekWordState state; 1.6395 + int32_t offsetAdjustment = 0; 1.6396 + bool done = false; 1.6397 + while (!done) { 1.6398 + bool movingInFrameDirection = 1.6399 + IsMovingInFrameDirection(current, aPos->mDirection, aPos->mVisual); 1.6400 + 1.6401 + done = current->PeekOffsetWord(movingInFrameDirection, wordSelectEatSpace, 1.6402 + aPos->mIsKeyboardSelect, &offset, &state) == FOUND; 1.6403 + 1.6404 + if (!done) { 1.6405 + nsIFrame* nextFrame; 1.6406 + int32_t nextFrameOffset; 1.6407 + bool jumpedLine; 1.6408 + result = 1.6409 + current->GetFrameFromDirection(aPos->mDirection, aPos->mVisual, 1.6410 + aPos->mJumpLines, aPos->mScrollViewStop, 1.6411 + &nextFrame, &nextFrameOffset, &jumpedLine); 1.6412 + // We can't jump lines if we're looking for whitespace following 1.6413 + // non-whitespace, and we already encountered non-whitespace. 1.6414 + if (NS_FAILED(result) || 1.6415 + (jumpedLine && !wordSelectEatSpace && state.mSawBeforeType)) { 1.6416 + done = true; 1.6417 + // If we've crossed the line boundary, check to make sure that we 1.6418 + // have not consumed a trailing newline as whitesapce if it's significant. 1.6419 + if (jumpedLine && wordSelectEatSpace && 1.6420 + current->HasSignificantTerminalNewline()) { 1.6421 + offsetAdjustment = -1; 1.6422 + } 1.6423 + } else { 1.6424 + if (jumpedLine) { 1.6425 + state.mContext.Truncate(); 1.6426 + } 1.6427 + current = nextFrame; 1.6428 + offset = nextFrameOffset; 1.6429 + // Jumping a line is equivalent to encountering whitespace 1.6430 + if (wordSelectEatSpace && jumpedLine) 1.6431 + state.SetSawBeforeType(); 1.6432 + } 1.6433 + } 1.6434 + } 1.6435 + 1.6436 + // Set outputs 1.6437 + range = GetRangeForFrame(current); 1.6438 + aPos->mResultFrame = current; 1.6439 + aPos->mResultContent = range.content; 1.6440 + // Output offset is relative to content, not frame 1.6441 + aPos->mContentOffset = (offset < 0 ? range.end : range.start + offset) + offsetAdjustment; 1.6442 + break; 1.6443 + } 1.6444 + case eSelectLine : 1.6445 + { 1.6446 + nsAutoLineIterator iter; 1.6447 + nsIFrame *blockFrame = this; 1.6448 + 1.6449 + while (NS_FAILED(result)){ 1.6450 + int32_t thisLine = nsFrame::GetLineNumber(blockFrame, aPos->mScrollViewStop, &blockFrame); 1.6451 + if (thisLine < 0) 1.6452 + return NS_ERROR_FAILURE; 1.6453 + iter = blockFrame->GetLineIterator(); 1.6454 + NS_ASSERTION(iter, "GetLineNumber() succeeded but no block frame?"); 1.6455 + result = NS_OK; 1.6456 + 1.6457 + int edgeCase = 0;//no edge case. this should look at thisLine 1.6458 + 1.6459 + bool doneLooping = false;//tells us when no more block frames hit. 1.6460 + //this part will find a frame or a block frame. if it's a block frame 1.6461 + //it will "drill down" to find a viable frame or it will return an error. 1.6462 + nsIFrame *lastFrame = this; 1.6463 + do { 1.6464 + result = nsFrame::GetNextPrevLineFromeBlockFrame(PresContext(), 1.6465 + aPos, 1.6466 + blockFrame, 1.6467 + thisLine, 1.6468 + edgeCase //start from thisLine 1.6469 + ); 1.6470 + if (NS_SUCCEEDED(result) && (!aPos->mResultFrame || aPos->mResultFrame == lastFrame))//we came back to same spot! keep going 1.6471 + { 1.6472 + aPos->mResultFrame = nullptr; 1.6473 + if (aPos->mDirection == eDirPrevious) 1.6474 + thisLine--; 1.6475 + else 1.6476 + thisLine++; 1.6477 + } 1.6478 + else //if failure or success with different frame. 1.6479 + doneLooping = true; //do not continue with while loop 1.6480 + 1.6481 + lastFrame = aPos->mResultFrame; //set last frame 1.6482 + 1.6483 + if (NS_SUCCEEDED(result) && aPos->mResultFrame 1.6484 + && blockFrame != aPos->mResultFrame)// make sure block element is not the same as the one we had before 1.6485 + { 1.6486 +/* SPECIAL CHECK FOR TABLE NAVIGATION 1.6487 + tables need to navigate also and the frame that supports it is nsTableRowGroupFrame which is INSIDE 1.6488 + nsTableOuterFrame. if we have stumbled onto an nsTableOuter we need to drill into nsTableRowGroup 1.6489 + if we hit a header or footer that's ok just go into them, 1.6490 +*/ 1.6491 + bool searchTableBool = false; 1.6492 + if (aPos->mResultFrame->GetType() == nsGkAtoms::tableOuterFrame || 1.6493 + aPos->mResultFrame->GetType() == nsGkAtoms::tableCellFrame) 1.6494 + { 1.6495 + nsIFrame *frame = aPos->mResultFrame->GetFirstPrincipalChild(); 1.6496 + //got the table frame now 1.6497 + while(frame) //ok time to drill down to find iterator 1.6498 + { 1.6499 + iter = frame->GetLineIterator(); 1.6500 + if (iter) 1.6501 + { 1.6502 + aPos->mResultFrame = frame; 1.6503 + searchTableBool = true; 1.6504 + result = NS_OK; 1.6505 + break; //while(frame) 1.6506 + } 1.6507 + result = NS_ERROR_FAILURE; 1.6508 + frame = frame->GetFirstPrincipalChild(); 1.6509 + } 1.6510 + } 1.6511 + 1.6512 + if (!searchTableBool) { 1.6513 + iter = aPos->mResultFrame->GetLineIterator(); 1.6514 + result = iter ? NS_OK : NS_ERROR_FAILURE; 1.6515 + } 1.6516 + if (NS_SUCCEEDED(result) && iter)//we've struck another block element! 1.6517 + { 1.6518 + doneLooping = false; 1.6519 + if (aPos->mDirection == eDirPrevious) 1.6520 + edgeCase = 1;//far edge, search from end backwards 1.6521 + else 1.6522 + edgeCase = -1;//near edge search from beginning onwards 1.6523 + thisLine=0;//this line means nothing now. 1.6524 + //everything else means something so keep looking "inside" the block 1.6525 + blockFrame = aPos->mResultFrame; 1.6526 + 1.6527 + } 1.6528 + else 1.6529 + { 1.6530 + result = NS_OK;//THIS is to mean that everything is ok to the containing while loop 1.6531 + break; 1.6532 + } 1.6533 + } 1.6534 + } while (!doneLooping); 1.6535 + } 1.6536 + return result; 1.6537 + } 1.6538 + 1.6539 + case eSelectParagraph: 1.6540 + return PeekOffsetParagraph(aPos); 1.6541 + 1.6542 + case eSelectBeginLine: 1.6543 + case eSelectEndLine: 1.6544 + { 1.6545 + // Adjusted so that the caret can't get confused when content changes 1.6546 + nsIFrame* blockFrame = AdjustFrameForSelectionStyles(this); 1.6547 + int32_t thisLine = nsFrame::GetLineNumber(blockFrame, aPos->mScrollViewStop, &blockFrame); 1.6548 + if (thisLine < 0) 1.6549 + return NS_ERROR_FAILURE; 1.6550 + nsAutoLineIterator it = blockFrame->GetLineIterator(); 1.6551 + NS_ASSERTION(it, "GetLineNumber() succeeded but no block frame?"); 1.6552 + 1.6553 + int32_t lineFrameCount; 1.6554 + nsIFrame *firstFrame; 1.6555 + nsRect usedRect; 1.6556 + uint32_t lineFlags; 1.6557 + nsIFrame* baseFrame = nullptr; 1.6558 + bool endOfLine = (eSelectEndLine == aPos->mAmount); 1.6559 + 1.6560 + if (aPos->mVisual && PresContext()->BidiEnabled()) { 1.6561 + bool lineIsRTL = it->GetDirection(); 1.6562 + bool isReordered; 1.6563 + nsIFrame *lastFrame; 1.6564 + result = it->CheckLineOrder(thisLine, &isReordered, &firstFrame, &lastFrame); 1.6565 + baseFrame = endOfLine ? lastFrame : firstFrame; 1.6566 + if (baseFrame) { 1.6567 + nsBidiLevel embeddingLevel = nsBidiPresUtils::GetFrameEmbeddingLevel(baseFrame); 1.6568 + // If the direction of the frame on the edge is opposite to that of the line, 1.6569 + // we'll need to drill down to its opposite end, so reverse endOfLine. 1.6570 + if ((embeddingLevel & 1) == !lineIsRTL) 1.6571 + endOfLine = !endOfLine; 1.6572 + } 1.6573 + } else { 1.6574 + it->GetLine(thisLine, &firstFrame, &lineFrameCount, usedRect, &lineFlags); 1.6575 + 1.6576 + nsIFrame* frame = firstFrame; 1.6577 + for (int32_t count = lineFrameCount; count; 1.6578 + --count, frame = frame->GetNextSibling()) { 1.6579 + if (!frame->IsGeneratedContentFrame()) { 1.6580 + baseFrame = frame; 1.6581 + if (!endOfLine) 1.6582 + break; 1.6583 + } 1.6584 + } 1.6585 + } 1.6586 + if (!baseFrame) 1.6587 + return NS_ERROR_FAILURE; 1.6588 + FrameTarget targetFrame = DrillDownToSelectionFrame(baseFrame, 1.6589 + endOfLine, 0); 1.6590 + FrameContentRange range = GetRangeForFrame(targetFrame.frame); 1.6591 + aPos->mResultContent = range.content; 1.6592 + aPos->mContentOffset = endOfLine ? range.end : range.start; 1.6593 + if (endOfLine && targetFrame.frame->HasSignificantTerminalNewline()) { 1.6594 + // Do not position the caret after the terminating newline if we're 1.6595 + // trying to move to the end of line (see bug 596506) 1.6596 + --aPos->mContentOffset; 1.6597 + } 1.6598 + aPos->mResultFrame = targetFrame.frame; 1.6599 + aPos->mAttachForward = (aPos->mContentOffset == range.start); 1.6600 + if (!range.content) 1.6601 + return NS_ERROR_FAILURE; 1.6602 + return NS_OK; 1.6603 + } 1.6604 + 1.6605 + default: 1.6606 + { 1.6607 + NS_ASSERTION(false, "Invalid amount"); 1.6608 + return NS_ERROR_FAILURE; 1.6609 + } 1.6610 + } 1.6611 + return NS_OK; 1.6612 +} 1.6613 + 1.6614 +nsIFrame::FrameSearchResult 1.6615 +nsFrame::PeekOffsetNoAmount(bool aForward, int32_t* aOffset) 1.6616 +{ 1.6617 + NS_ASSERTION (aOffset && *aOffset <= 1, "aOffset out of range"); 1.6618 + // Sure, we can stop right here. 1.6619 + return FOUND; 1.6620 +} 1.6621 + 1.6622 +nsIFrame::FrameSearchResult 1.6623 +nsFrame::PeekOffsetCharacter(bool aForward, int32_t* aOffset, 1.6624 + bool aRespectClusters) 1.6625 +{ 1.6626 + NS_ASSERTION (aOffset && *aOffset <= 1, "aOffset out of range"); 1.6627 + int32_t startOffset = *aOffset; 1.6628 + // A negative offset means "end of frame", which in our case means offset 1. 1.6629 + if (startOffset < 0) 1.6630 + startOffset = 1; 1.6631 + if (aForward == (startOffset == 0)) { 1.6632 + // We're before the frame and moving forward, or after it and moving backwards: 1.6633 + // skip to the other side and we're done. 1.6634 + *aOffset = 1 - startOffset; 1.6635 + return FOUND; 1.6636 + } 1.6637 + return CONTINUE; 1.6638 +} 1.6639 + 1.6640 +nsIFrame::FrameSearchResult 1.6641 +nsFrame::PeekOffsetWord(bool aForward, bool aWordSelectEatSpace, bool aIsKeyboardSelect, 1.6642 + int32_t* aOffset, PeekWordState* aState) 1.6643 +{ 1.6644 + NS_ASSERTION (aOffset && *aOffset <= 1, "aOffset out of range"); 1.6645 + int32_t startOffset = *aOffset; 1.6646 + // This isn't text, so truncate the context 1.6647 + aState->mContext.Truncate(); 1.6648 + if (startOffset < 0) 1.6649 + startOffset = 1; 1.6650 + if (aForward == (startOffset == 0)) { 1.6651 + // We're before the frame and moving forward, or after it and moving backwards. 1.6652 + // If we're looking for non-whitespace, we found it (without skipping this frame). 1.6653 + if (!aState->mAtStart) { 1.6654 + if (aState->mLastCharWasPunctuation) { 1.6655 + // We're not punctuation, so this is a punctuation boundary. 1.6656 + if (BreakWordBetweenPunctuation(aState, aForward, false, false, aIsKeyboardSelect)) 1.6657 + return FOUND; 1.6658 + } else { 1.6659 + // This is not a punctuation boundary. 1.6660 + if (aWordSelectEatSpace && aState->mSawBeforeType) 1.6661 + return FOUND; 1.6662 + } 1.6663 + } 1.6664 + // Otherwise skip to the other side and note that we encountered non-whitespace. 1.6665 + *aOffset = 1 - startOffset; 1.6666 + aState->Update(false, // not punctuation 1.6667 + false // not whitespace 1.6668 + ); 1.6669 + if (!aWordSelectEatSpace) 1.6670 + aState->SetSawBeforeType(); 1.6671 + } 1.6672 + return CONTINUE; 1.6673 +} 1.6674 + 1.6675 +bool 1.6676 +nsFrame::BreakWordBetweenPunctuation(const PeekWordState* aState, 1.6677 + bool aForward, 1.6678 + bool aPunctAfter, bool aWhitespaceAfter, 1.6679 + bool aIsKeyboardSelect) 1.6680 +{ 1.6681 + NS_ASSERTION(aPunctAfter != aState->mLastCharWasPunctuation, 1.6682 + "Call this only at punctuation boundaries"); 1.6683 + if (aState->mLastCharWasWhitespace) { 1.6684 + // We always stop between whitespace and punctuation 1.6685 + return true; 1.6686 + } 1.6687 + if (!Preferences::GetBool("layout.word_select.stop_at_punctuation")) { 1.6688 + // When this pref is false, we never stop at a punctuation boundary unless 1.6689 + // it's followed by whitespace (in the relevant direction). 1.6690 + return aWhitespaceAfter; 1.6691 + } 1.6692 + if (!aIsKeyboardSelect) { 1.6693 + // mouse caret movement (e.g. word selection) always stops at every punctuation boundary 1.6694 + return true; 1.6695 + } 1.6696 + bool afterPunct = aForward ? aState->mLastCharWasPunctuation : aPunctAfter; 1.6697 + if (!afterPunct) { 1.6698 + // keyboard caret movement only stops after punctuation (in content order) 1.6699 + return false; 1.6700 + } 1.6701 + // Stop only if we've seen some non-punctuation since the last whitespace; 1.6702 + // don't stop after punctuation that follows whitespace. 1.6703 + return aState->mSeenNonPunctuationSinceWhitespace; 1.6704 +} 1.6705 + 1.6706 +nsresult 1.6707 +nsFrame::CheckVisibility(nsPresContext* , int32_t , int32_t , bool , bool *, bool *) 1.6708 +{ 1.6709 + return NS_ERROR_NOT_IMPLEMENTED; 1.6710 +} 1.6711 + 1.6712 + 1.6713 +int32_t 1.6714 +nsFrame::GetLineNumber(nsIFrame *aFrame, bool aLockScroll, nsIFrame** aContainingBlock) 1.6715 +{ 1.6716 + NS_ASSERTION(aFrame, "null aFrame"); 1.6717 + nsFrameManager* frameManager = aFrame->PresContext()->FrameManager(); 1.6718 + nsIFrame *blockFrame = aFrame; 1.6719 + nsIFrame *thisBlock; 1.6720 + nsAutoLineIterator it; 1.6721 + nsresult result = NS_ERROR_FAILURE; 1.6722 + while (NS_FAILED(result) && blockFrame) 1.6723 + { 1.6724 + thisBlock = blockFrame; 1.6725 + if (thisBlock->GetStateBits() & NS_FRAME_OUT_OF_FLOW) { 1.6726 + //if we are searching for a frame that is not in flow we will not find it. 1.6727 + //we must instead look for its placeholder 1.6728 + if (thisBlock->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER) { 1.6729 + // abspos continuations don't have placeholders, get the fif 1.6730 + thisBlock = thisBlock->FirstInFlow(); 1.6731 + } 1.6732 + thisBlock = frameManager->GetPlaceholderFrameFor(thisBlock); 1.6733 + if (!thisBlock) 1.6734 + return -1; 1.6735 + } 1.6736 + blockFrame = thisBlock->GetParent(); 1.6737 + result = NS_OK; 1.6738 + if (blockFrame) { 1.6739 + if (aLockScroll && blockFrame->GetType() == nsGkAtoms::scrollFrame) 1.6740 + return -1; 1.6741 + it = blockFrame->GetLineIterator(); 1.6742 + if (!it) 1.6743 + result = NS_ERROR_FAILURE; 1.6744 + } 1.6745 + } 1.6746 + if (!blockFrame || !it) 1.6747 + return -1; 1.6748 + 1.6749 + if (aContainingBlock) 1.6750 + *aContainingBlock = blockFrame; 1.6751 + return it->FindLineContaining(thisBlock); 1.6752 +} 1.6753 + 1.6754 +nsresult 1.6755 +nsIFrame::GetFrameFromDirection(nsDirection aDirection, bool aVisual, 1.6756 + bool aJumpLines, bool aScrollViewStop, 1.6757 + nsIFrame** aOutFrame, int32_t* aOutOffset, bool* aOutJumpedLine) 1.6758 +{ 1.6759 + nsresult result; 1.6760 + 1.6761 + if (!aOutFrame || !aOutOffset || !aOutJumpedLine) 1.6762 + return NS_ERROR_NULL_POINTER; 1.6763 + 1.6764 + nsPresContext* presContext = PresContext(); 1.6765 + *aOutFrame = nullptr; 1.6766 + *aOutOffset = 0; 1.6767 + *aOutJumpedLine = false; 1.6768 + 1.6769 + // Find the prev/next selectable frame 1.6770 + bool selectable = false; 1.6771 + nsIFrame *traversedFrame = this; 1.6772 + while (!selectable) { 1.6773 + nsIFrame *blockFrame; 1.6774 + 1.6775 + int32_t thisLine = nsFrame::GetLineNumber(traversedFrame, aScrollViewStop, &blockFrame); 1.6776 + if (thisLine < 0) 1.6777 + return NS_ERROR_FAILURE; 1.6778 + 1.6779 + nsAutoLineIterator it = blockFrame->GetLineIterator(); 1.6780 + NS_ASSERTION(it, "GetLineNumber() succeeded but no block frame?"); 1.6781 + 1.6782 + bool atLineEdge; 1.6783 + nsIFrame *firstFrame; 1.6784 + nsIFrame *lastFrame; 1.6785 + if (aVisual && presContext->BidiEnabled()) { 1.6786 + bool lineIsRTL = it->GetDirection(); 1.6787 + bool isReordered; 1.6788 + result = it->CheckLineOrder(thisLine, &isReordered, &firstFrame, &lastFrame); 1.6789 + nsIFrame** framePtr = aDirection == eDirPrevious ? &firstFrame : &lastFrame; 1.6790 + if (*framePtr) { 1.6791 + nsBidiLevel embeddingLevel = nsBidiPresUtils::GetFrameEmbeddingLevel(*framePtr); 1.6792 + if ((((embeddingLevel & 1) && lineIsRTL) || (!(embeddingLevel & 1) && !lineIsRTL)) == 1.6793 + (aDirection == eDirPrevious)) { 1.6794 + nsFrame::GetFirstLeaf(presContext, framePtr); 1.6795 + } else { 1.6796 + nsFrame::GetLastLeaf(presContext, framePtr); 1.6797 + } 1.6798 + atLineEdge = *framePtr == traversedFrame; 1.6799 + } else { 1.6800 + atLineEdge = true; 1.6801 + } 1.6802 + } else { 1.6803 + nsRect nonUsedRect; 1.6804 + int32_t lineFrameCount; 1.6805 + uint32_t lineFlags; 1.6806 + result = it->GetLine(thisLine, &firstFrame, &lineFrameCount,nonUsedRect, 1.6807 + &lineFlags); 1.6808 + if (NS_FAILED(result)) 1.6809 + return result; 1.6810 + 1.6811 + if (aDirection == eDirPrevious) { 1.6812 + nsFrame::GetFirstLeaf(presContext, &firstFrame); 1.6813 + atLineEdge = firstFrame == traversedFrame; 1.6814 + } else { // eDirNext 1.6815 + lastFrame = firstFrame; 1.6816 + for (;lineFrameCount > 1;lineFrameCount --){ 1.6817 + result = it->GetNextSiblingOnLine(lastFrame, thisLine); 1.6818 + if (NS_FAILED(result) || !lastFrame){ 1.6819 + NS_ERROR("should not be reached nsFrame"); 1.6820 + return NS_ERROR_FAILURE; 1.6821 + } 1.6822 + } 1.6823 + nsFrame::GetLastLeaf(presContext, &lastFrame); 1.6824 + atLineEdge = lastFrame == traversedFrame; 1.6825 + } 1.6826 + } 1.6827 + 1.6828 + if (atLineEdge) { 1.6829 + *aOutJumpedLine = true; 1.6830 + if (!aJumpLines) 1.6831 + return NS_ERROR_FAILURE; //we are done. cannot jump lines 1.6832 + } 1.6833 + 1.6834 + nsCOMPtr<nsIFrameEnumerator> frameTraversal; 1.6835 + result = NS_NewFrameTraversal(getter_AddRefs(frameTraversal), 1.6836 + presContext, traversedFrame, 1.6837 + eLeaf, 1.6838 + aVisual && presContext->BidiEnabled(), 1.6839 + aScrollViewStop, 1.6840 + true // aFollowOOFs 1.6841 + ); 1.6842 + if (NS_FAILED(result)) 1.6843 + return result; 1.6844 + 1.6845 + if (aDirection == eDirNext) 1.6846 + frameTraversal->Next(); 1.6847 + else 1.6848 + frameTraversal->Prev(); 1.6849 + 1.6850 + traversedFrame = frameTraversal->CurrentItem(); 1.6851 + if (!traversedFrame) 1.6852 + return NS_ERROR_FAILURE; 1.6853 + traversedFrame->IsSelectable(&selectable, nullptr); 1.6854 + } // while (!selectable) 1.6855 + 1.6856 + *aOutOffset = (aDirection == eDirNext) ? 0 : -1; 1.6857 + 1.6858 + if (aVisual) { 1.6859 + uint8_t newLevel = NS_GET_EMBEDDING_LEVEL(traversedFrame); 1.6860 + uint8_t newBaseLevel = NS_GET_BASE_LEVEL(traversedFrame); 1.6861 + if ((newLevel & 1) != (newBaseLevel & 1)) // The new frame is reverse-direction, go to the other end 1.6862 + *aOutOffset = -1 - *aOutOffset; 1.6863 + } 1.6864 + *aOutFrame = traversedFrame; 1.6865 + return NS_OK; 1.6866 +} 1.6867 + 1.6868 +nsView* nsIFrame::GetClosestView(nsPoint* aOffset) const 1.6869 +{ 1.6870 + nsPoint offset(0,0); 1.6871 + for (const nsIFrame *f = this; f; f = f->GetParent()) { 1.6872 + if (f->HasView()) { 1.6873 + if (aOffset) 1.6874 + *aOffset = offset; 1.6875 + return f->GetView(); 1.6876 + } 1.6877 + offset += f->GetPosition(); 1.6878 + } 1.6879 + 1.6880 + NS_NOTREACHED("No view on any parent? How did that happen?"); 1.6881 + return nullptr; 1.6882 +} 1.6883 + 1.6884 + 1.6885 +/* virtual */ void 1.6886 +nsFrame::ChildIsDirty(nsIFrame* aChild) 1.6887 +{ 1.6888 + NS_NOTREACHED("should never be called on a frame that doesn't inherit from " 1.6889 + "nsContainerFrame"); 1.6890 +} 1.6891 + 1.6892 + 1.6893 +#ifdef ACCESSIBILITY 1.6894 +a11y::AccType 1.6895 +nsFrame::AccessibleType() 1.6896 +{ 1.6897 + return a11y::eNoType; 1.6898 +} 1.6899 +#endif 1.6900 + 1.6901 +NS_DECLARE_FRAME_PROPERTY(OverflowAreasProperty, 1.6902 + nsIFrame::DestroyOverflowAreas) 1.6903 + 1.6904 +bool 1.6905 +nsIFrame::ClearOverflowRects() 1.6906 +{ 1.6907 + if (mOverflow.mType == NS_FRAME_OVERFLOW_NONE) { 1.6908 + return false; 1.6909 + } 1.6910 + if (mOverflow.mType == NS_FRAME_OVERFLOW_LARGE) { 1.6911 + Properties().Delete(OverflowAreasProperty()); 1.6912 + } 1.6913 + mOverflow.mType = NS_FRAME_OVERFLOW_NONE; 1.6914 + return true; 1.6915 +} 1.6916 + 1.6917 +/** Create or retrieve the previously stored overflow area, if the frame does 1.6918 + * not overflow and no creation is required return nullptr. 1.6919 + * @return pointer to the overflow area rectangle 1.6920 + */ 1.6921 +nsOverflowAreas* 1.6922 +nsIFrame::GetOverflowAreasProperty() 1.6923 +{ 1.6924 + FrameProperties props = Properties(); 1.6925 + nsOverflowAreas *overflow = 1.6926 + static_cast<nsOverflowAreas*>(props.Get(OverflowAreasProperty())); 1.6927 + 1.6928 + if (overflow) { 1.6929 + return overflow; // the property already exists 1.6930 + } 1.6931 + 1.6932 + // The property isn't set yet, so allocate a new rect, set the property, 1.6933 + // and return the newly allocated rect 1.6934 + overflow = new nsOverflowAreas; 1.6935 + props.Set(OverflowAreasProperty(), overflow); 1.6936 + return overflow; 1.6937 +} 1.6938 + 1.6939 +/** Set the overflowArea rect, storing it as deltas or a separate rect 1.6940 + * depending on its size in relation to the primary frame rect. 1.6941 + */ 1.6942 +bool 1.6943 +nsIFrame::SetOverflowAreas(const nsOverflowAreas& aOverflowAreas) 1.6944 +{ 1.6945 + if (mOverflow.mType == NS_FRAME_OVERFLOW_LARGE) { 1.6946 + nsOverflowAreas *overflow = 1.6947 + static_cast<nsOverflowAreas*>(Properties().Get(OverflowAreasProperty())); 1.6948 + bool changed = *overflow != aOverflowAreas; 1.6949 + *overflow = aOverflowAreas; 1.6950 + 1.6951 + // Don't bother with converting to the deltas form if we already 1.6952 + // have a property. 1.6953 + return changed; 1.6954 + } 1.6955 + 1.6956 + const nsRect& vis = aOverflowAreas.VisualOverflow(); 1.6957 + uint32_t l = -vis.x, // left edge: positive delta is leftwards 1.6958 + t = -vis.y, // top: positive is upwards 1.6959 + r = vis.XMost() - mRect.width, // right: positive is rightwards 1.6960 + b = vis.YMost() - mRect.height; // bottom: positive is downwards 1.6961 + if (aOverflowAreas.ScrollableOverflow().IsEqualEdges(nsRect(nsPoint(0, 0), GetSize())) && 1.6962 + l <= NS_FRAME_OVERFLOW_DELTA_MAX && 1.6963 + t <= NS_FRAME_OVERFLOW_DELTA_MAX && 1.6964 + r <= NS_FRAME_OVERFLOW_DELTA_MAX && 1.6965 + b <= NS_FRAME_OVERFLOW_DELTA_MAX && 1.6966 + // we have to check these against zero because we *never* want to 1.6967 + // set a frame as having no overflow in this function. This is 1.6968 + // because FinishAndStoreOverflow calls this function prior to 1.6969 + // SetRect based on whether the overflow areas match aNewSize. 1.6970 + // In the case where the overflow areas exactly match mRect but 1.6971 + // do not match aNewSize, we need to store overflow in a property 1.6972 + // so that our eventual SetRect/SetSize will know that it has to 1.6973 + // reset our overflow areas. 1.6974 + (l | t | r | b) != 0) { 1.6975 + VisualDeltas oldDeltas = mOverflow.mVisualDeltas; 1.6976 + // It's a "small" overflow area so we store the deltas for each edge 1.6977 + // directly in the frame, rather than allocating a separate rect. 1.6978 + // If they're all zero, that's fine; we're setting things to 1.6979 + // no-overflow. 1.6980 + mOverflow.mVisualDeltas.mLeft = l; 1.6981 + mOverflow.mVisualDeltas.mTop = t; 1.6982 + mOverflow.mVisualDeltas.mRight = r; 1.6983 + mOverflow.mVisualDeltas.mBottom = b; 1.6984 + // There was no scrollable overflow before, and there isn't now. 1.6985 + return oldDeltas != mOverflow.mVisualDeltas; 1.6986 + } else { 1.6987 + bool changed = !aOverflowAreas.ScrollableOverflow().IsEqualEdges(nsRect(nsPoint(0, 0), GetSize())) || 1.6988 + !aOverflowAreas.VisualOverflow().IsEqualEdges(GetVisualOverflowFromDeltas()); 1.6989 + 1.6990 + // it's a large overflow area that we need to store as a property 1.6991 + mOverflow.mType = NS_FRAME_OVERFLOW_LARGE; 1.6992 + nsOverflowAreas* overflow = GetOverflowAreasProperty(); 1.6993 + NS_ASSERTION(overflow, "should have created areas"); 1.6994 + *overflow = aOverflowAreas; 1.6995 + return changed; 1.6996 + } 1.6997 +} 1.6998 + 1.6999 +inline bool 1.7000 +IsInlineFrame(nsIFrame *aFrame) 1.7001 +{ 1.7002 + nsIAtom *type = aFrame->GetType(); 1.7003 + return type == nsGkAtoms::inlineFrame; 1.7004 +} 1.7005 + 1.7006 +/** 1.7007 + * Compute the union of the border boxes of aFrame and its descendants, 1.7008 + * in aFrame's coordinate space (if aApplyTransform is false) or its 1.7009 + * post-transform coordinate space (if aApplyTransform is true). 1.7010 + */ 1.7011 +static nsRect 1.7012 +UnionBorderBoxes(nsIFrame* aFrame, bool aApplyTransform, 1.7013 + const nsSize* aSizeOverride = nullptr, 1.7014 + const nsOverflowAreas* aOverflowOverride = nullptr) 1.7015 +{ 1.7016 + const nsRect bounds(nsPoint(0, 0), 1.7017 + aSizeOverride ? *aSizeOverride : aFrame->GetSize()); 1.7018 + 1.7019 + // Start from our border-box, transformed. See comment below about 1.7020 + // transform of children. 1.7021 + nsRect u; 1.7022 + bool doTransform = aApplyTransform && aFrame->IsTransformed(); 1.7023 + if (doTransform) { 1.7024 + u = nsDisplayTransform::TransformRect(bounds, aFrame, 1.7025 + nsPoint(0, 0), &bounds); 1.7026 + } else { 1.7027 + u = bounds; 1.7028 + } 1.7029 + 1.7030 + // Only iterate through the children if the overflow areas suggest 1.7031 + // that we might need to, and if the frame doesn't clip its overflow 1.7032 + // anyway. 1.7033 + if (aOverflowOverride) { 1.7034 + if (!doTransform && 1.7035 + bounds.IsEqualEdges(aOverflowOverride->VisualOverflow()) && 1.7036 + bounds.IsEqualEdges(aOverflowOverride->ScrollableOverflow())) { 1.7037 + return u; 1.7038 + } 1.7039 + } else { 1.7040 + if (!doTransform && 1.7041 + bounds.IsEqualEdges(aFrame->GetVisualOverflowRect()) && 1.7042 + bounds.IsEqualEdges(aFrame->GetScrollableOverflowRect())) { 1.7043 + return u; 1.7044 + } 1.7045 + } 1.7046 + const nsStyleDisplay* disp = aFrame->StyleDisplay(); 1.7047 + nsIAtom* fType = aFrame->GetType(); 1.7048 + if (nsFrame::ShouldApplyOverflowClipping(aFrame, disp) || 1.7049 + fType == nsGkAtoms::scrollFrame || 1.7050 + fType == nsGkAtoms::svgOuterSVGFrame) { 1.7051 + return u; 1.7052 + } 1.7053 + 1.7054 + nsRect clipPropClipRect; 1.7055 + bool hasClipPropClip = 1.7056 + aFrame->GetClipPropClipRect(disp, &clipPropClipRect, bounds.Size()); 1.7057 + 1.7058 + // Iterate over all children except pop-ups. 1.7059 + const nsIFrame::ChildListIDs skip(nsIFrame::kPopupList | 1.7060 + nsIFrame::kSelectPopupList); 1.7061 + for (nsIFrame::ChildListIterator childLists(aFrame); 1.7062 + !childLists.IsDone(); childLists.Next()) { 1.7063 + if (skip.Contains(childLists.CurrentID())) { 1.7064 + continue; 1.7065 + } 1.7066 + 1.7067 + nsFrameList children = childLists.CurrentList(); 1.7068 + for (nsFrameList::Enumerator e(children); !e.AtEnd(); e.Next()) { 1.7069 + nsIFrame* child = e.get(); 1.7070 + // Note that passing |true| for aApplyTransform when 1.7071 + // child->Preserves3D() is incorrect if our aApplyTransform is 1.7072 + // false... but the opposite would be as well. This is because 1.7073 + // elements within a preserve-3d scene are always transformed up 1.7074 + // to the top of the scene. This means we don't have a 1.7075 + // mechanism for getting a transform up to an intermediate point 1.7076 + // within the scene. We choose to over-transform rather than 1.7077 + // under-transform because this is consistent with other 1.7078 + // overflow areas. 1.7079 + nsRect childRect = UnionBorderBoxes(child, true) + 1.7080 + child->GetPosition(); 1.7081 + 1.7082 + if (hasClipPropClip) { 1.7083 + // Intersect with the clip before transforming. 1.7084 + childRect.IntersectRect(childRect, clipPropClipRect); 1.7085 + } 1.7086 + 1.7087 + // Note that we transform each child separately according to 1.7088 + // aFrame's transform, and then union, which gives a different 1.7089 + // (smaller) result from unioning and then transforming the 1.7090 + // union. This doesn't match the way we handle overflow areas 1.7091 + // with 2-D transforms, though it does match the way we handle 1.7092 + // overflow areas in preserve-3d 3-D scenes. 1.7093 + if (doTransform && !child->Preserves3D()) { 1.7094 + childRect = nsDisplayTransform::TransformRect(childRect, aFrame, 1.7095 + nsPoint(0, 0), &bounds); 1.7096 + } 1.7097 + u.UnionRectEdges(u, childRect); 1.7098 + } 1.7099 + } 1.7100 + 1.7101 + return u; 1.7102 +} 1.7103 + 1.7104 +static void 1.7105 +ComputeAndIncludeOutlineArea(nsIFrame* aFrame, nsOverflowAreas& aOverflowAreas, 1.7106 + const nsSize& aNewSize) 1.7107 +{ 1.7108 + const nsStyleOutline* outline = aFrame->StyleOutline(); 1.7109 + if (outline->GetOutlineStyle() == NS_STYLE_BORDER_STYLE_NONE) { 1.7110 + return; 1.7111 + } 1.7112 + 1.7113 + nscoord width; 1.7114 + DebugOnly<bool> result = outline->GetOutlineWidth(width); 1.7115 + NS_ASSERTION(result, "GetOutlineWidth had no cached outline width"); 1.7116 + if (width <= 0) { 1.7117 + return; 1.7118 + } 1.7119 + 1.7120 + // When the outline property is set on :-moz-anonymous-block or 1.7121 + // :-moz-anonymous-positioned-block pseudo-elements, it inherited 1.7122 + // that outline from the inline that was broken because it 1.7123 + // contained a block. In that case, we don't want a really wide 1.7124 + // outline if the block inside the inline is narrow, so union the 1.7125 + // actual contents of the anonymous blocks. 1.7126 + nsIFrame *frameForArea = aFrame; 1.7127 + do { 1.7128 + nsIAtom *pseudoType = frameForArea->StyleContext()->GetPseudo(); 1.7129 + if (pseudoType != nsCSSAnonBoxes::mozAnonymousBlock && 1.7130 + pseudoType != nsCSSAnonBoxes::mozAnonymousPositionedBlock) 1.7131 + break; 1.7132 + // If we're done, we really want it and all its later siblings. 1.7133 + frameForArea = frameForArea->GetFirstPrincipalChild(); 1.7134 + NS_ASSERTION(frameForArea, "anonymous block with no children?"); 1.7135 + } while (frameForArea); 1.7136 + 1.7137 + // Find the union of the border boxes of all descendants, or in 1.7138 + // the block-in-inline case, all descendants we care about. 1.7139 + // 1.7140 + // Note that the interesting perspective-related cases are taken 1.7141 + // care of by the code that handles those issues for overflow 1.7142 + // calling FinishAndStoreOverflow again, which in turn calls this 1.7143 + // function again. We still need to deal with preserve-3d a bit. 1.7144 + nsRect innerRect; 1.7145 + if (frameForArea == aFrame) { 1.7146 + innerRect = UnionBorderBoxes(aFrame, false, &aNewSize, &aOverflowAreas); 1.7147 + } else { 1.7148 + for (; frameForArea; frameForArea = frameForArea->GetNextSibling()) { 1.7149 + nsRect r(UnionBorderBoxes(frameForArea, true)); 1.7150 + 1.7151 + // Adjust for offsets transforms up to aFrame's pre-transform 1.7152 + // (i.e., normal) coordinate space; see comments in 1.7153 + // UnionBorderBoxes for some of the subtlety here. 1.7154 + for (nsIFrame *f = frameForArea, *parent = f->GetParent(); 1.7155 + /* see middle of loop */; 1.7156 + f = parent, parent = f->GetParent()) { 1.7157 + r += f->GetPosition(); 1.7158 + if (parent == aFrame) { 1.7159 + break; 1.7160 + } 1.7161 + if (parent->IsTransformed() && !f->Preserves3D()) { 1.7162 + r = nsDisplayTransform::TransformRect(r, parent, nsPoint(0, 0)); 1.7163 + } 1.7164 + } 1.7165 + 1.7166 + innerRect.UnionRect(innerRect, r); 1.7167 + } 1.7168 + } 1.7169 + 1.7170 + aFrame->Properties().Set(nsIFrame::OutlineInnerRectProperty(), 1.7171 + new nsRect(innerRect)); 1.7172 + 1.7173 + nscoord offset = outline->mOutlineOffset; 1.7174 + nscoord inflateBy = std::max(width + offset, 0); 1.7175 + 1.7176 + // Keep this code (and the storing of properties just above) in 1.7177 + // sync with GetOutlineInnerRect in nsCSSRendering.cpp. 1.7178 + nsRect outerRect(innerRect); 1.7179 + outerRect.Inflate(inflateBy, inflateBy); 1.7180 + 1.7181 + nsRect& vo = aOverflowAreas.VisualOverflow(); 1.7182 + vo.UnionRectEdges(vo, outerRect); 1.7183 +} 1.7184 + 1.7185 +bool 1.7186 +nsIFrame::FinishAndStoreOverflow(nsOverflowAreas& aOverflowAreas, 1.7187 + nsSize aNewSize, nsSize* aOldSize) 1.7188 +{ 1.7189 + NS_ASSERTION(FrameMaintainsOverflow(this), 1.7190 + "Don't call - overflow rects not maintained on these SVG frames"); 1.7191 + 1.7192 + nsRect bounds(nsPoint(0, 0), aNewSize); 1.7193 + // Store the passed in overflow area if we are a preserve-3d frame or we have 1.7194 + // a transform, and it's not just the frame bounds. 1.7195 + if (Preserves3D() || HasPerspective() || IsTransformed()) { 1.7196 + if (!aOverflowAreas.VisualOverflow().IsEqualEdges(bounds) || 1.7197 + !aOverflowAreas.ScrollableOverflow().IsEqualEdges(bounds)) { 1.7198 + 1.7199 + nsOverflowAreas* initial = 1.7200 + static_cast<nsOverflowAreas*>(Properties().Get(nsIFrame::InitialOverflowProperty())); 1.7201 + if (!initial) { 1.7202 + Properties().Set(nsIFrame::InitialOverflowProperty(), 1.7203 + new nsOverflowAreas(aOverflowAreas)); 1.7204 + } else if (initial != &aOverflowAreas) { 1.7205 + *initial = aOverflowAreas; 1.7206 + } 1.7207 + } 1.7208 +#ifdef DEBUG 1.7209 + Properties().Set(nsIFrame::DebugInitialOverflowPropertyApplied(), nullptr); 1.7210 +#endif 1.7211 + } else { 1.7212 +#ifdef DEBUG 1.7213 + Properties().Delete(nsIFrame::DebugInitialOverflowPropertyApplied()); 1.7214 +#endif 1.7215 + } 1.7216 + 1.7217 + // This is now called FinishAndStoreOverflow() instead of 1.7218 + // StoreOverflow() because frame-generic ways of adding overflow 1.7219 + // can happen here, e.g. CSS2 outline and native theme. 1.7220 + // If the overflow area width or height is nscoord_MAX, then a 1.7221 + // saturating union may have encounted an overflow, so the overflow may not 1.7222 + // contain the frame border-box. Don't warn in that case. 1.7223 + // Don't warn for SVG either, since SVG doesn't need the overflow area 1.7224 + // to contain the frame bounds. 1.7225 + NS_FOR_FRAME_OVERFLOW_TYPES(otype) { 1.7226 + DebugOnly<nsRect*> r = &aOverflowAreas.Overflow(otype); 1.7227 + NS_ASSERTION(aNewSize.width == 0 || aNewSize.height == 0 || 1.7228 + r->width == nscoord_MAX || r->height == nscoord_MAX || 1.7229 + (mState & NS_FRAME_SVG_LAYOUT) || 1.7230 + r->Contains(nsRect(nsPoint(0,0), aNewSize)), 1.7231 + "Computed overflow area must contain frame bounds"); 1.7232 + } 1.7233 + 1.7234 + // If we clip our children, clear accumulated overflow area. The 1.7235 + // children are actually clipped to the padding-box, but since the 1.7236 + // overflow area should include the entire border-box, just set it to 1.7237 + // the border-box here. 1.7238 + const nsStyleDisplay* disp = StyleDisplay(); 1.7239 + NS_ASSERTION((disp->mOverflowY == NS_STYLE_OVERFLOW_CLIP) == 1.7240 + (disp->mOverflowX == NS_STYLE_OVERFLOW_CLIP), 1.7241 + "If one overflow is clip, the other should be too"); 1.7242 + if (nsFrame::ShouldApplyOverflowClipping(this, disp)) { 1.7243 + // The contents are actually clipped to the padding area 1.7244 + aOverflowAreas.SetAllTo(bounds); 1.7245 + } 1.7246 + 1.7247 + // Overflow area must always include the frame's top-left and bottom-right, 1.7248 + // even if the frame rect is empty (so we can scroll to those positions). 1.7249 + // Pending a real fix for bug 426879, don't do this for inline frames 1.7250 + // with zero width. 1.7251 + // Do not do this for SVG either, since it will usually massively increase 1.7252 + // the area unnecessarily. 1.7253 + if ((aNewSize.width != 0 || !IsInlineFrame(this)) && 1.7254 + !(GetStateBits() & NS_FRAME_SVG_LAYOUT)) { 1.7255 + NS_FOR_FRAME_OVERFLOW_TYPES(otype) { 1.7256 + nsRect& o = aOverflowAreas.Overflow(otype); 1.7257 + o.UnionRectEdges(o, bounds); 1.7258 + } 1.7259 + } 1.7260 + 1.7261 + // Note that NS_STYLE_OVERFLOW_CLIP doesn't clip the frame background, 1.7262 + // so we add theme background overflow here so it's not clipped. 1.7263 + if (!IsBoxWrapped() && IsThemed(disp)) { 1.7264 + nsRect r(bounds); 1.7265 + nsPresContext *presContext = PresContext(); 1.7266 + if (presContext->GetTheme()-> 1.7267 + GetWidgetOverflow(presContext->DeviceContext(), this, 1.7268 + disp->mAppearance, &r)) { 1.7269 + nsRect& vo = aOverflowAreas.VisualOverflow(); 1.7270 + vo.UnionRectEdges(vo, r); 1.7271 + } 1.7272 + } 1.7273 + 1.7274 + ComputeAndIncludeOutlineArea(this, aOverflowAreas, aNewSize); 1.7275 + 1.7276 + // Nothing in here should affect scrollable overflow. 1.7277 + aOverflowAreas.VisualOverflow() = 1.7278 + ComputeEffectsRect(this, aOverflowAreas.VisualOverflow(), aNewSize); 1.7279 + 1.7280 + // Absolute position clipping 1.7281 + nsRect clipPropClipRect; 1.7282 + bool hasClipPropClip = GetClipPropClipRect(disp, &clipPropClipRect, aNewSize); 1.7283 + if (hasClipPropClip) { 1.7284 + NS_FOR_FRAME_OVERFLOW_TYPES(otype) { 1.7285 + nsRect& o = aOverflowAreas.Overflow(otype); 1.7286 + o.IntersectRect(o, clipPropClipRect); 1.7287 + } 1.7288 + } 1.7289 + 1.7290 + /* If we're transformed, transform the overflow rect by the current transformation. */ 1.7291 + bool hasTransform = IsTransformed(); 1.7292 + nsSize oldSize = aOldSize ? *aOldSize : mRect.Size(); 1.7293 + bool sizeChanged = (oldSize != aNewSize); 1.7294 + if (hasTransform) { 1.7295 + Properties().Set(nsIFrame::PreTransformOverflowAreasProperty(), 1.7296 + new nsOverflowAreas(aOverflowAreas)); 1.7297 + /* Since our size might not actually have been computed yet, we need to make sure that we use the 1.7298 + * correct dimensions by overriding the stored bounding rectangle with the value the caller has 1.7299 + * ensured us we'll use. 1.7300 + */ 1.7301 + nsRect newBounds(nsPoint(0, 0), aNewSize); 1.7302 + // Transform affects both overflow areas. 1.7303 + NS_FOR_FRAME_OVERFLOW_TYPES(otype) { 1.7304 + nsRect& o = aOverflowAreas.Overflow(otype); 1.7305 + o = nsDisplayTransform::TransformRect(o, this, nsPoint(0, 0), &newBounds); 1.7306 + } 1.7307 + if (Preserves3DChildren()) { 1.7308 + ComputePreserve3DChildrenOverflow(aOverflowAreas, newBounds); 1.7309 + } else if (sizeChanged && ChildrenHavePerspective()) { 1.7310 + RecomputePerspectiveChildrenOverflow(this->StyleContext(), &newBounds); 1.7311 + } 1.7312 + } else { 1.7313 + Properties().Delete(nsIFrame::PreTransformOverflowAreasProperty()); 1.7314 + if (ChildrenHavePerspective() && sizeChanged) { 1.7315 + nsRect newBounds(nsPoint(0, 0), aNewSize); 1.7316 + RecomputePerspectiveChildrenOverflow(this->StyleContext(), &newBounds); 1.7317 + } 1.7318 + } 1.7319 + 1.7320 + bool anyOverflowChanged; 1.7321 + if (aOverflowAreas != nsOverflowAreas(bounds, bounds)) { 1.7322 + anyOverflowChanged = SetOverflowAreas(aOverflowAreas); 1.7323 + } else { 1.7324 + anyOverflowChanged = ClearOverflowRects(); 1.7325 + } 1.7326 + 1.7327 + if (anyOverflowChanged) { 1.7328 + nsSVGEffects::InvalidateDirectRenderingObservers(this); 1.7329 + } 1.7330 + return anyOverflowChanged; 1.7331 +} 1.7332 + 1.7333 +void 1.7334 +nsIFrame::RecomputePerspectiveChildrenOverflow(const nsStyleContext* aStartStyle, const nsRect* aBounds) 1.7335 +{ 1.7336 + // Children may check our size when getting our transform, make sure it's valid. 1.7337 + nsSize oldSize = GetSize(); 1.7338 + if (aBounds) { 1.7339 + SetSize(aBounds->Size()); 1.7340 + } 1.7341 + nsIFrame::ChildListIterator lists(this); 1.7342 + for (; !lists.IsDone(); lists.Next()) { 1.7343 + nsFrameList::Enumerator childFrames(lists.CurrentList()); 1.7344 + for (; !childFrames.AtEnd(); childFrames.Next()) { 1.7345 + nsIFrame* child = childFrames.get(); 1.7346 + if (!FrameMaintainsOverflow(child)) { 1.7347 + continue; // frame does not maintain overflow rects 1.7348 + } 1.7349 + if (child->HasPerspective()) { 1.7350 + nsOverflowAreas* overflow = 1.7351 + static_cast<nsOverflowAreas*>(child->Properties().Get(nsIFrame::InitialOverflowProperty())); 1.7352 + nsRect bounds(nsPoint(0, 0), child->GetSize()); 1.7353 + if (overflow) { 1.7354 + nsOverflowAreas overflowCopy = *overflow; 1.7355 + child->FinishAndStoreOverflow(overflowCopy, bounds.Size()); 1.7356 + } else { 1.7357 + nsOverflowAreas boundsOverflow; 1.7358 + boundsOverflow.SetAllTo(bounds); 1.7359 + child->FinishAndStoreOverflow(boundsOverflow, bounds.Size()); 1.7360 + } 1.7361 + } else if (child->StyleContext()->GetParent() == aStartStyle || 1.7362 + child->StyleContext() == aStartStyle) { 1.7363 + // If a frame is using perspective, then the size used to compute 1.7364 + // perspective-origin is the size of the frame belonging to its parent 1.7365 + // style context. We must find any descendant frames using our size 1.7366 + // (by recurse into frames with the same style context, or a direct 1.7367 + // child style context) to update their overflow rects too. 1.7368 + child->RecomputePerspectiveChildrenOverflow(aStartStyle, nullptr); 1.7369 + } 1.7370 + } 1.7371 + } 1.7372 + // Restore our old size just in case something depends on this elesewhere. 1.7373 + SetSize(oldSize); 1.7374 +} 1.7375 + 1.7376 +/* The overflow rects for leaf nodes in a preserve-3d hierarchy depends on 1.7377 + * the mRect value for their parents (since we use their transform, and transform 1.7378 + * depends on this for transform-origin etc). These weren't necessarily correct 1.7379 + * when we reflowed initially, so walk over all preserve-3d children and repeat the 1.7380 + * overflow calculation. 1.7381 + */ 1.7382 +static void 1.7383 +RecomputePreserve3DChildrenOverflow(nsIFrame* aFrame, const nsRect* aBounds) 1.7384 +{ 1.7385 + // Children may check our size when getting our transform, make sure it's valid. 1.7386 + nsSize oldSize = aFrame->GetSize(); 1.7387 + if (aBounds) { 1.7388 + aFrame->SetSize(aBounds->Size()); 1.7389 + } 1.7390 + nsIFrame::ChildListIterator lists(aFrame); 1.7391 + for (; !lists.IsDone(); lists.Next()) { 1.7392 + nsFrameList::Enumerator childFrames(lists.CurrentList()); 1.7393 + for (; !childFrames.AtEnd(); childFrames.Next()) { 1.7394 + nsIFrame* child = childFrames.get(); 1.7395 + if (!FrameMaintainsOverflow(child)) { 1.7396 + continue; // frame does not maintain overflow rects 1.7397 + } 1.7398 + if (child->Preserves3DChildren()) { 1.7399 + RecomputePreserve3DChildrenOverflow(child, nullptr); 1.7400 + } else if (child->Preserves3D()) { 1.7401 + nsOverflowAreas* overflow = 1.7402 + static_cast<nsOverflowAreas*>(child->Properties().Get(nsIFrame::InitialOverflowProperty())); 1.7403 + nsRect bounds(nsPoint(0, 0), child->GetSize()); 1.7404 + if (overflow) { 1.7405 + nsOverflowAreas overflowCopy = *overflow; 1.7406 + child->FinishAndStoreOverflow(overflowCopy, bounds.Size()); 1.7407 + } else { 1.7408 + nsOverflowAreas boundsOverflow; 1.7409 + boundsOverflow.SetAllTo(bounds); 1.7410 + child->FinishAndStoreOverflow(boundsOverflow, bounds.Size()); 1.7411 + } 1.7412 + } 1.7413 + } 1.7414 + } 1.7415 + // Restore our old size just in case something depends on this elesewhere. 1.7416 + aFrame->SetSize(oldSize); 1.7417 + 1.7418 + // Only repeat computing our overflow in recursive calls since the initial caller is still 1.7419 + // in the middle of doing this and we don't want an infinite loop. 1.7420 + if (!aBounds) { 1.7421 + nsOverflowAreas* overflow = 1.7422 + static_cast<nsOverflowAreas*>(aFrame->Properties().Get(nsIFrame::InitialOverflowProperty())); 1.7423 + nsRect bounds(nsPoint(0, 0), aFrame->GetSize()); 1.7424 + if (overflow) { 1.7425 + nsOverflowAreas overflowCopy = *overflow; 1.7426 + overflowCopy.UnionAllWith(bounds); 1.7427 + aFrame->FinishAndStoreOverflow(overflowCopy, bounds.Size()); 1.7428 + } else { 1.7429 + nsOverflowAreas boundsOverflow; 1.7430 + boundsOverflow.SetAllTo(bounds); 1.7431 + aFrame->FinishAndStoreOverflow(boundsOverflow, bounds.Size()); 1.7432 + } 1.7433 + } 1.7434 +} 1.7435 + 1.7436 +void 1.7437 +nsIFrame::ComputePreserve3DChildrenOverflow(nsOverflowAreas& aOverflowAreas, const nsRect& aBounds) 1.7438 +{ 1.7439 + // When we are preserving 3d we need to iterate over all children separately. 1.7440 + // If the child also preserves 3d then their overflow will already been in our 1.7441 + // coordinate space, otherwise we need to transform. 1.7442 + 1.7443 + // If we're the top frame in a preserve 3d chain then we need to recalculate the overflow 1.7444 + // areas of all our children since they will have used our size/offset which was invalid at 1.7445 + // the time. 1.7446 + if (!Preserves3D()) { 1.7447 + RecomputePreserve3DChildrenOverflow(this, &aBounds); 1.7448 + } 1.7449 + 1.7450 + nsRect childVisual; 1.7451 + nsRect childScrollable; 1.7452 + nsIFrame::ChildListIterator lists(this); 1.7453 + for (; !lists.IsDone(); lists.Next()) { 1.7454 + nsFrameList::Enumerator childFrames(lists.CurrentList()); 1.7455 + for (; !childFrames.AtEnd(); childFrames.Next()) { 1.7456 + nsIFrame* child = childFrames.get(); 1.7457 + nsPoint offset = child->GetPosition(); 1.7458 + nsRect visual = child->GetVisualOverflowRect(); 1.7459 + nsRect scrollable = child->GetScrollableOverflowRect(); 1.7460 + visual.MoveBy(offset); 1.7461 + scrollable.MoveBy(offset); 1.7462 + if (child->Preserves3D()) { 1.7463 + childVisual = childVisual.Union(visual); 1.7464 + childScrollable = childScrollable.Union(scrollable); 1.7465 + } else { 1.7466 + childVisual = 1.7467 + childVisual.Union(nsDisplayTransform::TransformRect(visual, 1.7468 + this, nsPoint(0,0), &aBounds)); 1.7469 + childScrollable = 1.7470 + childScrollable.Union(nsDisplayTransform::TransformRect(scrollable, 1.7471 + this, nsPoint(0,0), &aBounds)); 1.7472 + } 1.7473 + } 1.7474 + } 1.7475 + 1.7476 + aOverflowAreas.Overflow(eVisualOverflow) = aOverflowAreas.Overflow(eVisualOverflow).Union(childVisual); 1.7477 + aOverflowAreas.Overflow(eScrollableOverflow) = aOverflowAreas.Overflow(eScrollableOverflow).Union(childScrollable); 1.7478 +} 1.7479 + 1.7480 +void 1.7481 +nsFrame::ConsiderChildOverflow(nsOverflowAreas& aOverflowAreas, 1.7482 + nsIFrame* aChildFrame) 1.7483 +{ 1.7484 + aOverflowAreas.UnionWith(aChildFrame->GetOverflowAreas() + 1.7485 + aChildFrame->GetPosition()); 1.7486 +} 1.7487 + 1.7488 +/** 1.7489 + * This function takes a frame that is part of a block-in-inline split, 1.7490 + * and _if_ that frame is an anonymous block created by an ib split it 1.7491 + * returns the block's preceding inline. This is needed because the 1.7492 + * split inline's style context is the parent of the anonymous block's 1.7493 + * style context. 1.7494 + * 1.7495 + * If aFrame is not an anonymous block, null is returned. 1.7496 + */ 1.7497 +static nsIFrame* 1.7498 +GetIBSplitSiblingForAnonymousBlock(const nsIFrame* aFrame) 1.7499 +{ 1.7500 + NS_PRECONDITION(aFrame, "Must have a non-null frame!"); 1.7501 + NS_ASSERTION(aFrame->GetStateBits() & NS_FRAME_PART_OF_IBSPLIT, 1.7502 + "GetIBSplitSibling should only be called on ib-split frames"); 1.7503 + 1.7504 + nsIAtom* type = aFrame->StyleContext()->GetPseudo(); 1.7505 + if (type != nsCSSAnonBoxes::mozAnonymousBlock && 1.7506 + type != nsCSSAnonBoxes::mozAnonymousPositionedBlock) { 1.7507 + // it's not an anonymous block 1.7508 + return nullptr; 1.7509 + } 1.7510 + 1.7511 + // Find the first continuation of the frame. (Ugh. This ends up 1.7512 + // being O(N^2) when it is called O(N) times.) 1.7513 + aFrame = aFrame->FirstContinuation(); 1.7514 + 1.7515 + /* 1.7516 + * Now look up the nsGkAtoms::IBSplitPrevSibling 1.7517 + * property. 1.7518 + */ 1.7519 + nsIFrame *ibSplitSibling = static_cast<nsIFrame*> 1.7520 + (aFrame->Properties().Get(nsIFrame::IBSplitPrevSibling())); 1.7521 + NS_ASSERTION(ibSplitSibling, "Broken frame tree?"); 1.7522 + return ibSplitSibling; 1.7523 +} 1.7524 + 1.7525 +/** 1.7526 + * Get the parent, corrected for the mangled frame tree resulting from 1.7527 + * having a block within an inline. The result only differs from the 1.7528 + * result of |GetParent| when |GetParent| returns an anonymous block 1.7529 + * that was created for an element that was 'display: inline' because 1.7530 + * that element contained a block. 1.7531 + * 1.7532 + * Also skip anonymous scrolled-content parents; inherit directly from the 1.7533 + * outer scroll frame. 1.7534 + */ 1.7535 +static nsIFrame* 1.7536 +GetCorrectedParent(const nsIFrame* aFrame) 1.7537 +{ 1.7538 + nsIFrame *parent = aFrame->GetParent(); 1.7539 + if (!parent) { 1.7540 + return nullptr; 1.7541 + } 1.7542 + 1.7543 + // Outer tables are always anon boxes; if we're in here for an outer 1.7544 + // table, that actually means its the _inner_ table that wants to 1.7545 + // know its parent. So get the pseudo of the inner in that case. 1.7546 + nsIAtom* pseudo = aFrame->StyleContext()->GetPseudo(); 1.7547 + if (pseudo == nsCSSAnonBoxes::tableOuter) { 1.7548 + pseudo = aFrame->GetFirstPrincipalChild()->StyleContext()->GetPseudo(); 1.7549 + } 1.7550 + return nsFrame::CorrectStyleParentFrame(parent, pseudo); 1.7551 +} 1.7552 + 1.7553 +/* static */ 1.7554 +nsIFrame* 1.7555 +nsFrame::CorrectStyleParentFrame(nsIFrame* aProspectiveParent, 1.7556 + nsIAtom* aChildPseudo) 1.7557 +{ 1.7558 + NS_PRECONDITION(aProspectiveParent, "Must have a prospective parent"); 1.7559 + 1.7560 + // Anon boxes are parented to their actual parent already, except 1.7561 + // for non-elements. Those should not be treated as an anon box. 1.7562 + if (aChildPseudo && aChildPseudo != nsCSSAnonBoxes::mozNonElement && 1.7563 + nsCSSAnonBoxes::IsAnonBox(aChildPseudo)) { 1.7564 + NS_ASSERTION(aChildPseudo != nsCSSAnonBoxes::mozAnonymousBlock && 1.7565 + aChildPseudo != nsCSSAnonBoxes::mozAnonymousPositionedBlock, 1.7566 + "Should have dealt with kids that have " 1.7567 + "NS_FRAME_PART_OF_IBSPLIT elsewhere"); 1.7568 + return aProspectiveParent; 1.7569 + } 1.7570 + 1.7571 + // Otherwise, walk up out of all anon boxes. For placeholder frames, walk out 1.7572 + // of all pseudo-elements as well. Otherwise ReparentStyleContext could cause 1.7573 + // style data to be out of sync with the frame tree. 1.7574 + nsIFrame* parent = aProspectiveParent; 1.7575 + do { 1.7576 + if (parent->GetStateBits() & NS_FRAME_PART_OF_IBSPLIT) { 1.7577 + nsIFrame* sibling = GetIBSplitSiblingForAnonymousBlock(parent); 1.7578 + 1.7579 + if (sibling) { 1.7580 + // |parent| was a block in an {ib} split; use the inline as 1.7581 + // |the style parent. 1.7582 + parent = sibling; 1.7583 + } 1.7584 + } 1.7585 + 1.7586 + nsIAtom* parentPseudo = parent->StyleContext()->GetPseudo(); 1.7587 + if (!parentPseudo || 1.7588 + (!nsCSSAnonBoxes::IsAnonBox(parentPseudo) && 1.7589 + // nsPlaceholderFrame pases in nsGkAtoms::placeholderFrame for 1.7590 + // aChildPseudo (even though that's not a valid pseudo-type) just to 1.7591 + // trigger this behavior of walking up to the nearest non-pseudo 1.7592 + // ancestor. 1.7593 + aChildPseudo != nsGkAtoms::placeholderFrame)) { 1.7594 + return parent; 1.7595 + } 1.7596 + 1.7597 + parent = parent->GetParent(); 1.7598 + } while (parent); 1.7599 + 1.7600 + if (aProspectiveParent->StyleContext()->GetPseudo() == 1.7601 + nsCSSAnonBoxes::viewportScroll) { 1.7602 + // aProspectiveParent is the scrollframe for a viewport 1.7603 + // and the kids are the anonymous scrollbars 1.7604 + return aProspectiveParent; 1.7605 + } 1.7606 + 1.7607 + // We can get here if the root element is absolutely positioned. 1.7608 + // We can't test for this very accurately, but it can only happen 1.7609 + // when the prospective parent is a canvas frame. 1.7610 + NS_ASSERTION(aProspectiveParent->GetType() == nsGkAtoms::canvasFrame, 1.7611 + "Should have found a parent before this"); 1.7612 + return nullptr; 1.7613 +} 1.7614 + 1.7615 +nsIFrame* 1.7616 +nsFrame::DoGetParentStyleContextFrame() const 1.7617 +{ 1.7618 + if (mContent && !mContent->GetParent() && 1.7619 + !StyleContext()->GetPseudo()) { 1.7620 + // we're a frame for the root. We have no style context parent. 1.7621 + return nullptr; 1.7622 + } 1.7623 + 1.7624 + if (!(mState & NS_FRAME_OUT_OF_FLOW)) { 1.7625 + /* 1.7626 + * If this frame is an anonymous block created when an inline with a block 1.7627 + * inside it got split, then the parent style context is on its preceding 1.7628 + * inline. We can get to it using GetIBSplitSiblingForAnonymousBlock. 1.7629 + */ 1.7630 + if (mState & NS_FRAME_PART_OF_IBSPLIT) { 1.7631 + nsIFrame* ibSplitSibling = GetIBSplitSiblingForAnonymousBlock(this); 1.7632 + if (ibSplitSibling) { 1.7633 + return ibSplitSibling; 1.7634 + } 1.7635 + } 1.7636 + 1.7637 + // If this frame is one of the blocks that split an inline, we must 1.7638 + // return the "special" inline parent, i.e., the parent that this 1.7639 + // frame would have if we didn't mangle the frame structure. 1.7640 + return GetCorrectedParent(this); 1.7641 + } 1.7642 + 1.7643 + // We're an out-of-flow frame. For out-of-flow frames, we must 1.7644 + // resolve underneath the placeholder's parent. The placeholder is 1.7645 + // reached from the first-in-flow. 1.7646 + nsIFrame* placeholder = PresContext()->FrameManager()-> 1.7647 + GetPlaceholderFrameFor(FirstInFlow()); 1.7648 + if (!placeholder) { 1.7649 + NS_NOTREACHED("no placeholder frame for out-of-flow frame"); 1.7650 + return GetCorrectedParent(this); 1.7651 + } 1.7652 + return placeholder->GetParentStyleContextFrame(); 1.7653 +} 1.7654 + 1.7655 +void 1.7656 +nsFrame::GetLastLeaf(nsPresContext* aPresContext, nsIFrame **aFrame) 1.7657 +{ 1.7658 + if (!aFrame || !*aFrame) 1.7659 + return; 1.7660 + nsIFrame *child = *aFrame; 1.7661 + //if we are a block frame then go for the last line of 'this' 1.7662 + while (1){ 1.7663 + child = child->GetFirstPrincipalChild(); 1.7664 + if (!child) 1.7665 + return;//nothing to do 1.7666 + nsIFrame* siblingFrame; 1.7667 + nsIContent* content; 1.7668 + //ignore anonymous elements, e.g. mozTableAdd* mozTableRemove* 1.7669 + //see bug 278197 comment #12 #13 for details 1.7670 + while ((siblingFrame = child->GetNextSibling()) && 1.7671 + (content = siblingFrame->GetContent()) && 1.7672 + !content->IsRootOfNativeAnonymousSubtree()) 1.7673 + child = siblingFrame; 1.7674 + *aFrame = child; 1.7675 + } 1.7676 +} 1.7677 + 1.7678 +void 1.7679 +nsFrame::GetFirstLeaf(nsPresContext* aPresContext, nsIFrame **aFrame) 1.7680 +{ 1.7681 + if (!aFrame || !*aFrame) 1.7682 + return; 1.7683 + nsIFrame *child = *aFrame; 1.7684 + while (1){ 1.7685 + child = child->GetFirstPrincipalChild(); 1.7686 + if (!child) 1.7687 + return;//nothing to do 1.7688 + *aFrame = child; 1.7689 + } 1.7690 +} 1.7691 + 1.7692 +/* virtual */ bool 1.7693 +nsIFrame::IsFocusable(int32_t *aTabIndex, bool aWithMouse) 1.7694 +{ 1.7695 + int32_t tabIndex = -1; 1.7696 + if (aTabIndex) { 1.7697 + *aTabIndex = -1; // Default for early return is not focusable 1.7698 + } 1.7699 + bool isFocusable = false; 1.7700 + 1.7701 + if (mContent && mContent->IsElement() && IsVisibleConsideringAncestors()) { 1.7702 + const nsStyleUserInterface* ui = StyleUserInterface(); 1.7703 + if (ui->mUserFocus != NS_STYLE_USER_FOCUS_IGNORE && 1.7704 + ui->mUserFocus != NS_STYLE_USER_FOCUS_NONE) { 1.7705 + // Pass in default tabindex of -1 for nonfocusable and 0 for focusable 1.7706 + tabIndex = 0; 1.7707 + } 1.7708 + isFocusable = mContent->IsFocusable(&tabIndex, aWithMouse); 1.7709 + if (!isFocusable && !aWithMouse && 1.7710 + GetType() == nsGkAtoms::scrollFrame && 1.7711 + mContent->IsHTML() && 1.7712 + !mContent->IsRootOfNativeAnonymousSubtree() && 1.7713 + mContent->GetParent() && 1.7714 + !mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::tabindex)) { 1.7715 + // Elements with scrollable view are focusable with script & tabbable 1.7716 + // Otherwise you couldn't scroll them with keyboard, which is 1.7717 + // an accessibility issue (e.g. Section 508 rules) 1.7718 + // However, we don't make them to be focusable with the mouse, 1.7719 + // because the extra focus outlines are considered unnecessarily ugly. 1.7720 + // When clicked on, the selection position within the element 1.7721 + // will be enough to make them keyboard scrollable. 1.7722 + nsIScrollableFrame *scrollFrame = do_QueryFrame(this); 1.7723 + if (scrollFrame && 1.7724 + scrollFrame->GetScrollbarStyles() != ScrollbarStyles(NS_STYLE_OVERFLOW_HIDDEN, NS_STYLE_OVERFLOW_HIDDEN) && 1.7725 + !scrollFrame->GetScrollRange().IsEqualEdges(nsRect(0, 0, 0, 0))) { 1.7726 + // Scroll bars will be used for overflow 1.7727 + isFocusable = true; 1.7728 + tabIndex = 0; 1.7729 + } 1.7730 + } 1.7731 + } 1.7732 + 1.7733 + if (aTabIndex) { 1.7734 + *aTabIndex = tabIndex; 1.7735 + } 1.7736 + return isFocusable; 1.7737 +} 1.7738 + 1.7739 +/** 1.7740 + * @return true if this text frame ends with a newline character which is 1.7741 + * treated as preformatted. It should return false if this is not a text frame. 1.7742 + */ 1.7743 +bool 1.7744 +nsIFrame::HasSignificantTerminalNewline() const 1.7745 +{ 1.7746 + return false; 1.7747 +} 1.7748 + 1.7749 +static uint8_t 1.7750 +ConvertSVGDominantBaselineToVerticalAlign(uint8_t aDominantBaseline) 1.7751 +{ 1.7752 + // Most of these are approximate mappings. 1.7753 + switch (aDominantBaseline) { 1.7754 + case NS_STYLE_DOMINANT_BASELINE_HANGING: 1.7755 + case NS_STYLE_DOMINANT_BASELINE_TEXT_BEFORE_EDGE: 1.7756 + return NS_STYLE_VERTICAL_ALIGN_TEXT_TOP; 1.7757 + case NS_STYLE_DOMINANT_BASELINE_TEXT_AFTER_EDGE: 1.7758 + case NS_STYLE_DOMINANT_BASELINE_IDEOGRAPHIC: 1.7759 + return NS_STYLE_VERTICAL_ALIGN_TEXT_BOTTOM; 1.7760 + case NS_STYLE_DOMINANT_BASELINE_CENTRAL: 1.7761 + case NS_STYLE_DOMINANT_BASELINE_MIDDLE: 1.7762 + case NS_STYLE_DOMINANT_BASELINE_MATHEMATICAL: 1.7763 + return NS_STYLE_VERTICAL_ALIGN_MIDDLE; 1.7764 + case NS_STYLE_DOMINANT_BASELINE_AUTO: 1.7765 + case NS_STYLE_DOMINANT_BASELINE_ALPHABETIC: 1.7766 + return NS_STYLE_VERTICAL_ALIGN_BASELINE; 1.7767 + case NS_STYLE_DOMINANT_BASELINE_USE_SCRIPT: 1.7768 + case NS_STYLE_DOMINANT_BASELINE_NO_CHANGE: 1.7769 + case NS_STYLE_DOMINANT_BASELINE_RESET_SIZE: 1.7770 + // These three should not simply map to 'baseline', but we don't 1.7771 + // support the complex baseline model that SVG 1.1 has and which 1.7772 + // css3-linebox now defines. 1.7773 + return NS_STYLE_VERTICAL_ALIGN_BASELINE; 1.7774 + default: 1.7775 + NS_NOTREACHED("unexpected aDominantBaseline value"); 1.7776 + return NS_STYLE_VERTICAL_ALIGN_BASELINE; 1.7777 + } 1.7778 +} 1.7779 + 1.7780 +uint8_t 1.7781 +nsIFrame::VerticalAlignEnum() const 1.7782 +{ 1.7783 + if (IsSVGText()) { 1.7784 + uint8_t dominantBaseline; 1.7785 + for (const nsIFrame* frame = this; frame; frame = frame->GetParent()) { 1.7786 + dominantBaseline = frame->StyleSVGReset()->mDominantBaseline; 1.7787 + if (dominantBaseline != NS_STYLE_DOMINANT_BASELINE_AUTO || 1.7788 + frame->GetType() == nsGkAtoms::svgTextFrame) { 1.7789 + break; 1.7790 + } 1.7791 + } 1.7792 + return ConvertSVGDominantBaselineToVerticalAlign(dominantBaseline); 1.7793 + } 1.7794 + 1.7795 + const nsStyleCoord& verticalAlign = StyleTextReset()->mVerticalAlign; 1.7796 + if (verticalAlign.GetUnit() == eStyleUnit_Enumerated) { 1.7797 + return verticalAlign.GetIntValue(); 1.7798 + } 1.7799 + 1.7800 + return eInvalidVerticalAlign; 1.7801 +} 1.7802 + 1.7803 +/* static */ 1.7804 +void nsFrame::FillCursorInformationFromStyle(const nsStyleUserInterface* ui, 1.7805 + nsIFrame::Cursor& aCursor) 1.7806 +{ 1.7807 + aCursor.mCursor = ui->mCursor; 1.7808 + aCursor.mHaveHotspot = false; 1.7809 + aCursor.mHotspotX = aCursor.mHotspotY = 0.0f; 1.7810 + 1.7811 + for (nsCursorImage *item = ui->mCursorArray, 1.7812 + *item_end = ui->mCursorArray + ui->mCursorArrayLength; 1.7813 + item < item_end; ++item) { 1.7814 + uint32_t status; 1.7815 + nsresult rv = item->GetImage()->GetImageStatus(&status); 1.7816 + if (NS_SUCCEEDED(rv) && (status & imgIRequest::STATUS_LOAD_COMPLETE)) { 1.7817 + // This is the one we want 1.7818 + item->GetImage()->GetImage(getter_AddRefs(aCursor.mContainer)); 1.7819 + aCursor.mHaveHotspot = item->mHaveHotspot; 1.7820 + aCursor.mHotspotX = item->mHotspotX; 1.7821 + aCursor.mHotspotY = item->mHotspotY; 1.7822 + break; 1.7823 + } 1.7824 + } 1.7825 +} 1.7826 + 1.7827 +NS_IMETHODIMP 1.7828 +nsFrame::RefreshSizeCache(nsBoxLayoutState& aState) 1.7829 +{ 1.7830 + // XXXbz this comment needs some rewriting to make sense in the 1.7831 + // post-reflow-branch world. 1.7832 + 1.7833 + // Ok we need to compute our minimum, preferred, and maximum sizes. 1.7834 + // 1) Maximum size. This is easy. Its infinite unless it is overloaded by CSS. 1.7835 + // 2) Preferred size. This is a little harder. This is the size the block would be 1.7836 + // if it were laid out on an infinite canvas. So we can get this by reflowing 1.7837 + // the block with and INTRINSIC width and height. We can also do a nice optimization 1.7838 + // for incremental reflow. If the reflow is incremental then we can pass a flag to 1.7839 + // have the block compute the preferred width for us! Preferred height can just be 1.7840 + // the minimum height; 1.7841 + // 3) Minimum size. This is a toughy. We can pass the block a flag asking for the max element 1.7842 + // size. That would give us the width. Unfortunately you can only ask for a maxElementSize 1.7843 + // during an incremental reflow. So on other reflows we will just have to use 0. 1.7844 + // The min height on the other hand is fairly easy we need to get the largest 1.7845 + // line height. This can be done with the line iterator. 1.7846 + 1.7847 + // if we do have a rendering context 1.7848 + nsresult rv = NS_OK; 1.7849 + nsRenderingContext* rendContext = aState.GetRenderingContext(); 1.7850 + if (rendContext) { 1.7851 + nsPresContext* presContext = aState.PresContext(); 1.7852 + 1.7853 + // If we don't have any HTML constraints and it's a resize, then nothing in the block 1.7854 + // could have changed, so no refresh is necessary. 1.7855 + nsBoxLayoutMetrics* metrics = BoxMetrics(); 1.7856 + if (!DoesNeedRecalc(metrics->mBlockPrefSize)) 1.7857 + return NS_OK; 1.7858 + 1.7859 + // the rect we plan to size to. 1.7860 + nsRect rect = GetRect(); 1.7861 + 1.7862 + nsMargin bp(0,0,0,0); 1.7863 + GetBorderAndPadding(bp); 1.7864 + 1.7865 + { 1.7866 + // If we're a container for font size inflation, then shrink 1.7867 + // wrapping inside of us should not apply font size inflation. 1.7868 + AutoMaybeDisableFontInflation an(this); 1.7869 + 1.7870 + metrics->mBlockPrefSize.width = 1.7871 + GetPrefWidth(rendContext) + bp.LeftRight(); 1.7872 + metrics->mBlockMinSize.width = 1.7873 + GetMinWidth(rendContext) + bp.LeftRight(); 1.7874 + } 1.7875 + 1.7876 + // do the nasty. 1.7877 + const WritingMode wm = aState.OuterReflowState() ? 1.7878 + aState.OuterReflowState()->GetWritingMode() : GetWritingMode(); 1.7879 + nsHTMLReflowMetrics desiredSize(wm); 1.7880 + rv = BoxReflow(aState, presContext, desiredSize, rendContext, 1.7881 + rect.x, rect.y, 1.7882 + metrics->mBlockPrefSize.width, NS_UNCONSTRAINEDSIZE); 1.7883 + 1.7884 + metrics->mBlockMinSize.height = 0; 1.7885 + // ok we need the max ascent of the items on the line. So to do this 1.7886 + // ask the block for its line iterator. Get the max ascent. 1.7887 + nsAutoLineIterator lines = GetLineIterator(); 1.7888 + if (lines) 1.7889 + { 1.7890 + metrics->mBlockMinSize.height = 0; 1.7891 + int count = 0; 1.7892 + nsIFrame* firstFrame = nullptr; 1.7893 + int32_t framesOnLine; 1.7894 + nsRect lineBounds; 1.7895 + uint32_t lineFlags; 1.7896 + 1.7897 + do { 1.7898 + lines->GetLine(count, &firstFrame, &framesOnLine, lineBounds, &lineFlags); 1.7899 + 1.7900 + if (lineBounds.height > metrics->mBlockMinSize.height) 1.7901 + metrics->mBlockMinSize.height = lineBounds.height; 1.7902 + 1.7903 + count++; 1.7904 + } while(firstFrame); 1.7905 + } else { 1.7906 + metrics->mBlockMinSize.height = desiredSize.Height(); 1.7907 + } 1.7908 + 1.7909 + metrics->mBlockPrefSize.height = metrics->mBlockMinSize.height; 1.7910 + 1.7911 + if (desiredSize.TopAscent() == nsHTMLReflowMetrics::ASK_FOR_BASELINE) { 1.7912 + if (!nsLayoutUtils::GetFirstLineBaseline(this, &metrics->mBlockAscent)) 1.7913 + metrics->mBlockAscent = GetBaseline(); 1.7914 + } else { 1.7915 + metrics->mBlockAscent = desiredSize.TopAscent(); 1.7916 + } 1.7917 + 1.7918 +#ifdef DEBUG_adaptor 1.7919 + printf("min=(%d,%d), pref=(%d,%d), ascent=%d\n", metrics->mBlockMinSize.width, 1.7920 + metrics->mBlockMinSize.height, 1.7921 + metrics->mBlockPrefSize.width, 1.7922 + metrics->mBlockPrefSize.height, 1.7923 + metrics->mBlockAscent); 1.7924 +#endif 1.7925 + } 1.7926 + 1.7927 + return rv; 1.7928 +} 1.7929 + 1.7930 +/* virtual */ nsILineIterator* 1.7931 +nsFrame::GetLineIterator() 1.7932 +{ 1.7933 + return nullptr; 1.7934 +} 1.7935 + 1.7936 +nsSize 1.7937 +nsFrame::GetPrefSize(nsBoxLayoutState& aState) 1.7938 +{ 1.7939 + nsSize size(0,0); 1.7940 + DISPLAY_PREF_SIZE(this, size); 1.7941 + // If the size is cached, and there are no HTML constraints that we might 1.7942 + // be depending on, then we just return the cached size. 1.7943 + nsBoxLayoutMetrics *metrics = BoxMetrics(); 1.7944 + if (!DoesNeedRecalc(metrics->mPrefSize)) { 1.7945 + return metrics->mPrefSize; 1.7946 + } 1.7947 + 1.7948 + if (IsCollapsed()) 1.7949 + return size; 1.7950 + 1.7951 + // get our size in CSS. 1.7952 + bool widthSet, heightSet; 1.7953 + bool completelyRedefined = nsIFrame::AddCSSPrefSize(this, size, widthSet, heightSet); 1.7954 + 1.7955 + // Refresh our caches with new sizes. 1.7956 + if (!completelyRedefined) { 1.7957 + RefreshSizeCache(aState); 1.7958 + nsSize blockSize = metrics->mBlockPrefSize; 1.7959 + 1.7960 + // notice we don't need to add our borders or padding 1.7961 + // in. That's because the block did it for us. 1.7962 + if (!widthSet) 1.7963 + size.width = blockSize.width; 1.7964 + if (!heightSet) 1.7965 + size.height = blockSize.height; 1.7966 + } 1.7967 + 1.7968 + metrics->mPrefSize = size; 1.7969 + return size; 1.7970 +} 1.7971 + 1.7972 +nsSize 1.7973 +nsFrame::GetMinSize(nsBoxLayoutState& aState) 1.7974 +{ 1.7975 + nsSize size(0,0); 1.7976 + DISPLAY_MIN_SIZE(this, size); 1.7977 + // Don't use the cache if we have HTMLReflowState constraints --- they might have changed 1.7978 + nsBoxLayoutMetrics *metrics = BoxMetrics(); 1.7979 + if (!DoesNeedRecalc(metrics->mMinSize)) { 1.7980 + size = metrics->mMinSize; 1.7981 + return size; 1.7982 + } 1.7983 + 1.7984 + if (IsCollapsed()) 1.7985 + return size; 1.7986 + 1.7987 + // get our size in CSS. 1.7988 + bool widthSet, heightSet; 1.7989 + bool completelyRedefined = 1.7990 + nsIFrame::AddCSSMinSize(aState, this, size, widthSet, heightSet); 1.7991 + 1.7992 + // Refresh our caches with new sizes. 1.7993 + if (!completelyRedefined) { 1.7994 + RefreshSizeCache(aState); 1.7995 + nsSize blockSize = metrics->mBlockMinSize; 1.7996 + 1.7997 + if (!widthSet) 1.7998 + size.width = blockSize.width; 1.7999 + if (!heightSet) 1.8000 + size.height = blockSize.height; 1.8001 + } 1.8002 + 1.8003 + metrics->mMinSize = size; 1.8004 + return size; 1.8005 +} 1.8006 + 1.8007 +nsSize 1.8008 +nsFrame::GetMaxSize(nsBoxLayoutState& aState) 1.8009 +{ 1.8010 + nsSize size(NS_INTRINSICSIZE, NS_INTRINSICSIZE); 1.8011 + DISPLAY_MAX_SIZE(this, size); 1.8012 + // Don't use the cache if we have HTMLReflowState constraints --- they might have changed 1.8013 + nsBoxLayoutMetrics *metrics = BoxMetrics(); 1.8014 + if (!DoesNeedRecalc(metrics->mMaxSize)) { 1.8015 + size = metrics->mMaxSize; 1.8016 + return size; 1.8017 + } 1.8018 + 1.8019 + if (IsCollapsed()) 1.8020 + return size; 1.8021 + 1.8022 + size = nsBox::GetMaxSize(aState); 1.8023 + metrics->mMaxSize = size; 1.8024 + 1.8025 + return size; 1.8026 +} 1.8027 + 1.8028 +nscoord 1.8029 +nsFrame::GetFlex(nsBoxLayoutState& aState) 1.8030 +{ 1.8031 + nsBoxLayoutMetrics *metrics = BoxMetrics(); 1.8032 + if (!DoesNeedRecalc(metrics->mFlex)) 1.8033 + return metrics->mFlex; 1.8034 + 1.8035 + metrics->mFlex = nsBox::GetFlex(aState); 1.8036 + 1.8037 + return metrics->mFlex; 1.8038 +} 1.8039 + 1.8040 +nscoord 1.8041 +nsFrame::GetBoxAscent(nsBoxLayoutState& aState) 1.8042 +{ 1.8043 + nsBoxLayoutMetrics *metrics = BoxMetrics(); 1.8044 + if (!DoesNeedRecalc(metrics->mAscent)) 1.8045 + return metrics->mAscent; 1.8046 + 1.8047 + if (IsCollapsed()) { 1.8048 + metrics->mAscent = 0; 1.8049 + } else { 1.8050 + // Refresh our caches with new sizes. 1.8051 + RefreshSizeCache(aState); 1.8052 + metrics->mAscent = metrics->mBlockAscent; 1.8053 + } 1.8054 + 1.8055 + return metrics->mAscent; 1.8056 +} 1.8057 + 1.8058 +nsresult 1.8059 +nsFrame::DoLayout(nsBoxLayoutState& aState) 1.8060 +{ 1.8061 + nsRect ourRect(mRect); 1.8062 + 1.8063 + nsRenderingContext* rendContext = aState.GetRenderingContext(); 1.8064 + nsPresContext* presContext = aState.PresContext(); 1.8065 + const WritingMode wm = aState.OuterReflowState() ? 1.8066 + aState.OuterReflowState()->GetWritingMode() : GetWritingMode(); 1.8067 + nsHTMLReflowMetrics desiredSize(wm); 1.8068 + nsresult rv = NS_OK; 1.8069 + 1.8070 + if (rendContext) { 1.8071 + 1.8072 + rv = BoxReflow(aState, presContext, desiredSize, rendContext, 1.8073 + ourRect.x, ourRect.y, ourRect.width, ourRect.height); 1.8074 + 1.8075 + if (IsCollapsed()) { 1.8076 + SetSize(nsSize(0, 0)); 1.8077 + } else { 1.8078 + 1.8079 + // if our child needs to be bigger. This might happend with 1.8080 + // wrapping text. There is no way to predict its height until we 1.8081 + // reflow it. Now that we know the height reshuffle upward. 1.8082 + if (desiredSize.Width() > ourRect.width || 1.8083 + desiredSize.Height() > ourRect.height) { 1.8084 + 1.8085 +#ifdef DEBUG_GROW 1.8086 + DumpBox(stdout); 1.8087 + printf(" GREW from (%d,%d) -> (%d,%d)\n", 1.8088 + ourRect.width, ourRect.height, 1.8089 + desiredSize.Width(), desiredSize.Height()); 1.8090 +#endif 1.8091 + 1.8092 + if (desiredSize.Width() > ourRect.width) 1.8093 + ourRect.width = desiredSize.Width(); 1.8094 + 1.8095 + if (desiredSize.Height() > ourRect.height) 1.8096 + ourRect.height = desiredSize.Height(); 1.8097 + } 1.8098 + 1.8099 + // ensure our size is what we think is should be. Someone could have 1.8100 + // reset the frame to be smaller or something dumb like that. 1.8101 + SetSize(ourRect.Size()); 1.8102 + } 1.8103 + } 1.8104 + 1.8105 + // Should we do this if IsCollapsed() is true? 1.8106 + nsSize size(GetSize()); 1.8107 + desiredSize.Width() = size.width; 1.8108 + desiredSize.Height() = size.height; 1.8109 + desiredSize.UnionOverflowAreasWithDesiredBounds(); 1.8110 + 1.8111 + if (HasAbsolutelyPositionedChildren()) { 1.8112 + // Set up a |reflowState| to pass into ReflowAbsoluteFrames 1.8113 + nsHTMLReflowState reflowState(aState.PresContext(), this, 1.8114 + aState.GetRenderingContext(), 1.8115 + nsSize(size.width, NS_UNCONSTRAINEDSIZE), 1.8116 + nsHTMLReflowState::DUMMY_PARENT_REFLOW_STATE); 1.8117 + 1.8118 + AddStateBits(NS_FRAME_IN_REFLOW); 1.8119 + // Set up a |reflowStatus| to pass into ReflowAbsoluteFrames 1.8120 + // (just a dummy value; hopefully that's OK) 1.8121 + nsReflowStatus reflowStatus = NS_FRAME_COMPLETE; 1.8122 + ReflowAbsoluteFrames(aState.PresContext(), desiredSize, 1.8123 + reflowState, reflowStatus); 1.8124 + RemoveStateBits(NS_FRAME_IN_REFLOW); 1.8125 + } 1.8126 + 1.8127 + nsSize oldSize(ourRect.Size()); 1.8128 + FinishAndStoreOverflow(desiredSize.mOverflowAreas, size, &oldSize); 1.8129 + 1.8130 + SyncLayout(aState); 1.8131 + 1.8132 + return rv; 1.8133 +} 1.8134 + 1.8135 +nsresult 1.8136 +nsFrame::BoxReflow(nsBoxLayoutState& aState, 1.8137 + nsPresContext* aPresContext, 1.8138 + nsHTMLReflowMetrics& aDesiredSize, 1.8139 + nsRenderingContext* aRenderingContext, 1.8140 + nscoord aX, 1.8141 + nscoord aY, 1.8142 + nscoord aWidth, 1.8143 + nscoord aHeight, 1.8144 + bool aMoveFrame) 1.8145 +{ 1.8146 + DO_GLOBAL_REFLOW_COUNT("nsBoxToBlockAdaptor"); 1.8147 + 1.8148 +#ifdef DEBUG_REFLOW 1.8149 + nsAdaptorAddIndents(); 1.8150 + printf("Reflowing: "); 1.8151 + nsFrame::ListTag(stdout, mFrame); 1.8152 + printf("\n"); 1.8153 + gIndent2++; 1.8154 +#endif 1.8155 + 1.8156 + nsBoxLayoutMetrics *metrics = BoxMetrics(); 1.8157 + nsReflowStatus status = NS_FRAME_COMPLETE; 1.8158 + 1.8159 + bool needsReflow = NS_SUBTREE_DIRTY(this); 1.8160 + 1.8161 + // if we don't need a reflow then 1.8162 + // lets see if we are already that size. Yes? then don't even reflow. We are done. 1.8163 + if (!needsReflow) { 1.8164 + 1.8165 + if (aWidth != NS_INTRINSICSIZE && aHeight != NS_INTRINSICSIZE) { 1.8166 + 1.8167 + // if the new calculated size has a 0 width or a 0 height 1.8168 + if ((metrics->mLastSize.width == 0 || metrics->mLastSize.height == 0) && (aWidth == 0 || aHeight == 0)) { 1.8169 + needsReflow = false; 1.8170 + aDesiredSize.Width() = aWidth; 1.8171 + aDesiredSize.Height() = aHeight; 1.8172 + SetSize(nsSize(aDesiredSize.Width(), aDesiredSize.Height())); 1.8173 + } else { 1.8174 + aDesiredSize.Width() = metrics->mLastSize.width; 1.8175 + aDesiredSize.Height() = metrics->mLastSize.height; 1.8176 + 1.8177 + // remove the margin. The rect of our child does not include it but our calculated size does. 1.8178 + // don't reflow if we are already the right size 1.8179 + if (metrics->mLastSize.width == aWidth && metrics->mLastSize.height == aHeight) 1.8180 + needsReflow = false; 1.8181 + else 1.8182 + needsReflow = true; 1.8183 + 1.8184 + } 1.8185 + } else { 1.8186 + // if the width or height are intrinsic alway reflow because 1.8187 + // we don't know what it should be. 1.8188 + needsReflow = true; 1.8189 + } 1.8190 + } 1.8191 + 1.8192 + // ok now reflow the child into the spacers calculated space 1.8193 + if (needsReflow) { 1.8194 + 1.8195 + aDesiredSize.Width() = 0; 1.8196 + aDesiredSize.Height() = 0; 1.8197 + 1.8198 + // create a reflow state to tell our child to flow at the given size. 1.8199 + 1.8200 + // Construct a bogus parent reflow state so that there's a usable 1.8201 + // containing block reflow state. 1.8202 + nsMargin margin(0,0,0,0); 1.8203 + GetMargin(margin); 1.8204 + 1.8205 + nsSize parentSize(aWidth, aHeight); 1.8206 + if (parentSize.height != NS_INTRINSICSIZE) 1.8207 + parentSize.height += margin.TopBottom(); 1.8208 + if (parentSize.width != NS_INTRINSICSIZE) 1.8209 + parentSize.width += margin.LeftRight(); 1.8210 + 1.8211 + nsIFrame *parentFrame = GetParent(); 1.8212 + nsFrameState savedState = parentFrame->GetStateBits(); 1.8213 + nsHTMLReflowState parentReflowState(aPresContext, parentFrame, 1.8214 + aRenderingContext, 1.8215 + parentSize, 1.8216 + nsHTMLReflowState::DUMMY_PARENT_REFLOW_STATE); 1.8217 + parentFrame->RemoveStateBits(~nsFrameState(0)); 1.8218 + parentFrame->AddStateBits(savedState); 1.8219 + 1.8220 + // This may not do very much useful, but it's probably worth trying. 1.8221 + if (parentSize.width != NS_INTRINSICSIZE) 1.8222 + parentReflowState.SetComputedWidth(std::max(parentSize.width, 0)); 1.8223 + if (parentSize.height != NS_INTRINSICSIZE) 1.8224 + parentReflowState.SetComputedHeight(std::max(parentSize.height, 0)); 1.8225 + parentReflowState.ComputedPhysicalMargin().SizeTo(0, 0, 0, 0); 1.8226 + // XXX use box methods 1.8227 + parentFrame->GetPadding(parentReflowState.ComputedPhysicalPadding()); 1.8228 + parentFrame->GetBorder(parentReflowState.ComputedPhysicalBorderPadding()); 1.8229 + parentReflowState.ComputedPhysicalBorderPadding() += 1.8230 + parentReflowState.ComputedPhysicalPadding(); 1.8231 + 1.8232 + // Construct the parent chain manually since constructing it normally 1.8233 + // messes up dimensions. 1.8234 + const nsHTMLReflowState *outerReflowState = aState.OuterReflowState(); 1.8235 + NS_ASSERTION(!outerReflowState || outerReflowState->frame != this, 1.8236 + "in and out of XUL on a single frame?"); 1.8237 + const nsHTMLReflowState* parentRS; 1.8238 + if (outerReflowState && outerReflowState->frame == parentFrame) { 1.8239 + // We're a frame (such as a text control frame) that jumps into 1.8240 + // box reflow and then straight out of it on the child frame. 1.8241 + // This means we actually have a real parent reflow state. 1.8242 + // nsLayoutUtils::InflationMinFontSizeFor used to need this to be 1.8243 + // linked up correctly for text control frames, so do so here). 1.8244 + parentRS = outerReflowState; 1.8245 + } else { 1.8246 + parentRS = &parentReflowState; 1.8247 + } 1.8248 + 1.8249 + // XXX Is it OK that this reflow state has only one ancestor? 1.8250 + // (It used to have a bogus parent, skipping all the boxes). 1.8251 + nsSize availSize(aWidth, NS_INTRINSICSIZE); 1.8252 + nsHTMLReflowState reflowState(aPresContext, *parentRS, this, 1.8253 + availSize, -1, -1, 1.8254 + nsHTMLReflowState::DUMMY_PARENT_REFLOW_STATE); 1.8255 + 1.8256 + // XXX_jwir3: This is somewhat fishy. If this is actually changing the value 1.8257 + // here (which it might be), then we should make sure that it's 1.8258 + // correct the first time around, rather than changing it later. 1.8259 + reflowState.mCBReflowState = parentRS; 1.8260 + 1.8261 + reflowState.mReflowDepth = aState.GetReflowDepth(); 1.8262 + 1.8263 + // mComputedWidth and mComputedHeight are content-box, not 1.8264 + // border-box 1.8265 + if (aWidth != NS_INTRINSICSIZE) { 1.8266 + nscoord computedWidth = 1.8267 + aWidth - reflowState.ComputedPhysicalBorderPadding().LeftRight(); 1.8268 + computedWidth = std::max(computedWidth, 0); 1.8269 + reflowState.SetComputedWidth(computedWidth); 1.8270 + } 1.8271 + 1.8272 + // Most child frames of box frames (e.g. subdocument or scroll frames) 1.8273 + // need to be constrained to the provided size and overflow as necessary. 1.8274 + // The one exception are block frames, because we need to know their 1.8275 + // natural height excluding any overflow area which may be caused by 1.8276 + // various CSS effects such as shadow or outline. 1.8277 + if (!IsFrameOfType(eBlockFrame)) { 1.8278 + if (aHeight != NS_INTRINSICSIZE) { 1.8279 + nscoord computedHeight = 1.8280 + aHeight - reflowState.ComputedPhysicalBorderPadding().TopBottom(); 1.8281 + computedHeight = std::max(computedHeight, 0); 1.8282 + reflowState.SetComputedHeight(computedHeight); 1.8283 + } else { 1.8284 + reflowState.SetComputedHeight( 1.8285 + ComputeSize(aRenderingContext, availSize, availSize.width, 1.8286 + nsSize(reflowState.ComputedPhysicalMargin().LeftRight(), 1.8287 + reflowState.ComputedPhysicalMargin().TopBottom()), 1.8288 + nsSize(reflowState.ComputedPhysicalBorderPadding().LeftRight() - 1.8289 + reflowState.ComputedPhysicalPadding().LeftRight(), 1.8290 + reflowState.ComputedPhysicalBorderPadding().TopBottom() - 1.8291 + reflowState.ComputedPhysicalPadding().TopBottom()), 1.8292 + nsSize(reflowState.ComputedPhysicalPadding().LeftRight(), 1.8293 + reflowState.ComputedPhysicalPadding().TopBottom()), 1.8294 + false).height 1.8295 + ); 1.8296 + } 1.8297 + } 1.8298 + 1.8299 + // Box layout calls SetRect before Layout, whereas non-box layout 1.8300 + // calls SetRect after Reflow. 1.8301 + // XXX Perhaps we should be doing this by twiddling the rect back to 1.8302 + // mLastSize before calling Reflow and then switching it back, but 1.8303 + // However, mLastSize can also be the size passed to BoxReflow by 1.8304 + // RefreshSizeCache, so that doesn't really make sense. 1.8305 + if (metrics->mLastSize.width != aWidth) { 1.8306 + reflowState.mFlags.mHResize = true; 1.8307 + 1.8308 + // When font size inflation is enabled, a horizontal resize 1.8309 + // requires a full reflow. See nsHTMLReflowState::InitResizeFlags 1.8310 + // for more details. 1.8311 + if (nsLayoutUtils::FontSizeInflationEnabled(aPresContext)) { 1.8312 + AddStateBits(NS_FRAME_IS_DIRTY); 1.8313 + } 1.8314 + } 1.8315 + if (metrics->mLastSize.height != aHeight) 1.8316 + reflowState.mFlags.mVResize = true; 1.8317 + 1.8318 + #ifdef DEBUG_REFLOW 1.8319 + nsAdaptorAddIndents(); 1.8320 + printf("Size=(%d,%d)\n",reflowState.ComputedWidth(), 1.8321 + reflowState.ComputedHeight()); 1.8322 + nsAdaptorAddIndents(); 1.8323 + nsAdaptorPrintReason(reflowState); 1.8324 + printf("\n"); 1.8325 + #endif 1.8326 + 1.8327 + // place the child and reflow 1.8328 + WillReflow(aPresContext); 1.8329 + 1.8330 + Reflow(aPresContext, aDesiredSize, reflowState, status); 1.8331 + 1.8332 + NS_ASSERTION(NS_FRAME_IS_COMPLETE(status), "bad status"); 1.8333 + 1.8334 + uint32_t layoutFlags = aState.LayoutFlags(); 1.8335 + nsContainerFrame::FinishReflowChild(this, aPresContext, aDesiredSize, 1.8336 + &reflowState, aX, aY, layoutFlags | NS_FRAME_NO_MOVE_FRAME); 1.8337 + 1.8338 + // Save the ascent. (bug 103925) 1.8339 + if (IsCollapsed()) { 1.8340 + metrics->mAscent = 0; 1.8341 + } else { 1.8342 + if (aDesiredSize.TopAscent() == nsHTMLReflowMetrics::ASK_FOR_BASELINE) { 1.8343 + if (!nsLayoutUtils::GetFirstLineBaseline(this, &metrics->mAscent)) 1.8344 + metrics->mAscent = GetBaseline(); 1.8345 + } else 1.8346 + metrics->mAscent = aDesiredSize.TopAscent(); 1.8347 + } 1.8348 + 1.8349 + } else { 1.8350 + aDesiredSize.SetTopAscent(metrics->mBlockAscent); 1.8351 + } 1.8352 + 1.8353 +#ifdef DEBUG_REFLOW 1.8354 + if (aHeight != NS_INTRINSICSIZE && aDesiredSize.Height() != aHeight) 1.8355 + { 1.8356 + nsAdaptorAddIndents(); 1.8357 + printf("*****got taller!*****\n"); 1.8358 + 1.8359 + } 1.8360 + if (aWidth != NS_INTRINSICSIZE && aDesiredSize.Width() != aWidth) 1.8361 + { 1.8362 + nsAdaptorAddIndents(); 1.8363 + printf("*****got wider!******\n"); 1.8364 + 1.8365 + } 1.8366 +#endif 1.8367 + 1.8368 + if (aWidth == NS_INTRINSICSIZE) 1.8369 + aWidth = aDesiredSize.Width(); 1.8370 + 1.8371 + if (aHeight == NS_INTRINSICSIZE) 1.8372 + aHeight = aDesiredSize.Height(); 1.8373 + 1.8374 + metrics->mLastSize.width = aDesiredSize.Width(); 1.8375 + metrics->mLastSize.height = aDesiredSize.Height(); 1.8376 + 1.8377 +#ifdef DEBUG_REFLOW 1.8378 + gIndent2--; 1.8379 +#endif 1.8380 + 1.8381 + return NS_OK; 1.8382 +} 1.8383 + 1.8384 +static void 1.8385 +DestroyBoxMetrics(void* aPropertyValue) 1.8386 +{ 1.8387 + delete static_cast<nsBoxLayoutMetrics*>(aPropertyValue); 1.8388 +} 1.8389 + 1.8390 +NS_DECLARE_FRAME_PROPERTY(BoxMetricsProperty, DestroyBoxMetrics) 1.8391 + 1.8392 +nsBoxLayoutMetrics* 1.8393 +nsFrame::BoxMetrics() const 1.8394 +{ 1.8395 + nsBoxLayoutMetrics* metrics = 1.8396 + static_cast<nsBoxLayoutMetrics*>(Properties().Get(BoxMetricsProperty())); 1.8397 + NS_ASSERTION(metrics, "A box layout method was called but InitBoxMetrics was never called"); 1.8398 + return metrics; 1.8399 +} 1.8400 + 1.8401 +/* static */ void 1.8402 +nsIFrame::AddInPopupStateBitToDescendants(nsIFrame* aFrame) 1.8403 +{ 1.8404 + aFrame->AddStateBits(NS_FRAME_IN_POPUP); 1.8405 + 1.8406 + nsAutoTArray<nsIFrame::ChildList,4> childListArray; 1.8407 + aFrame->GetCrossDocChildLists(&childListArray); 1.8408 + 1.8409 + nsIFrame::ChildListArrayIterator lists(childListArray); 1.8410 + for (; !lists.IsDone(); lists.Next()) { 1.8411 + nsFrameList::Enumerator childFrames(lists.CurrentList()); 1.8412 + for (; !childFrames.AtEnd(); childFrames.Next()) { 1.8413 + AddInPopupStateBitToDescendants(childFrames.get()); 1.8414 + } 1.8415 + } 1.8416 +} 1.8417 + 1.8418 +/* static */ void 1.8419 +nsIFrame::RemoveInPopupStateBitFromDescendants(nsIFrame* aFrame) 1.8420 +{ 1.8421 + if (!aFrame->HasAnyStateBits(NS_FRAME_IN_POPUP) || 1.8422 + nsLayoutUtils::IsPopup(aFrame)) { 1.8423 + return; 1.8424 + } 1.8425 + 1.8426 + aFrame->RemoveStateBits(NS_FRAME_IN_POPUP); 1.8427 + 1.8428 + nsAutoTArray<nsIFrame::ChildList,4> childListArray; 1.8429 + aFrame->GetCrossDocChildLists(&childListArray); 1.8430 + 1.8431 + nsIFrame::ChildListArrayIterator lists(childListArray); 1.8432 + for (; !lists.IsDone(); lists.Next()) { 1.8433 + nsFrameList::Enumerator childFrames(lists.CurrentList()); 1.8434 + for (; !childFrames.AtEnd(); childFrames.Next()) { 1.8435 + RemoveInPopupStateBitFromDescendants(childFrames.get()); 1.8436 + } 1.8437 + } 1.8438 +} 1.8439 + 1.8440 +void 1.8441 +nsFrame::SetParent(nsIFrame* aParent) 1.8442 +{ 1.8443 + bool wasBoxWrapped = IsBoxWrapped(); 1.8444 + mParent = aParent; 1.8445 + if (!wasBoxWrapped && IsBoxWrapped()) { 1.8446 + InitBoxMetrics(true); 1.8447 + } else if (wasBoxWrapped && !IsBoxWrapped()) { 1.8448 + Properties().Delete(BoxMetricsProperty()); 1.8449 + } 1.8450 + 1.8451 + if (GetStateBits() & (NS_FRAME_HAS_VIEW | NS_FRAME_HAS_CHILD_WITH_VIEW)) { 1.8452 + for (nsIFrame* f = aParent; 1.8453 + f && !(f->GetStateBits() & NS_FRAME_HAS_CHILD_WITH_VIEW); 1.8454 + f = f->GetParent()) { 1.8455 + f->AddStateBits(NS_FRAME_HAS_CHILD_WITH_VIEW); 1.8456 + } 1.8457 + } 1.8458 + 1.8459 + if (HasInvalidFrameInSubtree()) { 1.8460 + for (nsIFrame* f = aParent; 1.8461 + f && !f->HasAnyStateBits(NS_FRAME_DESCENDANT_NEEDS_PAINT); 1.8462 + f = nsLayoutUtils::GetCrossDocParentFrame(f)) { 1.8463 + f->AddStateBits(NS_FRAME_DESCENDANT_NEEDS_PAINT); 1.8464 + } 1.8465 + } 1.8466 + 1.8467 + if (aParent->HasAnyStateBits(NS_FRAME_IN_POPUP)) { 1.8468 + AddInPopupStateBitToDescendants(this); 1.8469 + } else { 1.8470 + RemoveInPopupStateBitFromDescendants(this); 1.8471 + } 1.8472 + 1.8473 + // If our new parent only has invalid children, then we just invalidate 1.8474 + // ourselves too. This is probably faster than clearing the flag all 1.8475 + // the way up the frame tree. 1.8476 + if (aParent->HasAnyStateBits(NS_FRAME_ALL_DESCENDANTS_NEED_PAINT)) { 1.8477 + InvalidateFrame(); 1.8478 + } 1.8479 +} 1.8480 + 1.8481 +void 1.8482 +nsFrame::InitBoxMetrics(bool aClear) 1.8483 +{ 1.8484 + FrameProperties props = Properties(); 1.8485 + if (aClear) { 1.8486 + props.Delete(BoxMetricsProperty()); 1.8487 + } 1.8488 + 1.8489 + nsBoxLayoutMetrics *metrics = new nsBoxLayoutMetrics(); 1.8490 + props.Set(BoxMetricsProperty(), metrics); 1.8491 + 1.8492 + nsFrame::MarkIntrinsicWidthsDirty(); 1.8493 + metrics->mBlockAscent = 0; 1.8494 + metrics->mLastSize.SizeTo(0, 0); 1.8495 +} 1.8496 + 1.8497 +void 1.8498 +nsIFrame::CreateOwnLayerIfNeeded(nsDisplayListBuilder* aBuilder, 1.8499 + nsDisplayList* aList) 1.8500 +{ 1.8501 + if (GetContent() && 1.8502 + GetContent()->IsXUL() && 1.8503 + GetContent()->HasAttr(kNameSpaceID_None, nsGkAtoms::layer)) { 1.8504 + aList->AppendNewToTop(new (aBuilder) 1.8505 + nsDisplayOwnLayer(aBuilder, this, aList)); 1.8506 + } 1.8507 +} 1.8508 + 1.8509 +bool 1.8510 +nsIFrame::IsSelected() const 1.8511 +{ 1.8512 + return (GetContent() && GetContent()->IsSelectionDescendant()) ? 1.8513 + IsFrameSelected() : false; 1.8514 +} 1.8515 + 1.8516 +void 1.8517 +nsIFrame::DestroySurface(void* aPropertyValue) 1.8518 +{ 1.8519 + static_cast<gfxASurface*>(aPropertyValue)->Release(); 1.8520 +} 1.8521 + 1.8522 +void 1.8523 +nsIFrame::DestroyDT(void* aPropertyValue) 1.8524 +{ 1.8525 + static_cast<mozilla::gfx::DrawTarget*>(aPropertyValue)->Release(); 1.8526 +} 1.8527 + 1.8528 +void 1.8529 +nsIFrame::DestroyRegion(void* aPropertyValue) 1.8530 +{ 1.8531 + delete static_cast<nsRegion*>(aPropertyValue); 1.8532 +} 1.8533 + 1.8534 +bool 1.8535 +nsIFrame::IsPseudoStackingContextFromStyle() { 1.8536 + const nsStyleDisplay* disp = StyleDisplay(); 1.8537 + // If you change this, also change the computation of pseudoStackingContext 1.8538 + // in BuildDisplayListForChild() 1.8539 + return disp->mOpacity != 1.0f || 1.8540 + disp->IsPositioned(this) || 1.8541 + disp->IsFloating(this) || 1.8542 + (disp->mWillChangeBitField & NS_STYLE_WILL_CHANGE_STACKING_CONTEXT); 1.8543 +} 1.8544 + 1.8545 +Element* 1.8546 +nsIFrame::GetPseudoElement(nsCSSPseudoElements::Type aType) 1.8547 +{ 1.8548 + nsIFrame* frame = nullptr; 1.8549 + 1.8550 + if (aType == nsCSSPseudoElements::ePseudo_before) { 1.8551 + frame = nsLayoutUtils::GetBeforeFrame(this); 1.8552 + } else if (aType == nsCSSPseudoElements::ePseudo_after) { 1.8553 + frame = nsLayoutUtils::GetAfterFrame(this); 1.8554 + } 1.8555 + 1.8556 + if (frame) { 1.8557 + nsIContent* content = frame->GetContent(); 1.8558 + if (content->IsElement()) { 1.8559 + return content->AsElement(); 1.8560 + } 1.8561 + } 1.8562 + 1.8563 + return nullptr; 1.8564 +} 1.8565 + 1.8566 +nsIFrame::ContentOffsets::ContentOffsets() 1.8567 +{ 1.8568 +} 1.8569 + 1.8570 +nsIFrame::ContentOffsets::ContentOffsets(const ContentOffsets& rhs) 1.8571 + : content(rhs.content), 1.8572 + offset(rhs.offset), 1.8573 + secondaryOffset(rhs.secondaryOffset), 1.8574 + associateWithNext(rhs.associateWithNext) 1.8575 +{ 1.8576 +} 1.8577 + 1.8578 +nsIFrame::ContentOffsets::~ContentOffsets() 1.8579 +{ 1.8580 +} 1.8581 + 1.8582 +nsIFrame::CaretPosition::CaretPosition() 1.8583 + : mContentOffset(0) 1.8584 +{ 1.8585 +} 1.8586 + 1.8587 +nsIFrame::CaretPosition::~CaretPosition() 1.8588 +{ 1.8589 +} 1.8590 + 1.8591 +// Box layout debugging 1.8592 +#ifdef DEBUG_REFLOW 1.8593 +int32_t gIndent2 = 0; 1.8594 + 1.8595 +void 1.8596 +nsAdaptorAddIndents() 1.8597 +{ 1.8598 + for(int32_t i=0; i < gIndent2; i++) 1.8599 + { 1.8600 + printf(" "); 1.8601 + } 1.8602 +} 1.8603 + 1.8604 +void 1.8605 +nsAdaptorPrintReason(nsHTMLReflowState& aReflowState) 1.8606 +{ 1.8607 + char* reflowReasonString; 1.8608 + 1.8609 + switch(aReflowState.reason) 1.8610 + { 1.8611 + case eReflowReason_Initial: 1.8612 + reflowReasonString = "initial"; 1.8613 + break; 1.8614 + 1.8615 + case eReflowReason_Resize: 1.8616 + reflowReasonString = "resize"; 1.8617 + break; 1.8618 + case eReflowReason_Dirty: 1.8619 + reflowReasonString = "dirty"; 1.8620 + break; 1.8621 + case eReflowReason_StyleChange: 1.8622 + reflowReasonString = "stylechange"; 1.8623 + break; 1.8624 + case eReflowReason_Incremental: 1.8625 + { 1.8626 + switch (aReflowState.reflowCommand->Type()) { 1.8627 + case eReflowType_StyleChanged: 1.8628 + reflowReasonString = "incremental (StyleChanged)"; 1.8629 + break; 1.8630 + case eReflowType_ReflowDirty: 1.8631 + reflowReasonString = "incremental (ReflowDirty)"; 1.8632 + break; 1.8633 + default: 1.8634 + reflowReasonString = "incremental (Unknown)"; 1.8635 + } 1.8636 + } 1.8637 + break; 1.8638 + default: 1.8639 + reflowReasonString = "unknown"; 1.8640 + break; 1.8641 + } 1.8642 + 1.8643 + printf("%s",reflowReasonString); 1.8644 +} 1.8645 + 1.8646 +#endif 1.8647 +#ifdef DEBUG_LAYOUT 1.8648 +void 1.8649 +nsFrame::GetBoxName(nsAutoString& aName) 1.8650 +{ 1.8651 + GetFrameName(aName); 1.8652 +} 1.8653 +#endif 1.8654 + 1.8655 +#ifdef DEBUG 1.8656 +static void 1.8657 +GetTagName(nsFrame* aFrame, nsIContent* aContent, int aResultSize, 1.8658 + char* aResult) 1.8659 +{ 1.8660 + if (aContent) { 1.8661 + PR_snprintf(aResult, aResultSize, "%s@%p", 1.8662 + nsAtomCString(aContent->Tag()).get(), aFrame); 1.8663 + } 1.8664 + else { 1.8665 + PR_snprintf(aResult, aResultSize, "@%p", aFrame); 1.8666 + } 1.8667 +} 1.8668 + 1.8669 +void 1.8670 +nsFrame::Trace(const char* aMethod, bool aEnter) 1.8671 +{ 1.8672 + if (NS_FRAME_LOG_TEST(gLogModule, NS_FRAME_TRACE_CALLS)) { 1.8673 + char tagbuf[40]; 1.8674 + GetTagName(this, mContent, sizeof(tagbuf), tagbuf); 1.8675 + PR_LogPrint("%s: %s %s", tagbuf, aEnter ? "enter" : "exit", aMethod); 1.8676 + } 1.8677 +} 1.8678 + 1.8679 +void 1.8680 +nsFrame::Trace(const char* aMethod, bool aEnter, nsReflowStatus aStatus) 1.8681 +{ 1.8682 + if (NS_FRAME_LOG_TEST(gLogModule, NS_FRAME_TRACE_CALLS)) { 1.8683 + char tagbuf[40]; 1.8684 + GetTagName(this, mContent, sizeof(tagbuf), tagbuf); 1.8685 + PR_LogPrint("%s: %s %s, status=%scomplete%s", 1.8686 + tagbuf, aEnter ? "enter" : "exit", aMethod, 1.8687 + NS_FRAME_IS_NOT_COMPLETE(aStatus) ? "not" : "", 1.8688 + (NS_FRAME_REFLOW_NEXTINFLOW & aStatus) ? "+reflow" : ""); 1.8689 + } 1.8690 +} 1.8691 + 1.8692 +void 1.8693 +nsFrame::TraceMsg(const char* aFormatString, ...) 1.8694 +{ 1.8695 + if (NS_FRAME_LOG_TEST(gLogModule, NS_FRAME_TRACE_CALLS)) { 1.8696 + // Format arguments into a buffer 1.8697 + char argbuf[200]; 1.8698 + va_list ap; 1.8699 + va_start(ap, aFormatString); 1.8700 + PR_vsnprintf(argbuf, sizeof(argbuf), aFormatString, ap); 1.8701 + va_end(ap); 1.8702 + 1.8703 + char tagbuf[40]; 1.8704 + GetTagName(this, mContent, sizeof(tagbuf), tagbuf); 1.8705 + PR_LogPrint("%s: %s", tagbuf, argbuf); 1.8706 + } 1.8707 +} 1.8708 + 1.8709 +void 1.8710 +nsFrame::VerifyDirtyBitSet(const nsFrameList& aFrameList) 1.8711 +{ 1.8712 + for (nsFrameList::Enumerator e(aFrameList); !e.AtEnd(); e.Next()) { 1.8713 + NS_ASSERTION(e.get()->GetStateBits() & NS_FRAME_IS_DIRTY, 1.8714 + "dirty bit not set"); 1.8715 + } 1.8716 +} 1.8717 + 1.8718 +// Start Display Reflow 1.8719 +#ifdef DEBUG 1.8720 + 1.8721 +DR_cookie::DR_cookie(nsPresContext* aPresContext, 1.8722 + nsIFrame* aFrame, 1.8723 + const nsHTMLReflowState& aReflowState, 1.8724 + nsHTMLReflowMetrics& aMetrics, 1.8725 + nsReflowStatus& aStatus) 1.8726 + :mPresContext(aPresContext), mFrame(aFrame), mReflowState(aReflowState), mMetrics(aMetrics), mStatus(aStatus) 1.8727 +{ 1.8728 + MOZ_COUNT_CTOR(DR_cookie); 1.8729 + mValue = nsFrame::DisplayReflowEnter(aPresContext, mFrame, mReflowState); 1.8730 +} 1.8731 + 1.8732 +DR_cookie::~DR_cookie() 1.8733 +{ 1.8734 + MOZ_COUNT_DTOR(DR_cookie); 1.8735 + nsFrame::DisplayReflowExit(mPresContext, mFrame, mMetrics, mStatus, mValue); 1.8736 +} 1.8737 + 1.8738 +DR_layout_cookie::DR_layout_cookie(nsIFrame* aFrame) 1.8739 + : mFrame(aFrame) 1.8740 +{ 1.8741 + MOZ_COUNT_CTOR(DR_layout_cookie); 1.8742 + mValue = nsFrame::DisplayLayoutEnter(mFrame); 1.8743 +} 1.8744 + 1.8745 +DR_layout_cookie::~DR_layout_cookie() 1.8746 +{ 1.8747 + MOZ_COUNT_DTOR(DR_layout_cookie); 1.8748 + nsFrame::DisplayLayoutExit(mFrame, mValue); 1.8749 +} 1.8750 + 1.8751 +DR_intrinsic_width_cookie::DR_intrinsic_width_cookie( 1.8752 + nsIFrame* aFrame, 1.8753 + const char* aType, 1.8754 + nscoord& aResult) 1.8755 + : mFrame(aFrame) 1.8756 + , mType(aType) 1.8757 + , mResult(aResult) 1.8758 +{ 1.8759 + MOZ_COUNT_CTOR(DR_intrinsic_width_cookie); 1.8760 + mValue = nsFrame::DisplayIntrinsicWidthEnter(mFrame, mType); 1.8761 +} 1.8762 + 1.8763 +DR_intrinsic_width_cookie::~DR_intrinsic_width_cookie() 1.8764 +{ 1.8765 + MOZ_COUNT_DTOR(DR_intrinsic_width_cookie); 1.8766 + nsFrame::DisplayIntrinsicWidthExit(mFrame, mType, mResult, mValue); 1.8767 +} 1.8768 + 1.8769 +DR_intrinsic_size_cookie::DR_intrinsic_size_cookie( 1.8770 + nsIFrame* aFrame, 1.8771 + const char* aType, 1.8772 + nsSize& aResult) 1.8773 + : mFrame(aFrame) 1.8774 + , mType(aType) 1.8775 + , mResult(aResult) 1.8776 +{ 1.8777 + MOZ_COUNT_CTOR(DR_intrinsic_size_cookie); 1.8778 + mValue = nsFrame::DisplayIntrinsicSizeEnter(mFrame, mType); 1.8779 +} 1.8780 + 1.8781 +DR_intrinsic_size_cookie::~DR_intrinsic_size_cookie() 1.8782 +{ 1.8783 + MOZ_COUNT_DTOR(DR_intrinsic_size_cookie); 1.8784 + nsFrame::DisplayIntrinsicSizeExit(mFrame, mType, mResult, mValue); 1.8785 +} 1.8786 + 1.8787 +DR_init_constraints_cookie::DR_init_constraints_cookie( 1.8788 + nsIFrame* aFrame, 1.8789 + nsHTMLReflowState* aState, 1.8790 + nscoord aCBWidth, 1.8791 + nscoord aCBHeight, 1.8792 + const nsMargin* aMargin, 1.8793 + const nsMargin* aPadding) 1.8794 + : mFrame(aFrame) 1.8795 + , mState(aState) 1.8796 +{ 1.8797 + MOZ_COUNT_CTOR(DR_init_constraints_cookie); 1.8798 + mValue = nsHTMLReflowState::DisplayInitConstraintsEnter(mFrame, mState, 1.8799 + aCBWidth, aCBHeight, 1.8800 + aMargin, aPadding); 1.8801 +} 1.8802 + 1.8803 +DR_init_constraints_cookie::~DR_init_constraints_cookie() 1.8804 +{ 1.8805 + MOZ_COUNT_DTOR(DR_init_constraints_cookie); 1.8806 + nsHTMLReflowState::DisplayInitConstraintsExit(mFrame, mState, mValue); 1.8807 +} 1.8808 + 1.8809 +DR_init_offsets_cookie::DR_init_offsets_cookie( 1.8810 + nsIFrame* aFrame, 1.8811 + nsCSSOffsetState* aState, 1.8812 + nscoord aHorizontalPercentBasis, 1.8813 + nscoord aVerticalPercentBasis, 1.8814 + const nsMargin* aMargin, 1.8815 + const nsMargin* aPadding) 1.8816 + : mFrame(aFrame) 1.8817 + , mState(aState) 1.8818 +{ 1.8819 + MOZ_COUNT_CTOR(DR_init_offsets_cookie); 1.8820 + mValue = nsCSSOffsetState::DisplayInitOffsetsEnter(mFrame, mState, 1.8821 + aHorizontalPercentBasis, 1.8822 + aVerticalPercentBasis, 1.8823 + aMargin, aPadding); 1.8824 +} 1.8825 + 1.8826 +DR_init_offsets_cookie::~DR_init_offsets_cookie() 1.8827 +{ 1.8828 + MOZ_COUNT_DTOR(DR_init_offsets_cookie); 1.8829 + nsCSSOffsetState::DisplayInitOffsetsExit(mFrame, mState, mValue); 1.8830 +} 1.8831 + 1.8832 +DR_init_type_cookie::DR_init_type_cookie( 1.8833 + nsIFrame* aFrame, 1.8834 + nsHTMLReflowState* aState) 1.8835 + : mFrame(aFrame) 1.8836 + , mState(aState) 1.8837 +{ 1.8838 + MOZ_COUNT_CTOR(DR_init_type_cookie); 1.8839 + mValue = nsHTMLReflowState::DisplayInitFrameTypeEnter(mFrame, mState); 1.8840 +} 1.8841 + 1.8842 +DR_init_type_cookie::~DR_init_type_cookie() 1.8843 +{ 1.8844 + MOZ_COUNT_DTOR(DR_init_type_cookie); 1.8845 + nsHTMLReflowState::DisplayInitFrameTypeExit(mFrame, mState, mValue); 1.8846 +} 1.8847 + 1.8848 +struct DR_FrameTypeInfo; 1.8849 +struct DR_FrameTreeNode; 1.8850 +struct DR_Rule; 1.8851 + 1.8852 +struct DR_State 1.8853 +{ 1.8854 + DR_State(); 1.8855 + ~DR_State(); 1.8856 + void Init(); 1.8857 + void AddFrameTypeInfo(nsIAtom* aFrameType, 1.8858 + const char* aFrameNameAbbrev, 1.8859 + const char* aFrameName); 1.8860 + DR_FrameTypeInfo* GetFrameTypeInfo(nsIAtom* aFrameType); 1.8861 + DR_FrameTypeInfo* GetFrameTypeInfo(char* aFrameName); 1.8862 + void InitFrameTypeTable(); 1.8863 + DR_FrameTreeNode* CreateTreeNode(nsIFrame* aFrame, 1.8864 + const nsHTMLReflowState* aReflowState); 1.8865 + void FindMatchingRule(DR_FrameTreeNode& aNode); 1.8866 + bool RuleMatches(DR_Rule& aRule, 1.8867 + DR_FrameTreeNode& aNode); 1.8868 + bool GetToken(FILE* aFile, 1.8869 + char* aBuf, 1.8870 + size_t aBufSize); 1.8871 + DR_Rule* ParseRule(FILE* aFile); 1.8872 + void ParseRulesFile(); 1.8873 + void AddRule(nsTArray<DR_Rule*>& aRules, 1.8874 + DR_Rule& aRule); 1.8875 + bool IsWhiteSpace(int c); 1.8876 + bool GetNumber(char* aBuf, 1.8877 + int32_t& aNumber); 1.8878 + void PrettyUC(nscoord aSize, 1.8879 + char* aBuf); 1.8880 + void PrintMargin(const char* tag, const nsMargin* aMargin); 1.8881 + void DisplayFrameTypeInfo(nsIFrame* aFrame, 1.8882 + int32_t aIndent); 1.8883 + void DeleteTreeNode(DR_FrameTreeNode& aNode); 1.8884 + 1.8885 + bool mInited; 1.8886 + bool mActive; 1.8887 + int32_t mCount; 1.8888 + int32_t mAssert; 1.8889 + int32_t mIndent; 1.8890 + bool mIndentUndisplayedFrames; 1.8891 + bool mDisplayPixelErrors; 1.8892 + nsTArray<DR_Rule*> mWildRules; 1.8893 + nsTArray<DR_FrameTypeInfo> mFrameTypeTable; 1.8894 + // reflow specific state 1.8895 + nsTArray<DR_FrameTreeNode*> mFrameTreeLeaves; 1.8896 +}; 1.8897 + 1.8898 +static DR_State *DR_state; // the one and only DR_State 1.8899 + 1.8900 +struct DR_RulePart 1.8901 +{ 1.8902 + DR_RulePart(nsIAtom* aFrameType) : mFrameType(aFrameType), mNext(0) {} 1.8903 + void Destroy(); 1.8904 + 1.8905 + nsIAtom* mFrameType; 1.8906 + DR_RulePart* mNext; 1.8907 +}; 1.8908 + 1.8909 +void DR_RulePart::Destroy() 1.8910 +{ 1.8911 + if (mNext) { 1.8912 + mNext->Destroy(); 1.8913 + } 1.8914 + delete this; 1.8915 +} 1.8916 + 1.8917 +struct DR_Rule 1.8918 +{ 1.8919 + DR_Rule() : mLength(0), mTarget(nullptr), mDisplay(false) { 1.8920 + MOZ_COUNT_CTOR(DR_Rule); 1.8921 + } 1.8922 + ~DR_Rule() { 1.8923 + if (mTarget) mTarget->Destroy(); 1.8924 + MOZ_COUNT_DTOR(DR_Rule); 1.8925 + } 1.8926 + void AddPart(nsIAtom* aFrameType); 1.8927 + 1.8928 + uint32_t mLength; 1.8929 + DR_RulePart* mTarget; 1.8930 + bool mDisplay; 1.8931 +}; 1.8932 + 1.8933 +void DR_Rule::AddPart(nsIAtom* aFrameType) 1.8934 +{ 1.8935 + DR_RulePart* newPart = new DR_RulePart(aFrameType); 1.8936 + newPart->mNext = mTarget; 1.8937 + mTarget = newPart; 1.8938 + mLength++; 1.8939 +} 1.8940 + 1.8941 +struct DR_FrameTypeInfo 1.8942 +{ 1.8943 + DR_FrameTypeInfo(nsIAtom* aFrmeType, const char* aFrameNameAbbrev, const char* aFrameName); 1.8944 + ~DR_FrameTypeInfo() { 1.8945 + int32_t numElements; 1.8946 + numElements = mRules.Length(); 1.8947 + for (int32_t i = numElements - 1; i >= 0; i--) { 1.8948 + delete mRules.ElementAt(i); 1.8949 + } 1.8950 + } 1.8951 + 1.8952 + nsIAtom* mType; 1.8953 + char mNameAbbrev[16]; 1.8954 + char mName[32]; 1.8955 + nsTArray<DR_Rule*> mRules; 1.8956 +private: 1.8957 + DR_FrameTypeInfo& operator=(const DR_FrameTypeInfo&) MOZ_DELETE; 1.8958 +}; 1.8959 + 1.8960 +DR_FrameTypeInfo::DR_FrameTypeInfo(nsIAtom* aFrameType, 1.8961 + const char* aFrameNameAbbrev, 1.8962 + const char* aFrameName) 1.8963 +{ 1.8964 + mType = aFrameType; 1.8965 + PL_strncpyz(mNameAbbrev, aFrameNameAbbrev, sizeof(mNameAbbrev)); 1.8966 + PL_strncpyz(mName, aFrameName, sizeof(mName)); 1.8967 +} 1.8968 + 1.8969 +struct DR_FrameTreeNode 1.8970 +{ 1.8971 + DR_FrameTreeNode(nsIFrame* aFrame, DR_FrameTreeNode* aParent) : mFrame(aFrame), mParent(aParent), mDisplay(0), mIndent(0) 1.8972 + { 1.8973 + MOZ_COUNT_CTOR(DR_FrameTreeNode); 1.8974 + } 1.8975 + 1.8976 + ~DR_FrameTreeNode() 1.8977 + { 1.8978 + MOZ_COUNT_DTOR(DR_FrameTreeNode); 1.8979 + } 1.8980 + 1.8981 + nsIFrame* mFrame; 1.8982 + DR_FrameTreeNode* mParent; 1.8983 + bool mDisplay; 1.8984 + uint32_t mIndent; 1.8985 +}; 1.8986 + 1.8987 +// DR_State implementation 1.8988 + 1.8989 +DR_State::DR_State() 1.8990 +: mInited(false), mActive(false), mCount(0), mAssert(-1), mIndent(0), 1.8991 + mIndentUndisplayedFrames(false), mDisplayPixelErrors(false) 1.8992 +{ 1.8993 + MOZ_COUNT_CTOR(DR_State); 1.8994 +} 1.8995 + 1.8996 +void DR_State::Init() 1.8997 +{ 1.8998 + char* env = PR_GetEnv("GECKO_DISPLAY_REFLOW_ASSERT"); 1.8999 + int32_t num; 1.9000 + if (env) { 1.9001 + if (GetNumber(env, num)) 1.9002 + mAssert = num; 1.9003 + else 1.9004 + printf("GECKO_DISPLAY_REFLOW_ASSERT - invalid value = %s", env); 1.9005 + } 1.9006 + 1.9007 + env = PR_GetEnv("GECKO_DISPLAY_REFLOW_INDENT_START"); 1.9008 + if (env) { 1.9009 + if (GetNumber(env, num)) 1.9010 + mIndent = num; 1.9011 + else 1.9012 + printf("GECKO_DISPLAY_REFLOW_INDENT_START - invalid value = %s", env); 1.9013 + } 1.9014 + 1.9015 + env = PR_GetEnv("GECKO_DISPLAY_REFLOW_INDENT_UNDISPLAYED_FRAMES"); 1.9016 + if (env) { 1.9017 + if (GetNumber(env, num)) 1.9018 + mIndentUndisplayedFrames = num; 1.9019 + else 1.9020 + printf("GECKO_DISPLAY_REFLOW_INDENT_UNDISPLAYED_FRAMES - invalid value = %s", env); 1.9021 + } 1.9022 + 1.9023 + env = PR_GetEnv("GECKO_DISPLAY_REFLOW_FLAG_PIXEL_ERRORS"); 1.9024 + if (env) { 1.9025 + if (GetNumber(env, num)) 1.9026 + mDisplayPixelErrors = num; 1.9027 + else 1.9028 + printf("GECKO_DISPLAY_REFLOW_FLAG_PIXEL_ERRORS - invalid value = %s", env); 1.9029 + } 1.9030 + 1.9031 + InitFrameTypeTable(); 1.9032 + ParseRulesFile(); 1.9033 + mInited = true; 1.9034 +} 1.9035 + 1.9036 +DR_State::~DR_State() 1.9037 +{ 1.9038 + MOZ_COUNT_DTOR(DR_State); 1.9039 + int32_t numElements, i; 1.9040 + numElements = mWildRules.Length(); 1.9041 + for (i = numElements - 1; i >= 0; i--) { 1.9042 + delete mWildRules.ElementAt(i); 1.9043 + } 1.9044 + numElements = mFrameTreeLeaves.Length(); 1.9045 + for (i = numElements - 1; i >= 0; i--) { 1.9046 + delete mFrameTreeLeaves.ElementAt(i); 1.9047 + } 1.9048 +} 1.9049 + 1.9050 +bool DR_State::GetNumber(char* aBuf, 1.9051 + int32_t& aNumber) 1.9052 +{ 1.9053 + if (sscanf(aBuf, "%d", &aNumber) > 0) 1.9054 + return true; 1.9055 + else 1.9056 + return false; 1.9057 +} 1.9058 + 1.9059 +bool DR_State::IsWhiteSpace(int c) { 1.9060 + return (c == ' ') || (c == '\t') || (c == '\n') || (c == '\r'); 1.9061 +} 1.9062 + 1.9063 +bool DR_State::GetToken(FILE* aFile, 1.9064 + char* aBuf, 1.9065 + size_t aBufSize) 1.9066 +{ 1.9067 + bool haveToken = false; 1.9068 + aBuf[0] = 0; 1.9069 + // get the 1st non whitespace char 1.9070 + int c = -1; 1.9071 + for (c = getc(aFile); (c > 0) && IsWhiteSpace(c); c = getc(aFile)) { 1.9072 + } 1.9073 + 1.9074 + if (c > 0) { 1.9075 + haveToken = true; 1.9076 + aBuf[0] = c; 1.9077 + // get everything up to the next whitespace char 1.9078 + size_t cX; 1.9079 + for (cX = 1; cX + 1 < aBufSize ; cX++) { 1.9080 + c = getc(aFile); 1.9081 + if (c < 0) { // EOF 1.9082 + ungetc(' ', aFile); 1.9083 + break; 1.9084 + } 1.9085 + else { 1.9086 + if (IsWhiteSpace(c)) { 1.9087 + break; 1.9088 + } 1.9089 + else { 1.9090 + aBuf[cX] = c; 1.9091 + } 1.9092 + } 1.9093 + } 1.9094 + aBuf[cX] = 0; 1.9095 + } 1.9096 + return haveToken; 1.9097 +} 1.9098 + 1.9099 +DR_Rule* DR_State::ParseRule(FILE* aFile) 1.9100 +{ 1.9101 + char buf[128]; 1.9102 + int32_t doDisplay; 1.9103 + DR_Rule* rule = nullptr; 1.9104 + while (GetToken(aFile, buf, sizeof(buf))) { 1.9105 + if (GetNumber(buf, doDisplay)) { 1.9106 + if (rule) { 1.9107 + rule->mDisplay = !!doDisplay; 1.9108 + break; 1.9109 + } 1.9110 + else { 1.9111 + printf("unexpected token - %s \n", buf); 1.9112 + } 1.9113 + } 1.9114 + else { 1.9115 + if (!rule) { 1.9116 + rule = new DR_Rule; 1.9117 + } 1.9118 + if (strcmp(buf, "*") == 0) { 1.9119 + rule->AddPart(nullptr); 1.9120 + } 1.9121 + else { 1.9122 + DR_FrameTypeInfo* info = GetFrameTypeInfo(buf); 1.9123 + if (info) { 1.9124 + rule->AddPart(info->mType); 1.9125 + } 1.9126 + else { 1.9127 + printf("invalid frame type - %s \n", buf); 1.9128 + } 1.9129 + } 1.9130 + } 1.9131 + } 1.9132 + return rule; 1.9133 +} 1.9134 + 1.9135 +void DR_State::AddRule(nsTArray<DR_Rule*>& aRules, 1.9136 + DR_Rule& aRule) 1.9137 +{ 1.9138 + int32_t numRules = aRules.Length(); 1.9139 + for (int32_t ruleX = 0; ruleX < numRules; ruleX++) { 1.9140 + DR_Rule* rule = aRules.ElementAt(ruleX); 1.9141 + NS_ASSERTION(rule, "program error"); 1.9142 + if (aRule.mLength > rule->mLength) { 1.9143 + aRules.InsertElementAt(ruleX, &aRule); 1.9144 + return; 1.9145 + } 1.9146 + } 1.9147 + aRules.AppendElement(&aRule); 1.9148 +} 1.9149 + 1.9150 +void DR_State::ParseRulesFile() 1.9151 +{ 1.9152 + char* path = PR_GetEnv("GECKO_DISPLAY_REFLOW_RULES_FILE"); 1.9153 + if (path) { 1.9154 + FILE* inFile = fopen(path, "r"); 1.9155 + if (inFile) { 1.9156 + for (DR_Rule* rule = ParseRule(inFile); rule; rule = ParseRule(inFile)) { 1.9157 + if (rule->mTarget) { 1.9158 + nsIAtom* fType = rule->mTarget->mFrameType; 1.9159 + if (fType) { 1.9160 + DR_FrameTypeInfo* info = GetFrameTypeInfo(fType); 1.9161 + if (info) { 1.9162 + AddRule(info->mRules, *rule); 1.9163 + } 1.9164 + } 1.9165 + else { 1.9166 + AddRule(mWildRules, *rule); 1.9167 + } 1.9168 + mActive = true; 1.9169 + } 1.9170 + } 1.9171 + } 1.9172 + } 1.9173 +} 1.9174 + 1.9175 + 1.9176 +void DR_State::AddFrameTypeInfo(nsIAtom* aFrameType, 1.9177 + const char* aFrameNameAbbrev, 1.9178 + const char* aFrameName) 1.9179 +{ 1.9180 + mFrameTypeTable.AppendElement(DR_FrameTypeInfo(aFrameType, aFrameNameAbbrev, aFrameName)); 1.9181 +} 1.9182 + 1.9183 +DR_FrameTypeInfo* DR_State::GetFrameTypeInfo(nsIAtom* aFrameType) 1.9184 +{ 1.9185 + int32_t numEntries = mFrameTypeTable.Length(); 1.9186 + NS_ASSERTION(numEntries != 0, "empty FrameTypeTable"); 1.9187 + for (int32_t i = 0; i < numEntries; i++) { 1.9188 + DR_FrameTypeInfo& info = mFrameTypeTable.ElementAt(i); 1.9189 + if (info.mType == aFrameType) { 1.9190 + return &info; 1.9191 + } 1.9192 + } 1.9193 + return &mFrameTypeTable.ElementAt(numEntries - 1); // return unknown frame type 1.9194 +} 1.9195 + 1.9196 +DR_FrameTypeInfo* DR_State::GetFrameTypeInfo(char* aFrameName) 1.9197 +{ 1.9198 + int32_t numEntries = mFrameTypeTable.Length(); 1.9199 + NS_ASSERTION(numEntries != 0, "empty FrameTypeTable"); 1.9200 + for (int32_t i = 0; i < numEntries; i++) { 1.9201 + DR_FrameTypeInfo& info = mFrameTypeTable.ElementAt(i); 1.9202 + if ((strcmp(aFrameName, info.mName) == 0) || (strcmp(aFrameName, info.mNameAbbrev) == 0)) { 1.9203 + return &info; 1.9204 + } 1.9205 + } 1.9206 + return &mFrameTypeTable.ElementAt(numEntries - 1); // return unknown frame type 1.9207 +} 1.9208 + 1.9209 +void DR_State::InitFrameTypeTable() 1.9210 +{ 1.9211 + AddFrameTypeInfo(nsGkAtoms::blockFrame, "block", "block"); 1.9212 + AddFrameTypeInfo(nsGkAtoms::brFrame, "br", "br"); 1.9213 + AddFrameTypeInfo(nsGkAtoms::bulletFrame, "bullet", "bullet"); 1.9214 + AddFrameTypeInfo(nsGkAtoms::colorControlFrame, "color", "colorControl"); 1.9215 + AddFrameTypeInfo(nsGkAtoms::gfxButtonControlFrame, "button", "gfxButtonControl"); 1.9216 + AddFrameTypeInfo(nsGkAtoms::HTMLButtonControlFrame, "HTMLbutton", "HTMLButtonControl"); 1.9217 + AddFrameTypeInfo(nsGkAtoms::HTMLCanvasFrame, "HTMLCanvas","HTMLCanvas"); 1.9218 + AddFrameTypeInfo(nsGkAtoms::subDocumentFrame, "subdoc", "subDocument"); 1.9219 + AddFrameTypeInfo(nsGkAtoms::imageFrame, "img", "image"); 1.9220 + AddFrameTypeInfo(nsGkAtoms::inlineFrame, "inline", "inline"); 1.9221 + AddFrameTypeInfo(nsGkAtoms::letterFrame, "letter", "letter"); 1.9222 + AddFrameTypeInfo(nsGkAtoms::lineFrame, "line", "line"); 1.9223 + AddFrameTypeInfo(nsGkAtoms::listControlFrame, "select", "select"); 1.9224 + AddFrameTypeInfo(nsGkAtoms::objectFrame, "obj", "object"); 1.9225 + AddFrameTypeInfo(nsGkAtoms::pageFrame, "page", "page"); 1.9226 + AddFrameTypeInfo(nsGkAtoms::placeholderFrame, "place", "placeholder"); 1.9227 + AddFrameTypeInfo(nsGkAtoms::canvasFrame, "canvas", "canvas"); 1.9228 + AddFrameTypeInfo(nsGkAtoms::rootFrame, "root", "root"); 1.9229 + AddFrameTypeInfo(nsGkAtoms::scrollFrame, "scroll", "scroll"); 1.9230 + AddFrameTypeInfo(nsGkAtoms::tableCaptionFrame, "caption", "tableCaption"); 1.9231 + AddFrameTypeInfo(nsGkAtoms::tableCellFrame, "cell", "tableCell"); 1.9232 + AddFrameTypeInfo(nsGkAtoms::bcTableCellFrame, "bcCell", "bcTableCell"); 1.9233 + AddFrameTypeInfo(nsGkAtoms::tableColFrame, "col", "tableCol"); 1.9234 + AddFrameTypeInfo(nsGkAtoms::tableColGroupFrame, "colG", "tableColGroup"); 1.9235 + AddFrameTypeInfo(nsGkAtoms::tableFrame, "tbl", "table"); 1.9236 + AddFrameTypeInfo(nsGkAtoms::tableOuterFrame, "tblO", "tableOuter"); 1.9237 + AddFrameTypeInfo(nsGkAtoms::tableRowGroupFrame, "rowG", "tableRowGroup"); 1.9238 + AddFrameTypeInfo(nsGkAtoms::tableRowFrame, "row", "tableRow"); 1.9239 + AddFrameTypeInfo(nsGkAtoms::textInputFrame, "textCtl", "textInput"); 1.9240 + AddFrameTypeInfo(nsGkAtoms::textFrame, "text", "text"); 1.9241 + AddFrameTypeInfo(nsGkAtoms::viewportFrame, "VP", "viewport"); 1.9242 +#ifdef MOZ_XUL 1.9243 + AddFrameTypeInfo(nsGkAtoms::XULLabelFrame, "XULLabel", "XULLabel"); 1.9244 + AddFrameTypeInfo(nsGkAtoms::boxFrame, "Box", "Box"); 1.9245 + AddFrameTypeInfo(nsGkAtoms::sliderFrame, "Slider", "Slider"); 1.9246 + AddFrameTypeInfo(nsGkAtoms::popupSetFrame, "PopupSet", "PopupSet"); 1.9247 +#endif 1.9248 + AddFrameTypeInfo(nullptr, "unknown", "unknown"); 1.9249 +} 1.9250 + 1.9251 + 1.9252 +void DR_State::DisplayFrameTypeInfo(nsIFrame* aFrame, 1.9253 + int32_t aIndent) 1.9254 +{ 1.9255 + DR_FrameTypeInfo* frameTypeInfo = GetFrameTypeInfo(aFrame->GetType()); 1.9256 + if (frameTypeInfo) { 1.9257 + for (int32_t i = 0; i < aIndent; i++) { 1.9258 + printf(" "); 1.9259 + } 1.9260 + if(!strcmp(frameTypeInfo->mNameAbbrev, "unknown")) { 1.9261 + if (aFrame) { 1.9262 + nsAutoString name; 1.9263 + aFrame->GetFrameName(name); 1.9264 + printf("%s %p ", NS_LossyConvertUTF16toASCII(name).get(), (void*)aFrame); 1.9265 + } 1.9266 + else { 1.9267 + printf("%s %p ", frameTypeInfo->mNameAbbrev, (void*)aFrame); 1.9268 + } 1.9269 + } 1.9270 + else { 1.9271 + printf("%s %p ", frameTypeInfo->mNameAbbrev, (void*)aFrame); 1.9272 + } 1.9273 + } 1.9274 +} 1.9275 + 1.9276 +bool DR_State::RuleMatches(DR_Rule& aRule, 1.9277 + DR_FrameTreeNode& aNode) 1.9278 +{ 1.9279 + NS_ASSERTION(aRule.mTarget, "program error"); 1.9280 + 1.9281 + DR_RulePart* rulePart; 1.9282 + DR_FrameTreeNode* parentNode; 1.9283 + for (rulePart = aRule.mTarget->mNext, parentNode = aNode.mParent; 1.9284 + rulePart && parentNode; 1.9285 + rulePart = rulePart->mNext, parentNode = parentNode->mParent) { 1.9286 + if (rulePart->mFrameType) { 1.9287 + if (parentNode->mFrame) { 1.9288 + if (rulePart->mFrameType != parentNode->mFrame->GetType()) { 1.9289 + return false; 1.9290 + } 1.9291 + } 1.9292 + else NS_ASSERTION(false, "program error"); 1.9293 + } 1.9294 + // else wild card match 1.9295 + } 1.9296 + return true; 1.9297 +} 1.9298 + 1.9299 +void DR_State::FindMatchingRule(DR_FrameTreeNode& aNode) 1.9300 +{ 1.9301 + if (!aNode.mFrame) { 1.9302 + NS_ASSERTION(false, "invalid DR_FrameTreeNode \n"); 1.9303 + return; 1.9304 + } 1.9305 + 1.9306 + bool matchingRule = false; 1.9307 + 1.9308 + DR_FrameTypeInfo* info = GetFrameTypeInfo(aNode.mFrame->GetType()); 1.9309 + NS_ASSERTION(info, "program error"); 1.9310 + int32_t numRules = info->mRules.Length(); 1.9311 + for (int32_t ruleX = 0; ruleX < numRules; ruleX++) { 1.9312 + DR_Rule* rule = info->mRules.ElementAt(ruleX); 1.9313 + if (rule && RuleMatches(*rule, aNode)) { 1.9314 + aNode.mDisplay = rule->mDisplay; 1.9315 + matchingRule = true; 1.9316 + break; 1.9317 + } 1.9318 + } 1.9319 + if (!matchingRule) { 1.9320 + int32_t numWildRules = mWildRules.Length(); 1.9321 + for (int32_t ruleX = 0; ruleX < numWildRules; ruleX++) { 1.9322 + DR_Rule* rule = mWildRules.ElementAt(ruleX); 1.9323 + if (rule && RuleMatches(*rule, aNode)) { 1.9324 + aNode.mDisplay = rule->mDisplay; 1.9325 + break; 1.9326 + } 1.9327 + } 1.9328 + } 1.9329 +} 1.9330 + 1.9331 +DR_FrameTreeNode* DR_State::CreateTreeNode(nsIFrame* aFrame, 1.9332 + const nsHTMLReflowState* aReflowState) 1.9333 +{ 1.9334 + // find the frame of the parent reflow state (usually just the parent of aFrame) 1.9335 + nsIFrame* parentFrame; 1.9336 + if (aReflowState) { 1.9337 + const nsHTMLReflowState* parentRS = aReflowState->parentReflowState; 1.9338 + parentFrame = (parentRS) ? parentRS->frame : nullptr; 1.9339 + } else { 1.9340 + parentFrame = aFrame->GetParent(); 1.9341 + } 1.9342 + 1.9343 + // find the parent tree node leaf 1.9344 + DR_FrameTreeNode* parentNode = nullptr; 1.9345 + 1.9346 + DR_FrameTreeNode* lastLeaf = nullptr; 1.9347 + if(mFrameTreeLeaves.Length()) 1.9348 + lastLeaf = mFrameTreeLeaves.ElementAt(mFrameTreeLeaves.Length() - 1); 1.9349 + if (lastLeaf) { 1.9350 + for (parentNode = lastLeaf; parentNode && (parentNode->mFrame != parentFrame); parentNode = parentNode->mParent) { 1.9351 + } 1.9352 + } 1.9353 + DR_FrameTreeNode* newNode = new DR_FrameTreeNode(aFrame, parentNode); 1.9354 + FindMatchingRule(*newNode); 1.9355 + 1.9356 + newNode->mIndent = mIndent; 1.9357 + if (newNode->mDisplay || mIndentUndisplayedFrames) { 1.9358 + ++mIndent; 1.9359 + } 1.9360 + 1.9361 + if (lastLeaf && (lastLeaf == parentNode)) { 1.9362 + mFrameTreeLeaves.RemoveElementAt(mFrameTreeLeaves.Length() - 1); 1.9363 + } 1.9364 + mFrameTreeLeaves.AppendElement(newNode); 1.9365 + mCount++; 1.9366 + 1.9367 + return newNode; 1.9368 +} 1.9369 + 1.9370 +void DR_State::PrettyUC(nscoord aSize, 1.9371 + char* aBuf) 1.9372 +{ 1.9373 + if (NS_UNCONSTRAINEDSIZE == aSize) { 1.9374 + strcpy(aBuf, "UC"); 1.9375 + } 1.9376 + else { 1.9377 + if ((nscoord)0xdeadbeefU == aSize) 1.9378 + { 1.9379 + strcpy(aBuf, "deadbeef"); 1.9380 + } 1.9381 + else { 1.9382 + sprintf(aBuf, "%d", aSize); 1.9383 + } 1.9384 + } 1.9385 +} 1.9386 + 1.9387 +void DR_State::PrintMargin(const char *tag, const nsMargin* aMargin) 1.9388 +{ 1.9389 + if (aMargin) { 1.9390 + char t[16], r[16], b[16], l[16]; 1.9391 + PrettyUC(aMargin->top, t); 1.9392 + PrettyUC(aMargin->right, r); 1.9393 + PrettyUC(aMargin->bottom, b); 1.9394 + PrettyUC(aMargin->left, l); 1.9395 + printf(" %s=%s,%s,%s,%s", tag, t, r, b, l); 1.9396 + } else { 1.9397 + // use %p here for consistency with other null-pointer printouts 1.9398 + printf(" %s=%p", tag, (void*)aMargin); 1.9399 + } 1.9400 +} 1.9401 + 1.9402 +void DR_State::DeleteTreeNode(DR_FrameTreeNode& aNode) 1.9403 +{ 1.9404 + mFrameTreeLeaves.RemoveElement(&aNode); 1.9405 + int32_t numLeaves = mFrameTreeLeaves.Length(); 1.9406 + if ((0 == numLeaves) || (aNode.mParent != mFrameTreeLeaves.ElementAt(numLeaves - 1))) { 1.9407 + mFrameTreeLeaves.AppendElement(aNode.mParent); 1.9408 + } 1.9409 + 1.9410 + if (aNode.mDisplay || mIndentUndisplayedFrames) { 1.9411 + --mIndent; 1.9412 + } 1.9413 + // delete the tree node 1.9414 + delete &aNode; 1.9415 +} 1.9416 + 1.9417 +static void 1.9418 +CheckPixelError(nscoord aSize, 1.9419 + int32_t aPixelToTwips) 1.9420 +{ 1.9421 + if (NS_UNCONSTRAINEDSIZE != aSize) { 1.9422 + if ((aSize % aPixelToTwips) > 0) { 1.9423 + printf("VALUE %d is not a whole pixel \n", aSize); 1.9424 + } 1.9425 + } 1.9426 +} 1.9427 + 1.9428 +static void DisplayReflowEnterPrint(nsPresContext* aPresContext, 1.9429 + nsIFrame* aFrame, 1.9430 + const nsHTMLReflowState& aReflowState, 1.9431 + DR_FrameTreeNode& aTreeNode, 1.9432 + bool aChanged) 1.9433 +{ 1.9434 + if (aTreeNode.mDisplay) { 1.9435 + DR_state->DisplayFrameTypeInfo(aFrame, aTreeNode.mIndent); 1.9436 + 1.9437 + char width[16]; 1.9438 + char height[16]; 1.9439 + 1.9440 + DR_state->PrettyUC(aReflowState.AvailableWidth(), width); 1.9441 + DR_state->PrettyUC(aReflowState.AvailableHeight(), height); 1.9442 + printf("Reflow a=%s,%s ", width, height); 1.9443 + 1.9444 + DR_state->PrettyUC(aReflowState.ComputedWidth(), width); 1.9445 + DR_state->PrettyUC(aReflowState.ComputedHeight(), height); 1.9446 + printf("c=%s,%s ", width, height); 1.9447 + 1.9448 + if (aFrame->GetStateBits() & NS_FRAME_IS_DIRTY) 1.9449 + printf("dirty "); 1.9450 + 1.9451 + if (aFrame->GetStateBits() & NS_FRAME_HAS_DIRTY_CHILDREN) 1.9452 + printf("dirty-children "); 1.9453 + 1.9454 + if (aReflowState.mFlags.mSpecialHeightReflow) 1.9455 + printf("special-height "); 1.9456 + 1.9457 + if (aReflowState.mFlags.mHResize) 1.9458 + printf("h-resize "); 1.9459 + 1.9460 + if (aReflowState.mFlags.mVResize) 1.9461 + printf("v-resize "); 1.9462 + 1.9463 + nsIFrame* inFlow = aFrame->GetPrevInFlow(); 1.9464 + if (inFlow) { 1.9465 + printf("pif=%p ", (void*)inFlow); 1.9466 + } 1.9467 + inFlow = aFrame->GetNextInFlow(); 1.9468 + if (inFlow) { 1.9469 + printf("nif=%p ", (void*)inFlow); 1.9470 + } 1.9471 + if (aChanged) 1.9472 + printf("CHANGED \n"); 1.9473 + else 1.9474 + printf("cnt=%d \n", DR_state->mCount); 1.9475 + if (DR_state->mDisplayPixelErrors) { 1.9476 + int32_t p2t = aPresContext->AppUnitsPerDevPixel(); 1.9477 + CheckPixelError(aReflowState.AvailableWidth(), p2t); 1.9478 + CheckPixelError(aReflowState.AvailableHeight(), p2t); 1.9479 + CheckPixelError(aReflowState.ComputedWidth(), p2t); 1.9480 + CheckPixelError(aReflowState.ComputedHeight(), p2t); 1.9481 + } 1.9482 + } 1.9483 +} 1.9484 + 1.9485 +void* nsFrame::DisplayReflowEnter(nsPresContext* aPresContext, 1.9486 + nsIFrame* aFrame, 1.9487 + const nsHTMLReflowState& aReflowState) 1.9488 +{ 1.9489 + if (!DR_state->mInited) DR_state->Init(); 1.9490 + if (!DR_state->mActive) return nullptr; 1.9491 + 1.9492 + NS_ASSERTION(aFrame, "invalid call"); 1.9493 + 1.9494 + DR_FrameTreeNode* treeNode = DR_state->CreateTreeNode(aFrame, &aReflowState); 1.9495 + if (treeNode) { 1.9496 + DisplayReflowEnterPrint(aPresContext, aFrame, aReflowState, *treeNode, false); 1.9497 + } 1.9498 + return treeNode; 1.9499 +} 1.9500 + 1.9501 +void* nsFrame::DisplayLayoutEnter(nsIFrame* aFrame) 1.9502 +{ 1.9503 + if (!DR_state->mInited) DR_state->Init(); 1.9504 + if (!DR_state->mActive) return nullptr; 1.9505 + 1.9506 + NS_ASSERTION(aFrame, "invalid call"); 1.9507 + 1.9508 + DR_FrameTreeNode* treeNode = DR_state->CreateTreeNode(aFrame, nullptr); 1.9509 + if (treeNode && treeNode->mDisplay) { 1.9510 + DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent); 1.9511 + printf("Layout\n"); 1.9512 + } 1.9513 + return treeNode; 1.9514 +} 1.9515 + 1.9516 +void* nsFrame::DisplayIntrinsicWidthEnter(nsIFrame* aFrame, 1.9517 + const char* aType) 1.9518 +{ 1.9519 + if (!DR_state->mInited) DR_state->Init(); 1.9520 + if (!DR_state->mActive) return nullptr; 1.9521 + 1.9522 + NS_ASSERTION(aFrame, "invalid call"); 1.9523 + 1.9524 + DR_FrameTreeNode* treeNode = DR_state->CreateTreeNode(aFrame, nullptr); 1.9525 + if (treeNode && treeNode->mDisplay) { 1.9526 + DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent); 1.9527 + printf("Get%sWidth\n", aType); 1.9528 + } 1.9529 + return treeNode; 1.9530 +} 1.9531 + 1.9532 +void* nsFrame::DisplayIntrinsicSizeEnter(nsIFrame* aFrame, 1.9533 + const char* aType) 1.9534 +{ 1.9535 + if (!DR_state->mInited) DR_state->Init(); 1.9536 + if (!DR_state->mActive) return nullptr; 1.9537 + 1.9538 + NS_ASSERTION(aFrame, "invalid call"); 1.9539 + 1.9540 + DR_FrameTreeNode* treeNode = DR_state->CreateTreeNode(aFrame, nullptr); 1.9541 + if (treeNode && treeNode->mDisplay) { 1.9542 + DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent); 1.9543 + printf("Get%sSize\n", aType); 1.9544 + } 1.9545 + return treeNode; 1.9546 +} 1.9547 + 1.9548 +void nsFrame::DisplayReflowExit(nsPresContext* aPresContext, 1.9549 + nsIFrame* aFrame, 1.9550 + nsHTMLReflowMetrics& aMetrics, 1.9551 + nsReflowStatus aStatus, 1.9552 + void* aFrameTreeNode) 1.9553 +{ 1.9554 + if (!DR_state->mActive) return; 1.9555 + 1.9556 + NS_ASSERTION(aFrame, "DisplayReflowExit - invalid call"); 1.9557 + if (!aFrameTreeNode) return; 1.9558 + 1.9559 + DR_FrameTreeNode* treeNode = (DR_FrameTreeNode*)aFrameTreeNode; 1.9560 + if (treeNode->mDisplay) { 1.9561 + DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent); 1.9562 + 1.9563 + char width[16]; 1.9564 + char height[16]; 1.9565 + char x[16]; 1.9566 + char y[16]; 1.9567 + DR_state->PrettyUC(aMetrics.Width(), width); 1.9568 + DR_state->PrettyUC(aMetrics.Height(), height); 1.9569 + printf("Reflow d=%s,%s", width, height); 1.9570 + 1.9571 + if (!NS_FRAME_IS_FULLY_COMPLETE(aStatus)) { 1.9572 + printf(" status=0x%x", aStatus); 1.9573 + } 1.9574 + if (aFrame->HasOverflowAreas()) { 1.9575 + DR_state->PrettyUC(aMetrics.VisualOverflow().x, x); 1.9576 + DR_state->PrettyUC(aMetrics.VisualOverflow().y, y); 1.9577 + DR_state->PrettyUC(aMetrics.VisualOverflow().width, width); 1.9578 + DR_state->PrettyUC(aMetrics.VisualOverflow().height, height); 1.9579 + printf(" vis-o=(%s,%s) %s x %s", x, y, width, height); 1.9580 + 1.9581 + nsRect storedOverflow = aFrame->GetVisualOverflowRect(); 1.9582 + DR_state->PrettyUC(storedOverflow.x, x); 1.9583 + DR_state->PrettyUC(storedOverflow.y, y); 1.9584 + DR_state->PrettyUC(storedOverflow.width, width); 1.9585 + DR_state->PrettyUC(storedOverflow.height, height); 1.9586 + printf(" vis-sto=(%s,%s) %s x %s", x, y, width, height); 1.9587 + 1.9588 + DR_state->PrettyUC(aMetrics.ScrollableOverflow().x, x); 1.9589 + DR_state->PrettyUC(aMetrics.ScrollableOverflow().y, y); 1.9590 + DR_state->PrettyUC(aMetrics.ScrollableOverflow().width, width); 1.9591 + DR_state->PrettyUC(aMetrics.ScrollableOverflow().height, height); 1.9592 + printf(" scr-o=(%s,%s) %s x %s", x, y, width, height); 1.9593 + 1.9594 + storedOverflow = aFrame->GetScrollableOverflowRect(); 1.9595 + DR_state->PrettyUC(storedOverflow.x, x); 1.9596 + DR_state->PrettyUC(storedOverflow.y, y); 1.9597 + DR_state->PrettyUC(storedOverflow.width, width); 1.9598 + DR_state->PrettyUC(storedOverflow.height, height); 1.9599 + printf(" scr-sto=(%s,%s) %s x %s", x, y, width, height); 1.9600 + } 1.9601 + printf("\n"); 1.9602 + if (DR_state->mDisplayPixelErrors) { 1.9603 + int32_t p2t = aPresContext->AppUnitsPerDevPixel(); 1.9604 + CheckPixelError(aMetrics.Width(), p2t); 1.9605 + CheckPixelError(aMetrics.Height(), p2t); 1.9606 + } 1.9607 + } 1.9608 + DR_state->DeleteTreeNode(*treeNode); 1.9609 +} 1.9610 + 1.9611 +void nsFrame::DisplayLayoutExit(nsIFrame* aFrame, 1.9612 + void* aFrameTreeNode) 1.9613 +{ 1.9614 + if (!DR_state->mActive) return; 1.9615 + 1.9616 + NS_ASSERTION(aFrame, "non-null frame required"); 1.9617 + if (!aFrameTreeNode) return; 1.9618 + 1.9619 + DR_FrameTreeNode* treeNode = (DR_FrameTreeNode*)aFrameTreeNode; 1.9620 + if (treeNode->mDisplay) { 1.9621 + DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent); 1.9622 + nsRect rect = aFrame->GetRect(); 1.9623 + printf("Layout=%d,%d,%d,%d\n", rect.x, rect.y, rect.width, rect.height); 1.9624 + } 1.9625 + DR_state->DeleteTreeNode(*treeNode); 1.9626 +} 1.9627 + 1.9628 +void nsFrame::DisplayIntrinsicWidthExit(nsIFrame* aFrame, 1.9629 + const char* aType, 1.9630 + nscoord aResult, 1.9631 + void* aFrameTreeNode) 1.9632 +{ 1.9633 + if (!DR_state->mActive) return; 1.9634 + 1.9635 + NS_ASSERTION(aFrame, "non-null frame required"); 1.9636 + if (!aFrameTreeNode) return; 1.9637 + 1.9638 + DR_FrameTreeNode* treeNode = (DR_FrameTreeNode*)aFrameTreeNode; 1.9639 + if (treeNode->mDisplay) { 1.9640 + DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent); 1.9641 + char width[16]; 1.9642 + DR_state->PrettyUC(aResult, width); 1.9643 + printf("Get%sWidth=%s\n", aType, width); 1.9644 + } 1.9645 + DR_state->DeleteTreeNode(*treeNode); 1.9646 +} 1.9647 + 1.9648 +void nsFrame::DisplayIntrinsicSizeExit(nsIFrame* aFrame, 1.9649 + const char* aType, 1.9650 + nsSize aResult, 1.9651 + void* aFrameTreeNode) 1.9652 +{ 1.9653 + if (!DR_state->mActive) return; 1.9654 + 1.9655 + NS_ASSERTION(aFrame, "non-null frame required"); 1.9656 + if (!aFrameTreeNode) return; 1.9657 + 1.9658 + DR_FrameTreeNode* treeNode = (DR_FrameTreeNode*)aFrameTreeNode; 1.9659 + if (treeNode->mDisplay) { 1.9660 + DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent); 1.9661 + 1.9662 + char width[16]; 1.9663 + char height[16]; 1.9664 + DR_state->PrettyUC(aResult.width, width); 1.9665 + DR_state->PrettyUC(aResult.height, height); 1.9666 + printf("Get%sSize=%s,%s\n", aType, width, height); 1.9667 + } 1.9668 + DR_state->DeleteTreeNode(*treeNode); 1.9669 +} 1.9670 + 1.9671 +/* static */ void 1.9672 +nsFrame::DisplayReflowStartup() 1.9673 +{ 1.9674 + DR_state = new DR_State(); 1.9675 +} 1.9676 + 1.9677 +/* static */ void 1.9678 +nsFrame::DisplayReflowShutdown() 1.9679 +{ 1.9680 + delete DR_state; 1.9681 + DR_state = nullptr; 1.9682 +} 1.9683 + 1.9684 +void DR_cookie::Change() const 1.9685 +{ 1.9686 + DR_FrameTreeNode* treeNode = (DR_FrameTreeNode*)mValue; 1.9687 + if (treeNode && treeNode->mDisplay) { 1.9688 + DisplayReflowEnterPrint(mPresContext, mFrame, mReflowState, *treeNode, true); 1.9689 + } 1.9690 +} 1.9691 + 1.9692 +/* static */ void* 1.9693 +nsHTMLReflowState::DisplayInitConstraintsEnter(nsIFrame* aFrame, 1.9694 + nsHTMLReflowState* aState, 1.9695 + nscoord aContainingBlockWidth, 1.9696 + nscoord aContainingBlockHeight, 1.9697 + const nsMargin* aBorder, 1.9698 + const nsMargin* aPadding) 1.9699 +{ 1.9700 + NS_PRECONDITION(aFrame, "non-null frame required"); 1.9701 + NS_PRECONDITION(aState, "non-null state required"); 1.9702 + 1.9703 + if (!DR_state->mInited) DR_state->Init(); 1.9704 + if (!DR_state->mActive) return nullptr; 1.9705 + 1.9706 + DR_FrameTreeNode* treeNode = DR_state->CreateTreeNode(aFrame, aState); 1.9707 + if (treeNode && treeNode->mDisplay) { 1.9708 + DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent); 1.9709 + 1.9710 + printf("InitConstraints parent=%p", 1.9711 + (void*)aState->parentReflowState); 1.9712 + 1.9713 + char width[16]; 1.9714 + char height[16]; 1.9715 + 1.9716 + DR_state->PrettyUC(aContainingBlockWidth, width); 1.9717 + DR_state->PrettyUC(aContainingBlockHeight, height); 1.9718 + printf(" cb=%s,%s", width, height); 1.9719 + 1.9720 + DR_state->PrettyUC(aState->AvailableWidth(), width); 1.9721 + DR_state->PrettyUC(aState->AvailableHeight(), height); 1.9722 + printf(" as=%s,%s", width, height); 1.9723 + 1.9724 + DR_state->PrintMargin("b", aBorder); 1.9725 + DR_state->PrintMargin("p", aPadding); 1.9726 + putchar('\n'); 1.9727 + } 1.9728 + return treeNode; 1.9729 +} 1.9730 + 1.9731 +/* static */ void 1.9732 +nsHTMLReflowState::DisplayInitConstraintsExit(nsIFrame* aFrame, 1.9733 + nsHTMLReflowState* aState, 1.9734 + void* aValue) 1.9735 +{ 1.9736 + NS_PRECONDITION(aFrame, "non-null frame required"); 1.9737 + NS_PRECONDITION(aState, "non-null state required"); 1.9738 + 1.9739 + if (!DR_state->mActive) return; 1.9740 + if (!aValue) return; 1.9741 + 1.9742 + DR_FrameTreeNode* treeNode = (DR_FrameTreeNode*)aValue; 1.9743 + if (treeNode->mDisplay) { 1.9744 + DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent); 1.9745 + char cmiw[16], cw[16], cmxw[16], cmih[16], ch[16], cmxh[16]; 1.9746 + DR_state->PrettyUC(aState->ComputedMinWidth(), cmiw); 1.9747 + DR_state->PrettyUC(aState->ComputedWidth(), cw); 1.9748 + DR_state->PrettyUC(aState->ComputedMaxWidth(), cmxw); 1.9749 + DR_state->PrettyUC(aState->ComputedMinHeight(), cmih); 1.9750 + DR_state->PrettyUC(aState->ComputedHeight(), ch); 1.9751 + DR_state->PrettyUC(aState->ComputedMaxHeight(), cmxh); 1.9752 + printf("InitConstraints= cw=(%s <= %s <= %s) ch=(%s <= %s <= %s)", 1.9753 + cmiw, cw, cmxw, cmih, ch, cmxh); 1.9754 + DR_state->PrintMargin("co", &aState->ComputedPhysicalOffsets()); 1.9755 + putchar('\n'); 1.9756 + } 1.9757 + DR_state->DeleteTreeNode(*treeNode); 1.9758 +} 1.9759 + 1.9760 + 1.9761 +/* static */ void* 1.9762 +nsCSSOffsetState::DisplayInitOffsetsEnter(nsIFrame* aFrame, 1.9763 + nsCSSOffsetState* aState, 1.9764 + nscoord aHorizontalPercentBasis, 1.9765 + nscoord aVerticalPercentBasis, 1.9766 + const nsMargin* aBorder, 1.9767 + const nsMargin* aPadding) 1.9768 +{ 1.9769 + NS_PRECONDITION(aFrame, "non-null frame required"); 1.9770 + NS_PRECONDITION(aState, "non-null state required"); 1.9771 + 1.9772 + if (!DR_state->mInited) DR_state->Init(); 1.9773 + if (!DR_state->mActive) return nullptr; 1.9774 + 1.9775 + // aState is not necessarily a nsHTMLReflowState 1.9776 + DR_FrameTreeNode* treeNode = DR_state->CreateTreeNode(aFrame, nullptr); 1.9777 + if (treeNode && treeNode->mDisplay) { 1.9778 + DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent); 1.9779 + 1.9780 + char horizPctBasisStr[16]; 1.9781 + char vertPctBasisStr[16]; 1.9782 + DR_state->PrettyUC(aHorizontalPercentBasis, horizPctBasisStr); 1.9783 + DR_state->PrettyUC(aVerticalPercentBasis, vertPctBasisStr); 1.9784 + printf("InitOffsets pct_basis=%s,%s", horizPctBasisStr, vertPctBasisStr); 1.9785 + 1.9786 + DR_state->PrintMargin("b", aBorder); 1.9787 + DR_state->PrintMargin("p", aPadding); 1.9788 + putchar('\n'); 1.9789 + } 1.9790 + return treeNode; 1.9791 +} 1.9792 + 1.9793 +/* static */ void 1.9794 +nsCSSOffsetState::DisplayInitOffsetsExit(nsIFrame* aFrame, 1.9795 + nsCSSOffsetState* aState, 1.9796 + void* aValue) 1.9797 +{ 1.9798 + NS_PRECONDITION(aFrame, "non-null frame required"); 1.9799 + NS_PRECONDITION(aState, "non-null state required"); 1.9800 + 1.9801 + if (!DR_state->mActive) return; 1.9802 + if (!aValue) return; 1.9803 + 1.9804 + DR_FrameTreeNode* treeNode = (DR_FrameTreeNode*)aValue; 1.9805 + if (treeNode->mDisplay) { 1.9806 + DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent); 1.9807 + printf("InitOffsets="); 1.9808 + DR_state->PrintMargin("m", &aState->ComputedPhysicalMargin()); 1.9809 + DR_state->PrintMargin("p", &aState->ComputedPhysicalPadding()); 1.9810 + DR_state->PrintMargin("p+b", &aState->ComputedPhysicalBorderPadding()); 1.9811 + putchar('\n'); 1.9812 + } 1.9813 + DR_state->DeleteTreeNode(*treeNode); 1.9814 +} 1.9815 + 1.9816 +/* static */ void* 1.9817 +nsHTMLReflowState::DisplayInitFrameTypeEnter(nsIFrame* aFrame, 1.9818 + nsHTMLReflowState* aState) 1.9819 +{ 1.9820 + NS_PRECONDITION(aFrame, "non-null frame required"); 1.9821 + NS_PRECONDITION(aState, "non-null state required"); 1.9822 + 1.9823 + if (!DR_state->mInited) DR_state->Init(); 1.9824 + if (!DR_state->mActive) return nullptr; 1.9825 + 1.9826 + // we don't print anything here 1.9827 + return DR_state->CreateTreeNode(aFrame, aState); 1.9828 +} 1.9829 + 1.9830 +/* static */ void 1.9831 +nsHTMLReflowState::DisplayInitFrameTypeExit(nsIFrame* aFrame, 1.9832 + nsHTMLReflowState* aState, 1.9833 + void* aValue) 1.9834 +{ 1.9835 + NS_PRECONDITION(aFrame, "non-null frame required"); 1.9836 + NS_PRECONDITION(aState, "non-null state required"); 1.9837 + 1.9838 + if (!DR_state->mActive) return; 1.9839 + if (!aValue) return; 1.9840 + 1.9841 + DR_FrameTreeNode* treeNode = (DR_FrameTreeNode*)aValue; 1.9842 + if (treeNode->mDisplay) { 1.9843 + DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent); 1.9844 + printf("InitFrameType"); 1.9845 + 1.9846 + const nsStyleDisplay *disp = aState->mStyleDisplay; 1.9847 + 1.9848 + if (aFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) 1.9849 + printf(" out-of-flow"); 1.9850 + if (aFrame->GetPrevInFlow()) 1.9851 + printf(" prev-in-flow"); 1.9852 + if (aFrame->IsAbsolutelyPositioned()) 1.9853 + printf(" abspos"); 1.9854 + if (aFrame->IsFloating()) 1.9855 + printf(" float"); 1.9856 + 1.9857 + // This array must exactly match the NS_STYLE_DISPLAY constants. 1.9858 + const char *const displayTypes[] = { 1.9859 + "none", "block", "inline", "inline-block", "list-item", "marker", 1.9860 + "run-in", "compact", "table", "inline-table", "table-row-group", 1.9861 + "table-column", "table-column-group", "table-header-group", 1.9862 + "table-footer-group", "table-row", "table-cell", "table-caption", 1.9863 + "box", "inline-box", 1.9864 +#ifdef MOZ_XUL 1.9865 + "grid", "inline-grid", "grid-group", "grid-line", "stack", 1.9866 + "inline-stack", "deck", "popup", "groupbox", 1.9867 +#endif 1.9868 + }; 1.9869 + if (disp->mDisplay >= ArrayLength(displayTypes)) 1.9870 + printf(" display=%u", disp->mDisplay); 1.9871 + else 1.9872 + printf(" display=%s", displayTypes[disp->mDisplay]); 1.9873 + 1.9874 + // This array must exactly match the NS_CSS_FRAME_TYPE constants. 1.9875 + const char *const cssFrameTypes[] = { 1.9876 + "unknown", "inline", "block", "floating", "absolute", "internal-table" 1.9877 + }; 1.9878 + nsCSSFrameType bareType = NS_FRAME_GET_TYPE(aState->mFrameType); 1.9879 + bool repNoBlock = NS_FRAME_IS_REPLACED_NOBLOCK(aState->mFrameType); 1.9880 + bool repBlock = NS_FRAME_IS_REPLACED_CONTAINS_BLOCK(aState->mFrameType); 1.9881 + 1.9882 + if (bareType >= ArrayLength(cssFrameTypes)) { 1.9883 + printf(" result=type %u", bareType); 1.9884 + } else { 1.9885 + printf(" result=%s", cssFrameTypes[bareType]); 1.9886 + } 1.9887 + printf("%s%s\n", repNoBlock ? " +rep" : "", repBlock ? " +repBlk" : ""); 1.9888 + } 1.9889 + DR_state->DeleteTreeNode(*treeNode); 1.9890 +} 1.9891 + 1.9892 +#endif 1.9893 +// End Display Reflow 1.9894 + 1.9895 +#endif