123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109 |
- /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
- /* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
- //
- // Eric Vaughan
- // Netscape Communications
- //
- // See documentation in associated header file
- //
- // How boxes layout
- // ----------------
- // Boxes layout a bit differently than html. html does a bottom up layout. Where boxes do a top down.
- // 1) First thing a box does it goes out and askes each child for its min, max, and preferred sizes.
- // 2) It then adds them up to determine its size.
- // 3) If the box was asked to layout it self intrinically it will layout its children at their preferred size
- // otherwise it will layout the child at the size it was told to. It will squeeze or stretch its children if
- // Necessary.
- //
- // However there is a catch. Some html components like block frames can not determine their preferred size.
- // this is their size if they were laid out intrinsically. So the box will flow the child to determine this can
- // cache the value.
- // Boxes and Incremental Reflow
- // ----------------------------
- // Boxes layout out top down by adding up their children's min, max, and preferred sizes. Only problem is if a incremental
- // reflow occurs. The preferred size of a child deep in the hierarchy could change. And this could change
- // any number of syblings around the box. Basically any children in the reflow chain must have their caches cleared
- // so when asked for there current size they can relayout themselves.
- #include "nsBoxFrame.h"
- #include "gfxUtils.h"
- #include "mozilla/gfx/2D.h"
- #include "nsBoxLayoutState.h"
- #include "mozilla/dom/Touch.h"
- #include "mozilla/Move.h"
- #include "nsStyleContext.h"
- #include "nsPlaceholderFrame.h"
- #include "nsPresContext.h"
- #include "nsCOMPtr.h"
- #include "nsNameSpaceManager.h"
- #include "nsGkAtoms.h"
- #include "nsIContent.h"
- #include "nsHTMLParts.h"
- #include "nsViewManager.h"
- #include "nsView.h"
- #include "nsIPresShell.h"
- #include "nsCSSRendering.h"
- #include "nsIServiceManager.h"
- #include "nsBoxLayout.h"
- #include "nsSprocketLayout.h"
- #include "nsIScrollableFrame.h"
- #include "nsWidgetsCID.h"
- #include "nsCSSAnonBoxes.h"
- #include "nsContainerFrame.h"
- #include "nsIDOMElement.h"
- #include "nsITheme.h"
- #include "nsTransform2D.h"
- #include "mozilla/EventStateManager.h"
- #include "nsIDOMEvent.h"
- #include "nsDisplayList.h"
- #include "mozilla/Preferences.h"
- #include "nsThemeConstants.h"
- #include "nsLayoutUtils.h"
- #include "nsSliderFrame.h"
- #include <algorithm>
- // Needed for Print Preview
- #include "nsIURI.h"
- #include "mozilla/TouchEvents.h"
- using namespace mozilla;
- using namespace mozilla::dom;
- using namespace mozilla::gfx;
- //define DEBUG_REDRAW
- #define DEBUG_SPRING_SIZE 8
- #define DEBUG_BORDER_SIZE 2
- #define COIL_SIZE 8
- //#define TEST_SANITY
- #ifdef DEBUG_rods
- //#define DO_NOISY_REFLOW
- #endif
- #ifdef DEBUG_LAYOUT
- bool nsBoxFrame::gDebug = false;
- nsIFrame* nsBoxFrame::mDebugChild = nullptr;
- #endif
- nsIFrame*
- NS_NewBoxFrame(nsIPresShell* aPresShell, nsStyleContext* aContext, bool aIsRoot, nsBoxLayout* aLayoutManager)
- {
- return new (aPresShell) nsBoxFrame(aContext, aIsRoot, aLayoutManager);
- }
- nsIFrame*
- NS_NewBoxFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
- {
- return new (aPresShell) nsBoxFrame(aContext);
- }
- NS_IMPL_FRAMEARENA_HELPERS(nsBoxFrame)
- #ifdef DEBUG
- NS_QUERYFRAME_HEAD(nsBoxFrame)
- NS_QUERYFRAME_ENTRY(nsBoxFrame)
- NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)
- #endif
- nsBoxFrame::nsBoxFrame(nsStyleContext* aContext,
- bool aIsRoot,
- nsBoxLayout* aLayoutManager) :
- nsContainerFrame(aContext)
- {
- mState |= NS_STATE_IS_HORIZONTAL;
- mState |= NS_STATE_AUTO_STRETCH;
- if (aIsRoot)
- mState |= NS_STATE_IS_ROOT;
- mValign = vAlign_Top;
- mHalign = hAlign_Left;
-
- // if no layout manager specified us the static sprocket layout
- nsCOMPtr<nsBoxLayout> layout = aLayoutManager;
- if (layout == nullptr) {
- NS_NewSprocketLayout(layout);
- }
- SetXULLayoutManager(layout);
- }
- nsBoxFrame::~nsBoxFrame()
- {
- }
- void
- nsBoxFrame::SetInitialChildList(ChildListID aListID,
- nsFrameList& aChildList)
- {
- nsContainerFrame::SetInitialChildList(aListID, aChildList);
- if (aListID == kPrincipalList) {
- // initialize our list of infos.
- nsBoxLayoutState state(PresContext());
- CheckBoxOrder();
- if (mLayoutManager)
- mLayoutManager->ChildrenSet(this, state, mFrames.FirstChild());
- }
- }
- /* virtual */ void
- nsBoxFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext)
- {
- nsContainerFrame::DidSetStyleContext(aOldStyleContext);
- // The values that CacheAttributes() computes depend on our style,
- // so we need to recompute them here...
- CacheAttributes();
- }
- /**
- * Initialize us. This is a good time to get the alignment of the box
- */
- void
- nsBoxFrame::Init(nsIContent* aContent,
- nsContainerFrame* aParent,
- nsIFrame* aPrevInFlow)
- {
- nsContainerFrame::Init(aContent, aParent, aPrevInFlow);
- if (GetStateBits() & NS_FRAME_FONT_INFLATION_CONTAINER) {
- AddStateBits(NS_FRAME_FONT_INFLATION_FLOW_ROOT);
- }
- MarkIntrinsicISizesDirty();
- CacheAttributes();
- #ifdef DEBUG_LAYOUT
- // if we are root and this
- if (mState & NS_STATE_IS_ROOT) {
- GetDebugPref();
- }
- #endif
- UpdateMouseThrough();
- // register access key
- RegUnregAccessKey(true);
- }
- void nsBoxFrame::UpdateMouseThrough()
- {
- if (mContent) {
- static nsIContent::AttrValuesArray strings[] =
- {&nsGkAtoms::never, &nsGkAtoms::always, nullptr};
- switch (mContent->FindAttrValueIn(kNameSpaceID_None,
- nsGkAtoms::mousethrough, strings, eCaseMatters)) {
- case 0: AddStateBits(NS_FRAME_MOUSE_THROUGH_NEVER); break;
- case 1: AddStateBits(NS_FRAME_MOUSE_THROUGH_ALWAYS); break;
- case 2: {
- RemoveStateBits(NS_FRAME_MOUSE_THROUGH_ALWAYS);
- RemoveStateBits(NS_FRAME_MOUSE_THROUGH_NEVER);
- break;
- }
- }
- }
- }
- void
- nsBoxFrame::CacheAttributes()
- {
- /*
- printf("Caching: ");
- XULDumpBox(stdout);
- printf("\n");
- */
- mValign = vAlign_Top;
- mHalign = hAlign_Left;
- bool orient = false;
- GetInitialOrientation(orient);
- if (orient)
- mState |= NS_STATE_IS_HORIZONTAL;
- else
- mState &= ~NS_STATE_IS_HORIZONTAL;
- bool normal = true;
- GetInitialDirection(normal);
- if (normal)
- mState |= NS_STATE_IS_DIRECTION_NORMAL;
- else
- mState &= ~NS_STATE_IS_DIRECTION_NORMAL;
- GetInitialVAlignment(mValign);
- GetInitialHAlignment(mHalign);
-
- bool equalSize = false;
- GetInitialEqualSize(equalSize);
- if (equalSize)
- mState |= NS_STATE_EQUAL_SIZE;
- else
- mState &= ~NS_STATE_EQUAL_SIZE;
- bool autostretch = !!(mState & NS_STATE_AUTO_STRETCH);
- GetInitialAutoStretch(autostretch);
- if (autostretch)
- mState |= NS_STATE_AUTO_STRETCH;
- else
- mState &= ~NS_STATE_AUTO_STRETCH;
- #ifdef DEBUG_LAYOUT
- bool debug = mState & NS_STATE_SET_TO_DEBUG;
- bool debugSet = GetInitialDebug(debug);
- if (debugSet) {
- mState |= NS_STATE_DEBUG_WAS_SET;
- if (debug)
- mState |= NS_STATE_SET_TO_DEBUG;
- else
- mState &= ~NS_STATE_SET_TO_DEBUG;
- } else {
- mState &= ~NS_STATE_DEBUG_WAS_SET;
- }
- #endif
- }
- #ifdef DEBUG_LAYOUT
- bool
- nsBoxFrame::GetInitialDebug(bool& aDebug)
- {
- if (!GetContent())
- return false;
- static nsIContent::AttrValuesArray strings[] =
- {&nsGkAtoms::_false, &nsGkAtoms::_true, nullptr};
- int32_t index = GetContent()->FindAttrValueIn(kNameSpaceID_None,
- nsGkAtoms::debug, strings, eCaseMatters);
- if (index >= 0) {
- aDebug = index == 1;
- return true;
- }
- return false;
- }
- #endif
- bool
- nsBoxFrame::GetInitialHAlignment(nsBoxFrame::Halignment& aHalign)
- {
- if (!GetContent())
- return false;
- // XXXdwh Everything inside this if statement is deprecated code.
- static nsIContent::AttrValuesArray alignStrings[] =
- {&nsGkAtoms::left, &nsGkAtoms::right, nullptr};
- static const Halignment alignValues[] = {hAlign_Left, hAlign_Right};
- int32_t index = GetContent()->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::align,
- alignStrings, eCaseMatters);
- if (index >= 0) {
- aHalign = alignValues[index];
- return true;
- }
-
- // Now that the deprecated stuff is out of the way, we move on to check the appropriate
- // attribute. For horizontal boxes, we are checking the PACK attribute. For vertical boxes
- // we are checking the ALIGN attribute.
- nsIAtom* attrName = IsXULHorizontal() ? nsGkAtoms::pack : nsGkAtoms::align;
- static nsIContent::AttrValuesArray strings[] =
- {&nsGkAtoms::_empty, &nsGkAtoms::start, &nsGkAtoms::center, &nsGkAtoms::end, nullptr};
- static const Halignment values[] =
- {hAlign_Left/*not used*/, hAlign_Left, hAlign_Center, hAlign_Right};
- index = GetContent()->FindAttrValueIn(kNameSpaceID_None, attrName,
- strings, eCaseMatters);
- if (index == nsIContent::ATTR_VALUE_NO_MATCH) {
- // The attr was present but had a nonsensical value. Revert to the default.
- return false;
- }
- if (index > 0) {
- aHalign = values[index];
- return true;
- }
- // Now that we've checked for the attribute it's time to check CSS. For
- // horizontal boxes we're checking PACK. For vertical boxes we are checking
- // ALIGN.
- const nsStyleXUL* boxInfo = StyleXUL();
- if (IsXULHorizontal()) {
- switch (boxInfo->mBoxPack) {
- case StyleBoxPack::Start:
- aHalign = nsBoxFrame::hAlign_Left;
- return true;
- case StyleBoxPack::Center:
- aHalign = nsBoxFrame::hAlign_Center;
- return true;
- case StyleBoxPack::End:
- aHalign = nsBoxFrame::hAlign_Right;
- return true;
- default: // Nonsensical value. Just bail.
- return false;
- }
- }
- else {
- switch (boxInfo->mBoxAlign) {
- case StyleBoxAlign::Start:
- aHalign = nsBoxFrame::hAlign_Left;
- return true;
- case StyleBoxAlign::Center:
- aHalign = nsBoxFrame::hAlign_Center;
- return true;
- case StyleBoxAlign::End:
- aHalign = nsBoxFrame::hAlign_Right;
- return true;
- default: // Nonsensical value. Just bail.
- return false;
- }
- }
- return false;
- }
- bool
- nsBoxFrame::GetInitialVAlignment(nsBoxFrame::Valignment& aValign)
- {
- if (!GetContent())
- return false;
- static nsIContent::AttrValuesArray valignStrings[] =
- {&nsGkAtoms::top, &nsGkAtoms::baseline, &nsGkAtoms::middle, &nsGkAtoms::bottom, nullptr};
- static const Valignment valignValues[] =
- {vAlign_Top, vAlign_BaseLine, vAlign_Middle, vAlign_Bottom};
- int32_t index = GetContent()->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::valign,
- valignStrings, eCaseMatters);
- if (index >= 0) {
- aValign = valignValues[index];
- return true;
- }
- // Now that the deprecated stuff is out of the way, we move on to check the appropriate
- // attribute. For horizontal boxes, we are checking the ALIGN attribute. For vertical boxes
- // we are checking the PACK attribute.
- nsIAtom* attrName = IsXULHorizontal() ? nsGkAtoms::align : nsGkAtoms::pack;
- static nsIContent::AttrValuesArray strings[] =
- {&nsGkAtoms::_empty, &nsGkAtoms::start, &nsGkAtoms::center,
- &nsGkAtoms::baseline, &nsGkAtoms::end, nullptr};
- static const Valignment values[] =
- {vAlign_Top/*not used*/, vAlign_Top, vAlign_Middle, vAlign_BaseLine, vAlign_Bottom};
- index = GetContent()->FindAttrValueIn(kNameSpaceID_None, attrName,
- strings, eCaseMatters);
- if (index == nsIContent::ATTR_VALUE_NO_MATCH) {
- // The attr was present but had a nonsensical value. Revert to the default.
- return false;
- }
- if (index > 0) {
- aValign = values[index];
- return true;
- }
- // Now that we've checked for the attribute it's time to check CSS. For
- // horizontal boxes we're checking ALIGN. For vertical boxes we are checking
- // PACK.
- const nsStyleXUL* boxInfo = StyleXUL();
- if (IsXULHorizontal()) {
- switch (boxInfo->mBoxAlign) {
- case StyleBoxAlign::Start:
- aValign = nsBoxFrame::vAlign_Top;
- return true;
- case StyleBoxAlign::Center:
- aValign = nsBoxFrame::vAlign_Middle;
- return true;
- case StyleBoxAlign::Baseline:
- aValign = nsBoxFrame::vAlign_BaseLine;
- return true;
- case StyleBoxAlign::End:
- aValign = nsBoxFrame::vAlign_Bottom;
- return true;
- default: // Nonsensical value. Just bail.
- return false;
- }
- }
- else {
- switch (boxInfo->mBoxPack) {
- case StyleBoxPack::Start:
- aValign = nsBoxFrame::vAlign_Top;
- return true;
- case StyleBoxPack::Center:
- aValign = nsBoxFrame::vAlign_Middle;
- return true;
- case StyleBoxPack::End:
- aValign = nsBoxFrame::vAlign_Bottom;
- return true;
- default: // Nonsensical value. Just bail.
- return false;
- }
- }
- return false;
- }
- void
- nsBoxFrame::GetInitialOrientation(bool& aIsHorizontal)
- {
- // see if we are a vertical or horizontal box.
- if (!GetContent())
- return;
- // Check the style system first.
- const nsStyleXUL* boxInfo = StyleXUL();
- if (boxInfo->mBoxOrient == StyleBoxOrient::Horizontal) {
- aIsHorizontal = true;
- } else {
- aIsHorizontal = false;
- }
- // Now see if we have an attribute. The attribute overrides
- // the style system value.
- static nsIContent::AttrValuesArray strings[] =
- {&nsGkAtoms::vertical, &nsGkAtoms::horizontal, nullptr};
- int32_t index = GetContent()->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::orient,
- strings, eCaseMatters);
- if (index >= 0) {
- aIsHorizontal = index == 1;
- }
- }
- void
- nsBoxFrame::GetInitialDirection(bool& aIsNormal)
- {
- if (!GetContent())
- return;
- if (IsXULHorizontal()) {
- // For horizontal boxes only, we initialize our value based off the CSS 'direction' property.
- // This means that BiDI users will end up with horizontally inverted chrome.
- aIsNormal = (StyleVisibility()->mDirection == NS_STYLE_DIRECTION_LTR); // If text runs RTL then so do we.
- }
- else
- aIsNormal = true; // Assume a normal direction in the vertical case.
- // Now check the style system to see if we should invert aIsNormal.
- const nsStyleXUL* boxInfo = StyleXUL();
- if (boxInfo->mBoxDirection == StyleBoxDirection::Reverse) {
- aIsNormal = !aIsNormal; // Invert our direction.
- }
- // Now see if we have an attribute. The attribute overrides
- // the style system value.
- if (IsXULHorizontal()) {
- static nsIContent::AttrValuesArray strings[] =
- {&nsGkAtoms::reverse, &nsGkAtoms::ltr, &nsGkAtoms::rtl, nullptr};
- int32_t index = GetContent()->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::dir,
- strings, eCaseMatters);
- if (index >= 0) {
- bool values[] = {!aIsNormal, true, false};
- aIsNormal = values[index];
- }
- } else if (GetContent()->AttrValueIs(kNameSpaceID_None, nsGkAtoms::dir,
- nsGkAtoms::reverse, eCaseMatters)) {
- aIsNormal = !aIsNormal;
- }
- }
- /* Returns true if it was set.
- */
- bool
- nsBoxFrame::GetInitialEqualSize(bool& aEqualSize)
- {
- // see if we are a vertical or horizontal box.
- if (!GetContent())
- return false;
- if (GetContent()->AttrValueIs(kNameSpaceID_None, nsGkAtoms::equalsize,
- nsGkAtoms::always, eCaseMatters)) {
- aEqualSize = true;
- return true;
- }
- return false;
- }
- /* Returns true if it was set.
- */
- bool
- nsBoxFrame::GetInitialAutoStretch(bool& aStretch)
- {
- if (!GetContent())
- return false;
-
- // Check the align attribute.
- static nsIContent::AttrValuesArray strings[] =
- {&nsGkAtoms::_empty, &nsGkAtoms::stretch, nullptr};
- int32_t index = GetContent()->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::align,
- strings, eCaseMatters);
- if (index != nsIContent::ATTR_MISSING && index != 0) {
- aStretch = index == 1;
- return true;
- }
- // Check the CSS box-align property.
- const nsStyleXUL* boxInfo = StyleXUL();
- aStretch = (boxInfo->mBoxAlign == StyleBoxAlign::Stretch);
- return true;
- }
- void
- nsBoxFrame::DidReflow(nsPresContext* aPresContext,
- const ReflowInput* aReflowInput,
- nsDidReflowStatus aStatus)
- {
- nsFrameState preserveBits =
- mState & (NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN);
- nsFrame::DidReflow(aPresContext, aReflowInput, aStatus);
- mState |= preserveBits;
- }
- bool
- nsBoxFrame::HonorPrintBackgroundSettings()
- {
- return (!mContent || !mContent->IsInNativeAnonymousSubtree()) &&
- nsContainerFrame::HonorPrintBackgroundSettings();
- }
- #ifdef DO_NOISY_REFLOW
- static int myCounter = 0;
- static void printSize(char * aDesc, nscoord aSize)
- {
- printf(" %s: ", aDesc);
- if (aSize == NS_UNCONSTRAINEDSIZE) {
- printf("UC");
- } else {
- printf("%d", aSize);
- }
- }
- #endif
- /* virtual */ nscoord
- nsBoxFrame::GetMinISize(nsRenderingContext *aRenderingContext)
- {
- nscoord result;
- DISPLAY_MIN_WIDTH(this, result);
- nsBoxLayoutState state(PresContext(), aRenderingContext);
- nsSize minSize = GetXULMinSize(state);
- // GetXULMinSize returns border-box width, and we want to return content
- // width. Since Reflow uses the reflow state's border and padding, we
- // actually just want to subtract what GetXULMinSize added, which is the
- // result of GetXULBorderAndPadding.
- nsMargin bp;
- GetXULBorderAndPadding(bp);
- result = minSize.width - bp.LeftRight();
- result = std::max(result, 0);
- return result;
- }
- /* virtual */ nscoord
- nsBoxFrame::GetPrefISize(nsRenderingContext *aRenderingContext)
- {
- nscoord result;
- DISPLAY_PREF_WIDTH(this, result);
- nsBoxLayoutState state(PresContext(), aRenderingContext);
- nsSize prefSize = GetXULPrefSize(state);
- // GetXULPrefSize returns border-box width, and we want to return content
- // width. Since Reflow uses the reflow state's border and padding, we
- // actually just want to subtract what GetXULPrefSize added, which is the
- // result of GetXULBorderAndPadding.
- nsMargin bp;
- GetXULBorderAndPadding(bp);
- result = prefSize.width - bp.LeftRight();
- result = std::max(result, 0);
- return result;
- }
- void
- nsBoxFrame::Reflow(nsPresContext* aPresContext,
- ReflowOutput& aDesiredSize,
- const ReflowInput& aReflowInput,
- nsReflowStatus& aStatus)
- {
- MarkInReflow();
- // If you make changes to this method, please keep nsLeafBoxFrame::Reflow
- // in sync, if the changes are applicable there.
- DO_GLOBAL_REFLOW_COUNT("nsBoxFrame");
- DISPLAY_REFLOW(aPresContext, this, aReflowInput, aDesiredSize, aStatus);
- NS_ASSERTION(aReflowInput.ComputedWidth() >=0 &&
- aReflowInput.ComputedHeight() >= 0, "Computed Size < 0");
- #ifdef DO_NOISY_REFLOW
- printf("\n-------------Starting BoxFrame Reflow ----------------------------\n");
- printf("%p ** nsBF::Reflow %d ", this, myCounter++);
-
- printSize("AW", aReflowInput.AvailableWidth());
- printSize("AH", aReflowInput.AvailableHeight());
- printSize("CW", aReflowInput.ComputedWidth());
- printSize("CH", aReflowInput.ComputedHeight());
- printf(" *\n");
- #endif
- aStatus = NS_FRAME_COMPLETE;
- // create the layout state
- nsBoxLayoutState state(aPresContext, aReflowInput.mRenderingContext,
- &aReflowInput, aReflowInput.mReflowDepth);
- WritingMode wm = aReflowInput.GetWritingMode();
- LogicalSize computedSize(wm, aReflowInput.ComputedISize(),
- aReflowInput.ComputedBSize());
- LogicalMargin m = aReflowInput.ComputedLogicalBorderPadding();
- // GetXULBorderAndPadding(m);
- LogicalSize prefSize(wm);
- // if we are told to layout intrinsic then get our preferred size.
- NS_ASSERTION(computedSize.ISize(wm) != NS_INTRINSICSIZE,
- "computed inline size should always be computed");
- if (computedSize.BSize(wm) == NS_INTRINSICSIZE) {
- nsSize physicalPrefSize = GetXULPrefSize(state);
- nsSize minSize = GetXULMinSize(state);
- nsSize maxSize = GetXULMaxSize(state);
- // XXXbz isn't GetXULPrefSize supposed to bounds-check for us?
- physicalPrefSize = BoundsCheck(minSize, physicalPrefSize, maxSize);
- prefSize = LogicalSize(wm, physicalPrefSize);
- }
- // get our desiredSize
- computedSize.ISize(wm) += m.IStart(wm) + m.IEnd(wm);
- if (aReflowInput.ComputedBSize() == NS_INTRINSICSIZE) {
- computedSize.BSize(wm) = prefSize.BSize(wm);
- // prefSize is border-box but min/max constraints are content-box.
- nscoord blockDirBorderPadding =
- aReflowInput.ComputedLogicalBorderPadding().BStartEnd(wm);
- nscoord contentBSize = computedSize.BSize(wm) - blockDirBorderPadding;
- // Note: contentHeight might be negative, but that's OK because min-height
- // is never negative.
- computedSize.BSize(wm) = aReflowInput.ApplyMinMaxHeight(contentBSize) +
- blockDirBorderPadding;
- } else {
- computedSize.BSize(wm) += m.BStart(wm) + m.BEnd(wm);
- }
- nsSize physicalSize = computedSize.GetPhysicalSize(wm);
- nsRect r(mRect.x, mRect.y, physicalSize.width, physicalSize.height);
- SetXULBounds(state, r);
-
- // layout our children
- XULLayout(state);
-
- // ok our child could have gotten bigger. So lets get its bounds
-
- // get the ascent
- LogicalSize boxSize = GetLogicalSize(wm);
- nscoord ascent = boxSize.BSize(wm);
- // getting the ascent could be a lot of work. Don't get it if
- // we are the root. The viewport doesn't care about it.
- if (!(mState & NS_STATE_IS_ROOT)) {
- ascent = GetXULBoxAscent(state);
- }
- aDesiredSize.SetSize(wm, boxSize);
- aDesiredSize.SetBlockStartAscent(ascent);
- aDesiredSize.mOverflowAreas = GetOverflowAreas();
- #ifdef DO_NOISY_REFLOW
- {
- printf("%p ** nsBF(done) W:%d H:%d ", this, aDesiredSize.Width(), aDesiredSize.Height());
- if (maxElementSize) {
- printf("MW:%d\n", *maxElementWidth);
- } else {
- printf("MW:?\n");
- }
- }
- #endif
- ReflowAbsoluteFrames(aPresContext, aDesiredSize, aReflowInput, aStatus);
- NS_FRAME_SET_TRUNCATION(aStatus, aReflowInput, aDesiredSize);
- }
- nsSize
- nsBoxFrame::GetXULPrefSize(nsBoxLayoutState& aBoxLayoutState)
- {
- NS_ASSERTION(aBoxLayoutState.GetRenderingContext(),
- "must have rendering context");
- nsSize size(0,0);
- DISPLAY_PREF_SIZE(this, size);
- if (!DoesNeedRecalc(mPrefSize)) {
- return mPrefSize;
- }
- #ifdef DEBUG_LAYOUT
- PropagateDebug(aBoxLayoutState);
- #endif
- if (IsXULCollapsed())
- return size;
- // if the size was not completely redefined in CSS then ask our children
- bool widthSet, heightSet;
- if (!nsIFrame::AddXULPrefSize(this, size, widthSet, heightSet))
- {
- if (mLayoutManager) {
- nsSize layoutSize = mLayoutManager->GetXULPrefSize(this, aBoxLayoutState);
- if (!widthSet)
- size.width = layoutSize.width;
- if (!heightSet)
- size.height = layoutSize.height;
- }
- else {
- size = nsBox::GetXULPrefSize(aBoxLayoutState);
- }
- }
- nsSize minSize = GetXULMinSize(aBoxLayoutState);
- nsSize maxSize = GetXULMaxSize(aBoxLayoutState);
- mPrefSize = BoundsCheck(minSize, size, maxSize);
-
- return mPrefSize;
- }
- nscoord
- nsBoxFrame::GetXULBoxAscent(nsBoxLayoutState& aBoxLayoutState)
- {
- if (!DoesNeedRecalc(mAscent))
- return mAscent;
- #ifdef DEBUG_LAYOUT
- PropagateDebug(aBoxLayoutState);
- #endif
- if (IsXULCollapsed())
- return 0;
- if (mLayoutManager)
- mAscent = mLayoutManager->GetAscent(this, aBoxLayoutState);
- else
- mAscent = nsBox::GetXULBoxAscent(aBoxLayoutState);
- return mAscent;
- }
- nsSize
- nsBoxFrame::GetXULMinSize(nsBoxLayoutState& aBoxLayoutState)
- {
- NS_ASSERTION(aBoxLayoutState.GetRenderingContext(),
- "must have rendering context");
- nsSize size(0,0);
- DISPLAY_MIN_SIZE(this, size);
- if (!DoesNeedRecalc(mMinSize)) {
- return mMinSize;
- }
- #ifdef DEBUG_LAYOUT
- PropagateDebug(aBoxLayoutState);
- #endif
- if (IsXULCollapsed())
- return size;
- // if the size was not completely redefined in CSS then ask our children
- bool widthSet, heightSet;
- if (!nsIFrame::AddXULMinSize(aBoxLayoutState, this, size, widthSet, heightSet))
- {
- if (mLayoutManager) {
- nsSize layoutSize = mLayoutManager->GetXULMinSize(this, aBoxLayoutState);
- if (!widthSet)
- size.width = layoutSize.width;
- if (!heightSet)
- size.height = layoutSize.height;
- }
- else {
- size = nsBox::GetXULMinSize(aBoxLayoutState);
- }
- }
-
- mMinSize = size;
- return size;
- }
- nsSize
- nsBoxFrame::GetXULMaxSize(nsBoxLayoutState& aBoxLayoutState)
- {
- NS_ASSERTION(aBoxLayoutState.GetRenderingContext(),
- "must have rendering context");
- nsSize size(NS_INTRINSICSIZE, NS_INTRINSICSIZE);
- DISPLAY_MAX_SIZE(this, size);
- if (!DoesNeedRecalc(mMaxSize)) {
- return mMaxSize;
- }
- #ifdef DEBUG_LAYOUT
- PropagateDebug(aBoxLayoutState);
- #endif
- if (IsXULCollapsed())
- return size;
- // if the size was not completely redefined in CSS then ask our children
- bool widthSet, heightSet;
- if (!nsIFrame::AddXULMaxSize(this, size, widthSet, heightSet))
- {
- if (mLayoutManager) {
- nsSize layoutSize = mLayoutManager->GetXULMaxSize(this, aBoxLayoutState);
- if (!widthSet)
- size.width = layoutSize.width;
- if (!heightSet)
- size.height = layoutSize.height;
- }
- else {
- size = nsBox::GetXULMaxSize(aBoxLayoutState);
- }
- }
- mMaxSize = size;
- return size;
- }
- nscoord
- nsBoxFrame::GetXULFlex()
- {
- if (!DoesNeedRecalc(mFlex))
- return mFlex;
- mFlex = nsBox::GetXULFlex();
- return mFlex;
- }
- /**
- * If subclassing please subclass this method not layout.
- * layout will call this method.
- */
- NS_IMETHODIMP
- nsBoxFrame::DoXULLayout(nsBoxLayoutState& aState)
- {
- uint32_t oldFlags = aState.LayoutFlags();
- aState.SetLayoutFlags(0);
- nsresult rv = NS_OK;
- if (mLayoutManager) {
- CoordNeedsRecalc(mAscent);
- rv = mLayoutManager->XULLayout(this, aState);
- }
- aState.SetLayoutFlags(oldFlags);
- if (HasAbsolutelyPositionedChildren()) {
- // Set up a |reflowInput| to pass into ReflowAbsoluteFrames
- WritingMode wm = GetWritingMode();
- ReflowInput reflowInput(aState.PresContext(), this,
- aState.GetRenderingContext(),
- LogicalSize(wm, GetLogicalSize().ISize(wm),
- NS_UNCONSTRAINEDSIZE));
- // Set up a |desiredSize| to pass into ReflowAbsoluteFrames
- ReflowOutput desiredSize(reflowInput);
- desiredSize.Width() = mRect.width;
- desiredSize.Height() = mRect.height;
- // get the ascent (cribbed from ::Reflow)
- nscoord ascent = mRect.height;
- // getting the ascent could be a lot of work. Don't get it if
- // we are the root. The viewport doesn't care about it.
- if (!(mState & NS_STATE_IS_ROOT)) {
- ascent = GetXULBoxAscent(aState);
- }
- desiredSize.SetBlockStartAscent(ascent);
- desiredSize.mOverflowAreas = GetOverflowAreas();
- AddStateBits(NS_FRAME_IN_REFLOW);
- // Set up a |reflowStatus| to pass into ReflowAbsoluteFrames
- // (just a dummy value; hopefully that's OK)
- nsReflowStatus reflowStatus = NS_FRAME_COMPLETE;
- ReflowAbsoluteFrames(aState.PresContext(), desiredSize,
- reflowInput, reflowStatus);
- RemoveStateBits(NS_FRAME_IN_REFLOW);
- }
- return rv;
- }
- void
- nsBoxFrame::DestroyFrom(nsIFrame* aDestructRoot)
- {
- // unregister access key
- RegUnregAccessKey(false);
- // clean up the container box's layout manager and child boxes
- SetXULLayoutManager(nullptr);
- nsContainerFrame::DestroyFrom(aDestructRoot);
- }
- #ifdef DEBUG_LAYOUT
- nsresult
- nsBoxFrame::SetXULDebug(nsBoxLayoutState& aState, bool aDebug)
- {
- // see if our state matches the given debug state
- bool debugSet = mState & NS_STATE_CURRENTLY_IN_DEBUG;
- bool debugChanged = (!aDebug && debugSet) || (aDebug && !debugSet);
- // if it doesn't then tell each child below us the new debug state
- if (debugChanged)
- {
- if (aDebug) {
- mState |= NS_STATE_CURRENTLY_IN_DEBUG;
- } else {
- mState &= ~NS_STATE_CURRENTLY_IN_DEBUG;
- }
-
- SetDebugOnChildList(aState, mFirstChild, aDebug);
- MarkIntrinsicISizesDirty();
- }
- return NS_OK;
- }
- #endif
- /* virtual */ void
- nsBoxFrame::MarkIntrinsicISizesDirty()
- {
- SizeNeedsRecalc(mPrefSize);
- SizeNeedsRecalc(mMinSize);
- SizeNeedsRecalc(mMaxSize);
- CoordNeedsRecalc(mFlex);
- CoordNeedsRecalc(mAscent);
- if (mLayoutManager) {
- nsBoxLayoutState state(PresContext());
- mLayoutManager->IntrinsicISizesDirty(this, state);
- }
- // Don't call base class method, since everything it does is within an
- // IsXULBoxWrapped check.
- }
- void
- nsBoxFrame::RemoveFrame(ChildListID aListID,
- nsIFrame* aOldFrame)
- {
- NS_PRECONDITION(aListID == kPrincipalList, "We don't support out-of-flow kids");
- nsPresContext* presContext = PresContext();
- nsBoxLayoutState state(presContext);
- // remove the child frame
- mFrames.RemoveFrame(aOldFrame);
- // notify the layout manager
- if (mLayoutManager)
- mLayoutManager->ChildrenRemoved(this, state, aOldFrame);
- // destroy the child frame
- aOldFrame->Destroy();
- // mark us dirty and generate a reflow command
- PresContext()->PresShell()->
- FrameNeedsReflow(this, nsIPresShell::eTreeChange,
- NS_FRAME_HAS_DIRTY_CHILDREN);
- }
- void
- nsBoxFrame::InsertFrames(ChildListID aListID,
- nsIFrame* aPrevFrame,
- nsFrameList& aFrameList)
- {
- NS_ASSERTION(!aPrevFrame || aPrevFrame->GetParent() == this,
- "inserting after sibling frame with different parent");
- NS_ASSERTION(!aPrevFrame || mFrames.ContainsFrame(aPrevFrame),
- "inserting after sibling frame not in our child list");
- NS_PRECONDITION(aListID == kPrincipalList, "We don't support out-of-flow kids");
- nsBoxLayoutState state(PresContext());
- // insert the child frames
- const nsFrameList::Slice& newFrames =
- mFrames.InsertFrames(this, aPrevFrame, aFrameList);
- // notify the layout manager
- if (mLayoutManager)
- mLayoutManager->ChildrenInserted(this, state, aPrevFrame, newFrames);
- // Make sure to check box order _after_ notifying the layout
- // manager; otherwise the slice we give the layout manager will
- // just be bogus. If the layout manager cares about the order, we
- // just lose.
- CheckBoxOrder();
- #ifdef DEBUG_LAYOUT
- // if we are in debug make sure our children are in debug as well.
- if (mState & NS_STATE_CURRENTLY_IN_DEBUG)
- SetDebugOnChildList(state, mFrames.FirstChild(), true);
- #endif
- PresContext()->PresShell()->
- FrameNeedsReflow(this, nsIPresShell::eTreeChange,
- NS_FRAME_HAS_DIRTY_CHILDREN);
- }
- void
- nsBoxFrame::AppendFrames(ChildListID aListID,
- nsFrameList& aFrameList)
- {
- NS_PRECONDITION(aListID == kPrincipalList, "We don't support out-of-flow kids");
- nsBoxLayoutState state(PresContext());
- // append the new frames
- const nsFrameList::Slice& newFrames = mFrames.AppendFrames(this, aFrameList);
- // notify the layout manager
- if (mLayoutManager)
- mLayoutManager->ChildrenAppended(this, state, newFrames);
- // Make sure to check box order _after_ notifying the layout
- // manager; otherwise the slice we give the layout manager will
- // just be bogus. If the layout manager cares about the order, we
- // just lose.
- CheckBoxOrder();
- #ifdef DEBUG_LAYOUT
- // if we are in debug make sure our children are in debug as well.
- if (mState & NS_STATE_CURRENTLY_IN_DEBUG)
- SetDebugOnChildList(state, mFrames.FirstChild(), true);
- #endif
- // XXXbz why is this NS_FRAME_FIRST_REFLOW check here?
- if (!(GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
- PresContext()->PresShell()->
- FrameNeedsReflow(this, nsIPresShell::eTreeChange,
- NS_FRAME_HAS_DIRTY_CHILDREN);
- }
- }
- /* virtual */ nsContainerFrame*
- nsBoxFrame::GetContentInsertionFrame()
- {
- if (GetStateBits() & NS_STATE_BOX_WRAPS_KIDS_IN_BLOCK)
- return PrincipalChildList().FirstChild()->GetContentInsertionFrame();
- return nsContainerFrame::GetContentInsertionFrame();
- }
- nsresult
- nsBoxFrame::AttributeChanged(int32_t aNameSpaceID,
- nsIAtom* aAttribute,
- int32_t aModType)
- {
- nsresult rv = nsContainerFrame::AttributeChanged(aNameSpaceID, aAttribute,
- aModType);
- // Ignore 'width', 'height', 'screenX', 'screenY' and 'sizemode' on a
- // <window>.
- if (mContent->IsAnyOfXULElements(nsGkAtoms::window,
- nsGkAtoms::page,
- nsGkAtoms::dialog,
- nsGkAtoms::wizard) &&
- (nsGkAtoms::width == aAttribute ||
- nsGkAtoms::height == aAttribute ||
- nsGkAtoms::screenX == aAttribute ||
- nsGkAtoms::screenY == aAttribute ||
- nsGkAtoms::sizemode == aAttribute)) {
- return rv;
- }
- if (aAttribute == nsGkAtoms::width ||
- aAttribute == nsGkAtoms::height ||
- aAttribute == nsGkAtoms::align ||
- aAttribute == nsGkAtoms::valign ||
- aAttribute == nsGkAtoms::left ||
- aAttribute == nsGkAtoms::top ||
- aAttribute == nsGkAtoms::right ||
- aAttribute == nsGkAtoms::bottom ||
- aAttribute == nsGkAtoms::start ||
- aAttribute == nsGkAtoms::end ||
- aAttribute == nsGkAtoms::minwidth ||
- aAttribute == nsGkAtoms::maxwidth ||
- aAttribute == nsGkAtoms::minheight ||
- aAttribute == nsGkAtoms::maxheight ||
- aAttribute == nsGkAtoms::flex ||
- aAttribute == nsGkAtoms::orient ||
- aAttribute == nsGkAtoms::pack ||
- aAttribute == nsGkAtoms::dir ||
- aAttribute == nsGkAtoms::mousethrough ||
- aAttribute == nsGkAtoms::equalsize) {
- if (aAttribute == nsGkAtoms::align ||
- aAttribute == nsGkAtoms::valign ||
- aAttribute == nsGkAtoms::orient ||
- aAttribute == nsGkAtoms::pack ||
- #ifdef DEBUG_LAYOUT
- aAttribute == nsGkAtoms::debug ||
- #endif
- aAttribute == nsGkAtoms::dir) {
- mValign = nsBoxFrame::vAlign_Top;
- mHalign = nsBoxFrame::hAlign_Left;
- bool orient = true;
- GetInitialOrientation(orient);
- if (orient)
- mState |= NS_STATE_IS_HORIZONTAL;
- else
- mState &= ~NS_STATE_IS_HORIZONTAL;
- bool normal = true;
- GetInitialDirection(normal);
- if (normal)
- mState |= NS_STATE_IS_DIRECTION_NORMAL;
- else
- mState &= ~NS_STATE_IS_DIRECTION_NORMAL;
- GetInitialVAlignment(mValign);
- GetInitialHAlignment(mHalign);
- bool equalSize = false;
- GetInitialEqualSize(equalSize);
- if (equalSize)
- mState |= NS_STATE_EQUAL_SIZE;
- else
- mState &= ~NS_STATE_EQUAL_SIZE;
- #ifdef DEBUG_LAYOUT
- bool debug = mState & NS_STATE_SET_TO_DEBUG;
- bool debugSet = GetInitialDebug(debug);
- if (debugSet) {
- mState |= NS_STATE_DEBUG_WAS_SET;
- if (debug)
- mState |= NS_STATE_SET_TO_DEBUG;
- else
- mState &= ~NS_STATE_SET_TO_DEBUG;
- } else {
- mState &= ~NS_STATE_DEBUG_WAS_SET;
- }
- #endif
- bool autostretch = !!(mState & NS_STATE_AUTO_STRETCH);
- GetInitialAutoStretch(autostretch);
- if (autostretch)
- mState |= NS_STATE_AUTO_STRETCH;
- else
- mState &= ~NS_STATE_AUTO_STRETCH;
- }
- else if (aAttribute == nsGkAtoms::left ||
- aAttribute == nsGkAtoms::top ||
- aAttribute == nsGkAtoms::right ||
- aAttribute == nsGkAtoms::bottom ||
- aAttribute == nsGkAtoms::start ||
- aAttribute == nsGkAtoms::end) {
- mState &= ~NS_STATE_STACK_NOT_POSITIONED;
- }
- else if (aAttribute == nsGkAtoms::mousethrough) {
- UpdateMouseThrough();
- }
- PresContext()->PresShell()->
- FrameNeedsReflow(this, nsIPresShell::eStyleChange, NS_FRAME_IS_DIRTY);
- }
- else if (aAttribute == nsGkAtoms::ordinal) {
- nsIFrame* parent = GetParentXULBox(this);
- // If our parent is not a box, there's not much we can do... but in that
- // case our ordinal doesn't matter anyway, so that's ok.
- // Also don't bother with popup frames since they are kept on the
- // kPopupList and XULRelayoutChildAtOrdinal() only handles
- // principal children.
- if (parent && !(GetStateBits() & NS_FRAME_OUT_OF_FLOW) &&
- StyleDisplay()->mDisplay != mozilla::StyleDisplay::Popup) {
- parent->XULRelayoutChildAtOrdinal(this);
- // XXXldb Should this instead be a tree change on the child or parent?
- PresContext()->PresShell()->
- FrameNeedsReflow(parent, nsIPresShell::eStyleChange,
- NS_FRAME_IS_DIRTY);
- }
- }
- // If the accesskey changed, register for the new value
- // The old value has been unregistered in nsXULElement::SetAttr
- else if (aAttribute == nsGkAtoms::accesskey) {
- RegUnregAccessKey(true);
- }
- else if (aAttribute == nsGkAtoms::rows &&
- mContent->IsXULElement(nsGkAtoms::tree)) {
- // Reflow ourselves and all our children if "rows" changes, since
- // nsTreeBodyFrame's layout reads this from its parent (this frame).
- PresContext()->PresShell()->
- FrameNeedsReflow(this, nsIPresShell::eStyleChange, NS_FRAME_IS_DIRTY);
- }
- return rv;
- }
- #ifdef DEBUG_LAYOUT
- void
- nsBoxFrame::GetDebugPref()
- {
- gDebug = Preferences::GetBool("xul.debug.box");
- }
- class nsDisplayXULDebug : public nsDisplayItem {
- public:
- nsDisplayXULDebug(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame) :
- nsDisplayItem(aBuilder, aFrame) {
- MOZ_COUNT_CTOR(nsDisplayXULDebug);
- }
- #ifdef NS_BUILD_REFCNT_LOGGING
- virtual ~nsDisplayXULDebug() {
- MOZ_COUNT_DTOR(nsDisplayXULDebug);
- }
- #endif
- virtual void HitTest(nsDisplayListBuilder* aBuilder, nsRect aRect,
- HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames) {
- nsPoint rectCenter(aRect.x + aRect.width / 2, aRect.y + aRect.height / 2);
- static_cast<nsBoxFrame*>(mFrame)->
- DisplayDebugInfoFor(this, rectCenter - ToReferenceFrame());
- aOutFrames->AppendElement(this);
- }
- virtual void Paint(nsDisplayListBuilder* aBuilder
- nsRenderingContext* aCtx);
- NS_DISPLAY_DECL_NAME("XULDebug", TYPE_XUL_DEBUG)
- };
- void
- nsDisplayXULDebug::Paint(nsDisplayListBuilder* aBuilder,
- nsRenderingContext* aCtx)
- {
- static_cast<nsBoxFrame*>(mFrame)->
- PaintXULDebugOverlay(*aCtx->GetDrawTarget(), ToReferenceFrame());
- }
- static void
- PaintXULDebugBackground(nsIFrame* aFrame, DrawTarget* aDrawTarget,
- const nsRect& aDirtyRect, nsPoint aPt)
- {
- static_cast<nsBoxFrame*>(aFrame)->PaintXULDebugBackground(aDrawTarget, aPt);
- }
- #endif
- void
- nsBoxFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
- const nsDisplayListSet& aLists)
- {
- bool forceLayer = false;
- if (GetContent()->IsXULElement()) {
- // forcelayer is only supported on XUL elements with box layout
- if (GetContent()->HasAttr(kNameSpaceID_None, nsGkAtoms::layer)) {
- forceLayer = true;
- }
- // Check for frames that are marked as a part of the region used
- // in calculating glass margins on Windows.
- const nsStyleDisplay* styles = StyleDisplay();
- if (styles && styles->mAppearance == NS_THEME_WIN_EXCLUDE_GLASS) {
- aBuilder->AddWindowExcludeGlassRegion(
- nsRect(aBuilder->ToReferenceFrame(this), GetSize()));
- }
- }
- nsDisplayListCollection tempLists(aBuilder);
- const nsDisplayListSet& destination = forceLayer ? tempLists : aLists;
- DisplayBorderBackgroundOutline(aBuilder, destination);
- #ifdef DEBUG_LAYOUT
- if (mState & NS_STATE_CURRENTLY_IN_DEBUG) {
- destination.BorderBackground()->AppendNewToTop(new (aBuilder)
- nsDisplayGeneric(aBuilder, this, PaintXULDebugBackground,
- "XULDebugBackground"));
- destination.Outlines()->AppendNewToTop(new (aBuilder)
- nsDisplayXULDebug(aBuilder, this));
- }
- #endif
- BuildDisplayListForChildren(aBuilder, destination);
- // see if we have to draw a selection frame around this container
- DisplaySelectionOverlay(aBuilder, destination.Content());
- if (forceLayer) {
- // This is a bit of a hack. Collect up all descendant display items
- // and merge them into a single Content() list. This can cause us
- // to violate CSS stacking order, but forceLayer is a magic
- // XUL-only extension anyway.
- nsDisplayList masterList;
- masterList.AppendToTop(tempLists.BorderBackground());
- masterList.AppendToTop(tempLists.BlockBorderBackgrounds());
- masterList.AppendToTop(tempLists.Floats());
- masterList.AppendToTop(tempLists.Content());
- masterList.AppendToTop(tempLists.PositionedDescendants());
- masterList.AppendToTop(tempLists.Outlines());
- // Wrap the list to make it its own layer
- aLists.Content()->AppendNewToTop(new (aBuilder)
- nsDisplayOwnLayer(aBuilder, this, &masterList));
- }
- }
- void
- nsBoxFrame::BuildDisplayListForChildren(nsDisplayListBuilder* aBuilder,
- const nsDisplayListSet& aLists)
- {
- nsIFrame* kid = mFrames.FirstChild();
- // Put each child's background onto the BlockBorderBackgrounds list
- // to emulate the existing two-layer XUL painting scheme.
- nsDisplayListSet set(aLists, aLists.BlockBorderBackgrounds());
- // The children should be in the right order
- while (kid) {
- BuildDisplayListForChild(aBuilder, kid, set);
- kid = kid->GetNextSibling();
- }
- }
- // REVIEW: PaintChildren did a few things none of which are a big deal
- // anymore:
- // * Paint some debugging rects for this frame.
- // This is done by nsDisplayXULDebugBackground, which goes in the
- // BorderBackground() layer so it isn't clipped by OVERFLOW_CLIP.
- // * Apply OVERFLOW_CLIP to the children.
- // This is now in nsFrame::BuildDisplayListForStackingContext/Child.
- // * Actually paint the children.
- // Moved to BuildDisplayList.
- // * Paint per-kid debug information.
- // This is done by nsDisplayXULDebug, which is in the Outlines()
- // layer so it goes on top. This means it is not clipped by OVERFLOW_CLIP,
- // whereas it did used to respect OVERFLOW_CLIP, but too bad.
- #ifdef DEBUG_LAYOUT
- void
- nsBoxFrame::PaintXULDebugBackground(DrawTarget* aDrawTarget, nsPoint aPt)
- {
- nsMargin border;
- GetXULBorder(border);
- nsMargin debugBorder;
- nsMargin debugMargin;
- nsMargin debugPadding;
- bool isHorizontal = IsXULHorizontal();
- GetDebugBorder(debugBorder);
- PixelMarginToTwips(debugBorder);
- GetDebugMargin(debugMargin);
- PixelMarginToTwips(debugMargin);
- GetDebugPadding(debugPadding);
- PixelMarginToTwips(debugPadding);
- nsRect inner(mRect);
- inner.MoveTo(aPt);
- inner.Deflate(debugMargin);
- inner.Deflate(border);
- //nsRect borderRect(inner);
- int32_t appUnitsPerDevPixel = PresContext()->AppUnitsPerDevPixel();
- ColorPattern color(ToDeviceColor(isHorizontal ? Color(0.f, 0.f, 1.f, 1.f) :
- Color(1.f, 0.f, 0.f, 1.f)));
- //left
- nsRect r(inner);
- r.width = debugBorder.left;
- aDrawTarget->FillRect(NSRectToRect(r, appUnitsPerDevPixel), color);
- // top
- r = inner;
- r.height = debugBorder.top;
- aDrawTarget->FillRect(NSRectToRect(r, appUnitsPerDevPixel), color);
- //right
- r = inner;
- r.x = r.x + r.width - debugBorder.right;
- r.width = debugBorder.right;
- aDrawTarget->FillRect(NSRectToRect(r, appUnitsPerDevPixel), color);
- //bottom
- r = inner;
- r.y = r.y + r.height - debugBorder.bottom;
- r.height = debugBorder.bottom;
- aDrawTarget->FillRect(NSRectToRect(r, appUnitsPerDevPixel), color);
- // If we have dirty children or we are dirty place a green border around us.
- if (NS_SUBTREE_DIRTY(this)) {
- nsRect dirty(inner);
- ColorPattern green(ToDeviceColor(Color(0.f, 1.f, 0.f, 1.f)));
- aDrawTarget->StrokeRect(NSRectToRect(dirty, appUnitsPerDevPixel), green);
- }
- }
- void
- nsBoxFrame::PaintXULDebugOverlay(DrawTarget& aDrawTarget, nsPoint aPt)
- {
- nsMargin border;
- GetXULBorder(border);
- nsMargin debugMargin;
- GetDebugMargin(debugMargin);
- PixelMarginToTwips(debugMargin);
- nsRect inner(mRect);
- inner.MoveTo(aPt);
- inner.Deflate(debugMargin);
- inner.Deflate(border);
- nscoord onePixel = GetPresContext()->IntScaledPixelsToTwips(1);
- kid = nsBox::GetChildXULBox(this);
- while (nullptr != kid) {
- bool isHorizontal = IsXULHorizontal();
- nscoord x, y, borderSize, spacerSize;
-
- nsRect cr(kid->mRect);
- nsMargin margin;
- kid->GetXULMargin(margin);
- cr.Inflate(margin);
-
- if (isHorizontal)
- {
- cr.y = inner.y;
- x = cr.x;
- y = cr.y + onePixel;
- spacerSize = debugBorder.top - onePixel*4;
- } else {
- cr.x = inner.x;
- x = cr.y;
- y = cr.x + onePixel;
- spacerSize = debugBorder.left - onePixel*4;
- }
- nscoord flex = kid->GetXULFlex();
- if (!kid->IsXULCollapsed()) {
- if (isHorizontal)
- borderSize = cr.width;
- else
- borderSize = cr.height;
- DrawSpacer(GetPresContext(), aDrawTarget, isHorizontal, flex, x, y, borderSize, spacerSize);
- }
- kid = GetNextXULBox(kid);
- }
- }
- #endif
- #ifdef DEBUG_LAYOUT
- void
- nsBoxFrame::GetBoxName(nsAutoString& aName)
- {
- GetFrameName(aName);
- }
- #endif
- #ifdef DEBUG_FRAME_DUMP
- nsresult
- nsBoxFrame::GetFrameName(nsAString& aResult) const
- {
- return MakeFrameName(NS_LITERAL_STRING("Box"), aResult);
- }
- #endif
- nsIAtom*
- nsBoxFrame::GetType() const
- {
- return nsGkAtoms::boxFrame;
- }
- #ifdef DEBUG_LAYOUT
- nsresult
- nsBoxFrame::GetXULDebug(bool& aDebug)
- {
- aDebug = (mState & NS_STATE_CURRENTLY_IN_DEBUG);
- return NS_OK;
- }
- #endif
- // REVIEW: nsBoxFrame::GetFrameForPoint is a problem because of 'mousethrough'
- // attribute support. Here's how it works:
- // * For each child frame F, we determine the target frame T(F) by recursively
- // invoking GetFrameForPoint on the child
- // * Let F' be the last child frame such that T(F') doesn't have mousethrough.
- // If F' exists, return T(F')
- // * Otherwise let F'' be the first child frame such that T(F'') is non-null.
- // If F'' exists, return T(F'')
- // * Otherwise return this frame, if this frame contains the point
- // * Otherwise return null
- // It's not clear how this should work for more complex z-ordering situations.
- // The basic principle seems to be that if a frame F has a descendant
- // 'mousethrough' frame that includes the target position, then F
- // will not receive events (unless it overrides GetFrameForPoint).
- // A 'mousethrough' frame will only receive an event if, after applying that rule,
- // all eligible frames are 'mousethrough'; the bottom-most inner-most 'mousethrough'
- // frame is then chosen (the first eligible frame reached in a
- // traversal of the frame tree --- pre/post is irrelevant since ancestors
- // of the mousethrough frames can't be eligible).
- // IMHO this is very bogus and adds a great deal of complexity for something
- // that is very rarely used. So I'm redefining 'mousethrough' to the following:
- // a frame with mousethrough is transparent to mouse events. This is compatible
- // with the way 'mousethrough' is used in Seamonkey's navigator.xul and
- // Firefox's browser.xul. The only other place it's used is in the 'expander'
- // XBL binding, which in our tree is only used by Thunderbird SMIME Advanced
- // Preferences, and I can't figure out what that does, so I'll have to test it.
- // If it's broken I'll probably just change the binding to use it more sensibly.
- // This new behaviour is implemented in nsDisplayList::HitTest.
- // REVIEW: This debug-box stuff is annoying. I'm just going to put debug boxes
- // in the outline layer and avoid GetDebugBoxAt.
- // REVIEW: GetCursor had debug-only event dumping code. I have replaced it
- // with instrumentation in nsDisplayXULDebug.
- #ifdef DEBUG_LAYOUT
- void
- nsBoxFrame::DrawLine(DrawTarget& aDrawTarget, bool aHorizontal, nscoord x1, nscoord y1, nscoord x2, nscoord y2)
- {
- nsPoint p1(x1, y1);
- nsPoint p2(x2, y2);
- if (!aHorizontal) {
- Swap(p1.x, p1.y);
- Swap(p2.x, p2.y);
- }
- ColorPattern white(ToDeviceColor(Color(1.f, 1.f, 1.f, 1.f)));
- StrokeLineWithSnapping(p1, p2, PresContext()->AppUnitsPerDevPixel(),
- aDrawTarget, color);
- }
- void
- nsBoxFrame::FillRect(DrawTarget& aDrawTarget, bool aHorizontal, nscoord x, nscoord y, nscoord width, nscoord height)
- {
- Rect rect = NSRectToSnappedRect(aHorizontal ? nsRect(x, y, width, height) :
- nsRect(y, x, height, width),
- PresContext()->AppUnitsPerDevPixel(),
- aDrawTarget);
- ColorPattern white(ToDeviceColor(Color(1.f, 1.f, 1.f, 1.f)));
- aDrawTarget.FillRect(rect, white);
- }
- void
- nsBoxFrame::DrawSpacer(nsPresContext* aPresContext, DrawTarget& aDrawTarget,
- bool aHorizontal, int32_t flex, nscoord x, nscoord y,
- nscoord size, nscoord spacerSize)
- {
- nscoord onePixel = aPresContext->IntScaledPixelsToTwips(1);
- // if we do draw the coils
- int distance = 0;
- int center = 0;
- int offset = 0;
- int coilSize = COIL_SIZE*onePixel;
- int halfSpacer = spacerSize/2;
- distance = size;
- center = y + halfSpacer;
- offset = x;
- int coils = distance/coilSize;
- int halfCoilSize = coilSize/2;
- if (flex == 0) {
- DrawLine(aDrawTarget, aHorizontal, x,y + spacerSize/2, x + size, y + spacerSize/2);
- } else {
- for (int i=0; i < coils; i++)
- {
- DrawLine(aDrawTarget, aHorizontal, offset, center+halfSpacer, offset+halfCoilSize, center-halfSpacer);
- DrawLine(aDrawTarget, aHorizontal, offset+halfCoilSize, center-halfSpacer, offset+coilSize, center+halfSpacer);
- offset += coilSize;
- }
- }
- FillRect(aDrawTarget, aHorizontal, x + size - spacerSize/2, y, spacerSize/2, spacerSize);
- FillRect(aDrawTarget, aHorizontal, x, y, spacerSize/2, spacerSize);
- }
- void
- nsBoxFrame::GetDebugBorder(nsMargin& aInset)
- {
- aInset.SizeTo(2,2,2,2);
- if (IsXULHorizontal())
- aInset.top = 10;
- else
- aInset.left = 10;
- }
- void
- nsBoxFrame::GetDebugMargin(nsMargin& aInset)
- {
- aInset.SizeTo(2,2,2,2);
- }
- void
- nsBoxFrame::GetDebugPadding(nsMargin& aPadding)
- {
- aPadding.SizeTo(2,2,2,2);
- }
- void
- nsBoxFrame::PixelMarginToTwips(nsMargin& aMarginPixels)
- {
- nscoord onePixel = nsPresContext::CSSPixelsToAppUnits(1);
- aMarginPixels.left *= onePixel;
- aMarginPixels.right *= onePixel;
- aMarginPixels.top *= onePixel;
- aMarginPixels.bottom *= onePixel;
- }
- void
- nsBoxFrame::GetValue(nsPresContext* aPresContext, const nsSize& a, const nsSize& b, char* ch)
- {
- float p2t = aPresContext->ScaledPixelsToTwips();
- char width[100];
- char height[100];
-
- if (a.width == NS_INTRINSICSIZE)
- sprintf(width,"%s","INF");
- else
- sprintf(width,"%d", nscoord(a.width/*/p2t*/));
-
- if (a.height == NS_INTRINSICSIZE)
- sprintf(height,"%s","INF");
- else
- sprintf(height,"%d", nscoord(a.height/*/p2t*/));
-
- sprintf(ch, "(%s%s, %s%s)", width, (b.width != NS_INTRINSICSIZE ? "[SET]" : ""),
- height, (b.height != NS_INTRINSICSIZE ? "[SET]" : ""));
- }
- void
- nsBoxFrame::GetValue(nsPresContext* aPresContext, int32_t a, int32_t b, char* ch)
- {
- if (a == NS_INTRINSICSIZE)
- sprintf(ch, "%d[SET]", b);
- else
- sprintf(ch, "%d", a);
- }
- nsresult
- nsBoxFrame::DisplayDebugInfoFor(nsIFrame* aBox,
- nsPoint& aPoint)
- {
- nsBoxLayoutState state(GetPresContext());
- nscoord x = aPoint.x;
- nscoord y = aPoint.y;
- // get the area inside our border but not our debug margins.
- nsRect insideBorder(aBox->mRect);
- insideBorder.MoveTo(0,0):
- nsMargin border(0,0,0,0);
- aBox->GetXULBorderAndPadding(border);
- insideBorder.Deflate(border);
- bool isHorizontal = IsXULHorizontal();
- if (!insideBorder.Contains(nsPoint(x,y)))
- return NS_ERROR_FAILURE;
- //printf("%%%%%% inside box %%%%%%%\n");
- int count = 0;
- nsIFrame* child = nsBox::GetChildXULBox(aBox);
- nsMargin m;
- nsMargin m2;
- GetDebugBorder(m);
- PixelMarginToTwips(m);
- GetDebugMargin(m2);
- PixelMarginToTwips(m2);
- m += m2;
- if ((isHorizontal && y < insideBorder.y + m.top) ||
- (!isHorizontal && x < insideBorder.x + m.left)) {
- //printf("**** inside debug border *******\n");
- while (child)
- {
- const nsRect& r = child->mRect;
- // if we are not in the child. But in the spacer above the child.
- if ((isHorizontal && x >= r.x && x < r.x + r.width) ||
- (!isHorizontal && y >= r.y && y < r.y + r.height)) {
- aCursor = NS_STYLE_CURSOR_POINTER;
- // found it but we already showed it.
- if (mDebugChild == child)
- return NS_OK;
- if (aBox->GetContent()) {
- printf("---------------\n");
- XULDumpBox(stdout);
- printf("\n");
- }
- if (child->GetContent()) {
- printf("child #%d: ", count);
- child->XULDumpBox(stdout);
- printf("\n");
- }
- mDebugChild = child;
- nsSize prefSizeCSS(NS_INTRINSICSIZE, NS_INTRINSICSIZE);
- nsSize minSizeCSS (NS_INTRINSICSIZE, NS_INTRINSICSIZE);
- nsSize maxSizeCSS (NS_INTRINSICSIZE, NS_INTRINSICSIZE);
- nscoord flexCSS = NS_INTRINSICSIZE;
- bool widthSet, heightSet;
- nsIFrame::AddXULPrefSize(child, prefSizeCSS, widthSet, heightSet);
- nsIFrame::AddXULMinSize (state, child, minSizeCSS, widthSet, heightSet);
- nsIFrame::AddXULMaxSize (child, maxSizeCSS, widthSet, heightSet);
- nsIFrame::AddXULFlex (child, flexCSS);
- nsSize prefSize = child->GetXULPrefSize(state);
- nsSize minSize = child->GetXULMinSize(state);
- nsSize maxSize = child->GetXULMaxSize(state);
- nscoord flexSize = child->GetXULFlex();
- nscoord ascentSize = child->GetXULBoxAscent(state);
- char min[100];
- char pref[100];
- char max[100];
- char calc[100];
- char flex[100];
- char ascent[100];
-
- nsSize actualSize;
- GetFrameSizeWithMargin(child, actualSize);
- nsSize actualSizeCSS (NS_INTRINSICSIZE, NS_INTRINSICSIZE);
- GetValue(aPresContext, minSize, minSizeCSS, min);
- GetValue(aPresContext, prefSize, prefSizeCSS, pref);
- GetValue(aPresContext, maxSize, maxSizeCSS, max);
- GetValue(aPresContext, actualSize, actualSizeCSS, calc);
- GetValue(aPresContext, flexSize, flexCSS, flex);
- GetValue(aPresContext, ascentSize, NS_INTRINSICSIZE, ascent);
- printf("min%s, pref%s, max%s, actual%s, flex=%s, ascent=%s\n\n",
- min,
- pref,
- max,
- calc,
- flex,
- ascent
- );
- return NS_OK;
- }
- child = GetNextXULBox(child);
- count++;
- }
- } else {
- }
- mDebugChild = nullptr;
- return NS_OK;
- }
- void
- nsBoxFrame::SetDebugOnChildList(nsBoxLayoutState& aState, nsIFrame* aChild, bool aDebug)
- {
- nsIFrame* child = nsBox::GetChildXULBox(this);
- while (child)
- {
- child->SetXULDebug(aState, aDebug);
- child = GetNextXULBox(child);
- }
- }
- nsresult
- nsBoxFrame::GetFrameSizeWithMargin(nsIFrame* aBox, nsSize& aSize)
- {
- nsRect rect(aBox->GetRect());
- nsMargin margin(0,0,0,0);
- aBox->GetXULMargin(margin);
- rect.Inflate(margin);
- aSize.width = rect.width;
- aSize.height = rect.height;
- return NS_OK;
- }
- #endif
- // If you make changes to this function, check its counterparts
- // in nsTextBoxFrame and nsXULLabelFrame
- void
- nsBoxFrame::RegUnregAccessKey(bool aDoReg)
- {
- MOZ_ASSERT(mContent);
- // only support accesskeys for the following elements
- if (!mContent->IsAnyOfXULElements(nsGkAtoms::button,
- nsGkAtoms::toolbarbutton,
- nsGkAtoms::checkbox,
- nsGkAtoms::textbox,
- nsGkAtoms::tab,
- nsGkAtoms::radio)) {
- return;
- }
- nsAutoString accessKey;
- mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::accesskey, accessKey);
- if (accessKey.IsEmpty())
- return;
- // With a valid PresContext we can get the ESM
- // and register the access key
- EventStateManager* esm = PresContext()->EventStateManager();
- uint32_t key = accessKey.First();
- if (aDoReg)
- esm->RegisterAccessKey(mContent, key);
- else
- esm->UnregisterAccessKey(mContent, key);
- }
- bool
- nsBoxFrame::SupportsOrdinalsInChildren()
- {
- return true;
- }
- // Helper less-than-or-equal function, used in CheckBoxOrder() as a
- // template-parameter for the sorting functions.
- bool
- IsBoxOrdinalLEQ(nsIFrame* aFrame1,
- nsIFrame* aFrame2)
- {
- // If we've got a placeholder frame, use its out-of-flow frame's ordinal val.
- nsIFrame* aRealFrame1 = nsPlaceholderFrame::GetRealFrameFor(aFrame1);
- nsIFrame* aRealFrame2 = nsPlaceholderFrame::GetRealFrameFor(aFrame2);
- return aRealFrame1->GetXULOrdinal() <= aRealFrame2->GetXULOrdinal();
- }
- void
- nsBoxFrame::CheckBoxOrder()
- {
- if (SupportsOrdinalsInChildren() &&
- !nsIFrame::IsFrameListSorted<IsBoxOrdinalLEQ>(mFrames)) {
- nsIFrame::SortFrameList<IsBoxOrdinalLEQ>(mFrames);
- }
- }
- nsresult
- nsBoxFrame::LayoutChildAt(nsBoxLayoutState& aState, nsIFrame* aBox, const nsRect& aRect)
- {
- // get the current rect
- nsRect oldRect(aBox->GetRect());
- aBox->SetXULBounds(aState, aRect);
- bool layout = NS_SUBTREE_DIRTY(aBox);
-
- if (layout || (oldRect.width != aRect.width || oldRect.height != aRect.height)) {
- return aBox->XULLayout(aState);
- }
- return NS_OK;
- }
- nsresult
- nsBoxFrame::XULRelayoutChildAtOrdinal(nsIFrame* aChild)
- {
- if (!SupportsOrdinalsInChildren())
- return NS_OK;
- uint32_t ord = aChild->GetXULOrdinal();
-
- nsIFrame* child = mFrames.FirstChild();
- nsIFrame* newPrevSib = nullptr;
- while (child) {
- if (ord < child->GetXULOrdinal()) {
- break;
- }
- if (child != aChild) {
- newPrevSib = child;
- }
- child = GetNextXULBox(child);
- }
- if (aChild->GetPrevSibling() == newPrevSib) {
- // This box is not moving.
- return NS_OK;
- }
- // Take |aChild| out of its old position in the child list.
- mFrames.RemoveFrame(aChild);
- // Insert it after |newPrevSib| or at the start if it's null.
- mFrames.InsertFrame(nullptr, newPrevSib, aChild);
- return NS_OK;
- }
- /**
- * This wrapper class lets us redirect mouse hits from descendant frames
- * of a menu to the menu itself, if they didn't specify 'allowevents'.
- *
- * The wrapper simply turns a hit on a descendant element
- * into a hit on the menu itself, unless there is an element between the target
- * and the menu with the "allowevents" attribute.
- *
- * This is used by nsMenuFrame and nsTreeColFrame.
- *
- * Note that turning a hit on a descendant element into nullptr, so events
- * could fall through to the menu background, might be an appealing simplification
- * but it would mean slightly strange behaviour in some cases, because grabber
- * wrappers can be created for many individual lists and items, so the exact
- * fallthrough behaviour would be complex. E.g. an element with "allowevents"
- * on top of the Content() list could receive the event even if it was covered
- * by a PositionedDescenants() element without "allowevents". It is best to
- * never convert a non-null hit into null.
- */
- // REVIEW: This is roughly of what nsMenuFrame::GetFrameForPoint used to do.
- // I've made 'allowevents' affect child elements because that seems the only
- // reasonable thing to do.
- class nsDisplayXULEventRedirector : public nsDisplayWrapList {
- public:
- nsDisplayXULEventRedirector(nsDisplayListBuilder* aBuilder,
- nsIFrame* aFrame, nsDisplayItem* aItem,
- nsIFrame* aTargetFrame)
- : nsDisplayWrapList(aBuilder, aFrame, aItem), mTargetFrame(aTargetFrame) {}
- nsDisplayXULEventRedirector(nsDisplayListBuilder* aBuilder,
- nsIFrame* aFrame, nsDisplayList* aList,
- nsIFrame* aTargetFrame)
- : nsDisplayWrapList(aBuilder, aFrame, aList), mTargetFrame(aTargetFrame) {}
- virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
- HitTestState* aState,
- nsTArray<nsIFrame*> *aOutFrames) override;
- virtual bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) override {
- return false;
- }
- NS_DISPLAY_DECL_NAME("XULEventRedirector", TYPE_XUL_EVENT_REDIRECTOR)
- private:
- nsIFrame* mTargetFrame;
- };
- void nsDisplayXULEventRedirector::HitTest(nsDisplayListBuilder* aBuilder,
- const nsRect& aRect, HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames)
- {
- nsTArray<nsIFrame*> outFrames;
- mList.HitTest(aBuilder, aRect, aState, &outFrames);
- bool topMostAdded = false;
- uint32_t localLength = outFrames.Length();
- for (uint32_t i = 0; i < localLength; i++) {
- for (nsIContent* content = outFrames.ElementAt(i)->GetContent();
- content && content != mTargetFrame->GetContent();
- content = content->GetParent()) {
- if (content->AttrValueIs(kNameSpaceID_None, nsGkAtoms::allowevents,
- nsGkAtoms::_true, eCaseMatters)) {
- // Events are allowed on 'frame', so let it go.
- aOutFrames->AppendElement(outFrames.ElementAt(i));
- topMostAdded = true;
- }
- }
- // If there was no hit on the topmost frame or its ancestors,
- // add the target frame itself as the first candidate (see bug 562554).
- if (!topMostAdded) {
- topMostAdded = true;
- aOutFrames->AppendElement(mTargetFrame);
- }
- }
- }
- class nsXULEventRedirectorWrapper : public nsDisplayWrapper
- {
- public:
- explicit nsXULEventRedirectorWrapper(nsIFrame* aTargetFrame)
- : mTargetFrame(aTargetFrame) {}
- virtual nsDisplayItem* WrapList(nsDisplayListBuilder* aBuilder,
- nsIFrame* aFrame,
- nsDisplayList* aList) override {
- return new (aBuilder)
- nsDisplayXULEventRedirector(aBuilder, aFrame, aList, mTargetFrame);
- }
- virtual nsDisplayItem* WrapItem(nsDisplayListBuilder* aBuilder,
- nsDisplayItem* aItem) override {
- return new (aBuilder)
- nsDisplayXULEventRedirector(aBuilder, aItem->Frame(), aItem,
- mTargetFrame);
- }
- private:
- nsIFrame* mTargetFrame;
- };
- void
- nsBoxFrame::WrapListsInRedirector(nsDisplayListBuilder* aBuilder,
- const nsDisplayListSet& aIn,
- const nsDisplayListSet& aOut)
- {
- nsXULEventRedirectorWrapper wrapper(this);
- wrapper.WrapLists(aBuilder, this, aIn, aOut);
- }
- bool
- nsBoxFrame::GetEventPoint(WidgetGUIEvent* aEvent, nsPoint &aPoint) {
- LayoutDeviceIntPoint refPoint;
- bool res = GetEventPoint(aEvent, refPoint);
- aPoint = nsLayoutUtils::GetEventCoordinatesRelativeTo(
- aEvent, refPoint, this);
- return res;
- }
- bool
- nsBoxFrame::GetEventPoint(WidgetGUIEvent* aEvent, LayoutDeviceIntPoint& aPoint) {
- NS_ENSURE_TRUE(aEvent, false);
- WidgetTouchEvent* touchEvent = aEvent->AsTouchEvent();
- if (touchEvent) {
- // return false if there is more than one touch on the page, or if
- // we can't find a touch point
- if (touchEvent->mTouches.Length() != 1) {
- return false;
- }
- dom::Touch* touch = touchEvent->mTouches.SafeElementAt(0);
- if (!touch) {
- return false;
- }
- aPoint = touch->mRefPoint;
- } else {
- aPoint = aEvent->mRefPoint;
- }
- return true;
- }
|