nsFrame.cpp 392 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136813781388139814081418142814381448145814681478148814981508151815281538154815581568157815881598160816181628163816481658166816781688169817081718172817381748175817681778178817981808181818281838184818581868187818881898190819181928193819481958196819781988199820082018202820382048205820682078208820982108211821282138214821582168217821882198220822182228223822482258226822782288229823082318232823382348235823682378238823982408241824282438244824582468247824882498250825182528253825482558256825782588259826082618262826382648265826682678268826982708271827282738274827582768277827882798280828182828283828482858286828782888289829082918292829382948295829682978298829983008301830283038304830583068307830883098310831183128313831483158316831783188319832083218322832383248325832683278328832983308331833283338334833583368337833883398340834183428343834483458346834783488349835083518352835383548355835683578358835983608361836283638364836583668367836883698370837183728373837483758376837783788379838083818382838383848385838683878388838983908391839283938394839583968397839883998400840184028403840484058406840784088409841084118412841384148415841684178418841984208421842284238424842584268427842884298430843184328433843484358436843784388439844084418442844384448445844684478448844984508451845284538454845584568457845884598460846184628463846484658466846784688469847084718472847384748475847684778478847984808481848284838484848584868487848884898490849184928493849484958496849784988499850085018502850385048505850685078508850985108511851285138514851585168517851885198520852185228523852485258526852785288529853085318532853385348535853685378538853985408541854285438544854585468547854885498550855185528553855485558556855785588559856085618562856385648565856685678568856985708571857285738574857585768577857885798580858185828583858485858586858785888589859085918592859385948595859685978598859986008601860286038604860586068607860886098610861186128613861486158616861786188619862086218622862386248625862686278628862986308631863286338634863586368637863886398640864186428643864486458646864786488649865086518652865386548655865686578658865986608661866286638664866586668667866886698670867186728673867486758676867786788679868086818682868386848685868686878688868986908691869286938694869586968697869886998700870187028703870487058706870787088709871087118712871387148715871687178718871987208721872287238724872587268727872887298730873187328733873487358736873787388739874087418742874387448745874687478748874987508751875287538754875587568757875887598760876187628763876487658766876787688769877087718772877387748775877687778778877987808781878287838784878587868787878887898790879187928793879487958796879787988799880088018802880388048805880688078808880988108811881288138814881588168817881888198820882188228823882488258826882788288829883088318832883388348835883688378838883988408841884288438844884588468847884888498850885188528853885488558856885788588859886088618862886388648865886688678868886988708871887288738874887588768877887888798880888188828883888488858886888788888889889088918892889388948895889688978898889989008901890289038904890589068907890889098910891189128913891489158916891789188919892089218922892389248925892689278928892989308931893289338934893589368937893889398940894189428943894489458946894789488949895089518952895389548955895689578958895989608961896289638964896589668967896889698970897189728973897489758976897789788979898089818982898389848985898689878988898989908991899289938994899589968997899889999000900190029003900490059006900790089009901090119012901390149015901690179018901990209021902290239024902590269027902890299030903190329033903490359036903790389039904090419042904390449045904690479048904990509051905290539054905590569057905890599060906190629063906490659066906790689069907090719072907390749075907690779078907990809081908290839084908590869087908890899090909190929093909490959096909790989099910091019102910391049105910691079108910991109111911291139114911591169117911891199120912191229123912491259126912791289129913091319132913391349135913691379138913991409141914291439144914591469147914891499150915191529153915491559156915791589159916091619162916391649165916691679168916991709171917291739174917591769177917891799180918191829183918491859186918791889189919091919192919391949195919691979198919992009201920292039204920592069207920892099210921192129213921492159216921792189219922092219222922392249225922692279228922992309231923292339234923592369237923892399240924192429243924492459246924792489249925092519252925392549255925692579258925992609261926292639264926592669267926892699270927192729273927492759276927792789279928092819282928392849285928692879288928992909291929292939294929592969297929892999300930193029303930493059306930793089309931093119312931393149315931693179318931993209321932293239324932593269327932893299330933193329333933493359336933793389339934093419342934393449345934693479348934993509351935293539354935593569357935893599360936193629363936493659366936793689369937093719372937393749375937693779378937993809381938293839384938593869387938893899390939193929393939493959396939793989399940094019402940394049405940694079408940994109411941294139414941594169417941894199420942194229423942494259426942794289429943094319432943394349435943694379438943994409441944294439444944594469447944894499450945194529453945494559456945794589459946094619462946394649465946694679468946994709471947294739474947594769477947894799480948194829483948494859486948794889489949094919492949394949495949694979498949995009501950295039504950595069507950895099510951195129513951495159516951795189519952095219522952395249525952695279528952995309531953295339534953595369537953895399540954195429543954495459546954795489549955095519552955395549555955695579558955995609561956295639564956595669567956895699570957195729573957495759576957795789579958095819582958395849585958695879588958995909591959295939594959595969597959895999600960196029603960496059606960796089609961096119612961396149615961696179618961996209621962296239624962596269627962896299630963196329633963496359636963796389639964096419642964396449645964696479648964996509651965296539654965596569657965896599660966196629663966496659666966796689669967096719672967396749675967696779678967996809681968296839684968596869687968896899690969196929693969496959696969796989699970097019702970397049705970697079708970997109711971297139714971597169717971897199720972197229723972497259726972797289729973097319732973397349735973697379738973997409741974297439744974597469747974897499750975197529753975497559756975797589759976097619762976397649765976697679768976997709771977297739774977597769777977897799780978197829783978497859786978797889789979097919792979397949795979697979798979998009801980298039804980598069807980898099810981198129813981498159816981798189819982098219822982398249825982698279828982998309831983298339834983598369837983898399840984198429843984498459846984798489849985098519852985398549855985698579858985998609861986298639864986598669867986898699870987198729873987498759876987798789879988098819882988398849885988698879888988998909891989298939894989598969897989898999900990199029903990499059906990799089909991099119912991399149915991699179918991999209921992299239924992599269927992899299930993199329933993499359936993799389939994099419942994399449945994699479948994999509951995299539954995599569957995899599960996199629963996499659966996799689969997099719972997399749975997699779978997999809981998299839984998599869987998899899990999199929993999499959996999799989999100001000110002100031000410005100061000710008100091001010011100121001310014100151001610017100181001910020100211002210023100241002510026100271002810029100301003110032100331003410035100361003710038100391004010041100421004310044100451004610047100481004910050100511005210053100541005510056100571005810059100601006110062100631006410065100661006710068100691007010071100721007310074100751007610077100781007910080100811008210083100841008510086100871008810089100901009110092100931009410095100961009710098100991010010101101021010310104101051010610107101081010910110101111011210113101141011510116101171011810119101201012110122101231012410125101261012710128101291013010131101321013310134101351013610137101381013910140101411014210143101441014510146101471014810149101501015110152101531015410155101561015710158101591016010161101621016310164101651016610167101681016910170101711017210173101741017510176101771017810179101801018110182101831018410185101861018710188101891019010191101921019310194101951019610197101981019910200102011020210203102041020510206102071020810209102101021110212102131021410215102161021710218102191022010221102221022310224102251022610227102281022910230102311023210233102341023510236102371023810239102401024110242102431024410245102461024710248102491025010251102521025310254102551025610257102581025910260102611026210263102641026510266102671026810269102701027110272102731027410275102761027710278102791028010281102821028310284102851028610287102881028910290102911029210293102941029510296102971029810299103001030110302103031030410305103061030710308103091031010311103121031310314103151031610317103181031910320103211032210323103241032510326103271032810329103301033110332103331033410335103361033710338103391034010341103421034310344103451034610347103481034910350103511035210353103541035510356103571035810359103601036110362103631036410365103661036710368103691037010371103721037310374103751037610377103781037910380103811038210383103841038510386103871038810389103901039110392103931039410395103961039710398103991040010401104021040310404104051040610407104081040910410104111041210413104141041510416104171041810419104201042110422104231042410425104261042710428104291043010431104321043310434104351043610437104381043910440104411044210443104441044510446104471044810449104501045110452104531045410455104561045710458104591046010461104621046310464104651046610467104681046910470104711047210473104741047510476104771047810479104801048110482104831048410485104861048710488104891049010491104921049310494104951049610497104981049910500105011050210503105041050510506105071050810509105101051110512105131051410515105161051710518105191052010521105221052310524105251052610527105281052910530105311053210533105341053510536105371053810539105401054110542105431054410545105461054710548105491055010551105521055310554105551055610557105581055910560105611056210563105641056510566105671056810569105701057110572105731057410575105761057710578105791058010581105821058310584105851058610587105881058910590105911059210593105941059510596105971059810599106001060110602106031060410605106061060710608106091061010611106121061310614106151061610617106181061910620106211062210623106241062510626106271062810629106301063110632106331063410635106361063710638106391064010641106421064310644106451064610647106481064910650106511065210653106541065510656106571065810659106601066110662106631066410665106661066710668106691067010671106721067310674106751067610677106781067910680106811068210683106841068510686106871068810689106901069110692106931069410695106961069710698106991070010701107021070310704107051070610707107081070910710107111071210713107141071510716107171071810719107201072110722107231072410725107261072710728107291073010731107321073310734107351073610737107381073910740107411074210743107441074510746107471074810749107501075110752107531075410755107561075710758107591076010761107621076310764107651076610767107681076910770107711077210773107741077510776107771077810779107801078110782107831078410785107861078710788107891079010791107921079310794107951079610797107981079910800108011080210803108041080510806108071080810809108101081110812108131081410815108161081710818108191082010821108221082310824108251082610827108281082910830108311083210833108341083510836108371083810839108401084110842108431084410845108461084710848108491085010851108521085310854108551085610857108581085910860108611086210863108641086510866108671086810869108701087110872108731087410875108761087710878108791088010881108821088310884108851088610887108881088910890108911089210893108941089510896108971089810899109001090110902109031090410905109061090710908109091091010911109121091310914109151091610917109181091910920109211092210923109241092510926109271092810929109301093110932109331093410935109361093710938109391094010941109421094310944109451094610947109481094910950109511095210953109541095510956109571095810959109601096110962109631096410965109661096710968109691097010971109721097310974109751097610977109781097910980109811098210983109841098510986109871098810989109901099110992109931099410995109961099710998109991100011001110021100311004110051100611007110081100911010110111101211013110141101511016110171101811019110201102111022110231102411025110261102711028110291103011031110321103311034110351103611037110381103911040110411104211043110441104511046110471104811049110501105111052110531105411055110561105711058110591106011061110621106311064110651106611067110681106911070110711107211073110741107511076110771107811079110801108111082110831108411085110861108711088110891109011091110921109311094110951109611097110981109911100111011110211103111041110511106111071110811109111101111111112111131111411115111161111711118111191112011121111221112311124111251112611127111281112911130111311113211133111341113511136111371113811139111401114111142111431114411145111461114711148111491115011151111521115311154111551115611157111581115911160111611116211163111641116511166111671116811169111701117111172111731117411175111761117711178111791118011181111821118311184111851118611187111881118911190111911119211193111941119511196111971119811199112001120111202112031120411205112061120711208112091121011211112121121311214112151121611217112181121911220112211122211223112241122511226112271122811229112301123111232112331123411235112361123711238112391124011241112421124311244112451124611247112481124911250112511125211253112541125511256112571125811259112601126111262112631126411265112661126711268112691127011271112721127311274112751127611277112781127911280112811128211283112841128511286112871128811289112901129111292112931129411295112961129711298112991130011301113021130311304113051130611307113081130911310113111131211313113141131511316113171131811319113201132111322113231132411325113261132711328113291133011331113321133311334113351133611337113381133911340113411134211343113441134511346113471134811349113501135111352113531135411355113561135711358113591136011361113621136311364113651136611367113681136911370113711137211373113741137511376113771137811379113801138111382113831138411385113861138711388113891139011391113921139311394113951139611397113981139911400114011140211403114041140511406114071140811409114101141111412114131141411415114161141711418
  1. /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. /* base class of all rendering objects */
  6. #include "nsFrame.h"
  7. #include <stdarg.h>
  8. #include <algorithm>
  9. #include "gfx2DGlue.h"
  10. #include "gfxUtils.h"
  11. #include "mozilla/Attributes.h"
  12. #include "mozilla/DebugOnly.h"
  13. #include "mozilla/gfx/2D.h"
  14. #include "mozilla/gfx/PathHelpers.h"
  15. #include "mozilla/Sprintf.h"
  16. #include "nsCOMPtr.h"
  17. #include "nsFrameList.h"
  18. #include "nsPlaceholderFrame.h"
  19. #include "nsIContent.h"
  20. #include "nsIContentInlines.h"
  21. #include "nsContentUtils.h"
  22. #include "nsCSSPseudoElements.h"
  23. #include "nsIAtom.h"
  24. #include "nsString.h"
  25. #include "nsReadableUtils.h"
  26. #include "nsStyleContext.h"
  27. #include "nsTableWrapperFrame.h"
  28. #include "nsView.h"
  29. #include "nsViewManager.h"
  30. #include "nsIScrollableFrame.h"
  31. #include "nsPresContext.h"
  32. #include "nsStyleConsts.h"
  33. #include "nsIPresShell.h"
  34. #include "mozilla/Logging.h"
  35. #include "mozilla/Sprintf.h"
  36. #include "nsFrameManager.h"
  37. #include "nsLayoutUtils.h"
  38. #include "LayoutLogging.h"
  39. #include "mozilla/RestyleManager.h"
  40. #include "mozilla/RestyleManagerHandle.h"
  41. #include "mozilla/RestyleManagerHandleInlines.h"
  42. #include "nsIDOMNode.h"
  43. #include "nsISelection.h"
  44. #include "nsISelectionPrivate.h"
  45. #include "nsFrameSelection.h"
  46. #include "nsGkAtoms.h"
  47. #include "nsHtml5Atoms.h"
  48. #include "nsCSSAnonBoxes.h"
  49. #include "nsGenericHTMLElement.h"
  50. #include "nsFrameTraversal.h"
  51. #include "nsRange.h"
  52. #include "nsITextControlFrame.h"
  53. #include "nsNameSpaceManager.h"
  54. #include "nsIPercentBSizeObserver.h"
  55. #include "nsStyleStructInlines.h"
  56. #include "FrameLayerBuilder.h"
  57. #include "ImageLayers.h"
  58. #include "nsBidiPresUtils.h"
  59. #include "RubyUtils.h"
  60. #include "nsAnimationManager.h"
  61. // For triple-click pref
  62. #include "imgIContainer.h"
  63. #include "imgIRequest.h"
  64. #include "nsError.h"
  65. #include "nsContainerFrame.h"
  66. #include "nsBoxLayoutState.h"
  67. #include "nsBlockFrame.h"
  68. #include "nsDisplayList.h"
  69. #include "nsSVGIntegrationUtils.h"
  70. #include "nsSVGEffects.h"
  71. #include "nsChangeHint.h"
  72. #include "nsDeckFrame.h"
  73. #include "nsSubDocumentFrame.h"
  74. #include "SVGTextFrame.h"
  75. #include "gfxContext.h"
  76. #include "nsRenderingContext.h"
  77. #include "nsAbsoluteContainingBlock.h"
  78. #include "DisplayItemScrollClip.h"
  79. #include "StickyScrollContainer.h"
  80. #include "nsFontInflationData.h"
  81. #include "nsRegion.h"
  82. #include "nsIFrameInlines.h"
  83. #include "mozilla/AsyncEventDispatcher.h"
  84. #include "mozilla/EffectCompositor.h"
  85. #include "mozilla/EffectSet.h"
  86. #include "mozilla/EventListenerManager.h"
  87. #include "mozilla/EventStateManager.h"
  88. #include "mozilla/EventStates.h"
  89. #include "mozilla/Preferences.h"
  90. #include "mozilla/LookAndFeel.h"
  91. #include "mozilla/MouseEvents.h"
  92. #include "mozilla/css/ImageLoader.h"
  93. #include "mozilla/gfx/Tools.h"
  94. #include "nsPrintfCString.h"
  95. #include "ActiveLayerTracker.h"
  96. #include "nsITheme.h"
  97. #include "nsThemeConstants.h"
  98. using namespace mozilla;
  99. using namespace mozilla::css;
  100. using namespace mozilla::dom;
  101. using namespace mozilla::gfx;
  102. using namespace mozilla::layers;
  103. using namespace mozilla::layout;
  104. typedef nsAbsoluteContainingBlock::AbsPosReflowFlags AbsPosReflowFlags;
  105. // Struct containing cached metrics for box-wrapped frames.
  106. struct nsBoxLayoutMetrics
  107. {
  108. nsSize mPrefSize;
  109. nsSize mMinSize;
  110. nsSize mMaxSize;
  111. nsSize mBlockMinSize;
  112. nsSize mBlockPrefSize;
  113. nscoord mBlockAscent;
  114. nscoord mFlex;
  115. nscoord mAscent;
  116. nsSize mLastSize;
  117. };
  118. struct nsContentAndOffset
  119. {
  120. nsIContent* mContent;
  121. int32_t mOffset;
  122. };
  123. // Some Misc #defines
  124. #define SELECTION_DEBUG 0
  125. #define FORCE_SELECTION_UPDATE 1
  126. #define CALC_DEBUG 0
  127. // This is faster than nsBidiPresUtils::IsFrameInParagraphDirection,
  128. // because it uses the frame pointer passed in without drilling down to
  129. // the leaf frame.
  130. static bool
  131. IsReversedDirectionFrame(nsIFrame* aFrame)
  132. {
  133. FrameBidiData bidiData = aFrame->GetBidiData();
  134. return !IS_SAME_DIRECTION(bidiData.embeddingLevel, bidiData.baseLevel);
  135. }
  136. #include "nsILineIterator.h"
  137. //non Hack prototypes
  138. #if 0
  139. static void RefreshContentFrames(nsPresContext* aPresContext, nsIContent * aStartContent, nsIContent * aEndContent);
  140. #endif
  141. #include "prenv.h"
  142. NS_DECLARE_FRAME_PROPERTY_DELETABLE(BoxMetricsProperty, nsBoxLayoutMetrics)
  143. static void
  144. InitBoxMetrics(nsIFrame* aFrame, bool aClear)
  145. {
  146. if (aClear) {
  147. aFrame->DeleteProperty(BoxMetricsProperty());
  148. }
  149. nsBoxLayoutMetrics* metrics = new nsBoxLayoutMetrics();
  150. aFrame->SetProperty(BoxMetricsProperty(), metrics);
  151. static_cast<nsFrame*>(aFrame)->nsFrame::MarkIntrinsicISizesDirty();
  152. metrics->mBlockAscent = 0;
  153. metrics->mLastSize.SizeTo(0, 0);
  154. }
  155. static bool
  156. IsXULBoxWrapped(const nsIFrame* aFrame)
  157. {
  158. return aFrame->GetParent() &&
  159. aFrame->GetParent()->IsXULBoxFrame() &&
  160. !aFrame->IsXULBoxFrame();
  161. }
  162. // Formerly the nsIFrameDebug interface
  163. #ifdef DEBUG
  164. static bool gShowFrameBorders = false;
  165. void nsFrame::ShowFrameBorders(bool aEnable)
  166. {
  167. gShowFrameBorders = aEnable;
  168. }
  169. bool nsFrame::GetShowFrameBorders()
  170. {
  171. return gShowFrameBorders;
  172. }
  173. static bool gShowEventTargetFrameBorder = false;
  174. void nsFrame::ShowEventTargetFrameBorder(bool aEnable)
  175. {
  176. gShowEventTargetFrameBorder = aEnable;
  177. }
  178. bool nsFrame::GetShowEventTargetFrameBorder()
  179. {
  180. return gShowEventTargetFrameBorder;
  181. }
  182. /**
  183. * Note: the log module is created during library initialization which
  184. * means that you cannot perform logging before then.
  185. */
  186. mozilla::LazyLogModule nsFrame::sFrameLogModule("frame");
  187. static mozilla::LazyLogModule sStyleVerifyTreeLogModuleInfo("styleverifytree");
  188. static uint32_t gStyleVerifyTreeEnable = 0x55;
  189. bool
  190. nsFrame::GetVerifyStyleTreeEnable()
  191. {
  192. if (gStyleVerifyTreeEnable == 0x55) {
  193. gStyleVerifyTreeEnable = 0 != (int)((mozilla::LogModule*)sStyleVerifyTreeLogModuleInfo)->Level();
  194. }
  195. return gStyleVerifyTreeEnable;
  196. }
  197. void
  198. nsFrame::SetVerifyStyleTreeEnable(bool aEnabled)
  199. {
  200. gStyleVerifyTreeEnable = aEnabled;
  201. }
  202. #endif
  203. NS_DECLARE_FRAME_PROPERTY_DELETABLE(AbsoluteContainingBlockProperty,
  204. nsAbsoluteContainingBlock)
  205. bool
  206. nsIFrame::HasAbsolutelyPositionedChildren() const {
  207. return IsAbsoluteContainer() && GetAbsoluteContainingBlock()->HasAbsoluteFrames();
  208. }
  209. nsAbsoluteContainingBlock*
  210. nsIFrame::GetAbsoluteContainingBlock() const {
  211. NS_ASSERTION(IsAbsoluteContainer(), "The frame is not marked as an abspos container correctly");
  212. nsAbsoluteContainingBlock* absCB = GetProperty(AbsoluteContainingBlockProperty());
  213. NS_ASSERTION(absCB, "The frame is marked as an abspos container but doesn't have the property");
  214. return absCB;
  215. }
  216. void
  217. nsIFrame::MarkAsAbsoluteContainingBlock()
  218. {
  219. MOZ_ASSERT(GetStateBits() & NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
  220. NS_ASSERTION(!GetProperty(AbsoluteContainingBlockProperty()),
  221. "Already has an abs-pos containing block property?");
  222. NS_ASSERTION(!HasAnyStateBits(NS_FRAME_HAS_ABSPOS_CHILDREN),
  223. "Already has NS_FRAME_HAS_ABSPOS_CHILDREN state bit?");
  224. AddStateBits(NS_FRAME_HAS_ABSPOS_CHILDREN);
  225. SetProperty(AbsoluteContainingBlockProperty(), new nsAbsoluteContainingBlock(GetAbsoluteListID()));
  226. }
  227. void
  228. nsIFrame::MarkAsNotAbsoluteContainingBlock()
  229. {
  230. NS_ASSERTION(!HasAbsolutelyPositionedChildren(), "Think of the children!");
  231. NS_ASSERTION(GetProperty(AbsoluteContainingBlockProperty()),
  232. "Should have an abs-pos containing block property");
  233. NS_ASSERTION(HasAnyStateBits(NS_FRAME_HAS_ABSPOS_CHILDREN),
  234. "Should have NS_FRAME_HAS_ABSPOS_CHILDREN state bit");
  235. MOZ_ASSERT(HasAnyStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN));
  236. RemoveStateBits(NS_FRAME_HAS_ABSPOS_CHILDREN);
  237. DeleteProperty(AbsoluteContainingBlockProperty());
  238. }
  239. bool
  240. nsIFrame::CheckAndClearPaintedState()
  241. {
  242. bool result = (GetStateBits() & NS_FRAME_PAINTED_THEBES);
  243. RemoveStateBits(NS_FRAME_PAINTED_THEBES);
  244. nsIFrame::ChildListIterator lists(this);
  245. for (; !lists.IsDone(); lists.Next()) {
  246. nsFrameList::Enumerator childFrames(lists.CurrentList());
  247. for (; !childFrames.AtEnd(); childFrames.Next()) {
  248. nsIFrame* child = childFrames.get();
  249. if (child->CheckAndClearPaintedState()) {
  250. result = true;
  251. }
  252. }
  253. }
  254. return result;
  255. }
  256. bool
  257. nsIFrame::IsVisibleConsideringAncestors(uint32_t aFlags) const
  258. {
  259. if (!StyleVisibility()->IsVisible()) {
  260. return false;
  261. }
  262. const nsIFrame* frame = this;
  263. while (frame) {
  264. nsView* view = frame->GetView();
  265. if (view && view->GetVisibility() == nsViewVisibility_kHide)
  266. return false;
  267. nsIFrame* parent = frame->GetParent();
  268. nsDeckFrame* deck = do_QueryFrame(parent);
  269. if (deck) {
  270. if (deck->GetSelectedBox() != frame)
  271. return false;
  272. }
  273. if (parent) {
  274. frame = parent;
  275. } else {
  276. parent = nsLayoutUtils::GetCrossDocParentFrame(frame);
  277. if (!parent)
  278. break;
  279. if ((aFlags & nsIFrame::VISIBILITY_CROSS_CHROME_CONTENT_BOUNDARY) == 0 &&
  280. parent->PresContext()->IsChrome() && !frame->PresContext()->IsChrome()) {
  281. break;
  282. }
  283. if (!parent->StyleVisibility()->IsVisible())
  284. return false;
  285. frame = parent;
  286. }
  287. }
  288. return true;
  289. }
  290. void
  291. nsIFrame::FindCloserFrameForSelection(
  292. nsPoint aPoint,
  293. nsIFrame::FrameWithDistance* aCurrentBestFrame)
  294. {
  295. if (nsLayoutUtils::PointIsCloserToRect(aPoint, mRect,
  296. aCurrentBestFrame->mXDistance,
  297. aCurrentBestFrame->mYDistance)) {
  298. aCurrentBestFrame->mFrame = this;
  299. }
  300. }
  301. void
  302. nsIFrame::ContentStatesChanged(mozilla::EventStates aStates)
  303. {
  304. }
  305. void
  306. NS_MergeReflowStatusInto(nsReflowStatus* aPrimary, nsReflowStatus aSecondary)
  307. {
  308. *aPrimary |= aSecondary &
  309. (NS_FRAME_NOT_COMPLETE | NS_FRAME_OVERFLOW_INCOMPLETE |
  310. NS_FRAME_TRUNCATED | NS_FRAME_REFLOW_NEXTINFLOW);
  311. if (*aPrimary & NS_FRAME_NOT_COMPLETE) {
  312. *aPrimary &= ~NS_FRAME_OVERFLOW_INCOMPLETE;
  313. }
  314. }
  315. void
  316. nsWeakFrame::Init(nsIFrame* aFrame)
  317. {
  318. Clear(mFrame ? mFrame->PresContext()->GetPresShell() : nullptr);
  319. mFrame = aFrame;
  320. if (mFrame) {
  321. nsIPresShell* shell = mFrame->PresContext()->GetPresShell();
  322. NS_WARNING_ASSERTION(shell, "Null PresShell in nsWeakFrame!");
  323. if (shell) {
  324. shell->AddWeakFrame(this);
  325. } else {
  326. mFrame = nullptr;
  327. }
  328. }
  329. }
  330. nsIFrame*
  331. NS_NewEmptyFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
  332. {
  333. return new (aPresShell) nsFrame(aContext);
  334. }
  335. nsFrame::nsFrame(nsStyleContext* aContext)
  336. {
  337. MOZ_COUNT_CTOR(nsFrame);
  338. mState = NS_FRAME_FIRST_REFLOW | NS_FRAME_IS_DIRTY;
  339. mStyleContext = aContext;
  340. mStyleContext->AddRef();
  341. #ifdef DEBUG
  342. mStyleContext->FrameAddRef();
  343. #endif
  344. }
  345. nsFrame::~nsFrame()
  346. {
  347. MOZ_COUNT_DTOR(nsFrame);
  348. MOZ_ASSERT(GetVisibility() != Visibility::APPROXIMATELY_VISIBLE,
  349. "Visible nsFrame is being destroyed");
  350. NS_IF_RELEASE(mContent);
  351. #ifdef DEBUG
  352. mStyleContext->FrameRelease();
  353. #endif
  354. mStyleContext->Release();
  355. }
  356. NS_IMPL_FRAMEARENA_HELPERS(nsFrame)
  357. // Dummy operator delete. Will never be called, but must be defined
  358. // to satisfy some C++ ABIs.
  359. void
  360. nsFrame::operator delete(void *, size_t)
  361. {
  362. NS_RUNTIMEABORT("nsFrame::operator delete should never be called");
  363. }
  364. NS_QUERYFRAME_HEAD(nsFrame)
  365. NS_QUERYFRAME_ENTRY(nsIFrame)
  366. NS_QUERYFRAME_TAIL_INHERITANCE_ROOT
  367. /////////////////////////////////////////////////////////////////////////////
  368. // nsIFrame
  369. static bool
  370. IsFontSizeInflationContainer(nsIFrame* aFrame,
  371. const nsStyleDisplay* aStyleDisplay)
  372. {
  373. /*
  374. * Font size inflation is built around the idea that we're inflating
  375. * the fonts for a pan-and-zoom UI so that when the user scales up a
  376. * block or other container to fill the width of the device, the fonts
  377. * will be readable. To do this, we need to pick what counts as a
  378. * container.
  379. *
  380. * From a code perspective, the only hard requirement is that frames
  381. * that are line participants
  382. * (nsIFrame::IsFrameOfType(nsIFrame::eLineParticipant)) are never
  383. * containers, since line layout assumes that the inflation is
  384. * consistent within a line.
  385. *
  386. * This is not an imposition, since we obviously want a bunch of text
  387. * (possibly with inline elements) flowing within a block to count the
  388. * block (or higher) as its container.
  389. *
  390. * We also want form controls, including the text in the anonymous
  391. * content inside of them, to match each other and the text next to
  392. * them, so they and their anonymous content should also not be a
  393. * container.
  394. *
  395. * However, because we can't reliably compute sizes across XUL during
  396. * reflow, any XUL frame with a XUL parent is always a container.
  397. *
  398. * There are contexts where it would be nice if some blocks didn't
  399. * count as a container, so that, for example, an indented quotation
  400. * didn't end up with a smaller font size. However, it's hard to
  401. * distinguish these situations where we really do want the indented
  402. * thing to count as a container, so we don't try, and blocks are
  403. * always containers.
  404. */
  405. // The root frame should always be an inflation container.
  406. if (!aFrame->GetParent()) {
  407. return true;
  408. }
  409. nsIContent *content = aFrame->GetContent();
  410. nsIAtom* frameType = aFrame->GetType();
  411. bool isInline = (aFrame->GetDisplay() == StyleDisplay::Inline ||
  412. RubyUtils::IsRubyBox(frameType) ||
  413. (aFrame->IsFloating() &&
  414. frameType == nsGkAtoms::letterFrame) ||
  415. // Given multiple frames for the same node, only the
  416. // outer one should be considered a container.
  417. // (Important, e.g., for nsSelectsAreaFrame.)
  418. (aFrame->GetParent()->GetContent() == content) ||
  419. (content && (content->IsAnyOfHTMLElements(nsGkAtoms::option,
  420. nsGkAtoms::optgroup,
  421. nsGkAtoms::select) ||
  422. content->IsInNativeAnonymousSubtree()))) &&
  423. !(aFrame->IsXULBoxFrame() && aFrame->GetParent()->IsXULBoxFrame());
  424. NS_ASSERTION(!aFrame->IsFrameOfType(nsIFrame::eLineParticipant) ||
  425. isInline ||
  426. // br frames and mathml frames report being line
  427. // participants even when their position or display is
  428. // set
  429. aFrame->GetType() == nsGkAtoms::brFrame ||
  430. aFrame->IsFrameOfType(nsIFrame::eMathML),
  431. "line participants must not be containers");
  432. NS_ASSERTION(aFrame->GetType() != nsGkAtoms::bulletFrame || isInline,
  433. "bullets should not be containers");
  434. return !isInline;
  435. }
  436. void
  437. nsFrame::Init(nsIContent* aContent,
  438. nsContainerFrame* aParent,
  439. nsIFrame* aPrevInFlow)
  440. {
  441. NS_PRECONDITION(!mContent, "Double-initing a frame?");
  442. NS_ASSERTION(IsFrameOfType(eDEBUGAllFrames) &&
  443. !IsFrameOfType(eDEBUGNoFrames),
  444. "IsFrameOfType implementation that doesn't call base class");
  445. mContent = aContent;
  446. mParent = aParent;
  447. if (aContent) {
  448. NS_ADDREF(aContent);
  449. }
  450. if (aPrevInFlow) {
  451. // Make sure the general flags bits are the same
  452. nsFrameState state = aPrevInFlow->GetStateBits();
  453. // Make bits that are currently off (see constructor) the same:
  454. mState |= state & (NS_FRAME_INDEPENDENT_SELECTION |
  455. NS_FRAME_PART_OF_IBSPLIT |
  456. NS_FRAME_MAY_BE_TRANSFORMED |
  457. NS_FRAME_MAY_HAVE_GENERATED_CONTENT |
  458. NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
  459. } else {
  460. PresContext()->ConstructedFrame();
  461. }
  462. if (GetParent()) {
  463. nsFrameState state = GetParent()->GetStateBits();
  464. // Make bits that are currently off (see constructor) the same:
  465. mState |= state & (NS_FRAME_INDEPENDENT_SELECTION |
  466. NS_FRAME_GENERATED_CONTENT |
  467. NS_FRAME_IS_SVG_TEXT |
  468. NS_FRAME_IN_POPUP |
  469. NS_FRAME_IS_NONDISPLAY);
  470. if (HasAnyStateBits(NS_FRAME_IN_POPUP) && TrackingVisibility()) {
  471. // Assume all frames in popups are visible.
  472. IncApproximateVisibleCount();
  473. }
  474. }
  475. const nsStyleDisplay *disp = StyleDisplay();
  476. if (disp->HasTransform(this) ||
  477. (IsFrameOfType(eSupportsCSSTransforms) &&
  478. nsLayoutUtils::HasAnimationOfProperty(this, eCSSProperty_transform))) {
  479. // The frame gets reconstructed if we toggle the -moz-transform
  480. // property, so we can set this bit here and then ignore it.
  481. mState |= NS_FRAME_MAY_BE_TRANSFORMED;
  482. }
  483. if (disp->mPosition == NS_STYLE_POSITION_STICKY &&
  484. !aPrevInFlow &&
  485. !(mState & NS_FRAME_IS_NONDISPLAY)) {
  486. // Note that we only add first continuations, but we really only
  487. // want to add first continuation-or-ib-split-siblings. But since we
  488. // don't yet know if we're a later part of a block-in-inline split,
  489. // we'll just add later members of a block-in-inline split here, and
  490. // then StickyScrollContainer will remove them later.
  491. StickyScrollContainer* ssc =
  492. StickyScrollContainer::GetStickyScrollContainerForFrame(this);
  493. if (ssc) {
  494. ssc->AddFrame(this);
  495. }
  496. }
  497. if (nsLayoutUtils::FontSizeInflationEnabled(PresContext()) || !GetParent()
  498. #ifdef DEBUG
  499. // We have assertions that check inflation invariants even when
  500. // font size inflation is not enabled.
  501. || true
  502. #endif
  503. ) {
  504. if (IsFontSizeInflationContainer(this, disp)) {
  505. AddStateBits(NS_FRAME_FONT_INFLATION_CONTAINER);
  506. if (!GetParent() ||
  507. // I'd use NS_FRAME_OUT_OF_FLOW, but it's not set yet.
  508. disp->IsFloating(this) || disp->IsAbsolutelyPositioned(this)) {
  509. AddStateBits(NS_FRAME_FONT_INFLATION_FLOW_ROOT);
  510. }
  511. }
  512. NS_ASSERTION(GetParent() ||
  513. (GetStateBits() & NS_FRAME_FONT_INFLATION_CONTAINER),
  514. "root frame should always be a container");
  515. }
  516. if (PresContext()->PresShell()->AssumeAllFramesVisible() &&
  517. TrackingVisibility()) {
  518. IncApproximateVisibleCount();
  519. }
  520. DidSetStyleContext(nullptr);
  521. if (::IsXULBoxWrapped(this))
  522. ::InitBoxMetrics(this, false);
  523. }
  524. void
  525. nsFrame::DestroyFrom(nsIFrame* aDestructRoot)
  526. {
  527. NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
  528. "destroy called on frame while scripts not blocked");
  529. NS_ASSERTION(!GetNextSibling() && !GetPrevSibling(),
  530. "Frames should be removed before destruction.");
  531. NS_ASSERTION(aDestructRoot, "Must specify destruct root");
  532. MOZ_ASSERT(!HasAbsolutelyPositionedChildren());
  533. nsSVGEffects::InvalidateDirectRenderingObservers(this);
  534. if (StyleDisplay()->mPosition == NS_STYLE_POSITION_STICKY) {
  535. StickyScrollContainer* ssc =
  536. StickyScrollContainer::GetStickyScrollContainerForFrame(this);
  537. if (ssc) {
  538. ssc->RemoveFrame(this);
  539. }
  540. }
  541. // Get the view pointer now before the frame properties disappear
  542. // when we call NotifyDestroyingFrame()
  543. nsView* view = GetView();
  544. nsPresContext* presContext = PresContext();
  545. nsIPresShell *shell = presContext->GetPresShell();
  546. if (mState & NS_FRAME_OUT_OF_FLOW) {
  547. nsPlaceholderFrame* placeholder = GetPlaceholderFrame();
  548. NS_ASSERTION(!placeholder || (aDestructRoot != this),
  549. "Don't call Destroy() on OOFs, call Destroy() on the placeholder.");
  550. NS_ASSERTION(!placeholder ||
  551. nsLayoutUtils::IsProperAncestorFrame(aDestructRoot, placeholder),
  552. "Placeholder relationship should have been torn down already; "
  553. "this might mean we have a stray placeholder in the tree.");
  554. if (placeholder) {
  555. placeholder->SetOutOfFlowFrame(nullptr);
  556. }
  557. }
  558. // If we have any IB split siblings, clear their references to us.
  559. // (Note: This has to happen before we clear our Properties() table.)
  560. if (mState & NS_FRAME_PART_OF_IBSPLIT) {
  561. // Delete previous sibling's reference to me.
  562. nsIFrame* prevSib = GetProperty(nsIFrame::IBSplitPrevSibling());
  563. if (prevSib) {
  564. NS_WARNING_ASSERTION(
  565. this == prevSib->GetProperty(nsIFrame::IBSplitSibling()),
  566. "IB sibling chain is inconsistent");
  567. prevSib->DeleteProperty(nsIFrame::IBSplitSibling());
  568. }
  569. // Delete next sibling's reference to me.
  570. nsIFrame* nextSib = GetProperty(nsIFrame::IBSplitSibling());
  571. if (nextSib) {
  572. NS_WARNING_ASSERTION(
  573. this == nextSib->GetProperty(nsIFrame::IBSplitPrevSibling()),
  574. "IB sibling chain is inconsistent");
  575. nextSib->DeleteProperty(nsIFrame::IBSplitPrevSibling());
  576. }
  577. }
  578. bool isPrimaryFrame = (mContent && mContent->GetPrimaryFrame() == this);
  579. if (isPrimaryFrame) {
  580. // This needs to happen before we clear our Properties() table.
  581. ActiveLayerTracker::TransferActivityToContent(this, mContent);
  582. // Unfortunately, we need to do this for all frames being reframed
  583. // and not only those whose current style involves CSS transitions,
  584. // because what matters is whether the new style (not the old)
  585. // specifies CSS transitions.
  586. if (presContext->RestyleManager()->IsGecko()) {
  587. // stylo: ServoRestyleManager does not handle transitions yet, and when
  588. // it does it probably won't need to track reframed style contexts to
  589. // initiate transitions correctly.
  590. RestyleManager::ReframingStyleContexts* rsc =
  591. presContext->RestyleManager()->AsGecko()->GetReframingStyleContexts();
  592. if (rsc) {
  593. rsc->Put(mContent, mStyleContext);
  594. }
  595. }
  596. }
  597. if (HasCSSAnimations() || HasCSSTransitions() ||
  598. EffectSet::GetEffectSet(this)) {
  599. // If no new frame for this element is created by the end of the
  600. // restyling process, stop animations and transitions for this frame
  601. if (presContext->RestyleManager()->IsGecko()) {
  602. RestyleManager::AnimationsWithDestroyedFrame* adf =
  603. presContext->RestyleManager()->AsGecko()->GetAnimationsWithDestroyedFrame();
  604. // AnimationsWithDestroyedFrame only lives during the restyling process.
  605. if (adf) {
  606. adf->Put(mContent, mStyleContext);
  607. }
  608. } else {
  609. NS_ERROR("stylo: ServoRestyleManager does not support animations yet");
  610. }
  611. }
  612. // Disable visibility tracking. Note that we have to do this before we clear
  613. // frame properties and lose track of whether we were previously visible.
  614. // XXX(seth): It'd be ideal to assert that we're already marked nonvisible
  615. // here, but it's unfortunately tricky to guarantee in the face of things like
  616. // frame reconstruction induced by style changes.
  617. DisableVisibilityTracking();
  618. // Ensure that we're not in the approximately visible list anymore.
  619. PresContext()->GetPresShell()->RemoveFrameFromApproximatelyVisibleList(this);
  620. shell->NotifyDestroyingFrame(this);
  621. if (mState & NS_FRAME_EXTERNAL_REFERENCE) {
  622. shell->ClearFrameRefs(this);
  623. }
  624. if (view) {
  625. // Break association between view and frame
  626. view->SetFrame(nullptr);
  627. // Destroy the view
  628. view->Destroy();
  629. }
  630. // Make sure that our deleted frame can't be returned from GetPrimaryFrame()
  631. if (isPrimaryFrame) {
  632. mContent->SetPrimaryFrame(nullptr);
  633. }
  634. // Delete all properties attached to the frame, to ensure any property
  635. // destructors that need the frame pointer are handled properly.
  636. DeleteAllProperties();
  637. // Must retrieve the object ID before calling destructors, so the
  638. // vtable is still valid.
  639. //
  640. // Note to future tweakers: having the method that returns the
  641. // object size call the destructor will not avoid an indirect call;
  642. // the compiler cannot devirtualize the call to the destructor even
  643. // if it's from a method defined in the same class.
  644. nsQueryFrame::FrameIID id = GetFrameId();
  645. this->~nsFrame();
  646. // Now that we're totally cleaned out, we need to add ourselves to
  647. // the presshell's recycler.
  648. shell->FreeFrame(id, this);
  649. }
  650. nsresult
  651. nsFrame::GetOffsets(int32_t &aStart, int32_t &aEnd) const
  652. {
  653. aStart = 0;
  654. aEnd = 0;
  655. return NS_OK;
  656. }
  657. static
  658. void
  659. AddAndRemoveImageAssociations(nsFrame* aFrame,
  660. const nsStyleImageLayers* aOldLayers,
  661. const nsStyleImageLayers* aNewLayers)
  662. {
  663. ImageLoader* imageLoader =
  664. aFrame->PresContext()->Document()->StyleImageLoader();
  665. // If the old context had a background-image image, or mask-image image,
  666. // and new context does not have the same image, clear the image load
  667. // notifier (which keeps the image loading, if it still is) for the frame.
  668. // We want to do this conservatively because some frames paint their
  669. // backgrounds from some other frame's style data, and we don't want
  670. // to clear those notifiers unless we have to. (They'll be reset
  671. // when we paint, although we could miss a notification in that
  672. // interval.)
  673. if (aOldLayers) {
  674. NS_FOR_VISIBLE_IMAGE_LAYERS_BACK_TO_FRONT(i, (*aOldLayers)) {
  675. // If there is an image in oldBG that's not in newBG, drop it.
  676. if (i >= aNewLayers->mImageCount ||
  677. !aOldLayers->mLayers[i].mImage.ImageDataEquals(
  678. aNewLayers->mLayers[i].mImage)) {
  679. const nsStyleImage& oldImage = aOldLayers->mLayers[i].mImage;
  680. if (oldImage.GetType() != eStyleImageType_Image) {
  681. continue;
  682. }
  683. if (imgRequestProxy* req = oldImage.GetImageData()) {
  684. imageLoader->DisassociateRequestFromFrame(req, aFrame);
  685. }
  686. }
  687. }
  688. }
  689. NS_FOR_VISIBLE_IMAGE_LAYERS_BACK_TO_FRONT(i, (*aNewLayers)) {
  690. // If there is an image in newBG that's not in oldBG, add it.
  691. if (!aOldLayers || i >= aOldLayers->mImageCount ||
  692. !aNewLayers->mLayers[i].mImage.ImageDataEquals(
  693. aOldLayers->mLayers[i].mImage)) {
  694. const nsStyleImage& newImage = aNewLayers->mLayers[i].mImage;
  695. if (newImage.GetType() != eStyleImageType_Image) {
  696. continue;
  697. }
  698. if (imgRequestProxy* req = newImage.GetImageData()) {
  699. imageLoader->AssociateRequestToFrame(req, aFrame);
  700. }
  701. }
  702. }
  703. }
  704. // Subclass hook for style post processing
  705. /* virtual */ void
  706. nsFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext)
  707. {
  708. if (IsSVGText()) {
  709. SVGTextFrame* svgTextFrame = static_cast<SVGTextFrame*>(
  710. nsLayoutUtils::GetClosestFrameOfType(this, nsGkAtoms::svgTextFrame));
  711. nsIFrame* anonBlock = svgTextFrame->PrincipalChildList().FirstChild();
  712. // Just as in SVGTextFrame::DidSetStyleContext, we need to ensure that
  713. // any non-display SVGTextFrames get reflowed when a child text frame
  714. // gets new style.
  715. //
  716. // Note that we must check NS_FRAME_FIRST_REFLOW on our SVGTextFrame's
  717. // anonymous block frame rather than our self, since NS_FRAME_FIRST_REFLOW
  718. // may be set on us if we're a new frame that has been inserted after the
  719. // document's first reflow. (In which case this DidSetStyleContext call may
  720. // be happening under frame construction under a Reflow() call.)
  721. if (anonBlock && !(anonBlock->GetStateBits() & NS_FRAME_FIRST_REFLOW) &&
  722. (svgTextFrame->GetStateBits() & NS_FRAME_IS_NONDISPLAY) &&
  723. !(svgTextFrame->GetStateBits() & NS_STATE_SVG_TEXT_IN_REFLOW)) {
  724. svgTextFrame->ScheduleReflowSVGNonDisplayText(nsIPresShell::eStyleChange);
  725. }
  726. }
  727. const nsStyleImageLayers *oldLayers = aOldStyleContext ?
  728. &aOldStyleContext->StyleBackground()->mImage :
  729. nullptr;
  730. const nsStyleImageLayers *newLayers = &StyleBackground()->mImage;
  731. AddAndRemoveImageAssociations(this, oldLayers, newLayers);
  732. oldLayers = aOldStyleContext ? &aOldStyleContext->StyleSVGReset()->mMask :
  733. nullptr;
  734. newLayers = &StyleSVGReset()->mMask;
  735. AddAndRemoveImageAssociations(this, oldLayers, newLayers);
  736. if (aOldStyleContext) {
  737. // If we detect a change on margin, padding or border, we store the old
  738. // values on the frame itself between now and reflow, so if someone
  739. // calls GetUsed(Margin|Border|Padding)() before the next reflow, we
  740. // can give an accurate answer.
  741. // We don't want to set the property if one already exists.
  742. nsMargin oldValue(0, 0, 0, 0);
  743. nsMargin newValue(0, 0, 0, 0);
  744. const nsStyleMargin* oldMargin = aOldStyleContext->PeekStyleMargin();
  745. if (oldMargin && oldMargin->GetMargin(oldValue)) {
  746. if ((!StyleMargin()->GetMargin(newValue) || oldValue != newValue) &&
  747. !GetProperty(UsedMarginProperty())) {
  748. SetProperty(UsedMarginProperty(), new nsMargin(oldValue));
  749. }
  750. }
  751. const nsStylePadding* oldPadding = aOldStyleContext->PeekStylePadding();
  752. if (oldPadding && oldPadding->GetPadding(oldValue)) {
  753. if ((!StylePadding()->GetPadding(newValue) || oldValue != newValue) &&
  754. !GetProperty(UsedPaddingProperty())) {
  755. SetProperty(UsedPaddingProperty(), new nsMargin(oldValue));
  756. }
  757. }
  758. const nsStyleBorder* oldBorder = aOldStyleContext->PeekStyleBorder();
  759. if (oldBorder) {
  760. oldValue = oldBorder->GetComputedBorder();
  761. newValue = StyleBorder()->GetComputedBorder();
  762. if (oldValue != newValue &&
  763. !GetProperty(UsedBorderProperty())) {
  764. SetProperty(UsedBorderProperty(), new nsMargin(oldValue));
  765. }
  766. }
  767. }
  768. ImageLoader* imageLoader = PresContext()->Document()->StyleImageLoader();
  769. imgIRequest *oldBorderImage = aOldStyleContext
  770. ? aOldStyleContext->StyleBorder()->GetBorderImageRequest()
  771. : nullptr;
  772. imgIRequest *newBorderImage = StyleBorder()->GetBorderImageRequest();
  773. // FIXME (Bug 759996): The following is no longer true.
  774. // For border-images, we can't be as conservative (we need to set the
  775. // new loaders if there has been any change) since the CalcDifference
  776. // call depended on the result of GetComputedBorder() and that result
  777. // depends on whether the image has loaded, start the image load now
  778. // so that we'll get notified when it completes loading and can do a
  779. // restyle. Otherwise, the image might finish loading from the
  780. // network before we start listening to its notifications, and then
  781. // we'll never know that it's finished loading. Likewise, we want to
  782. // do this for freshly-created frames to prevent a similar race if the
  783. // image loads between reflow (which can depend on whether the image
  784. // is loaded) and paint. We also don't really care about any callers
  785. // who try to paint borders with a different style context, because
  786. // they won't have the correct size for the border either.
  787. if (oldBorderImage != newBorderImage) {
  788. // stop and restart the image loading/notification
  789. if (oldBorderImage) {
  790. imageLoader->DisassociateRequestFromFrame(oldBorderImage, this);
  791. }
  792. if (newBorderImage) {
  793. imageLoader->AssociateRequestToFrame(newBorderImage, this);
  794. }
  795. }
  796. // If the page contains markup that overrides text direction, and
  797. // does not contain any characters that would activate the Unicode
  798. // bidi algorithm, we need to call |SetBidiEnabled| on the pres
  799. // context before reflow starts. See bug 115921.
  800. if (StyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL) {
  801. PresContext()->SetBidiEnabled();
  802. }
  803. RemoveStateBits(NS_FRAME_SIMPLE_EVENT_REGIONS);
  804. }
  805. // MSVC fails with link error "one or more multiply defined symbols found",
  806. // gcc fails with "hidden symbol `nsIFrame::kPrincipalList' isn't defined"
  807. // etc if they are not defined.
  808. #ifndef _MSC_VER
  809. // static nsIFrame constants; initialized in the header file.
  810. const nsIFrame::ChildListID nsIFrame::kPrincipalList;
  811. const nsIFrame::ChildListID nsIFrame::kAbsoluteList;
  812. const nsIFrame::ChildListID nsIFrame::kBulletList;
  813. const nsIFrame::ChildListID nsIFrame::kCaptionList;
  814. const nsIFrame::ChildListID nsIFrame::kColGroupList;
  815. const nsIFrame::ChildListID nsIFrame::kExcessOverflowContainersList;
  816. const nsIFrame::ChildListID nsIFrame::kFixedList;
  817. const nsIFrame::ChildListID nsIFrame::kFloatList;
  818. const nsIFrame::ChildListID nsIFrame::kOverflowContainersList;
  819. const nsIFrame::ChildListID nsIFrame::kOverflowList;
  820. const nsIFrame::ChildListID nsIFrame::kOverflowOutOfFlowList;
  821. const nsIFrame::ChildListID nsIFrame::kPopupList;
  822. const nsIFrame::ChildListID nsIFrame::kPushedFloatsList;
  823. const nsIFrame::ChildListID nsIFrame::kSelectPopupList;
  824. const nsIFrame::ChildListID nsIFrame::kNoReflowPrincipalList;
  825. #endif
  826. /* virtual */ nsMargin
  827. nsIFrame::GetUsedMargin() const
  828. {
  829. nsMargin margin(0, 0, 0, 0);
  830. if (((mState & NS_FRAME_FIRST_REFLOW) &&
  831. !(mState & NS_FRAME_IN_REFLOW)) ||
  832. IsSVGText())
  833. return margin;
  834. nsMargin *m = GetProperty(UsedMarginProperty());
  835. if (m) {
  836. margin = *m;
  837. } else {
  838. if (!StyleMargin()->GetMargin(margin)) {
  839. // If we get here, our caller probably shouldn't be calling us...
  840. NS_ERROR("Returning bogus 0-sized margin, because this margin "
  841. "depends on layout & isn't cached!");
  842. }
  843. }
  844. return margin;
  845. }
  846. /* virtual */ nsMargin
  847. nsIFrame::GetUsedBorder() const
  848. {
  849. nsMargin border(0, 0, 0, 0);
  850. if (((mState & NS_FRAME_FIRST_REFLOW) &&
  851. !(mState & NS_FRAME_IN_REFLOW)) ||
  852. IsSVGText())
  853. return border;
  854. // Theme methods don't use const-ness.
  855. nsIFrame *mutable_this = const_cast<nsIFrame*>(this);
  856. const nsStyleDisplay *disp = StyleDisplay();
  857. if (mutable_this->IsThemed(disp)) {
  858. nsIntMargin result;
  859. nsPresContext *presContext = PresContext();
  860. presContext->GetTheme()->GetWidgetBorder(presContext->DeviceContext(),
  861. mutable_this, disp->mAppearance,
  862. &result);
  863. border.left = presContext->DevPixelsToAppUnits(result.left);
  864. border.top = presContext->DevPixelsToAppUnits(result.top);
  865. border.right = presContext->DevPixelsToAppUnits(result.right);
  866. border.bottom = presContext->DevPixelsToAppUnits(result.bottom);
  867. return border;
  868. }
  869. nsMargin *b = GetProperty(UsedBorderProperty());
  870. if (b) {
  871. border = *b;
  872. } else {
  873. border = StyleBorder()->GetComputedBorder();
  874. }
  875. return border;
  876. }
  877. /* virtual */ nsMargin
  878. nsIFrame::GetUsedPadding() const
  879. {
  880. nsMargin padding(0, 0, 0, 0);
  881. if (((mState & NS_FRAME_FIRST_REFLOW) &&
  882. !(mState & NS_FRAME_IN_REFLOW)) ||
  883. IsSVGText())
  884. return padding;
  885. // Theme methods don't use const-ness.
  886. nsIFrame *mutable_this = const_cast<nsIFrame*>(this);
  887. const nsStyleDisplay *disp = StyleDisplay();
  888. if (mutable_this->IsThemed(disp)) {
  889. nsPresContext *presContext = PresContext();
  890. nsIntMargin widget;
  891. if (presContext->GetTheme()->GetWidgetPadding(presContext->DeviceContext(),
  892. mutable_this,
  893. disp->mAppearance,
  894. &widget)) {
  895. padding.top = presContext->DevPixelsToAppUnits(widget.top);
  896. padding.right = presContext->DevPixelsToAppUnits(widget.right);
  897. padding.bottom = presContext->DevPixelsToAppUnits(widget.bottom);
  898. padding.left = presContext->DevPixelsToAppUnits(widget.left);
  899. return padding;
  900. }
  901. }
  902. nsMargin *p = GetProperty(UsedPaddingProperty());
  903. if (p) {
  904. padding = *p;
  905. } else {
  906. if (!StylePadding()->GetPadding(padding)) {
  907. // If we get here, our caller probably shouldn't be calling us...
  908. NS_ERROR("Returning bogus 0-sized padding, because this padding "
  909. "depends on layout & isn't cached!");
  910. }
  911. }
  912. return padding;
  913. }
  914. nsIFrame::Sides
  915. nsIFrame::GetSkipSides(const ReflowInput* aReflowInput) const
  916. {
  917. if (MOZ_UNLIKELY(StyleBorder()->mBoxDecorationBreak ==
  918. StyleBoxDecorationBreak::Clone) &&
  919. !(GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER)) {
  920. return Sides();
  921. }
  922. // Convert the logical skip sides to physical sides using the frame's
  923. // writing mode
  924. WritingMode writingMode = GetWritingMode();
  925. LogicalSides logicalSkip = GetLogicalSkipSides(aReflowInput);
  926. Sides skip;
  927. if (logicalSkip.BStart()) {
  928. if (writingMode.IsVertical()) {
  929. skip |= writingMode.IsVerticalLR() ? eSideBitsLeft : eSideBitsRight;
  930. } else {
  931. skip |= eSideBitsTop;
  932. }
  933. }
  934. if (logicalSkip.BEnd()) {
  935. if (writingMode.IsVertical()) {
  936. skip |= writingMode.IsVerticalLR() ? eSideBitsRight : eSideBitsLeft;
  937. } else {
  938. skip |= eSideBitsBottom;
  939. }
  940. }
  941. if (logicalSkip.IStart()) {
  942. if (writingMode.IsVertical()) {
  943. skip |= eSideBitsTop;
  944. } else {
  945. skip |= writingMode.IsBidiLTR() ? eSideBitsLeft : eSideBitsRight;
  946. }
  947. }
  948. if (logicalSkip.IEnd()) {
  949. if (writingMode.IsVertical()) {
  950. skip |= eSideBitsBottom;
  951. } else {
  952. skip |= writingMode.IsBidiLTR() ? eSideBitsRight : eSideBitsLeft;
  953. }
  954. }
  955. return skip;
  956. }
  957. nsRect
  958. nsIFrame::GetPaddingRectRelativeToSelf() const
  959. {
  960. nsMargin border(GetUsedBorder());
  961. border.ApplySkipSides(GetSkipSides());
  962. nsRect r(0, 0, mRect.width, mRect.height);
  963. r.Deflate(border);
  964. return r;
  965. }
  966. nsRect
  967. nsIFrame::GetPaddingRect() const
  968. {
  969. return GetPaddingRectRelativeToSelf() + GetPosition();
  970. }
  971. WritingMode
  972. nsIFrame::GetWritingMode(nsIFrame* aSubFrame) const
  973. {
  974. WritingMode writingMode = GetWritingMode();
  975. if (StyleTextReset()->mUnicodeBidi & NS_STYLE_UNICODE_BIDI_PLAINTEXT) {
  976. nsBidiLevel frameLevel = nsBidiPresUtils::GetFrameBaseLevel(aSubFrame);
  977. writingMode.SetDirectionFromBidiLevel(frameLevel);
  978. }
  979. return writingMode;
  980. }
  981. nsRect
  982. nsIFrame::GetMarginRectRelativeToSelf() const
  983. {
  984. nsMargin m = GetUsedMargin();
  985. m.ApplySkipSides(GetSkipSides());
  986. nsRect r(0, 0, mRect.width, mRect.height);
  987. r.Inflate(m);
  988. return r;
  989. }
  990. bool
  991. nsIFrame::IsTransformed() const
  992. {
  993. return ((mState & NS_FRAME_MAY_BE_TRANSFORMED) &&
  994. (StyleDisplay()->HasTransform(this) ||
  995. IsSVGTransformed() ||
  996. (mContent &&
  997. nsLayoutUtils::HasAnimationOfProperty(this,
  998. eCSSProperty_transform) &&
  999. IsFrameOfType(eSupportsCSSTransforms) &&
  1000. mContent->GetPrimaryFrame() == this)));
  1001. }
  1002. bool
  1003. nsIFrame::HasOpacityInternal(float aThreshold) const
  1004. {
  1005. MOZ_ASSERT(0.0 <= aThreshold && aThreshold <= 1.0, "Invalid argument");
  1006. return StyleEffects()->mOpacity < aThreshold ||
  1007. (StyleDisplay()->mWillChangeBitField & NS_STYLE_WILL_CHANGE_OPACITY) ||
  1008. (mContent &&
  1009. nsLayoutUtils::HasAnimationOfProperty(this, eCSSProperty_opacity) &&
  1010. mContent->GetPrimaryFrame() == this);
  1011. }
  1012. bool
  1013. nsIFrame::IsSVGTransformed(gfx::Matrix *aOwnTransforms,
  1014. gfx::Matrix *aFromParentTransforms) const
  1015. {
  1016. return false;
  1017. }
  1018. bool
  1019. nsIFrame::Extend3DContext() const
  1020. {
  1021. const nsStyleDisplay* disp = StyleDisplay();
  1022. if (disp->mTransformStyle != NS_STYLE_TRANSFORM_STYLE_PRESERVE_3D ||
  1023. !IsFrameOfType(nsIFrame::eSupportsCSSTransforms)) {
  1024. return false;
  1025. }
  1026. // If we're all scroll frame, then all descendants will be clipped, so we can't preserve 3d.
  1027. if (GetType() == nsGkAtoms::scrollFrame) {
  1028. return false;
  1029. }
  1030. if (HasOpacity()) {
  1031. return false;
  1032. }
  1033. const nsStyleEffects* effects = StyleEffects();
  1034. return !nsFrame::ShouldApplyOverflowClipping(this, disp) &&
  1035. !GetClipPropClipRect(disp, effects, GetSize()) &&
  1036. !nsSVGIntegrationUtils::UsingEffectsForFrame(this);
  1037. }
  1038. bool
  1039. nsIFrame::Combines3DTransformWithAncestors() const
  1040. {
  1041. if (!GetParent() || !GetParent()->Extend3DContext()) {
  1042. return false;
  1043. }
  1044. return IsTransformed() || BackfaceIsHidden();
  1045. }
  1046. bool
  1047. nsIFrame::In3DContextAndBackfaceIsHidden() const
  1048. {
  1049. return Combines3DTransformWithAncestors() && BackfaceIsHidden();
  1050. }
  1051. bool
  1052. nsIFrame::HasPerspective() const
  1053. {
  1054. if (!IsTransformed()) {
  1055. return false;
  1056. }
  1057. nsIFrame* containingBlock = GetContainingBlock(SKIP_SCROLLED_FRAME);
  1058. if (!containingBlock) {
  1059. return false;
  1060. }
  1061. return containingBlock->ChildrenHavePerspective();
  1062. }
  1063. bool
  1064. nsIFrame::ChildrenHavePerspective() const
  1065. {
  1066. return StyleDisplay()->HasPerspectiveStyle();
  1067. }
  1068. nsRect
  1069. nsIFrame::GetContentRectRelativeToSelf() const
  1070. {
  1071. nsMargin bp(GetUsedBorderAndPadding());
  1072. bp.ApplySkipSides(GetSkipSides());
  1073. nsRect r(0, 0, mRect.width, mRect.height);
  1074. r.Deflate(bp);
  1075. return r;
  1076. }
  1077. nsRect
  1078. nsIFrame::GetContentRect() const
  1079. {
  1080. return GetContentRectRelativeToSelf() + GetPosition();
  1081. }
  1082. bool
  1083. nsIFrame::ComputeBorderRadii(const nsStyleCorners& aBorderRadius,
  1084. const nsSize& aFrameSize,
  1085. const nsSize& aBorderArea,
  1086. Sides aSkipSides,
  1087. nscoord aRadii[8])
  1088. {
  1089. // Percentages are relative to whichever side they're on.
  1090. NS_FOR_CSS_HALF_CORNERS(i) {
  1091. const nsStyleCoord c = aBorderRadius.Get(i);
  1092. nscoord axis =
  1093. NS_HALF_CORNER_IS_X(i) ? aFrameSize.width : aFrameSize.height;
  1094. if (c.IsCoordPercentCalcUnit()) {
  1095. aRadii[i] = nsRuleNode::ComputeCoordPercentCalc(c, axis);
  1096. if (aRadii[i] < 0) {
  1097. // clamp calc()
  1098. aRadii[i] = 0;
  1099. }
  1100. } else {
  1101. NS_NOTREACHED("ComputeBorderRadii: bad unit");
  1102. aRadii[i] = 0;
  1103. }
  1104. }
  1105. if (aSkipSides.Top()) {
  1106. aRadii[NS_CORNER_TOP_LEFT_X] = 0;
  1107. aRadii[NS_CORNER_TOP_LEFT_Y] = 0;
  1108. aRadii[NS_CORNER_TOP_RIGHT_X] = 0;
  1109. aRadii[NS_CORNER_TOP_RIGHT_Y] = 0;
  1110. }
  1111. if (aSkipSides.Right()) {
  1112. aRadii[NS_CORNER_TOP_RIGHT_X] = 0;
  1113. aRadii[NS_CORNER_TOP_RIGHT_Y] = 0;
  1114. aRadii[NS_CORNER_BOTTOM_RIGHT_X] = 0;
  1115. aRadii[NS_CORNER_BOTTOM_RIGHT_Y] = 0;
  1116. }
  1117. if (aSkipSides.Bottom()) {
  1118. aRadii[NS_CORNER_BOTTOM_RIGHT_X] = 0;
  1119. aRadii[NS_CORNER_BOTTOM_RIGHT_Y] = 0;
  1120. aRadii[NS_CORNER_BOTTOM_LEFT_X] = 0;
  1121. aRadii[NS_CORNER_BOTTOM_LEFT_Y] = 0;
  1122. }
  1123. if (aSkipSides.Left()) {
  1124. aRadii[NS_CORNER_BOTTOM_LEFT_X] = 0;
  1125. aRadii[NS_CORNER_BOTTOM_LEFT_Y] = 0;
  1126. aRadii[NS_CORNER_TOP_LEFT_X] = 0;
  1127. aRadii[NS_CORNER_TOP_LEFT_Y] = 0;
  1128. }
  1129. // css3-background specifies this algorithm for reducing
  1130. // corner radii when they are too big.
  1131. bool haveRadius = false;
  1132. double ratio = 1.0f;
  1133. NS_FOR_CSS_SIDES(side) {
  1134. uint32_t hc1 = NS_SIDE_TO_HALF_CORNER(side, false, true);
  1135. uint32_t hc2 = NS_SIDE_TO_HALF_CORNER(side, true, true);
  1136. nscoord length =
  1137. NS_SIDE_IS_VERTICAL(side) ? aBorderArea.height : aBorderArea.width;
  1138. nscoord sum = aRadii[hc1] + aRadii[hc2];
  1139. if (sum)
  1140. haveRadius = true;
  1141. // avoid floating point division in the normal case
  1142. if (length < sum)
  1143. ratio = std::min(ratio, double(length)/sum);
  1144. }
  1145. if (ratio < 1.0) {
  1146. NS_FOR_CSS_HALF_CORNERS(corner) {
  1147. aRadii[corner] *= ratio;
  1148. }
  1149. }
  1150. return haveRadius;
  1151. }
  1152. /* static */ void
  1153. nsIFrame::InsetBorderRadii(nscoord aRadii[8], const nsMargin &aOffsets)
  1154. {
  1155. NS_FOR_CSS_SIDES(side) {
  1156. nscoord offset = aOffsets.Side(side);
  1157. uint32_t hc1 = NS_SIDE_TO_HALF_CORNER(side, false, false);
  1158. uint32_t hc2 = NS_SIDE_TO_HALF_CORNER(side, true, false);
  1159. aRadii[hc1] = std::max(0, aRadii[hc1] - offset);
  1160. aRadii[hc2] = std::max(0, aRadii[hc2] - offset);
  1161. }
  1162. }
  1163. /* static */ void
  1164. nsIFrame::OutsetBorderRadii(nscoord aRadii[8], const nsMargin &aOffsets)
  1165. {
  1166. NS_FOR_CSS_SIDES(side) {
  1167. nscoord offset = aOffsets.Side(side);
  1168. uint32_t hc1 = NS_SIDE_TO_HALF_CORNER(side, false, false);
  1169. uint32_t hc2 = NS_SIDE_TO_HALF_CORNER(side, true, false);
  1170. if (aRadii[hc1] > 0)
  1171. aRadii[hc1] += offset;
  1172. if (aRadii[hc2] > 0)
  1173. aRadii[hc2] += offset;
  1174. }
  1175. }
  1176. /* virtual */ bool
  1177. nsIFrame::GetBorderRadii(const nsSize& aFrameSize, const nsSize& aBorderArea,
  1178. Sides aSkipSides, nscoord aRadii[8]) const
  1179. {
  1180. if (IsThemed()) {
  1181. // When we're themed, the native theme code draws the border and
  1182. // background, and therefore it doesn't make sense to tell other
  1183. // code that's interested in border-radius that we have any radii.
  1184. //
  1185. // In an ideal world, we might have a way for the them to tell us an
  1186. // border radius, but since we don't, we're better off assuming
  1187. // zero.
  1188. NS_FOR_CSS_HALF_CORNERS(corner) {
  1189. aRadii[corner] = 0;
  1190. }
  1191. return false;
  1192. }
  1193. return ComputeBorderRadii(StyleBorder()->mBorderRadius,
  1194. aFrameSize, aBorderArea,
  1195. aSkipSides, aRadii);
  1196. }
  1197. bool
  1198. nsIFrame::GetBorderRadii(nscoord aRadii[8]) const
  1199. {
  1200. nsSize sz = GetSize();
  1201. return GetBorderRadii(sz, sz, GetSkipSides(), aRadii);
  1202. }
  1203. bool
  1204. nsIFrame::GetPaddingBoxBorderRadii(nscoord aRadii[8]) const
  1205. {
  1206. if (!GetBorderRadii(aRadii))
  1207. return false;
  1208. InsetBorderRadii(aRadii, GetUsedBorder());
  1209. NS_FOR_CSS_HALF_CORNERS(corner) {
  1210. if (aRadii[corner])
  1211. return true;
  1212. }
  1213. return false;
  1214. }
  1215. bool
  1216. nsIFrame::GetContentBoxBorderRadii(nscoord aRadii[8]) const
  1217. {
  1218. if (!GetBorderRadii(aRadii))
  1219. return false;
  1220. InsetBorderRadii(aRadii, GetUsedBorderAndPadding());
  1221. NS_FOR_CSS_HALF_CORNERS(corner) {
  1222. if (aRadii[corner])
  1223. return true;
  1224. }
  1225. return false;
  1226. }
  1227. nsStyleContext*
  1228. nsFrame::GetAdditionalStyleContext(int32_t aIndex) const
  1229. {
  1230. NS_PRECONDITION(aIndex >= 0, "invalid index number");
  1231. return nullptr;
  1232. }
  1233. void
  1234. nsFrame::SetAdditionalStyleContext(int32_t aIndex,
  1235. nsStyleContext* aStyleContext)
  1236. {
  1237. NS_PRECONDITION(aIndex >= 0, "invalid index number");
  1238. }
  1239. nscoord
  1240. nsFrame::GetLogicalBaseline(WritingMode aWritingMode) const
  1241. {
  1242. NS_ASSERTION(!NS_SUBTREE_DIRTY(this),
  1243. "frame must not be dirty");
  1244. // Baseline for inverted line content is the top (block-start) margin edge,
  1245. // as the frame is in effect "flipped" for alignment purposes.
  1246. if (aWritingMode.IsLineInverted()) {
  1247. return -GetLogicalUsedMargin(aWritingMode).BStart(aWritingMode);
  1248. }
  1249. // Otherwise, the bottom margin edge, per CSS2.1's definition of the
  1250. // 'baseline' value of 'vertical-align'.
  1251. return BSize(aWritingMode) +
  1252. GetLogicalUsedMargin(aWritingMode).BEnd(aWritingMode);
  1253. }
  1254. const nsFrameList&
  1255. nsFrame::GetChildList(ChildListID aListID) const
  1256. {
  1257. if (IsAbsoluteContainer() &&
  1258. aListID == GetAbsoluteListID()) {
  1259. return GetAbsoluteContainingBlock()->GetChildList();
  1260. } else {
  1261. return nsFrameList::EmptyList();
  1262. }
  1263. }
  1264. void
  1265. nsFrame::GetChildLists(nsTArray<ChildList>* aLists) const
  1266. {
  1267. if (IsAbsoluteContainer()) {
  1268. nsFrameList absoluteList = GetAbsoluteContainingBlock()->GetChildList();
  1269. absoluteList.AppendIfNonempty(aLists, GetAbsoluteListID());
  1270. }
  1271. }
  1272. void
  1273. nsIFrame::GetCrossDocChildLists(nsTArray<ChildList>* aLists)
  1274. {
  1275. nsSubDocumentFrame* subdocumentFrame = do_QueryFrame(this);
  1276. if (subdocumentFrame) {
  1277. // Descend into the subdocument
  1278. nsIFrame* root = subdocumentFrame->GetSubdocumentRootFrame();
  1279. if (root) {
  1280. aLists->AppendElement(nsIFrame::ChildList(
  1281. nsFrameList(root, nsLayoutUtils::GetLastSibling(root)),
  1282. nsIFrame::kPrincipalList));
  1283. }
  1284. }
  1285. GetChildLists(aLists);
  1286. }
  1287. Visibility
  1288. nsIFrame::GetVisibility() const
  1289. {
  1290. if (!(GetStateBits() & NS_FRAME_VISIBILITY_IS_TRACKED)) {
  1291. return Visibility::UNTRACKED;
  1292. }
  1293. bool isSet = false;
  1294. uint32_t visibleCount = GetProperty(VisibilityStateProperty(), &isSet);
  1295. MOZ_ASSERT(isSet, "Should have a VisibilityStateProperty value "
  1296. "if NS_FRAME_VISIBILITY_IS_TRACKED is set");
  1297. return visibleCount > 0
  1298. ? Visibility::APPROXIMATELY_VISIBLE
  1299. : Visibility::APPROXIMATELY_NONVISIBLE;
  1300. }
  1301. void
  1302. nsIFrame::UpdateVisibilitySynchronously()
  1303. {
  1304. nsIPresShell* presShell = PresContext()->PresShell();
  1305. if (!presShell) {
  1306. return;
  1307. }
  1308. if (presShell->AssumeAllFramesVisible()) {
  1309. presShell->EnsureFrameInApproximatelyVisibleList(this);
  1310. return;
  1311. }
  1312. bool visible = true;
  1313. nsIFrame* f = GetParent();
  1314. nsRect rect = GetRectRelativeToSelf();
  1315. nsIFrame* rectFrame = this;
  1316. while (f) {
  1317. nsIScrollableFrame* sf = do_QueryFrame(f);
  1318. if (sf) {
  1319. nsRect transformedRect =
  1320. nsLayoutUtils::TransformFrameRectToAncestor(rectFrame, rect, f);
  1321. if (!sf->IsRectNearlyVisible(transformedRect)) {
  1322. visible = false;
  1323. break;
  1324. }
  1325. // In this code we're trying to synchronously update *approximate*
  1326. // visibility. (In the future we may update precise visibility here as
  1327. // well, which is why the method name does not contain 'approximate'.) The
  1328. // IsRectNearlyVisible() check above tells us that the rect we're checking
  1329. // is approximately visible within the scrollframe, but we still need to
  1330. // ensure that, even if it was scrolled into view, it'd be visible when we
  1331. // consider the rest of the document. To do that, we move transformedRect
  1332. // to be contained in the scrollport as best we can (it might not fit) to
  1333. // pretend that it was scrolled into view.
  1334. rect = transformedRect.MoveInsideAndClamp(sf->GetScrollPortRect());
  1335. rectFrame = f;
  1336. }
  1337. nsIFrame* parent = f->GetParent();
  1338. if (!parent) {
  1339. parent = nsLayoutUtils::GetCrossDocParentFrame(f);
  1340. if (parent && parent->PresContext()->IsChrome()) {
  1341. break;
  1342. }
  1343. }
  1344. f = parent;
  1345. }
  1346. if (visible) {
  1347. presShell->EnsureFrameInApproximatelyVisibleList(this);
  1348. } else {
  1349. presShell->RemoveFrameFromApproximatelyVisibleList(this);
  1350. }
  1351. }
  1352. void
  1353. nsIFrame::EnableVisibilityTracking()
  1354. {
  1355. if (GetStateBits() & NS_FRAME_VISIBILITY_IS_TRACKED) {
  1356. return; // Nothing to do.
  1357. }
  1358. MOZ_ASSERT(!HasProperty(VisibilityStateProperty()),
  1359. "Shouldn't have a VisibilityStateProperty value "
  1360. "if NS_FRAME_VISIBILITY_IS_TRACKED is not set");
  1361. // Add the state bit so we know to track visibility for this frame, and
  1362. // initialize the frame property.
  1363. AddStateBits(NS_FRAME_VISIBILITY_IS_TRACKED);
  1364. SetProperty(VisibilityStateProperty(), 0);
  1365. nsIPresShell* presShell = PresContext()->PresShell();
  1366. if (!presShell) {
  1367. return;
  1368. }
  1369. // Schedule a visibility update. This method will virtually always be called
  1370. // when layout has changed anyway, so it's very unlikely that any additional
  1371. // visibility updates will be triggered by this, but this way we guarantee
  1372. // that if this frame is currently visible we'll eventually find out.
  1373. presShell->ScheduleApproximateFrameVisibilityUpdateSoon();
  1374. }
  1375. void
  1376. nsIFrame::DisableVisibilityTracking()
  1377. {
  1378. if (!(GetStateBits() & NS_FRAME_VISIBILITY_IS_TRACKED)) {
  1379. return; // Nothing to do.
  1380. }
  1381. bool isSet = false;
  1382. uint32_t visibleCount = RemoveProperty(VisibilityStateProperty(), &isSet);
  1383. MOZ_ASSERT(isSet, "Should have a VisibilityStateProperty value "
  1384. "if NS_FRAME_VISIBILITY_IS_TRACKED is set");
  1385. RemoveStateBits(NS_FRAME_VISIBILITY_IS_TRACKED);
  1386. if (visibleCount == 0) {
  1387. return; // We were nonvisible.
  1388. }
  1389. // We were visible, so send an OnVisibilityChange() notification.
  1390. OnVisibilityChange(Visibility::APPROXIMATELY_NONVISIBLE);
  1391. }
  1392. void
  1393. nsIFrame::DecApproximateVisibleCount(Maybe<OnNonvisible> aNonvisibleAction
  1394. /* = Nothing() */)
  1395. {
  1396. MOZ_ASSERT(GetStateBits() & NS_FRAME_VISIBILITY_IS_TRACKED);
  1397. bool isSet = false;
  1398. uint32_t visibleCount = GetProperty(VisibilityStateProperty(), &isSet);
  1399. MOZ_ASSERT(isSet, "Should have a VisibilityStateProperty value "
  1400. "if NS_FRAME_VISIBILITY_IS_TRACKED is set");
  1401. MOZ_ASSERT(visibleCount > 0, "Frame is already nonvisible and we're "
  1402. "decrementing its visible count?");
  1403. visibleCount--;
  1404. SetProperty(VisibilityStateProperty(), visibleCount);
  1405. if (visibleCount > 0) {
  1406. return;
  1407. }
  1408. // We just became nonvisible, so send an OnVisibilityChange() notification.
  1409. OnVisibilityChange(Visibility::APPROXIMATELY_NONVISIBLE, aNonvisibleAction);
  1410. }
  1411. void
  1412. nsIFrame::IncApproximateVisibleCount()
  1413. {
  1414. MOZ_ASSERT(GetStateBits() & NS_FRAME_VISIBILITY_IS_TRACKED);
  1415. bool isSet = false;
  1416. uint32_t visibleCount = GetProperty(VisibilityStateProperty(), &isSet);
  1417. MOZ_ASSERT(isSet, "Should have a VisibilityStateProperty value "
  1418. "if NS_FRAME_VISIBILITY_IS_TRACKED is set");
  1419. visibleCount++;
  1420. SetProperty(VisibilityStateProperty(), visibleCount);
  1421. if (visibleCount > 1) {
  1422. return;
  1423. }
  1424. // We just became visible, so send an OnVisibilityChange() notification.
  1425. OnVisibilityChange(Visibility::APPROXIMATELY_VISIBLE);
  1426. }
  1427. void
  1428. nsIFrame::OnVisibilityChange(Visibility aNewVisibility,
  1429. Maybe<OnNonvisible> aNonvisibleAction
  1430. /* = Nothing() */)
  1431. {
  1432. // XXX(seth): In bug 1218990 we'll implement visibility tracking for CSS
  1433. // images here.
  1434. }
  1435. static nsIFrame*
  1436. GetActiveSelectionFrame(nsPresContext* aPresContext, nsIFrame* aFrame)
  1437. {
  1438. nsIContent* capturingContent = nsIPresShell::GetCapturingContent();
  1439. if (capturingContent) {
  1440. nsIFrame* activeFrame = aPresContext->GetPrimaryFrameFor(capturingContent);
  1441. return activeFrame ? activeFrame : aFrame;
  1442. }
  1443. return aFrame;
  1444. }
  1445. int16_t
  1446. nsFrame::DisplaySelection(nsPresContext* aPresContext, bool isOkToTurnOn)
  1447. {
  1448. int16_t selType = nsISelectionController::SELECTION_OFF;
  1449. nsCOMPtr<nsISelectionController> selCon;
  1450. nsresult result = GetSelectionController(aPresContext, getter_AddRefs(selCon));
  1451. if (NS_SUCCEEDED(result) && selCon) {
  1452. result = selCon->GetDisplaySelection(&selType);
  1453. if (NS_SUCCEEDED(result) && (selType != nsISelectionController::SELECTION_OFF)) {
  1454. // Check whether style allows selection.
  1455. bool selectable;
  1456. IsSelectable(&selectable, nullptr);
  1457. if (!selectable) {
  1458. selType = nsISelectionController::SELECTION_OFF;
  1459. isOkToTurnOn = false;
  1460. }
  1461. }
  1462. if (isOkToTurnOn && (selType == nsISelectionController::SELECTION_OFF)) {
  1463. selCon->SetDisplaySelection(nsISelectionController::SELECTION_ON);
  1464. selType = nsISelectionController::SELECTION_ON;
  1465. }
  1466. }
  1467. return selType;
  1468. }
  1469. class nsDisplaySelectionOverlay : public nsDisplayItem {
  1470. public:
  1471. nsDisplaySelectionOverlay(nsDisplayListBuilder* aBuilder,
  1472. nsFrame* aFrame, int16_t aSelectionValue)
  1473. : nsDisplayItem(aBuilder, aFrame), mSelectionValue(aSelectionValue) {
  1474. MOZ_COUNT_CTOR(nsDisplaySelectionOverlay);
  1475. }
  1476. #ifdef NS_BUILD_REFCNT_LOGGING
  1477. virtual ~nsDisplaySelectionOverlay() {
  1478. MOZ_COUNT_DTOR(nsDisplaySelectionOverlay);
  1479. }
  1480. #endif
  1481. virtual void Paint(nsDisplayListBuilder* aBuilder,
  1482. nsRenderingContext* aCtx) override;
  1483. NS_DISPLAY_DECL_NAME("SelectionOverlay", TYPE_SELECTION_OVERLAY)
  1484. private:
  1485. int16_t mSelectionValue;
  1486. };
  1487. void nsDisplaySelectionOverlay::Paint(nsDisplayListBuilder* aBuilder,
  1488. nsRenderingContext* aCtx)
  1489. {
  1490. DrawTarget& aDrawTarget = *aCtx->GetDrawTarget();
  1491. LookAndFeel::ColorID colorID;
  1492. if (mSelectionValue == nsISelectionController::SELECTION_ON) {
  1493. colorID = LookAndFeel::eColorID_TextSelectBackground;
  1494. } else if (mSelectionValue == nsISelectionController::SELECTION_ATTENTION) {
  1495. colorID = LookAndFeel::eColorID_TextSelectBackgroundAttention;
  1496. } else {
  1497. colorID = LookAndFeel::eColorID_TextSelectBackgroundDisabled;
  1498. }
  1499. Color c = Color::FromABGR(LookAndFeel::GetColor(colorID, NS_RGB(255, 255, 255)));
  1500. c.a = .5;
  1501. ColorPattern color(ToDeviceColor(c));
  1502. nsIntRect pxRect =
  1503. mVisibleRect.ToOutsidePixels(mFrame->PresContext()->AppUnitsPerDevPixel());
  1504. Rect rect(pxRect.x, pxRect.y, pxRect.width, pxRect.height);
  1505. MaybeSnapToDevicePixels(rect, aDrawTarget, true);
  1506. aDrawTarget.FillRect(rect, color);
  1507. }
  1508. /********************************************************
  1509. * Refreshes each content's frame
  1510. *********************************************************/
  1511. void
  1512. nsFrame::DisplaySelectionOverlay(nsDisplayListBuilder* aBuilder,
  1513. nsDisplayList* aList,
  1514. uint16_t aContentType)
  1515. {
  1516. if (!IsSelected() || !IsVisibleForPainting(aBuilder))
  1517. return;
  1518. nsPresContext* presContext = PresContext();
  1519. nsIPresShell *shell = presContext->PresShell();
  1520. if (!shell)
  1521. return;
  1522. int16_t displaySelection = shell->GetSelectionFlags();
  1523. if (!(displaySelection & aContentType))
  1524. return;
  1525. const nsFrameSelection* frameSelection = GetConstFrameSelection();
  1526. int16_t selectionValue = frameSelection->GetDisplaySelection();
  1527. if (selectionValue <= nsISelectionController::SELECTION_HIDDEN)
  1528. return; // selection is hidden or off
  1529. nsIContent *newContent = mContent->GetParent();
  1530. //check to see if we are anonymous content
  1531. int32_t offset = 0;
  1532. if (newContent) {
  1533. // XXXbz there has GOT to be a better way of determining this!
  1534. offset = newContent->IndexOf(mContent);
  1535. }
  1536. SelectionDetails *details;
  1537. //look up to see what selection(s) are on this frame
  1538. details = frameSelection->LookUpSelection(newContent, offset, 1, false);
  1539. if (!details)
  1540. return;
  1541. bool normal = false;
  1542. while (details) {
  1543. if (details->mSelectionType == SelectionType::eNormal) {
  1544. normal = true;
  1545. }
  1546. SelectionDetails *next = details->mNext;
  1547. delete details;
  1548. details = next;
  1549. }
  1550. if (!normal && aContentType == nsISelectionDisplay::DISPLAY_IMAGES) {
  1551. // Don't overlay an image if it's not in the primary selection.
  1552. return;
  1553. }
  1554. aList->AppendNewToTop(new (aBuilder)
  1555. nsDisplaySelectionOverlay(aBuilder, this, selectionValue));
  1556. }
  1557. void
  1558. nsFrame::DisplayOutlineUnconditional(nsDisplayListBuilder* aBuilder,
  1559. const nsDisplayListSet& aLists)
  1560. {
  1561. // Per https://drafts.csswg.org/css-tables-3/#global-style-overrides:
  1562. // "All css properties of table-column and table-column-group boxes are
  1563. // ignored, except when explicitly specified by this specification."
  1564. // CSS outlines fall into this category, so we skip them on these boxes.
  1565. MOZ_ASSERT(GetType() != nsGkAtoms::tableColGroupFrame && GetType() != nsGkAtoms::tableColFrame);
  1566. if (StyleOutline()->mOutlineStyle == NS_STYLE_BORDER_STYLE_NONE) {
  1567. return;
  1568. }
  1569. aLists.Outlines()->AppendNewToTop(
  1570. new (aBuilder) nsDisplayOutline(aBuilder, this));
  1571. }
  1572. void
  1573. nsFrame::DisplayOutline(nsDisplayListBuilder* aBuilder,
  1574. const nsDisplayListSet& aLists)
  1575. {
  1576. if (!IsVisibleForPainting(aBuilder))
  1577. return;
  1578. DisplayOutlineUnconditional(aBuilder, aLists);
  1579. }
  1580. void
  1581. nsIFrame::DisplayCaret(nsDisplayListBuilder* aBuilder,
  1582. nsDisplayList* aList)
  1583. {
  1584. if (!IsVisibleForPainting(aBuilder))
  1585. return;
  1586. aList->AppendNewToTop(new (aBuilder) nsDisplayCaret(aBuilder, this));
  1587. }
  1588. nscolor
  1589. nsIFrame::GetCaretColorAt(int32_t aOffset)
  1590. {
  1591. return nsLayoutUtils::GetColor(this, eCSSProperty_caret_color);
  1592. }
  1593. bool
  1594. nsFrame::DisplayBackgroundUnconditional(nsDisplayListBuilder* aBuilder,
  1595. const nsDisplayListSet& aLists,
  1596. bool aForceBackground)
  1597. {
  1598. // Here we don't try to detect background propagation. Frames that might
  1599. // receive a propagated background should just set aForceBackground to
  1600. // true.
  1601. if (aBuilder->IsForEventDelivery() || aForceBackground ||
  1602. !StyleBackground()->IsTransparent() || StyleDisplay()->mAppearance) {
  1603. return nsDisplayBackgroundImage::AppendBackgroundItemsToTop(
  1604. aBuilder, this,
  1605. GetRectRelativeToSelf() + aBuilder->ToReferenceFrame(this),
  1606. aLists.BorderBackground());
  1607. }
  1608. return false;
  1609. }
  1610. void
  1611. nsFrame::DisplayBorderBackgroundOutline(nsDisplayListBuilder* aBuilder,
  1612. const nsDisplayListSet& aLists,
  1613. bool aForceBackground)
  1614. {
  1615. // The visibility check belongs here since child elements have the
  1616. // opportunity to override the visibility property and display even if
  1617. // their parent is hidden.
  1618. if (!IsVisibleForPainting(aBuilder)) {
  1619. return;
  1620. }
  1621. nsCSSShadowArray* shadows = StyleEffects()->mBoxShadow;
  1622. if (shadows && shadows->HasShadowWithInset(false)) {
  1623. aLists.BorderBackground()->AppendNewToTop(new (aBuilder)
  1624. nsDisplayBoxShadowOuter(aBuilder, this));
  1625. }
  1626. bool bgIsThemed = DisplayBackgroundUnconditional(aBuilder, aLists,
  1627. aForceBackground);
  1628. if (shadows && shadows->HasShadowWithInset(true)) {
  1629. aLists.BorderBackground()->AppendNewToTop(new (aBuilder)
  1630. nsDisplayBoxShadowInner(aBuilder, this));
  1631. }
  1632. // If there's a themed background, we should not create a border item.
  1633. // It won't be rendered.
  1634. // Don't paint borders for tables here, since they paint them in a different
  1635. // order.
  1636. if (!bgIsThemed && StyleBorder()->HasBorder() && GetType() != nsGkAtoms::tableFrame) {
  1637. aLists.BorderBackground()->AppendNewToTop(new (aBuilder)
  1638. nsDisplayBorder(aBuilder, this));
  1639. }
  1640. DisplayOutlineUnconditional(aBuilder, aLists);
  1641. }
  1642. inline static bool IsSVGContentWithCSSClip(const nsIFrame *aFrame)
  1643. {
  1644. // The CSS spec says that the 'clip' property only applies to absolutely
  1645. // positioned elements, whereas the SVG spec says that it applies to SVG
  1646. // elements regardless of the value of the 'position' property. Here we obey
  1647. // the CSS spec for outer-<svg> (since that's what we generally do), but
  1648. // obey the SVG spec for other SVG elements to which 'clip' applies.
  1649. return (aFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT) &&
  1650. aFrame->GetContent()->IsAnyOfSVGElements(nsGkAtoms::svg,
  1651. nsGkAtoms::foreignObject);
  1652. }
  1653. Maybe<nsRect>
  1654. nsIFrame::GetClipPropClipRect(const nsStyleDisplay* aDisp,
  1655. const nsStyleEffects* aEffects,
  1656. const nsSize& aSize) const
  1657. {
  1658. if (!(aEffects->mClipFlags & NS_STYLE_CLIP_RECT) ||
  1659. !(aDisp->IsAbsolutelyPositioned(this) || IsSVGContentWithCSSClip(this))) {
  1660. return Nothing();
  1661. }
  1662. nsRect rect = aEffects->mClip;
  1663. if (MOZ_LIKELY(StyleBorder()->mBoxDecorationBreak ==
  1664. StyleBoxDecorationBreak::Slice)) {
  1665. // The clip applies to the joined boxes so it's relative the first
  1666. // continuation.
  1667. nscoord y = 0;
  1668. for (nsIFrame* f = GetPrevContinuation(); f; f = f->GetPrevContinuation()) {
  1669. y += f->GetRect().height;
  1670. }
  1671. rect.MoveBy(nsPoint(0, -y));
  1672. }
  1673. if (NS_STYLE_CLIP_RIGHT_AUTO & aEffects->mClipFlags) {
  1674. rect.width = aSize.width - rect.x;
  1675. }
  1676. if (NS_STYLE_CLIP_BOTTOM_AUTO & aEffects->mClipFlags) {
  1677. rect.height = aSize.height - rect.y;
  1678. }
  1679. return Some(rect);
  1680. }
  1681. /**
  1682. * If the CSS 'overflow' property applies to this frame, and is not
  1683. * handled by constructing a dedicated nsHTML/XULScrollFrame, set up clipping
  1684. * for that overflow in aBuilder->ClipState() to clip all containing-block
  1685. * descendants.
  1686. */
  1687. static void
  1688. ApplyOverflowClipping(nsDisplayListBuilder* aBuilder,
  1689. const nsIFrame* aFrame,
  1690. const nsStyleDisplay* aDisp,
  1691. DisplayListClipState::AutoClipMultiple& aClipState)
  1692. {
  1693. // Only -moz-hidden-unscrollable is handled here (and 'hidden' for table
  1694. // frames, and any non-visible value for blocks in a paginated context).
  1695. // We allow -moz-hidden-unscrollable to apply to any kind of frame. This
  1696. // is required by comboboxes which make their display text (an inline frame)
  1697. // have clipping.
  1698. if (!nsFrame::ShouldApplyOverflowClipping(aFrame, aDisp)) {
  1699. return;
  1700. }
  1701. nsRect clipRect;
  1702. bool haveRadii = false;
  1703. nscoord radii[8];
  1704. if (aFrame->StyleDisplay()->mOverflowClipBox ==
  1705. NS_STYLE_OVERFLOW_CLIP_BOX_PADDING_BOX) {
  1706. clipRect = aFrame->GetPaddingRectRelativeToSelf() +
  1707. aBuilder->ToReferenceFrame(aFrame);
  1708. haveRadii = aFrame->GetPaddingBoxBorderRadii(radii);
  1709. } else {
  1710. clipRect = aFrame->GetContentRectRelativeToSelf() +
  1711. aBuilder->ToReferenceFrame(aFrame);
  1712. // XXX border-radius
  1713. }
  1714. aClipState.ClipContainingBlockDescendantsExtra(clipRect, haveRadii ? radii : nullptr);
  1715. }
  1716. #ifdef DEBUG
  1717. static void PaintDebugBorder(nsIFrame* aFrame, DrawTarget* aDrawTarget,
  1718. const nsRect& aDirtyRect, nsPoint aPt)
  1719. {
  1720. nsRect r(aPt, aFrame->GetSize());
  1721. int32_t appUnitsPerDevPixel = aFrame->PresContext()->AppUnitsPerDevPixel();
  1722. Color blueOrRed(aFrame->HasView() ? Color(0.f, 0.f, 1.f, 1.f) :
  1723. Color(1.f, 0.f, 0.f, 1.f));
  1724. aDrawTarget->StrokeRect(NSRectToRect(r, appUnitsPerDevPixel),
  1725. ColorPattern(ToDeviceColor(blueOrRed)));
  1726. }
  1727. static void PaintEventTargetBorder(nsIFrame* aFrame, DrawTarget* aDrawTarget,
  1728. const nsRect& aDirtyRect, nsPoint aPt)
  1729. {
  1730. nsRect r(aPt, aFrame->GetSize());
  1731. int32_t appUnitsPerDevPixel = aFrame->PresContext()->AppUnitsPerDevPixel();
  1732. ColorPattern purple(ToDeviceColor(Color(.5f, 0.f, .5f, 1.f)));
  1733. aDrawTarget->StrokeRect(NSRectToRect(r, appUnitsPerDevPixel), purple);
  1734. }
  1735. static void
  1736. DisplayDebugBorders(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
  1737. const nsDisplayListSet& aLists) {
  1738. // Draw a border around the child
  1739. // REVIEW: From nsContainerFrame::PaintChild
  1740. if (nsFrame::GetShowFrameBorders() && !aFrame->GetRect().IsEmpty()) {
  1741. aLists.Outlines()->AppendNewToTop(new (aBuilder)
  1742. nsDisplayGeneric(aBuilder, aFrame, PaintDebugBorder, "DebugBorder",
  1743. nsDisplayItem::TYPE_DEBUG_BORDER));
  1744. }
  1745. // Draw a border around the current event target
  1746. if (nsFrame::GetShowEventTargetFrameBorder() &&
  1747. aFrame->PresContext()->PresShell()->GetDrawEventTargetFrame() == aFrame) {
  1748. aLists.Outlines()->AppendNewToTop(new (aBuilder)
  1749. nsDisplayGeneric(aBuilder, aFrame, PaintEventTargetBorder, "EventTargetBorder",
  1750. nsDisplayItem::TYPE_EVENT_TARGET_BORDER));
  1751. }
  1752. }
  1753. #endif
  1754. static bool
  1755. IsScrollFrameActive(nsDisplayListBuilder* aBuilder, nsIScrollableFrame* aScrollableFrame)
  1756. {
  1757. return aScrollableFrame && aScrollableFrame->IsScrollingActive(aBuilder);
  1758. }
  1759. class AutoSaveRestoreContainsBlendMode
  1760. {
  1761. nsDisplayListBuilder& mBuilder;
  1762. bool mSavedContainsBlendMode;
  1763. public:
  1764. explicit AutoSaveRestoreContainsBlendMode(nsDisplayListBuilder& aBuilder)
  1765. : mBuilder(aBuilder)
  1766. , mSavedContainsBlendMode(aBuilder.ContainsBlendMode())
  1767. { }
  1768. ~AutoSaveRestoreContainsBlendMode() {
  1769. mBuilder.SetContainsBlendMode(mSavedContainsBlendMode);
  1770. }
  1771. };
  1772. static void
  1773. CheckForApzAwareEventHandlers(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
  1774. {
  1775. nsIContent* content = aFrame->GetContent();
  1776. if (!content) {
  1777. return;
  1778. }
  1779. if (content->IsNodeApzAware()) {
  1780. aBuilder->SetAncestorHasApzAwareEventHandler(true);
  1781. }
  1782. }
  1783. /**
  1784. * True if aDescendant participates the context aAncestor participating.
  1785. */
  1786. static bool
  1787. FrameParticipatesIn3DContext(nsIFrame* aAncestor, nsIFrame* aDescendant) {
  1788. MOZ_ASSERT(aAncestor != aDescendant);
  1789. MOZ_ASSERT(aAncestor->Extend3DContext());
  1790. nsIFrame* frame;
  1791. for (frame = nsLayoutUtils::GetCrossDocParentFrame(aDescendant);
  1792. frame && aAncestor != frame;
  1793. frame = nsLayoutUtils::GetCrossDocParentFrame(frame)) {
  1794. if (!frame->Extend3DContext()) {
  1795. return false;
  1796. }
  1797. }
  1798. MOZ_ASSERT(frame == aAncestor);
  1799. return true;
  1800. }
  1801. static bool
  1802. ItemParticipatesIn3DContext(nsIFrame* aAncestor, nsDisplayItem* aItem)
  1803. {
  1804. nsIFrame* transformFrame;
  1805. if (aItem->GetType() == nsDisplayItem::TYPE_TRANSFORM) {
  1806. transformFrame = aItem->Frame();
  1807. } else if (aItem->GetType() == nsDisplayItem::TYPE_PERSPECTIVE) {
  1808. transformFrame = static_cast<nsDisplayPerspective*>(aItem)->TransformFrame();
  1809. } else {
  1810. return false;
  1811. }
  1812. if (aAncestor == transformFrame) {
  1813. return true;
  1814. }
  1815. return FrameParticipatesIn3DContext(aAncestor, transformFrame);
  1816. }
  1817. static void
  1818. WrapSeparatorTransform(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
  1819. nsDisplayList* aSource, nsDisplayList* aTarget,
  1820. int aIndex) {
  1821. if (!aSource->IsEmpty()) {
  1822. nsDisplayTransform *sepIdItem =
  1823. new (aBuilder) nsDisplayTransform(aBuilder, aFrame, aSource,
  1824. aBuilder->GetDirtyRect(), Matrix4x4(), aIndex);
  1825. sepIdItem->SetNoExtendContext();
  1826. aTarget->AppendToTop(sepIdItem);
  1827. }
  1828. }
  1829. void
  1830. nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
  1831. nsDisplayList* aList) {
  1832. if (GetStateBits() & NS_FRAME_TOO_DEEP_IN_FRAME_TREE)
  1833. return;
  1834. // Replaced elements have their visibility handled here, because
  1835. // they're visually atomic
  1836. if (IsFrameOfType(eReplaced) && !IsVisibleForPainting(aBuilder))
  1837. return;
  1838. const nsStyleDisplay* disp = StyleDisplay();
  1839. const nsStyleEffects* effects = StyleEffects();
  1840. // We can stop right away if this is a zero-opacity stacking context and
  1841. // we're painting, and we're not animating opacity. Don't do this
  1842. // if we're going to compute plugin geometry, since opacity-0 plugins
  1843. // need to have display items built for them.
  1844. bool needEventRegions =
  1845. aBuilder->IsBuildingLayerEventRegions() &&
  1846. StyleUserInterface()->GetEffectivePointerEvents(this) !=
  1847. NS_STYLE_POINTER_EVENTS_NONE;
  1848. bool opacityItemForEventsAndPluginsOnly = false;
  1849. if (effects->mOpacity == 0.0 && aBuilder->IsForPainting() &&
  1850. !(disp->mWillChangeBitField & NS_STYLE_WILL_CHANGE_OPACITY) &&
  1851. !nsLayoutUtils::HasAnimationOfProperty(this, eCSSProperty_opacity)) {
  1852. if (needEventRegions ||
  1853. aBuilder->WillComputePluginGeometry()) {
  1854. opacityItemForEventsAndPluginsOnly = true;
  1855. } else {
  1856. return;
  1857. }
  1858. }
  1859. if (disp->mWillChangeBitField != 0) {
  1860. aBuilder->AddToWillChangeBudget(this, GetSize());
  1861. }
  1862. const bool isTransformed = IsTransformed();
  1863. const bool hasPerspective = isTransformed && HasPerspective();
  1864. const bool extend3DContext = Extend3DContext();
  1865. const bool combines3DTransformWithAncestors =
  1866. (extend3DContext || isTransformed) && Combines3DTransformWithAncestors();
  1867. const bool childrenHavePerspective = ChildrenHavePerspective();
  1868. Maybe<nsDisplayListBuilder::AutoPreserves3DContext> autoPreserves3DContext;
  1869. if (extend3DContext && !combines3DTransformWithAncestors) {
  1870. // Start a new preserves3d context to keep informations on
  1871. // nsDisplayListBuilder.
  1872. autoPreserves3DContext.emplace(aBuilder);
  1873. // Save dirty rect on the builder to avoid being distorted for
  1874. // multiple transforms along the chain.
  1875. aBuilder->SavePreserves3DRects();
  1876. }
  1877. // For preserves3d, use the dirty rect already installed on the
  1878. // builder, since aDirtyRect maybe distorted for transforms along
  1879. // the chain.
  1880. nsRect dirtyRect = aBuilder->GetDirtyRect();
  1881. // reset blend mode so we can keep track if this stacking context needs have
  1882. // a nsDisplayBlendContainer. Set the blend mode back when the routine exits
  1883. // so we keep track if the parent stacking context needs a container too.
  1884. AutoSaveRestoreContainsBlendMode autoRestoreBlendMode(*aBuilder);
  1885. aBuilder->SetContainsBlendMode(false);
  1886. nsRect dirtyRectOutsideTransform = dirtyRect;
  1887. bool inTransform = aBuilder->IsInTransform();
  1888. if (isTransformed) {
  1889. const nsRect overflow = GetVisualOverflowRectRelativeToSelf();
  1890. if (nsDisplayTransform::ShouldPrerenderTransformedContent(aBuilder,
  1891. this)) {
  1892. dirtyRect = overflow;
  1893. } else {
  1894. if (overflow.IsEmpty() && !extend3DContext) {
  1895. return;
  1896. }
  1897. // If we're in preserve-3d then grab the dirty rect that was given to the root
  1898. // and transform using the combined transform.
  1899. if (combines3DTransformWithAncestors) {
  1900. dirtyRect = aBuilder->GetPreserves3DRects();
  1901. }
  1902. nsRect untransformedDirtyRect;
  1903. if (nsDisplayTransform::UntransformRect(dirtyRect, overflow, this,
  1904. &untransformedDirtyRect)) {
  1905. dirtyRect = untransformedDirtyRect;
  1906. } else {
  1907. NS_WARNING("Unable to untransform dirty rect!");
  1908. // This should only happen if the transform is singular, in which case nothing is visible anyway
  1909. dirtyRect.SetEmpty();
  1910. }
  1911. }
  1912. inTransform = true;
  1913. }
  1914. bool usingFilter = StyleEffects()->HasFilters();
  1915. bool usingMask = nsSVGIntegrationUtils::UsingMaskOrClipPathForFrame(this);
  1916. bool usingSVGEffects = usingFilter || usingMask;
  1917. nsRect dirtyRectOutsideSVGEffects = dirtyRect;
  1918. nsDisplayList hoistedScrollInfoItemsStorage;
  1919. if (usingSVGEffects) {
  1920. dirtyRect =
  1921. nsSVGIntegrationUtils::GetRequiredSourceForInvalidArea(this, dirtyRect);
  1922. aBuilder->EnterSVGEffectsContents(&hoistedScrollInfoItemsStorage);
  1923. }
  1924. // We build an opacity item if it's not going to be drawn by SVG content, or
  1925. // SVG effects. SVG effects won't handle the opacity if we want an active
  1926. // layer (for async animations), see
  1927. // nsSVGIntegrationsUtils::PaintMaskAndClipPath or
  1928. // nsSVGIntegrationsUtils::PaintFilter.
  1929. bool useOpacity = HasVisualOpacity() && !nsSVGUtils::CanOptimizeOpacity(this) &&
  1930. (!usingSVGEffects || nsDisplayOpacity::NeedsActiveLayer(aBuilder, this));
  1931. bool useBlendMode = effects->mMixBlendMode != NS_STYLE_BLEND_NORMAL;
  1932. bool useStickyPosition = disp->mPosition == NS_STYLE_POSITION_STICKY &&
  1933. IsScrollFrameActive(aBuilder,
  1934. nsLayoutUtils::GetNearestScrollableFrame(GetParent(),
  1935. nsLayoutUtils::SCROLLABLE_SAME_DOC |
  1936. nsLayoutUtils::SCROLLABLE_INCLUDE_HIDDEN));
  1937. bool useFixedPosition = nsLayoutUtils::IsFixedPosFrameInDisplayPort(this);
  1938. nsDisplayListBuilder::AutoBuildingDisplayList
  1939. buildingDisplayList(aBuilder, this, dirtyRect, true);
  1940. // Depending on the effects that are applied to this frame, we can create
  1941. // multiple container display items and wrap them around our contents.
  1942. // This enum lists all the potential container display items, in the order
  1943. // outside to inside.
  1944. enum class ContainerItemType : uint8_t {
  1945. eNone = 0,
  1946. eOwnLayerIfNeeded,
  1947. eBlendMode,
  1948. eFixedPosition,
  1949. eStickyPosition,
  1950. eOwnLayerForTransformWithRoundedClip,
  1951. ePerspective,
  1952. eTransform,
  1953. eSeparatorTransforms,
  1954. eOpacity,
  1955. eFilter,
  1956. eBlendContainer
  1957. };
  1958. DisplayListClipState::AutoSaveRestore clipState(aBuilder);
  1959. // If there is a current clip, then depending on the container items we
  1960. // create, different things can happen to it. Some container items simply
  1961. // propagate the clip to their children and aren't clipped themselves.
  1962. // But other container items, especially those that establish a different
  1963. // geometry for their contents (e.g. transforms), capture the clip on
  1964. // themselves and unset the clip for their contents. If we create more than
  1965. // one of those container items, the clip will be captured on the outermost
  1966. // one and the inner container items will be unclipped.
  1967. ContainerItemType clipCapturedBy = ContainerItemType::eNone;
  1968. if (useFixedPosition) {
  1969. clipCapturedBy = ContainerItemType::eFixedPosition;
  1970. } else if (useStickyPosition) {
  1971. clipCapturedBy = ContainerItemType::eStickyPosition;
  1972. } else if (isTransformed) {
  1973. if ((hasPerspective || extend3DContext) && clipState.SavedStateHasRoundedCorners()) {
  1974. // If we're creating an nsDisplayTransform item that is going to combine
  1975. // its transform with its children (preserve-3d or perspective), then we
  1976. // can't have an intermediate surface. Mask layers force an intermediate
  1977. // surface, so if we're going to need both then create a separate
  1978. // wrapping layer for the mask.
  1979. clipCapturedBy = ContainerItemType::eOwnLayerForTransformWithRoundedClip;
  1980. } else if (hasPerspective) {
  1981. clipCapturedBy = ContainerItemType::ePerspective;
  1982. } else {
  1983. clipCapturedBy = ContainerItemType::eTransform;
  1984. }
  1985. } else if (usingFilter) {
  1986. clipCapturedBy = ContainerItemType::eFilter;
  1987. }
  1988. bool clearClip = false;
  1989. if (clipCapturedBy != ContainerItemType::eNone) {
  1990. // We don't need to pass ancestor clipping down to our children;
  1991. // everything goes inside a display item's child list, and the display
  1992. // item itself will be clipped.
  1993. // For transforms we also need to clear ancestor clipping because it's
  1994. // relative to the wrong display item reference frame anyway.
  1995. clearClip = true;
  1996. }
  1997. clipState.EnterStackingContextContents(clearClip);
  1998. nsDisplayListCollection set(aBuilder);
  1999. {
  2000. DisplayListClipState::AutoSaveRestore nestedClipState(aBuilder);
  2001. nsDisplayListBuilder::AutoInTransformSetter
  2002. inTransformSetter(aBuilder, inTransform);
  2003. nsDisplayListBuilder::AutoSaveRestorePerspectiveIndex
  2004. perspectiveIndex(aBuilder, childrenHavePerspective);
  2005. CheckForApzAwareEventHandlers(aBuilder, this);
  2006. Maybe<nsRect> clipPropClip = GetClipPropClipRect(disp, effects, GetSize());
  2007. if (clipPropClip) {
  2008. aBuilder->IntersectDirtyRect(*clipPropClip);
  2009. nestedClipState.ClipContentDescendants(
  2010. *clipPropClip + aBuilder->ToReferenceFrame(this));
  2011. }
  2012. // extend3DContext also guarantees that applyAbsPosClipping and usingSVGEffects are false
  2013. // We only modify the preserve-3d rect if we are the top of a preserve-3d heirarchy
  2014. if (extend3DContext) {
  2015. // Mark these first so MarkAbsoluteFramesForDisplayList knows if we are
  2016. // going to be forced to descend into frames.
  2017. aBuilder->MarkPreserve3DFramesForDisplayList(this);
  2018. }
  2019. MarkAbsoluteFramesForDisplayList(aBuilder);
  2020. nsDisplayLayerEventRegions* eventRegions = nullptr;
  2021. if (aBuilder->IsBuildingLayerEventRegions()) {
  2022. eventRegions = new (aBuilder) nsDisplayLayerEventRegions(aBuilder, this);
  2023. eventRegions->AddFrame(aBuilder, this);
  2024. aBuilder->SetLayerEventRegions(eventRegions);
  2025. }
  2026. aBuilder->AdjustWindowDraggingRegion(this);
  2027. BuildDisplayList(aBuilder, set);
  2028. if (eventRegions) {
  2029. // If the event regions item ended up empty, throw it away rather than
  2030. // adding it to the display list.
  2031. if (!eventRegions->IsEmpty()) {
  2032. set.BorderBackground()->AppendToBottom(eventRegions);
  2033. } else {
  2034. aBuilder->SetLayerEventRegions(nullptr);
  2035. eventRegions->~nsDisplayLayerEventRegions();
  2036. eventRegions = nullptr;
  2037. }
  2038. }
  2039. }
  2040. if (aBuilder->IsBackgroundOnly()) {
  2041. set.BlockBorderBackgrounds()->DeleteAll();
  2042. set.Floats()->DeleteAll();
  2043. set.Content()->DeleteAll();
  2044. set.PositionedDescendants()->DeleteAll();
  2045. set.Outlines()->DeleteAll();
  2046. }
  2047. // Sort PositionedDescendants() in CSS 'z-order' order. The list is already
  2048. // in content document order and SortByZOrder is a stable sort which
  2049. // guarantees that boxes produced by the same element are placed together
  2050. // in the sort. Consider a position:relative inline element that breaks
  2051. // across lines and has absolutely positioned children; all the abs-pos
  2052. // children should be z-ordered after all the boxes for the position:relative
  2053. // element itself.
  2054. set.PositionedDescendants()->SortByZOrder();
  2055. nsDisplayList resultList;
  2056. // Now follow the rules of http://www.w3.org/TR/CSS21/zindex.html
  2057. // 1,2: backgrounds and borders
  2058. resultList.AppendToTop(set.BorderBackground());
  2059. // 3: negative z-index children.
  2060. for (;;) {
  2061. nsDisplayItem* item = set.PositionedDescendants()->GetBottom();
  2062. if (item && item->ZIndex() < 0) {
  2063. set.PositionedDescendants()->RemoveBottom();
  2064. resultList.AppendToTop(item);
  2065. continue;
  2066. }
  2067. break;
  2068. }
  2069. // 4: block backgrounds
  2070. resultList.AppendToTop(set.BlockBorderBackgrounds());
  2071. // 5: floats
  2072. resultList.AppendToTop(set.Floats());
  2073. // 7: general content
  2074. resultList.AppendToTop(set.Content());
  2075. // 7.5: outlines, in content tree order. We need to sort by content order
  2076. // because an element with outline that breaks and has children with outline
  2077. // might have placed child outline items between its own outline items.
  2078. // The element's outline items need to all come before any child outline
  2079. // items.
  2080. nsIContent* content = GetContent();
  2081. if (!content) {
  2082. content = PresContext()->Document()->GetRootElement();
  2083. }
  2084. if (content) {
  2085. set.Outlines()->SortByContentOrder(content);
  2086. }
  2087. #ifdef DEBUG
  2088. DisplayDebugBorders(aBuilder, this, set);
  2089. #endif
  2090. resultList.AppendToTop(set.Outlines());
  2091. // 8, 9: non-negative z-index children
  2092. resultList.AppendToTop(set.PositionedDescendants());
  2093. // Get the scroll clip to use for the container items that we create here.
  2094. // If we cleared the clip, and we create multiple container items, then the
  2095. // items we create before we restore the clip will have a different scroll
  2096. // clip from the items we create after we restore the clip.
  2097. const DisplayItemScrollClip* containerItemScrollClip =
  2098. aBuilder->ClipState().CurrentAncestorScrollClipForStackingContextContents();
  2099. /* If adding both a nsDisplayBlendContainer and a nsDisplayBlendMode to the
  2100. * same list, the nsDisplayBlendContainer should be added first. This only
  2101. * happens when the element creating this stacking context has mix-blend-mode
  2102. * and also contains a child which has mix-blend-mode.
  2103. * The nsDisplayBlendContainer must be added to the list first, so it does not
  2104. * isolate the containing element blending as well.
  2105. */
  2106. if (aBuilder->ContainsBlendMode()) {
  2107. DisplayListClipState::AutoSaveRestore blendContainerClipState(aBuilder);
  2108. blendContainerClipState.Clear();
  2109. resultList.AppendNewToTop(
  2110. nsDisplayBlendContainer::CreateForMixBlendMode(aBuilder, this, &resultList,
  2111. containerItemScrollClip));
  2112. }
  2113. /* If there are any SVG effects, wrap the list up in an SVG effects item
  2114. * (which also handles CSS group opacity). Note that we create an SVG effects
  2115. * item even if resultList is empty, since a filter can produce graphical
  2116. * output even if the element being filtered wouldn't otherwise do so.
  2117. */
  2118. if (usingSVGEffects) {
  2119. MOZ_ASSERT(usingFilter ||usingMask,
  2120. "Beside filter & mask/clip-path, what else effect do we have?");
  2121. if (clipCapturedBy == ContainerItemType::eFilter) {
  2122. clipState.ExitStackingContextContents(&containerItemScrollClip);
  2123. }
  2124. // Revert to the post-filter dirty rect.
  2125. aBuilder->SetDirtyRect(dirtyRectOutsideSVGEffects);
  2126. // Skip all filter effects while generating glyph mask.
  2127. if (usingFilter && !aBuilder->IsForGenerateGlyphMask()) {
  2128. // If we are going to create a mask display item, handle opacity effect
  2129. // in that mask display item; Otherwise, take care of opacity in this
  2130. // filter display item.
  2131. bool handleOpacity = !usingMask && !useOpacity;
  2132. /* List now emptied, so add the new list to the top. */
  2133. resultList.AppendNewToTop(
  2134. new (aBuilder) nsDisplayFilter(aBuilder, this, &resultList,
  2135. handleOpacity));
  2136. }
  2137. if (usingMask) {
  2138. DisplayListClipState::AutoSaveRestore maskClipState(aBuilder);
  2139. maskClipState.Clear();
  2140. /* List now emptied, so add the new list to the top. */
  2141. resultList.AppendNewToTop(
  2142. new (aBuilder) nsDisplayMask(aBuilder, this, &resultList,
  2143. !useOpacity, containerItemScrollClip));
  2144. }
  2145. // Also add the hoisted scroll info items. We need those for APZ scrolling
  2146. // because nsDisplayMask items can't build active layers.
  2147. aBuilder->ExitSVGEffectsContents();
  2148. resultList.AppendToTop(&hoistedScrollInfoItemsStorage);
  2149. }
  2150. /* If the list is non-empty and there is CSS group opacity without SVG
  2151. * effects, wrap it up in an opacity item.
  2152. */
  2153. if (useOpacity && !resultList.IsEmpty()) {
  2154. // Don't clip nsDisplayOpacity items. We clip their descendants instead.
  2155. // The clip we would set on an element with opacity would clip
  2156. // all descendant content, but some should not be clipped.
  2157. DisplayListClipState::AutoSaveRestore opacityClipState(aBuilder);
  2158. opacityClipState.Clear();
  2159. resultList.AppendNewToTop(
  2160. new (aBuilder) nsDisplayOpacity(aBuilder, this, &resultList,
  2161. containerItemScrollClip, opacityItemForEventsAndPluginsOnly));
  2162. }
  2163. /* If we're going to apply a transformation and don't have preserve-3d set, wrap
  2164. * everything in an nsDisplayTransform. If there's nothing in the list, don't add
  2165. * anything.
  2166. *
  2167. * For the preserve-3d case we want to individually wrap every child in the list with
  2168. * a separate nsDisplayTransform instead. When the child is already an nsDisplayTransform,
  2169. * we can skip this step, as the computed transform will already include our own.
  2170. *
  2171. * We also traverse into sublists created by nsDisplayWrapList, so that we find all the
  2172. * correct children.
  2173. */
  2174. if (isTransformed && !resultList.IsEmpty() && extend3DContext) {
  2175. // Install dummy nsDisplayTransform as a leaf containing
  2176. // descendants not participating this 3D rendering context.
  2177. nsDisplayList nonparticipants;
  2178. nsDisplayList participants;
  2179. int index = 1;
  2180. while (nsDisplayItem* item = resultList.RemoveBottom()) {
  2181. if (ItemParticipatesIn3DContext(this, item) && !item->GetClip().HasClip()) {
  2182. // The frame of this item participates the same 3D context.
  2183. WrapSeparatorTransform(aBuilder, this, &nonparticipants, &participants, index++);
  2184. participants.AppendToTop(item);
  2185. } else {
  2186. // The frame of the item doesn't participate the current
  2187. // context, or has no transform.
  2188. //
  2189. // For items participating but not transformed, they are add
  2190. // to nonparticipants to get a separator layer for handling
  2191. // clips, if there is, on an intermediate surface.
  2192. // \see ContainerLayer::DefaultComputeEffectiveTransforms().
  2193. nonparticipants.AppendToTop(item);
  2194. }
  2195. }
  2196. WrapSeparatorTransform(aBuilder, this, &nonparticipants, &participants, index++);
  2197. resultList.AppendToTop(&participants);
  2198. }
  2199. if (isTransformed && !resultList.IsEmpty()) {
  2200. if (clipCapturedBy == ContainerItemType::eTransform) {
  2201. // Restore clip state now so nsDisplayTransform is clipped properly.
  2202. clipState.ExitStackingContextContents(&containerItemScrollClip);
  2203. }
  2204. // Revert to the dirtyrect coming in from the parent, without our transform
  2205. // taken into account.
  2206. aBuilder->SetDirtyRect(dirtyRectOutsideTransform);
  2207. // Revert to the outer reference frame and offset because all display
  2208. // items we create from now on are outside the transform.
  2209. nsPoint toOuterReferenceFrame;
  2210. const nsIFrame* outerReferenceFrame = this;
  2211. if (this != aBuilder->RootReferenceFrame()) {
  2212. outerReferenceFrame =
  2213. aBuilder->FindReferenceFrameFor(GetParent(), &toOuterReferenceFrame);
  2214. }
  2215. buildingDisplayList.SetReferenceFrameAndCurrentOffset(outerReferenceFrame,
  2216. GetOffsetToCrossDoc(outerReferenceFrame));
  2217. bool isFullyVisible =
  2218. dirtyRectOutsideSVGEffects.Contains(GetVisualOverflowRectRelativeToSelf());
  2219. nsDisplayTransform *transformItem =
  2220. new (aBuilder) nsDisplayTransform(aBuilder, this,
  2221. &resultList, dirtyRect, 0,
  2222. isFullyVisible);
  2223. resultList.AppendNewToTop(transformItem);
  2224. if (hasPerspective) {
  2225. if (clipCapturedBy == ContainerItemType::ePerspective) {
  2226. clipState.ExitStackingContextContents(&containerItemScrollClip);
  2227. }
  2228. resultList.AppendNewToTop(
  2229. new (aBuilder) nsDisplayPerspective(
  2230. aBuilder, this,
  2231. GetContainingBlock()->GetContent()->GetPrimaryFrame(), &resultList));
  2232. }
  2233. }
  2234. if (clipCapturedBy == ContainerItemType::eOwnLayerForTransformWithRoundedClip) {
  2235. clipState.ExitStackingContextContents(&containerItemScrollClip);
  2236. resultList.AppendNewToTop(
  2237. new (aBuilder) nsDisplayOwnLayer(aBuilder, this, &resultList, 0,
  2238. mozilla::layers::FrameMetrics::NULL_SCROLL_ID,
  2239. 0.0f, /* aForceActive = */ false));
  2240. }
  2241. /* If we have sticky positioning, wrap it in a sticky position item.
  2242. */
  2243. if (useFixedPosition) {
  2244. if (clipCapturedBy == ContainerItemType::eFixedPosition) {
  2245. clipState.ExitStackingContextContents(&containerItemScrollClip);
  2246. }
  2247. resultList.AppendNewToTop(
  2248. new (aBuilder) nsDisplayFixedPosition(aBuilder, this, &resultList));
  2249. } else if (useStickyPosition) {
  2250. if (clipCapturedBy == ContainerItemType::eStickyPosition) {
  2251. clipState.ExitStackingContextContents(&containerItemScrollClip);
  2252. }
  2253. resultList.AppendNewToTop(
  2254. new (aBuilder) nsDisplayStickyPosition(aBuilder, this, &resultList));
  2255. }
  2256. /* If there's blending, wrap up the list in a blend-mode item. Note
  2257. * that opacity can be applied before blending as the blend color is
  2258. * not affected by foreground opacity (only background alpha).
  2259. */
  2260. if (useBlendMode && !resultList.IsEmpty()) {
  2261. DisplayListClipState::AutoSaveRestore mixBlendClipState(aBuilder);
  2262. mixBlendClipState.Clear();
  2263. resultList.AppendNewToTop(
  2264. new (aBuilder) nsDisplayBlendMode(aBuilder, this, &resultList,
  2265. effects->mMixBlendMode,
  2266. containerItemScrollClip));
  2267. }
  2268. CreateOwnLayerIfNeeded(aBuilder, &resultList);
  2269. aList->AppendToTop(&resultList);
  2270. }
  2271. static nsDisplayItem*
  2272. WrapInWrapList(nsDisplayListBuilder* aBuilder,
  2273. nsIFrame* aFrame, nsDisplayList* aList,
  2274. const DisplayItemScrollClip* aScrollClip)
  2275. {
  2276. nsDisplayItem* item = aList->GetBottom();
  2277. if (!item) {
  2278. return nullptr;
  2279. }
  2280. // For perspective items we want to treat the 'frame' as being the transform
  2281. // frame that created it. This stops the transform frame from wrapping another
  2282. // nsDisplayWrapList around it (with mismatching reference frames), but still
  2283. // makes the perspective frame create one (so we have an atomic entry for z-index
  2284. // sorting).
  2285. nsIFrame *itemFrame = item->Frame();
  2286. if (item->GetType() == nsDisplayItem::TYPE_PERSPECTIVE) {
  2287. itemFrame = static_cast<nsDisplayPerspective*>(item)->TransformFrame();
  2288. }
  2289. if (item->GetAbove() || itemFrame != aFrame) {
  2290. return new (aBuilder) nsDisplayWrapList(aBuilder, aFrame, aList, aScrollClip);
  2291. }
  2292. aList->RemoveBottom();
  2293. return item;
  2294. }
  2295. static bool DescendIntoChild(nsDisplayListBuilder* aBuilder,
  2296. const nsIFrame* aChild, const nsRect& aDirty) {
  2297. if (aChild->GetStateBits() & NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO) {
  2298. return true;
  2299. }
  2300. // If the child is a scrollframe that we want to ignore, then we need
  2301. // to descend into it because its scrolled child may intersect the dirty
  2302. // area even if the scrollframe itself doesn't.
  2303. if (aChild == aBuilder->GetIgnoreScrollFrame()) {
  2304. return true;
  2305. }
  2306. // There are cases where the "ignore scroll frame" on the builder is not set
  2307. // correctly, and so we additionally want to catch cases where the child is
  2308. // a root scrollframe and we are ignoring scrolling on the viewport.
  2309. if (aChild == aBuilder->GetPresShellIgnoreScrollFrame()) {
  2310. return true;
  2311. }
  2312. const nsRect overflow = aChild->GetVisualOverflowRect();
  2313. if (aDirty.Intersects(overflow)) {
  2314. return true;
  2315. }
  2316. if (aChild->IsFrameOfType(nsIFrame::eTablePart)) {
  2317. // Relative positioning and transforms can cause table parts to move, but we
  2318. // will still paint the backgrounds for their ancestor parts under them at
  2319. // their 'normal' position. That means that we must consider the overflow
  2320. // rects at both positions.
  2321. // We convert the overflow rect into the nsTableFrame's coordinate
  2322. // space, applying the normal position offset at each step. Then we
  2323. // compare that against the builder's cached dirty rect in table
  2324. // coordinate space.
  2325. const nsIFrame* f = aChild;
  2326. nsRect normalPositionOverflowRelativeToTable = overflow;
  2327. while (f->IsFrameOfType(nsIFrame::eTablePart)) {
  2328. normalPositionOverflowRelativeToTable += f->GetNormalPosition();
  2329. f = f->GetParent();
  2330. }
  2331. nsDisplayTableBackgroundSet* tableBGs = aBuilder->GetTableBackgroundSet();
  2332. if (tableBGs &&
  2333. tableBGs->GetDirtyRect().Intersects(normalPositionOverflowRelativeToTable)) {
  2334. return true;
  2335. }
  2336. }
  2337. return false;
  2338. }
  2339. void
  2340. nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
  2341. nsIFrame* aChild,
  2342. const nsDisplayListSet& aLists,
  2343. uint32_t aFlags) {
  2344. // If painting is restricted to just the background of the top level frame,
  2345. // then we have nothing to do here.
  2346. if (aBuilder->IsBackgroundOnly())
  2347. return;
  2348. if (aBuilder->IsForGenerateGlyphMask() ||
  2349. aBuilder->IsForPaintingSelectionBG()) {
  2350. if (nsGkAtoms::textFrame != aChild->GetType() && aChild->IsLeaf()) {
  2351. return;
  2352. }
  2353. }
  2354. nsIFrame* child = aChild;
  2355. if (child->GetStateBits() & NS_FRAME_TOO_DEEP_IN_FRAME_TREE)
  2356. return;
  2357. const bool isSVG = child->GetStateBits() & NS_FRAME_SVG_LAYOUT;
  2358. // true if this is a real or pseudo stacking context
  2359. bool pseudoStackingContext =
  2360. (aFlags & DISPLAY_CHILD_FORCE_PSEUDO_STACKING_CONTEXT) != 0;
  2361. if (!pseudoStackingContext &&
  2362. !isSVG &&
  2363. (aFlags & DISPLAY_CHILD_INLINE) &&
  2364. !child->IsFrameOfType(eLineParticipant)) {
  2365. // child is a non-inline frame in an inline context, i.e.,
  2366. // it acts like inline-block or inline-table. Therefore it is a
  2367. // pseudo-stacking-context.
  2368. pseudoStackingContext = true;
  2369. }
  2370. nsIAtom* childType = child->GetType();
  2371. nsDisplayListBuilder::OutOfFlowDisplayData* savedOutOfFlowData = nullptr;
  2372. bool isPlaceholder = false;
  2373. // dirty rect in child-relative coordinates
  2374. NS_ASSERTION(aBuilder->GetCurrentFrame() == this, "Wrong coord space!");
  2375. nsRect dirty = aBuilder->GetDirtyRect() - child->GetOffsetTo(this);
  2376. if (childType == nsGkAtoms::placeholderFrame) {
  2377. isPlaceholder = true;
  2378. nsPlaceholderFrame* placeholder = static_cast<nsPlaceholderFrame*>(child);
  2379. child = placeholder->GetOutOfFlowFrame();
  2380. NS_ASSERTION(child, "No out of flow frame?");
  2381. // If 'child' is a pushed float then it's owned by a block that's not an
  2382. // ancestor of the placeholder, and it will be painted by that block and
  2383. // should not be painted through the placeholder.
  2384. if (!child || nsLayoutUtils::IsPopup(child) ||
  2385. (child->GetStateBits() & NS_FRAME_IS_PUSHED_FLOAT))
  2386. return;
  2387. MOZ_ASSERT(child->GetStateBits() & NS_FRAME_OUT_OF_FLOW);
  2388. // If the out-of-flow frame is in the top layer, the viewport frame
  2389. // will paint it. Skip it here. Note that, only out-of-flow frames
  2390. // with this property should be skipped, because non-HTML elements
  2391. // may stop their children from being out-of-flow. Those frames
  2392. // should still be handled in the normal in-flow path.
  2393. if (placeholder->GetStateBits() & PLACEHOLDER_FOR_TOPLAYER) {
  2394. return;
  2395. }
  2396. // Make sure that any attempt to use childType below is disappointed. We
  2397. // could call GetType again but since we don't currently need it, let's
  2398. // avoid the virtual call.
  2399. childType = nullptr;
  2400. // Recheck NS_FRAME_TOO_DEEP_IN_FRAME_TREE
  2401. if (child->GetStateBits() & NS_FRAME_TOO_DEEP_IN_FRAME_TREE)
  2402. return;
  2403. savedOutOfFlowData = nsDisplayListBuilder::GetOutOfFlowData(child);
  2404. if (savedOutOfFlowData) {
  2405. dirty = savedOutOfFlowData->mDirtyRect;
  2406. } else {
  2407. // The out-of-flow frame did not intersect the dirty area. We may still
  2408. // need to traverse into it, since it may contain placeholders we need
  2409. // to enter to reach other out-of-flow frames that are visible.
  2410. dirty.SetEmpty();
  2411. }
  2412. pseudoStackingContext = true;
  2413. }
  2414. NS_ASSERTION(childType != nsGkAtoms::placeholderFrame,
  2415. "Should have dealt with placeholders already");
  2416. if (aBuilder->GetSelectedFramesOnly() &&
  2417. child->IsLeaf() &&
  2418. !aChild->IsSelected()) {
  2419. return;
  2420. }
  2421. if (aBuilder->GetIncludeAllOutOfFlows() && isPlaceholder) {
  2422. dirty = child->GetVisualOverflowRect();
  2423. } else if (!DescendIntoChild(aBuilder, child, dirty)) {
  2424. return;
  2425. }
  2426. // XXX need to have inline-block and inline-table set pseudoStackingContext
  2427. const nsStyleDisplay* ourDisp = StyleDisplay();
  2428. // REVIEW: Taken from nsBoxFrame::Paint
  2429. // Don't paint our children if the theme object is a leaf.
  2430. if (IsThemed(ourDisp) &&
  2431. !PresContext()->GetTheme()->WidgetIsContainer(ourDisp->mAppearance))
  2432. return;
  2433. // Since we're now sure that we're adding this frame to the display list
  2434. // (which means we're painting it, modulo occlusion), mark it as visible
  2435. // within the displayport.
  2436. if (aBuilder->IsPaintingToWindow() && child->TrackingVisibility()) {
  2437. child->PresContext()->PresShell()->EnsureFrameInApproximatelyVisibleList(child);
  2438. }
  2439. // Child is composited if it's transformed, partially transparent, or has
  2440. // SVG effects or a blend mode..
  2441. const nsStyleDisplay* disp = child->StyleDisplay();
  2442. const nsStyleEffects* effects = child->StyleEffects();
  2443. const nsStylePosition* pos = child->StylePosition();
  2444. const bool isVisuallyAtomic = child->HasOpacity()
  2445. || child->IsTransformed()
  2446. // strictly speaking, 'perspective' doesn't require visual atomicity,
  2447. // but the spec says it acts like the rest of these
  2448. || disp->mChildPerspective.GetUnit() == eStyleUnit_Coord
  2449. || effects->mMixBlendMode != NS_STYLE_BLEND_NORMAL
  2450. || nsSVGIntegrationUtils::UsingEffectsForFrame(child);
  2451. const bool isPositioned = disp->IsAbsPosContainingBlock(child);
  2452. const bool isStackingContext =
  2453. (isPositioned && (disp->IsPositionForcingStackingContext() ||
  2454. pos->mZIndex.GetUnit() == eStyleUnit_Integer)) ||
  2455. (disp->mWillChangeBitField & NS_STYLE_WILL_CHANGE_STACKING_CONTEXT) ||
  2456. disp->mIsolation != NS_STYLE_ISOLATION_AUTO ||
  2457. isVisuallyAtomic || (aFlags & DISPLAY_CHILD_FORCE_STACKING_CONTEXT);
  2458. if (pseudoStackingContext || isStackingContext || isPositioned ||
  2459. (!isSVG && disp->IsFloating(child)) ||
  2460. (isSVG && (effects->mClipFlags & NS_STYLE_CLIP_RECT) &&
  2461. IsSVGContentWithCSSClip(child))) {
  2462. // If you change this, also change IsPseudoStackingContextFromStyle()
  2463. pseudoStackingContext = true;
  2464. }
  2465. NS_ASSERTION(!isStackingContext || pseudoStackingContext,
  2466. "Stacking contexts must also be pseudo-stacking-contexts");
  2467. nsDisplayListBuilder::AutoBuildingDisplayList
  2468. buildingForChild(aBuilder, child, dirty, pseudoStackingContext);
  2469. DisplayListClipState::AutoClipMultiple clipState(aBuilder);
  2470. CheckForApzAwareEventHandlers(aBuilder, child);
  2471. if (savedOutOfFlowData) {
  2472. aBuilder->SetBuildingInvisibleItems(false);
  2473. clipState.SetClipForContainingBlockDescendants(
  2474. &savedOutOfFlowData->mContainingBlockClip);
  2475. clipState.SetScrollClipForContainingBlockDescendants(aBuilder,
  2476. savedOutOfFlowData->mContainingBlockScrollClip);
  2477. } else if (GetStateBits() & NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO &&
  2478. isPlaceholder) {
  2479. NS_ASSERTION(dirty.IsEmpty(), "should have empty visible rect");
  2480. // Every item we build from now until we descent into an out of flow that
  2481. // does have saved out of flow data should be invisible. This state gets
  2482. // restored when AutoBuildingDisplayList gets out of scope.
  2483. aBuilder->SetBuildingInvisibleItems(true);
  2484. // If we have nested out-of-flow frames and the outer one isn't visible
  2485. // then we won't have stored clip data for it. We can just clear the clip
  2486. // instead since we know we won't render anything, and the inner out-of-flow
  2487. // frame will setup the correct clip for itself.
  2488. clipState.SetClipForContainingBlockDescendants(nullptr);
  2489. clipState.SetScrollClipForContainingBlockDescendants(aBuilder, nullptr);
  2490. }
  2491. // Setup clipping for the parent's overflow:-moz-hidden-unscrollable,
  2492. // or overflow:hidden on elements that don't support scrolling (and therefore
  2493. // don't create nsHTML/XULScrollFrame). This clipping needs to not clip
  2494. // anything directly rendered by the parent, only the rendering of its
  2495. // children.
  2496. // Don't use overflowClip to restrict the dirty rect, since some of the
  2497. // descendants may not be clipped by it. Even if we end up with unnecessary
  2498. // display items, they'll be pruned during ComputeVisibility.
  2499. nsIFrame* parent = child->GetParent();
  2500. const nsStyleDisplay* parentDisp =
  2501. parent == this ? ourDisp : parent->StyleDisplay();
  2502. ApplyOverflowClipping(aBuilder, parent, parentDisp, clipState);
  2503. nsDisplayList list;
  2504. nsDisplayList extraPositionedDescendants;
  2505. if (isStackingContext) {
  2506. if (effects->mMixBlendMode != NS_STYLE_BLEND_NORMAL) {
  2507. aBuilder->SetContainsBlendMode(true);
  2508. }
  2509. // True stacking context.
  2510. // For stacking contexts, BuildDisplayListForStackingContext handles
  2511. // clipping and MarkAbsoluteFramesForDisplayList.
  2512. child->BuildDisplayListForStackingContext(aBuilder, &list);
  2513. aBuilder->DisplayCaret(child, &list);
  2514. } else {
  2515. Maybe<nsRect> clipPropClip =
  2516. child->GetClipPropClipRect(disp, effects, child->GetSize());
  2517. if (clipPropClip) {
  2518. aBuilder->IntersectDirtyRect(*clipPropClip);
  2519. clipState.ClipContentDescendants(
  2520. *clipPropClip + aBuilder->ToReferenceFrame(child));
  2521. }
  2522. child->MarkAbsoluteFramesForDisplayList(aBuilder);
  2523. if (aBuilder->IsBuildingLayerEventRegions()) {
  2524. // If this frame has a different animated geometry root than its parent,
  2525. // make sure we accumulate event regions for its layer.
  2526. if (buildingForChild.IsAnimatedGeometryRoot() || isPositioned) {
  2527. nsDisplayLayerEventRegions* eventRegions =
  2528. new (aBuilder) nsDisplayLayerEventRegions(aBuilder, child);
  2529. eventRegions->AddFrame(aBuilder, child);
  2530. aBuilder->SetLayerEventRegions(eventRegions);
  2531. if (isPositioned) {
  2532. // We need this nsDisplayLayerEventRegions to be sorted with the positioned
  2533. // elements as positioned elements will be sorted on top of normal elements
  2534. list.AppendNewToTop(eventRegions);
  2535. } else {
  2536. aLists.BorderBackground()->AppendNewToTop(eventRegions);
  2537. }
  2538. } else {
  2539. nsDisplayLayerEventRegions* eventRegions = aBuilder->GetLayerEventRegions();
  2540. if (eventRegions) {
  2541. eventRegions->AddFrame(aBuilder, child);
  2542. }
  2543. }
  2544. }
  2545. if (!pseudoStackingContext) {
  2546. // THIS IS THE COMMON CASE.
  2547. // Not a pseudo or real stacking context. Do the simple thing and
  2548. // return early.
  2549. aBuilder->AdjustWindowDraggingRegion(child);
  2550. child->BuildDisplayList(aBuilder, aLists);
  2551. aBuilder->DisplayCaret(child, aLists.Content());
  2552. #ifdef DEBUG
  2553. DisplayDebugBorders(aBuilder, child, aLists);
  2554. #endif
  2555. return;
  2556. }
  2557. // A pseudo-stacking context (e.g., a positioned element with z-index auto).
  2558. // We allow positioned descendants of the child to escape to our parent
  2559. // stacking context's positioned descendant list, because they might be
  2560. // z-index:non-auto
  2561. nsDisplayListCollection pseudoStack(aBuilder);
  2562. aBuilder->AdjustWindowDraggingRegion(child);
  2563. child->BuildDisplayList(aBuilder, pseudoStack);
  2564. aBuilder->DisplayCaret(child, pseudoStack.Content());
  2565. list.AppendToTop(pseudoStack.BorderBackground());
  2566. list.AppendToTop(pseudoStack.BlockBorderBackgrounds());
  2567. list.AppendToTop(pseudoStack.Floats());
  2568. list.AppendToTop(pseudoStack.Content());
  2569. list.AppendToTop(pseudoStack.Outlines());
  2570. extraPositionedDescendants.AppendToTop(pseudoStack.PositionedDescendants());
  2571. #ifdef DEBUG
  2572. DisplayDebugBorders(aBuilder, child, aLists);
  2573. #endif
  2574. }
  2575. buildingForChild.RestoreBuildingInvisibleItemsValue();
  2576. // Clear clip rect for the construction of the items below. Since we're
  2577. // clipping all their contents, they themselves don't need to be clipped.
  2578. clipState.Clear();
  2579. const DisplayItemScrollClip* containerItemScrollClip =
  2580. aBuilder->ClipState().CurrentAncestorScrollClipForStackingContextContents();
  2581. if (isPositioned || isVisuallyAtomic ||
  2582. (aFlags & DISPLAY_CHILD_FORCE_STACKING_CONTEXT)) {
  2583. // Genuine stacking contexts, and positioned pseudo-stacking-contexts,
  2584. // go in this level.
  2585. if (!list.IsEmpty()) {
  2586. nsDisplayItem* item = WrapInWrapList(aBuilder, child, &list, containerItemScrollClip);
  2587. if (isSVG) {
  2588. aLists.Content()->AppendNewToTop(item);
  2589. } else {
  2590. aLists.PositionedDescendants()->AppendNewToTop(item);
  2591. }
  2592. }
  2593. } else if (!isSVG && disp->IsFloating(child)) {
  2594. if (!list.IsEmpty()) {
  2595. aLists.Floats()->AppendNewToTop(WrapInWrapList(aBuilder, child, &list, containerItemScrollClip));
  2596. }
  2597. } else {
  2598. aLists.Content()->AppendToTop(&list);
  2599. }
  2600. // We delay placing the positioned descendants of positioned frames to here,
  2601. // because in the absence of z-index this is the correct order for them.
  2602. // This doesn't affect correctness because the positioned descendants list
  2603. // is sorted by z-order and content in BuildDisplayListForStackingContext,
  2604. // but it means that sort routine needs to do less work.
  2605. aLists.PositionedDescendants()->AppendToTop(&extraPositionedDescendants);
  2606. }
  2607. void
  2608. nsIFrame::MarkAbsoluteFramesForDisplayList(nsDisplayListBuilder* aBuilder)
  2609. {
  2610. if (IsAbsoluteContainer()) {
  2611. aBuilder->MarkFramesForDisplayList(this, GetAbsoluteContainingBlock()->GetChildList());
  2612. }
  2613. }
  2614. nsresult
  2615. nsFrame::GetContentForEvent(WidgetEvent* aEvent,
  2616. nsIContent** aContent)
  2617. {
  2618. nsIFrame* f = nsLayoutUtils::GetNonGeneratedAncestor(this);
  2619. *aContent = f->GetContent();
  2620. NS_IF_ADDREF(*aContent);
  2621. return NS_OK;
  2622. }
  2623. void
  2624. nsFrame::FireDOMEvent(const nsAString& aDOMEventName, nsIContent *aContent)
  2625. {
  2626. nsIContent* target = aContent ? aContent : mContent;
  2627. if (target) {
  2628. RefPtr<AsyncEventDispatcher> asyncDispatcher =
  2629. new AsyncEventDispatcher(target, aDOMEventName, true, false);
  2630. DebugOnly<nsresult> rv = asyncDispatcher->PostDOMEvent();
  2631. NS_ASSERTION(NS_SUCCEEDED(rv), "AsyncEventDispatcher failed to dispatch");
  2632. }
  2633. }
  2634. nsresult
  2635. nsFrame::HandleEvent(nsPresContext* aPresContext,
  2636. WidgetGUIEvent* aEvent,
  2637. nsEventStatus* aEventStatus)
  2638. {
  2639. if (aEvent->mMessage == eMouseMove) {
  2640. // XXX If the second argument of HandleDrag() is WidgetMouseEvent,
  2641. // the implementation becomes simpler.
  2642. return HandleDrag(aPresContext, aEvent, aEventStatus);
  2643. }
  2644. if ((aEvent->mClass == eMouseEventClass &&
  2645. aEvent->AsMouseEvent()->button == WidgetMouseEvent::eLeftButton) ||
  2646. aEvent->mClass == eTouchEventClass) {
  2647. if (aEvent->mMessage == eMouseDown || aEvent->mMessage == eTouchStart) {
  2648. HandlePress(aPresContext, aEvent, aEventStatus);
  2649. } else if (aEvent->mMessage == eMouseUp || aEvent->mMessage == eTouchEnd) {
  2650. HandleRelease(aPresContext, aEvent, aEventStatus);
  2651. }
  2652. }
  2653. return NS_OK;
  2654. }
  2655. NS_IMETHODIMP
  2656. nsFrame::GetDataForTableSelection(const nsFrameSelection* aFrameSelection,
  2657. nsIPresShell* aPresShell,
  2658. WidgetMouseEvent* aMouseEvent,
  2659. nsIContent** aParentContent,
  2660. int32_t* aContentOffset,
  2661. int32_t* aTarget)
  2662. {
  2663. if (!aFrameSelection || !aPresShell || !aMouseEvent || !aParentContent || !aContentOffset || !aTarget)
  2664. return NS_ERROR_NULL_POINTER;
  2665. *aParentContent = nullptr;
  2666. *aContentOffset = 0;
  2667. *aTarget = 0;
  2668. int16_t displaySelection = aPresShell->GetSelectionFlags();
  2669. bool selectingTableCells = aFrameSelection->GetTableCellSelection();
  2670. // DISPLAY_ALL means we're in an editor.
  2671. // If already in cell selection mode,
  2672. // continue selecting with mouse drag or end on mouse up,
  2673. // or when using shift key to extend block of cells
  2674. // (Mouse down does normal selection unless Ctrl/Cmd is pressed)
  2675. bool doTableSelection =
  2676. displaySelection == nsISelectionDisplay::DISPLAY_ALL && selectingTableCells &&
  2677. (aMouseEvent->mMessage == eMouseMove ||
  2678. (aMouseEvent->mMessage == eMouseUp &&
  2679. aMouseEvent->button == WidgetMouseEvent::eLeftButton) ||
  2680. aMouseEvent->IsShift());
  2681. if (!doTableSelection)
  2682. {
  2683. // In Browser, special 'table selection' key must be pressed for table selection
  2684. // or when just Shift is pressed and we're already in table/cell selection mode
  2685. doTableSelection = aMouseEvent->IsControl() || (aMouseEvent->IsShift() && selectingTableCells);
  2686. }
  2687. if (!doTableSelection)
  2688. return NS_OK;
  2689. // Get the cell frame or table frame (or parent) of the current content node
  2690. nsIFrame *frame = this;
  2691. bool foundCell = false;
  2692. bool foundTable = false;
  2693. // Get the limiting node to stop parent frame search
  2694. nsIContent* limiter = aFrameSelection->GetLimiter();
  2695. // If our content node is an ancestor of the limiting node,
  2696. // we should stop the search right now.
  2697. if (limiter && nsContentUtils::ContentIsDescendantOf(limiter, GetContent()))
  2698. return NS_OK;
  2699. //We don't initiate row/col selection from here now,
  2700. // but we may in future
  2701. //bool selectColumn = false;
  2702. //bool selectRow = false;
  2703. while (frame)
  2704. {
  2705. // Check for a table cell by querying to a known CellFrame interface
  2706. nsITableCellLayout *cellElement = do_QueryFrame(frame);
  2707. if (cellElement)
  2708. {
  2709. foundCell = true;
  2710. //TODO: If we want to use proximity to top or left border
  2711. // for row and column selection, this is the place to do it
  2712. break;
  2713. }
  2714. else
  2715. {
  2716. // If not a cell, check for table
  2717. // This will happen when starting frame is the table or child of a table,
  2718. // such as a row (we were inbetween cells or in table border)
  2719. nsTableWrapperFrame *tableFrame = do_QueryFrame(frame);
  2720. if (tableFrame)
  2721. {
  2722. foundTable = true;
  2723. //TODO: How can we select row when along left table edge
  2724. // or select column when along top edge?
  2725. break;
  2726. } else {
  2727. frame = frame->GetParent();
  2728. // Stop if we have hit the selection's limiting content node
  2729. if (frame && frame->GetContent() == limiter)
  2730. break;
  2731. }
  2732. }
  2733. }
  2734. // We aren't in a cell or table
  2735. if (!foundCell && !foundTable) return NS_OK;
  2736. nsIContent* tableOrCellContent = frame->GetContent();
  2737. if (!tableOrCellContent) return NS_ERROR_FAILURE;
  2738. nsCOMPtr<nsIContent> parentContent = tableOrCellContent->GetParent();
  2739. if (!parentContent) return NS_ERROR_FAILURE;
  2740. int32_t offset = parentContent->IndexOf(tableOrCellContent);
  2741. // Not likely?
  2742. if (offset < 0) return NS_ERROR_FAILURE;
  2743. // Everything is OK -- set the return values
  2744. parentContent.forget(aParentContent);
  2745. *aContentOffset = offset;
  2746. #if 0
  2747. if (selectRow)
  2748. *aTarget = nsISelectionPrivate::TABLESELECTION_ROW;
  2749. else if (selectColumn)
  2750. *aTarget = nsISelectionPrivate::TABLESELECTION_COLUMN;
  2751. else
  2752. #endif
  2753. if (foundCell)
  2754. *aTarget = nsISelectionPrivate::TABLESELECTION_CELL;
  2755. else if (foundTable)
  2756. *aTarget = nsISelectionPrivate::TABLESELECTION_TABLE;
  2757. return NS_OK;
  2758. }
  2759. nsresult
  2760. nsFrame::IsSelectable(bool* aSelectable, StyleUserSelect* aSelectStyle) const
  2761. {
  2762. if (!aSelectable) //it's ok if aSelectStyle is null
  2763. return NS_ERROR_NULL_POINTER;
  2764. // Like 'visibility', we must check all the parents: if a parent
  2765. // is not selectable, none of its children is selectable.
  2766. //
  2767. // The -moz-all value acts similarly: if a frame has 'user-select:-moz-all',
  2768. // all its children are selectable, even those with 'user-select:none'.
  2769. //
  2770. // As a result, if 'none' and '-moz-all' are not present in the frame hierarchy,
  2771. // aSelectStyle returns the first style that is not AUTO. If these values
  2772. // are present in the frame hierarchy, aSelectStyle returns the style of the
  2773. // topmost parent that has either 'none' or '-moz-all'.
  2774. //
  2775. // The -moz-text value acts as a way to override an ancestor's all/-moz-all value.
  2776. //
  2777. // For instance, if the frame hierarchy is:
  2778. // AUTO -> _MOZ_ALL -> NONE -> TEXT, the returned value is ALL
  2779. // AUTO -> _MOZ_ALL -> NONE -> _MOZ_TEXT, the returned value is TEXT.
  2780. // TEXT -> NONE -> AUTO -> _MOZ_ALL, the returned value is TEXT
  2781. // _MOZ_ALL -> TEXT -> AUTO -> AUTO, the returned value is ALL
  2782. // _MOZ_ALL -> _MOZ_TEXT -> AUTO -> AUTO, the returned value is TEXT.
  2783. // AUTO -> CELL -> TEXT -> AUTO, the returned value is TEXT
  2784. //
  2785. StyleUserSelect selectStyle = StyleUserSelect::Auto;
  2786. nsIFrame* frame = const_cast<nsFrame*>(this);
  2787. bool containsEditable = false;
  2788. while (frame) {
  2789. const nsStyleUIReset* userinterface = frame->StyleUIReset();
  2790. switch (userinterface->mUserSelect) {
  2791. case StyleUserSelect::All:
  2792. case StyleUserSelect::MozAll:
  2793. {
  2794. // override the previous values
  2795. if (selectStyle != StyleUserSelect::MozText) {
  2796. selectStyle = userinterface->mUserSelect;
  2797. }
  2798. nsIContent* frameContent = frame->GetContent();
  2799. containsEditable = frameContent &&
  2800. frameContent->EditableDescendantCount() > 0;
  2801. break;
  2802. }
  2803. default:
  2804. // otherwise return the first value which is not 'auto'
  2805. if (selectStyle == StyleUserSelect::Auto) {
  2806. selectStyle = userinterface->mUserSelect;
  2807. }
  2808. break;
  2809. }
  2810. frame = nsLayoutUtils::GetParentOrPlaceholderFor(frame);
  2811. }
  2812. // convert internal values to standard values
  2813. if (selectStyle == StyleUserSelect::Auto ||
  2814. selectStyle == StyleUserSelect::MozText) {
  2815. selectStyle = StyleUserSelect::Text;
  2816. } else if (selectStyle == StyleUserSelect::MozAll) {
  2817. selectStyle = StyleUserSelect::All;
  2818. }
  2819. // If user tries to select all of a non-editable content,
  2820. // prevent selection if it contains editable content.
  2821. bool allowSelection = true;
  2822. if (selectStyle == StyleUserSelect::All) {
  2823. allowSelection = !containsEditable;
  2824. }
  2825. // return stuff
  2826. if (aSelectStyle) {
  2827. *aSelectStyle = selectStyle;
  2828. }
  2829. if (mState & NS_FRAME_GENERATED_CONTENT) {
  2830. *aSelectable = false;
  2831. } else {
  2832. *aSelectable = allowSelection && (selectStyle != StyleUserSelect::None);
  2833. }
  2834. return NS_OK;
  2835. }
  2836. /**
  2837. * Handles the Mouse Press Event for the frame
  2838. */
  2839. NS_IMETHODIMP
  2840. nsFrame::HandlePress(nsPresContext* aPresContext,
  2841. WidgetGUIEvent* aEvent,
  2842. nsEventStatus* aEventStatus)
  2843. {
  2844. NS_ENSURE_ARG_POINTER(aEventStatus);
  2845. if (nsEventStatus_eConsumeNoDefault == *aEventStatus) {
  2846. return NS_OK;
  2847. }
  2848. NS_ENSURE_ARG_POINTER(aEvent);
  2849. if (aEvent->mClass == eTouchEventClass) {
  2850. return NS_OK;
  2851. }
  2852. //We often get out of sync state issues with mousedown events that
  2853. //get interrupted by alerts/dialogs.
  2854. //Check with the ESM to see if we should process this one
  2855. if (!aPresContext->EventStateManager()->EventStatusOK(aEvent))
  2856. return NS_OK;
  2857. nsresult rv;
  2858. nsIPresShell *shell = aPresContext->GetPresShell();
  2859. if (!shell)
  2860. return NS_ERROR_FAILURE;
  2861. // if we are in Navigator and the click is in a draggable node, we don't want
  2862. // to start selection because we don't want to interfere with a potential
  2863. // drag of said node and steal all its glory.
  2864. int16_t isEditor = shell->GetSelectionFlags();
  2865. //weaaak. only the editor can display frame selection not just text and images
  2866. isEditor = isEditor == nsISelectionDisplay::DISPLAY_ALL;
  2867. WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
  2868. if (!mouseEvent->IsAlt()) {
  2869. for (nsIContent* content = mContent; content;
  2870. content = content->GetParent()) {
  2871. if (nsContentUtils::ContentIsDraggable(content) &&
  2872. !content->IsEditable()) {
  2873. // coordinate stuff is the fix for bug #55921
  2874. if ((mRect - GetPosition()).Contains(
  2875. nsLayoutUtils::GetEventCoordinatesRelativeTo(mouseEvent, this))) {
  2876. return NS_OK;
  2877. }
  2878. }
  2879. }
  2880. }
  2881. // check whether style allows selection
  2882. // if not, don't tell selection the mouse event even occurred.
  2883. bool selectable;
  2884. StyleUserSelect selectStyle;
  2885. rv = IsSelectable(&selectable, &selectStyle);
  2886. if (NS_FAILED(rv)) return rv;
  2887. // check for select: none
  2888. if (!selectable)
  2889. return NS_OK;
  2890. // When implementing StyleUserSelect::Element, StyleUserSelect::Elements and
  2891. // StyleUserSelect::Toggle, need to change this logic
  2892. bool useFrameSelection = (selectStyle == StyleUserSelect::Text);
  2893. // If the mouse is dragged outside the nearest enclosing scrollable area
  2894. // while making a selection, the area will be scrolled. To do this, capture
  2895. // the mouse on the nearest scrollable frame. If there isn't a scrollable
  2896. // frame, or something else is already capturing the mouse, there's no
  2897. // reason to capture.
  2898. bool hasCapturedContent = false;
  2899. if (!nsIPresShell::GetCapturingContent()) {
  2900. nsIScrollableFrame* scrollFrame =
  2901. nsLayoutUtils::GetNearestScrollableFrame(this,
  2902. nsLayoutUtils::SCROLLABLE_SAME_DOC |
  2903. nsLayoutUtils::SCROLLABLE_INCLUDE_HIDDEN);
  2904. if (scrollFrame) {
  2905. nsIFrame* capturingFrame = do_QueryFrame(scrollFrame);
  2906. nsIPresShell::SetCapturingContent(capturingFrame->GetContent(),
  2907. CAPTURE_IGNOREALLOWED);
  2908. hasCapturedContent = true;
  2909. }
  2910. }
  2911. // XXX This is screwy; it really should use the selection frame, not the
  2912. // event frame
  2913. const nsFrameSelection* frameselection = nullptr;
  2914. if (useFrameSelection)
  2915. frameselection = GetConstFrameSelection();
  2916. else
  2917. frameselection = shell->ConstFrameSelection();
  2918. if (!frameselection || frameselection->GetDisplaySelection() == nsISelectionController::SELECTION_OFF)
  2919. return NS_OK;//nothing to do we cannot affect selection from here
  2920. bool control = mouseEvent->IsControl();
  2921. RefPtr<nsFrameSelection> fc = const_cast<nsFrameSelection*>(frameselection);
  2922. if (mouseEvent->mClickCount > 1) {
  2923. // These methods aren't const but can't actually delete anything,
  2924. // so no need for nsWeakFrame.
  2925. fc->SetDragState(true);
  2926. fc->SetMouseDoubleDown(true);
  2927. return HandleMultiplePress(aPresContext, mouseEvent, aEventStatus, control);
  2928. }
  2929. nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(mouseEvent, this);
  2930. ContentOffsets offsets = GetContentOffsetsFromPoint(pt, SKIP_HIDDEN);
  2931. if (!offsets.content)
  2932. return NS_ERROR_FAILURE;
  2933. // On touchables devices, touch the screen is usually a pan action,
  2934. // so let's reposition the caret if needed but do not select text
  2935. // if the touch did not happen over an editable element. Otherwise,
  2936. // let the user move the caret by tapping and dragging.
  2937. if (!offsets.content->IsEditable() &&
  2938. Preferences::GetBool("browser.ignoreNativeFrameTextSelection", false)) {
  2939. // On touchables devices, mouse events are generated if the gesture is a tap.
  2940. // Such events are never going to generate a drag action, so let's release
  2941. // captured content if any.
  2942. if (hasCapturedContent) {
  2943. nsIPresShell::SetCapturingContent(nullptr, 0);
  2944. }
  2945. return fc->HandleClick(offsets.content, offsets.StartOffset(),
  2946. offsets.EndOffset(), false, false,
  2947. offsets.associate);
  2948. }
  2949. // Let Ctrl/Cmd+mouse down do table selection instead of drag initiation
  2950. nsCOMPtr<nsIContent>parentContent;
  2951. int32_t contentOffset;
  2952. int32_t target;
  2953. rv = GetDataForTableSelection(frameselection, shell, mouseEvent,
  2954. getter_AddRefs(parentContent), &contentOffset,
  2955. &target);
  2956. if (NS_SUCCEEDED(rv) && parentContent)
  2957. {
  2958. fc->SetDragState(true);
  2959. return fc->HandleTableSelection(parentContent, contentOffset, target,
  2960. mouseEvent);
  2961. }
  2962. fc->SetDelayedCaretData(0);
  2963. // Check if any part of this frame is selected, and if the
  2964. // user clicked inside the selected region. If so, we delay
  2965. // starting a new selection since the user may be trying to
  2966. // drag the selected region to some other app.
  2967. SelectionDetails *details = 0;
  2968. if (GetContent()->IsSelectionDescendant())
  2969. {
  2970. bool inSelection = false;
  2971. details = frameselection->LookUpSelection(offsets.content, 0,
  2972. offsets.EndOffset(), false);
  2973. //
  2974. // If there are any details, check to see if the user clicked
  2975. // within any selected region of the frame.
  2976. //
  2977. SelectionDetails *curDetail = details;
  2978. while (curDetail)
  2979. {
  2980. //
  2981. // If the user clicked inside a selection, then just
  2982. // return without doing anything. We will handle placing
  2983. // the caret later on when the mouse is released. We ignore
  2984. // the spellcheck, find and url formatting selections.
  2985. //
  2986. if (curDetail->mSelectionType != SelectionType::eSpellCheck &&
  2987. curDetail->mSelectionType != SelectionType::eFind &&
  2988. curDetail->mSelectionType != SelectionType::eURLSecondary &&
  2989. curDetail->mSelectionType != SelectionType::eURLStrikeout &&
  2990. curDetail->mStart <= offsets.StartOffset() &&
  2991. offsets.EndOffset() <= curDetail->mEnd)
  2992. {
  2993. inSelection = true;
  2994. }
  2995. SelectionDetails *nextDetail = curDetail->mNext;
  2996. delete curDetail;
  2997. curDetail = nextDetail;
  2998. }
  2999. if (inSelection) {
  3000. fc->SetDragState(false);
  3001. fc->SetDelayedCaretData(mouseEvent);
  3002. return NS_OK;
  3003. }
  3004. }
  3005. fc->SetDragState(true);
  3006. // Do not touch any nsFrame members after this point without adding
  3007. // weakFrame checks.
  3008. rv = fc->HandleClick(offsets.content, offsets.StartOffset(),
  3009. offsets.EndOffset(), mouseEvent->IsShift(), control,
  3010. offsets.associate);
  3011. if (NS_FAILED(rv))
  3012. return rv;
  3013. if (offsets.offset != offsets.secondaryOffset)
  3014. fc->MaintainSelection();
  3015. if (isEditor && !mouseEvent->IsShift() &&
  3016. (offsets.EndOffset() - offsets.StartOffset()) == 1)
  3017. {
  3018. // A single node is selected and we aren't extending an existing
  3019. // selection, which means the user clicked directly on an object (either
  3020. // -moz-user-select: all or a non-text node without children).
  3021. // Therefore, disable selection extension during mouse moves.
  3022. // XXX This is a bit hacky; shouldn't editor be able to deal with this?
  3023. fc->SetDragState(false);
  3024. }
  3025. return rv;
  3026. }
  3027. /*
  3028. * SelectByTypeAtPoint
  3029. *
  3030. * Search for selectable content at point and attempt to select
  3031. * based on the start and end selection behaviours.
  3032. *
  3033. * @param aPresContext Presentation context
  3034. * @param aPoint Point at which selection will occur. Coordinates
  3035. * should be relaitve to this frame.
  3036. * @param aBeginAmountType, aEndAmountType Selection behavior, see
  3037. * nsIFrame for definitions.
  3038. * @param aSelectFlags Selection flags defined in nsFame.h.
  3039. * @return success or failure at finding suitable content to select.
  3040. */
  3041. nsresult
  3042. nsFrame::SelectByTypeAtPoint(nsPresContext* aPresContext,
  3043. const nsPoint& aPoint,
  3044. nsSelectionAmount aBeginAmountType,
  3045. nsSelectionAmount aEndAmountType,
  3046. uint32_t aSelectFlags)
  3047. {
  3048. NS_ENSURE_ARG_POINTER(aPresContext);
  3049. // No point in selecting if selection is turned off
  3050. if (DisplaySelection(aPresContext) == nsISelectionController::SELECTION_OFF)
  3051. return NS_OK;
  3052. ContentOffsets offsets = GetContentOffsetsFromPoint(aPoint, SKIP_HIDDEN);
  3053. if (!offsets.content)
  3054. return NS_ERROR_FAILURE;
  3055. int32_t offset;
  3056. const nsFrameSelection* frameSelection =
  3057. PresContext()->GetPresShell()->ConstFrameSelection();
  3058. nsIFrame* theFrame = frameSelection->
  3059. GetFrameForNodeOffset(offsets.content, offsets.offset,
  3060. offsets.associate, &offset);
  3061. if (!theFrame)
  3062. return NS_ERROR_FAILURE;
  3063. nsFrame* frame = static_cast<nsFrame*>(theFrame);
  3064. return frame->PeekBackwardAndForward(aBeginAmountType, aEndAmountType, offset,
  3065. aBeginAmountType != eSelectWord,
  3066. aSelectFlags);
  3067. }
  3068. /**
  3069. * Multiple Mouse Press -- line or paragraph selection -- for the frame.
  3070. * Wouldn't it be nice if this didn't have to be hardwired into Frame code?
  3071. */
  3072. NS_IMETHODIMP
  3073. nsFrame::HandleMultiplePress(nsPresContext* aPresContext,
  3074. WidgetGUIEvent* aEvent,
  3075. nsEventStatus* aEventStatus,
  3076. bool aControlHeld)
  3077. {
  3078. NS_ENSURE_ARG_POINTER(aEvent);
  3079. NS_ENSURE_ARG_POINTER(aEventStatus);
  3080. if (nsEventStatus_eConsumeNoDefault == *aEventStatus ||
  3081. DisplaySelection(aPresContext) == nsISelectionController::SELECTION_OFF) {
  3082. return NS_OK;
  3083. }
  3084. // Find out whether we're doing line or paragraph selection.
  3085. // If browser.triple_click_selects_paragraph is true, triple-click selects paragraph.
  3086. // Otherwise, triple-click selects line, and quadruple-click selects paragraph
  3087. // (on platforms that support quadruple-click).
  3088. nsSelectionAmount beginAmount, endAmount;
  3089. WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
  3090. if (!mouseEvent) {
  3091. return NS_OK;
  3092. }
  3093. if (mouseEvent->mClickCount == 4) {
  3094. beginAmount = endAmount = eSelectParagraph;
  3095. } else if (mouseEvent->mClickCount == 3) {
  3096. if (Preferences::GetBool("browser.triple_click_selects_paragraph")) {
  3097. beginAmount = endAmount = eSelectParagraph;
  3098. } else {
  3099. beginAmount = eSelectBeginLine;
  3100. endAmount = eSelectEndLine;
  3101. }
  3102. } else if (mouseEvent->mClickCount == 2) {
  3103. // We only want inline frames; PeekBackwardAndForward dislikes blocks
  3104. beginAmount = endAmount = eSelectWord;
  3105. } else {
  3106. return NS_OK;
  3107. }
  3108. nsPoint relPoint =
  3109. nsLayoutUtils::GetEventCoordinatesRelativeTo(mouseEvent, this);
  3110. return SelectByTypeAtPoint(aPresContext, relPoint, beginAmount, endAmount,
  3111. (aControlHeld ? SELECT_ACCUMULATE : 0));
  3112. }
  3113. nsresult
  3114. nsFrame::PeekBackwardAndForward(nsSelectionAmount aAmountBack,
  3115. nsSelectionAmount aAmountForward,
  3116. int32_t aStartPos,
  3117. bool aJumpLines,
  3118. uint32_t aSelectFlags)
  3119. {
  3120. nsIFrame* baseFrame = this;
  3121. int32_t baseOffset = aStartPos;
  3122. nsresult rv;
  3123. if (aAmountBack == eSelectWord) {
  3124. // To avoid selecting the previous word when at start of word,
  3125. // first move one character forward.
  3126. nsPeekOffsetStruct pos(eSelectCharacter,
  3127. eDirNext,
  3128. aStartPos,
  3129. nsPoint(0, 0),
  3130. aJumpLines,
  3131. true, //limit on scrolled views
  3132. false,
  3133. false,
  3134. false);
  3135. rv = PeekOffset(&pos);
  3136. if (NS_SUCCEEDED(rv)) {
  3137. baseFrame = pos.mResultFrame;
  3138. baseOffset = pos.mContentOffset;
  3139. }
  3140. }
  3141. // Use peek offset one way then the other:
  3142. nsPeekOffsetStruct startpos(aAmountBack,
  3143. eDirPrevious,
  3144. baseOffset,
  3145. nsPoint(0, 0),
  3146. aJumpLines,
  3147. true, //limit on scrolled views
  3148. false,
  3149. false,
  3150. false);
  3151. rv = baseFrame->PeekOffset(&startpos);
  3152. if (NS_FAILED(rv))
  3153. return rv;
  3154. nsPeekOffsetStruct endpos(aAmountForward,
  3155. eDirNext,
  3156. aStartPos,
  3157. nsPoint(0, 0),
  3158. aJumpLines,
  3159. true, //limit on scrolled views
  3160. false,
  3161. false,
  3162. false);
  3163. rv = PeekOffset(&endpos);
  3164. if (NS_FAILED(rv))
  3165. return rv;
  3166. // Keep frameSelection alive.
  3167. RefPtr<nsFrameSelection> frameSelection = GetFrameSelection();
  3168. rv = frameSelection->HandleClick(startpos.mResultContent,
  3169. startpos.mContentOffset, startpos.mContentOffset,
  3170. false, (aSelectFlags & SELECT_ACCUMULATE),
  3171. CARET_ASSOCIATE_AFTER);
  3172. if (NS_FAILED(rv))
  3173. return rv;
  3174. rv = frameSelection->HandleClick(endpos.mResultContent,
  3175. endpos.mContentOffset, endpos.mContentOffset,
  3176. true, false,
  3177. CARET_ASSOCIATE_BEFORE);
  3178. if (NS_FAILED(rv))
  3179. return rv;
  3180. // maintain selection
  3181. return frameSelection->MaintainSelection(aAmountBack);
  3182. }
  3183. NS_IMETHODIMP nsFrame::HandleDrag(nsPresContext* aPresContext,
  3184. WidgetGUIEvent* aEvent,
  3185. nsEventStatus* aEventStatus)
  3186. {
  3187. MOZ_ASSERT(aEvent->mClass == eMouseEventClass,
  3188. "HandleDrag can only handle mouse event");
  3189. RefPtr<nsFrameSelection> frameselection = GetFrameSelection();
  3190. bool mouseDown = frameselection->GetDragState();
  3191. if (!mouseDown) {
  3192. return NS_OK;
  3193. }
  3194. nsIFrame* scrollbar =
  3195. nsLayoutUtils::GetClosestFrameOfType(this, nsGkAtoms::scrollbarFrame);
  3196. if (!scrollbar) {
  3197. // XXX Do we really need to exclude non-selectable content here?
  3198. // GetContentOffsetsFromPoint can handle it just fine, although some
  3199. // other stuff might not like it.
  3200. // NOTE: DisplaySelection() returns SELECTION_OFF for non-selectable frames.
  3201. if (DisplaySelection(aPresContext) == nsISelectionController::SELECTION_OFF) {
  3202. return NS_OK;
  3203. }
  3204. }
  3205. frameselection->StopAutoScrollTimer();
  3206. // Check if we are dragging in a table cell
  3207. nsCOMPtr<nsIContent> parentContent;
  3208. int32_t contentOffset;
  3209. int32_t target;
  3210. WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
  3211. nsCOMPtr<nsIPresShell> presShell = aPresContext->PresShell();
  3212. nsresult result;
  3213. result = GetDataForTableSelection(frameselection, presShell, mouseEvent,
  3214. getter_AddRefs(parentContent),
  3215. &contentOffset, &target);
  3216. nsWeakFrame weakThis = this;
  3217. if (NS_SUCCEEDED(result) && parentContent) {
  3218. frameselection->HandleTableSelection(parentContent, contentOffset, target,
  3219. mouseEvent);
  3220. } else {
  3221. nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(mouseEvent, this);
  3222. frameselection->HandleDrag(this, pt);
  3223. }
  3224. // The frameselection object notifies selection listeners synchronously above
  3225. // which might have killed us.
  3226. if (!weakThis.IsAlive()) {
  3227. return NS_OK;
  3228. }
  3229. // get the nearest scrollframe
  3230. nsIScrollableFrame* scrollFrame =
  3231. nsLayoutUtils::GetNearestScrollableFrame(this,
  3232. nsLayoutUtils::SCROLLABLE_SAME_DOC |
  3233. nsLayoutUtils::SCROLLABLE_INCLUDE_HIDDEN);
  3234. if (scrollFrame) {
  3235. nsIFrame* capturingFrame = scrollFrame->GetScrolledFrame();
  3236. if (capturingFrame) {
  3237. nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(mouseEvent,
  3238. capturingFrame);
  3239. frameselection->StartAutoScrollTimer(capturingFrame, pt, 30);
  3240. }
  3241. }
  3242. return NS_OK;
  3243. }
  3244. /**
  3245. * This static method handles part of the nsFrame::HandleRelease in a way
  3246. * which doesn't rely on the nsFrame object to stay alive.
  3247. */
  3248. static nsresult
  3249. HandleFrameSelection(nsFrameSelection* aFrameSelection,
  3250. nsIFrame::ContentOffsets& aOffsets,
  3251. bool aHandleTableSel,
  3252. int32_t aContentOffsetForTableSel,
  3253. int32_t aTargetForTableSel,
  3254. nsIContent* aParentContentForTableSel,
  3255. WidgetGUIEvent* aEvent,
  3256. nsEventStatus* aEventStatus)
  3257. {
  3258. if (!aFrameSelection) {
  3259. return NS_OK;
  3260. }
  3261. nsresult rv = NS_OK;
  3262. if (nsEventStatus_eConsumeNoDefault != *aEventStatus) {
  3263. if (!aHandleTableSel) {
  3264. if (!aOffsets.content || !aFrameSelection->HasDelayedCaretData()) {
  3265. return NS_ERROR_FAILURE;
  3266. }
  3267. // We are doing this to simulate what we would have done on HandlePress.
  3268. // We didn't do it there to give the user an opportunity to drag
  3269. // the text, but since they didn't drag, we want to place the
  3270. // caret.
  3271. // However, we'll use the mouse position from the release, since:
  3272. // * it's easier
  3273. // * that's the normal click position to use (although really, in
  3274. // the normal case, small movements that don't count as a drag
  3275. // can do selection)
  3276. aFrameSelection->SetDragState(true);
  3277. rv = aFrameSelection->HandleClick(aOffsets.content,
  3278. aOffsets.StartOffset(),
  3279. aOffsets.EndOffset(),
  3280. aFrameSelection->IsShiftDownInDelayedCaretData(),
  3281. false,
  3282. aOffsets.associate);
  3283. if (NS_FAILED(rv)) {
  3284. return rv;
  3285. }
  3286. } else if (aParentContentForTableSel) {
  3287. aFrameSelection->SetDragState(false);
  3288. rv = aFrameSelection->HandleTableSelection(
  3289. aParentContentForTableSel,
  3290. aContentOffsetForTableSel,
  3291. aTargetForTableSel,
  3292. aEvent->AsMouseEvent());
  3293. if (NS_FAILED(rv)) {
  3294. return rv;
  3295. }
  3296. }
  3297. aFrameSelection->SetDelayedCaretData(0);
  3298. }
  3299. aFrameSelection->SetDragState(false);
  3300. aFrameSelection->StopAutoScrollTimer();
  3301. return NS_OK;
  3302. }
  3303. NS_IMETHODIMP nsFrame::HandleRelease(nsPresContext* aPresContext,
  3304. WidgetGUIEvent* aEvent,
  3305. nsEventStatus* aEventStatus)
  3306. {
  3307. if (aEvent->mClass != eMouseEventClass) {
  3308. return NS_OK;
  3309. }
  3310. nsIFrame* activeFrame = GetActiveSelectionFrame(aPresContext, this);
  3311. nsCOMPtr<nsIContent> captureContent = nsIPresShell::GetCapturingContent();
  3312. // We can unconditionally stop capturing because
  3313. // we should never be capturing when the mouse button is up
  3314. nsIPresShell::SetCapturingContent(nullptr, 0);
  3315. bool selectionOff =
  3316. (DisplaySelection(aPresContext) == nsISelectionController::SELECTION_OFF);
  3317. RefPtr<nsFrameSelection> frameselection;
  3318. ContentOffsets offsets;
  3319. nsCOMPtr<nsIContent> parentContent;
  3320. int32_t contentOffsetForTableSel = 0;
  3321. int32_t targetForTableSel = 0;
  3322. bool handleTableSelection = true;
  3323. if (!selectionOff) {
  3324. frameselection = GetFrameSelection();
  3325. if (nsEventStatus_eConsumeNoDefault != *aEventStatus && frameselection) {
  3326. // Check if the frameselection recorded the mouse going down.
  3327. // If not, the user must have clicked in a part of the selection.
  3328. // Place the caret before continuing!
  3329. if (frameselection->MouseDownRecorded()) {
  3330. nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, this);
  3331. offsets = GetContentOffsetsFromPoint(pt, SKIP_HIDDEN);
  3332. handleTableSelection = false;
  3333. } else {
  3334. GetDataForTableSelection(frameselection, PresContext()->PresShell(),
  3335. aEvent->AsMouseEvent(),
  3336. getter_AddRefs(parentContent),
  3337. &contentOffsetForTableSel,
  3338. &targetForTableSel);
  3339. }
  3340. }
  3341. }
  3342. // We might be capturing in some other document and the event just happened to
  3343. // trickle down here. Make sure that document's frame selection is notified.
  3344. // Note, this may cause the current nsFrame object to be deleted, bug 336592.
  3345. RefPtr<nsFrameSelection> frameSelection;
  3346. if (activeFrame != this &&
  3347. static_cast<nsFrame*>(activeFrame)->DisplaySelection(activeFrame->PresContext())
  3348. != nsISelectionController::SELECTION_OFF) {
  3349. frameSelection = activeFrame->GetFrameSelection();
  3350. }
  3351. // Also check the selection of the capturing content which might be in a
  3352. // different document.
  3353. if (!frameSelection && captureContent) {
  3354. nsIDocument* doc = captureContent->GetUncomposedDoc();
  3355. if (doc) {
  3356. nsIPresShell* capturingShell = doc->GetShell();
  3357. if (capturingShell && capturingShell != PresContext()->GetPresShell()) {
  3358. frameSelection = capturingShell->FrameSelection();
  3359. }
  3360. }
  3361. }
  3362. if (frameSelection) {
  3363. frameSelection->SetDragState(false);
  3364. frameSelection->StopAutoScrollTimer();
  3365. nsIScrollableFrame* scrollFrame =
  3366. nsLayoutUtils::GetNearestScrollableFrame(this,
  3367. nsLayoutUtils::SCROLLABLE_SAME_DOC |
  3368. nsLayoutUtils::SCROLLABLE_INCLUDE_HIDDEN);
  3369. if (scrollFrame) {
  3370. // Perform any additional scrolling needed to maintain CSS snap point
  3371. // requirements when autoscrolling is over.
  3372. scrollFrame->ScrollSnap();
  3373. }
  3374. }
  3375. // Do not call any methods of the current object after this point!!!
  3376. // The object is perhaps dead!
  3377. return selectionOff
  3378. ? NS_OK
  3379. : HandleFrameSelection(frameselection, offsets, handleTableSelection,
  3380. contentOffsetForTableSel, targetForTableSel,
  3381. parentContent, aEvent, aEventStatus);
  3382. }
  3383. struct MOZ_STACK_CLASS FrameContentRange {
  3384. FrameContentRange(nsIContent* aContent, int32_t aStart, int32_t aEnd) :
  3385. content(aContent), start(aStart), end(aEnd) { }
  3386. nsCOMPtr<nsIContent> content;
  3387. int32_t start;
  3388. int32_t end;
  3389. };
  3390. // Retrieve the content offsets of a frame
  3391. static FrameContentRange GetRangeForFrame(nsIFrame* aFrame) {
  3392. nsCOMPtr<nsIContent> content, parent;
  3393. content = aFrame->GetContent();
  3394. if (!content) {
  3395. NS_WARNING("Frame has no content");
  3396. return FrameContentRange(nullptr, -1, -1);
  3397. }
  3398. nsIAtom* type = aFrame->GetType();
  3399. if (type == nsGkAtoms::textFrame) {
  3400. int32_t offset, offsetEnd;
  3401. aFrame->GetOffsets(offset, offsetEnd);
  3402. return FrameContentRange(content, offset, offsetEnd);
  3403. }
  3404. if (type == nsGkAtoms::brFrame) {
  3405. parent = content->GetParent();
  3406. int32_t beginOffset = parent->IndexOf(content);
  3407. return FrameContentRange(parent, beginOffset, beginOffset);
  3408. }
  3409. // Loop to deal with anonymous content, which has no index; this loop
  3410. // probably won't run more than twice under normal conditions
  3411. do {
  3412. parent = content->GetParent();
  3413. if (parent) {
  3414. int32_t beginOffset = parent->IndexOf(content);
  3415. if (beginOffset >= 0)
  3416. return FrameContentRange(parent, beginOffset, beginOffset + 1);
  3417. content = parent;
  3418. }
  3419. } while (parent);
  3420. // The root content node must act differently
  3421. return FrameContentRange(content, 0, content->GetChildCount());
  3422. }
  3423. // The FrameTarget represents the closest frame to a point that can be selected
  3424. // The frame is the frame represented, frameEdge says whether one end of the
  3425. // frame is the result (in which case different handling is needed), and
  3426. // afterFrame says which end is repersented if frameEdge is true
  3427. struct FrameTarget {
  3428. FrameTarget(nsIFrame* aFrame, bool aFrameEdge, bool aAfterFrame,
  3429. bool aEmptyBlock = false) :
  3430. frame(aFrame), frameEdge(aFrameEdge), afterFrame(aAfterFrame),
  3431. emptyBlock(aEmptyBlock) { }
  3432. static FrameTarget Null() {
  3433. return FrameTarget(nullptr, false, false);
  3434. }
  3435. bool IsNull() {
  3436. return !frame;
  3437. }
  3438. nsIFrame* frame;
  3439. bool frameEdge;
  3440. bool afterFrame;
  3441. bool emptyBlock;
  3442. };
  3443. // See function implementation for information
  3444. static FrameTarget GetSelectionClosestFrame(nsIFrame* aFrame, nsPoint aPoint,
  3445. uint32_t aFlags);
  3446. static bool SelfIsSelectable(nsIFrame* aFrame, uint32_t aFlags)
  3447. {
  3448. if ((aFlags & nsIFrame::SKIP_HIDDEN) &&
  3449. !aFrame->StyleVisibility()->IsVisible()) {
  3450. return false;
  3451. }
  3452. return !aFrame->IsGeneratedContentFrame() &&
  3453. aFrame->StyleUIReset()->mUserSelect != StyleUserSelect::None;
  3454. }
  3455. static bool SelectionDescendToKids(nsIFrame* aFrame) {
  3456. StyleUserSelect style = aFrame->StyleUIReset()->mUserSelect;
  3457. nsIFrame* parent = aFrame->GetParent();
  3458. // If we are only near (not directly over) then don't traverse
  3459. // frames with independent selection (e.g. text and list controls)
  3460. // unless we're already inside such a frame (see bug 268497). Note that this
  3461. // prevents any of the users of this method from entering form controls.
  3462. // XXX We might want some way to allow using the up-arrow to go into a form
  3463. // control, but the focus didn't work right anyway; it'd probably be enough
  3464. // if the left and right arrows could enter textboxes (which I don't believe
  3465. // they can at the moment)
  3466. return !aFrame->IsGeneratedContentFrame() &&
  3467. style != StyleUserSelect::All &&
  3468. style != StyleUserSelect::None &&
  3469. ((parent->GetStateBits() & NS_FRAME_INDEPENDENT_SELECTION) ||
  3470. !(aFrame->GetStateBits() & NS_FRAME_INDEPENDENT_SELECTION));
  3471. }
  3472. static FrameTarget GetSelectionClosestFrameForChild(nsIFrame* aChild,
  3473. nsPoint aPoint,
  3474. uint32_t aFlags)
  3475. {
  3476. nsIFrame* parent = aChild->GetParent();
  3477. if (SelectionDescendToKids(aChild)) {
  3478. nsPoint pt = aPoint - aChild->GetOffsetTo(parent);
  3479. return GetSelectionClosestFrame(aChild, pt, aFlags);
  3480. }
  3481. return FrameTarget(aChild, false, false);
  3482. }
  3483. // When the cursor needs to be at the beginning of a block, it shouldn't be
  3484. // before the first child. A click on a block whose first child is a block
  3485. // should put the cursor in the child. The cursor shouldn't be between the
  3486. // blocks, because that's not where it's expected.
  3487. // Note that this method is guaranteed to succeed.
  3488. static FrameTarget DrillDownToSelectionFrame(nsIFrame* aFrame,
  3489. bool aEndFrame, uint32_t aFlags) {
  3490. if (SelectionDescendToKids(aFrame)) {
  3491. nsIFrame* result = nullptr;
  3492. nsIFrame *frame = aFrame->PrincipalChildList().FirstChild();
  3493. if (!aEndFrame) {
  3494. while (frame && (!SelfIsSelectable(frame, aFlags) ||
  3495. frame->IsEmpty()))
  3496. frame = frame->GetNextSibling();
  3497. if (frame)
  3498. result = frame;
  3499. } else {
  3500. // Because the frame tree is singly linked, to find the last frame,
  3501. // we have to iterate through all the frames
  3502. // XXX I have a feeling this could be slow for long blocks, although
  3503. // I can't find any slowdowns
  3504. while (frame) {
  3505. if (!frame->IsEmpty() && SelfIsSelectable(frame, aFlags))
  3506. result = frame;
  3507. frame = frame->GetNextSibling();
  3508. }
  3509. }
  3510. if (result)
  3511. return DrillDownToSelectionFrame(result, aEndFrame, aFlags);
  3512. }
  3513. // If the current frame has no targetable children, target the current frame
  3514. return FrameTarget(aFrame, true, aEndFrame);
  3515. }
  3516. // This method finds the closest valid FrameTarget on a given line; if there is
  3517. // no valid FrameTarget on the line, it returns a null FrameTarget
  3518. static FrameTarget GetSelectionClosestFrameForLine(
  3519. nsBlockFrame* aParent,
  3520. nsBlockFrame::LineIterator aLine,
  3521. nsPoint aPoint,
  3522. uint32_t aFlags)
  3523. {
  3524. nsIFrame *frame = aLine->mFirstChild;
  3525. // Account for end of lines (any iterator from the block is valid)
  3526. if (aLine == aParent->LinesEnd())
  3527. return DrillDownToSelectionFrame(aParent, true, aFlags);
  3528. nsIFrame *closestFromIStart = nullptr, *closestFromIEnd = nullptr;
  3529. nscoord closestIStart = aLine->IStart(), closestIEnd = aLine->IEnd();
  3530. WritingMode wm = aLine->mWritingMode;
  3531. LogicalPoint pt(wm, aPoint, aLine->mContainerSize);
  3532. bool canSkipBr = false;
  3533. for (int32_t n = aLine->GetChildCount(); n;
  3534. --n, frame = frame->GetNextSibling()) {
  3535. // Skip brFrames. Can only skip if the line contains at least
  3536. // one selectable and non-empty frame before
  3537. if (!SelfIsSelectable(frame, aFlags) || frame->IsEmpty() ||
  3538. (canSkipBr && frame->GetType() == nsGkAtoms::brFrame)) {
  3539. continue;
  3540. }
  3541. canSkipBr = true;
  3542. LogicalRect frameRect = LogicalRect(wm, frame->GetRect(),
  3543. aLine->mContainerSize);
  3544. if (pt.I(wm) >= frameRect.IStart(wm)) {
  3545. if (pt.I(wm) < frameRect.IEnd(wm)) {
  3546. return GetSelectionClosestFrameForChild(frame, aPoint, aFlags);
  3547. }
  3548. if (frameRect.IEnd(wm) >= closestIStart) {
  3549. closestFromIStart = frame;
  3550. closestIStart = frameRect.IEnd(wm);
  3551. }
  3552. } else {
  3553. if (frameRect.IStart(wm) <= closestIEnd) {
  3554. closestFromIEnd = frame;
  3555. closestIEnd = frameRect.IStart(wm);
  3556. }
  3557. }
  3558. }
  3559. if (!closestFromIStart && !closestFromIEnd) {
  3560. // We should only get here if there are no selectable frames on a line
  3561. // XXX Do we need more elaborate handling here?
  3562. return FrameTarget::Null();
  3563. }
  3564. if (closestFromIStart &&
  3565. (!closestFromIEnd ||
  3566. (abs(pt.I(wm) - closestIStart) <= abs(pt.I(wm) - closestIEnd)))) {
  3567. return GetSelectionClosestFrameForChild(closestFromIStart, aPoint,
  3568. aFlags);
  3569. }
  3570. return GetSelectionClosestFrameForChild(closestFromIEnd, aPoint, aFlags);
  3571. }
  3572. // This method is for the special handling we do for block frames; they're
  3573. // special because they represent paragraphs and because they are organized
  3574. // into lines, which have bounds that are not stored elsewhere in the
  3575. // frame tree. Returns a null FrameTarget for frames which are not
  3576. // blocks or blocks with no lines except editable one.
  3577. static FrameTarget GetSelectionClosestFrameForBlock(nsIFrame* aFrame,
  3578. nsPoint aPoint,
  3579. uint32_t aFlags)
  3580. {
  3581. nsBlockFrame* bf = nsLayoutUtils::GetAsBlock(aFrame); // used only for QI
  3582. if (!bf)
  3583. return FrameTarget::Null();
  3584. // This code searches for the correct line
  3585. nsBlockFrame::LineIterator firstLine = bf->LinesBegin();
  3586. nsBlockFrame::LineIterator end = bf->LinesEnd();
  3587. if (firstLine == end) {
  3588. nsIContent *blockContent = aFrame->GetContent();
  3589. if (blockContent) {
  3590. // Return with empty flag true.
  3591. return FrameTarget(aFrame, false, false, true);
  3592. }
  3593. return FrameTarget::Null();
  3594. }
  3595. nsBlockFrame::LineIterator curLine = firstLine;
  3596. nsBlockFrame::LineIterator closestLine = end;
  3597. // Convert aPoint into a LogicalPoint in the writing-mode of this block
  3598. WritingMode wm = curLine->mWritingMode;
  3599. LogicalPoint pt(wm, aPoint, curLine->mContainerSize);
  3600. while (curLine != end) {
  3601. // Check to see if our point lies within the line's block-direction bounds
  3602. nscoord BCoord = pt.B(wm) - curLine->BStart();
  3603. nscoord BSize = curLine->BSize();
  3604. if (BCoord >= 0 && BCoord < BSize) {
  3605. closestLine = curLine;
  3606. break; // We found the line; stop looking
  3607. }
  3608. if (BCoord < 0)
  3609. break;
  3610. ++curLine;
  3611. }
  3612. if (closestLine == end) {
  3613. nsBlockFrame::LineIterator prevLine = curLine.prev();
  3614. nsBlockFrame::LineIterator nextLine = curLine;
  3615. // Avoid empty lines
  3616. while (nextLine != end && nextLine->IsEmpty())
  3617. ++nextLine;
  3618. while (prevLine != end && prevLine->IsEmpty())
  3619. --prevLine;
  3620. // This hidden pref dictates whether a point above or below all lines comes
  3621. // up with a line or the beginning or end of the frame; 0 on Windows,
  3622. // 1 on other platforms by default at the writing of this code
  3623. int32_t dragOutOfFrame =
  3624. Preferences::GetInt("browser.drag_out_of_frame_style");
  3625. if (prevLine == end) {
  3626. if (dragOutOfFrame == 1 || nextLine == end)
  3627. return DrillDownToSelectionFrame(aFrame, false, aFlags);
  3628. closestLine = nextLine;
  3629. } else if (nextLine == end) {
  3630. if (dragOutOfFrame == 1)
  3631. return DrillDownToSelectionFrame(aFrame, true, aFlags);
  3632. closestLine = prevLine;
  3633. } else { // Figure out which line is closer
  3634. if (pt.B(wm) - prevLine->BEnd() < nextLine->BStart() - pt.B(wm))
  3635. closestLine = prevLine;
  3636. else
  3637. closestLine = nextLine;
  3638. }
  3639. }
  3640. do {
  3641. FrameTarget target = GetSelectionClosestFrameForLine(bf, closestLine,
  3642. aPoint, aFlags);
  3643. if (!target.IsNull())
  3644. return target;
  3645. ++closestLine;
  3646. } while (closestLine != end);
  3647. // Fall back to just targeting the last targetable place
  3648. return DrillDownToSelectionFrame(aFrame, true, aFlags);
  3649. }
  3650. // GetSelectionClosestFrame is the helper function that calculates the closest
  3651. // frame to the given point.
  3652. // It doesn't completely account for offset styles, so needs to be used in
  3653. // restricted environments.
  3654. // Cannot handle overlapping frames correctly, so it should receive the output
  3655. // of GetFrameForPoint
  3656. // Guaranteed to return a valid FrameTarget
  3657. static FrameTarget GetSelectionClosestFrame(nsIFrame* aFrame, nsPoint aPoint,
  3658. uint32_t aFlags)
  3659. {
  3660. {
  3661. // Handle blocks; if the frame isn't a block, the method fails
  3662. FrameTarget target = GetSelectionClosestFrameForBlock(aFrame, aPoint, aFlags);
  3663. if (!target.IsNull())
  3664. return target;
  3665. }
  3666. nsIFrame *kid = aFrame->PrincipalChildList().FirstChild();
  3667. if (kid) {
  3668. // Go through all the child frames to find the closest one
  3669. nsIFrame::FrameWithDistance closest = { nullptr, nscoord_MAX, nscoord_MAX };
  3670. for (; kid; kid = kid->GetNextSibling()) {
  3671. if (!SelfIsSelectable(kid, aFlags) || kid->IsEmpty())
  3672. continue;
  3673. kid->FindCloserFrameForSelection(aPoint, &closest);
  3674. }
  3675. if (closest.mFrame) {
  3676. if (closest.mFrame->IsSVGText())
  3677. return FrameTarget(closest.mFrame, false, false);
  3678. return GetSelectionClosestFrameForChild(closest.mFrame, aPoint, aFlags);
  3679. }
  3680. }
  3681. return FrameTarget(aFrame, false, false);
  3682. }
  3683. nsIFrame::ContentOffsets OffsetsForSingleFrame(nsIFrame* aFrame, nsPoint aPoint)
  3684. {
  3685. nsIFrame::ContentOffsets offsets;
  3686. FrameContentRange range = GetRangeForFrame(aFrame);
  3687. offsets.content = range.content;
  3688. // If there are continuations (meaning it's not one rectangle), this is the
  3689. // best this function can do
  3690. if (aFrame->GetNextContinuation() || aFrame->GetPrevContinuation()) {
  3691. offsets.offset = range.start;
  3692. offsets.secondaryOffset = range.end;
  3693. offsets.associate = CARET_ASSOCIATE_AFTER;
  3694. return offsets;
  3695. }
  3696. // Figure out whether the offsets should be over, after, or before the frame
  3697. nsRect rect(nsPoint(0, 0), aFrame->GetSize());
  3698. bool isBlock = aFrame->GetDisplay() != StyleDisplay::Inline;
  3699. bool isRtl = (aFrame->StyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL);
  3700. if ((isBlock && rect.y < aPoint.y) ||
  3701. (!isBlock && ((isRtl && rect.x + rect.width / 2 > aPoint.x) ||
  3702. (!isRtl && rect.x + rect.width / 2 < aPoint.x)))) {
  3703. offsets.offset = range.end;
  3704. if (rect.Contains(aPoint))
  3705. offsets.secondaryOffset = range.start;
  3706. else
  3707. offsets.secondaryOffset = range.end;
  3708. } else {
  3709. offsets.offset = range.start;
  3710. if (rect.Contains(aPoint))
  3711. offsets.secondaryOffset = range.end;
  3712. else
  3713. offsets.secondaryOffset = range.start;
  3714. }
  3715. offsets.associate =
  3716. offsets.offset == range.start ? CARET_ASSOCIATE_AFTER : CARET_ASSOCIATE_BEFORE;
  3717. return offsets;
  3718. }
  3719. static nsIFrame* AdjustFrameForSelectionStyles(nsIFrame* aFrame) {
  3720. nsIFrame* adjustedFrame = aFrame;
  3721. for (nsIFrame* frame = aFrame; frame; frame = frame->GetParent())
  3722. {
  3723. // These are the conditions that make all children not able to handle
  3724. // a cursor.
  3725. StyleUserSelect userSelect = frame->StyleUIReset()->mUserSelect;
  3726. if (userSelect == StyleUserSelect::MozText) {
  3727. // If we see a -moz-text element, we shouldn't look further up the parent
  3728. // chain!
  3729. break;
  3730. }
  3731. if (userSelect == StyleUserSelect::All ||
  3732. frame->IsGeneratedContentFrame()) {
  3733. adjustedFrame = frame;
  3734. }
  3735. }
  3736. return adjustedFrame;
  3737. }
  3738. nsIFrame::ContentOffsets nsIFrame::GetContentOffsetsFromPoint(nsPoint aPoint,
  3739. uint32_t aFlags)
  3740. {
  3741. nsIFrame *adjustedFrame;
  3742. if (aFlags & IGNORE_SELECTION_STYLE) {
  3743. adjustedFrame = this;
  3744. }
  3745. else {
  3746. // This section of code deals with special selection styles. Note that
  3747. // -moz-all exists, even though it doesn't need to be explicitly handled.
  3748. //
  3749. // The offset is forced not to end up in generated content; content offsets
  3750. // cannot represent content outside of the document's content tree.
  3751. adjustedFrame = AdjustFrameForSelectionStyles(this);
  3752. // -moz-user-select: all needs special handling, because clicking on it
  3753. // should lead to the whole frame being selected
  3754. if (adjustedFrame && adjustedFrame->StyleUIReset()->mUserSelect ==
  3755. StyleUserSelect::All) {
  3756. nsPoint adjustedPoint = aPoint + this->GetOffsetTo(adjustedFrame);
  3757. return OffsetsForSingleFrame(adjustedFrame, adjustedPoint);
  3758. }
  3759. // For other cases, try to find a closest frame starting from the parent of
  3760. // the unselectable frame
  3761. if (adjustedFrame != this)
  3762. adjustedFrame = adjustedFrame->GetParent();
  3763. }
  3764. nsPoint adjustedPoint = aPoint + this->GetOffsetTo(adjustedFrame);
  3765. FrameTarget closest =
  3766. GetSelectionClosestFrame(adjustedFrame, adjustedPoint, aFlags);
  3767. if (closest.emptyBlock) {
  3768. ContentOffsets offsets;
  3769. NS_ASSERTION(closest.frame,
  3770. "closest.frame must not be null when it's empty");
  3771. offsets.content = closest.frame->GetContent();
  3772. offsets.offset = 0;
  3773. offsets.secondaryOffset = 0;
  3774. offsets.associate = CARET_ASSOCIATE_AFTER;
  3775. return offsets;
  3776. }
  3777. // If the correct offset is at one end of a frame, use offset-based
  3778. // calculation method
  3779. if (closest.frameEdge) {
  3780. ContentOffsets offsets;
  3781. FrameContentRange range = GetRangeForFrame(closest.frame);
  3782. offsets.content = range.content;
  3783. if (closest.afterFrame)
  3784. offsets.offset = range.end;
  3785. else
  3786. offsets.offset = range.start;
  3787. offsets.secondaryOffset = offsets.offset;
  3788. offsets.associate = offsets.offset == range.start ?
  3789. CARET_ASSOCIATE_AFTER : CARET_ASSOCIATE_BEFORE;
  3790. return offsets;
  3791. }
  3792. nsPoint pt;
  3793. if (closest.frame != this) {
  3794. if (closest.frame->IsSVGText()) {
  3795. pt = nsLayoutUtils::TransformAncestorPointToFrame(closest.frame,
  3796. aPoint, this);
  3797. } else {
  3798. pt = aPoint - closest.frame->GetOffsetTo(this);
  3799. }
  3800. } else {
  3801. pt = aPoint;
  3802. }
  3803. return static_cast<nsFrame*>(closest.frame)->CalcContentOffsetsFromFramePoint(pt);
  3804. // XXX should I add some kind of offset standardization?
  3805. // consider <b>xxxxx</b><i>zzzzz</i>; should any click between the last
  3806. // x and first z put the cursor in the same logical position in addition
  3807. // to the same visual position?
  3808. }
  3809. nsIFrame::ContentOffsets nsFrame::CalcContentOffsetsFromFramePoint(nsPoint aPoint)
  3810. {
  3811. return OffsetsForSingleFrame(this, aPoint);
  3812. }
  3813. void
  3814. nsIFrame::AssociateImage(const nsStyleImage& aImage, nsPresContext* aPresContext)
  3815. {
  3816. if (aImage.GetType() != eStyleImageType_Image) {
  3817. return;
  3818. }
  3819. imgRequestProxy* req = aImage.GetImageData();
  3820. if (!req) {
  3821. return;
  3822. }
  3823. mozilla::css::ImageLoader* loader =
  3824. aPresContext->Document()->StyleImageLoader();
  3825. // If this fails there's not much we can do ...
  3826. loader->AssociateRequestToFrame(req, this);
  3827. }
  3828. nsresult
  3829. nsFrame::GetCursor(const nsPoint& aPoint,
  3830. nsIFrame::Cursor& aCursor)
  3831. {
  3832. FillCursorInformationFromStyle(StyleUserInterface(), aCursor);
  3833. if (NS_STYLE_CURSOR_AUTO == aCursor.mCursor) {
  3834. // If this is editable, I-beam cursor is better for most elements.
  3835. aCursor.mCursor =
  3836. (mContent && mContent->IsEditable())
  3837. ? NS_STYLE_CURSOR_TEXT : NS_STYLE_CURSOR_DEFAULT;
  3838. }
  3839. if (NS_STYLE_CURSOR_TEXT == aCursor.mCursor &&
  3840. GetWritingMode().IsVertical()) {
  3841. // Per CSS UI spec, UA may treat value 'text' as
  3842. // 'vertical-text' for vertical text.
  3843. aCursor.mCursor = NS_STYLE_CURSOR_VERTICAL_TEXT;
  3844. }
  3845. return NS_OK;
  3846. }
  3847. // Resize and incremental reflow
  3848. /* virtual */ void
  3849. nsFrame::MarkIntrinsicISizesDirty()
  3850. {
  3851. // This version is meant only for what used to be box-to-block adaptors.
  3852. // It should not be called by other derived classes.
  3853. if (::IsXULBoxWrapped(this)) {
  3854. nsBoxLayoutMetrics *metrics = BoxMetrics();
  3855. SizeNeedsRecalc(metrics->mPrefSize);
  3856. SizeNeedsRecalc(metrics->mMinSize);
  3857. SizeNeedsRecalc(metrics->mMaxSize);
  3858. SizeNeedsRecalc(metrics->mBlockPrefSize);
  3859. SizeNeedsRecalc(metrics->mBlockMinSize);
  3860. CoordNeedsRecalc(metrics->mFlex);
  3861. CoordNeedsRecalc(metrics->mAscent);
  3862. }
  3863. if (GetStateBits() & NS_FRAME_FONT_INFLATION_FLOW_ROOT) {
  3864. nsFontInflationData::MarkFontInflationDataTextDirty(this);
  3865. }
  3866. }
  3867. /* virtual */ nscoord
  3868. nsFrame::GetMinISize(nsRenderingContext *aRenderingContext)
  3869. {
  3870. nscoord result = 0;
  3871. DISPLAY_MIN_WIDTH(this, result);
  3872. return result;
  3873. }
  3874. /* virtual */ nscoord
  3875. nsFrame::GetPrefISize(nsRenderingContext *aRenderingContext)
  3876. {
  3877. nscoord result = 0;
  3878. DISPLAY_PREF_WIDTH(this, result);
  3879. return result;
  3880. }
  3881. /* virtual */ void
  3882. nsFrame::AddInlineMinISize(nsRenderingContext* aRenderingContext,
  3883. nsIFrame::InlineMinISizeData* aData)
  3884. {
  3885. nscoord isize = nsLayoutUtils::IntrinsicForContainer(aRenderingContext,
  3886. this, nsLayoutUtils::MIN_ISIZE);
  3887. aData->DefaultAddInlineMinISize(this, isize);
  3888. }
  3889. /* virtual */ void
  3890. nsFrame::AddInlinePrefISize(nsRenderingContext* aRenderingContext,
  3891. nsIFrame::InlinePrefISizeData* aData)
  3892. {
  3893. nscoord isize = nsLayoutUtils::IntrinsicForContainer(aRenderingContext,
  3894. this, nsLayoutUtils::PREF_ISIZE);
  3895. aData->DefaultAddInlinePrefISize(isize);
  3896. }
  3897. void
  3898. nsIFrame::InlineMinISizeData::DefaultAddInlineMinISize(nsIFrame* aFrame,
  3899. nscoord aISize,
  3900. bool aAllowBreak)
  3901. {
  3902. auto parent = aFrame->GetParent();
  3903. MOZ_ASSERT(parent, "Must have a parent if we get here!");
  3904. const bool mayBreak = aAllowBreak &&
  3905. !aFrame->CanContinueTextRun() &&
  3906. !parent->StyleContext()->ShouldSuppressLineBreak() &&
  3907. parent->StyleText()->WhiteSpaceCanWrap(parent);
  3908. if (mayBreak) {
  3909. OptionallyBreak();
  3910. }
  3911. mTrailingWhitespace = 0;
  3912. mSkipWhitespace = false;
  3913. mCurrentLine += aISize;
  3914. mAtStartOfLine = false;
  3915. if (mayBreak) {
  3916. OptionallyBreak();
  3917. }
  3918. }
  3919. void
  3920. nsIFrame::InlinePrefISizeData::DefaultAddInlinePrefISize(nscoord aISize)
  3921. {
  3922. mCurrentLine = NSCoordSaturatingAdd(mCurrentLine, aISize);
  3923. mTrailingWhitespace = 0;
  3924. mSkipWhitespace = false;
  3925. }
  3926. void
  3927. nsIFrame::InlineMinISizeData::ForceBreak()
  3928. {
  3929. mCurrentLine -= mTrailingWhitespace;
  3930. mPrevLines = std::max(mPrevLines, mCurrentLine);
  3931. mCurrentLine = mTrailingWhitespace = 0;
  3932. for (uint32_t i = 0, i_end = mFloats.Length(); i != i_end; ++i) {
  3933. nscoord float_min = mFloats[i].Width();
  3934. if (float_min > mPrevLines)
  3935. mPrevLines = float_min;
  3936. }
  3937. mFloats.Clear();
  3938. mSkipWhitespace = true;
  3939. }
  3940. void
  3941. nsIFrame::InlineMinISizeData::OptionallyBreak(nscoord aHyphenWidth)
  3942. {
  3943. // If we can fit more content into a smaller width by staying on this
  3944. // line (because we're still at a negative offset due to negative
  3945. // text-indent or negative margin), don't break. Otherwise, do the
  3946. // same as ForceBreak. it doesn't really matter when we accumulate
  3947. // floats.
  3948. if (mCurrentLine + aHyphenWidth < 0 || mAtStartOfLine)
  3949. return;
  3950. mCurrentLine += aHyphenWidth;
  3951. ForceBreak();
  3952. }
  3953. void
  3954. nsIFrame::InlinePrefISizeData::ForceBreak()
  3955. {
  3956. if (mFloats.Length() != 0) {
  3957. // preferred widths accumulated for floats that have already
  3958. // been cleared past
  3959. nscoord floats_done = 0,
  3960. // preferred widths accumulated for floats that have not yet
  3961. // been cleared past
  3962. floats_cur_left = 0,
  3963. floats_cur_right = 0;
  3964. for (uint32_t i = 0, i_end = mFloats.Length(); i != i_end; ++i) {
  3965. const FloatInfo& floatInfo = mFloats[i];
  3966. const nsStyleDisplay* floatDisp = floatInfo.Frame()->StyleDisplay();
  3967. StyleClear breakType = floatDisp->PhysicalBreakType(mLineContainerWM);
  3968. if (breakType == StyleClear::Left ||
  3969. breakType == StyleClear::Right ||
  3970. breakType == StyleClear::Both) {
  3971. nscoord floats_cur = NSCoordSaturatingAdd(floats_cur_left,
  3972. floats_cur_right);
  3973. if (floats_cur > floats_done) {
  3974. floats_done = floats_cur;
  3975. }
  3976. if (breakType != StyleClear::Right) {
  3977. floats_cur_left = 0;
  3978. }
  3979. if (breakType != StyleClear::Left) {
  3980. floats_cur_right = 0;
  3981. }
  3982. }
  3983. StyleFloat floatStyle = floatDisp->PhysicalFloats(mLineContainerWM);
  3984. nscoord& floats_cur =
  3985. floatStyle == StyleFloat::Left ? floats_cur_left : floats_cur_right;
  3986. nscoord floatWidth = floatInfo.Width();
  3987. // Negative-width floats don't change the available space so they
  3988. // shouldn't change our intrinsic line width either.
  3989. floats_cur =
  3990. NSCoordSaturatingAdd(floats_cur, std::max(0, floatWidth));
  3991. }
  3992. nscoord floats_cur =
  3993. NSCoordSaturatingAdd(floats_cur_left, floats_cur_right);
  3994. if (floats_cur > floats_done)
  3995. floats_done = floats_cur;
  3996. mCurrentLine = NSCoordSaturatingAdd(mCurrentLine, floats_done);
  3997. mFloats.Clear();
  3998. }
  3999. mCurrentLine =
  4000. NSCoordSaturatingSubtract(mCurrentLine, mTrailingWhitespace, nscoord_MAX);
  4001. mPrevLines = std::max(mPrevLines, mCurrentLine);
  4002. mCurrentLine = mTrailingWhitespace = 0;
  4003. mSkipWhitespace = true;
  4004. }
  4005. static nscoord
  4006. ResolveMargin(const nsStyleCoord& aStyle, nscoord aPercentageBasis)
  4007. {
  4008. if (aStyle.GetUnit() == eStyleUnit_Auto) {
  4009. return nscoord(0);
  4010. }
  4011. return nsLayoutUtils::ResolveToLength<false>(aStyle, aPercentageBasis);
  4012. }
  4013. static nscoord
  4014. ResolvePadding(const nsStyleCoord& aStyle, nscoord aPercentageBasis)
  4015. {
  4016. return nsLayoutUtils::ResolveToLength<true>(aStyle, aPercentageBasis);
  4017. }
  4018. static nsIFrame::IntrinsicISizeOffsetData
  4019. IntrinsicSizeOffsets(nsIFrame* aFrame, nscoord aPercentageBasis, bool aForISize)
  4020. {
  4021. nsIFrame::IntrinsicISizeOffsetData result;
  4022. WritingMode wm = aFrame->GetWritingMode();
  4023. const auto& margin = aFrame->StyleMargin()->mMargin;
  4024. bool verticalAxis = aForISize == wm.IsVertical();
  4025. if (verticalAxis) {
  4026. result.hMargin += ResolveMargin(margin.GetTop(), aPercentageBasis);
  4027. result.hMargin += ResolveMargin(margin.GetBottom(), aPercentageBasis);
  4028. } else {
  4029. result.hMargin += ResolveMargin(margin.GetLeft(), aPercentageBasis);
  4030. result.hMargin += ResolveMargin(margin.GetRight(), aPercentageBasis);
  4031. }
  4032. const auto& padding = aFrame->StylePadding()->mPadding;
  4033. if (verticalAxis) {
  4034. result.hPadding += ResolvePadding(padding.GetTop(), aPercentageBasis);
  4035. result.hPadding += ResolvePadding(padding.GetBottom(), aPercentageBasis);
  4036. } else {
  4037. result.hPadding += ResolvePadding(padding.GetLeft(), aPercentageBasis);
  4038. result.hPadding += ResolvePadding(padding.GetRight(), aPercentageBasis);
  4039. }
  4040. const nsStyleBorder* styleBorder = aFrame->StyleBorder();
  4041. if (verticalAxis) {
  4042. result.hBorder += styleBorder->GetComputedBorderWidth(NS_SIDE_TOP);
  4043. result.hBorder += styleBorder->GetComputedBorderWidth(NS_SIDE_BOTTOM);
  4044. } else {
  4045. result.hBorder += styleBorder->GetComputedBorderWidth(NS_SIDE_LEFT);
  4046. result.hBorder += styleBorder->GetComputedBorderWidth(NS_SIDE_RIGHT);
  4047. }
  4048. const nsStyleDisplay* disp = aFrame->StyleDisplay();
  4049. if (aFrame->IsThemed(disp)) {
  4050. nsPresContext* presContext = aFrame->PresContext();
  4051. nsIntMargin border;
  4052. presContext->GetTheme()->GetWidgetBorder(presContext->DeviceContext(),
  4053. aFrame, disp->mAppearance,
  4054. &border);
  4055. result.hBorder =
  4056. presContext->DevPixelsToAppUnits(verticalAxis ? border.TopBottom()
  4057. : border.LeftRight());
  4058. nsIntMargin padding;
  4059. if (presContext->GetTheme()->GetWidgetPadding(presContext->DeviceContext(),
  4060. aFrame, disp->mAppearance,
  4061. &padding)) {
  4062. result.hPadding =
  4063. presContext->DevPixelsToAppUnits(verticalAxis ? padding.TopBottom()
  4064. : padding.LeftRight());
  4065. }
  4066. }
  4067. return result;
  4068. }
  4069. /* virtual */ nsIFrame::IntrinsicISizeOffsetData
  4070. nsFrame::IntrinsicISizeOffsets(nscoord aPercentageBasis)
  4071. {
  4072. return IntrinsicSizeOffsets(this, aPercentageBasis, true);
  4073. }
  4074. nsIFrame::IntrinsicISizeOffsetData
  4075. nsIFrame::IntrinsicBSizeOffsets(nscoord aPercentageBasis)
  4076. {
  4077. return IntrinsicSizeOffsets(this, aPercentageBasis, false);
  4078. }
  4079. /* virtual */ IntrinsicSize
  4080. nsFrame::GetIntrinsicSize()
  4081. {
  4082. return IntrinsicSize(); // default is width/height set to eStyleUnit_None
  4083. }
  4084. /* virtual */ AspectRatio
  4085. nsFrame::GetIntrinsicRatio()
  4086. {
  4087. return AspectRatio();
  4088. }
  4089. /* virtual */
  4090. LogicalSize
  4091. nsFrame::ComputeSize(nsRenderingContext* aRenderingContext,
  4092. WritingMode aWM,
  4093. const LogicalSize& aCBSize,
  4094. nscoord aAvailableISize,
  4095. const LogicalSize& aMargin,
  4096. const LogicalSize& aBorder,
  4097. const LogicalSize& aPadding,
  4098. ComputeSizeFlags aFlags)
  4099. {
  4100. MOZ_ASSERT(!GetIntrinsicRatio(),
  4101. "Please override this method and call "
  4102. "nsFrame::ComputeSizeWithIntrinsicDimensions instead.");
  4103. LogicalSize result = ComputeAutoSize(aRenderingContext, aWM,
  4104. aCBSize, aAvailableISize,
  4105. aMargin, aBorder, aPadding,
  4106. aFlags);
  4107. const nsStylePosition *stylePos = StylePosition();
  4108. LogicalSize boxSizingAdjust(aWM);
  4109. if (stylePos->mBoxSizing == StyleBoxSizing::Border) {
  4110. boxSizingAdjust = aBorder + aPadding;
  4111. }
  4112. nscoord boxSizingToMarginEdgeISize =
  4113. aMargin.ISize(aWM) + aBorder.ISize(aWM) + aPadding.ISize(aWM) -
  4114. boxSizingAdjust.ISize(aWM);
  4115. const nsStyleCoord* inlineStyleCoord = &stylePos->ISize(aWM);
  4116. const nsStyleCoord* blockStyleCoord = &stylePos->BSize(aWM);
  4117. nsIAtom* parentFrameType = GetParent() ? GetParent()->GetType() : nullptr;
  4118. auto alignCB = GetParent();
  4119. bool isGridItem = (parentFrameType == nsGkAtoms::gridContainerFrame &&
  4120. !(GetStateBits() & NS_FRAME_OUT_OF_FLOW));
  4121. if (parentFrameType == nsGkAtoms::tableWrapperFrame &&
  4122. GetType() == nsGkAtoms::tableFrame) {
  4123. // An inner table frame is sized as a grid item if its table wrapper is,
  4124. // because they actually have the same CB (the wrapper's CB).
  4125. // @see ReflowInput::InitCBReflowInput
  4126. auto tableWrapper = GetParent();
  4127. auto grandParent = tableWrapper->GetParent();
  4128. isGridItem = (grandParent->GetType() == nsGkAtoms::gridContainerFrame &&
  4129. !(tableWrapper->GetStateBits() & NS_FRAME_OUT_OF_FLOW));
  4130. if (isGridItem) {
  4131. // When resolving justify/align-self below, we want to use the grid
  4132. // container's justify/align-items value and WritingMode.
  4133. alignCB = grandParent;
  4134. }
  4135. }
  4136. bool isFlexItem = (parentFrameType == nsGkAtoms::flexContainerFrame &&
  4137. !(GetStateBits() & NS_FRAME_OUT_OF_FLOW));
  4138. bool isInlineFlexItem = false;
  4139. if (isFlexItem) {
  4140. // Flex items use their "flex-basis" property in place of their main-size
  4141. // property (e.g. "width") for sizing purposes, *unless* they have
  4142. // "flex-basis:auto", in which case they use their main-size property after
  4143. // all.
  4144. uint32_t flexDirection = GetParent()->StylePosition()->mFlexDirection;
  4145. isInlineFlexItem =
  4146. flexDirection == NS_STYLE_FLEX_DIRECTION_ROW ||
  4147. flexDirection == NS_STYLE_FLEX_DIRECTION_ROW_REVERSE;
  4148. // NOTE: The logic here should match the similar chunk for determining
  4149. // inlineStyleCoord and blockStyleCoord in
  4150. // nsFrame::ComputeSizeWithIntrinsicDimensions().
  4151. const nsStyleCoord* flexBasis = &(stylePos->mFlexBasis);
  4152. if (flexBasis->GetUnit() != eStyleUnit_Auto) {
  4153. if (isInlineFlexItem) {
  4154. inlineStyleCoord = flexBasis;
  4155. } else {
  4156. // One caveat for vertical flex items: We don't support enumerated
  4157. // values (e.g. "max-content") for height properties yet. So, if our
  4158. // computed flex-basis is an enumerated value, we'll just behave as if
  4159. // it were "auto", which means "use the main-size property after all"
  4160. // (which is "height", in this case).
  4161. // NOTE: Once we support intrinsic sizing keywords for "height",
  4162. // we should remove this check.
  4163. if (flexBasis->GetUnit() != eStyleUnit_Enumerated) {
  4164. blockStyleCoord = flexBasis;
  4165. }
  4166. }
  4167. }
  4168. }
  4169. // Compute inline-axis size
  4170. if (inlineStyleCoord->GetUnit() != eStyleUnit_Auto) {
  4171. result.ISize(aWM) =
  4172. ComputeISizeValue(aRenderingContext, aCBSize.ISize(aWM),
  4173. boxSizingAdjust.ISize(aWM), boxSizingToMarginEdgeISize,
  4174. *inlineStyleCoord, aFlags);
  4175. } else if (MOZ_UNLIKELY(isGridItem) &&
  4176. !IS_TRUE_OVERFLOW_CONTAINER(this)) {
  4177. // 'auto' inline-size for grid-level box - fill the CB for 'stretch' /
  4178. // 'normal' and clamp it to the CB if requested:
  4179. bool stretch = false;
  4180. if (!(aFlags & nsIFrame::eShrinkWrap) &&
  4181. !StyleMargin()->HasInlineAxisAuto(aWM)) {
  4182. auto inlineAxisAlignment =
  4183. aWM.IsOrthogonalTo(alignCB->GetWritingMode()) ?
  4184. StylePosition()->UsedAlignSelf(alignCB->StyleContext()) :
  4185. StylePosition()->UsedJustifySelf(alignCB->StyleContext());
  4186. stretch = inlineAxisAlignment == NS_STYLE_ALIGN_NORMAL ||
  4187. inlineAxisAlignment == NS_STYLE_ALIGN_STRETCH;
  4188. }
  4189. if (stretch || (aFlags & ComputeSizeFlags::eIClampMarginBoxMinSize)) {
  4190. auto iSizeToFillCB = std::max(nscoord(0), aCBSize.ISize(aWM) -
  4191. aPadding.ISize(aWM) -
  4192. aBorder.ISize(aWM) -
  4193. aMargin.ISize(aWM));
  4194. if (stretch || result.ISize(aWM) > iSizeToFillCB) {
  4195. result.ISize(aWM) = iSizeToFillCB;
  4196. }
  4197. }
  4198. }
  4199. // Flex items ignore their min & max sizing properties in their
  4200. // flex container's main-axis. (Those properties get applied later in
  4201. // the flexbox algorithm.)
  4202. const nsStyleCoord& maxISizeCoord = stylePos->MaxISize(aWM);
  4203. nscoord maxISize = NS_UNCONSTRAINEDSIZE;
  4204. if (maxISizeCoord.GetUnit() != eStyleUnit_None &&
  4205. !(isFlexItem && isInlineFlexItem)) {
  4206. maxISize =
  4207. ComputeISizeValue(aRenderingContext, aCBSize.ISize(aWM),
  4208. boxSizingAdjust.ISize(aWM), boxSizingToMarginEdgeISize,
  4209. maxISizeCoord, aFlags);
  4210. result.ISize(aWM) = std::min(maxISize, result.ISize(aWM));
  4211. }
  4212. const nsStyleCoord& minISizeCoord = stylePos->MinISize(aWM);
  4213. nscoord minISize;
  4214. if (minISizeCoord.GetUnit() != eStyleUnit_Auto &&
  4215. !(isFlexItem && isInlineFlexItem)) {
  4216. minISize =
  4217. ComputeISizeValue(aRenderingContext, aCBSize.ISize(aWM),
  4218. boxSizingAdjust.ISize(aWM), boxSizingToMarginEdgeISize,
  4219. minISizeCoord, aFlags);
  4220. } else if (MOZ_UNLIKELY(aFlags & eIApplyAutoMinSize)) {
  4221. // This implements "Implied Minimum Size of Grid Items".
  4222. // https://drafts.csswg.org/css-grid/#min-size-auto
  4223. minISize = std::min(maxISize, GetMinISize(aRenderingContext));
  4224. if (inlineStyleCoord->IsCoordPercentCalcUnit()) {
  4225. minISize = std::min(minISize, result.ISize(aWM));
  4226. } else if (aFlags & eIClampMarginBoxMinSize) {
  4227. // "if the grid item spans only grid tracks that have a fixed max track
  4228. // sizing function, its automatic minimum size in that dimension is
  4229. // further clamped to less than or equal to the size necessary to fit
  4230. // its margin box within the resulting grid area (flooring at zero)"
  4231. // https://drafts.csswg.org/css-grid/#min-size-auto
  4232. auto maxMinISize = std::max(nscoord(0), aCBSize.ISize(aWM) -
  4233. aPadding.ISize(aWM) -
  4234. aBorder.ISize(aWM) -
  4235. aMargin.ISize(aWM));
  4236. minISize = std::min(minISize, maxMinISize);
  4237. }
  4238. } else {
  4239. // Treat "min-width: auto" as 0.
  4240. // NOTE: Technically, "auto" is supposed to behave like "min-content" on
  4241. // flex items. However, we don't need to worry about that here, because
  4242. // flex items' min-sizes are intentionally ignored until the flex
  4243. // container explicitly considers them during space distribution.
  4244. minISize = 0;
  4245. }
  4246. result.ISize(aWM) = std::max(minISize, result.ISize(aWM));
  4247. // Compute block-axis size
  4248. // (but not if we have auto bsize or if we recieved the "eUseAutoBSize"
  4249. // flag -- then, we'll just stick with the bsize that we already calculated
  4250. // in the initial ComputeAutoSize() call.)
  4251. if (!(aFlags & nsIFrame::eUseAutoBSize)) {
  4252. if (!nsLayoutUtils::IsAutoBSize(*blockStyleCoord, aCBSize.BSize(aWM))) {
  4253. result.BSize(aWM) =
  4254. nsLayoutUtils::ComputeBSizeValue(aCBSize.BSize(aWM),
  4255. boxSizingAdjust.BSize(aWM),
  4256. *blockStyleCoord);
  4257. } else if (MOZ_UNLIKELY(isGridItem) &&
  4258. blockStyleCoord->GetUnit() == eStyleUnit_Auto &&
  4259. !IS_TRUE_OVERFLOW_CONTAINER(this)) {
  4260. auto cbSize = aCBSize.BSize(aWM);
  4261. if (cbSize != NS_AUTOHEIGHT) {
  4262. // 'auto' block-size for grid-level box - fill the CB for 'stretch' /
  4263. // 'normal' and clamp it to the CB if requested:
  4264. bool stretch = false;
  4265. if (!StyleMargin()->HasBlockAxisAuto(aWM)) {
  4266. auto blockAxisAlignment =
  4267. !aWM.IsOrthogonalTo(alignCB->GetWritingMode()) ?
  4268. StylePosition()->UsedAlignSelf(alignCB->StyleContext()) :
  4269. StylePosition()->UsedJustifySelf(alignCB->StyleContext());
  4270. stretch = blockAxisAlignment == NS_STYLE_ALIGN_NORMAL ||
  4271. blockAxisAlignment == NS_STYLE_ALIGN_STRETCH;
  4272. }
  4273. if (stretch || (aFlags & ComputeSizeFlags::eBClampMarginBoxMinSize)) {
  4274. auto bSizeToFillCB = std::max(nscoord(0), cbSize -
  4275. aPadding.BSize(aWM) -
  4276. aBorder.BSize(aWM) -
  4277. aMargin.BSize(aWM));
  4278. if (stretch || (result.BSize(aWM) != NS_AUTOHEIGHT &&
  4279. result.BSize(aWM) > bSizeToFillCB)) {
  4280. result.BSize(aWM) = bSizeToFillCB;
  4281. }
  4282. }
  4283. }
  4284. }
  4285. }
  4286. const nsStyleCoord& maxBSizeCoord = stylePos->MaxBSize(aWM);
  4287. if (result.BSize(aWM) != NS_UNCONSTRAINEDSIZE) {
  4288. if (!nsLayoutUtils::IsAutoBSize(maxBSizeCoord, aCBSize.BSize(aWM)) &&
  4289. !(isFlexItem && !isInlineFlexItem)) {
  4290. nscoord maxBSize =
  4291. nsLayoutUtils::ComputeBSizeValue(aCBSize.BSize(aWM),
  4292. boxSizingAdjust.BSize(aWM),
  4293. maxBSizeCoord);
  4294. result.BSize(aWM) = std::min(maxBSize, result.BSize(aWM));
  4295. }
  4296. const nsStyleCoord& minBSizeCoord = stylePos->MinBSize(aWM);
  4297. if (!nsLayoutUtils::IsAutoBSize(minBSizeCoord, aCBSize.BSize(aWM)) &&
  4298. !(isFlexItem && !isInlineFlexItem)) {
  4299. nscoord minBSize =
  4300. nsLayoutUtils::ComputeBSizeValue(aCBSize.BSize(aWM),
  4301. boxSizingAdjust.BSize(aWM),
  4302. minBSizeCoord);
  4303. result.BSize(aWM) = std::max(minBSize, result.BSize(aWM));
  4304. }
  4305. }
  4306. const nsStyleDisplay *disp = StyleDisplay();
  4307. if (IsThemed(disp)) {
  4308. LayoutDeviceIntSize widget;
  4309. bool canOverride = true;
  4310. nsPresContext *presContext = PresContext();
  4311. presContext->GetTheme()->
  4312. GetMinimumWidgetSize(presContext, this, disp->mAppearance,
  4313. &widget, &canOverride);
  4314. // Convert themed widget's physical dimensions to logical coords
  4315. LogicalSize size(aWM,
  4316. nsSize(presContext->DevPixelsToAppUnits(widget.width),
  4317. presContext->DevPixelsToAppUnits(widget.height)));
  4318. // GMWS() returns border-box; we need content-box
  4319. size.ISize(aWM) -= aBorder.ISize(aWM) + aPadding.ISize(aWM);
  4320. size.BSize(aWM) -= aBorder.BSize(aWM) + aPadding.BSize(aWM);
  4321. if (size.BSize(aWM) > result.BSize(aWM) || !canOverride) {
  4322. result.BSize(aWM) = size.BSize(aWM);
  4323. }
  4324. if (size.ISize(aWM) > result.ISize(aWM) || !canOverride) {
  4325. result.ISize(aWM) = size.ISize(aWM);
  4326. }
  4327. }
  4328. result.ISize(aWM) = std::max(0, result.ISize(aWM));
  4329. result.BSize(aWM) = std::max(0, result.BSize(aWM));
  4330. return result;
  4331. }
  4332. LogicalSize
  4333. nsFrame::ComputeSizeWithIntrinsicDimensions(nsRenderingContext* aRenderingContext,
  4334. WritingMode aWM,
  4335. const IntrinsicSize& aIntrinsicSize,
  4336. const AspectRatio& aIntrinsicRatio,
  4337. const LogicalSize& aCBSize,
  4338. const LogicalSize& aMargin,
  4339. const LogicalSize& aBorder,
  4340. const LogicalSize& aPadding,
  4341. ComputeSizeFlags aFlags)
  4342. {
  4343. auto logicalRatio =
  4344. aWM.IsVertical() ? aIntrinsicRatio.Inverted() : aIntrinsicRatio;
  4345. const nsStylePosition* stylePos = StylePosition();
  4346. const nsStyleCoord* inlineStyleCoord = &stylePos->ISize(aWM);
  4347. const nsStyleCoord* blockStyleCoord = &stylePos->BSize(aWM);
  4348. const nsIAtom* parentFrameType =
  4349. GetParent() ? GetParent()->GetType() : nullptr;
  4350. const bool isGridItem = (parentFrameType == nsGkAtoms::gridContainerFrame &&
  4351. !(GetStateBits() & NS_FRAME_OUT_OF_FLOW));
  4352. const bool isFlexItem = (parentFrameType == nsGkAtoms::flexContainerFrame &&
  4353. !(GetStateBits() & NS_FRAME_OUT_OF_FLOW));
  4354. bool isInlineFlexItem = false;
  4355. Maybe<nsStyleCoord> imposedMainSizeStyleCoord;
  4356. // If this is a flex item, and we're measuring its cross size after flexing
  4357. // to resolve its main size, then we need to use the resolved main size
  4358. // that the container provides to us *instead of* the main-size coordinate
  4359. // from our style struct. (Otherwise, we'll be using an irrelevant value in
  4360. // the aspect-ratio calculations below.)
  4361. if (isFlexItem) {
  4362. uint32_t flexDirection =
  4363. GetParent()->StylePosition()->mFlexDirection;
  4364. isInlineFlexItem =
  4365. flexDirection == NS_STYLE_FLEX_DIRECTION_ROW ||
  4366. flexDirection == NS_STYLE_FLEX_DIRECTION_ROW_REVERSE;
  4367. // If FlexItemMainSizeOverride frame-property is set, then that means the
  4368. // flex container is imposing a main-size on this flex item for it to use
  4369. // as its size in the container's main axis.
  4370. bool didImposeMainSize;
  4371. nscoord imposedMainSize =
  4372. GetProperty(nsIFrame::FlexItemMainSizeOverride(), &didImposeMainSize);
  4373. if (didImposeMainSize) {
  4374. imposedMainSizeStyleCoord.emplace(imposedMainSize,
  4375. nsStyleCoord::CoordConstructor);
  4376. if (isInlineFlexItem) {
  4377. inlineStyleCoord = imposedMainSizeStyleCoord.ptr();
  4378. } else {
  4379. blockStyleCoord = imposedMainSizeStyleCoord.ptr();
  4380. }
  4381. } else {
  4382. // Flex items use their "flex-basis" property in place of their main-size
  4383. // property (e.g. "width") for sizing purposes, *unless* they have
  4384. // "flex-basis:auto", in which case they use their main-size property
  4385. // after all.
  4386. // NOTE: The logic here should match the similar chunk for determining
  4387. // inlineStyleCoord and blockStyleCoord in nsFrame::ComputeSize().
  4388. const nsStyleCoord* flexBasis = &(stylePos->mFlexBasis);
  4389. if (flexBasis->GetUnit() != eStyleUnit_Auto) {
  4390. if (isInlineFlexItem) {
  4391. inlineStyleCoord = flexBasis;
  4392. } else {
  4393. // One caveat for vertical flex items: We don't support enumerated
  4394. // values (e.g. "max-content") for height properties yet. So, if our
  4395. // computed flex-basis is an enumerated value, we'll just behave as if
  4396. // it were "auto", which means "use the main-size property after all"
  4397. // (which is "height", in this case).
  4398. // NOTE: Once we support intrinsic sizing keywords for "height",
  4399. // we should remove this check.
  4400. if (flexBasis->GetUnit() != eStyleUnit_Enumerated) {
  4401. blockStyleCoord = flexBasis;
  4402. }
  4403. }
  4404. }
  4405. }
  4406. }
  4407. // Handle intrinsic sizes and their interaction with
  4408. // {min-,max-,}{width,height} according to the rules in
  4409. // http://www.w3.org/TR/CSS21/visudet.html#min-max-widths
  4410. // Note: throughout the following section of the function, I avoid
  4411. // a * (b / c) because of its reduced accuracy relative to a * b / c
  4412. // or (a * b) / c (which are equivalent).
  4413. const bool isAutoISize = inlineStyleCoord->GetUnit() == eStyleUnit_Auto;
  4414. const bool isAutoBSize =
  4415. nsLayoutUtils::IsAutoBSize(*blockStyleCoord, aCBSize.BSize(aWM));
  4416. LogicalSize boxSizingAdjust(aWM);
  4417. if (stylePos->mBoxSizing == StyleBoxSizing::Border) {
  4418. boxSizingAdjust = aBorder + aPadding;
  4419. }
  4420. nscoord boxSizingToMarginEdgeISize =
  4421. aMargin.ISize(aWM) + aBorder.ISize(aWM) + aPadding.ISize(aWM) -
  4422. boxSizingAdjust.ISize(aWM);
  4423. nscoord iSize, minISize, maxISize, bSize, minBSize, maxBSize;
  4424. enum class Stretch {
  4425. // stretch to fill the CB (preserving intrinsic ratio) in the relevant axis
  4426. eStretchPreservingRatio,
  4427. // stretch to fill the CB in the relevant axis
  4428. eStretch,
  4429. // no stretching in the relevant axis
  4430. eNoStretch,
  4431. };
  4432. // just to avoid having to type these out everywhere:
  4433. const auto eStretchPreservingRatio = Stretch::eStretchPreservingRatio;
  4434. const auto eStretch = Stretch::eStretch;
  4435. const auto eNoStretch = Stretch::eNoStretch;
  4436. Stretch stretchI = eNoStretch; // stretch behavior in the inline axis
  4437. Stretch stretchB = eNoStretch; // stretch behavior in the block axis
  4438. if (!isAutoISize) {
  4439. iSize = ComputeISizeValue(aRenderingContext,
  4440. aCBSize.ISize(aWM), boxSizingAdjust.ISize(aWM),
  4441. boxSizingToMarginEdgeISize, *inlineStyleCoord, aFlags);
  4442. } else if (MOZ_UNLIKELY(isGridItem)) {
  4443. MOZ_ASSERT(!IS_TRUE_OVERFLOW_CONTAINER(this));
  4444. // 'auto' inline-size for grid-level box - apply 'stretch' as needed:
  4445. auto cbSize = aCBSize.ISize(aWM);
  4446. if (cbSize != NS_UNCONSTRAINEDSIZE) {
  4447. if (!StyleMargin()->HasInlineAxisAuto(aWM)) {
  4448. auto inlineAxisAlignment =
  4449. aWM.IsOrthogonalTo(GetParent()->GetWritingMode()) ?
  4450. stylePos->UsedAlignSelf(GetParent()->StyleContext()) :
  4451. stylePos->UsedJustifySelf(GetParent()->StyleContext());
  4452. if (inlineAxisAlignment == NS_STYLE_ALIGN_NORMAL) {
  4453. stretchI = eStretchPreservingRatio;
  4454. } else if (inlineAxisAlignment == NS_STYLE_ALIGN_STRETCH) {
  4455. stretchI = eStretch;
  4456. }
  4457. }
  4458. if (stretchI != eNoStretch ||
  4459. (aFlags & ComputeSizeFlags::eIClampMarginBoxMinSize)) {
  4460. iSize = std::max(nscoord(0), cbSize -
  4461. aPadding.ISize(aWM) -
  4462. aBorder.ISize(aWM) -
  4463. aMargin.ISize(aWM));
  4464. }
  4465. } else {
  4466. // Reset this flag to avoid applying the clamping below.
  4467. aFlags = ComputeSizeFlags(aFlags &
  4468. ~ComputeSizeFlags::eIClampMarginBoxMinSize);
  4469. }
  4470. }
  4471. const nsStyleCoord& maxISizeCoord = stylePos->MaxISize(aWM);
  4472. if (maxISizeCoord.GetUnit() != eStyleUnit_None &&
  4473. !(isFlexItem && isInlineFlexItem)) {
  4474. maxISize = ComputeISizeValue(aRenderingContext,
  4475. aCBSize.ISize(aWM), boxSizingAdjust.ISize(aWM),
  4476. boxSizingToMarginEdgeISize, maxISizeCoord, aFlags);
  4477. } else {
  4478. maxISize = nscoord_MAX;
  4479. }
  4480. // NOTE: Flex items ignore their min & max sizing properties in their
  4481. // flex container's main-axis. (Those properties get applied later in
  4482. // the flexbox algorithm.)
  4483. const nsStyleCoord& minISizeCoord = stylePos->MinISize(aWM);
  4484. if (minISizeCoord.GetUnit() != eStyleUnit_Auto &&
  4485. !(isFlexItem && isInlineFlexItem)) {
  4486. minISize = ComputeISizeValue(aRenderingContext,
  4487. aCBSize.ISize(aWM), boxSizingAdjust.ISize(aWM),
  4488. boxSizingToMarginEdgeISize, minISizeCoord, aFlags);
  4489. } else {
  4490. // Treat "min-width: auto" as 0.
  4491. // NOTE: Technically, "auto" is supposed to behave like "min-content" on
  4492. // flex items. However, we don't need to worry about that here, because
  4493. // flex items' min-sizes are intentionally ignored until the flex
  4494. // container explicitly considers them during space distribution.
  4495. minISize = 0;
  4496. }
  4497. if (!isAutoBSize) {
  4498. bSize = nsLayoutUtils::ComputeBSizeValue(aCBSize.BSize(aWM),
  4499. boxSizingAdjust.BSize(aWM),
  4500. *blockStyleCoord);
  4501. } else if (MOZ_UNLIKELY(isGridItem)) {
  4502. MOZ_ASSERT(!IS_TRUE_OVERFLOW_CONTAINER(this));
  4503. // 'auto' block-size for grid-level box - apply 'stretch' as needed:
  4504. auto cbSize = aCBSize.BSize(aWM);
  4505. if (cbSize != NS_AUTOHEIGHT) {
  4506. if (!StyleMargin()->HasBlockAxisAuto(aWM)) {
  4507. auto blockAxisAlignment =
  4508. !aWM.IsOrthogonalTo(GetParent()->GetWritingMode()) ?
  4509. stylePos->UsedAlignSelf(GetParent()->StyleContext()) :
  4510. stylePos->UsedJustifySelf(GetParent()->StyleContext());
  4511. if (blockAxisAlignment == NS_STYLE_ALIGN_NORMAL) {
  4512. stretchB = eStretchPreservingRatio;
  4513. } else if (blockAxisAlignment == NS_STYLE_ALIGN_STRETCH) {
  4514. stretchB = eStretch;
  4515. }
  4516. }
  4517. if (stretchB != eNoStretch ||
  4518. (aFlags & ComputeSizeFlags::eBClampMarginBoxMinSize)) {
  4519. bSize = std::max(nscoord(0), cbSize -
  4520. aPadding.BSize(aWM) -
  4521. aBorder.BSize(aWM) -
  4522. aMargin.BSize(aWM));
  4523. }
  4524. } else {
  4525. // Reset this flag to avoid applying the clamping below.
  4526. aFlags = ComputeSizeFlags(aFlags &
  4527. ~ComputeSizeFlags::eBClampMarginBoxMinSize);
  4528. }
  4529. }
  4530. const nsStyleCoord& maxBSizeCoord = stylePos->MaxBSize(aWM);
  4531. if (!nsLayoutUtils::IsAutoBSize(maxBSizeCoord, aCBSize.BSize(aWM)) &&
  4532. !(isFlexItem && !isInlineFlexItem)) {
  4533. maxBSize = nsLayoutUtils::ComputeBSizeValue(aCBSize.BSize(aWM),
  4534. boxSizingAdjust.BSize(aWM), maxBSizeCoord);
  4535. } else {
  4536. maxBSize = nscoord_MAX;
  4537. }
  4538. const nsStyleCoord& minBSizeCoord = stylePos->MinBSize(aWM);
  4539. if (!nsLayoutUtils::IsAutoBSize(minBSizeCoord, aCBSize.BSize(aWM)) &&
  4540. !(isFlexItem && !isInlineFlexItem)) {
  4541. minBSize = nsLayoutUtils::ComputeBSizeValue(aCBSize.BSize(aWM),
  4542. boxSizingAdjust.BSize(aWM), minBSizeCoord);
  4543. } else {
  4544. minBSize = 0;
  4545. }
  4546. // Resolve percentage intrinsic iSize/bSize as necessary:
  4547. NS_ASSERTION(aCBSize.ISize(aWM) != NS_UNCONSTRAINEDSIZE,
  4548. "Our containing block must not have unconstrained inline-size!");
  4549. const bool isVertical = aWM.IsVertical();
  4550. const nsStyleCoord& isizeCoord =
  4551. isVertical ? aIntrinsicSize.height : aIntrinsicSize.width;
  4552. const nsStyleCoord& bsizeCoord =
  4553. isVertical ? aIntrinsicSize.width : aIntrinsicSize.height;
  4554. bool hasIntrinsicISize, hasIntrinsicBSize;
  4555. nscoord intrinsicISize, intrinsicBSize;
  4556. if (isizeCoord.GetUnit() == eStyleUnit_Coord) {
  4557. hasIntrinsicISize = true;
  4558. intrinsicISize = isizeCoord.GetCoordValue();
  4559. if (intrinsicISize < 0)
  4560. intrinsicISize = 0;
  4561. } else {
  4562. NS_ASSERTION(isizeCoord.GetUnit() == eStyleUnit_None,
  4563. "unexpected unit");
  4564. hasIntrinsicISize = false;
  4565. intrinsicISize = 0;
  4566. }
  4567. if (bsizeCoord.GetUnit() == eStyleUnit_Coord) {
  4568. hasIntrinsicBSize = true;
  4569. intrinsicBSize = bsizeCoord.GetCoordValue();
  4570. if (intrinsicBSize < 0)
  4571. intrinsicBSize = 0;
  4572. } else {
  4573. NS_ASSERTION(bsizeCoord.GetUnit() == eStyleUnit_None,
  4574. "unexpected unit");
  4575. hasIntrinsicBSize = false;
  4576. intrinsicBSize = 0;
  4577. }
  4578. // Now calculate the used values for iSize and bSize:
  4579. if (isAutoISize) {
  4580. if (isAutoBSize) {
  4581. // 'auto' iSize, 'auto' bSize
  4582. // Get tentative values - CSS 2.1 sections 10.3.2 and 10.6.2:
  4583. nscoord tentISize, tentBSize;
  4584. if (hasIntrinsicISize) {
  4585. tentISize = intrinsicISize;
  4586. } else if (hasIntrinsicBSize && logicalRatio) {
  4587. tentISize = logicalRatio.ApplyTo(intrinsicBSize);
  4588. } else if (logicalRatio) {
  4589. tentISize = aCBSize.ISize(aWM) - boxSizingToMarginEdgeISize; // XXX scrollbar?
  4590. if (tentISize < 0) tentISize = 0;
  4591. } else {
  4592. tentISize = nsPresContext::CSSPixelsToAppUnits(300);
  4593. }
  4594. // If we need to clamp the inline size to fit the CB, we use the 'stretch'
  4595. // or 'normal' codepath. We use the ratio-preserving 'normal' codepath
  4596. // unless we have 'stretch' in the other axis.
  4597. if ((aFlags & ComputeSizeFlags::eIClampMarginBoxMinSize) &&
  4598. stretchI != eStretch && tentISize > iSize) {
  4599. stretchI = (stretchB == eStretch ? eStretch : eStretchPreservingRatio);
  4600. }
  4601. if (hasIntrinsicBSize) {
  4602. tentBSize = intrinsicBSize;
  4603. } else if (logicalRatio) {
  4604. tentBSize = logicalRatio.Inverted().ApplyTo(tentISize);
  4605. } else {
  4606. tentBSize = nsPresContext::CSSPixelsToAppUnits(150);
  4607. }
  4608. // (ditto the comment about clamping the inline size above)
  4609. if ((aFlags & ComputeSizeFlags::eBClampMarginBoxMinSize) &&
  4610. stretchB != eStretch && tentBSize > bSize) {
  4611. stretchB = (stretchI == eStretch ? eStretch : eStretchPreservingRatio);
  4612. }
  4613. if (logicalRatio) {
  4614. if (stretchI == eStretch) {
  4615. tentISize = iSize; // * / 'stretch'
  4616. if (stretchB == eStretch) {
  4617. tentBSize = bSize; // 'stretch' / 'stretch'
  4618. } else if (stretchB == eStretchPreservingRatio) {
  4619. // 'normal' / 'stretch'
  4620. tentBSize = logicalRatio.Inverted().ApplyTo(iSize);
  4621. }
  4622. } else if (stretchB == eStretch) {
  4623. tentBSize = bSize; // 'stretch' / * (except 'stretch')
  4624. if (stretchI == eStretchPreservingRatio) {
  4625. // 'stretch' / 'normal'
  4626. tentISize = logicalRatio.ApplyTo(bSize);
  4627. }
  4628. } else if (stretchI == eStretchPreservingRatio) {
  4629. tentISize = iSize; // * (except 'stretch') / 'normal'
  4630. tentBSize = logicalRatio.Inverted().ApplyTo(iSize);
  4631. if (stretchB == eStretchPreservingRatio && tentBSize > bSize) {
  4632. // Stretch within the CB size with preserved intrinsic ratio.
  4633. tentBSize = bSize; // 'normal' / 'normal'
  4634. tentISize = logicalRatio.ApplyTo(bSize);
  4635. }
  4636. } else if (stretchB == eStretchPreservingRatio) {
  4637. tentBSize = bSize; // 'normal' / * (except 'normal' and 'stretch')
  4638. tentISize = logicalRatio.ApplyTo(bSize);
  4639. }
  4640. }
  4641. // ComputeAutoSizeWithIntrinsicDimensions preserves the ratio when applying
  4642. // the min/max-size. We don't want that when we have 'stretch' in either
  4643. // axis because tentISize/tentBSize is likely not according to ratio now.
  4644. if (logicalRatio && stretchI != eStretch && stretchB != eStretch) {
  4645. nsSize autoSize = nsLayoutUtils::
  4646. ComputeAutoSizeWithIntrinsicDimensions(minISize, minBSize,
  4647. maxISize, maxBSize,
  4648. tentISize, tentBSize);
  4649. // The nsSize that ComputeAutoSizeWithIntrinsicDimensions returns will
  4650. // actually contain logical values if the parameters passed to it were
  4651. // logical coordinates, so we do NOT perform a physical-to-logical
  4652. // conversion here, but just assign the fields directly to our result.
  4653. iSize = autoSize.width;
  4654. bSize = autoSize.height;
  4655. } else {
  4656. // Not honoring an intrinsic ratio: clamp the dimensions independently.
  4657. iSize = NS_CSS_MINMAX(tentISize, minISize, maxISize);
  4658. bSize = NS_CSS_MINMAX(tentBSize, minBSize, maxBSize);
  4659. }
  4660. } else {
  4661. // 'auto' iSize, non-'auto' bSize
  4662. bSize = NS_CSS_MINMAX(bSize, minBSize, maxBSize);
  4663. if (stretchI != eStretch) {
  4664. if (logicalRatio) {
  4665. iSize = logicalRatio.ApplyTo(bSize);
  4666. } else if (hasIntrinsicISize) {
  4667. if (!((aFlags & ComputeSizeFlags::eIClampMarginBoxMinSize) &&
  4668. intrinsicISize > iSize)) {
  4669. iSize = intrinsicISize;
  4670. } // else - leave iSize as is to fill the CB
  4671. } else {
  4672. iSize = nsPresContext::CSSPixelsToAppUnits(300);
  4673. }
  4674. } // else - leave iSize as is to fill the CB
  4675. iSize = NS_CSS_MINMAX(iSize, minISize, maxISize);
  4676. }
  4677. } else {
  4678. if (isAutoBSize) {
  4679. // non-'auto' iSize, 'auto' bSize
  4680. iSize = NS_CSS_MINMAX(iSize, minISize, maxISize);
  4681. if (stretchB != eStretch) {
  4682. if (logicalRatio) {
  4683. bSize = logicalRatio.Inverted().ApplyTo(iSize);
  4684. } else if (hasIntrinsicBSize) {
  4685. if (!((aFlags & ComputeSizeFlags::eBClampMarginBoxMinSize) &&
  4686. intrinsicBSize > bSize)) {
  4687. bSize = intrinsicBSize;
  4688. } // else - leave bSize as is to fill the CB
  4689. } else {
  4690. bSize = nsPresContext::CSSPixelsToAppUnits(150);
  4691. }
  4692. } // else - leave bSize as is to fill the CB
  4693. bSize = NS_CSS_MINMAX(bSize, minBSize, maxBSize);
  4694. } else {
  4695. // non-'auto' iSize, non-'auto' bSize
  4696. iSize = NS_CSS_MINMAX(iSize, minISize, maxISize);
  4697. bSize = NS_CSS_MINMAX(bSize, minBSize, maxBSize);
  4698. }
  4699. }
  4700. return LogicalSize(aWM, iSize, bSize);
  4701. }
  4702. nsRect
  4703. nsIFrame::ComputeTightBounds(DrawTarget* aDrawTarget) const
  4704. {
  4705. return GetVisualOverflowRect();
  4706. }
  4707. nsRect
  4708. nsFrame::ComputeSimpleTightBounds(DrawTarget* aDrawTarget) const
  4709. {
  4710. if (StyleOutline()->mOutlineStyle != NS_STYLE_BORDER_STYLE_NONE ||
  4711. StyleBorder()->HasBorder() || !StyleBackground()->IsTransparent() ||
  4712. StyleDisplay()->mAppearance) {
  4713. // Not necessarily tight, due to clipping, negative
  4714. // outline-offset, and lots of other issues, but that's OK
  4715. return GetVisualOverflowRect();
  4716. }
  4717. nsRect r(0, 0, 0, 0);
  4718. ChildListIterator lists(this);
  4719. for (; !lists.IsDone(); lists.Next()) {
  4720. nsFrameList::Enumerator childFrames(lists.CurrentList());
  4721. for (; !childFrames.AtEnd(); childFrames.Next()) {
  4722. nsIFrame* child = childFrames.get();
  4723. r.UnionRect(r, child->ComputeTightBounds(aDrawTarget) + child->GetPosition());
  4724. }
  4725. }
  4726. return r;
  4727. }
  4728. /* virtual */ nsresult
  4729. nsIFrame::GetPrefWidthTightBounds(nsRenderingContext* aContext,
  4730. nscoord* aX,
  4731. nscoord* aXMost)
  4732. {
  4733. return NS_ERROR_NOT_IMPLEMENTED;
  4734. }
  4735. /* virtual */
  4736. LogicalSize
  4737. nsFrame::ComputeAutoSize(nsRenderingContext* aRenderingContext,
  4738. WritingMode aWM,
  4739. const mozilla::LogicalSize& aCBSize,
  4740. nscoord aAvailableISize,
  4741. const mozilla::LogicalSize& aMargin,
  4742. const mozilla::LogicalSize& aBorder,
  4743. const mozilla::LogicalSize& aPadding,
  4744. ComputeSizeFlags aFlags)
  4745. {
  4746. // Use basic shrink-wrapping as a default implementation.
  4747. LogicalSize result(aWM, 0xdeadbeef, NS_UNCONSTRAINEDSIZE);
  4748. // don't bother setting it if the result won't be used
  4749. if (StylePosition()->ISize(aWM).GetUnit() == eStyleUnit_Auto) {
  4750. nscoord availBased = aAvailableISize - aMargin.ISize(aWM) -
  4751. aBorder.ISize(aWM) - aPadding.ISize(aWM);
  4752. result.ISize(aWM) = ShrinkWidthToFit(aRenderingContext, availBased, aFlags);
  4753. }
  4754. return result;
  4755. }
  4756. nscoord
  4757. nsFrame::ShrinkWidthToFit(nsRenderingContext* aRenderingContext,
  4758. nscoord aISizeInCB,
  4759. ComputeSizeFlags aFlags)
  4760. {
  4761. // If we're a container for font size inflation, then shrink
  4762. // wrapping inside of us should not apply font size inflation.
  4763. AutoMaybeDisableFontInflation an(this);
  4764. nscoord result;
  4765. nscoord minISize = GetMinISize(aRenderingContext);
  4766. if (minISize > aISizeInCB) {
  4767. const bool clamp = aFlags & ComputeSizeFlags::eIClampMarginBoxMinSize;
  4768. result = MOZ_UNLIKELY(clamp) ? aISizeInCB : minISize;
  4769. } else {
  4770. nscoord prefISize = GetPrefISize(aRenderingContext);
  4771. if (prefISize > aISizeInCB) {
  4772. result = aISizeInCB;
  4773. } else {
  4774. result = prefISize;
  4775. }
  4776. }
  4777. return result;
  4778. }
  4779. nscoord
  4780. nsIFrame::ComputeISizeValue(nsRenderingContext* aRenderingContext,
  4781. nscoord aContainingBlockISize,
  4782. nscoord aContentEdgeToBoxSizing,
  4783. nscoord aBoxSizingToMarginEdge,
  4784. const nsStyleCoord& aCoord,
  4785. ComputeSizeFlags aFlags)
  4786. {
  4787. NS_PRECONDITION(aRenderingContext, "non-null rendering context expected");
  4788. LAYOUT_WARN_IF_FALSE(aContainingBlockISize != NS_UNCONSTRAINEDSIZE,
  4789. "have unconstrained inline-size; this should only result from "
  4790. "very large sizes, not attempts at intrinsic inline-size "
  4791. "calculation");
  4792. NS_PRECONDITION(aContainingBlockISize >= 0,
  4793. "inline-size less than zero");
  4794. nscoord result;
  4795. if (aCoord.IsCoordPercentCalcUnit()) {
  4796. result = nsRuleNode::ComputeCoordPercentCalc(aCoord,
  4797. aContainingBlockISize);
  4798. // The result of a calc() expression might be less than 0; we
  4799. // should clamp at runtime (below). (Percentages and coords that
  4800. // are less than 0 have already been dropped by the parser.)
  4801. result -= aContentEdgeToBoxSizing;
  4802. } else {
  4803. MOZ_ASSERT(eStyleUnit_Enumerated == aCoord.GetUnit());
  4804. // If 'this' is a container for font size inflation, then shrink
  4805. // wrapping inside of it should not apply font size inflation.
  4806. AutoMaybeDisableFontInflation an(this);
  4807. int32_t val = aCoord.GetIntValue();
  4808. switch (val) {
  4809. case NS_STYLE_WIDTH_MAX_CONTENT:
  4810. result = GetPrefISize(aRenderingContext);
  4811. NS_ASSERTION(result >= 0, "inline-size less than zero");
  4812. break;
  4813. case NS_STYLE_WIDTH_MIN_CONTENT:
  4814. result = GetMinISize(aRenderingContext);
  4815. NS_ASSERTION(result >= 0, "inline-size less than zero");
  4816. if (MOZ_UNLIKELY(aFlags & ComputeSizeFlags::eIClampMarginBoxMinSize)) {
  4817. auto available = aContainingBlockISize -
  4818. (aBoxSizingToMarginEdge + aContentEdgeToBoxSizing);
  4819. result = std::min(available, result);
  4820. }
  4821. break;
  4822. case NS_STYLE_WIDTH_FIT_CONTENT:
  4823. {
  4824. nscoord pref = GetPrefISize(aRenderingContext),
  4825. min = GetMinISize(aRenderingContext),
  4826. fill = aContainingBlockISize -
  4827. (aBoxSizingToMarginEdge + aContentEdgeToBoxSizing);
  4828. if (MOZ_UNLIKELY(aFlags & ComputeSizeFlags::eIClampMarginBoxMinSize)) {
  4829. min = std::min(min, fill);
  4830. }
  4831. result = std::max(min, std::min(pref, fill));
  4832. NS_ASSERTION(result >= 0, "inline-size less than zero");
  4833. }
  4834. break;
  4835. case NS_STYLE_WIDTH_AVAILABLE:
  4836. result = aContainingBlockISize -
  4837. (aBoxSizingToMarginEdge + aContentEdgeToBoxSizing);
  4838. }
  4839. }
  4840. return std::max(0, result);
  4841. }
  4842. void
  4843. nsFrame::DidReflow(nsPresContext* aPresContext,
  4844. const ReflowInput* aReflowInput,
  4845. nsDidReflowStatus aStatus)
  4846. {
  4847. NS_FRAME_TRACE_MSG(NS_FRAME_TRACE_CALLS,
  4848. ("nsFrame::DidReflow: aStatus=%d", static_cast<uint32_t>(aStatus)));
  4849. nsSVGEffects::InvalidateDirectRenderingObservers(this, nsSVGEffects::INVALIDATE_REFLOW);
  4850. if (nsDidReflowStatus::FINISHED == aStatus) {
  4851. mState &= ~(NS_FRAME_IN_REFLOW | NS_FRAME_FIRST_REFLOW | NS_FRAME_IS_DIRTY |
  4852. NS_FRAME_HAS_DIRTY_CHILDREN);
  4853. }
  4854. // Notify the percent bsize observer if there is a percent bsize.
  4855. // The observer may be able to initiate another reflow with a computed
  4856. // bsize. This happens in the case where a table cell has no computed
  4857. // bsize but can fabricate one when the cell bsize is known.
  4858. if (aReflowInput && aReflowInput->mPercentBSizeObserver &&
  4859. !GetPrevInFlow()) {
  4860. const nsStyleCoord &bsize =
  4861. aReflowInput->mStylePosition->BSize(aReflowInput->GetWritingMode());
  4862. if (bsize.HasPercent()) {
  4863. aReflowInput->mPercentBSizeObserver->NotifyPercentBSize(*aReflowInput);
  4864. }
  4865. }
  4866. aPresContext->ReflowedFrame();
  4867. }
  4868. void
  4869. nsFrame::FinishReflowWithAbsoluteFrames(nsPresContext* aPresContext,
  4870. ReflowOutput& aDesiredSize,
  4871. const ReflowInput& aReflowInput,
  4872. nsReflowStatus& aStatus,
  4873. bool aConstrainBSize)
  4874. {
  4875. ReflowAbsoluteFrames(aPresContext, aDesiredSize, aReflowInput, aStatus, aConstrainBSize);
  4876. FinishAndStoreOverflow(&aDesiredSize);
  4877. }
  4878. void
  4879. nsFrame::ReflowAbsoluteFrames(nsPresContext* aPresContext,
  4880. ReflowOutput& aDesiredSize,
  4881. const ReflowInput& aReflowInput,
  4882. nsReflowStatus& aStatus,
  4883. bool aConstrainBSize)
  4884. {
  4885. if (HasAbsolutelyPositionedChildren()) {
  4886. nsAbsoluteContainingBlock* absoluteContainer = GetAbsoluteContainingBlock();
  4887. // Let the absolutely positioned container reflow any absolutely positioned
  4888. // child frames that need to be reflowed
  4889. // The containing block for the abs pos kids is formed by our padding edge.
  4890. nsMargin usedBorder = GetUsedBorder();
  4891. nscoord containingBlockWidth =
  4892. std::max(0, aDesiredSize.Width() - usedBorder.LeftRight());
  4893. nscoord containingBlockHeight =
  4894. std::max(0, aDesiredSize.Height() - usedBorder.TopBottom());
  4895. nsContainerFrame* container = do_QueryFrame(this);
  4896. NS_ASSERTION(container, "Abs-pos children only supported on container frames for now");
  4897. nsRect containingBlock(0, 0, containingBlockWidth, containingBlockHeight);
  4898. AbsPosReflowFlags flags =
  4899. AbsPosReflowFlags::eCBWidthAndHeightChanged; // XXX could be optimized
  4900. if (aConstrainBSize) {
  4901. flags |= AbsPosReflowFlags::eConstrainHeight;
  4902. }
  4903. absoluteContainer->Reflow(container, aPresContext, aReflowInput, aStatus,
  4904. containingBlock, flags,
  4905. &aDesiredSize.mOverflowAreas);
  4906. }
  4907. }
  4908. void
  4909. nsFrame::PushDirtyBitToAbsoluteFrames()
  4910. {
  4911. if (!(GetStateBits() & NS_FRAME_IS_DIRTY)) {
  4912. return; // No dirty bit to push.
  4913. }
  4914. if (!HasAbsolutelyPositionedChildren()) {
  4915. return; // No absolute children to push to.
  4916. }
  4917. GetAbsoluteContainingBlock()->MarkAllFramesDirty();
  4918. }
  4919. /* virtual */ bool
  4920. nsFrame::CanContinueTextRun() const
  4921. {
  4922. // By default, a frame will *not* allow a text run to be continued
  4923. // through it.
  4924. return false;
  4925. }
  4926. void
  4927. nsFrame::Reflow(nsPresContext* aPresContext,
  4928. ReflowOutput& aDesiredSize,
  4929. const ReflowInput& aReflowInput,
  4930. nsReflowStatus& aStatus)
  4931. {
  4932. MarkInReflow();
  4933. DO_GLOBAL_REFLOW_COUNT("nsFrame");
  4934. aDesiredSize.ClearSize();
  4935. aStatus = NS_FRAME_COMPLETE;
  4936. NS_FRAME_SET_TRUNCATION(aStatus, aReflowInput, aDesiredSize);
  4937. }
  4938. nsresult
  4939. nsFrame::CharacterDataChanged(CharacterDataChangeInfo* aInfo)
  4940. {
  4941. NS_NOTREACHED("should only be called for text frames");
  4942. return NS_OK;
  4943. }
  4944. nsresult
  4945. nsFrame::AttributeChanged(int32_t aNameSpaceID,
  4946. nsIAtom* aAttribute,
  4947. int32_t aModType)
  4948. {
  4949. return NS_OK;
  4950. }
  4951. // Flow member functions
  4952. nsSplittableType
  4953. nsFrame::GetSplittableType() const
  4954. {
  4955. return NS_FRAME_NOT_SPLITTABLE;
  4956. }
  4957. nsIFrame* nsFrame::GetPrevContinuation() const
  4958. {
  4959. return nullptr;
  4960. }
  4961. void
  4962. nsFrame::SetPrevContinuation(nsIFrame* aPrevContinuation)
  4963. {
  4964. MOZ_ASSERT(false, "not splittable");
  4965. }
  4966. nsIFrame* nsFrame::GetNextContinuation() const
  4967. {
  4968. return nullptr;
  4969. }
  4970. void
  4971. nsFrame::SetNextContinuation(nsIFrame*)
  4972. {
  4973. MOZ_ASSERT(false, "not splittable");
  4974. }
  4975. nsIFrame* nsFrame::GetPrevInFlowVirtual() const
  4976. {
  4977. return nullptr;
  4978. }
  4979. void
  4980. nsFrame::SetPrevInFlow(nsIFrame* aPrevInFlow)
  4981. {
  4982. MOZ_ASSERT(false, "not splittable");
  4983. }
  4984. nsIFrame* nsFrame::GetNextInFlowVirtual() const
  4985. {
  4986. return nullptr;
  4987. }
  4988. void
  4989. nsFrame::SetNextInFlow(nsIFrame*)
  4990. {
  4991. MOZ_ASSERT(false, "not splittable");
  4992. }
  4993. nsIFrame* nsIFrame::GetTailContinuation()
  4994. {
  4995. nsIFrame* frame = this;
  4996. while (frame->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER) {
  4997. frame = frame->GetPrevContinuation();
  4998. NS_ASSERTION(frame, "first continuation can't be overflow container");
  4999. }
  5000. for (nsIFrame* next = frame->GetNextContinuation();
  5001. next && !(next->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER);
  5002. next = frame->GetNextContinuation()) {
  5003. frame = next;
  5004. }
  5005. NS_POSTCONDITION(frame, "illegal state in continuation chain.");
  5006. return frame;
  5007. }
  5008. NS_DECLARE_FRAME_PROPERTY_WITHOUT_DTOR(ViewProperty, nsView)
  5009. // Associated view object
  5010. nsView*
  5011. nsIFrame::GetView() const
  5012. {
  5013. // Check the frame state bit and see if the frame has a view
  5014. if (!(GetStateBits() & NS_FRAME_HAS_VIEW))
  5015. return nullptr;
  5016. // Check for a property on the frame
  5017. nsView* value = GetProperty(ViewProperty());
  5018. NS_ASSERTION(value, "frame state bit was set but frame has no view");
  5019. return value;
  5020. }
  5021. nsresult
  5022. nsIFrame::SetView(nsView* aView)
  5023. {
  5024. if (aView) {
  5025. aView->SetFrame(this);
  5026. #ifdef DEBUG
  5027. nsIAtom* frameType = GetType();
  5028. NS_ASSERTION(frameType == nsGkAtoms::scrollFrame ||
  5029. frameType == nsGkAtoms::subDocumentFrame ||
  5030. frameType == nsGkAtoms::listControlFrame ||
  5031. frameType == nsGkAtoms::objectFrame ||
  5032. frameType == nsGkAtoms::viewportFrame ||
  5033. frameType == nsGkAtoms::menuPopupFrame,
  5034. "Only specific frame types can have an nsView");
  5035. #endif
  5036. // Set a property on the frame
  5037. SetProperty(ViewProperty(), aView);
  5038. // Set the frame state bit that says the frame has a view
  5039. AddStateBits(NS_FRAME_HAS_VIEW);
  5040. // Let all of the ancestors know they have a descendant with a view.
  5041. for (nsIFrame* f = GetParent();
  5042. f && !(f->GetStateBits() & NS_FRAME_HAS_CHILD_WITH_VIEW);
  5043. f = f->GetParent())
  5044. f->AddStateBits(NS_FRAME_HAS_CHILD_WITH_VIEW);
  5045. }
  5046. return NS_OK;
  5047. }
  5048. // Find the first geometric parent that has a view
  5049. nsIFrame* nsIFrame::GetAncestorWithView() const
  5050. {
  5051. for (nsIFrame* f = GetParent(); nullptr != f; f = f->GetParent()) {
  5052. if (f->HasView()) {
  5053. return f;
  5054. }
  5055. }
  5056. return nullptr;
  5057. }
  5058. nsPoint nsIFrame::GetOffsetTo(const nsIFrame* aOther) const
  5059. {
  5060. NS_PRECONDITION(aOther,
  5061. "Must have frame for destination coordinate system!");
  5062. NS_ASSERTION(PresContext() == aOther->PresContext(),
  5063. "GetOffsetTo called on frames in different documents");
  5064. nsPoint offset(0, 0);
  5065. const nsIFrame* f;
  5066. for (f = this; f != aOther && f; f = f->GetParent()) {
  5067. offset += f->GetPosition();
  5068. }
  5069. if (f != aOther) {
  5070. // Looks like aOther wasn't an ancestor of |this|. So now we have
  5071. // the root-frame-relative position of |this| in |offset|. Convert back
  5072. // to the coordinates of aOther
  5073. while (aOther) {
  5074. offset -= aOther->GetPosition();
  5075. aOther = aOther->GetParent();
  5076. }
  5077. }
  5078. return offset;
  5079. }
  5080. nsPoint nsIFrame::GetOffsetToCrossDoc(const nsIFrame* aOther) const
  5081. {
  5082. return GetOffsetToCrossDoc(aOther, PresContext()->AppUnitsPerDevPixel());
  5083. }
  5084. nsPoint
  5085. nsIFrame::GetOffsetToCrossDoc(const nsIFrame* aOther, const int32_t aAPD) const
  5086. {
  5087. NS_PRECONDITION(aOther,
  5088. "Must have frame for destination coordinate system!");
  5089. NS_ASSERTION(PresContext()->GetRootPresContext() ==
  5090. aOther->PresContext()->GetRootPresContext(),
  5091. "trying to get the offset between frames in different document "
  5092. "hierarchies?");
  5093. if (PresContext()->GetRootPresContext() !=
  5094. aOther->PresContext()->GetRootPresContext()) {
  5095. // crash right away, we are almost certainly going to crash anyway.
  5096. NS_RUNTIMEABORT("trying to get the offset between frames in different "
  5097. "document hierarchies?");
  5098. }
  5099. const nsIFrame* root = nullptr;
  5100. // offset will hold the final offset
  5101. // docOffset holds the currently accumulated offset at the current APD, it
  5102. // will be converted and added to offset when the current APD changes.
  5103. nsPoint offset(0, 0), docOffset(0, 0);
  5104. const nsIFrame* f = this;
  5105. int32_t currAPD = PresContext()->AppUnitsPerDevPixel();
  5106. while (f && f != aOther) {
  5107. docOffset += f->GetPosition();
  5108. nsIFrame* parent = f->GetParent();
  5109. if (parent) {
  5110. f = parent;
  5111. } else {
  5112. nsPoint newOffset(0, 0);
  5113. root = f;
  5114. f = nsLayoutUtils::GetCrossDocParentFrame(f, &newOffset);
  5115. int32_t newAPD = f ? f->PresContext()->AppUnitsPerDevPixel() : 0;
  5116. if (!f || newAPD != currAPD) {
  5117. // Convert docOffset to the right APD and add it to offset.
  5118. offset += docOffset.ScaleToOtherAppUnits(currAPD, aAPD);
  5119. docOffset.x = docOffset.y = 0;
  5120. }
  5121. currAPD = newAPD;
  5122. docOffset += newOffset;
  5123. }
  5124. }
  5125. if (f == aOther) {
  5126. offset += docOffset.ScaleToOtherAppUnits(currAPD, aAPD);
  5127. } else {
  5128. // Looks like aOther wasn't an ancestor of |this|. So now we have
  5129. // the root-document-relative position of |this| in |offset|. Subtract the
  5130. // root-document-relative position of |aOther| from |offset|.
  5131. // This call won't try to recurse again because root is an ancestor of
  5132. // aOther.
  5133. nsPoint negOffset = aOther->GetOffsetToCrossDoc(root, aAPD);
  5134. offset -= negOffset;
  5135. }
  5136. return offset;
  5137. }
  5138. nsIntRect nsIFrame::GetScreenRect() const
  5139. {
  5140. return GetScreenRectInAppUnits().ToNearestPixels(PresContext()->AppUnitsPerCSSPixel());
  5141. }
  5142. nsRect nsIFrame::GetScreenRectInAppUnits() const
  5143. {
  5144. nsPresContext* presContext = PresContext();
  5145. nsIFrame* rootFrame =
  5146. presContext->PresShell()->FrameManager()->GetRootFrame();
  5147. nsPoint rootScreenPos(0, 0);
  5148. nsPoint rootFrameOffsetInParent(0, 0);
  5149. nsIFrame* rootFrameParent =
  5150. nsLayoutUtils::GetCrossDocParentFrame(rootFrame, &rootFrameOffsetInParent);
  5151. if (rootFrameParent) {
  5152. nsRect parentScreenRectAppUnits = rootFrameParent->GetScreenRectInAppUnits();
  5153. nsPresContext* parentPresContext = rootFrameParent->PresContext();
  5154. double parentScale = double(presContext->AppUnitsPerDevPixel())/
  5155. parentPresContext->AppUnitsPerDevPixel();
  5156. nsPoint rootPt = parentScreenRectAppUnits.TopLeft() + rootFrameOffsetInParent;
  5157. rootScreenPos.x = NS_round(parentScale*rootPt.x);
  5158. rootScreenPos.y = NS_round(parentScale*rootPt.y);
  5159. } else {
  5160. nsCOMPtr<nsIWidget> rootWidget;
  5161. presContext->PresShell()->GetViewManager()->GetRootWidget(getter_AddRefs(rootWidget));
  5162. if (rootWidget) {
  5163. LayoutDeviceIntPoint rootDevPx = rootWidget->WidgetToScreenOffset();
  5164. rootScreenPos.x = presContext->DevPixelsToAppUnits(rootDevPx.x);
  5165. rootScreenPos.y = presContext->DevPixelsToAppUnits(rootDevPx.y);
  5166. }
  5167. }
  5168. return nsRect(rootScreenPos + GetOffsetTo(rootFrame), GetSize());
  5169. }
  5170. // Returns the offset from this frame to the closest geometric parent that
  5171. // has a view. Also returns the containing view or null in case of error
  5172. void
  5173. nsIFrame::GetOffsetFromView(nsPoint& aOffset, nsView** aView) const
  5174. {
  5175. NS_PRECONDITION(nullptr != aView, "null OUT parameter pointer");
  5176. nsIFrame* frame = const_cast<nsIFrame*>(this);
  5177. *aView = nullptr;
  5178. aOffset.MoveTo(0, 0);
  5179. do {
  5180. aOffset += frame->GetPosition();
  5181. frame = frame->GetParent();
  5182. } while (frame && !frame->HasView());
  5183. if (frame) {
  5184. *aView = frame->GetView();
  5185. }
  5186. }
  5187. nsIWidget*
  5188. nsIFrame::GetNearestWidget() const
  5189. {
  5190. return GetClosestView()->GetNearestWidget(nullptr);
  5191. }
  5192. nsIWidget*
  5193. nsIFrame::GetNearestWidget(nsPoint& aOffset) const
  5194. {
  5195. nsPoint offsetToView;
  5196. nsPoint offsetToWidget;
  5197. nsIWidget* widget =
  5198. GetClosestView(&offsetToView)->GetNearestWidget(&offsetToWidget);
  5199. aOffset = offsetToView + offsetToWidget;
  5200. return widget;
  5201. }
  5202. nsIAtom*
  5203. nsFrame::GetType() const
  5204. {
  5205. return nullptr;
  5206. }
  5207. bool
  5208. nsIFrame::IsLeaf() const
  5209. {
  5210. return true;
  5211. }
  5212. Matrix4x4
  5213. nsIFrame::GetTransformMatrix(const nsIFrame* aStopAtAncestor,
  5214. nsIFrame** aOutAncestor)
  5215. {
  5216. NS_PRECONDITION(aOutAncestor, "Need a place to put the ancestor!");
  5217. /* If we're transformed, we want to hand back the combination
  5218. * transform/translate matrix that will apply our current transform, then
  5219. * shift us to our parent.
  5220. */
  5221. if (IsTransformed()) {
  5222. /* Compute the delta to the parent, which we need because we are converting
  5223. * coordinates to our parent.
  5224. */
  5225. NS_ASSERTION(nsLayoutUtils::GetCrossDocParentFrame(this),
  5226. "Cannot transform the viewport frame!");
  5227. int32_t scaleFactor = PresContext()->AppUnitsPerDevPixel();
  5228. Matrix4x4 result = nsDisplayTransform::GetResultingTransformMatrix(this,
  5229. nsPoint(0,0), scaleFactor,
  5230. nsDisplayTransform::INCLUDE_PERSPECTIVE|nsDisplayTransform::OFFSET_BY_ORIGIN,
  5231. nullptr);
  5232. *aOutAncestor = nsLayoutUtils::GetCrossDocParentFrame(this);
  5233. nsPoint delta = GetOffsetToCrossDoc(*aOutAncestor);
  5234. /* Combine the raw transform with a translation to our parent. */
  5235. result.PostTranslate(NSAppUnitsToFloatPixels(delta.x, scaleFactor),
  5236. NSAppUnitsToFloatPixels(delta.y, scaleFactor),
  5237. 0.0f);
  5238. return result;
  5239. }
  5240. if (nsLayoutUtils::IsPopup(this) &&
  5241. GetType() == nsGkAtoms::listControlFrame) {
  5242. nsPresContext* presContext = PresContext();
  5243. nsIFrame* docRootFrame = presContext->PresShell()->GetRootFrame();
  5244. // Compute a matrix that transforms from the popup widget to the toplevel
  5245. // widget. We use the widgets because they're the simplest and most
  5246. // accurate approach --- this should work no matter how the widget position
  5247. // was chosen.
  5248. nsIWidget* widget = GetView()->GetWidget();
  5249. nsPresContext* rootPresContext = PresContext()->GetRootPresContext();
  5250. // Maybe the widget hasn't been created yet? Popups without widgets are
  5251. // treated as regular frames. That should work since they'll be rendered
  5252. // as part of the page if they're rendered at all.
  5253. if (widget && rootPresContext) {
  5254. nsIWidget* toplevel = rootPresContext->GetNearestWidget();
  5255. if (toplevel) {
  5256. LayoutDeviceIntRect screenBounds = widget->GetClientBounds();
  5257. LayoutDeviceIntRect toplevelScreenBounds = toplevel->GetClientBounds();
  5258. LayoutDeviceIntPoint translation =
  5259. screenBounds.TopLeft() - toplevelScreenBounds.TopLeft();
  5260. Matrix4x4 transformToTop;
  5261. transformToTop._41 = translation.x;
  5262. transformToTop._42 = translation.y;
  5263. *aOutAncestor = docRootFrame;
  5264. Matrix4x4 docRootTransformToTop =
  5265. nsLayoutUtils::GetTransformToAncestor(docRootFrame, nullptr);
  5266. if (docRootTransformToTop.IsSingular()) {
  5267. NS_WARNING("Containing document is invisible, we can't compute a valid transform");
  5268. } else {
  5269. docRootTransformToTop.Invert();
  5270. return transformToTop * docRootTransformToTop;
  5271. }
  5272. }
  5273. }
  5274. }
  5275. *aOutAncestor = nsLayoutUtils::GetCrossDocParentFrame(this);
  5276. /* Otherwise, we're not transformed. In that case, we'll walk up the frame
  5277. * tree until we either hit the root frame or something that may be
  5278. * transformed. We'll then change coordinates into that frame, since we're
  5279. * guaranteed that nothing in-between can be transformed. First, however,
  5280. * we have to check to see if we have a parent. If not, we'll set the
  5281. * outparam to null (indicating that there's nothing left) and will hand back
  5282. * the identity matrix.
  5283. */
  5284. if (!*aOutAncestor)
  5285. return Matrix4x4();
  5286. /* Keep iterating while the frame can't possibly be transformed. */
  5287. while (!(*aOutAncestor)->IsTransformed() &&
  5288. !nsLayoutUtils::IsPopup(*aOutAncestor) &&
  5289. *aOutAncestor != aStopAtAncestor) {
  5290. /* If no parent, stop iterating. Otherwise, update the ancestor. */
  5291. nsIFrame* parent = nsLayoutUtils::GetCrossDocParentFrame(*aOutAncestor);
  5292. if (!parent)
  5293. break;
  5294. *aOutAncestor = parent;
  5295. }
  5296. NS_ASSERTION(*aOutAncestor, "Somehow ended up with a null ancestor...?");
  5297. /* Translate from this frame to our ancestor, if it exists. That's the
  5298. * entire transform, so we're done.
  5299. */
  5300. nsPoint delta = GetOffsetToCrossDoc(*aOutAncestor);
  5301. int32_t scaleFactor = PresContext()->AppUnitsPerDevPixel();
  5302. return Matrix4x4::Translation(NSAppUnitsToFloatPixels(delta.x, scaleFactor),
  5303. NSAppUnitsToFloatPixels(delta.y, scaleFactor),
  5304. 0.0f);
  5305. }
  5306. static void InvalidateRenderingObservers(nsIFrame* aFrame)
  5307. {
  5308. nsSVGEffects::InvalidateDirectRenderingObservers(aFrame);
  5309. nsIFrame* displayRoot = nsLayoutUtils::GetDisplayRootFrame(aFrame);
  5310. nsIFrame* parent = aFrame;
  5311. while (parent != displayRoot &&
  5312. (parent = nsLayoutUtils::GetCrossDocParentFrame(parent)) &&
  5313. !parent->HasAnyStateBits(NS_FRAME_DESCENDANT_NEEDS_PAINT)) {
  5314. nsSVGEffects::InvalidateDirectRenderingObservers(parent);
  5315. }
  5316. }
  5317. void
  5318. SchedulePaintInternal(nsIFrame* aFrame, nsIFrame::PaintType aType = nsIFrame::PAINT_DEFAULT)
  5319. {
  5320. nsIFrame* displayRoot = nsLayoutUtils::GetDisplayRootFrame(aFrame);
  5321. nsPresContext* pres = displayRoot->PresContext()->GetRootPresContext();
  5322. // No need to schedule a paint for an external document since they aren't
  5323. // painted directly.
  5324. if (!pres || (pres->Document() && pres->Document()->IsResourceDoc())) {
  5325. return;
  5326. }
  5327. if (!pres->GetContainerWeak()) {
  5328. NS_WARNING("Shouldn't call SchedulePaint in a detached pres context");
  5329. return;
  5330. }
  5331. pres->PresShell()->ScheduleViewManagerFlush(aType == nsIFrame::PAINT_DELAYED_COMPRESS ?
  5332. nsIPresShell::PAINT_DELAYED_COMPRESS :
  5333. nsIPresShell::PAINT_DEFAULT);
  5334. if (aType == nsIFrame::PAINT_DELAYED_COMPRESS) {
  5335. return;
  5336. }
  5337. if (aType == nsIFrame::PAINT_DEFAULT) {
  5338. displayRoot->AddStateBits(NS_FRAME_UPDATE_LAYER_TREE);
  5339. }
  5340. nsIPresShell* shell = aFrame->PresContext()->PresShell();
  5341. if (shell) {
  5342. shell->AddInvalidateHiddenPresShellObserver(pres->RefreshDriver());
  5343. }
  5344. }
  5345. static void InvalidateFrameInternal(nsIFrame *aFrame, bool aHasDisplayItem = true)
  5346. {
  5347. if (aHasDisplayItem) {
  5348. aFrame->AddStateBits(NS_FRAME_NEEDS_PAINT);
  5349. }
  5350. nsSVGEffects::InvalidateDirectRenderingObservers(aFrame);
  5351. bool needsSchedulePaint = false;
  5352. if (nsLayoutUtils::IsPopup(aFrame)) {
  5353. needsSchedulePaint = true;
  5354. } else {
  5355. nsIFrame *parent = nsLayoutUtils::GetCrossDocParentFrame(aFrame);
  5356. while (parent && !parent->HasAnyStateBits(NS_FRAME_DESCENDANT_NEEDS_PAINT)) {
  5357. if (aHasDisplayItem && !parent->HasAnyStateBits(NS_FRAME_IS_NONDISPLAY)) {
  5358. parent->AddStateBits(NS_FRAME_DESCENDANT_NEEDS_PAINT);
  5359. }
  5360. nsSVGEffects::InvalidateDirectRenderingObservers(parent);
  5361. // If we're inside a popup, then we need to make sure that we
  5362. // call schedule paint so that the NS_FRAME_UPDATE_LAYER_TREE
  5363. // flag gets added to the popup display root frame.
  5364. if (nsLayoutUtils::IsPopup(parent)) {
  5365. needsSchedulePaint = true;
  5366. break;
  5367. }
  5368. parent = nsLayoutUtils::GetCrossDocParentFrame(parent);
  5369. }
  5370. if (!parent) {
  5371. needsSchedulePaint = true;
  5372. }
  5373. }
  5374. if (!aHasDisplayItem) {
  5375. return;
  5376. }
  5377. if (needsSchedulePaint) {
  5378. SchedulePaintInternal(aFrame);
  5379. }
  5380. if (aFrame->HasAnyStateBits(NS_FRAME_HAS_INVALID_RECT)) {
  5381. aFrame->DeleteProperty(nsIFrame::InvalidationRect());
  5382. aFrame->RemoveStateBits(NS_FRAME_HAS_INVALID_RECT);
  5383. }
  5384. }
  5385. void
  5386. nsIFrame::InvalidateFrameSubtree(uint32_t aDisplayItemKey)
  5387. {
  5388. bool hasDisplayItem =
  5389. !aDisplayItemKey || FrameLayerBuilder::HasRetainedDataFor(this, aDisplayItemKey);
  5390. InvalidateFrame(aDisplayItemKey);
  5391. if (HasAnyStateBits(NS_FRAME_ALL_DESCENDANTS_NEED_PAINT) || !hasDisplayItem) {
  5392. return;
  5393. }
  5394. AddStateBits(NS_FRAME_ALL_DESCENDANTS_NEED_PAINT);
  5395. AutoTArray<nsIFrame::ChildList,4> childListArray;
  5396. GetCrossDocChildLists(&childListArray);
  5397. nsIFrame::ChildListArrayIterator lists(childListArray);
  5398. for (; !lists.IsDone(); lists.Next()) {
  5399. nsFrameList::Enumerator childFrames(lists.CurrentList());
  5400. for (; !childFrames.AtEnd(); childFrames.Next()) {
  5401. childFrames.get()->InvalidateFrameSubtree();
  5402. }
  5403. }
  5404. }
  5405. void
  5406. nsIFrame::ClearInvalidationStateBits()
  5407. {
  5408. if (HasAnyStateBits(NS_FRAME_DESCENDANT_NEEDS_PAINT)) {
  5409. AutoTArray<nsIFrame::ChildList,4> childListArray;
  5410. GetCrossDocChildLists(&childListArray);
  5411. nsIFrame::ChildListArrayIterator lists(childListArray);
  5412. for (; !lists.IsDone(); lists.Next()) {
  5413. nsFrameList::Enumerator childFrames(lists.CurrentList());
  5414. for (; !childFrames.AtEnd(); childFrames.Next()) {
  5415. childFrames.get()->ClearInvalidationStateBits();
  5416. }
  5417. }
  5418. }
  5419. RemoveStateBits(NS_FRAME_NEEDS_PAINT |
  5420. NS_FRAME_DESCENDANT_NEEDS_PAINT |
  5421. NS_FRAME_ALL_DESCENDANTS_NEED_PAINT);
  5422. }
  5423. void
  5424. nsIFrame::InvalidateFrame(uint32_t aDisplayItemKey)
  5425. {
  5426. bool hasDisplayItem =
  5427. !aDisplayItemKey || FrameLayerBuilder::HasRetainedDataFor(this, aDisplayItemKey);
  5428. InvalidateFrameInternal(this, hasDisplayItem);
  5429. }
  5430. void
  5431. nsIFrame::InvalidateFrameWithRect(const nsRect& aRect, uint32_t aDisplayItemKey)
  5432. {
  5433. bool hasDisplayItem =
  5434. !aDisplayItemKey || FrameLayerBuilder::HasRetainedDataFor(this, aDisplayItemKey);
  5435. bool alreadyInvalid = false;
  5436. if (!HasAnyStateBits(NS_FRAME_NEEDS_PAINT)) {
  5437. InvalidateFrameInternal(this, hasDisplayItem);
  5438. } else {
  5439. alreadyInvalid = true;
  5440. }
  5441. if (!hasDisplayItem) {
  5442. return;
  5443. }
  5444. nsRect* rect = GetProperty(InvalidationRect());
  5445. if (!rect) {
  5446. if (alreadyInvalid) {
  5447. return;
  5448. }
  5449. rect = new nsRect();
  5450. SetProperty(InvalidationRect(), rect);
  5451. AddStateBits(NS_FRAME_HAS_INVALID_RECT);
  5452. }
  5453. *rect = rect->Union(aRect);
  5454. }
  5455. /*static*/ uint8_t nsIFrame::sLayerIsPrerenderedDataKey;
  5456. static bool
  5457. DoesLayerHaveOutOfDateFrameMetrics(Layer* aLayer)
  5458. {
  5459. for (uint32_t i = 0; i < aLayer->GetScrollMetadataCount(); i++) {
  5460. const FrameMetrics& metrics = aLayer->GetFrameMetrics(i);
  5461. if (!metrics.IsScrollable()) {
  5462. continue;
  5463. }
  5464. nsIScrollableFrame* scrollableFrame =
  5465. nsLayoutUtils::FindScrollableFrameFor(metrics.GetScrollId());
  5466. if (!scrollableFrame) {
  5467. // This shouldn't happen, so let's do the safe thing and trigger a full
  5468. // paint if it does.
  5469. return true;
  5470. }
  5471. nsPoint scrollPosition = scrollableFrame->GetScrollPosition();
  5472. if (metrics.GetScrollOffset() != CSSPoint::FromAppUnits(scrollPosition)) {
  5473. return true;
  5474. }
  5475. }
  5476. return false;
  5477. }
  5478. static bool
  5479. DoesLayerOrAncestorsHaveOutOfDateFrameMetrics(Layer* aLayer)
  5480. {
  5481. for (Layer* layer = aLayer; layer; layer = layer->GetParent()) {
  5482. if (DoesLayerHaveOutOfDateFrameMetrics(layer)) {
  5483. return true;
  5484. }
  5485. }
  5486. return false;
  5487. }
  5488. bool
  5489. nsIFrame::TryUpdateTransformOnly(Layer** aLayerResult)
  5490. {
  5491. Layer* layer = FrameLayerBuilder::GetDedicatedLayer(
  5492. this, nsDisplayItem::TYPE_TRANSFORM);
  5493. if (!layer || !layer->HasUserData(LayerIsPrerenderedDataKey())) {
  5494. // If this layer isn't prerendered or we clip composites to our OS
  5495. // window, then we can't correctly optimize to an empty
  5496. // transaction in general.
  5497. return false;
  5498. }
  5499. if (DoesLayerOrAncestorsHaveOutOfDateFrameMetrics(layer)) {
  5500. // At least one scroll frame that can affect the position of this layer
  5501. // has changed its scroll offset since the last paint. Schedule a full
  5502. // paint to make sure that this layer's transform and all the frame
  5503. // metrics that affect it are in sync.
  5504. return false;
  5505. }
  5506. gfx::Matrix4x4 transform3d;
  5507. if (!nsLayoutUtils::GetLayerTransformForFrame(this, &transform3d)) {
  5508. // We're not able to compute a layer transform that we know would
  5509. // be used at the next layers transaction, so we can't only update
  5510. // the transform and will need to schedule an invalidating paint.
  5511. return false;
  5512. }
  5513. gfx::Matrix transform;
  5514. gfx::Matrix previousTransform;
  5515. // FIXME/bug 796690 and 796705: in general, changes to 3D
  5516. // transforms, or transform changes to properties other than
  5517. // translation, may lead us to choose a different rendering
  5518. // resolution for our layer. So if the transform is 3D or has a
  5519. // non-translation change, bail and schedule an invalidating paint.
  5520. // (We can often do better than this, for example for scale-down
  5521. // changes.)
  5522. static const gfx::Float kError = 0.0001f;
  5523. if (!transform3d.Is2D(&transform) ||
  5524. !layer->GetBaseTransform().Is2D(&previousTransform) ||
  5525. !gfx::FuzzyEqual(transform._11, previousTransform._11, kError) ||
  5526. !gfx::FuzzyEqual(transform._22, previousTransform._22, kError) ||
  5527. !gfx::FuzzyEqual(transform._21, previousTransform._21, kError) ||
  5528. !gfx::FuzzyEqual(transform._12, previousTransform._12, kError)) {
  5529. return false;
  5530. }
  5531. layer->SetBaseTransformForNextTransaction(transform3d);
  5532. *aLayerResult = layer;
  5533. return true;
  5534. }
  5535. bool
  5536. nsIFrame::IsInvalid(nsRect& aRect)
  5537. {
  5538. if (!HasAnyStateBits(NS_FRAME_NEEDS_PAINT)) {
  5539. return false;
  5540. }
  5541. if (HasAnyStateBits(NS_FRAME_HAS_INVALID_RECT)) {
  5542. nsRect* rect = GetProperty(InvalidationRect());
  5543. NS_ASSERTION(rect, "Must have an invalid rect if NS_FRAME_HAS_INVALID_RECT is set!");
  5544. aRect = *rect;
  5545. } else {
  5546. aRect.SetEmpty();
  5547. }
  5548. return true;
  5549. }
  5550. void
  5551. nsIFrame::SchedulePaint(PaintType aType)
  5552. {
  5553. InvalidateRenderingObservers(this);
  5554. SchedulePaintInternal(this, aType);
  5555. }
  5556. Layer*
  5557. nsIFrame::InvalidateLayer(uint32_t aDisplayItemKey,
  5558. const nsIntRect* aDamageRect,
  5559. const nsRect* aFrameDamageRect,
  5560. uint32_t aFlags /* = 0 */)
  5561. {
  5562. NS_ASSERTION(aDisplayItemKey > 0, "Need a key");
  5563. Layer* layer = FrameLayerBuilder::GetDedicatedLayer(this, aDisplayItemKey);
  5564. InvalidateRenderingObservers(this);
  5565. // If the layer is being updated asynchronously, and it's being forwarded
  5566. // to a compositor, then we don't need to invalidate.
  5567. if ((aFlags & UPDATE_IS_ASYNC) && layer &&
  5568. layer->Manager()->GetBackendType() == LayersBackend::LAYERS_CLIENT) {
  5569. return layer;
  5570. }
  5571. if (!layer) {
  5572. if (aFrameDamageRect && aFrameDamageRect->IsEmpty()) {
  5573. return nullptr;
  5574. }
  5575. // Plugins can transition from not rendering anything to rendering,
  5576. // and still only call this. So always invalidate, with specifying
  5577. // the display item type just in case.
  5578. //
  5579. // In the bug 930056, dialer app startup but not shown on the
  5580. // screen because sometimes we don't have any retainned data
  5581. // for remote type displayitem and thus Repaint event is not
  5582. // triggered. So, always invalidate here as well.
  5583. uint32_t displayItemKey = aDisplayItemKey;
  5584. if (aDisplayItemKey == nsDisplayItem::TYPE_PLUGIN ||
  5585. aDisplayItemKey == nsDisplayItem::TYPE_REMOTE) {
  5586. displayItemKey = 0;
  5587. }
  5588. if (aFrameDamageRect) {
  5589. InvalidateFrameWithRect(*aFrameDamageRect, displayItemKey);
  5590. } else {
  5591. InvalidateFrame(displayItemKey);
  5592. }
  5593. return nullptr;
  5594. }
  5595. if (aDamageRect && aDamageRect->IsEmpty()) {
  5596. return layer;
  5597. }
  5598. if (aDamageRect) {
  5599. layer->AddInvalidRect(*aDamageRect);
  5600. } else {
  5601. layer->SetInvalidRectToVisibleRegion();
  5602. }
  5603. SchedulePaintInternal(this, PAINT_COMPOSITE_ONLY);
  5604. return layer;
  5605. }
  5606. static nsRect
  5607. ComputeEffectsRect(nsIFrame* aFrame, const nsRect& aOverflowRect,
  5608. const nsSize& aNewSize)
  5609. {
  5610. nsRect r = aOverflowRect;
  5611. if (aFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT) {
  5612. // For SVG frames, we only need to account for filters.
  5613. // TODO: We could also take account of clipPath and mask to reduce the
  5614. // visual overflow, but that's not essential.
  5615. if (aFrame->StyleEffects()->HasFilters()) {
  5616. aFrame->SetProperty
  5617. (nsIFrame::PreEffectsBBoxProperty(), new nsRect(r));
  5618. r = nsSVGUtils::GetPostFilterVisualOverflowRect(aFrame, aOverflowRect);
  5619. }
  5620. return r;
  5621. }
  5622. // box-shadow
  5623. r.UnionRect(r, nsLayoutUtils::GetBoxShadowRectForFrame(aFrame, aNewSize));
  5624. // border-image-outset.
  5625. // We need to include border-image-outset because it can cause the
  5626. // border image to be drawn beyond the border box.
  5627. // (1) It's important we not check whether there's a border-image
  5628. // since the style hint for a change in border image doesn't cause
  5629. // reflow, and that's probably more important than optimizing the
  5630. // overflow areas for the silly case of border-image-outset without
  5631. // border-image
  5632. // (2) It's important that we not check whether the border-image
  5633. // is actually loaded, since that would require us to reflow when
  5634. // the image loads.
  5635. const nsStyleBorder* styleBorder = aFrame->StyleBorder();
  5636. nsMargin outsetMargin = styleBorder->GetImageOutset();
  5637. if (outsetMargin != nsMargin(0, 0, 0, 0)) {
  5638. nsRect outsetRect(nsPoint(0, 0), aNewSize);
  5639. outsetRect.Inflate(outsetMargin);
  5640. r.UnionRect(r, outsetRect);
  5641. }
  5642. // Note that we don't remove the outlineInnerRect if a frame loses outline
  5643. // style. That would require an extra property lookup for every frame,
  5644. // or a new frame state bit to track whether a property had been stored,
  5645. // or something like that. It's not worth doing that here. At most it's
  5646. // only one heap-allocated rect per frame and it will be cleaned up when
  5647. // the frame dies.
  5648. if (nsSVGIntegrationUtils::UsingEffectsForFrame(aFrame)) {
  5649. aFrame->SetProperty
  5650. (nsIFrame::PreEffectsBBoxProperty(), new nsRect(r));
  5651. r = nsSVGIntegrationUtils::ComputePostEffectsVisualOverflowRect(aFrame, r);
  5652. }
  5653. return r;
  5654. }
  5655. void
  5656. nsIFrame::MovePositionBy(const nsPoint& aTranslation)
  5657. {
  5658. nsPoint position = GetNormalPosition() + aTranslation;
  5659. const nsMargin* computedOffsets = nullptr;
  5660. if (IsRelativelyPositioned()) {
  5661. computedOffsets = GetProperty(nsIFrame::ComputedOffsetProperty());
  5662. }
  5663. ReflowInput::ApplyRelativePositioning(this, computedOffsets ?
  5664. *computedOffsets : nsMargin(),
  5665. &position);
  5666. SetPosition(position);
  5667. }
  5668. nsRect
  5669. nsIFrame::GetNormalRect() const
  5670. {
  5671. // It might be faster to first check
  5672. // StyleDisplay()->IsRelativelyPositionedStyle().
  5673. nsPoint* normalPosition = GetProperty(NormalPositionProperty());
  5674. if (normalPosition) {
  5675. return nsRect(*normalPosition, GetSize());
  5676. }
  5677. return GetRect();
  5678. }
  5679. nsPoint
  5680. nsIFrame::GetNormalPosition() const
  5681. {
  5682. // It might be faster to first check
  5683. // StyleDisplay()->IsRelativelyPositionedStyle().
  5684. nsPoint* normalPosition = GetProperty(NormalPositionProperty());
  5685. if (normalPosition) {
  5686. return *normalPosition;
  5687. }
  5688. return GetPosition();
  5689. }
  5690. nsPoint
  5691. nsIFrame::GetPositionIgnoringScrolling()
  5692. {
  5693. return GetParent() ? GetParent()->GetPositionOfChildIgnoringScrolling(this)
  5694. : GetPosition();
  5695. }
  5696. nsRect
  5697. nsIFrame::GetOverflowRect(nsOverflowType aType) const
  5698. {
  5699. MOZ_ASSERT(aType == eVisualOverflow || aType == eScrollableOverflow,
  5700. "unexpected type");
  5701. // Note that in some cases the overflow area might not have been
  5702. // updated (yet) to reflect any outline set on the frame or the area
  5703. // of child frames. That's OK because any reflow that updates these
  5704. // areas will invalidate the appropriate area, so any (mis)uses of
  5705. // this method will be fixed up.
  5706. if (mOverflow.mType == NS_FRAME_OVERFLOW_LARGE) {
  5707. // there is an overflow rect, and it's not stored as deltas but as
  5708. // a separately-allocated rect
  5709. return static_cast<nsOverflowAreas*>(const_cast<nsIFrame*>(this)->
  5710. GetOverflowAreasProperty())->Overflow(aType);
  5711. }
  5712. if (aType == eVisualOverflow &&
  5713. mOverflow.mType != NS_FRAME_OVERFLOW_NONE) {
  5714. return GetVisualOverflowFromDeltas();
  5715. }
  5716. return nsRect(nsPoint(0, 0), GetSize());
  5717. }
  5718. nsOverflowAreas
  5719. nsIFrame::GetOverflowAreas() const
  5720. {
  5721. if (mOverflow.mType == NS_FRAME_OVERFLOW_LARGE) {
  5722. // there is an overflow rect, and it's not stored as deltas but as
  5723. // a separately-allocated rect
  5724. return *const_cast<nsIFrame*>(this)->GetOverflowAreasProperty();
  5725. }
  5726. return nsOverflowAreas(GetVisualOverflowFromDeltas(),
  5727. nsRect(nsPoint(0, 0), GetSize()));
  5728. }
  5729. nsOverflowAreas
  5730. nsIFrame::GetOverflowAreasRelativeToSelf() const
  5731. {
  5732. if (IsTransformed()) {
  5733. nsOverflowAreas* preTransformOverflows =
  5734. GetProperty(PreTransformOverflowAreasProperty());
  5735. if (preTransformOverflows) {
  5736. return nsOverflowAreas(preTransformOverflows->VisualOverflow(),
  5737. preTransformOverflows->ScrollableOverflow());
  5738. }
  5739. }
  5740. return nsOverflowAreas(GetVisualOverflowRect(),
  5741. GetScrollableOverflowRect());
  5742. }
  5743. nsRect
  5744. nsIFrame::GetScrollableOverflowRectRelativeToParent() const
  5745. {
  5746. return GetScrollableOverflowRect() + mRect.TopLeft();
  5747. }
  5748. nsRect
  5749. nsIFrame::GetVisualOverflowRectRelativeToParent() const
  5750. {
  5751. return GetVisualOverflowRect() + mRect.TopLeft();
  5752. }
  5753. nsRect
  5754. nsIFrame::GetScrollableOverflowRectRelativeToSelf() const
  5755. {
  5756. if (IsTransformed()) {
  5757. nsOverflowAreas* preTransformOverflows =
  5758. GetProperty(PreTransformOverflowAreasProperty());
  5759. if (preTransformOverflows)
  5760. return preTransformOverflows->ScrollableOverflow();
  5761. }
  5762. return GetScrollableOverflowRect();
  5763. }
  5764. nsRect
  5765. nsIFrame::GetVisualOverflowRectRelativeToSelf() const
  5766. {
  5767. if (IsTransformed()) {
  5768. nsOverflowAreas* preTransformOverflows =
  5769. GetProperty(PreTransformOverflowAreasProperty());
  5770. if (preTransformOverflows)
  5771. return preTransformOverflows->VisualOverflow();
  5772. }
  5773. return GetVisualOverflowRect();
  5774. }
  5775. nsRect
  5776. nsIFrame::GetPreEffectsVisualOverflowRect() const
  5777. {
  5778. nsRect* r = GetProperty(nsIFrame::PreEffectsBBoxProperty());
  5779. return r ? *r : GetVisualOverflowRectRelativeToSelf();
  5780. }
  5781. bool
  5782. nsIFrame::UpdateOverflow()
  5783. {
  5784. MOZ_ASSERT(FrameMaintainsOverflow(),
  5785. "Non-display SVG do not maintain visual overflow rects");
  5786. nsRect rect(nsPoint(0, 0), GetSize());
  5787. nsOverflowAreas overflowAreas(rect, rect);
  5788. if (!ComputeCustomOverflow(overflowAreas)) {
  5789. return false;
  5790. }
  5791. UnionChildOverflow(overflowAreas);
  5792. if (FinishAndStoreOverflow(overflowAreas, GetSize())) {
  5793. nsView* view = GetView();
  5794. if (view) {
  5795. uint32_t flags = GetXULLayoutFlags();
  5796. if ((flags & NS_FRAME_NO_SIZE_VIEW) == 0) {
  5797. // Make sure the frame's view is properly sized.
  5798. nsViewManager* vm = view->GetViewManager();
  5799. vm->ResizeView(view, overflowAreas.VisualOverflow(), true);
  5800. }
  5801. }
  5802. return true;
  5803. }
  5804. return false;
  5805. }
  5806. /* virtual */ bool
  5807. nsFrame::ComputeCustomOverflow(nsOverflowAreas& aOverflowAreas)
  5808. {
  5809. return true;
  5810. }
  5811. /* virtual */ void
  5812. nsFrame::UnionChildOverflow(nsOverflowAreas& aOverflowAreas)
  5813. {
  5814. if (!DoesClipChildren() &&
  5815. !(IsXULCollapsed() && (IsXULBoxFrame() || ::IsXULBoxWrapped(this)))) {
  5816. nsLayoutUtils::UnionChildOverflow(this, aOverflowAreas);
  5817. }
  5818. }
  5819. // Define the MAX_FRAME_DEPTH to be the ContentSink's MAX_REFLOW_DEPTH plus
  5820. // 4 for the frames above the document's frames:
  5821. // the Viewport, GFXScroll, ScrollPort, and Canvas
  5822. #define MAX_FRAME_DEPTH (MAX_REFLOW_DEPTH+4)
  5823. bool
  5824. nsFrame::IsFrameTreeTooDeep(const ReflowInput& aReflowInput,
  5825. ReflowOutput& aMetrics,
  5826. nsReflowStatus& aStatus)
  5827. {
  5828. if (aReflowInput.mReflowDepth > MAX_FRAME_DEPTH) {
  5829. NS_WARNING("frame tree too deep; setting zero size and returning");
  5830. mState |= NS_FRAME_TOO_DEEP_IN_FRAME_TREE;
  5831. ClearOverflowRects();
  5832. aMetrics.ClearSize();
  5833. aMetrics.SetBlockStartAscent(0);
  5834. aMetrics.mCarriedOutBEndMargin.Zero();
  5835. aMetrics.mOverflowAreas.Clear();
  5836. if (GetNextInFlow()) {
  5837. // Reflow depth might vary between reflows, so we might have
  5838. // successfully reflowed and split this frame before. If so, we
  5839. // shouldn't delete its continuations.
  5840. aStatus = NS_FRAME_NOT_COMPLETE;
  5841. } else {
  5842. aStatus = NS_FRAME_COMPLETE;
  5843. }
  5844. return true;
  5845. }
  5846. mState &= ~NS_FRAME_TOO_DEEP_IN_FRAME_TREE;
  5847. return false;
  5848. }
  5849. bool
  5850. nsIFrame::IsBlockWrapper() const
  5851. {
  5852. nsIAtom *pseudoType = StyleContext()->GetPseudo();
  5853. return (pseudoType == nsCSSAnonBoxes::mozAnonymousBlock ||
  5854. pseudoType == nsCSSAnonBoxes::mozAnonymousPositionedBlock ||
  5855. pseudoType == nsCSSAnonBoxes::buttonContent ||
  5856. pseudoType == nsCSSAnonBoxes::cellContent);
  5857. }
  5858. static nsIFrame*
  5859. GetNearestBlockContainer(nsIFrame* frame)
  5860. {
  5861. // The block wrappers we use to wrap blocks inside inlines aren't
  5862. // described in the CSS spec. We need to make them not be containing
  5863. // blocks.
  5864. // Since the parent of such a block is either a normal block or
  5865. // another such pseudo, this shouldn't cause anything bad to happen.
  5866. // Also the anonymous blocks inside table cells are not containing blocks.
  5867. //
  5868. // If we ever start skipping table row groups from being containing blocks,
  5869. // we need to remove the containing block assignment in StickyScrollContainer .
  5870. while (frame->IsFrameOfType(nsIFrame::eLineParticipant) ||
  5871. frame->IsBlockWrapper() ||
  5872. // Table rows are not containing blocks either
  5873. frame->GetType() == nsGkAtoms::tableRowFrame) {
  5874. frame = frame->GetParent();
  5875. NS_ASSERTION(frame, "How come we got to the root frame without seeing a containing block?");
  5876. }
  5877. return frame;
  5878. }
  5879. nsIFrame*
  5880. nsIFrame::GetContainingBlock(uint32_t aFlags) const
  5881. {
  5882. if (!GetParent()) {
  5883. return nullptr;
  5884. }
  5885. // MathML frames might have absolute positioning style, but they would
  5886. // still be in-flow. So we have to check to make sure that the frame
  5887. // is really out-of-flow too.
  5888. nsIFrame* f;
  5889. if (IsAbsolutelyPositioned() &&
  5890. (GetStateBits() & NS_FRAME_OUT_OF_FLOW)) {
  5891. f = GetParent(); // the parent is always the containing block
  5892. } else {
  5893. f = GetNearestBlockContainer(GetParent());
  5894. }
  5895. if (aFlags & SKIP_SCROLLED_FRAME && f &&
  5896. f->StyleContext()->GetPseudo() == nsCSSAnonBoxes::scrolledContent) {
  5897. f = f->GetParent();
  5898. }
  5899. return f;
  5900. }
  5901. #ifdef DEBUG_FRAME_DUMP
  5902. int32_t nsFrame::ContentIndexInContainer(const nsIFrame* aFrame)
  5903. {
  5904. int32_t result = -1;
  5905. nsIContent* content = aFrame->GetContent();
  5906. if (content) {
  5907. nsIContent* parentContent = content->GetParent();
  5908. if (parentContent) {
  5909. result = parentContent->IndexOf(content);
  5910. }
  5911. }
  5912. return result;
  5913. }
  5914. /**
  5915. * List a frame tree to stderr. Meant to be called from gdb.
  5916. */
  5917. void
  5918. DebugListFrameTree(nsIFrame* aFrame)
  5919. {
  5920. ((nsFrame*)aFrame)->List(stderr);
  5921. }
  5922. void
  5923. nsIFrame::ListTag(nsACString& aTo) const
  5924. {
  5925. ListTag(aTo, this);
  5926. }
  5927. /* static */
  5928. void
  5929. nsIFrame::ListTag(nsACString& aTo, const nsIFrame* aFrame) {
  5930. nsAutoString tmp;
  5931. aFrame->GetFrameName(tmp);
  5932. aTo += NS_ConvertUTF16toUTF8(tmp).get();
  5933. aTo += nsPrintfCString("@%p", static_cast<const void*>(aFrame));
  5934. }
  5935. // Debugging
  5936. void
  5937. nsIFrame::ListGeneric(nsACString& aTo, const char* aPrefix, uint32_t aFlags) const
  5938. {
  5939. aTo =+ aPrefix;
  5940. ListTag(aTo);
  5941. if (HasView()) {
  5942. aTo += nsPrintfCString(" [view=%p]", static_cast<void*>(GetView()));
  5943. }
  5944. if (GetNextSibling()) {
  5945. aTo += nsPrintfCString(" next=%p", static_cast<void*>(GetNextSibling()));
  5946. }
  5947. if (GetPrevContinuation()) {
  5948. bool fluid = GetPrevInFlow() == GetPrevContinuation();
  5949. aTo += nsPrintfCString(" prev-%s=%p", fluid?"in-flow":"continuation",
  5950. static_cast<void*>(GetPrevContinuation()));
  5951. }
  5952. if (GetNextContinuation()) {
  5953. bool fluid = GetNextInFlow() == GetNextContinuation();
  5954. aTo += nsPrintfCString(" next-%s=%p", fluid?"in-flow":"continuation",
  5955. static_cast<void*>(GetNextContinuation()));
  5956. }
  5957. void* IBsibling = GetProperty(IBSplitSibling());
  5958. if (IBsibling) {
  5959. aTo += nsPrintfCString(" IBSplitSibling=%p", IBsibling);
  5960. }
  5961. void* IBprevsibling = GetProperty(IBSplitPrevSibling());
  5962. if (IBprevsibling) {
  5963. aTo += nsPrintfCString(" IBSplitPrevSibling=%p", IBprevsibling);
  5964. }
  5965. aTo += nsPrintfCString(" {%d,%d,%d,%d}", mRect.x, mRect.y, mRect.width, mRect.height);
  5966. mozilla::WritingMode wm = GetWritingMode();
  5967. if (wm.IsVertical() || !wm.IsBidiLTR()) {
  5968. aTo += nsPrintfCString(" wm=%s: logical size={%d,%d}", wm.DebugString(),
  5969. ISize(), BSize());
  5970. }
  5971. nsIFrame* parent = GetParent();
  5972. if (parent) {
  5973. WritingMode pWM = parent->GetWritingMode();
  5974. if (pWM.IsVertical() || !pWM.IsBidiLTR()) {
  5975. nsSize containerSize = parent->mRect.Size();
  5976. LogicalRect lr(pWM, mRect, containerSize);
  5977. aTo += nsPrintfCString(" parent wm=%s, cs={%d,%d}, "
  5978. " logicalRect={%d,%d,%d,%d}",
  5979. pWM.DebugString(),
  5980. containerSize.width, containerSize.height,
  5981. lr.IStart(pWM), lr.BStart(pWM),
  5982. lr.ISize(pWM), lr.BSize(pWM));
  5983. }
  5984. }
  5985. nsIFrame* f = const_cast<nsIFrame*>(this);
  5986. if (f->HasOverflowAreas()) {
  5987. nsRect vo = f->GetVisualOverflowRect();
  5988. if (!vo.IsEqualEdges(mRect)) {
  5989. aTo += nsPrintfCString(" vis-overflow=%d,%d,%d,%d", vo.x, vo.y, vo.width, vo.height);
  5990. }
  5991. nsRect so = f->GetScrollableOverflowRect();
  5992. if (!so.IsEqualEdges(mRect)) {
  5993. aTo += nsPrintfCString(" scr-overflow=%d,%d,%d,%d", so.x, so.y, so.width, so.height);
  5994. }
  5995. }
  5996. if (0 != mState) {
  5997. aTo += nsPrintfCString(" [state=%016llx]", (unsigned long long)mState);
  5998. }
  5999. if (IsTransformed()) {
  6000. aTo += nsPrintfCString(" transformed");
  6001. }
  6002. if (ChildrenHavePerspective()) {
  6003. aTo += nsPrintfCString(" perspective");
  6004. }
  6005. if (Extend3DContext()) {
  6006. aTo += nsPrintfCString(" preserves-3d-children");
  6007. }
  6008. if (Combines3DTransformWithAncestors()) {
  6009. aTo += nsPrintfCString(" preserves-3d");
  6010. }
  6011. if (mContent) {
  6012. aTo += nsPrintfCString(" [content=%p]", static_cast<void*>(mContent));
  6013. }
  6014. aTo += nsPrintfCString(" [sc=%p", static_cast<void*>(mStyleContext));
  6015. if (mStyleContext) {
  6016. nsIAtom* pseudoTag = mStyleContext->GetPseudo();
  6017. if (pseudoTag) {
  6018. nsAutoString atomString;
  6019. pseudoTag->ToString(atomString);
  6020. aTo += nsPrintfCString("%s", NS_LossyConvertUTF16toASCII(atomString).get());
  6021. }
  6022. if (!mStyleContext->GetParent() ||
  6023. (GetParent() && GetParent()->StyleContext() != mStyleContext->GetParent())) {
  6024. aTo += nsPrintfCString("^%p", mStyleContext->GetParent());
  6025. if (mStyleContext->GetParent()) {
  6026. aTo += nsPrintfCString("^%p", mStyleContext->GetParent()->GetParent());
  6027. if (mStyleContext->GetParent()->GetParent()) {
  6028. aTo += nsPrintfCString("^%p", mStyleContext->GetParent()->GetParent()->GetParent());
  6029. }
  6030. }
  6031. }
  6032. }
  6033. aTo += "]";
  6034. }
  6035. void
  6036. nsIFrame::List(FILE* out, const char* aPrefix, uint32_t aFlags) const
  6037. {
  6038. nsCString str;
  6039. ListGeneric(str, aPrefix, aFlags);
  6040. fprintf_stderr(out, "%s\n", str.get());
  6041. }
  6042. nsresult
  6043. nsFrame::GetFrameName(nsAString& aResult) const
  6044. {
  6045. return MakeFrameName(NS_LITERAL_STRING("Frame"), aResult);
  6046. }
  6047. nsresult
  6048. nsFrame::MakeFrameName(const nsAString& aType, nsAString& aResult) const
  6049. {
  6050. aResult = aType;
  6051. if (mContent && !mContent->IsNodeOfType(nsINode::eTEXT)) {
  6052. nsAutoString buf;
  6053. mContent->NodeInfo()->NameAtom()->ToString(buf);
  6054. if (GetType() == nsGkAtoms::subDocumentFrame) {
  6055. nsAutoString src;
  6056. mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::src, src);
  6057. buf.AppendLiteral(" src=");
  6058. buf.Append(src);
  6059. }
  6060. aResult.Append('(');
  6061. aResult.Append(buf);
  6062. aResult.Append(')');
  6063. }
  6064. char buf[40];
  6065. SprintfLiteral(buf, "(%d)", ContentIndexInContainer(this));
  6066. AppendASCIItoUTF16(buf, aResult);
  6067. return NS_OK;
  6068. }
  6069. void
  6070. nsIFrame::DumpFrameTree() const
  6071. {
  6072. RootFrameList(PresContext(), stderr);
  6073. }
  6074. void
  6075. nsIFrame::DumpFrameTreeLimited() const
  6076. {
  6077. List(stderr);
  6078. }
  6079. void
  6080. nsIFrame::RootFrameList(nsPresContext* aPresContext, FILE* out, const char* aPrefix)
  6081. {
  6082. if (!aPresContext || !out)
  6083. return;
  6084. nsIPresShell *shell = aPresContext->GetPresShell();
  6085. if (shell) {
  6086. nsIFrame* frame = shell->FrameManager()->GetRootFrame();
  6087. if(frame) {
  6088. frame->List(out, aPrefix);
  6089. }
  6090. }
  6091. }
  6092. #endif
  6093. #ifdef DEBUG
  6094. nsFrameState
  6095. nsFrame::GetDebugStateBits() const
  6096. {
  6097. // We'll ignore these flags for the purposes of comparing frame state:
  6098. //
  6099. // NS_FRAME_EXTERNAL_REFERENCE
  6100. // because this is set by the event state manager or the
  6101. // caret code when a frame is focused. Depending on whether
  6102. // or not the regression tests are run as the focused window
  6103. // will make this value vary randomly.
  6104. #define IRRELEVANT_FRAME_STATE_FLAGS NS_FRAME_EXTERNAL_REFERENCE
  6105. #define FRAME_STATE_MASK (~(IRRELEVANT_FRAME_STATE_FLAGS))
  6106. return GetStateBits() & FRAME_STATE_MASK;
  6107. }
  6108. void
  6109. nsFrame::XMLQuote(nsString& aString)
  6110. {
  6111. int32_t i, len = aString.Length();
  6112. for (i = 0; i < len; i++) {
  6113. char16_t ch = aString.CharAt(i);
  6114. if (ch == '<') {
  6115. nsAutoString tmp(NS_LITERAL_STRING("&lt;"));
  6116. aString.Cut(i, 1);
  6117. aString.Insert(tmp, i);
  6118. len += 3;
  6119. i += 3;
  6120. }
  6121. else if (ch == '>') {
  6122. nsAutoString tmp(NS_LITERAL_STRING("&gt;"));
  6123. aString.Cut(i, 1);
  6124. aString.Insert(tmp, i);
  6125. len += 3;
  6126. i += 3;
  6127. }
  6128. else if (ch == '\"') {
  6129. nsAutoString tmp(NS_LITERAL_STRING("&quot;"));
  6130. aString.Cut(i, 1);
  6131. aString.Insert(tmp, i);
  6132. len += 5;
  6133. i += 5;
  6134. }
  6135. }
  6136. }
  6137. #endif
  6138. bool
  6139. nsIFrame::IsVisibleForPainting(nsDisplayListBuilder* aBuilder) {
  6140. if (!StyleVisibility()->IsVisible())
  6141. return false;
  6142. nsISelection* sel = aBuilder->GetBoundingSelection();
  6143. return !sel || IsVisibleInSelection(sel);
  6144. }
  6145. bool
  6146. nsIFrame::IsVisibleForPainting() {
  6147. if (!StyleVisibility()->IsVisible())
  6148. return false;
  6149. nsPresContext* pc = PresContext();
  6150. if (!pc->IsRenderingOnlySelection())
  6151. return true;
  6152. nsCOMPtr<nsISelectionController> selcon(do_QueryInterface(pc->PresShell()));
  6153. if (selcon) {
  6154. nsCOMPtr<nsISelection> sel;
  6155. selcon->GetSelection(nsISelectionController::SELECTION_NORMAL,
  6156. getter_AddRefs(sel));
  6157. if (sel)
  6158. return IsVisibleInSelection(sel);
  6159. }
  6160. return true;
  6161. }
  6162. bool
  6163. nsIFrame::IsVisibleInSelection(nsDisplayListBuilder* aBuilder) {
  6164. nsISelection* sel = aBuilder->GetBoundingSelection();
  6165. return !sel || IsVisibleInSelection(sel);
  6166. }
  6167. bool
  6168. nsIFrame::IsVisibleOrCollapsedForPainting(nsDisplayListBuilder* aBuilder) {
  6169. if (!StyleVisibility()->IsVisibleOrCollapsed())
  6170. return false;
  6171. nsISelection* sel = aBuilder->GetBoundingSelection();
  6172. return !sel || IsVisibleInSelection(sel);
  6173. }
  6174. bool
  6175. nsIFrame::IsVisibleInSelection(nsISelection* aSelection)
  6176. {
  6177. if (!GetContent() || !GetContent()->IsSelectionDescendant()) {
  6178. return false;
  6179. }
  6180. nsCOMPtr<nsIDOMNode> node(do_QueryInterface(mContent));
  6181. bool vis;
  6182. nsresult rv = aSelection->ContainsNode(node, true, &vis);
  6183. return NS_FAILED(rv) || vis;
  6184. }
  6185. /* virtual */ bool
  6186. nsFrame::IsEmpty()
  6187. {
  6188. return false;
  6189. }
  6190. bool
  6191. nsIFrame::CachedIsEmpty()
  6192. {
  6193. NS_PRECONDITION(!(GetStateBits() & NS_FRAME_IS_DIRTY),
  6194. "Must only be called on reflowed lines");
  6195. return IsEmpty();
  6196. }
  6197. /* virtual */ bool
  6198. nsFrame::IsSelfEmpty()
  6199. {
  6200. return false;
  6201. }
  6202. nsresult
  6203. nsFrame::GetSelectionController(nsPresContext *aPresContext, nsISelectionController **aSelCon)
  6204. {
  6205. if (!aPresContext || !aSelCon)
  6206. return NS_ERROR_INVALID_ARG;
  6207. nsIFrame *frame = this;
  6208. while (frame && (frame->GetStateBits() & NS_FRAME_INDEPENDENT_SELECTION)) {
  6209. nsITextControlFrame *tcf = do_QueryFrame(frame);
  6210. if (tcf) {
  6211. return tcf->GetOwnedSelectionController(aSelCon);
  6212. }
  6213. frame = frame->GetParent();
  6214. }
  6215. return CallQueryInterface(aPresContext->GetPresShell(), aSelCon);
  6216. }
  6217. already_AddRefed<nsFrameSelection>
  6218. nsIFrame::GetFrameSelection()
  6219. {
  6220. RefPtr<nsFrameSelection> fs =
  6221. const_cast<nsFrameSelection*>(GetConstFrameSelection());
  6222. return fs.forget();
  6223. }
  6224. const nsFrameSelection*
  6225. nsIFrame::GetConstFrameSelection() const
  6226. {
  6227. nsIFrame* frame = const_cast<nsIFrame*>(this);
  6228. while (frame && (frame->GetStateBits() & NS_FRAME_INDEPENDENT_SELECTION)) {
  6229. nsITextControlFrame* tcf = do_QueryFrame(frame);
  6230. if (tcf) {
  6231. return tcf->GetOwnedFrameSelection();
  6232. }
  6233. frame = frame->GetParent();
  6234. }
  6235. return PresContext()->PresShell()->ConstFrameSelection();
  6236. }
  6237. #ifdef DEBUG
  6238. nsresult
  6239. nsFrame::DumpRegressionData(nsPresContext* aPresContext, FILE* out, int32_t aIndent)
  6240. {
  6241. IndentBy(out, aIndent);
  6242. fprintf(out, "<frame va=\"%p\" type=\"", (void*)this);
  6243. nsAutoString name;
  6244. GetFrameName(name);
  6245. XMLQuote(name);
  6246. fputs(NS_LossyConvertUTF16toASCII(name).get(), out);
  6247. fprintf(out, "\" state=\"%016llx\" parent=\"%p\">\n",
  6248. (unsigned long long)GetDebugStateBits(), (void*)GetParent());
  6249. aIndent++;
  6250. DumpBaseRegressionData(aPresContext, out, aIndent);
  6251. aIndent--;
  6252. IndentBy(out, aIndent);
  6253. fprintf(out, "</frame>\n");
  6254. return NS_OK;
  6255. }
  6256. void
  6257. nsFrame::DumpBaseRegressionData(nsPresContext* aPresContext, FILE* out, int32_t aIndent)
  6258. {
  6259. if (GetNextSibling()) {
  6260. IndentBy(out, aIndent);
  6261. fprintf(out, "<next-sibling va=\"%p\"/>\n", (void*)GetNextSibling());
  6262. }
  6263. if (HasView()) {
  6264. IndentBy(out, aIndent);
  6265. fprintf(out, "<view va=\"%p\">\n", (void*)GetView());
  6266. aIndent++;
  6267. // XXX add in code to dump out view state too...
  6268. aIndent--;
  6269. IndentBy(out, aIndent);
  6270. fprintf(out, "</view>\n");
  6271. }
  6272. IndentBy(out, aIndent);
  6273. fprintf(out, "<bbox x=\"%d\" y=\"%d\" w=\"%d\" h=\"%d\"/>\n",
  6274. mRect.x, mRect.y, mRect.width, mRect.height);
  6275. // Now dump all of the children on all of the child lists
  6276. ChildListIterator lists(this);
  6277. for (; !lists.IsDone(); lists.Next()) {
  6278. IndentBy(out, aIndent);
  6279. if (lists.CurrentID() != kPrincipalList) {
  6280. fprintf(out, "<child-list name=\"%s\">\n", mozilla::layout::ChildListName(lists.CurrentID()));
  6281. }
  6282. else {
  6283. fprintf(out, "<child-list>\n");
  6284. }
  6285. aIndent++;
  6286. nsFrameList::Enumerator childFrames(lists.CurrentList());
  6287. for (; !childFrames.AtEnd(); childFrames.Next()) {
  6288. nsIFrame* kid = childFrames.get();
  6289. kid->DumpRegressionData(aPresContext, out, aIndent);
  6290. }
  6291. aIndent--;
  6292. IndentBy(out, aIndent);
  6293. fprintf(out, "</child-list>\n");
  6294. }
  6295. }
  6296. #endif
  6297. bool
  6298. nsIFrame::IsFrameSelected() const
  6299. {
  6300. NS_ASSERTION(!GetContent() || GetContent()->IsSelectionDescendant(),
  6301. "use the public IsSelected() instead");
  6302. return nsRange::IsNodeSelected(GetContent(), 0,
  6303. GetContent()->GetChildCount());
  6304. }
  6305. nsresult
  6306. nsFrame::GetPointFromOffset(int32_t inOffset, nsPoint* outPoint)
  6307. {
  6308. NS_PRECONDITION(outPoint != nullptr, "Null parameter");
  6309. nsRect contentRect = GetContentRectRelativeToSelf();
  6310. nsPoint pt = contentRect.TopLeft();
  6311. if (mContent)
  6312. {
  6313. nsIContent* newContent = mContent->GetParent();
  6314. if (newContent){
  6315. int32_t newOffset = newContent->IndexOf(mContent);
  6316. // Find the direction of the frame from the EmbeddingLevelProperty,
  6317. // which is the resolved bidi level set in
  6318. // nsBidiPresUtils::ResolveParagraph (odd levels = right-to-left).
  6319. // If the embedding level isn't set, just use the CSS direction
  6320. // property.
  6321. bool hasBidiData;
  6322. FrameBidiData bidiData = GetProperty(BidiDataProperty(), &hasBidiData);
  6323. bool isRTL = hasBidiData
  6324. ? IS_LEVEL_RTL(bidiData.embeddingLevel)
  6325. : StyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL;
  6326. if ((!isRTL && inOffset > newOffset) ||
  6327. (isRTL && inOffset <= newOffset)) {
  6328. pt = contentRect.TopRight();
  6329. }
  6330. }
  6331. }
  6332. *outPoint = pt;
  6333. return NS_OK;
  6334. }
  6335. nsresult
  6336. nsFrame::GetCharacterRectsInRange(int32_t aInOffset, int32_t aLength,
  6337. nsTArray<nsRect>& aOutRect)
  6338. {
  6339. /* no text */
  6340. return NS_ERROR_FAILURE;
  6341. }
  6342. nsresult
  6343. nsFrame::GetChildFrameContainingOffset(int32_t inContentOffset, bool inHint, int32_t* outFrameContentOffset, nsIFrame **outChildFrame)
  6344. {
  6345. NS_PRECONDITION(outChildFrame && outFrameContentOffset, "Null parameter");
  6346. *outFrameContentOffset = (int32_t)inHint;
  6347. //the best frame to reflect any given offset would be a visible frame if possible
  6348. //i.e. we are looking for a valid frame to place the blinking caret
  6349. nsRect rect = GetRect();
  6350. if (!rect.width || !rect.height)
  6351. {
  6352. //if we have a 0 width or height then lets look for another frame that possibly has
  6353. //the same content. If we have no frames in flow then just let us return 'this' frame
  6354. nsIFrame* nextFlow = GetNextInFlow();
  6355. if (nextFlow)
  6356. return nextFlow->GetChildFrameContainingOffset(inContentOffset, inHint, outFrameContentOffset, outChildFrame);
  6357. }
  6358. *outChildFrame = this;
  6359. return NS_OK;
  6360. }
  6361. //
  6362. // What I've pieced together about this routine:
  6363. // Starting with a block frame (from which a line frame can be gotten)
  6364. // and a line number, drill down and get the first/last selectable
  6365. // frame on that line, depending on aPos->mDirection.
  6366. // aOutSideLimit != 0 means ignore aLineStart, instead work from
  6367. // the end (if > 0) or beginning (if < 0).
  6368. //
  6369. nsresult
  6370. nsFrame::GetNextPrevLineFromeBlockFrame(nsPresContext* aPresContext,
  6371. nsPeekOffsetStruct *aPos,
  6372. nsIFrame *aBlockFrame,
  6373. int32_t aLineStart,
  6374. int8_t aOutSideLimit
  6375. )
  6376. {
  6377. //magic numbers aLineStart will be -1 for end of block 0 will be start of block
  6378. if (!aBlockFrame || !aPos)
  6379. return NS_ERROR_NULL_POINTER;
  6380. aPos->mResultFrame = nullptr;
  6381. aPos->mResultContent = nullptr;
  6382. aPos->mAttach =
  6383. aPos->mDirection == eDirNext ? CARET_ASSOCIATE_AFTER : CARET_ASSOCIATE_BEFORE;
  6384. nsAutoLineIterator it = aBlockFrame->GetLineIterator();
  6385. if (!it)
  6386. return NS_ERROR_FAILURE;
  6387. int32_t searchingLine = aLineStart;
  6388. int32_t countLines = it->GetNumLines();
  6389. if (aOutSideLimit > 0) //start at end
  6390. searchingLine = countLines;
  6391. else if (aOutSideLimit <0)//start at beginning
  6392. searchingLine = -1;//"next" will be 0
  6393. else
  6394. if ((aPos->mDirection == eDirPrevious && searchingLine == 0) ||
  6395. (aPos->mDirection == eDirNext && searchingLine >= (countLines -1) )){
  6396. //we need to jump to new block frame.
  6397. return NS_ERROR_FAILURE;
  6398. }
  6399. int32_t lineFrameCount;
  6400. nsIFrame *resultFrame = nullptr;
  6401. nsIFrame *farStoppingFrame = nullptr; //we keep searching until we find a "this" frame then we go to next line
  6402. nsIFrame *nearStoppingFrame = nullptr; //if we are backing up from edge, stop here
  6403. nsIFrame *firstFrame;
  6404. nsIFrame *lastFrame;
  6405. nsRect rect;
  6406. bool isBeforeFirstFrame, isAfterLastFrame;
  6407. bool found = false;
  6408. nsresult result = NS_OK;
  6409. while (!found)
  6410. {
  6411. if (aPos->mDirection == eDirPrevious)
  6412. searchingLine --;
  6413. else
  6414. searchingLine ++;
  6415. if ((aPos->mDirection == eDirPrevious && searchingLine < 0) ||
  6416. (aPos->mDirection == eDirNext && searchingLine >= countLines ))
  6417. {
  6418. //we need to jump to new block frame.
  6419. return NS_ERROR_FAILURE;
  6420. }
  6421. result = it->GetLine(searchingLine, &firstFrame, &lineFrameCount,
  6422. rect);
  6423. if (!lineFrameCount)
  6424. continue;
  6425. if (NS_SUCCEEDED(result)){
  6426. lastFrame = firstFrame;
  6427. for (;lineFrameCount > 1;lineFrameCount --){
  6428. //result = lastFrame->GetNextSibling(&lastFrame, searchingLine);
  6429. result = it->GetNextSiblingOnLine(lastFrame, searchingLine);
  6430. if (NS_FAILED(result) || !lastFrame){
  6431. NS_ERROR("GetLine promised more frames than could be found");
  6432. return NS_ERROR_FAILURE;
  6433. }
  6434. }
  6435. GetLastLeaf(aPresContext, &lastFrame);
  6436. if (aPos->mDirection == eDirNext){
  6437. nearStoppingFrame = firstFrame;
  6438. farStoppingFrame = lastFrame;
  6439. }
  6440. else{
  6441. nearStoppingFrame = lastFrame;
  6442. farStoppingFrame = firstFrame;
  6443. }
  6444. nsPoint offset;
  6445. nsView * view; //used for call of get offset from view
  6446. aBlockFrame->GetOffsetFromView(offset,&view);
  6447. nsPoint newDesiredPos =
  6448. aPos->mDesiredPos - offset; //get desired position into blockframe coords
  6449. result = it->FindFrameAt(searchingLine, newDesiredPos, &resultFrame,
  6450. &isBeforeFirstFrame, &isAfterLastFrame);
  6451. if(NS_FAILED(result))
  6452. continue;
  6453. }
  6454. if (NS_SUCCEEDED(result) && resultFrame)
  6455. {
  6456. //check to see if this is ANOTHER blockframe inside the other one if so then call into its lines
  6457. nsAutoLineIterator newIt = resultFrame->GetLineIterator();
  6458. if (newIt)
  6459. {
  6460. aPos->mResultFrame = resultFrame;
  6461. return NS_OK;
  6462. }
  6463. //resultFrame is not a block frame
  6464. result = NS_ERROR_FAILURE;
  6465. nsCOMPtr<nsIFrameEnumerator> frameTraversal;
  6466. result = NS_NewFrameTraversal(getter_AddRefs(frameTraversal),
  6467. aPresContext, resultFrame,
  6468. ePostOrder,
  6469. false, // aVisual
  6470. aPos->mScrollViewStop,
  6471. false, // aFollowOOFs
  6472. false // aSkipPopupChecks
  6473. );
  6474. if (NS_FAILED(result))
  6475. return result;
  6476. nsIFrame *storeOldResultFrame = resultFrame;
  6477. while ( !found ){
  6478. nsPoint point;
  6479. nsRect tempRect = resultFrame->GetRect();
  6480. nsPoint offset;
  6481. nsView * view; //used for call of get offset from view
  6482. resultFrame->GetOffsetFromView(offset, &view);
  6483. if (!view) {
  6484. return NS_ERROR_FAILURE;
  6485. }
  6486. if (resultFrame->GetWritingMode().IsVertical()) {
  6487. point.y = aPos->mDesiredPos.y;
  6488. point.x = tempRect.width + offset.x;
  6489. } else {
  6490. point.y = tempRect.height + offset.y;
  6491. point.x = aPos->mDesiredPos.x;
  6492. }
  6493. //special check. if we allow non-text selection then we can allow a hit location to fall before a table.
  6494. //otherwise there is no way to get and click signal to fall before a table (it being a line iterator itself)
  6495. nsIPresShell *shell = aPresContext->GetPresShell();
  6496. if (!shell)
  6497. return NS_ERROR_FAILURE;
  6498. int16_t isEditor = shell->GetSelectionFlags();
  6499. isEditor = isEditor == nsISelectionDisplay::DISPLAY_ALL;
  6500. if ( isEditor )
  6501. {
  6502. if (resultFrame->GetType() == nsGkAtoms::tableWrapperFrame)
  6503. {
  6504. if (((point.x - offset.x + tempRect.x)<0) || ((point.x - offset.x+ tempRect.x)>tempRect.width))//off left/right side
  6505. {
  6506. nsIContent* content = resultFrame->GetContent();
  6507. if (content)
  6508. {
  6509. nsIContent* parent = content->GetParent();
  6510. if (parent)
  6511. {
  6512. aPos->mResultContent = parent;
  6513. aPos->mContentOffset = parent->IndexOf(content);
  6514. aPos->mAttach = CARET_ASSOCIATE_BEFORE;
  6515. if ((point.x - offset.x+ tempRect.x)>tempRect.width)
  6516. {
  6517. aPos->mContentOffset++;//go to end of this frame
  6518. aPos->mAttach = CARET_ASSOCIATE_AFTER;
  6519. }
  6520. //result frame is the result frames parent.
  6521. aPos->mResultFrame = resultFrame->GetParent();
  6522. return NS_POSITION_BEFORE_TABLE;
  6523. }
  6524. }
  6525. }
  6526. }
  6527. }
  6528. if (!resultFrame->HasView())
  6529. {
  6530. nsView* view;
  6531. nsPoint offset;
  6532. resultFrame->GetOffsetFromView(offset, &view);
  6533. ContentOffsets offsets =
  6534. resultFrame->GetContentOffsetsFromPoint(point - offset);
  6535. aPos->mResultContent = offsets.content;
  6536. aPos->mContentOffset = offsets.offset;
  6537. aPos->mAttach = offsets.associate;
  6538. if (offsets.content)
  6539. {
  6540. bool selectable;
  6541. resultFrame->IsSelectable(&selectable, nullptr);
  6542. if (selectable)
  6543. {
  6544. found = true;
  6545. break;
  6546. }
  6547. }
  6548. }
  6549. if (aPos->mDirection == eDirPrevious && (resultFrame == farStoppingFrame))
  6550. break;
  6551. if (aPos->mDirection == eDirNext && (resultFrame == nearStoppingFrame))
  6552. break;
  6553. //always try previous on THAT line if that fails go the other way
  6554. frameTraversal->Prev();
  6555. resultFrame = frameTraversal->CurrentItem();
  6556. if (!resultFrame)
  6557. return NS_ERROR_FAILURE;
  6558. }
  6559. if (!found){
  6560. resultFrame = storeOldResultFrame;
  6561. result = NS_NewFrameTraversal(getter_AddRefs(frameTraversal),
  6562. aPresContext, resultFrame,
  6563. eLeaf,
  6564. false, // aVisual
  6565. aPos->mScrollViewStop,
  6566. false, // aFollowOOFs
  6567. false // aSkipPopupChecks
  6568. );
  6569. }
  6570. while ( !found ){
  6571. nsPoint point = aPos->mDesiredPos;
  6572. nsView* view;
  6573. nsPoint offset;
  6574. resultFrame->GetOffsetFromView(offset, &view);
  6575. ContentOffsets offsets =
  6576. resultFrame->GetContentOffsetsFromPoint(point - offset);
  6577. aPos->mResultContent = offsets.content;
  6578. aPos->mContentOffset = offsets.offset;
  6579. aPos->mAttach = offsets.associate;
  6580. if (offsets.content)
  6581. {
  6582. bool selectable;
  6583. resultFrame->IsSelectable(&selectable, nullptr);
  6584. if (selectable)
  6585. {
  6586. found = true;
  6587. if (resultFrame == farStoppingFrame)
  6588. aPos->mAttach = CARET_ASSOCIATE_BEFORE;
  6589. else
  6590. aPos->mAttach = CARET_ASSOCIATE_AFTER;
  6591. break;
  6592. }
  6593. }
  6594. if (aPos->mDirection == eDirPrevious && (resultFrame == nearStoppingFrame))
  6595. break;
  6596. if (aPos->mDirection == eDirNext && (resultFrame == farStoppingFrame))
  6597. break;
  6598. //previous didnt work now we try "next"
  6599. frameTraversal->Next();
  6600. nsIFrame *tempFrame = frameTraversal->CurrentItem();
  6601. if (!tempFrame)
  6602. break;
  6603. resultFrame = tempFrame;
  6604. }
  6605. aPos->mResultFrame = resultFrame;
  6606. }
  6607. else {
  6608. //we need to jump to new block frame.
  6609. aPos->mAmount = eSelectLine;
  6610. aPos->mStartOffset = 0;
  6611. aPos->mAttach = aPos->mDirection == eDirNext ?
  6612. CARET_ASSOCIATE_BEFORE : CARET_ASSOCIATE_AFTER;
  6613. if (aPos->mDirection == eDirPrevious)
  6614. aPos->mStartOffset = -1;//start from end
  6615. return aBlockFrame->PeekOffset(aPos);
  6616. }
  6617. }
  6618. return NS_OK;
  6619. }
  6620. nsIFrame::CaretPosition
  6621. nsIFrame::GetExtremeCaretPosition(bool aStart)
  6622. {
  6623. CaretPosition result;
  6624. FrameTarget targetFrame = DrillDownToSelectionFrame(this, !aStart, 0);
  6625. FrameContentRange range = GetRangeForFrame(targetFrame.frame);
  6626. result.mResultContent = range.content;
  6627. result.mContentOffset = aStart ? range.start : range.end;
  6628. return result;
  6629. }
  6630. // Find the first (or last) descendant of the given frame
  6631. // which is either a block frame or a BRFrame.
  6632. static nsContentAndOffset
  6633. FindBlockFrameOrBR(nsIFrame* aFrame, nsDirection aDirection)
  6634. {
  6635. nsContentAndOffset result;
  6636. result.mContent = nullptr;
  6637. result.mOffset = 0;
  6638. if (aFrame->IsGeneratedContentFrame())
  6639. return result;
  6640. // Treat form controls as inline leaves
  6641. // XXX we really need a way to determine whether a frame is inline-level
  6642. nsIFormControlFrame* fcf = do_QueryFrame(aFrame);
  6643. if (fcf)
  6644. return result;
  6645. // Check the frame itself
  6646. // Fall through block-in-inline split frames because their mContent is
  6647. // the content of the inline frames they were created from. The
  6648. // first/last child of such frames is the real block frame we're
  6649. // looking for.
  6650. if ((nsLayoutUtils::GetAsBlock(aFrame) &&
  6651. !(aFrame->GetStateBits() & NS_FRAME_PART_OF_IBSPLIT)) ||
  6652. aFrame->GetType() == nsGkAtoms::brFrame) {
  6653. nsIContent* content = aFrame->GetContent();
  6654. result.mContent = content->GetParent();
  6655. // In some cases (bug 310589, bug 370174) we end up here with a null content.
  6656. // This probably shouldn't ever happen, but since it sometimes does, we want
  6657. // to avoid crashing here.
  6658. NS_ASSERTION(result.mContent, "Unexpected orphan content");
  6659. if (result.mContent)
  6660. result.mOffset = result.mContent->IndexOf(content) +
  6661. (aDirection == eDirPrevious ? 1 : 0);
  6662. return result;
  6663. }
  6664. // If this is a preformatted text frame, see if it ends with a newline
  6665. if (aFrame->HasSignificantTerminalNewline()) {
  6666. int32_t startOffset, endOffset;
  6667. aFrame->GetOffsets(startOffset, endOffset);
  6668. result.mContent = aFrame->GetContent();
  6669. result.mOffset = endOffset - (aDirection == eDirPrevious ? 0 : 1);
  6670. return result;
  6671. }
  6672. // Iterate over children and call ourselves recursively
  6673. if (aDirection == eDirPrevious) {
  6674. nsIFrame* child = aFrame->GetChildList(nsIFrame::kPrincipalList).LastChild();
  6675. while(child && !result.mContent) {
  6676. result = FindBlockFrameOrBR(child, aDirection);
  6677. child = child->GetPrevSibling();
  6678. }
  6679. } else { // eDirNext
  6680. nsIFrame* child = aFrame->PrincipalChildList().FirstChild();
  6681. while(child && !result.mContent) {
  6682. result = FindBlockFrameOrBR(child, aDirection);
  6683. child = child->GetNextSibling();
  6684. }
  6685. }
  6686. return result;
  6687. }
  6688. nsresult
  6689. nsIFrame::PeekOffsetParagraph(nsPeekOffsetStruct *aPos)
  6690. {
  6691. nsIFrame* frame = this;
  6692. nsContentAndOffset blockFrameOrBR;
  6693. blockFrameOrBR.mContent = nullptr;
  6694. bool reachedBlockAncestor = false;
  6695. // Go through containing frames until reaching a block frame.
  6696. // In each step, search the previous (or next) siblings for the closest
  6697. // "stop frame" (a block frame or a BRFrame).
  6698. // If found, set it to be the selection boundray and abort.
  6699. if (aPos->mDirection == eDirPrevious) {
  6700. while (!reachedBlockAncestor) {
  6701. nsIFrame* parent = frame->GetParent();
  6702. // Treat a frame associated with the root content as if it were a block frame.
  6703. if (!frame->mContent || !frame->mContent->GetParent()) {
  6704. reachedBlockAncestor = true;
  6705. break;
  6706. }
  6707. nsIFrame* sibling = frame->GetPrevSibling();
  6708. while (sibling && !blockFrameOrBR.mContent) {
  6709. blockFrameOrBR = FindBlockFrameOrBR(sibling, eDirPrevious);
  6710. sibling = sibling->GetPrevSibling();
  6711. }
  6712. if (blockFrameOrBR.mContent) {
  6713. aPos->mResultContent = blockFrameOrBR.mContent;
  6714. aPos->mContentOffset = blockFrameOrBR.mOffset;
  6715. break;
  6716. }
  6717. frame = parent;
  6718. reachedBlockAncestor = (nsLayoutUtils::GetAsBlock(frame) != nullptr);
  6719. }
  6720. if (reachedBlockAncestor) { // no "stop frame" found
  6721. aPos->mResultContent = frame->GetContent();
  6722. aPos->mContentOffset = 0;
  6723. }
  6724. } else { // eDirNext
  6725. while (!reachedBlockAncestor) {
  6726. nsIFrame* parent = frame->GetParent();
  6727. // Treat a frame associated with the root content as if it were a block frame.
  6728. if (!frame->mContent || !frame->mContent->GetParent()) {
  6729. reachedBlockAncestor = true;
  6730. break;
  6731. }
  6732. nsIFrame* sibling = frame;
  6733. while (sibling && !blockFrameOrBR.mContent) {
  6734. blockFrameOrBR = FindBlockFrameOrBR(sibling, eDirNext);
  6735. sibling = sibling->GetNextSibling();
  6736. }
  6737. if (blockFrameOrBR.mContent) {
  6738. aPos->mResultContent = blockFrameOrBR.mContent;
  6739. aPos->mContentOffset = blockFrameOrBR.mOffset;
  6740. break;
  6741. }
  6742. frame = parent;
  6743. reachedBlockAncestor = (nsLayoutUtils::GetAsBlock(frame) != nullptr);
  6744. }
  6745. if (reachedBlockAncestor) { // no "stop frame" found
  6746. aPos->mResultContent = frame->GetContent();
  6747. if (aPos->mResultContent)
  6748. aPos->mContentOffset = aPos->mResultContent->GetChildCount();
  6749. }
  6750. }
  6751. return NS_OK;
  6752. }
  6753. // Determine movement direction relative to frame
  6754. static bool IsMovingInFrameDirection(nsIFrame* frame, nsDirection aDirection, bool aVisual)
  6755. {
  6756. bool isReverseDirection = aVisual && IsReversedDirectionFrame(frame);
  6757. return aDirection == (isReverseDirection ? eDirPrevious : eDirNext);
  6758. }
  6759. nsresult
  6760. nsIFrame::PeekOffset(nsPeekOffsetStruct* aPos)
  6761. {
  6762. if (!aPos)
  6763. return NS_ERROR_NULL_POINTER;
  6764. nsresult result = NS_ERROR_FAILURE;
  6765. if (mState & NS_FRAME_IS_DIRTY)
  6766. return NS_ERROR_UNEXPECTED;
  6767. // Translate content offset to be relative to frame
  6768. FrameContentRange range = GetRangeForFrame(this);
  6769. int32_t offset = aPos->mStartOffset - range.start;
  6770. nsIFrame* current = this;
  6771. switch (aPos->mAmount) {
  6772. case eSelectCharacter:
  6773. case eSelectCluster:
  6774. {
  6775. bool eatingNonRenderableWS = false;
  6776. nsIFrame::FrameSearchResult peekSearchState = CONTINUE;
  6777. bool jumpedLine = false;
  6778. bool movedOverNonSelectableText = false;
  6779. while (peekSearchState != FOUND) {
  6780. bool movingInFrameDirection =
  6781. IsMovingInFrameDirection(current, aPos->mDirection, aPos->mVisual);
  6782. if (eatingNonRenderableWS)
  6783. peekSearchState = current->PeekOffsetNoAmount(movingInFrameDirection, &offset);
  6784. else
  6785. peekSearchState = current->PeekOffsetCharacter(movingInFrameDirection, &offset,
  6786. aPos->mAmount == eSelectCluster);
  6787. movedOverNonSelectableText |= (peekSearchState == CONTINUE_UNSELECTABLE);
  6788. if (peekSearchState != FOUND) {
  6789. bool movedOverNonSelectable = false;
  6790. result =
  6791. current->GetFrameFromDirection(aPos->mDirection, aPos->mVisual,
  6792. aPos->mJumpLines, aPos->mScrollViewStop,
  6793. &current, &offset, &jumpedLine,
  6794. &movedOverNonSelectable);
  6795. if (NS_FAILED(result))
  6796. return result;
  6797. // If we jumped lines, it's as if we found a character, but we still need
  6798. // to eat non-renderable content on the new line.
  6799. if (jumpedLine)
  6800. eatingNonRenderableWS = true;
  6801. // Remember if we moved over non-selectable text when finding another frame.
  6802. if (movedOverNonSelectable) {
  6803. movedOverNonSelectableText = true;
  6804. }
  6805. }
  6806. // Found frame, but because we moved over non selectable text we want the offset
  6807. // to be at the frame edge. Note that if we are extending the selection, this
  6808. // doesn't matter.
  6809. if (peekSearchState == FOUND && movedOverNonSelectableText &&
  6810. !aPos->mExtend)
  6811. {
  6812. int32_t start, end;
  6813. current->GetOffsets(start, end);
  6814. offset = aPos->mDirection == eDirNext ? 0 : end - start;
  6815. }
  6816. }
  6817. // Set outputs
  6818. range = GetRangeForFrame(current);
  6819. aPos->mResultFrame = current;
  6820. aPos->mResultContent = range.content;
  6821. // Output offset is relative to content, not frame
  6822. aPos->mContentOffset = offset < 0 ? range.end : range.start + offset;
  6823. // If we're dealing with a text frame and moving backward positions us at
  6824. // the end of that line, decrease the offset by one to make sure that
  6825. // we're placed before the linefeed character on the previous line.
  6826. if (offset < 0 && jumpedLine &&
  6827. aPos->mDirection == eDirPrevious &&
  6828. current->HasSignificantTerminalNewline()) {
  6829. --aPos->mContentOffset;
  6830. }
  6831. break;
  6832. }
  6833. case eSelectWordNoSpace:
  6834. // eSelectWordNoSpace means that we should not be eating any whitespace when
  6835. // moving to the adjacent word. This means that we should set aPos->
  6836. // mWordMovementType to eEndWord if we're moving forwards, and to eStartWord
  6837. // if we're moving backwards.
  6838. if (aPos->mDirection == eDirPrevious) {
  6839. aPos->mWordMovementType = eStartWord;
  6840. } else {
  6841. aPos->mWordMovementType = eEndWord;
  6842. }
  6843. // Intentionally fall through the eSelectWord case.
  6844. MOZ_FALLTHROUGH;
  6845. case eSelectWord:
  6846. {
  6847. // wordSelectEatSpace means "are we looking for a boundary between whitespace
  6848. // and non-whitespace (in the direction we're moving in)".
  6849. // It is true when moving forward and looking for a beginning of a word, or
  6850. // when moving backwards and looking for an end of a word.
  6851. bool wordSelectEatSpace;
  6852. if (aPos->mWordMovementType != eDefaultBehavior) {
  6853. // aPos->mWordMovementType possible values:
  6854. // eEndWord: eat the space if we're moving backwards
  6855. // eStartWord: eat the space if we're moving forwards
  6856. wordSelectEatSpace = ((aPos->mWordMovementType == eEndWord) == (aPos->mDirection == eDirPrevious));
  6857. }
  6858. else {
  6859. // Use the hidden preference which is based on operating system behavior.
  6860. // This pref only affects whether moving forward by word should go to the end of this word or start of the next word.
  6861. // When going backwards, the start of the word is always used, on every operating system.
  6862. wordSelectEatSpace = aPos->mDirection == eDirNext &&
  6863. Preferences::GetBool("layout.word_select.eat_space_to_next_word");
  6864. }
  6865. // mSawBeforeType means "we already saw characters of the type
  6866. // before the boundary we're looking for". Examples:
  6867. // 1. If we're moving forward, looking for a word beginning (i.e. a boundary
  6868. // between whitespace and non-whitespace), then eatingWS==true means
  6869. // "we already saw some whitespace".
  6870. // 2. If we're moving backward, looking for a word beginning (i.e. a boundary
  6871. // between non-whitespace and whitespace), then eatingWS==true means
  6872. // "we already saw some non-whitespace".
  6873. PeekWordState state;
  6874. int32_t offsetAdjustment = 0;
  6875. bool done = false;
  6876. while (!done) {
  6877. bool movingInFrameDirection =
  6878. IsMovingInFrameDirection(current, aPos->mDirection, aPos->mVisual);
  6879. done = current->PeekOffsetWord(movingInFrameDirection, wordSelectEatSpace,
  6880. aPos->mIsKeyboardSelect, &offset, &state) == FOUND;
  6881. if (!done) {
  6882. nsIFrame* nextFrame;
  6883. int32_t nextFrameOffset;
  6884. bool jumpedLine, movedOverNonSelectableText;
  6885. result =
  6886. current->GetFrameFromDirection(aPos->mDirection, aPos->mVisual,
  6887. aPos->mJumpLines, aPos->mScrollViewStop,
  6888. &nextFrame, &nextFrameOffset, &jumpedLine,
  6889. &movedOverNonSelectableText);
  6890. // We can't jump lines if we're looking for whitespace following
  6891. // non-whitespace, and we already encountered non-whitespace.
  6892. if (NS_FAILED(result) ||
  6893. (jumpedLine && !wordSelectEatSpace && state.mSawBeforeType)) {
  6894. done = true;
  6895. // If we've crossed the line boundary, check to make sure that we
  6896. // have not consumed a trailing newline as whitesapce if it's significant.
  6897. if (jumpedLine && wordSelectEatSpace &&
  6898. current->HasSignificantTerminalNewline()) {
  6899. offsetAdjustment = -1;
  6900. }
  6901. } else {
  6902. if (jumpedLine) {
  6903. state.mContext.Truncate();
  6904. }
  6905. current = nextFrame;
  6906. offset = nextFrameOffset;
  6907. // Jumping a line is equivalent to encountering whitespace
  6908. if (wordSelectEatSpace && jumpedLine)
  6909. state.SetSawBeforeType();
  6910. }
  6911. }
  6912. }
  6913. // Set outputs
  6914. range = GetRangeForFrame(current);
  6915. aPos->mResultFrame = current;
  6916. aPos->mResultContent = range.content;
  6917. // Output offset is relative to content, not frame
  6918. aPos->mContentOffset = (offset < 0 ? range.end : range.start + offset) + offsetAdjustment;
  6919. break;
  6920. }
  6921. case eSelectLine :
  6922. {
  6923. nsAutoLineIterator iter;
  6924. nsIFrame *blockFrame = this;
  6925. while (NS_FAILED(result)){
  6926. int32_t thisLine = nsFrame::GetLineNumber(blockFrame, aPos->mScrollViewStop, &blockFrame);
  6927. if (thisLine < 0)
  6928. return NS_ERROR_FAILURE;
  6929. iter = blockFrame->GetLineIterator();
  6930. NS_ASSERTION(iter, "GetLineNumber() succeeded but no block frame?");
  6931. result = NS_OK;
  6932. int edgeCase = 0; // no edge case. this should look at thisLine
  6933. bool doneLooping = false; // tells us when no more block frames hit.
  6934. // this part will find a frame or a block frame. if it's a block frame
  6935. // it will "drill down" to find a viable frame or it will return an error.
  6936. nsIFrame *lastFrame = this;
  6937. do {
  6938. result = nsFrame::GetNextPrevLineFromeBlockFrame(PresContext(),
  6939. aPos,
  6940. blockFrame,
  6941. thisLine,
  6942. edgeCase); // start from thisLine
  6943. // we came back to same spot! keep going
  6944. if (NS_SUCCEEDED(result) &&
  6945. (!aPos->mResultFrame || aPos->mResultFrame == lastFrame)) {
  6946. aPos->mResultFrame = nullptr;
  6947. if (aPos->mDirection == eDirPrevious)
  6948. thisLine--;
  6949. else
  6950. thisLine++;
  6951. } else // if failure or success with different frame.
  6952. doneLooping = true; // do not continue with while loop
  6953. lastFrame = aPos->mResultFrame; // set last frame
  6954. // make sure block element is not the same as the one we had before
  6955. if (NS_SUCCEEDED(result) &&
  6956. aPos->mResultFrame &&
  6957. blockFrame != aPos->mResultFrame) {
  6958. /* SPECIAL CHECK FOR TABLE NAVIGATION
  6959. tables need to navigate also and the frame that supports it is
  6960. nsTableRowGroupFrame which is INSIDE nsTableWrapperFrame.
  6961. If we have stumbled onto an nsTableWrapperFrame we need to drill
  6962. into nsTableRowGroup if we hit a header or footer that's ok just
  6963. go into them.
  6964. */
  6965. bool searchTableBool = false;
  6966. if (aPos->mResultFrame->GetType() == nsGkAtoms::tableWrapperFrame ||
  6967. aPos->mResultFrame->GetType() == nsGkAtoms::tableCellFrame) {
  6968. nsIFrame* frame = aPos->mResultFrame->PrincipalChildList().FirstChild();
  6969. // got the table frame now
  6970. // ok time to drill down to find iterator
  6971. while (frame) {
  6972. iter = frame->GetLineIterator();
  6973. if (iter) {
  6974. aPos->mResultFrame = frame;
  6975. searchTableBool = true;
  6976. result = NS_OK;
  6977. break; // while(frame)
  6978. }
  6979. result = NS_ERROR_FAILURE;
  6980. frame = frame->PrincipalChildList().FirstChild();
  6981. }
  6982. }
  6983. if (!searchTableBool) {
  6984. iter = aPos->mResultFrame->GetLineIterator();
  6985. result = iter ? NS_OK : NS_ERROR_FAILURE;
  6986. }
  6987. // we've struck another block element!
  6988. if (NS_SUCCEEDED(result) && iter) {
  6989. doneLooping = false;
  6990. if (aPos->mDirection == eDirPrevious)
  6991. edgeCase = 1; // far edge, search from end backwards
  6992. else
  6993. edgeCase = -1; // near edge search from beginning onwards
  6994. thisLine = 0; // this line means nothing now.
  6995. // everything else means something so keep looking "inside" the block
  6996. blockFrame = aPos->mResultFrame;
  6997. } else {
  6998. // THIS is to mean that everything is ok to the containing while loop
  6999. result = NS_OK;
  7000. break;
  7001. }
  7002. }
  7003. } while (!doneLooping);
  7004. }
  7005. return result;
  7006. }
  7007. case eSelectParagraph:
  7008. return PeekOffsetParagraph(aPos);
  7009. case eSelectBeginLine:
  7010. case eSelectEndLine:
  7011. {
  7012. // Adjusted so that the caret can't get confused when content changes
  7013. nsIFrame* blockFrame = AdjustFrameForSelectionStyles(this);
  7014. int32_t thisLine = nsFrame::GetLineNumber(blockFrame, aPos->mScrollViewStop, &blockFrame);
  7015. if (thisLine < 0)
  7016. return NS_ERROR_FAILURE;
  7017. nsAutoLineIterator it = blockFrame->GetLineIterator();
  7018. NS_ASSERTION(it, "GetLineNumber() succeeded but no block frame?");
  7019. int32_t lineFrameCount;
  7020. nsIFrame *firstFrame;
  7021. nsRect usedRect;
  7022. nsIFrame* baseFrame = nullptr;
  7023. bool endOfLine = (eSelectEndLine == aPos->mAmount);
  7024. if (aPos->mVisual && PresContext()->BidiEnabled()) {
  7025. bool lineIsRTL = it->GetDirection();
  7026. bool isReordered;
  7027. nsIFrame *lastFrame;
  7028. result = it->CheckLineOrder(thisLine, &isReordered, &firstFrame, &lastFrame);
  7029. baseFrame = endOfLine ? lastFrame : firstFrame;
  7030. if (baseFrame) {
  7031. bool frameIsRTL =
  7032. (nsBidiPresUtils::FrameDirection(baseFrame) == NSBIDI_RTL);
  7033. // If the direction of the frame on the edge is opposite to
  7034. // that of the line, we'll need to drill down to its opposite
  7035. // end, so reverse endOfLine.
  7036. if (frameIsRTL != lineIsRTL) {
  7037. endOfLine = !endOfLine;
  7038. }
  7039. }
  7040. } else {
  7041. it->GetLine(thisLine, &firstFrame, &lineFrameCount, usedRect);
  7042. nsIFrame* frame = firstFrame;
  7043. for (int32_t count = lineFrameCount; count;
  7044. --count, frame = frame->GetNextSibling()) {
  7045. if (!frame->IsGeneratedContentFrame()) {
  7046. // When jumping to the end of the line with the "end" key,
  7047. // skip over brFrames
  7048. if (endOfLine && lineFrameCount > 1 &&
  7049. frame->GetType() == nsGkAtoms::brFrame) {
  7050. continue;
  7051. }
  7052. baseFrame = frame;
  7053. if (!endOfLine)
  7054. break;
  7055. }
  7056. }
  7057. }
  7058. if (!baseFrame)
  7059. return NS_ERROR_FAILURE;
  7060. FrameTarget targetFrame = DrillDownToSelectionFrame(baseFrame,
  7061. endOfLine, 0);
  7062. FrameContentRange range = GetRangeForFrame(targetFrame.frame);
  7063. aPos->mResultContent = range.content;
  7064. aPos->mContentOffset = endOfLine ? range.end : range.start;
  7065. if (endOfLine && targetFrame.frame->HasSignificantTerminalNewline()) {
  7066. // Do not position the caret after the terminating newline if we're
  7067. // trying to move to the end of line (see bug 596506)
  7068. --aPos->mContentOffset;
  7069. }
  7070. aPos->mResultFrame = targetFrame.frame;
  7071. aPos->mAttach = aPos->mContentOffset == range.start ?
  7072. CARET_ASSOCIATE_AFTER : CARET_ASSOCIATE_BEFORE;
  7073. if (!range.content)
  7074. return NS_ERROR_FAILURE;
  7075. return NS_OK;
  7076. }
  7077. default:
  7078. {
  7079. NS_ASSERTION(false, "Invalid amount");
  7080. return NS_ERROR_FAILURE;
  7081. }
  7082. }
  7083. return NS_OK;
  7084. }
  7085. nsIFrame::FrameSearchResult
  7086. nsFrame::PeekOffsetNoAmount(bool aForward, int32_t* aOffset)
  7087. {
  7088. NS_ASSERTION (aOffset && *aOffset <= 1, "aOffset out of range");
  7089. // Sure, we can stop right here.
  7090. return FOUND;
  7091. }
  7092. nsIFrame::FrameSearchResult
  7093. nsFrame::PeekOffsetCharacter(bool aForward, int32_t* aOffset,
  7094. bool aRespectClusters)
  7095. {
  7096. NS_ASSERTION (aOffset && *aOffset <= 1, "aOffset out of range");
  7097. int32_t startOffset = *aOffset;
  7098. // A negative offset means "end of frame", which in our case means offset 1.
  7099. if (startOffset < 0)
  7100. startOffset = 1;
  7101. if (aForward == (startOffset == 0)) {
  7102. // We're before the frame and moving forward, or after it and moving backwards:
  7103. // skip to the other side and we're done.
  7104. *aOffset = 1 - startOffset;
  7105. return FOUND;
  7106. }
  7107. return CONTINUE;
  7108. }
  7109. nsIFrame::FrameSearchResult
  7110. nsFrame::PeekOffsetWord(bool aForward,
  7111. bool aWordSelectEatSpace,
  7112. bool aIsKeyboardSelect,
  7113. int32_t* aOffset,
  7114. PeekWordState* aState)
  7115. {
  7116. NS_ASSERTION (aOffset && *aOffset <= 1, "aOffset out of range");
  7117. int32_t startOffset = *aOffset;
  7118. // This isn't text, so truncate the context
  7119. aState->mContext.Truncate();
  7120. if (startOffset < 0)
  7121. startOffset = 1;
  7122. if (aForward == (startOffset == 0)) {
  7123. // We're before the frame and moving forward, or after it and moving backwards.
  7124. // If we're looking for non-whitespace, we found it (without skipping this frame).
  7125. if (!aState->mAtStart) {
  7126. if (aState->mLastCharWasPunctuation) {
  7127. // We're not punctuation, so this is a punctuation boundary.
  7128. if (BreakWordBetweenPunctuation(aState, aForward, false, false, aIsKeyboardSelect))
  7129. return FOUND;
  7130. } else {
  7131. // This is not a punctuation boundary.
  7132. if (aWordSelectEatSpace && aState->mSawBeforeType)
  7133. return FOUND;
  7134. }
  7135. }
  7136. // Otherwise skip to the other side and note that we encountered non-whitespace.
  7137. *aOffset = 1 - startOffset;
  7138. aState->Update(false, // not punctuation
  7139. false // not whitespace
  7140. );
  7141. if (!aWordSelectEatSpace)
  7142. aState->SetSawBeforeType();
  7143. }
  7144. return CONTINUE;
  7145. }
  7146. bool
  7147. nsFrame::BreakWordBetweenPunctuation(const PeekWordState* aState,
  7148. bool aForward,
  7149. bool aPunctAfter, bool aWhitespaceAfter,
  7150. bool aIsKeyboardSelect)
  7151. {
  7152. NS_ASSERTION(aPunctAfter != aState->mLastCharWasPunctuation,
  7153. "Call this only at punctuation boundaries");
  7154. if (aState->mLastCharWasWhitespace) {
  7155. // We always stop between whitespace and punctuation
  7156. return true;
  7157. }
  7158. if (!Preferences::GetBool("layout.word_select.stop_at_punctuation")) {
  7159. // When this pref is false, we never stop at a punctuation boundary unless
  7160. // it's followed by whitespace (in the relevant direction).
  7161. return aWhitespaceAfter;
  7162. }
  7163. if (!aIsKeyboardSelect) {
  7164. // mouse caret movement (e.g. word selection) always stops at every punctuation boundary
  7165. return true;
  7166. }
  7167. bool afterPunct = aForward ? aState->mLastCharWasPunctuation : aPunctAfter;
  7168. if (!afterPunct) {
  7169. // keyboard caret movement only stops after punctuation (in content order)
  7170. return false;
  7171. }
  7172. // Stop only if we've seen some non-punctuation since the last whitespace;
  7173. // don't stop after punctuation that follows whitespace.
  7174. return aState->mSeenNonPunctuationSinceWhitespace;
  7175. }
  7176. nsresult
  7177. nsFrame::CheckVisibility(nsPresContext* , int32_t , int32_t , bool , bool *, bool *)
  7178. {
  7179. return NS_ERROR_NOT_IMPLEMENTED;
  7180. }
  7181. int32_t
  7182. nsFrame::GetLineNumber(nsIFrame *aFrame, bool aLockScroll, nsIFrame** aContainingBlock)
  7183. {
  7184. NS_ASSERTION(aFrame, "null aFrame");
  7185. nsIFrame* blockFrame = aFrame;
  7186. nsIFrame* thisBlock;
  7187. nsAutoLineIterator it;
  7188. nsresult result = NS_ERROR_FAILURE;
  7189. while (NS_FAILED(result) && blockFrame)
  7190. {
  7191. thisBlock = blockFrame;
  7192. if (thisBlock->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
  7193. //if we are searching for a frame that is not in flow we will not find it.
  7194. //we must instead look for its placeholder
  7195. if (thisBlock->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER) {
  7196. // abspos continuations don't have placeholders, get the fif
  7197. thisBlock = thisBlock->FirstInFlow();
  7198. }
  7199. thisBlock = thisBlock->GetPlaceholderFrame();
  7200. if (!thisBlock)
  7201. return -1;
  7202. }
  7203. blockFrame = thisBlock->GetParent();
  7204. result = NS_OK;
  7205. if (blockFrame) {
  7206. if (aLockScroll && blockFrame->GetType() == nsGkAtoms::scrollFrame)
  7207. return -1;
  7208. it = blockFrame->GetLineIterator();
  7209. if (!it)
  7210. result = NS_ERROR_FAILURE;
  7211. }
  7212. }
  7213. if (!blockFrame || !it)
  7214. return -1;
  7215. if (aContainingBlock)
  7216. *aContainingBlock = blockFrame;
  7217. return it->FindLineContaining(thisBlock);
  7218. }
  7219. nsresult
  7220. nsIFrame::GetFrameFromDirection(nsDirection aDirection, bool aVisual,
  7221. bool aJumpLines, bool aScrollViewStop,
  7222. nsIFrame** aOutFrame, int32_t* aOutOffset,
  7223. bool* aOutJumpedLine, bool* aOutMovedOverNonSelectableText)
  7224. {
  7225. nsresult result;
  7226. if (!aOutFrame || !aOutOffset || !aOutJumpedLine)
  7227. return NS_ERROR_NULL_POINTER;
  7228. nsPresContext* presContext = PresContext();
  7229. *aOutFrame = nullptr;
  7230. *aOutOffset = 0;
  7231. *aOutJumpedLine = false;
  7232. *aOutMovedOverNonSelectableText = false;
  7233. // Find the prev/next selectable frame
  7234. bool selectable = false;
  7235. nsIFrame *traversedFrame = this;
  7236. while (!selectable) {
  7237. nsIFrame *blockFrame;
  7238. int32_t thisLine = nsFrame::GetLineNumber(traversedFrame, aScrollViewStop, &blockFrame);
  7239. if (thisLine < 0)
  7240. return NS_ERROR_FAILURE;
  7241. nsAutoLineIterator it = blockFrame->GetLineIterator();
  7242. NS_ASSERTION(it, "GetLineNumber() succeeded but no block frame?");
  7243. bool atLineEdge;
  7244. nsIFrame *firstFrame;
  7245. nsIFrame *lastFrame;
  7246. if (aVisual && presContext->BidiEnabled()) {
  7247. bool lineIsRTL = it->GetDirection();
  7248. bool isReordered;
  7249. result = it->CheckLineOrder(thisLine, &isReordered, &firstFrame, &lastFrame);
  7250. nsIFrame** framePtr = aDirection == eDirPrevious ? &firstFrame : &lastFrame;
  7251. if (*framePtr) {
  7252. bool frameIsRTL =
  7253. (nsBidiPresUtils::FrameDirection(*framePtr) == NSBIDI_RTL);
  7254. if ((frameIsRTL == lineIsRTL) == (aDirection == eDirPrevious)) {
  7255. nsFrame::GetFirstLeaf(presContext, framePtr);
  7256. } else {
  7257. nsFrame::GetLastLeaf(presContext, framePtr);
  7258. }
  7259. atLineEdge = *framePtr == traversedFrame;
  7260. } else {
  7261. atLineEdge = true;
  7262. }
  7263. } else {
  7264. nsRect nonUsedRect;
  7265. int32_t lineFrameCount;
  7266. result = it->GetLine(thisLine, &firstFrame, &lineFrameCount,
  7267. nonUsedRect);
  7268. if (NS_FAILED(result))
  7269. return result;
  7270. if (aDirection == eDirPrevious) {
  7271. nsFrame::GetFirstLeaf(presContext, &firstFrame);
  7272. atLineEdge = firstFrame == traversedFrame;
  7273. } else { // eDirNext
  7274. lastFrame = firstFrame;
  7275. for (;lineFrameCount > 1;lineFrameCount --){
  7276. result = it->GetNextSiblingOnLine(lastFrame, thisLine);
  7277. if (NS_FAILED(result) || !lastFrame){
  7278. NS_ERROR("should not be reached nsFrame");
  7279. return NS_ERROR_FAILURE;
  7280. }
  7281. }
  7282. nsFrame::GetLastLeaf(presContext, &lastFrame);
  7283. atLineEdge = lastFrame == traversedFrame;
  7284. }
  7285. }
  7286. if (atLineEdge) {
  7287. *aOutJumpedLine = true;
  7288. if (!aJumpLines)
  7289. return NS_ERROR_FAILURE; //we are done. cannot jump lines
  7290. }
  7291. nsCOMPtr<nsIFrameEnumerator> frameTraversal;
  7292. result = NS_NewFrameTraversal(getter_AddRefs(frameTraversal),
  7293. presContext, traversedFrame,
  7294. eLeaf,
  7295. aVisual && presContext->BidiEnabled(),
  7296. aScrollViewStop,
  7297. true, // aFollowOOFs
  7298. false // aSkipPopupChecks
  7299. );
  7300. if (NS_FAILED(result))
  7301. return result;
  7302. if (aDirection == eDirNext)
  7303. frameTraversal->Next();
  7304. else
  7305. frameTraversal->Prev();
  7306. traversedFrame = frameTraversal->CurrentItem();
  7307. // Skip anonymous elements, but watch out for generated content
  7308. if (!traversedFrame ||
  7309. (!traversedFrame->IsGeneratedContentFrame() &&
  7310. traversedFrame->GetContent()->IsRootOfNativeAnonymousSubtree())) {
  7311. return NS_ERROR_FAILURE;
  7312. }
  7313. // Skip brFrames, but only if they are not the only frame in the line
  7314. if (atLineEdge && aDirection == eDirPrevious &&
  7315. traversedFrame->GetType() == nsGkAtoms::brFrame) {
  7316. int32_t lineFrameCount;
  7317. nsIFrame *currentBlockFrame, *currentFirstFrame;
  7318. nsRect usedRect;
  7319. int32_t currentLine = nsFrame::GetLineNumber(traversedFrame, aScrollViewStop, &currentBlockFrame);
  7320. nsAutoLineIterator iter = currentBlockFrame->GetLineIterator();
  7321. result = iter->GetLine(currentLine, &currentFirstFrame, &lineFrameCount, usedRect);
  7322. if (NS_FAILED(result)) {
  7323. return result;
  7324. }
  7325. if (lineFrameCount > 1) {
  7326. continue;
  7327. }
  7328. }
  7329. traversedFrame->IsSelectable(&selectable, nullptr);
  7330. if (!selectable) {
  7331. *aOutMovedOverNonSelectableText = true;
  7332. }
  7333. } // while (!selectable)
  7334. *aOutOffset = (aDirection == eDirNext) ? 0 : -1;
  7335. if (aVisual && IsReversedDirectionFrame(traversedFrame)) {
  7336. // The new frame is reverse-direction, go to the other end
  7337. *aOutOffset = -1 - *aOutOffset;
  7338. }
  7339. *aOutFrame = traversedFrame;
  7340. return NS_OK;
  7341. }
  7342. nsView* nsIFrame::GetClosestView(nsPoint* aOffset) const
  7343. {
  7344. nsPoint offset(0,0);
  7345. for (const nsIFrame *f = this; f; f = f->GetParent()) {
  7346. if (f->HasView()) {
  7347. if (aOffset)
  7348. *aOffset = offset;
  7349. return f->GetView();
  7350. }
  7351. offset += f->GetPosition();
  7352. }
  7353. NS_NOTREACHED("No view on any parent? How did that happen?");
  7354. return nullptr;
  7355. }
  7356. /* virtual */ void
  7357. nsFrame::ChildIsDirty(nsIFrame* aChild)
  7358. {
  7359. NS_NOTREACHED("should never be called on a frame that doesn't inherit from "
  7360. "nsContainerFrame");
  7361. }
  7362. #ifdef ACCESSIBILITY
  7363. a11y::AccType
  7364. nsFrame::AccessibleType()
  7365. {
  7366. if (IsTableCaption() && !GetRect().IsEmpty()) {
  7367. return a11y::eHTMLCaptionType;
  7368. }
  7369. return a11y::eNoType;
  7370. }
  7371. #endif
  7372. NS_DECLARE_FRAME_PROPERTY_DELETABLE(OverflowAreasProperty, nsOverflowAreas)
  7373. bool
  7374. nsIFrame::ClearOverflowRects()
  7375. {
  7376. if (mOverflow.mType == NS_FRAME_OVERFLOW_NONE) {
  7377. return false;
  7378. }
  7379. if (mOverflow.mType == NS_FRAME_OVERFLOW_LARGE) {
  7380. DeleteProperty(OverflowAreasProperty());
  7381. }
  7382. mOverflow.mType = NS_FRAME_OVERFLOW_NONE;
  7383. return true;
  7384. }
  7385. /** Create or retrieve the previously stored overflow area, if the frame does
  7386. * not overflow and no creation is required return nullptr.
  7387. * @return pointer to the overflow area rectangle
  7388. */
  7389. nsOverflowAreas*
  7390. nsIFrame::GetOverflowAreasProperty()
  7391. {
  7392. nsOverflowAreas* overflow = GetProperty(OverflowAreasProperty());
  7393. if (overflow) {
  7394. return overflow; // the property already exists
  7395. }
  7396. // The property isn't set yet, so allocate a new rect, set the property,
  7397. // and return the newly allocated rect
  7398. overflow = new nsOverflowAreas;
  7399. SetProperty(OverflowAreasProperty(), overflow);
  7400. return overflow;
  7401. }
  7402. /** Set the overflowArea rect, storing it as deltas or a separate rect
  7403. * depending on its size in relation to the primary frame rect.
  7404. */
  7405. bool
  7406. nsIFrame::SetOverflowAreas(const nsOverflowAreas& aOverflowAreas)
  7407. {
  7408. if (mOverflow.mType == NS_FRAME_OVERFLOW_LARGE) {
  7409. nsOverflowAreas* overflow = GetProperty(OverflowAreasProperty());
  7410. bool changed = *overflow != aOverflowAreas;
  7411. *overflow = aOverflowAreas;
  7412. // Don't bother with converting to the deltas form if we already
  7413. // have a property.
  7414. return changed;
  7415. }
  7416. const nsRect& vis = aOverflowAreas.VisualOverflow();
  7417. uint32_t l = -vis.x, // left edge: positive delta is leftwards
  7418. t = -vis.y, // top: positive is upwards
  7419. r = vis.XMost() - mRect.width, // right: positive is rightwards
  7420. b = vis.YMost() - mRect.height; // bottom: positive is downwards
  7421. if (aOverflowAreas.ScrollableOverflow().IsEqualEdges(nsRect(nsPoint(0, 0), GetSize())) &&
  7422. l <= NS_FRAME_OVERFLOW_DELTA_MAX &&
  7423. t <= NS_FRAME_OVERFLOW_DELTA_MAX &&
  7424. r <= NS_FRAME_OVERFLOW_DELTA_MAX &&
  7425. b <= NS_FRAME_OVERFLOW_DELTA_MAX &&
  7426. // we have to check these against zero because we *never* want to
  7427. // set a frame as having no overflow in this function. This is
  7428. // because FinishAndStoreOverflow calls this function prior to
  7429. // SetRect based on whether the overflow areas match aNewSize.
  7430. // In the case where the overflow areas exactly match mRect but
  7431. // do not match aNewSize, we need to store overflow in a property
  7432. // so that our eventual SetRect/SetSize will know that it has to
  7433. // reset our overflow areas.
  7434. (l | t | r | b) != 0) {
  7435. VisualDeltas oldDeltas = mOverflow.mVisualDeltas;
  7436. // It's a "small" overflow area so we store the deltas for each edge
  7437. // directly in the frame, rather than allocating a separate rect.
  7438. // If they're all zero, that's fine; we're setting things to
  7439. // no-overflow.
  7440. mOverflow.mVisualDeltas.mLeft = l;
  7441. mOverflow.mVisualDeltas.mTop = t;
  7442. mOverflow.mVisualDeltas.mRight = r;
  7443. mOverflow.mVisualDeltas.mBottom = b;
  7444. // There was no scrollable overflow before, and there isn't now.
  7445. return oldDeltas != mOverflow.mVisualDeltas;
  7446. } else {
  7447. bool changed = !aOverflowAreas.ScrollableOverflow().IsEqualEdges(nsRect(nsPoint(0, 0), GetSize())) ||
  7448. !aOverflowAreas.VisualOverflow().IsEqualEdges(GetVisualOverflowFromDeltas());
  7449. // it's a large overflow area that we need to store as a property
  7450. mOverflow.mType = NS_FRAME_OVERFLOW_LARGE;
  7451. nsOverflowAreas* overflow = GetOverflowAreasProperty();
  7452. NS_ASSERTION(overflow, "should have created areas");
  7453. *overflow = aOverflowAreas;
  7454. return changed;
  7455. }
  7456. }
  7457. inline bool
  7458. IsInlineFrame(nsIFrame *aFrame)
  7459. {
  7460. nsIAtom *type = aFrame->GetType();
  7461. return type == nsGkAtoms::inlineFrame;
  7462. }
  7463. /**
  7464. * Compute the union of the border boxes of aFrame and its descendants,
  7465. * in aFrame's coordinate space (if aApplyTransform is false) or its
  7466. * post-transform coordinate space (if aApplyTransform is true).
  7467. */
  7468. static nsRect
  7469. UnionBorderBoxes(nsIFrame* aFrame, bool aApplyTransform,
  7470. bool& aOutValid,
  7471. const nsSize* aSizeOverride = nullptr,
  7472. const nsOverflowAreas* aOverflowOverride = nullptr)
  7473. {
  7474. const nsRect bounds(nsPoint(0, 0),
  7475. aSizeOverride ? *aSizeOverride : aFrame->GetSize());
  7476. // The SVG container frames do not maintain an accurate mRect.
  7477. // It will make the outline be larger than we expect, we need
  7478. // to make them narrow to their children's outline.
  7479. // aOutValid is set to false if the returned nsRect is not valid
  7480. // and should not be included in the outline rectangle.
  7481. aOutValid = !aFrame->IsFrameOfType(nsIFrame::eSVGContainer);
  7482. // Start from our border-box, transformed. See comment below about
  7483. // transform of children.
  7484. nsRect u;
  7485. bool doTransform = aApplyTransform && aFrame->IsTransformed();
  7486. if (doTransform) {
  7487. u = nsDisplayTransform::TransformRect(bounds, aFrame, &bounds);
  7488. } else {
  7489. u = bounds;
  7490. }
  7491. // Only iterate through the children if the overflow areas suggest
  7492. // that we might need to, and if the frame doesn't clip its overflow
  7493. // anyway.
  7494. if (aOverflowOverride) {
  7495. if (!doTransform &&
  7496. bounds.IsEqualEdges(aOverflowOverride->VisualOverflow()) &&
  7497. bounds.IsEqualEdges(aOverflowOverride->ScrollableOverflow())) {
  7498. return u;
  7499. }
  7500. } else {
  7501. if (!doTransform &&
  7502. bounds.IsEqualEdges(aFrame->GetVisualOverflowRect()) &&
  7503. bounds.IsEqualEdges(aFrame->GetScrollableOverflowRect())) {
  7504. return u;
  7505. }
  7506. }
  7507. const nsStyleDisplay* disp = aFrame->StyleDisplay();
  7508. nsIAtom* fType = aFrame->GetType();
  7509. if (nsFrame::ShouldApplyOverflowClipping(aFrame, disp) ||
  7510. fType == nsGkAtoms::scrollFrame ||
  7511. fType == nsGkAtoms::listControlFrame ||
  7512. fType == nsGkAtoms::svgOuterSVGFrame) {
  7513. return u;
  7514. }
  7515. const nsStyleEffects* effects = aFrame->StyleEffects();
  7516. Maybe<nsRect> clipPropClipRect =
  7517. aFrame->GetClipPropClipRect(disp, effects, bounds.Size());
  7518. // Iterate over all children except pop-ups, absolutely positioned children,
  7519. // fixed-positioned children and floats.
  7520. const nsIFrame::ChildListIDs skip(nsIFrame::kPopupList |
  7521. nsIFrame::kSelectPopupList |
  7522. nsIFrame::kAbsoluteList |
  7523. nsIFrame::kFixedList |
  7524. nsIFrame::kFloatList);
  7525. for (nsIFrame::ChildListIterator childLists(aFrame);
  7526. !childLists.IsDone(); childLists.Next()) {
  7527. if (skip.Contains(childLists.CurrentID())) {
  7528. continue;
  7529. }
  7530. nsFrameList children = childLists.CurrentList();
  7531. for (nsFrameList::Enumerator e(children); !e.AtEnd(); e.Next()) {
  7532. nsIFrame* child = e.get();
  7533. if (child->GetType() == nsGkAtoms::placeholderFrame) {
  7534. // Skip placeholders too.
  7535. continue;
  7536. }
  7537. // Note that passing |true| for aApplyTransform when
  7538. // child->Combines3DTransformWithAncestors() is incorrect if our
  7539. // aApplyTransform is false... but the opposite would be as
  7540. // well. This is because elements within a preserve-3d scene
  7541. // are always transformed up to the top of the scene. This
  7542. // means we don't have a mechanism for getting a transform up to
  7543. // an intermediate point within the scene. We choose to
  7544. // over-transform rather than under-transform because this is
  7545. // consistent with other overflow areas.
  7546. bool validRect = true;
  7547. nsRect childRect = UnionBorderBoxes(child, true, validRect) +
  7548. child->GetPosition();
  7549. if (!validRect) {
  7550. continue;
  7551. }
  7552. if (clipPropClipRect) {
  7553. // Intersect with the clip before transforming.
  7554. childRect.IntersectRect(childRect, *clipPropClipRect);
  7555. }
  7556. // Note that we transform each child separately according to
  7557. // aFrame's transform, and then union, which gives a different
  7558. // (smaller) result from unioning and then transforming the
  7559. // union. This doesn't match the way we handle overflow areas
  7560. // with 2-D transforms, though it does match the way we handle
  7561. // overflow areas in preserve-3d 3-D scenes.
  7562. if (doTransform && !child->Combines3DTransformWithAncestors()) {
  7563. childRect = nsDisplayTransform::TransformRect(childRect, aFrame, &bounds);
  7564. }
  7565. // If a SVGContainer has a non-SVGContainer child, we assign
  7566. // its child's outline to this SVGContainer directly.
  7567. if (!aOutValid && validRect) {
  7568. u = childRect;
  7569. aOutValid = true;
  7570. } else {
  7571. u.UnionRectEdges(u, childRect);
  7572. }
  7573. }
  7574. }
  7575. return u;
  7576. }
  7577. static void
  7578. ComputeAndIncludeOutlineArea(nsIFrame* aFrame, nsOverflowAreas& aOverflowAreas,
  7579. const nsSize& aNewSize)
  7580. {
  7581. const nsStyleOutline* outline = aFrame->StyleOutline();
  7582. const uint8_t outlineStyle = outline->mOutlineStyle;
  7583. if (outlineStyle == NS_STYLE_BORDER_STYLE_NONE) {
  7584. return;
  7585. }
  7586. nscoord width = outline->GetOutlineWidth();
  7587. if (width <= 0 && outlineStyle != NS_STYLE_BORDER_STYLE_AUTO) {
  7588. return;
  7589. }
  7590. // When the outline property is set on :-moz-anonymous-block or
  7591. // :-moz-anonymous-positioned-block pseudo-elements, it inherited
  7592. // that outline from the inline that was broken because it
  7593. // contained a block. In that case, we don't want a really wide
  7594. // outline if the block inside the inline is narrow, so union the
  7595. // actual contents of the anonymous blocks.
  7596. nsIFrame *frameForArea = aFrame;
  7597. do {
  7598. nsIAtom *pseudoType = frameForArea->StyleContext()->GetPseudo();
  7599. if (pseudoType != nsCSSAnonBoxes::mozAnonymousBlock &&
  7600. pseudoType != nsCSSAnonBoxes::mozAnonymousPositionedBlock)
  7601. break;
  7602. // If we're done, we really want it and all its later siblings.
  7603. frameForArea = frameForArea->PrincipalChildList().FirstChild();
  7604. NS_ASSERTION(frameForArea, "anonymous block with no children?");
  7605. } while (frameForArea);
  7606. // Find the union of the border boxes of all descendants, or in
  7607. // the block-in-inline case, all descendants we care about.
  7608. //
  7609. // Note that the interesting perspective-related cases are taken
  7610. // care of by the code that handles those issues for overflow
  7611. // calling FinishAndStoreOverflow again, which in turn calls this
  7612. // function again. We still need to deal with preserve-3d a bit.
  7613. nsRect innerRect;
  7614. bool validRect;
  7615. if (frameForArea == aFrame) {
  7616. innerRect = UnionBorderBoxes(aFrame, false, validRect, &aNewSize, &aOverflowAreas);
  7617. } else {
  7618. for (; frameForArea; frameForArea = frameForArea->GetNextSibling()) {
  7619. nsRect r(UnionBorderBoxes(frameForArea, true, validRect));
  7620. // Adjust for offsets transforms up to aFrame's pre-transform
  7621. // (i.e., normal) coordinate space; see comments in
  7622. // UnionBorderBoxes for some of the subtlety here.
  7623. for (nsIFrame *f = frameForArea, *parent = f->GetParent();
  7624. /* see middle of loop */;
  7625. f = parent, parent = f->GetParent()) {
  7626. r += f->GetPosition();
  7627. if (parent == aFrame) {
  7628. break;
  7629. }
  7630. if (parent->IsTransformed() && !f->Combines3DTransformWithAncestors()) {
  7631. r = nsDisplayTransform::TransformRect(r, parent);
  7632. }
  7633. }
  7634. innerRect.UnionRect(innerRect, r);
  7635. }
  7636. }
  7637. // Keep this code in sync with GetOutlineInnerRect in nsCSSRendering.cpp.
  7638. aFrame->SetProperty(nsIFrame::OutlineInnerRectProperty(),
  7639. new nsRect(innerRect));
  7640. const nscoord offset = outline->mOutlineOffset;
  7641. nsRect outerRect(innerRect);
  7642. bool useOutlineAuto = false;
  7643. if (nsLayoutUtils::IsOutlineStyleAutoEnabled()) {
  7644. useOutlineAuto = outlineStyle == NS_STYLE_BORDER_STYLE_AUTO;
  7645. if (MOZ_UNLIKELY(useOutlineAuto)) {
  7646. nsPresContext* presContext = aFrame->PresContext();
  7647. nsITheme* theme = presContext->GetTheme();
  7648. if (theme && theme->ThemeSupportsWidget(presContext, aFrame,
  7649. NS_THEME_FOCUS_OUTLINE)) {
  7650. outerRect.Inflate(offset);
  7651. theme->GetWidgetOverflow(presContext->DeviceContext(), aFrame,
  7652. NS_THEME_FOCUS_OUTLINE, &outerRect);
  7653. } else {
  7654. useOutlineAuto = false;
  7655. }
  7656. }
  7657. }
  7658. if (MOZ_LIKELY(!useOutlineAuto)) {
  7659. outerRect.Inflate(width + offset);
  7660. }
  7661. nsRect& vo = aOverflowAreas.VisualOverflow();
  7662. vo.UnionRectEdges(vo, innerRect.Union(outerRect));
  7663. }
  7664. bool
  7665. nsIFrame::FinishAndStoreOverflow(nsOverflowAreas& aOverflowAreas,
  7666. nsSize aNewSize, nsSize* aOldSize)
  7667. {
  7668. NS_ASSERTION(FrameMaintainsOverflow(),
  7669. "Don't call - overflow rects not maintained on these SVG frames");
  7670. nsRect bounds(nsPoint(0, 0), aNewSize);
  7671. // Store the passed in overflow area if we are a preserve-3d frame or we have
  7672. // a transform, and it's not just the frame bounds.
  7673. if (Combines3DTransformWithAncestors() || IsTransformed()) {
  7674. if (!aOverflowAreas.VisualOverflow().IsEqualEdges(bounds) ||
  7675. !aOverflowAreas.ScrollableOverflow().IsEqualEdges(bounds)) {
  7676. nsOverflowAreas* initial =
  7677. GetProperty(nsIFrame::InitialOverflowProperty());
  7678. if (!initial) {
  7679. SetProperty(nsIFrame::InitialOverflowProperty(),
  7680. new nsOverflowAreas(aOverflowAreas));
  7681. } else if (initial != &aOverflowAreas) {
  7682. *initial = aOverflowAreas;
  7683. }
  7684. } else {
  7685. DeleteProperty(nsIFrame::InitialOverflowProperty());
  7686. }
  7687. #ifdef DEBUG
  7688. SetProperty(nsIFrame::DebugInitialOverflowPropertyApplied(), true);
  7689. #endif
  7690. } else {
  7691. #ifdef DEBUG
  7692. DeleteProperty(nsIFrame::DebugInitialOverflowPropertyApplied());
  7693. #endif
  7694. }
  7695. // This is now called FinishAndStoreOverflow() instead of
  7696. // StoreOverflow() because frame-generic ways of adding overflow
  7697. // can happen here, e.g. CSS2 outline and native theme.
  7698. // If the overflow area width or height is nscoord_MAX, then a
  7699. // saturating union may have encounted an overflow, so the overflow may not
  7700. // contain the frame border-box. Don't warn in that case.
  7701. // Don't warn for SVG either, since SVG doesn't need the overflow area
  7702. // to contain the frame bounds.
  7703. NS_FOR_FRAME_OVERFLOW_TYPES(otype) {
  7704. DebugOnly<nsRect*> r = &aOverflowAreas.Overflow(otype);
  7705. NS_ASSERTION(aNewSize.width == 0 || aNewSize.height == 0 ||
  7706. r->width == nscoord_MAX || r->height == nscoord_MAX ||
  7707. (mState & NS_FRAME_SVG_LAYOUT) ||
  7708. r->Contains(nsRect(nsPoint(0,0), aNewSize)),
  7709. "Computed overflow area must contain frame bounds");
  7710. }
  7711. // If we clip our children, clear accumulated overflow area. The
  7712. // children are actually clipped to the padding-box, but since the
  7713. // overflow area should include the entire border-box, just set it to
  7714. // the border-box here.
  7715. const nsStyleDisplay* disp = StyleDisplay();
  7716. NS_ASSERTION((disp->mOverflowY == NS_STYLE_OVERFLOW_CLIP) ==
  7717. (disp->mOverflowX == NS_STYLE_OVERFLOW_CLIP),
  7718. "If one overflow is clip, the other should be too");
  7719. if (nsFrame::ShouldApplyOverflowClipping(this, disp)) {
  7720. // The contents are actually clipped to the padding area
  7721. aOverflowAreas.SetAllTo(bounds);
  7722. }
  7723. // Overflow area must always include the frame's top-left and bottom-right,
  7724. // even if the frame rect is empty (so we can scroll to those positions).
  7725. // Pending a real fix for bug 426879, don't do this for inline frames
  7726. // with zero width.
  7727. // Do not do this for SVG either, since it will usually massively increase
  7728. // the area unnecessarily.
  7729. if ((aNewSize.width != 0 || !IsInlineFrame(this)) &&
  7730. !(GetStateBits() & NS_FRAME_SVG_LAYOUT)) {
  7731. NS_FOR_FRAME_OVERFLOW_TYPES(otype) {
  7732. nsRect& o = aOverflowAreas.Overflow(otype);
  7733. o.UnionRectEdges(o, bounds);
  7734. }
  7735. }
  7736. // Note that NS_STYLE_OVERFLOW_CLIP doesn't clip the frame background,
  7737. // so we add theme background overflow here so it's not clipped.
  7738. if (!::IsXULBoxWrapped(this) && IsThemed(disp)) {
  7739. nsRect r(bounds);
  7740. nsPresContext *presContext = PresContext();
  7741. if (presContext->GetTheme()->
  7742. GetWidgetOverflow(presContext->DeviceContext(), this,
  7743. disp->mAppearance, &r)) {
  7744. nsRect& vo = aOverflowAreas.VisualOverflow();
  7745. vo.UnionRectEdges(vo, r);
  7746. }
  7747. }
  7748. ComputeAndIncludeOutlineArea(this, aOverflowAreas, aNewSize);
  7749. // Nothing in here should affect scrollable overflow.
  7750. aOverflowAreas.VisualOverflow() =
  7751. ComputeEffectsRect(this, aOverflowAreas.VisualOverflow(), aNewSize);
  7752. // Absolute position clipping
  7753. const nsStyleEffects* effects = StyleEffects();
  7754. Maybe<nsRect> clipPropClipRect =
  7755. GetClipPropClipRect(disp, effects, aNewSize);
  7756. if (clipPropClipRect) {
  7757. NS_FOR_FRAME_OVERFLOW_TYPES(otype) {
  7758. nsRect& o = aOverflowAreas.Overflow(otype);
  7759. o.IntersectRect(o, *clipPropClipRect);
  7760. }
  7761. }
  7762. /* If we're transformed, transform the overflow rect by the current transformation. */
  7763. bool hasTransform = IsTransformed();
  7764. nsSize oldSize = mRect.Size();
  7765. bool sizeChanged = ((aOldSize ? *aOldSize : oldSize) != aNewSize);
  7766. /* Since our size might not actually have been computed yet, we need to make sure that we use the
  7767. * correct dimensions by overriding the stored bounding rectangle with the value the caller has
  7768. * ensured us we'll use.
  7769. */
  7770. SetSize(aNewSize);
  7771. if (ChildrenHavePerspective() && sizeChanged) {
  7772. nsRect newBounds(nsPoint(0, 0), aNewSize);
  7773. RecomputePerspectiveChildrenOverflow(this);
  7774. }
  7775. if (hasTransform) {
  7776. SetProperty(nsIFrame::PreTransformOverflowAreasProperty(),
  7777. new nsOverflowAreas(aOverflowAreas));
  7778. if (Combines3DTransformWithAncestors()) {
  7779. /* If we're a preserve-3d leaf frame, then our pre-transform overflow should be correct. Our
  7780. * post-transform overflow is empty though, because we only contribute to the overflow area
  7781. * of the preserve-3d root frame.
  7782. * If we're an intermediate frame then the pre-transform overflow should contain all our
  7783. * non-preserve-3d children, which is what we want. Again we have no post-transform overflow.
  7784. */
  7785. aOverflowAreas.SetAllTo(nsRect());
  7786. } else {
  7787. NS_FOR_FRAME_OVERFLOW_TYPES(otype) {
  7788. nsRect& o = aOverflowAreas.Overflow(otype);
  7789. o = nsDisplayTransform::TransformRect(o, this);
  7790. }
  7791. /* If we're the root of the 3d context, then we want to include the overflow areas of all
  7792. * the participants. This won't have happened yet as the code above set their overflow
  7793. * area to empty. Manually collect these overflow areas now.
  7794. */
  7795. if (Extend3DContext()) {
  7796. ComputePreserve3DChildrenOverflow(aOverflowAreas);
  7797. }
  7798. }
  7799. } else {
  7800. DeleteProperty(nsIFrame::PreTransformOverflowAreasProperty());
  7801. }
  7802. /* Revert the size change in case some caller is depending on this. */
  7803. SetSize(oldSize);
  7804. bool anyOverflowChanged;
  7805. if (aOverflowAreas != nsOverflowAreas(bounds, bounds)) {
  7806. anyOverflowChanged = SetOverflowAreas(aOverflowAreas);
  7807. } else {
  7808. anyOverflowChanged = ClearOverflowRects();
  7809. }
  7810. if (anyOverflowChanged) {
  7811. nsSVGEffects::InvalidateDirectRenderingObservers(this);
  7812. }
  7813. return anyOverflowChanged;
  7814. }
  7815. void
  7816. nsIFrame::RecomputePerspectiveChildrenOverflow(const nsIFrame* aStartFrame)
  7817. {
  7818. nsIFrame::ChildListIterator lists(this);
  7819. for (; !lists.IsDone(); lists.Next()) {
  7820. nsFrameList::Enumerator childFrames(lists.CurrentList());
  7821. for (; !childFrames.AtEnd(); childFrames.Next()) {
  7822. nsIFrame* child = childFrames.get();
  7823. if (!child->FrameMaintainsOverflow()) {
  7824. continue; // frame does not maintain overflow rects
  7825. }
  7826. if (child->HasPerspective()) {
  7827. nsOverflowAreas* overflow =
  7828. child->GetProperty(nsIFrame::InitialOverflowProperty());
  7829. nsRect bounds(nsPoint(0, 0), child->GetSize());
  7830. if (overflow) {
  7831. nsOverflowAreas overflowCopy = *overflow;
  7832. child->FinishAndStoreOverflow(overflowCopy, bounds.Size());
  7833. } else {
  7834. nsOverflowAreas boundsOverflow;
  7835. boundsOverflow.SetAllTo(bounds);
  7836. child->FinishAndStoreOverflow(boundsOverflow, bounds.Size());
  7837. }
  7838. } else if (child->GetContainingBlock(SKIP_SCROLLED_FRAME) == aStartFrame) {
  7839. // If a frame is using perspective, then the size used to compute
  7840. // perspective-origin is the size of the frame belonging to its parent
  7841. // style context. We must find any descendant frames using our size
  7842. // (by recursing into frames that have the same containing block)
  7843. // to update their overflow rects too.
  7844. child->RecomputePerspectiveChildrenOverflow(aStartFrame);
  7845. }
  7846. }
  7847. }
  7848. }
  7849. void
  7850. nsIFrame::ComputePreserve3DChildrenOverflow(nsOverflowAreas& aOverflowAreas)
  7851. {
  7852. // Find all descendants that participate in the 3d context, and include their overflow.
  7853. // These descendants have an empty overflow, so won't have been included in the normal
  7854. // overflow calculation. Any children that don't participate have normal overflow,
  7855. // so will have been included already.
  7856. nsRect childVisual;
  7857. nsRect childScrollable;
  7858. nsIFrame::ChildListIterator lists(this);
  7859. for (; !lists.IsDone(); lists.Next()) {
  7860. nsFrameList::Enumerator childFrames(lists.CurrentList());
  7861. for (; !childFrames.AtEnd(); childFrames.Next()) {
  7862. nsIFrame* child = childFrames.get();
  7863. // If this child participates in the 3d context, then take the pre-transform
  7864. // region (which contains all descendants that aren't participating in the 3d context)
  7865. // and transform it into the 3d context root coordinate space.
  7866. if (child->Combines3DTransformWithAncestors()) {
  7867. nsOverflowAreas childOverflow = child->GetOverflowAreasRelativeToSelf();
  7868. NS_FOR_FRAME_OVERFLOW_TYPES(otype) {
  7869. nsRect& o = childOverflow.Overflow(otype);
  7870. o = nsDisplayTransform::TransformRect(o, child);
  7871. }
  7872. aOverflowAreas.UnionWith(childOverflow);
  7873. // If this child also extends the 3d context, then recurse into it
  7874. // looking for more participants.
  7875. if (child->Extend3DContext()) {
  7876. child->ComputePreserve3DChildrenOverflow(aOverflowAreas);
  7877. }
  7878. }
  7879. }
  7880. }
  7881. }
  7882. uint32_t
  7883. nsIFrame::GetDepthInFrameTree() const
  7884. {
  7885. uint32_t result = 0;
  7886. for (nsContainerFrame* ancestor = GetParent(); ancestor;
  7887. ancestor = ancestor->GetParent()) {
  7888. result++;
  7889. }
  7890. return result;
  7891. }
  7892. void
  7893. nsFrame::ConsiderChildOverflow(nsOverflowAreas& aOverflowAreas,
  7894. nsIFrame* aChildFrame)
  7895. {
  7896. aOverflowAreas.UnionWith(aChildFrame->GetOverflowAreas() +
  7897. aChildFrame->GetPosition());
  7898. }
  7899. /**
  7900. * This function takes a frame that is part of a block-in-inline split,
  7901. * and _if_ that frame is an anonymous block created by an ib split it
  7902. * returns the block's preceding inline. This is needed because the
  7903. * split inline's style context is the parent of the anonymous block's
  7904. * style context.
  7905. *
  7906. * If aFrame is not an anonymous block, null is returned.
  7907. */
  7908. static nsIFrame*
  7909. GetIBSplitSiblingForAnonymousBlock(const nsIFrame* aFrame)
  7910. {
  7911. NS_PRECONDITION(aFrame, "Must have a non-null frame!");
  7912. NS_ASSERTION(aFrame->GetStateBits() & NS_FRAME_PART_OF_IBSPLIT,
  7913. "GetIBSplitSibling should only be called on ib-split frames");
  7914. nsIAtom* type = aFrame->StyleContext()->GetPseudo();
  7915. if (type != nsCSSAnonBoxes::mozAnonymousBlock &&
  7916. type != nsCSSAnonBoxes::mozAnonymousPositionedBlock) {
  7917. // it's not an anonymous block
  7918. return nullptr;
  7919. }
  7920. // Find the first continuation of the frame. (Ugh. This ends up
  7921. // being O(N^2) when it is called O(N) times.)
  7922. aFrame = aFrame->FirstContinuation();
  7923. /*
  7924. * Now look up the nsGkAtoms::IBSplitPrevSibling
  7925. * property.
  7926. */
  7927. nsIFrame *ibSplitSibling =
  7928. aFrame->GetProperty(nsIFrame::IBSplitPrevSibling());
  7929. NS_ASSERTION(ibSplitSibling, "Broken frame tree?");
  7930. return ibSplitSibling;
  7931. }
  7932. /**
  7933. * Get the parent, corrected for the mangled frame tree resulting from
  7934. * having a block within an inline. The result only differs from the
  7935. * result of |GetParent| when |GetParent| returns an anonymous block
  7936. * that was created for an element that was 'display: inline' because
  7937. * that element contained a block.
  7938. *
  7939. * Also skip anonymous scrolled-content parents; inherit directly from the
  7940. * outer scroll frame.
  7941. *
  7942. * Also skip NAC parents if the child frame is NAC.
  7943. */
  7944. static nsIFrame*
  7945. GetCorrectedParent(const nsIFrame* aFrame)
  7946. {
  7947. nsIFrame* parent = aFrame->GetParent();
  7948. if (!parent) {
  7949. return nullptr;
  7950. }
  7951. // For a table caption we want the _inner_ table frame (unless it's anonymous)
  7952. // as the style parent.
  7953. if (aFrame->IsTableCaption()) {
  7954. nsIFrame* innerTable = parent->PrincipalChildList().FirstChild();
  7955. if (!innerTable->StyleContext()->GetPseudo()) {
  7956. return innerTable;
  7957. }
  7958. }
  7959. // Table wrappers are always anon boxes; if we're in here for an outer
  7960. // table, that actually means its the _inner_ table that wants to
  7961. // know its parent. So get the pseudo of the inner in that case.
  7962. nsIAtom* pseudo = aFrame->StyleContext()->GetPseudo();
  7963. if (pseudo == nsCSSAnonBoxes::tableWrapper) {
  7964. pseudo = aFrame->PrincipalChildList().FirstChild()->StyleContext()->GetPseudo();
  7965. }
  7966. // Prevent NAC from inheriting NAC. This partially duplicates the logic
  7967. // implemented in nsCSSFrameConstructor::AddFCItemsForAnonymousContent, and is
  7968. // necessary so that restyle inherits style contexts in the same way as the
  7969. // initial styling performed in frame construction.
  7970. //
  7971. // It would be nice to put it in CorrectStyleParentFrame and therefore share
  7972. // it, but that would lose the information of whether the _child_ is NAC,
  7973. // since CorrectStyleParentFrame only knows about the prospective _parent_.
  7974. // This duplication and complexity will go away when we fully switch to the
  7975. // Servo style system, where all this can be handled much more naturally.
  7976. //
  7977. // We need to take special care not to disrupt the style inheritance of frames
  7978. // whose content is NAC but who implement a pseudo (like an anonymous
  7979. // box, or a non-NAC-backed pseudo like ::first-line) that does not match the
  7980. // one that the NAC implements, if any.
  7981. nsIContent* content = aFrame->GetContent();
  7982. Element* element =
  7983. content && content->IsElement() ? content->AsElement() : nullptr;
  7984. if (element && element->IsNativeAnonymous() && !element->IsNativeScrollbarContent() &&
  7985. element->GetPseudoElementType() == aFrame->StyleContext()->GetPseudoType()) {
  7986. while (parent->GetContent() && parent->GetContent()->IsNativeAnonymous()) {
  7987. parent = parent->GetInFlowParent();
  7988. }
  7989. }
  7990. return nsFrame::CorrectStyleParentFrame(parent, pseudo);
  7991. }
  7992. /* static */
  7993. nsIFrame*
  7994. nsFrame::CorrectStyleParentFrame(nsIFrame* aProspectiveParent,
  7995. nsIAtom* aChildPseudo)
  7996. {
  7997. NS_PRECONDITION(aProspectiveParent, "Must have a prospective parent");
  7998. // Anon boxes are parented to their actual parent already, except
  7999. // for non-elements. Those should not be treated as an anon box.
  8000. if (aChildPseudo && !nsCSSAnonBoxes::IsNonElement(aChildPseudo) &&
  8001. nsCSSAnonBoxes::IsAnonBox(aChildPseudo)) {
  8002. NS_ASSERTION(aChildPseudo != nsCSSAnonBoxes::mozAnonymousBlock &&
  8003. aChildPseudo != nsCSSAnonBoxes::mozAnonymousPositionedBlock,
  8004. "Should have dealt with kids that have "
  8005. "NS_FRAME_PART_OF_IBSPLIT elsewhere");
  8006. return aProspectiveParent;
  8007. }
  8008. // Otherwise, walk up out of all anon boxes. For placeholder frames, walk out
  8009. // of all pseudo-elements as well. Otherwise ReparentStyleContext could cause
  8010. // style data to be out of sync with the frame tree.
  8011. nsIFrame* parent = aProspectiveParent;
  8012. do {
  8013. if (parent->GetStateBits() & NS_FRAME_PART_OF_IBSPLIT) {
  8014. nsIFrame* sibling = GetIBSplitSiblingForAnonymousBlock(parent);
  8015. if (sibling) {
  8016. // |parent| was a block in an {ib} split; use the inline as
  8017. // |the style parent.
  8018. parent = sibling;
  8019. }
  8020. }
  8021. nsIAtom* parentPseudo = parent->StyleContext()->GetPseudo();
  8022. if (!parentPseudo ||
  8023. (!nsCSSAnonBoxes::IsAnonBox(parentPseudo) &&
  8024. // nsPlaceholderFrame pases in nsGkAtoms::placeholderFrame for
  8025. // aChildPseudo (even though that's not a valid pseudo-type) just to
  8026. // trigger this behavior of walking up to the nearest non-pseudo
  8027. // ancestor.
  8028. aChildPseudo != nsGkAtoms::placeholderFrame)) {
  8029. return parent;
  8030. }
  8031. parent = parent->GetParent();
  8032. } while (parent);
  8033. if (aProspectiveParent->StyleContext()->GetPseudo() ==
  8034. nsCSSAnonBoxes::viewportScroll) {
  8035. // aProspectiveParent is the scrollframe for a viewport
  8036. // and the kids are the anonymous scrollbars
  8037. return aProspectiveParent;
  8038. }
  8039. // We can get here if the root element is absolutely positioned.
  8040. // We can't test for this very accurately, but it can only happen
  8041. // when the prospective parent is a canvas frame.
  8042. NS_ASSERTION(aProspectiveParent->GetType() == nsGkAtoms::canvasFrame,
  8043. "Should have found a parent before this");
  8044. return nullptr;
  8045. }
  8046. nsStyleContext*
  8047. nsFrame::DoGetParentStyleContext(nsIFrame** aProviderFrame) const
  8048. {
  8049. *aProviderFrame = nullptr;
  8050. // Handle display:contents and the root frame, when there's no parent frame
  8051. // to inherit from.
  8052. if (MOZ_LIKELY(mContent)) {
  8053. nsIContent* parentContent = mContent->GetFlattenedTreeParent();
  8054. if (MOZ_LIKELY(parentContent)) {
  8055. nsIAtom* pseudo = StyleContext()->GetPseudo();
  8056. if (!pseudo || !mContent->IsElement() ||
  8057. (!nsCSSAnonBoxes::IsAnonBox(pseudo) &&
  8058. // Ensure that we don't return the display:contents style
  8059. // of the parent content for pseudos that have the same content
  8060. // as their primary frame (like -moz-list-bullets do):
  8061. mContent->GetPrimaryFrame() == this) ||
  8062. /* if next is true then it's really a request for the table frame's
  8063. parent context, see nsTable[Outer]Frame::GetParentStyleContext. */
  8064. pseudo == nsCSSAnonBoxes::tableWrapper) {
  8065. nsFrameManager* fm = PresContext()->FrameManager();
  8066. nsStyleContext* sc = fm->GetDisplayContentsStyleFor(parentContent);
  8067. if (MOZ_UNLIKELY(sc)) {
  8068. return sc;
  8069. }
  8070. }
  8071. } else {
  8072. if (!StyleContext()->GetPseudo()) {
  8073. // we're a frame for the root. We have no style context parent.
  8074. return nullptr;
  8075. }
  8076. }
  8077. }
  8078. if (!(mState & NS_FRAME_OUT_OF_FLOW)) {
  8079. /*
  8080. * If this frame is an anonymous block created when an inline with a block
  8081. * inside it got split, then the parent style context is on its preceding
  8082. * inline. We can get to it using GetIBSplitSiblingForAnonymousBlock.
  8083. */
  8084. if (mState & NS_FRAME_PART_OF_IBSPLIT) {
  8085. nsIFrame* ibSplitSibling = GetIBSplitSiblingForAnonymousBlock(this);
  8086. if (ibSplitSibling) {
  8087. return (*aProviderFrame = ibSplitSibling)->StyleContext();
  8088. }
  8089. }
  8090. // If this frame is one of the blocks that split an inline, we must
  8091. // return the "special" inline parent, i.e., the parent that this
  8092. // frame would have if we didn't mangle the frame structure.
  8093. *aProviderFrame = GetCorrectedParent(this);
  8094. return *aProviderFrame ? (*aProviderFrame)->StyleContext() : nullptr;
  8095. }
  8096. // We're an out-of-flow frame. For out-of-flow frames, we must
  8097. // resolve underneath the placeholder's parent. The placeholder is
  8098. // reached from the first-in-flow.
  8099. nsIFrame* placeholder = FirstInFlow()->GetPlaceholderFrame();
  8100. if (!placeholder) {
  8101. NS_NOTREACHED("no placeholder frame for out-of-flow frame");
  8102. *aProviderFrame = GetCorrectedParent(this);
  8103. return *aProviderFrame ? (*aProviderFrame)->StyleContext() : nullptr;
  8104. }
  8105. return placeholder->GetParentStyleContext(aProviderFrame);
  8106. }
  8107. void
  8108. nsFrame::GetLastLeaf(nsPresContext* aPresContext, nsIFrame **aFrame)
  8109. {
  8110. if (!aFrame || !*aFrame)
  8111. return;
  8112. nsIFrame *child = *aFrame;
  8113. //if we are a block frame then go for the last line of 'this'
  8114. while (1){
  8115. child = child->PrincipalChildList().FirstChild();
  8116. if (!child)
  8117. return;//nothing to do
  8118. nsIFrame* siblingFrame;
  8119. nsIContent* content;
  8120. //ignore anonymous elements, e.g. mozTableAdd* mozTableRemove*
  8121. //see bug 278197 comment #12 #13 for details
  8122. while ((siblingFrame = child->GetNextSibling()) &&
  8123. (content = siblingFrame->GetContent()) &&
  8124. !content->IsRootOfNativeAnonymousSubtree())
  8125. child = siblingFrame;
  8126. *aFrame = child;
  8127. }
  8128. }
  8129. void
  8130. nsFrame::GetFirstLeaf(nsPresContext* aPresContext, nsIFrame **aFrame)
  8131. {
  8132. if (!aFrame || !*aFrame)
  8133. return;
  8134. nsIFrame *child = *aFrame;
  8135. while (1){
  8136. child = child->PrincipalChildList().FirstChild();
  8137. if (!child)
  8138. return;//nothing to do
  8139. *aFrame = child;
  8140. }
  8141. }
  8142. /* virtual */ bool
  8143. nsIFrame::IsFocusable(int32_t *aTabIndex, bool aWithMouse)
  8144. {
  8145. int32_t tabIndex = -1;
  8146. if (aTabIndex) {
  8147. *aTabIndex = -1; // Default for early return is not focusable
  8148. }
  8149. bool isFocusable = false;
  8150. if (mContent && mContent->IsElement() && IsVisibleConsideringAncestors() &&
  8151. StyleContext()->GetPseudo() != nsCSSAnonBoxes::anonymousFlexItem &&
  8152. StyleContext()->GetPseudo() != nsCSSAnonBoxes::anonymousGridItem) {
  8153. const nsStyleUserInterface* ui = StyleUserInterface();
  8154. if (ui->mUserFocus != StyleUserFocus::Ignore &&
  8155. ui->mUserFocus != StyleUserFocus::None) {
  8156. // Pass in default tabindex of -1 for nonfocusable and 0 for focusable
  8157. tabIndex = 0;
  8158. }
  8159. isFocusable = mContent->IsFocusable(&tabIndex, aWithMouse);
  8160. if (!isFocusable && !aWithMouse &&
  8161. GetType() == nsGkAtoms::scrollFrame &&
  8162. mContent->IsHTMLElement() &&
  8163. !mContent->IsRootOfNativeAnonymousSubtree() &&
  8164. mContent->GetParent() &&
  8165. !mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::tabindex)) {
  8166. // Elements with scrollable view are focusable with script & tabbable
  8167. // Otherwise you couldn't scroll them with keyboard, which is
  8168. // an accessibility issue (e.g. Section 508 rules)
  8169. // However, we don't make them to be focusable with the mouse,
  8170. // because the extra focus outlines are considered unnecessarily ugly.
  8171. // When clicked on, the selection position within the element
  8172. // will be enough to make them keyboard scrollable.
  8173. nsIScrollableFrame *scrollFrame = do_QueryFrame(this);
  8174. if (scrollFrame &&
  8175. !scrollFrame->GetScrollStyles().IsHiddenInBothDirections() &&
  8176. !scrollFrame->GetScrollRange().IsEqualEdges(nsRect(0, 0, 0, 0))) {
  8177. // Scroll bars will be used for overflow
  8178. isFocusable = true;
  8179. tabIndex = 0;
  8180. }
  8181. }
  8182. }
  8183. if (aTabIndex) {
  8184. *aTabIndex = tabIndex;
  8185. }
  8186. return isFocusable;
  8187. }
  8188. /**
  8189. * @return true if this text frame ends with a newline character which is
  8190. * treated as preformatted. It should return false if this is not a text frame.
  8191. */
  8192. bool
  8193. nsIFrame::HasSignificantTerminalNewline() const
  8194. {
  8195. return false;
  8196. }
  8197. static uint8_t
  8198. ConvertSVGDominantBaselineToVerticalAlign(uint8_t aDominantBaseline)
  8199. {
  8200. // Most of these are approximate mappings.
  8201. switch (aDominantBaseline) {
  8202. case NS_STYLE_DOMINANT_BASELINE_HANGING:
  8203. case NS_STYLE_DOMINANT_BASELINE_TEXT_BEFORE_EDGE:
  8204. return NS_STYLE_VERTICAL_ALIGN_TEXT_TOP;
  8205. case NS_STYLE_DOMINANT_BASELINE_TEXT_AFTER_EDGE:
  8206. case NS_STYLE_DOMINANT_BASELINE_IDEOGRAPHIC:
  8207. return NS_STYLE_VERTICAL_ALIGN_TEXT_BOTTOM;
  8208. case NS_STYLE_DOMINANT_BASELINE_CENTRAL:
  8209. case NS_STYLE_DOMINANT_BASELINE_MIDDLE:
  8210. case NS_STYLE_DOMINANT_BASELINE_MATHEMATICAL:
  8211. return NS_STYLE_VERTICAL_ALIGN_MIDDLE;
  8212. case NS_STYLE_DOMINANT_BASELINE_AUTO:
  8213. case NS_STYLE_DOMINANT_BASELINE_ALPHABETIC:
  8214. return NS_STYLE_VERTICAL_ALIGN_BASELINE;
  8215. case NS_STYLE_DOMINANT_BASELINE_USE_SCRIPT:
  8216. case NS_STYLE_DOMINANT_BASELINE_NO_CHANGE:
  8217. case NS_STYLE_DOMINANT_BASELINE_RESET_SIZE:
  8218. // These three should not simply map to 'baseline', but we don't
  8219. // support the complex baseline model that SVG 1.1 has and which
  8220. // css3-linebox now defines.
  8221. return NS_STYLE_VERTICAL_ALIGN_BASELINE;
  8222. default:
  8223. NS_NOTREACHED("unexpected aDominantBaseline value");
  8224. return NS_STYLE_VERTICAL_ALIGN_BASELINE;
  8225. }
  8226. }
  8227. uint8_t
  8228. nsIFrame::VerticalAlignEnum() const
  8229. {
  8230. if (IsSVGText()) {
  8231. uint8_t dominantBaseline;
  8232. for (const nsIFrame* frame = this; frame; frame = frame->GetParent()) {
  8233. dominantBaseline = frame->StyleSVGReset()->mDominantBaseline;
  8234. if (dominantBaseline != NS_STYLE_DOMINANT_BASELINE_AUTO ||
  8235. frame->GetType() == nsGkAtoms::svgTextFrame) {
  8236. break;
  8237. }
  8238. }
  8239. return ConvertSVGDominantBaselineToVerticalAlign(dominantBaseline);
  8240. }
  8241. const nsStyleCoord& verticalAlign = StyleDisplay()->mVerticalAlign;
  8242. if (verticalAlign.GetUnit() == eStyleUnit_Enumerated) {
  8243. return verticalAlign.GetIntValue();
  8244. }
  8245. return eInvalidVerticalAlign;
  8246. }
  8247. /* static */
  8248. void nsFrame::FillCursorInformationFromStyle(const nsStyleUserInterface* ui,
  8249. nsIFrame::Cursor& aCursor)
  8250. {
  8251. aCursor.mCursor = ui->mCursor;
  8252. aCursor.mHaveHotspot = false;
  8253. aCursor.mLoading = false;
  8254. aCursor.mHotspotX = aCursor.mHotspotY = 0.0f;
  8255. for (const nsCursorImage& item : ui->mCursorImages) {
  8256. uint32_t status;
  8257. nsresult rv = item.GetImage()->GetImageStatus(&status);
  8258. if (NS_SUCCEEDED(rv)) {
  8259. if (!(status & imgIRequest::STATUS_LOAD_COMPLETE)) {
  8260. // If we are falling back because any cursor before is loading,
  8261. // let the consumer know.
  8262. aCursor.mLoading = true;
  8263. } else if (!(status & imgIRequest::STATUS_ERROR)) {
  8264. // This is the one we want
  8265. item.GetImage()->GetImage(getter_AddRefs(aCursor.mContainer));
  8266. aCursor.mHaveHotspot = item.mHaveHotspot;
  8267. aCursor.mHotspotX = item.mHotspotX;
  8268. aCursor.mHotspotY = item.mHotspotY;
  8269. break;
  8270. }
  8271. }
  8272. }
  8273. }
  8274. NS_IMETHODIMP
  8275. nsFrame::RefreshSizeCache(nsBoxLayoutState& aState)
  8276. {
  8277. // XXXbz this comment needs some rewriting to make sense in the
  8278. // post-reflow-branch world.
  8279. // Ok we need to compute our minimum, preferred, and maximum sizes.
  8280. // 1) Maximum size. This is easy. Its infinite unless it is overloaded by CSS.
  8281. // 2) Preferred size. This is a little harder. This is the size the block would be
  8282. // if it were laid out on an infinite canvas. So we can get this by reflowing
  8283. // the block with and INTRINSIC width and height. We can also do a nice optimization
  8284. // for incremental reflow. If the reflow is incremental then we can pass a flag to
  8285. // have the block compute the preferred width for us! Preferred height can just be
  8286. // the minimum height;
  8287. // 3) Minimum size. This is a toughy. We can pass the block a flag asking for the max element
  8288. // size. That would give us the width. Unfortunately you can only ask for a maxElementSize
  8289. // during an incremental reflow. So on other reflows we will just have to use 0.
  8290. // The min height on the other hand is fairly easy we need to get the largest
  8291. // line height. This can be done with the line iterator.
  8292. // if we do have a rendering context
  8293. nsRenderingContext* rendContext = aState.GetRenderingContext();
  8294. if (rendContext) {
  8295. nsPresContext* presContext = aState.PresContext();
  8296. // If we don't have any HTML constraints and it's a resize, then nothing in the block
  8297. // could have changed, so no refresh is necessary.
  8298. nsBoxLayoutMetrics* metrics = BoxMetrics();
  8299. if (!DoesNeedRecalc(metrics->mBlockPrefSize))
  8300. return NS_OK;
  8301. // the rect we plan to size to.
  8302. nsRect rect = GetRect();
  8303. nsMargin bp(0,0,0,0);
  8304. GetXULBorderAndPadding(bp);
  8305. {
  8306. // If we're a container for font size inflation, then shrink
  8307. // wrapping inside of us should not apply font size inflation.
  8308. AutoMaybeDisableFontInflation an(this);
  8309. metrics->mBlockPrefSize.width =
  8310. GetPrefISize(rendContext) + bp.LeftRight();
  8311. metrics->mBlockMinSize.width =
  8312. GetMinISize(rendContext) + bp.LeftRight();
  8313. }
  8314. // do the nasty.
  8315. const WritingMode wm = aState.OuterReflowInput() ?
  8316. aState.OuterReflowInput()->GetWritingMode() : GetWritingMode();
  8317. ReflowOutput desiredSize(wm);
  8318. BoxReflow(aState, presContext, desiredSize, rendContext,
  8319. rect.x, rect.y,
  8320. metrics->mBlockPrefSize.width, NS_UNCONSTRAINEDSIZE);
  8321. metrics->mBlockMinSize.height = 0;
  8322. // ok we need the max ascent of the items on the line. So to do this
  8323. // ask the block for its line iterator. Get the max ascent.
  8324. nsAutoLineIterator lines = GetLineIterator();
  8325. if (lines)
  8326. {
  8327. metrics->mBlockMinSize.height = 0;
  8328. int count = 0;
  8329. nsIFrame* firstFrame = nullptr;
  8330. int32_t framesOnLine;
  8331. nsRect lineBounds;
  8332. do {
  8333. lines->GetLine(count, &firstFrame, &framesOnLine, lineBounds);
  8334. if (lineBounds.height > metrics->mBlockMinSize.height)
  8335. metrics->mBlockMinSize.height = lineBounds.height;
  8336. count++;
  8337. } while(firstFrame);
  8338. } else {
  8339. metrics->mBlockMinSize.height = desiredSize.Height();
  8340. }
  8341. metrics->mBlockPrefSize.height = metrics->mBlockMinSize.height;
  8342. if (desiredSize.BlockStartAscent() ==
  8343. ReflowOutput::ASK_FOR_BASELINE) {
  8344. if (!nsLayoutUtils::GetFirstLineBaseline(wm, this,
  8345. &metrics->mBlockAscent))
  8346. metrics->mBlockAscent = GetLogicalBaseline(wm);
  8347. } else {
  8348. metrics->mBlockAscent = desiredSize.BlockStartAscent();
  8349. }
  8350. #ifdef DEBUG_adaptor
  8351. printf("min=(%d,%d), pref=(%d,%d), ascent=%d\n", metrics->mBlockMinSize.width,
  8352. metrics->mBlockMinSize.height,
  8353. metrics->mBlockPrefSize.width,
  8354. metrics->mBlockPrefSize.height,
  8355. metrics->mBlockAscent);
  8356. #endif
  8357. }
  8358. return NS_OK;
  8359. }
  8360. /* virtual */ nsILineIterator*
  8361. nsFrame::GetLineIterator()
  8362. {
  8363. return nullptr;
  8364. }
  8365. nsSize
  8366. nsFrame::GetXULPrefSize(nsBoxLayoutState& aState)
  8367. {
  8368. nsSize size(0,0);
  8369. DISPLAY_PREF_SIZE(this, size);
  8370. // If the size is cached, and there are no HTML constraints that we might
  8371. // be depending on, then we just return the cached size.
  8372. nsBoxLayoutMetrics *metrics = BoxMetrics();
  8373. if (!DoesNeedRecalc(metrics->mPrefSize)) {
  8374. return metrics->mPrefSize;
  8375. }
  8376. if (IsXULCollapsed())
  8377. return size;
  8378. // get our size in CSS.
  8379. bool widthSet, heightSet;
  8380. bool completelyRedefined = nsIFrame::AddXULPrefSize(this, size, widthSet, heightSet);
  8381. // Refresh our caches with new sizes.
  8382. if (!completelyRedefined) {
  8383. RefreshSizeCache(aState);
  8384. nsSize blockSize = metrics->mBlockPrefSize;
  8385. // notice we don't need to add our borders or padding
  8386. // in. That's because the block did it for us.
  8387. if (!widthSet)
  8388. size.width = blockSize.width;
  8389. if (!heightSet)
  8390. size.height = blockSize.height;
  8391. }
  8392. metrics->mPrefSize = size;
  8393. return size;
  8394. }
  8395. nsSize
  8396. nsFrame::GetXULMinSize(nsBoxLayoutState& aState)
  8397. {
  8398. nsSize size(0,0);
  8399. DISPLAY_MIN_SIZE(this, size);
  8400. // Don't use the cache if we have HTMLReflowInput constraints --- they might have changed
  8401. nsBoxLayoutMetrics *metrics = BoxMetrics();
  8402. if (!DoesNeedRecalc(metrics->mMinSize)) {
  8403. size = metrics->mMinSize;
  8404. return size;
  8405. }
  8406. if (IsXULCollapsed())
  8407. return size;
  8408. // get our size in CSS.
  8409. bool widthSet, heightSet;
  8410. bool completelyRedefined =
  8411. nsIFrame::AddXULMinSize(aState, this, size, widthSet, heightSet);
  8412. // Refresh our caches with new sizes.
  8413. if (!completelyRedefined) {
  8414. RefreshSizeCache(aState);
  8415. nsSize blockSize = metrics->mBlockMinSize;
  8416. if (!widthSet)
  8417. size.width = blockSize.width;
  8418. if (!heightSet)
  8419. size.height = blockSize.height;
  8420. }
  8421. metrics->mMinSize = size;
  8422. return size;
  8423. }
  8424. nsSize
  8425. nsFrame::GetXULMaxSize(nsBoxLayoutState& aState)
  8426. {
  8427. nsSize size(NS_INTRINSICSIZE, NS_INTRINSICSIZE);
  8428. DISPLAY_MAX_SIZE(this, size);
  8429. // Don't use the cache if we have HTMLReflowInput constraints --- they might have changed
  8430. nsBoxLayoutMetrics *metrics = BoxMetrics();
  8431. if (!DoesNeedRecalc(metrics->mMaxSize)) {
  8432. size = metrics->mMaxSize;
  8433. return size;
  8434. }
  8435. if (IsXULCollapsed())
  8436. return size;
  8437. size = nsBox::GetXULMaxSize(aState);
  8438. metrics->mMaxSize = size;
  8439. return size;
  8440. }
  8441. nscoord
  8442. nsFrame::GetXULFlex()
  8443. {
  8444. nsBoxLayoutMetrics *metrics = BoxMetrics();
  8445. if (!DoesNeedRecalc(metrics->mFlex))
  8446. return metrics->mFlex;
  8447. metrics->mFlex = nsBox::GetXULFlex();
  8448. return metrics->mFlex;
  8449. }
  8450. nscoord
  8451. nsFrame::GetXULBoxAscent(nsBoxLayoutState& aState)
  8452. {
  8453. nsBoxLayoutMetrics *metrics = BoxMetrics();
  8454. if (!DoesNeedRecalc(metrics->mAscent))
  8455. return metrics->mAscent;
  8456. if (IsXULCollapsed()) {
  8457. metrics->mAscent = 0;
  8458. } else {
  8459. // Refresh our caches with new sizes.
  8460. RefreshSizeCache(aState);
  8461. metrics->mAscent = metrics->mBlockAscent;
  8462. }
  8463. return metrics->mAscent;
  8464. }
  8465. nsresult
  8466. nsFrame::DoXULLayout(nsBoxLayoutState& aState)
  8467. {
  8468. nsRect ourRect(mRect);
  8469. nsRenderingContext* rendContext = aState.GetRenderingContext();
  8470. nsPresContext* presContext = aState.PresContext();
  8471. WritingMode ourWM = GetWritingMode();
  8472. const WritingMode outerWM = aState.OuterReflowInput() ?
  8473. aState.OuterReflowInput()->GetWritingMode() : ourWM;
  8474. ReflowOutput desiredSize(outerWM);
  8475. LogicalSize ourSize = GetLogicalSize(outerWM);
  8476. if (rendContext) {
  8477. BoxReflow(aState, presContext, desiredSize, rendContext,
  8478. ourRect.x, ourRect.y, ourRect.width, ourRect.height);
  8479. if (IsXULCollapsed()) {
  8480. SetSize(nsSize(0, 0));
  8481. } else {
  8482. // if our child needs to be bigger. This might happend with
  8483. // wrapping text. There is no way to predict its height until we
  8484. // reflow it. Now that we know the height reshuffle upward.
  8485. if (desiredSize.ISize(outerWM) > ourSize.ISize(outerWM) ||
  8486. desiredSize.BSize(outerWM) > ourSize.BSize(outerWM)) {
  8487. #ifdef DEBUG_GROW
  8488. XULDumpBox(stdout);
  8489. printf(" GREW from (%d,%d) -> (%d,%d)\n",
  8490. ourSize.ISize(outerWM), ourSize.BSize(outerWM),
  8491. desiredSize.ISize(outerWM), desiredSize.BSize(outerWM));
  8492. #endif
  8493. if (desiredSize.ISize(outerWM) > ourSize.ISize(outerWM)) {
  8494. ourSize.ISize(outerWM) = desiredSize.ISize(outerWM);
  8495. }
  8496. if (desiredSize.BSize(outerWM) > ourSize.BSize(outerWM)) {
  8497. ourSize.BSize(outerWM) = desiredSize.BSize(outerWM);
  8498. }
  8499. }
  8500. // ensure our size is what we think is should be. Someone could have
  8501. // reset the frame to be smaller or something dumb like that.
  8502. SetSize(ourSize.ConvertTo(ourWM, outerWM));
  8503. }
  8504. }
  8505. // Should we do this if IsXULCollapsed() is true?
  8506. LogicalSize size(GetLogicalSize(outerWM));
  8507. desiredSize.ISize(outerWM) = size.ISize(outerWM);
  8508. desiredSize.BSize(outerWM) = size.BSize(outerWM);
  8509. desiredSize.UnionOverflowAreasWithDesiredBounds();
  8510. if (HasAbsolutelyPositionedChildren()) {
  8511. // Set up a |reflowInput| to pass into ReflowAbsoluteFrames
  8512. ReflowInput reflowInput(aState.PresContext(), this,
  8513. aState.GetRenderingContext(),
  8514. LogicalSize(ourWM, ISize(),
  8515. NS_UNCONSTRAINEDSIZE),
  8516. ReflowInput::DUMMY_PARENT_REFLOW_STATE);
  8517. AddStateBits(NS_FRAME_IN_REFLOW);
  8518. // Set up a |reflowStatus| to pass into ReflowAbsoluteFrames
  8519. // (just a dummy value; hopefully that's OK)
  8520. nsReflowStatus reflowStatus = NS_FRAME_COMPLETE;
  8521. ReflowAbsoluteFrames(aState.PresContext(), desiredSize,
  8522. reflowInput, reflowStatus);
  8523. RemoveStateBits(NS_FRAME_IN_REFLOW);
  8524. }
  8525. nsSize oldSize(ourRect.Size());
  8526. FinishAndStoreOverflow(desiredSize.mOverflowAreas,
  8527. size.GetPhysicalSize(outerWM), &oldSize);
  8528. SyncLayout(aState);
  8529. return NS_OK;
  8530. }
  8531. void
  8532. nsFrame::BoxReflow(nsBoxLayoutState& aState,
  8533. nsPresContext* aPresContext,
  8534. ReflowOutput& aDesiredSize,
  8535. nsRenderingContext* aRenderingContext,
  8536. nscoord aX,
  8537. nscoord aY,
  8538. nscoord aWidth,
  8539. nscoord aHeight,
  8540. bool aMoveFrame)
  8541. {
  8542. DO_GLOBAL_REFLOW_COUNT("nsBoxToBlockAdaptor");
  8543. #ifdef DEBUG_REFLOW
  8544. nsAdaptorAddIndents();
  8545. printf("Reflowing: ");
  8546. nsFrame::ListTag(stdout, mFrame);
  8547. printf("\n");
  8548. gIndent2++;
  8549. #endif
  8550. nsBoxLayoutMetrics *metrics = BoxMetrics();
  8551. nsReflowStatus status = NS_FRAME_COMPLETE;
  8552. WritingMode wm = aDesiredSize.GetWritingMode();
  8553. bool needsReflow = NS_SUBTREE_DIRTY(this);
  8554. // if we don't need a reflow then
  8555. // lets see if we are already that size. Yes? then don't even reflow. We are done.
  8556. if (!needsReflow) {
  8557. if (aWidth != NS_INTRINSICSIZE && aHeight != NS_INTRINSICSIZE) {
  8558. // if the new calculated size has a 0 width or a 0 height
  8559. if ((metrics->mLastSize.width == 0 || metrics->mLastSize.height == 0) && (aWidth == 0 || aHeight == 0)) {
  8560. needsReflow = false;
  8561. aDesiredSize.Width() = aWidth;
  8562. aDesiredSize.Height() = aHeight;
  8563. SetSize(aDesiredSize.Size(wm).ConvertTo(GetWritingMode(), wm));
  8564. } else {
  8565. aDesiredSize.Width() = metrics->mLastSize.width;
  8566. aDesiredSize.Height() = metrics->mLastSize.height;
  8567. // remove the margin. The rect of our child does not include it but our calculated size does.
  8568. // don't reflow if we are already the right size
  8569. if (metrics->mLastSize.width == aWidth && metrics->mLastSize.height == aHeight)
  8570. needsReflow = false;
  8571. else
  8572. needsReflow = true;
  8573. }
  8574. } else {
  8575. // if the width or height are intrinsic alway reflow because
  8576. // we don't know what it should be.
  8577. needsReflow = true;
  8578. }
  8579. }
  8580. // ok now reflow the child into the spacers calculated space
  8581. if (needsReflow) {
  8582. aDesiredSize.ClearSize();
  8583. // create a reflow state to tell our child to flow at the given size.
  8584. // Construct a bogus parent reflow state so that there's a usable
  8585. // containing block reflow state.
  8586. nsMargin margin(0,0,0,0);
  8587. GetXULMargin(margin);
  8588. nsSize parentSize(aWidth, aHeight);
  8589. if (parentSize.height != NS_INTRINSICSIZE)
  8590. parentSize.height += margin.TopBottom();
  8591. if (parentSize.width != NS_INTRINSICSIZE)
  8592. parentSize.width += margin.LeftRight();
  8593. nsIFrame *parentFrame = GetParent();
  8594. nsFrameState savedState = parentFrame->GetStateBits();
  8595. WritingMode parentWM = parentFrame->GetWritingMode();
  8596. ReflowInput
  8597. parentReflowInput(aPresContext, parentFrame, aRenderingContext,
  8598. LogicalSize(parentWM, parentSize),
  8599. ReflowInput::DUMMY_PARENT_REFLOW_STATE);
  8600. parentFrame->RemoveStateBits(~nsFrameState(0));
  8601. parentFrame->AddStateBits(savedState);
  8602. // This may not do very much useful, but it's probably worth trying.
  8603. if (parentSize.width != NS_INTRINSICSIZE)
  8604. parentReflowInput.SetComputedWidth(std::max(parentSize.width, 0));
  8605. if (parentSize.height != NS_INTRINSICSIZE)
  8606. parentReflowInput.SetComputedHeight(std::max(parentSize.height, 0));
  8607. parentReflowInput.ComputedPhysicalMargin().SizeTo(0, 0, 0, 0);
  8608. // XXX use box methods
  8609. parentFrame->GetXULPadding(parentReflowInput.ComputedPhysicalPadding());
  8610. parentFrame->GetXULBorder(parentReflowInput.ComputedPhysicalBorderPadding());
  8611. parentReflowInput.ComputedPhysicalBorderPadding() +=
  8612. parentReflowInput.ComputedPhysicalPadding();
  8613. // Construct the parent chain manually since constructing it normally
  8614. // messes up dimensions.
  8615. const ReflowInput *outerReflowInput = aState.OuterReflowInput();
  8616. NS_ASSERTION(!outerReflowInput || outerReflowInput->mFrame != this,
  8617. "in and out of XUL on a single frame?");
  8618. const ReflowInput* parentRI;
  8619. if (outerReflowInput && outerReflowInput->mFrame == parentFrame) {
  8620. // We're a frame (such as a text control frame) that jumps into
  8621. // box reflow and then straight out of it on the child frame.
  8622. // This means we actually have a real parent reflow state.
  8623. // nsLayoutUtils::InflationMinFontSizeFor used to need this to be
  8624. // linked up correctly for text control frames, so do so here).
  8625. parentRI = outerReflowInput;
  8626. } else {
  8627. parentRI = &parentReflowInput;
  8628. }
  8629. // XXX Is it OK that this reflow state has only one ancestor?
  8630. // (It used to have a bogus parent, skipping all the boxes).
  8631. WritingMode wm = GetWritingMode();
  8632. LogicalSize logicalSize(wm, nsSize(aWidth, aHeight));
  8633. logicalSize.BSize(wm) = NS_INTRINSICSIZE;
  8634. ReflowInput reflowInput(aPresContext, *parentRI, this,
  8635. logicalSize, nullptr,
  8636. ReflowInput::DUMMY_PARENT_REFLOW_STATE);
  8637. // XXX_jwir3: This is somewhat fishy. If this is actually changing the value
  8638. // here (which it might be), then we should make sure that it's
  8639. // correct the first time around, rather than changing it later.
  8640. reflowInput.mCBReflowInput = parentRI;
  8641. reflowInput.mReflowDepth = aState.GetReflowDepth();
  8642. // mComputedWidth and mComputedHeight are content-box, not
  8643. // border-box
  8644. if (aWidth != NS_INTRINSICSIZE) {
  8645. nscoord computedWidth =
  8646. aWidth - reflowInput.ComputedPhysicalBorderPadding().LeftRight();
  8647. computedWidth = std::max(computedWidth, 0);
  8648. reflowInput.SetComputedWidth(computedWidth);
  8649. }
  8650. // Most child frames of box frames (e.g. subdocument or scroll frames)
  8651. // need to be constrained to the provided size and overflow as necessary.
  8652. // The one exception are block frames, because we need to know their
  8653. // natural height excluding any overflow area which may be caused by
  8654. // various CSS effects such as shadow or outline.
  8655. if (!IsFrameOfType(eBlockFrame)) {
  8656. if (aHeight != NS_INTRINSICSIZE) {
  8657. nscoord computedHeight =
  8658. aHeight - reflowInput.ComputedPhysicalBorderPadding().TopBottom();
  8659. computedHeight = std::max(computedHeight, 0);
  8660. reflowInput.SetComputedHeight(computedHeight);
  8661. } else {
  8662. reflowInput.SetComputedHeight(
  8663. ComputeSize(aRenderingContext, wm,
  8664. logicalSize,
  8665. logicalSize.ISize(wm),
  8666. reflowInput.ComputedLogicalMargin().Size(wm),
  8667. reflowInput.ComputedLogicalBorderPadding().Size(wm) -
  8668. reflowInput.ComputedLogicalPadding().Size(wm),
  8669. reflowInput.ComputedLogicalPadding().Size(wm),
  8670. ComputeSizeFlags::eDefault).Height(wm));
  8671. }
  8672. }
  8673. // Box layout calls SetRect before XULLayout, whereas non-box layout
  8674. // calls SetRect after Reflow.
  8675. // XXX Perhaps we should be doing this by twiddling the rect back to
  8676. // mLastSize before calling Reflow and then switching it back, but
  8677. // However, mLastSize can also be the size passed to BoxReflow by
  8678. // RefreshSizeCache, so that doesn't really make sense.
  8679. if (metrics->mLastSize.width != aWidth) {
  8680. reflowInput.SetHResize(true);
  8681. // When font size inflation is enabled, a horizontal resize
  8682. // requires a full reflow. See ReflowInput::InitResizeFlags
  8683. // for more details.
  8684. if (nsLayoutUtils::FontSizeInflationEnabled(aPresContext)) {
  8685. AddStateBits(NS_FRAME_IS_DIRTY);
  8686. }
  8687. }
  8688. if (metrics->mLastSize.height != aHeight) {
  8689. reflowInput.SetVResize(true);
  8690. }
  8691. #ifdef DEBUG_REFLOW
  8692. nsAdaptorAddIndents();
  8693. printf("Size=(%d,%d)\n",reflowInput.ComputedWidth(),
  8694. reflowInput.ComputedHeight());
  8695. nsAdaptorAddIndents();
  8696. nsAdaptorPrintReason(reflowInput);
  8697. printf("\n");
  8698. #endif
  8699. // place the child and reflow
  8700. Reflow(aPresContext, aDesiredSize, reflowInput, status);
  8701. NS_ASSERTION(NS_FRAME_IS_COMPLETE(status), "bad status");
  8702. uint32_t layoutFlags = aState.LayoutFlags();
  8703. nsContainerFrame::FinishReflowChild(this, aPresContext, aDesiredSize,
  8704. &reflowInput, aX, aY, layoutFlags | NS_FRAME_NO_MOVE_FRAME);
  8705. // Save the ascent. (bug 103925)
  8706. if (IsXULCollapsed()) {
  8707. metrics->mAscent = 0;
  8708. } else {
  8709. if (aDesiredSize.BlockStartAscent() ==
  8710. ReflowOutput::ASK_FOR_BASELINE) {
  8711. if (!nsLayoutUtils::GetFirstLineBaseline(wm, this, &metrics->mAscent))
  8712. metrics->mAscent = GetLogicalBaseline(wm);
  8713. } else
  8714. metrics->mAscent = aDesiredSize.BlockStartAscent();
  8715. }
  8716. } else {
  8717. aDesiredSize.SetBlockStartAscent(metrics->mBlockAscent);
  8718. }
  8719. #ifdef DEBUG_REFLOW
  8720. if (aHeight != NS_INTRINSICSIZE && aDesiredSize.Height() != aHeight)
  8721. {
  8722. nsAdaptorAddIndents();
  8723. printf("*****got taller!*****\n");
  8724. }
  8725. if (aWidth != NS_INTRINSICSIZE && aDesiredSize.Width() != aWidth)
  8726. {
  8727. nsAdaptorAddIndents();
  8728. printf("*****got wider!******\n");
  8729. }
  8730. #endif
  8731. if (aWidth == NS_INTRINSICSIZE)
  8732. aWidth = aDesiredSize.Width();
  8733. if (aHeight == NS_INTRINSICSIZE)
  8734. aHeight = aDesiredSize.Height();
  8735. metrics->mLastSize.width = aDesiredSize.Width();
  8736. metrics->mLastSize.height = aDesiredSize.Height();
  8737. #ifdef DEBUG_REFLOW
  8738. gIndent2--;
  8739. #endif
  8740. }
  8741. nsBoxLayoutMetrics*
  8742. nsFrame::BoxMetrics() const
  8743. {
  8744. nsBoxLayoutMetrics* metrics = GetProperty(BoxMetricsProperty());
  8745. NS_ASSERTION(metrics, "A box layout method was called but InitBoxMetrics was never called");
  8746. return metrics;
  8747. }
  8748. /* static */ void
  8749. nsIFrame::AddInPopupStateBitToDescendants(nsIFrame* aFrame)
  8750. {
  8751. if (!aFrame->HasAnyStateBits(NS_FRAME_IN_POPUP) &&
  8752. aFrame->TrackingVisibility()) {
  8753. // Assume all frames in popups are visible.
  8754. aFrame->IncApproximateVisibleCount();
  8755. }
  8756. aFrame->AddStateBits(NS_FRAME_IN_POPUP);
  8757. AutoTArray<nsIFrame::ChildList,4> childListArray;
  8758. aFrame->GetCrossDocChildLists(&childListArray);
  8759. nsIFrame::ChildListArrayIterator lists(childListArray);
  8760. for (; !lists.IsDone(); lists.Next()) {
  8761. nsFrameList::Enumerator childFrames(lists.CurrentList());
  8762. for (; !childFrames.AtEnd(); childFrames.Next()) {
  8763. AddInPopupStateBitToDescendants(childFrames.get());
  8764. }
  8765. }
  8766. }
  8767. /* static */ void
  8768. nsIFrame::RemoveInPopupStateBitFromDescendants(nsIFrame* aFrame)
  8769. {
  8770. if (!aFrame->HasAnyStateBits(NS_FRAME_IN_POPUP) ||
  8771. nsLayoutUtils::IsPopup(aFrame)) {
  8772. return;
  8773. }
  8774. aFrame->RemoveStateBits(NS_FRAME_IN_POPUP);
  8775. if (aFrame->TrackingVisibility()) {
  8776. // We assume all frames in popups are visible, so this decrement balances
  8777. // out the increment in AddInPopupStateBitToDescendants above.
  8778. aFrame->DecApproximateVisibleCount();
  8779. }
  8780. AutoTArray<nsIFrame::ChildList,4> childListArray;
  8781. aFrame->GetCrossDocChildLists(&childListArray);
  8782. nsIFrame::ChildListArrayIterator lists(childListArray);
  8783. for (; !lists.IsDone(); lists.Next()) {
  8784. nsFrameList::Enumerator childFrames(lists.CurrentList());
  8785. for (; !childFrames.AtEnd(); childFrames.Next()) {
  8786. RemoveInPopupStateBitFromDescendants(childFrames.get());
  8787. }
  8788. }
  8789. }
  8790. void
  8791. nsIFrame::SetParent(nsContainerFrame* aParent)
  8792. {
  8793. // Note that the current mParent may already be destroyed at this point.
  8794. mParent = aParent;
  8795. if (::IsXULBoxWrapped(this)) {
  8796. ::InitBoxMetrics(this, true);
  8797. } else {
  8798. // We could call Properties().Delete(BoxMetricsProperty()); here but
  8799. // that's kind of slow and re-parenting in such a way that we were
  8800. // IsXULBoxWrapped() before but not now should be very rare, so we'll just
  8801. // keep this unused frame property until this frame dies instead.
  8802. }
  8803. if (GetStateBits() & (NS_FRAME_HAS_VIEW | NS_FRAME_HAS_CHILD_WITH_VIEW)) {
  8804. for (nsIFrame* f = aParent;
  8805. f && !(f->GetStateBits() & NS_FRAME_HAS_CHILD_WITH_VIEW);
  8806. f = f->GetParent()) {
  8807. f->AddStateBits(NS_FRAME_HAS_CHILD_WITH_VIEW);
  8808. }
  8809. }
  8810. if (HasAnyStateBits(NS_FRAME_CONTAINS_RELATIVE_BSIZE)) {
  8811. for (nsIFrame* f = aParent; f; f = f->GetParent()) {
  8812. if (f->HasAnyStateBits(NS_FRAME_CONTAINS_RELATIVE_BSIZE)) {
  8813. break;
  8814. }
  8815. f->AddStateBits(NS_FRAME_CONTAINS_RELATIVE_BSIZE);
  8816. }
  8817. }
  8818. if (HasAnyStateBits(NS_FRAME_DESCENDANT_INTRINSIC_ISIZE_DEPENDS_ON_BSIZE)) {
  8819. for (nsIFrame* f = aParent; f; f = f->GetParent()) {
  8820. if (f->HasAnyStateBits(NS_FRAME_DESCENDANT_INTRINSIC_ISIZE_DEPENDS_ON_BSIZE)) {
  8821. break;
  8822. }
  8823. f->AddStateBits(NS_FRAME_DESCENDANT_INTRINSIC_ISIZE_DEPENDS_ON_BSIZE);
  8824. }
  8825. }
  8826. if (HasInvalidFrameInSubtree()) {
  8827. for (nsIFrame* f = aParent;
  8828. f && !f->HasAnyStateBits(NS_FRAME_DESCENDANT_NEEDS_PAINT | NS_FRAME_IS_NONDISPLAY);
  8829. f = nsLayoutUtils::GetCrossDocParentFrame(f)) {
  8830. f->AddStateBits(NS_FRAME_DESCENDANT_NEEDS_PAINT);
  8831. }
  8832. }
  8833. if (aParent->HasAnyStateBits(NS_FRAME_IN_POPUP)) {
  8834. AddInPopupStateBitToDescendants(this);
  8835. } else {
  8836. RemoveInPopupStateBitFromDescendants(this);
  8837. }
  8838. // If our new parent only has invalid children, then we just invalidate
  8839. // ourselves too. This is probably faster than clearing the flag all
  8840. // the way up the frame tree.
  8841. if (aParent->HasAnyStateBits(NS_FRAME_ALL_DESCENDANTS_NEED_PAINT)) {
  8842. InvalidateFrame();
  8843. }
  8844. }
  8845. void
  8846. nsIFrame::CreateOwnLayerIfNeeded(nsDisplayListBuilder* aBuilder,
  8847. nsDisplayList* aList)
  8848. {
  8849. if (GetContent() &&
  8850. GetContent()->IsXULElement() &&
  8851. GetContent()->HasAttr(kNameSpaceID_None, nsGkAtoms::layer)) {
  8852. aList->AppendNewToTop(new (aBuilder)
  8853. nsDisplayOwnLayer(aBuilder, this, aList));
  8854. }
  8855. }
  8856. bool
  8857. nsIFrame::IsSelected() const
  8858. {
  8859. return (GetContent() && GetContent()->IsSelectionDescendant()) ?
  8860. IsFrameSelected() : false;
  8861. }
  8862. /*static*/ void
  8863. nsIFrame::DestroyContentArray(ContentArray* aArray)
  8864. {
  8865. for (nsIContent* content : *aArray) {
  8866. content->UnbindFromTree();
  8867. NS_RELEASE(content);
  8868. }
  8869. delete aArray;
  8870. }
  8871. bool
  8872. nsIFrame::IsPseudoStackingContextFromStyle() {
  8873. // If you change this, also change the computation of pseudoStackingContext
  8874. // in BuildDisplayListForChild()
  8875. if (StyleEffects()->mOpacity != 1.0f) {
  8876. return true;
  8877. }
  8878. const nsStyleDisplay* disp = StyleDisplay();
  8879. return disp->IsAbsPosContainingBlock(this) ||
  8880. disp->IsFloating(this) ||
  8881. (disp->mWillChangeBitField & NS_STYLE_WILL_CHANGE_STACKING_CONTEXT);
  8882. }
  8883. Element*
  8884. nsIFrame::GetPseudoElement(CSSPseudoElementType aType)
  8885. {
  8886. if (!mContent) {
  8887. return nullptr;
  8888. }
  8889. if (aType == CSSPseudoElementType::before) {
  8890. return nsLayoutUtils::GetBeforePseudo(mContent);
  8891. }
  8892. if (aType == CSSPseudoElementType::after) {
  8893. return nsLayoutUtils::GetAfterPseudo(mContent);
  8894. }
  8895. return nullptr;
  8896. }
  8897. static bool
  8898. IsFrameScrolledOutOfView(nsIFrame *aFrame)
  8899. {
  8900. nsIScrollableFrame* scrollableFrame =
  8901. nsLayoutUtils::GetNearestScrollableFrame(aFrame,
  8902. nsLayoutUtils::SCROLLABLE_SAME_DOC |
  8903. nsLayoutUtils::SCROLLABLE_INCLUDE_HIDDEN);
  8904. if (!scrollableFrame) {
  8905. return false;
  8906. }
  8907. nsIFrame *scrollableParent = do_QueryFrame(scrollableFrame);
  8908. nsRect rect = aFrame->GetVisualOverflowRect();
  8909. nsRect transformedRect =
  8910. nsLayoutUtils::TransformFrameRectToAncestor(aFrame,
  8911. rect,
  8912. scrollableParent);
  8913. nsRect scrollableRect = scrollableParent->GetVisualOverflowRect();
  8914. if (!transformedRect.Intersects(scrollableRect)) {
  8915. return true;
  8916. }
  8917. nsIFrame* parent = scrollableParent->GetParent();
  8918. if (!parent) {
  8919. return false;
  8920. }
  8921. return IsFrameScrolledOutOfView(parent);
  8922. }
  8923. bool
  8924. nsIFrame::IsScrolledOutOfView()
  8925. {
  8926. return IsFrameScrolledOutOfView(this);
  8927. }
  8928. nsIFrame::CaretPosition::CaretPosition()
  8929. : mContentOffset(0)
  8930. {
  8931. }
  8932. nsIFrame::CaretPosition::~CaretPosition()
  8933. {
  8934. }
  8935. bool
  8936. nsFrame::HasCSSAnimations()
  8937. {
  8938. auto collection =
  8939. AnimationCollection<CSSAnimation>::GetAnimationCollection(this);
  8940. return collection && collection->mAnimations.Length() > 0;
  8941. }
  8942. bool
  8943. nsFrame::HasCSSTransitions()
  8944. {
  8945. auto collection =
  8946. AnimationCollection<CSSTransition>::GetAnimationCollection(this);
  8947. return collection && collection->mAnimations.Length() > 0;
  8948. }
  8949. size_t
  8950. nsIFrame::SizeOfFramePropertiesForTree(MallocSizeOf aMallocSizeOf) const
  8951. {
  8952. size_t result = 0;
  8953. result += mProperties.SizeOfExcludingThis(aMallocSizeOf);
  8954. FrameChildListIterator iter(this);
  8955. while (!iter.IsDone()) {
  8956. for (const nsIFrame* f : iter.CurrentList()) {
  8957. result += f->SizeOfFramePropertiesForTree(aMallocSizeOf);
  8958. }
  8959. iter.Next();
  8960. }
  8961. return result;
  8962. }
  8963. // Box layout debugging
  8964. #ifdef DEBUG_REFLOW
  8965. int32_t gIndent2 = 0;
  8966. void
  8967. nsAdaptorAddIndents()
  8968. {
  8969. for(int32_t i=0; i < gIndent2; i++)
  8970. {
  8971. printf(" ");
  8972. }
  8973. }
  8974. void
  8975. nsAdaptorPrintReason(ReflowInput& aReflowInput)
  8976. {
  8977. char* reflowReasonString;
  8978. switch(aReflowInput.reason)
  8979. {
  8980. case eReflowReason_Initial:
  8981. reflowReasonString = "initial";
  8982. break;
  8983. case eReflowReason_Resize:
  8984. reflowReasonString = "resize";
  8985. break;
  8986. case eReflowReason_Dirty:
  8987. reflowReasonString = "dirty";
  8988. break;
  8989. case eReflowReason_StyleChange:
  8990. reflowReasonString = "stylechange";
  8991. break;
  8992. case eReflowReason_Incremental:
  8993. {
  8994. switch (aReflowInput.reflowCommand->Type()) {
  8995. case eReflowType_StyleChanged:
  8996. reflowReasonString = "incremental (StyleChanged)";
  8997. break;
  8998. case eReflowType_ReflowDirty:
  8999. reflowReasonString = "incremental (ReflowDirty)";
  9000. break;
  9001. default:
  9002. reflowReasonString = "incremental (Unknown)";
  9003. }
  9004. }
  9005. break;
  9006. default:
  9007. reflowReasonString = "unknown";
  9008. break;
  9009. }
  9010. printf("%s",reflowReasonString);
  9011. }
  9012. #endif
  9013. #ifdef DEBUG_LAYOUT
  9014. void
  9015. nsFrame::GetBoxName(nsAutoString& aName)
  9016. {
  9017. GetFrameName(aName);
  9018. }
  9019. #endif
  9020. #ifdef DEBUG
  9021. static void
  9022. GetTagName(nsFrame* aFrame, nsIContent* aContent, int aResultSize,
  9023. char* aResult)
  9024. {
  9025. if (aContent) {
  9026. snprintf(aResult, aResultSize, "%s@%p",
  9027. nsAtomCString(aContent->NodeInfo()->NameAtom()).get(), aFrame);
  9028. }
  9029. else {
  9030. snprintf(aResult, aResultSize, "@%p", aFrame);
  9031. }
  9032. }
  9033. void
  9034. nsFrame::Trace(const char* aMethod, bool aEnter)
  9035. {
  9036. if (NS_FRAME_LOG_TEST(sFrameLogModule, NS_FRAME_TRACE_CALLS)) {
  9037. char tagbuf[40];
  9038. GetTagName(this, mContent, sizeof(tagbuf), tagbuf);
  9039. PR_LogPrint("%s: %s %s", tagbuf, aEnter ? "enter" : "exit", aMethod);
  9040. }
  9041. }
  9042. void
  9043. nsFrame::Trace(const char* aMethod, bool aEnter, nsReflowStatus aStatus)
  9044. {
  9045. if (NS_FRAME_LOG_TEST(sFrameLogModule, NS_FRAME_TRACE_CALLS)) {
  9046. char tagbuf[40];
  9047. GetTagName(this, mContent, sizeof(tagbuf), tagbuf);
  9048. PR_LogPrint("%s: %s %s, status=%scomplete%s",
  9049. tagbuf, aEnter ? "enter" : "exit", aMethod,
  9050. NS_FRAME_IS_NOT_COMPLETE(aStatus) ? "not" : "",
  9051. (NS_FRAME_REFLOW_NEXTINFLOW & aStatus) ? "+reflow" : "");
  9052. }
  9053. }
  9054. void
  9055. nsFrame::TraceMsg(const char* aFormatString, ...)
  9056. {
  9057. if (NS_FRAME_LOG_TEST(sFrameLogModule, NS_FRAME_TRACE_CALLS)) {
  9058. // Format arguments into a buffer
  9059. char argbuf[200];
  9060. va_list ap;
  9061. va_start(ap, aFormatString);
  9062. PR_vsnprintf(argbuf, sizeof(argbuf), aFormatString, ap);
  9063. va_end(ap);
  9064. char tagbuf[40];
  9065. GetTagName(this, mContent, sizeof(tagbuf), tagbuf);
  9066. PR_LogPrint("%s: %s", tagbuf, argbuf);
  9067. }
  9068. }
  9069. void
  9070. nsFrame::VerifyDirtyBitSet(const nsFrameList& aFrameList)
  9071. {
  9072. for (nsFrameList::Enumerator e(aFrameList); !e.AtEnd(); e.Next()) {
  9073. NS_ASSERTION(e.get()->GetStateBits() & NS_FRAME_IS_DIRTY,
  9074. "dirty bit not set");
  9075. }
  9076. }
  9077. // Start Display Reflow
  9078. #ifdef DEBUG
  9079. DR_cookie::DR_cookie(nsPresContext* aPresContext,
  9080. nsIFrame* aFrame,
  9081. const ReflowInput& aReflowInput,
  9082. ReflowOutput& aMetrics,
  9083. nsReflowStatus& aStatus)
  9084. :mPresContext(aPresContext), mFrame(aFrame), mReflowInput(aReflowInput), mMetrics(aMetrics), mStatus(aStatus)
  9085. {
  9086. MOZ_COUNT_CTOR(DR_cookie);
  9087. mValue = nsFrame::DisplayReflowEnter(aPresContext, mFrame, mReflowInput);
  9088. }
  9089. DR_cookie::~DR_cookie()
  9090. {
  9091. MOZ_COUNT_DTOR(DR_cookie);
  9092. nsFrame::DisplayReflowExit(mPresContext, mFrame, mMetrics, mStatus, mValue);
  9093. }
  9094. DR_layout_cookie::DR_layout_cookie(nsIFrame* aFrame)
  9095. : mFrame(aFrame)
  9096. {
  9097. MOZ_COUNT_CTOR(DR_layout_cookie);
  9098. mValue = nsFrame::DisplayLayoutEnter(mFrame);
  9099. }
  9100. DR_layout_cookie::~DR_layout_cookie()
  9101. {
  9102. MOZ_COUNT_DTOR(DR_layout_cookie);
  9103. nsFrame::DisplayLayoutExit(mFrame, mValue);
  9104. }
  9105. DR_intrinsic_width_cookie::DR_intrinsic_width_cookie(
  9106. nsIFrame* aFrame,
  9107. const char* aType,
  9108. nscoord& aResult)
  9109. : mFrame(aFrame)
  9110. , mType(aType)
  9111. , mResult(aResult)
  9112. {
  9113. MOZ_COUNT_CTOR(DR_intrinsic_width_cookie);
  9114. mValue = nsFrame::DisplayIntrinsicISizeEnter(mFrame, mType);
  9115. }
  9116. DR_intrinsic_width_cookie::~DR_intrinsic_width_cookie()
  9117. {
  9118. MOZ_COUNT_DTOR(DR_intrinsic_width_cookie);
  9119. nsFrame::DisplayIntrinsicISizeExit(mFrame, mType, mResult, mValue);
  9120. }
  9121. DR_intrinsic_size_cookie::DR_intrinsic_size_cookie(
  9122. nsIFrame* aFrame,
  9123. const char* aType,
  9124. nsSize& aResult)
  9125. : mFrame(aFrame)
  9126. , mType(aType)
  9127. , mResult(aResult)
  9128. {
  9129. MOZ_COUNT_CTOR(DR_intrinsic_size_cookie);
  9130. mValue = nsFrame::DisplayIntrinsicSizeEnter(mFrame, mType);
  9131. }
  9132. DR_intrinsic_size_cookie::~DR_intrinsic_size_cookie()
  9133. {
  9134. MOZ_COUNT_DTOR(DR_intrinsic_size_cookie);
  9135. nsFrame::DisplayIntrinsicSizeExit(mFrame, mType, mResult, mValue);
  9136. }
  9137. DR_init_constraints_cookie::DR_init_constraints_cookie(
  9138. nsIFrame* aFrame,
  9139. ReflowInput* aState,
  9140. nscoord aCBWidth,
  9141. nscoord aCBHeight,
  9142. const nsMargin* aMargin,
  9143. const nsMargin* aPadding)
  9144. : mFrame(aFrame)
  9145. , mState(aState)
  9146. {
  9147. MOZ_COUNT_CTOR(DR_init_constraints_cookie);
  9148. mValue = ReflowInput::DisplayInitConstraintsEnter(mFrame, mState,
  9149. aCBWidth, aCBHeight,
  9150. aMargin, aPadding);
  9151. }
  9152. DR_init_constraints_cookie::~DR_init_constraints_cookie()
  9153. {
  9154. MOZ_COUNT_DTOR(DR_init_constraints_cookie);
  9155. ReflowInput::DisplayInitConstraintsExit(mFrame, mState, mValue);
  9156. }
  9157. DR_init_offsets_cookie::DR_init_offsets_cookie(
  9158. nsIFrame* aFrame,
  9159. SizeComputationInput* aState,
  9160. nscoord aPercentBasis,
  9161. const nsMargin* aMargin,
  9162. const nsMargin* aPadding)
  9163. : mFrame(aFrame)
  9164. , mState(aState)
  9165. {
  9166. MOZ_COUNT_CTOR(DR_init_offsets_cookie);
  9167. mValue = SizeComputationInput::DisplayInitOffsetsEnter(mFrame, mState,
  9168. aPercentBasis,
  9169. aMargin, aPadding);
  9170. }
  9171. DR_init_offsets_cookie::~DR_init_offsets_cookie()
  9172. {
  9173. MOZ_COUNT_DTOR(DR_init_offsets_cookie);
  9174. SizeComputationInput::DisplayInitOffsetsExit(mFrame, mState, mValue);
  9175. }
  9176. DR_init_type_cookie::DR_init_type_cookie(
  9177. nsIFrame* aFrame,
  9178. ReflowInput* aState)
  9179. : mFrame(aFrame)
  9180. , mState(aState)
  9181. {
  9182. MOZ_COUNT_CTOR(DR_init_type_cookie);
  9183. mValue = ReflowInput::DisplayInitFrameTypeEnter(mFrame, mState);
  9184. }
  9185. DR_init_type_cookie::~DR_init_type_cookie()
  9186. {
  9187. MOZ_COUNT_DTOR(DR_init_type_cookie);
  9188. ReflowInput::DisplayInitFrameTypeExit(mFrame, mState, mValue);
  9189. }
  9190. struct DR_FrameTypeInfo;
  9191. struct DR_FrameTreeNode;
  9192. struct DR_Rule;
  9193. struct DR_State
  9194. {
  9195. DR_State();
  9196. ~DR_State();
  9197. void Init();
  9198. void AddFrameTypeInfo(nsIAtom* aFrameType,
  9199. const char* aFrameNameAbbrev,
  9200. const char* aFrameName);
  9201. DR_FrameTypeInfo* GetFrameTypeInfo(nsIAtom* aFrameType);
  9202. DR_FrameTypeInfo* GetFrameTypeInfo(char* aFrameName);
  9203. void InitFrameTypeTable();
  9204. DR_FrameTreeNode* CreateTreeNode(nsIFrame* aFrame,
  9205. const ReflowInput* aReflowInput);
  9206. void FindMatchingRule(DR_FrameTreeNode& aNode);
  9207. bool RuleMatches(DR_Rule& aRule,
  9208. DR_FrameTreeNode& aNode);
  9209. bool GetToken(FILE* aFile,
  9210. char* aBuf,
  9211. size_t aBufSize);
  9212. DR_Rule* ParseRule(FILE* aFile);
  9213. void ParseRulesFile();
  9214. void AddRule(nsTArray<DR_Rule*>& aRules,
  9215. DR_Rule& aRule);
  9216. bool IsWhiteSpace(int c);
  9217. bool GetNumber(char* aBuf,
  9218. int32_t& aNumber);
  9219. void PrettyUC(nscoord aSize,
  9220. char* aBuf,
  9221. int aBufSize);
  9222. void PrintMargin(const char* tag, const nsMargin* aMargin);
  9223. void DisplayFrameTypeInfo(nsIFrame* aFrame,
  9224. int32_t aIndent);
  9225. void DeleteTreeNode(DR_FrameTreeNode& aNode);
  9226. bool mInited;
  9227. bool mActive;
  9228. int32_t mCount;
  9229. int32_t mAssert;
  9230. int32_t mIndent;
  9231. bool mIndentUndisplayedFrames;
  9232. bool mDisplayPixelErrors;
  9233. nsTArray<DR_Rule*> mWildRules;
  9234. nsTArray<DR_FrameTypeInfo> mFrameTypeTable;
  9235. // reflow specific state
  9236. nsTArray<DR_FrameTreeNode*> mFrameTreeLeaves;
  9237. };
  9238. static DR_State *DR_state; // the one and only DR_State
  9239. struct DR_RulePart
  9240. {
  9241. explicit DR_RulePart(nsIAtom* aFrameType) : mFrameType(aFrameType), mNext(0) {}
  9242. void Destroy();
  9243. nsIAtom* mFrameType;
  9244. DR_RulePart* mNext;
  9245. };
  9246. void DR_RulePart::Destroy()
  9247. {
  9248. if (mNext) {
  9249. mNext->Destroy();
  9250. }
  9251. delete this;
  9252. }
  9253. struct DR_Rule
  9254. {
  9255. DR_Rule() : mLength(0), mTarget(nullptr), mDisplay(false) {
  9256. MOZ_COUNT_CTOR(DR_Rule);
  9257. }
  9258. ~DR_Rule() {
  9259. if (mTarget) mTarget->Destroy();
  9260. MOZ_COUNT_DTOR(DR_Rule);
  9261. }
  9262. void AddPart(nsIAtom* aFrameType);
  9263. uint32_t mLength;
  9264. DR_RulePart* mTarget;
  9265. bool mDisplay;
  9266. };
  9267. void DR_Rule::AddPart(nsIAtom* aFrameType)
  9268. {
  9269. DR_RulePart* newPart = new DR_RulePart(aFrameType);
  9270. newPart->mNext = mTarget;
  9271. mTarget = newPart;
  9272. mLength++;
  9273. }
  9274. struct DR_FrameTypeInfo
  9275. {
  9276. DR_FrameTypeInfo(nsIAtom* aFrmeType, const char* aFrameNameAbbrev, const char* aFrameName);
  9277. ~DR_FrameTypeInfo() {
  9278. int32_t numElements;
  9279. numElements = mRules.Length();
  9280. for (int32_t i = numElements - 1; i >= 0; i--) {
  9281. delete mRules.ElementAt(i);
  9282. }
  9283. }
  9284. nsIAtom* mType;
  9285. char mNameAbbrev[16];
  9286. char mName[32];
  9287. nsTArray<DR_Rule*> mRules;
  9288. private:
  9289. DR_FrameTypeInfo& operator=(const DR_FrameTypeInfo&) = delete;
  9290. };
  9291. DR_FrameTypeInfo::DR_FrameTypeInfo(nsIAtom* aFrameType,
  9292. const char* aFrameNameAbbrev,
  9293. const char* aFrameName)
  9294. {
  9295. mType = aFrameType;
  9296. PL_strncpyz(mNameAbbrev, aFrameNameAbbrev, sizeof(mNameAbbrev));
  9297. PL_strncpyz(mName, aFrameName, sizeof(mName));
  9298. }
  9299. struct DR_FrameTreeNode
  9300. {
  9301. DR_FrameTreeNode(nsIFrame* aFrame, DR_FrameTreeNode* aParent) : mFrame(aFrame), mParent(aParent), mDisplay(0), mIndent(0)
  9302. {
  9303. MOZ_COUNT_CTOR(DR_FrameTreeNode);
  9304. }
  9305. ~DR_FrameTreeNode()
  9306. {
  9307. MOZ_COUNT_DTOR(DR_FrameTreeNode);
  9308. }
  9309. nsIFrame* mFrame;
  9310. DR_FrameTreeNode* mParent;
  9311. bool mDisplay;
  9312. uint32_t mIndent;
  9313. };
  9314. // DR_State implementation
  9315. DR_State::DR_State()
  9316. : mInited(false), mActive(false), mCount(0), mAssert(-1), mIndent(0),
  9317. mIndentUndisplayedFrames(false), mDisplayPixelErrors(false)
  9318. {
  9319. MOZ_COUNT_CTOR(DR_State);
  9320. }
  9321. void DR_State::Init()
  9322. {
  9323. char* env = PR_GetEnv("GECKO_DISPLAY_REFLOW_ASSERT");
  9324. int32_t num;
  9325. if (env) {
  9326. if (GetNumber(env, num))
  9327. mAssert = num;
  9328. else
  9329. printf("GECKO_DISPLAY_REFLOW_ASSERT - invalid value = %s", env);
  9330. }
  9331. env = PR_GetEnv("GECKO_DISPLAY_REFLOW_INDENT_START");
  9332. if (env) {
  9333. if (GetNumber(env, num))
  9334. mIndent = num;
  9335. else
  9336. printf("GECKO_DISPLAY_REFLOW_INDENT_START - invalid value = %s", env);
  9337. }
  9338. env = PR_GetEnv("GECKO_DISPLAY_REFLOW_INDENT_UNDISPLAYED_FRAMES");
  9339. if (env) {
  9340. if (GetNumber(env, num))
  9341. mIndentUndisplayedFrames = num;
  9342. else
  9343. printf("GECKO_DISPLAY_REFLOW_INDENT_UNDISPLAYED_FRAMES - invalid value = %s", env);
  9344. }
  9345. env = PR_GetEnv("GECKO_DISPLAY_REFLOW_FLAG_PIXEL_ERRORS");
  9346. if (env) {
  9347. if (GetNumber(env, num))
  9348. mDisplayPixelErrors = num;
  9349. else
  9350. printf("GECKO_DISPLAY_REFLOW_FLAG_PIXEL_ERRORS - invalid value = %s", env);
  9351. }
  9352. InitFrameTypeTable();
  9353. ParseRulesFile();
  9354. mInited = true;
  9355. }
  9356. DR_State::~DR_State()
  9357. {
  9358. MOZ_COUNT_DTOR(DR_State);
  9359. int32_t numElements, i;
  9360. numElements = mWildRules.Length();
  9361. for (i = numElements - 1; i >= 0; i--) {
  9362. delete mWildRules.ElementAt(i);
  9363. }
  9364. numElements = mFrameTreeLeaves.Length();
  9365. for (i = numElements - 1; i >= 0; i--) {
  9366. delete mFrameTreeLeaves.ElementAt(i);
  9367. }
  9368. }
  9369. bool DR_State::GetNumber(char* aBuf,
  9370. int32_t& aNumber)
  9371. {
  9372. if (sscanf(aBuf, "%d", &aNumber) > 0)
  9373. return true;
  9374. else
  9375. return false;
  9376. }
  9377. bool DR_State::IsWhiteSpace(int c) {
  9378. return (c == ' ') || (c == '\t') || (c == '\n') || (c == '\r');
  9379. }
  9380. bool DR_State::GetToken(FILE* aFile,
  9381. char* aBuf,
  9382. size_t aBufSize)
  9383. {
  9384. bool haveToken = false;
  9385. aBuf[0] = 0;
  9386. // get the 1st non whitespace char
  9387. int c = -1;
  9388. for (c = getc(aFile); (c > 0) && IsWhiteSpace(c); c = getc(aFile)) {
  9389. }
  9390. if (c > 0) {
  9391. haveToken = true;
  9392. aBuf[0] = c;
  9393. // get everything up to the next whitespace char
  9394. size_t cX;
  9395. for (cX = 1; cX + 1 < aBufSize ; cX++) {
  9396. c = getc(aFile);
  9397. if (c < 0) { // EOF
  9398. ungetc(' ', aFile);
  9399. break;
  9400. }
  9401. else {
  9402. if (IsWhiteSpace(c)) {
  9403. break;
  9404. }
  9405. else {
  9406. aBuf[cX] = c;
  9407. }
  9408. }
  9409. }
  9410. aBuf[cX] = 0;
  9411. }
  9412. return haveToken;
  9413. }
  9414. DR_Rule* DR_State::ParseRule(FILE* aFile)
  9415. {
  9416. char buf[128];
  9417. int32_t doDisplay;
  9418. DR_Rule* rule = nullptr;
  9419. while (GetToken(aFile, buf, sizeof(buf))) {
  9420. if (GetNumber(buf, doDisplay)) {
  9421. if (rule) {
  9422. rule->mDisplay = !!doDisplay;
  9423. break;
  9424. }
  9425. else {
  9426. printf("unexpected token - %s \n", buf);
  9427. }
  9428. }
  9429. else {
  9430. if (!rule) {
  9431. rule = new DR_Rule;
  9432. }
  9433. if (strcmp(buf, "*") == 0) {
  9434. rule->AddPart(nullptr);
  9435. }
  9436. else {
  9437. DR_FrameTypeInfo* info = GetFrameTypeInfo(buf);
  9438. if (info) {
  9439. rule->AddPart(info->mType);
  9440. }
  9441. else {
  9442. printf("invalid frame type - %s \n", buf);
  9443. }
  9444. }
  9445. }
  9446. }
  9447. return rule;
  9448. }
  9449. void DR_State::AddRule(nsTArray<DR_Rule*>& aRules,
  9450. DR_Rule& aRule)
  9451. {
  9452. int32_t numRules = aRules.Length();
  9453. for (int32_t ruleX = 0; ruleX < numRules; ruleX++) {
  9454. DR_Rule* rule = aRules.ElementAt(ruleX);
  9455. NS_ASSERTION(rule, "program error");
  9456. if (aRule.mLength > rule->mLength) {
  9457. aRules.InsertElementAt(ruleX, &aRule);
  9458. return;
  9459. }
  9460. }
  9461. aRules.AppendElement(&aRule);
  9462. }
  9463. void DR_State::ParseRulesFile()
  9464. {
  9465. char* path = PR_GetEnv("GECKO_DISPLAY_REFLOW_RULES_FILE");
  9466. if (path) {
  9467. FILE* inFile = fopen(path, "r");
  9468. if (inFile) {
  9469. for (DR_Rule* rule = ParseRule(inFile); rule; rule = ParseRule(inFile)) {
  9470. if (rule->mTarget) {
  9471. nsIAtom* fType = rule->mTarget->mFrameType;
  9472. if (fType) {
  9473. DR_FrameTypeInfo* info = GetFrameTypeInfo(fType);
  9474. if (info) {
  9475. AddRule(info->mRules, *rule);
  9476. }
  9477. }
  9478. else {
  9479. AddRule(mWildRules, *rule);
  9480. }
  9481. mActive = true;
  9482. }
  9483. }
  9484. fclose(inFile);
  9485. }
  9486. }
  9487. }
  9488. void DR_State::AddFrameTypeInfo(nsIAtom* aFrameType,
  9489. const char* aFrameNameAbbrev,
  9490. const char* aFrameName)
  9491. {
  9492. mFrameTypeTable.AppendElement(DR_FrameTypeInfo(aFrameType, aFrameNameAbbrev, aFrameName));
  9493. }
  9494. DR_FrameTypeInfo* DR_State::GetFrameTypeInfo(nsIAtom* aFrameType)
  9495. {
  9496. int32_t numEntries = mFrameTypeTable.Length();
  9497. NS_ASSERTION(numEntries != 0, "empty FrameTypeTable");
  9498. for (int32_t i = 0; i < numEntries; i++) {
  9499. DR_FrameTypeInfo& info = mFrameTypeTable.ElementAt(i);
  9500. if (info.mType == aFrameType) {
  9501. return &info;
  9502. }
  9503. }
  9504. return &mFrameTypeTable.ElementAt(numEntries - 1); // return unknown frame type
  9505. }
  9506. DR_FrameTypeInfo* DR_State::GetFrameTypeInfo(char* aFrameName)
  9507. {
  9508. int32_t numEntries = mFrameTypeTable.Length();
  9509. NS_ASSERTION(numEntries != 0, "empty FrameTypeTable");
  9510. for (int32_t i = 0; i < numEntries; i++) {
  9511. DR_FrameTypeInfo& info = mFrameTypeTable.ElementAt(i);
  9512. if ((strcmp(aFrameName, info.mName) == 0) || (strcmp(aFrameName, info.mNameAbbrev) == 0)) {
  9513. return &info;
  9514. }
  9515. }
  9516. return &mFrameTypeTable.ElementAt(numEntries - 1); // return unknown frame type
  9517. }
  9518. void DR_State::InitFrameTypeTable()
  9519. {
  9520. AddFrameTypeInfo(nsGkAtoms::blockFrame, "block", "block");
  9521. AddFrameTypeInfo(nsGkAtoms::brFrame, "br", "br");
  9522. AddFrameTypeInfo(nsGkAtoms::bulletFrame, "bullet", "bullet");
  9523. AddFrameTypeInfo(nsGkAtoms::colorControlFrame, "color", "colorControl");
  9524. AddFrameTypeInfo(nsGkAtoms::gfxButtonControlFrame, "button", "gfxButtonControl");
  9525. AddFrameTypeInfo(nsGkAtoms::HTMLButtonControlFrame, "HTMLbutton", "HTMLButtonControl");
  9526. AddFrameTypeInfo(nsGkAtoms::HTMLCanvasFrame, "HTMLCanvas","HTMLCanvas");
  9527. AddFrameTypeInfo(nsGkAtoms::subDocumentFrame, "subdoc", "subDocument");
  9528. AddFrameTypeInfo(nsGkAtoms::imageFrame, "img", "image");
  9529. AddFrameTypeInfo(nsGkAtoms::inlineFrame, "inline", "inline");
  9530. AddFrameTypeInfo(nsGkAtoms::letterFrame, "letter", "letter");
  9531. AddFrameTypeInfo(nsGkAtoms::lineFrame, "line", "line");
  9532. AddFrameTypeInfo(nsGkAtoms::listControlFrame, "select", "select");
  9533. AddFrameTypeInfo(nsGkAtoms::objectFrame, "obj", "object");
  9534. AddFrameTypeInfo(nsGkAtoms::pageFrame, "page", "page");
  9535. AddFrameTypeInfo(nsGkAtoms::placeholderFrame, "place", "placeholder");
  9536. AddFrameTypeInfo(nsGkAtoms::canvasFrame, "canvas", "canvas");
  9537. AddFrameTypeInfo(nsGkAtoms::rootFrame, "root", "root");
  9538. AddFrameTypeInfo(nsGkAtoms::scrollFrame, "scroll", "scroll");
  9539. AddFrameTypeInfo(nsGkAtoms::tableCellFrame, "cell", "tableCell");
  9540. AddFrameTypeInfo(nsGkAtoms::bcTableCellFrame, "bcCell", "bcTableCell");
  9541. AddFrameTypeInfo(nsGkAtoms::tableColFrame, "col", "tableCol");
  9542. AddFrameTypeInfo(nsGkAtoms::tableColGroupFrame, "colG", "tableColGroup");
  9543. AddFrameTypeInfo(nsGkAtoms::tableFrame, "tbl", "table");
  9544. AddFrameTypeInfo(nsGkAtoms::tableWrapperFrame, "tblW", "tableWrapper");
  9545. AddFrameTypeInfo(nsGkAtoms::tableRowGroupFrame, "rowG", "tableRowGroup");
  9546. AddFrameTypeInfo(nsGkAtoms::tableRowFrame, "row", "tableRow");
  9547. AddFrameTypeInfo(nsGkAtoms::textInputFrame, "textCtl", "textInput");
  9548. AddFrameTypeInfo(nsGkAtoms::textFrame, "text", "text");
  9549. AddFrameTypeInfo(nsGkAtoms::viewportFrame, "VP", "viewport");
  9550. #ifdef MOZ_XUL
  9551. AddFrameTypeInfo(nsGkAtoms::XULLabelFrame, "XULLabel", "XULLabel");
  9552. AddFrameTypeInfo(nsGkAtoms::boxFrame, "Box", "Box");
  9553. AddFrameTypeInfo(nsGkAtoms::sliderFrame, "Slider", "Slider");
  9554. AddFrameTypeInfo(nsGkAtoms::popupSetFrame, "PopupSet", "PopupSet");
  9555. #endif
  9556. AddFrameTypeInfo(nullptr, "unknown", "unknown");
  9557. }
  9558. void DR_State::DisplayFrameTypeInfo(nsIFrame* aFrame,
  9559. int32_t aIndent)
  9560. {
  9561. DR_FrameTypeInfo* frameTypeInfo = GetFrameTypeInfo(aFrame->GetType());
  9562. if (frameTypeInfo) {
  9563. for (int32_t i = 0; i < aIndent; i++) {
  9564. printf(" ");
  9565. }
  9566. if(!strcmp(frameTypeInfo->mNameAbbrev, "unknown")) {
  9567. if (aFrame) {
  9568. nsAutoString name;
  9569. aFrame->GetFrameName(name);
  9570. printf("%s %p ", NS_LossyConvertUTF16toASCII(name).get(), (void*)aFrame);
  9571. }
  9572. else {
  9573. printf("%s %p ", frameTypeInfo->mNameAbbrev, (void*)aFrame);
  9574. }
  9575. }
  9576. else {
  9577. printf("%s %p ", frameTypeInfo->mNameAbbrev, (void*)aFrame);
  9578. }
  9579. }
  9580. }
  9581. bool DR_State::RuleMatches(DR_Rule& aRule,
  9582. DR_FrameTreeNode& aNode)
  9583. {
  9584. NS_ASSERTION(aRule.mTarget, "program error");
  9585. DR_RulePart* rulePart;
  9586. DR_FrameTreeNode* parentNode;
  9587. for (rulePart = aRule.mTarget->mNext, parentNode = aNode.mParent;
  9588. rulePart && parentNode;
  9589. rulePart = rulePart->mNext, parentNode = parentNode->mParent) {
  9590. if (rulePart->mFrameType) {
  9591. if (parentNode->mFrame) {
  9592. if (rulePart->mFrameType != parentNode->mFrame->GetType()) {
  9593. return false;
  9594. }
  9595. }
  9596. else NS_ASSERTION(false, "program error");
  9597. }
  9598. // else wild card match
  9599. }
  9600. return true;
  9601. }
  9602. void DR_State::FindMatchingRule(DR_FrameTreeNode& aNode)
  9603. {
  9604. if (!aNode.mFrame) {
  9605. NS_ASSERTION(false, "invalid DR_FrameTreeNode \n");
  9606. return;
  9607. }
  9608. bool matchingRule = false;
  9609. DR_FrameTypeInfo* info = GetFrameTypeInfo(aNode.mFrame->GetType());
  9610. NS_ASSERTION(info, "program error");
  9611. int32_t numRules = info->mRules.Length();
  9612. for (int32_t ruleX = 0; ruleX < numRules; ruleX++) {
  9613. DR_Rule* rule = info->mRules.ElementAt(ruleX);
  9614. if (rule && RuleMatches(*rule, aNode)) {
  9615. aNode.mDisplay = rule->mDisplay;
  9616. matchingRule = true;
  9617. break;
  9618. }
  9619. }
  9620. if (!matchingRule) {
  9621. int32_t numWildRules = mWildRules.Length();
  9622. for (int32_t ruleX = 0; ruleX < numWildRules; ruleX++) {
  9623. DR_Rule* rule = mWildRules.ElementAt(ruleX);
  9624. if (rule && RuleMatches(*rule, aNode)) {
  9625. aNode.mDisplay = rule->mDisplay;
  9626. break;
  9627. }
  9628. }
  9629. }
  9630. }
  9631. DR_FrameTreeNode* DR_State::CreateTreeNode(nsIFrame* aFrame,
  9632. const ReflowInput* aReflowInput)
  9633. {
  9634. // find the frame of the parent reflow state (usually just the parent of aFrame)
  9635. nsIFrame* parentFrame;
  9636. if (aReflowInput) {
  9637. const ReflowInput* parentRI = aReflowInput->mParentReflowInput;
  9638. parentFrame = (parentRI) ? parentRI->mFrame : nullptr;
  9639. } else {
  9640. parentFrame = aFrame->GetParent();
  9641. }
  9642. // find the parent tree node leaf
  9643. DR_FrameTreeNode* parentNode = nullptr;
  9644. DR_FrameTreeNode* lastLeaf = nullptr;
  9645. if(mFrameTreeLeaves.Length())
  9646. lastLeaf = mFrameTreeLeaves.ElementAt(mFrameTreeLeaves.Length() - 1);
  9647. if (lastLeaf) {
  9648. for (parentNode = lastLeaf; parentNode && (parentNode->mFrame != parentFrame); parentNode = parentNode->mParent) {
  9649. }
  9650. }
  9651. DR_FrameTreeNode* newNode = new DR_FrameTreeNode(aFrame, parentNode);
  9652. FindMatchingRule(*newNode);
  9653. newNode->mIndent = mIndent;
  9654. if (newNode->mDisplay || mIndentUndisplayedFrames) {
  9655. ++mIndent;
  9656. }
  9657. if (lastLeaf && (lastLeaf == parentNode)) {
  9658. mFrameTreeLeaves.RemoveElementAt(mFrameTreeLeaves.Length() - 1);
  9659. }
  9660. mFrameTreeLeaves.AppendElement(newNode);
  9661. mCount++;
  9662. return newNode;
  9663. }
  9664. void DR_State::PrettyUC(nscoord aSize,
  9665. char* aBuf,
  9666. int aBufSize)
  9667. {
  9668. if (NS_UNCONSTRAINEDSIZE == aSize) {
  9669. strcpy(aBuf, "UC");
  9670. }
  9671. else {
  9672. if ((nscoord)0xdeadbeefU == aSize)
  9673. {
  9674. strcpy(aBuf, "deadbeef");
  9675. }
  9676. else {
  9677. snprintf(aBuf, aBufSize, "%d", aSize);
  9678. }
  9679. }
  9680. }
  9681. void DR_State::PrintMargin(const char *tag, const nsMargin* aMargin)
  9682. {
  9683. if (aMargin) {
  9684. char t[16], r[16], b[16], l[16];
  9685. PrettyUC(aMargin->top, t, 16);
  9686. PrettyUC(aMargin->right, r, 16);
  9687. PrettyUC(aMargin->bottom, b, 16);
  9688. PrettyUC(aMargin->left, l, 16);
  9689. printf(" %s=%s,%s,%s,%s", tag, t, r, b, l);
  9690. } else {
  9691. // use %p here for consistency with other null-pointer printouts
  9692. printf(" %s=%p", tag, (void*)aMargin);
  9693. }
  9694. }
  9695. void DR_State::DeleteTreeNode(DR_FrameTreeNode& aNode)
  9696. {
  9697. mFrameTreeLeaves.RemoveElement(&aNode);
  9698. int32_t numLeaves = mFrameTreeLeaves.Length();
  9699. if ((0 == numLeaves) || (aNode.mParent != mFrameTreeLeaves.ElementAt(numLeaves - 1))) {
  9700. mFrameTreeLeaves.AppendElement(aNode.mParent);
  9701. }
  9702. if (aNode.mDisplay || mIndentUndisplayedFrames) {
  9703. --mIndent;
  9704. }
  9705. // delete the tree node
  9706. delete &aNode;
  9707. }
  9708. static void
  9709. CheckPixelError(nscoord aSize,
  9710. int32_t aPixelToTwips)
  9711. {
  9712. if (NS_UNCONSTRAINEDSIZE != aSize) {
  9713. if ((aSize % aPixelToTwips) > 0) {
  9714. printf("VALUE %d is not a whole pixel \n", aSize);
  9715. }
  9716. }
  9717. }
  9718. static void DisplayReflowEnterPrint(nsPresContext* aPresContext,
  9719. nsIFrame* aFrame,
  9720. const ReflowInput& aReflowInput,
  9721. DR_FrameTreeNode& aTreeNode,
  9722. bool aChanged)
  9723. {
  9724. if (aTreeNode.mDisplay) {
  9725. DR_state->DisplayFrameTypeInfo(aFrame, aTreeNode.mIndent);
  9726. char width[16];
  9727. char height[16];
  9728. DR_state->PrettyUC(aReflowInput.AvailableWidth(), width, 16);
  9729. DR_state->PrettyUC(aReflowInput.AvailableHeight(), height, 16);
  9730. printf("Reflow a=%s,%s ", width, height);
  9731. DR_state->PrettyUC(aReflowInput.ComputedWidth(), width, 16);
  9732. DR_state->PrettyUC(aReflowInput.ComputedHeight(), height, 16);
  9733. printf("c=%s,%s ", width, height);
  9734. if (aFrame->GetStateBits() & NS_FRAME_IS_DIRTY)
  9735. printf("dirty ");
  9736. if (aFrame->GetStateBits() & NS_FRAME_HAS_DIRTY_CHILDREN)
  9737. printf("dirty-children ");
  9738. if (aReflowInput.mFlags.mSpecialBSizeReflow)
  9739. printf("special-bsize ");
  9740. if (aReflowInput.IsHResize())
  9741. printf("h-resize ");
  9742. if (aReflowInput.IsVResize())
  9743. printf("v-resize ");
  9744. nsIFrame* inFlow = aFrame->GetPrevInFlow();
  9745. if (inFlow) {
  9746. printf("pif=%p ", (void*)inFlow);
  9747. }
  9748. inFlow = aFrame->GetNextInFlow();
  9749. if (inFlow) {
  9750. printf("nif=%p ", (void*)inFlow);
  9751. }
  9752. if (aChanged)
  9753. printf("CHANGED \n");
  9754. else
  9755. printf("cnt=%d \n", DR_state->mCount);
  9756. if (DR_state->mDisplayPixelErrors) {
  9757. int32_t p2t = aPresContext->AppUnitsPerDevPixel();
  9758. CheckPixelError(aReflowInput.AvailableWidth(), p2t);
  9759. CheckPixelError(aReflowInput.AvailableHeight(), p2t);
  9760. CheckPixelError(aReflowInput.ComputedWidth(), p2t);
  9761. CheckPixelError(aReflowInput.ComputedHeight(), p2t);
  9762. }
  9763. }
  9764. }
  9765. void* nsFrame::DisplayReflowEnter(nsPresContext* aPresContext,
  9766. nsIFrame* aFrame,
  9767. const ReflowInput& aReflowInput)
  9768. {
  9769. if (!DR_state->mInited) DR_state->Init();
  9770. if (!DR_state->mActive) return nullptr;
  9771. NS_ASSERTION(aFrame, "invalid call");
  9772. DR_FrameTreeNode* treeNode = DR_state->CreateTreeNode(aFrame, &aReflowInput);
  9773. if (treeNode) {
  9774. DisplayReflowEnterPrint(aPresContext, aFrame, aReflowInput, *treeNode, false);
  9775. }
  9776. return treeNode;
  9777. }
  9778. void* nsFrame::DisplayLayoutEnter(nsIFrame* aFrame)
  9779. {
  9780. if (!DR_state->mInited) DR_state->Init();
  9781. if (!DR_state->mActive) return nullptr;
  9782. NS_ASSERTION(aFrame, "invalid call");
  9783. DR_FrameTreeNode* treeNode = DR_state->CreateTreeNode(aFrame, nullptr);
  9784. if (treeNode && treeNode->mDisplay) {
  9785. DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
  9786. printf("XULLayout\n");
  9787. }
  9788. return treeNode;
  9789. }
  9790. void* nsFrame::DisplayIntrinsicISizeEnter(nsIFrame* aFrame,
  9791. const char* aType)
  9792. {
  9793. if (!DR_state->mInited) DR_state->Init();
  9794. if (!DR_state->mActive) return nullptr;
  9795. NS_ASSERTION(aFrame, "invalid call");
  9796. DR_FrameTreeNode* treeNode = DR_state->CreateTreeNode(aFrame, nullptr);
  9797. if (treeNode && treeNode->mDisplay) {
  9798. DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
  9799. printf("Get%sWidth\n", aType);
  9800. }
  9801. return treeNode;
  9802. }
  9803. void* nsFrame::DisplayIntrinsicSizeEnter(nsIFrame* aFrame,
  9804. const char* aType)
  9805. {
  9806. if (!DR_state->mInited) DR_state->Init();
  9807. if (!DR_state->mActive) return nullptr;
  9808. NS_ASSERTION(aFrame, "invalid call");
  9809. DR_FrameTreeNode* treeNode = DR_state->CreateTreeNode(aFrame, nullptr);
  9810. if (treeNode && treeNode->mDisplay) {
  9811. DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
  9812. printf("Get%sSize\n", aType);
  9813. }
  9814. return treeNode;
  9815. }
  9816. void nsFrame::DisplayReflowExit(nsPresContext* aPresContext,
  9817. nsIFrame* aFrame,
  9818. ReflowOutput& aMetrics,
  9819. nsReflowStatus aStatus,
  9820. void* aFrameTreeNode)
  9821. {
  9822. if (!DR_state->mActive) return;
  9823. NS_ASSERTION(aFrame, "DisplayReflowExit - invalid call");
  9824. if (!aFrameTreeNode) return;
  9825. DR_FrameTreeNode* treeNode = (DR_FrameTreeNode*)aFrameTreeNode;
  9826. if (treeNode->mDisplay) {
  9827. DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
  9828. char width[16];
  9829. char height[16];
  9830. char x[16];
  9831. char y[16];
  9832. DR_state->PrettyUC(aMetrics.Width(), width, 16);
  9833. DR_state->PrettyUC(aMetrics.Height(), height, 16);
  9834. printf("Reflow d=%s,%s", width, height);
  9835. if (!NS_FRAME_IS_FULLY_COMPLETE(aStatus)) {
  9836. printf(" status=0x%x", aStatus);
  9837. }
  9838. if (aFrame->HasOverflowAreas()) {
  9839. DR_state->PrettyUC(aMetrics.VisualOverflow().x, x, 16);
  9840. DR_state->PrettyUC(aMetrics.VisualOverflow().y, y, 16);
  9841. DR_state->PrettyUC(aMetrics.VisualOverflow().width, width, 16);
  9842. DR_state->PrettyUC(aMetrics.VisualOverflow().height, height, 16);
  9843. printf(" vis-o=(%s,%s) %s x %s", x, y, width, height);
  9844. nsRect storedOverflow = aFrame->GetVisualOverflowRect();
  9845. DR_state->PrettyUC(storedOverflow.x, x, 16);
  9846. DR_state->PrettyUC(storedOverflow.y, y, 16);
  9847. DR_state->PrettyUC(storedOverflow.width, width, 16);
  9848. DR_state->PrettyUC(storedOverflow.height, height, 16);
  9849. printf(" vis-sto=(%s,%s) %s x %s", x, y, width, height);
  9850. DR_state->PrettyUC(aMetrics.ScrollableOverflow().x, x, 16);
  9851. DR_state->PrettyUC(aMetrics.ScrollableOverflow().y, y, 16);
  9852. DR_state->PrettyUC(aMetrics.ScrollableOverflow().width, width, 16);
  9853. DR_state->PrettyUC(aMetrics.ScrollableOverflow().height, height, 16);
  9854. printf(" scr-o=(%s,%s) %s x %s", x, y, width, height);
  9855. storedOverflow = aFrame->GetScrollableOverflowRect();
  9856. DR_state->PrettyUC(storedOverflow.x, x, 16);
  9857. DR_state->PrettyUC(storedOverflow.y, y, 16);
  9858. DR_state->PrettyUC(storedOverflow.width, width, 16);
  9859. DR_state->PrettyUC(storedOverflow.height, height, 16);
  9860. printf(" scr-sto=(%s,%s) %s x %s", x, y, width, height);
  9861. }
  9862. printf("\n");
  9863. if (DR_state->mDisplayPixelErrors) {
  9864. int32_t p2t = aPresContext->AppUnitsPerDevPixel();
  9865. CheckPixelError(aMetrics.Width(), p2t);
  9866. CheckPixelError(aMetrics.Height(), p2t);
  9867. }
  9868. }
  9869. DR_state->DeleteTreeNode(*treeNode);
  9870. }
  9871. void nsFrame::DisplayLayoutExit(nsIFrame* aFrame,
  9872. void* aFrameTreeNode)
  9873. {
  9874. if (!DR_state->mActive) return;
  9875. NS_ASSERTION(aFrame, "non-null frame required");
  9876. if (!aFrameTreeNode) return;
  9877. DR_FrameTreeNode* treeNode = (DR_FrameTreeNode*)aFrameTreeNode;
  9878. if (treeNode->mDisplay) {
  9879. DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
  9880. nsRect rect = aFrame->GetRect();
  9881. printf("XULLayout=%d,%d,%d,%d\n", rect.x, rect.y, rect.width, rect.height);
  9882. }
  9883. DR_state->DeleteTreeNode(*treeNode);
  9884. }
  9885. void nsFrame::DisplayIntrinsicISizeExit(nsIFrame* aFrame,
  9886. const char* aType,
  9887. nscoord aResult,
  9888. void* aFrameTreeNode)
  9889. {
  9890. if (!DR_state->mActive) return;
  9891. NS_ASSERTION(aFrame, "non-null frame required");
  9892. if (!aFrameTreeNode) return;
  9893. DR_FrameTreeNode* treeNode = (DR_FrameTreeNode*)aFrameTreeNode;
  9894. if (treeNode->mDisplay) {
  9895. DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
  9896. char width[16];
  9897. DR_state->PrettyUC(aResult, width, 16);
  9898. printf("Get%sWidth=%s\n", aType, width);
  9899. }
  9900. DR_state->DeleteTreeNode(*treeNode);
  9901. }
  9902. void nsFrame::DisplayIntrinsicSizeExit(nsIFrame* aFrame,
  9903. const char* aType,
  9904. nsSize aResult,
  9905. void* aFrameTreeNode)
  9906. {
  9907. if (!DR_state->mActive) return;
  9908. NS_ASSERTION(aFrame, "non-null frame required");
  9909. if (!aFrameTreeNode) return;
  9910. DR_FrameTreeNode* treeNode = (DR_FrameTreeNode*)aFrameTreeNode;
  9911. if (treeNode->mDisplay) {
  9912. DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
  9913. char width[16];
  9914. char height[16];
  9915. DR_state->PrettyUC(aResult.width, width, 16);
  9916. DR_state->PrettyUC(aResult.height, height, 16);
  9917. printf("Get%sSize=%s,%s\n", aType, width, height);
  9918. }
  9919. DR_state->DeleteTreeNode(*treeNode);
  9920. }
  9921. /* static */ void
  9922. nsFrame::DisplayReflowStartup()
  9923. {
  9924. DR_state = new DR_State();
  9925. }
  9926. /* static */ void
  9927. nsFrame::DisplayReflowShutdown()
  9928. {
  9929. delete DR_state;
  9930. DR_state = nullptr;
  9931. }
  9932. void DR_cookie::Change() const
  9933. {
  9934. DR_FrameTreeNode* treeNode = (DR_FrameTreeNode*)mValue;
  9935. if (treeNode && treeNode->mDisplay) {
  9936. DisplayReflowEnterPrint(mPresContext, mFrame, mReflowInput, *treeNode, true);
  9937. }
  9938. }
  9939. /* static */ void*
  9940. ReflowInput::DisplayInitConstraintsEnter(nsIFrame* aFrame,
  9941. ReflowInput* aState,
  9942. nscoord aContainingBlockWidth,
  9943. nscoord aContainingBlockHeight,
  9944. const nsMargin* aBorder,
  9945. const nsMargin* aPadding)
  9946. {
  9947. NS_PRECONDITION(aFrame, "non-null frame required");
  9948. NS_PRECONDITION(aState, "non-null state required");
  9949. if (!DR_state->mInited) DR_state->Init();
  9950. if (!DR_state->mActive) return nullptr;
  9951. DR_FrameTreeNode* treeNode = DR_state->CreateTreeNode(aFrame, aState);
  9952. if (treeNode && treeNode->mDisplay) {
  9953. DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
  9954. printf("InitConstraints parent=%p",
  9955. (void*)aState->mParentReflowInput);
  9956. char width[16];
  9957. char height[16];
  9958. DR_state->PrettyUC(aContainingBlockWidth, width, 16);
  9959. DR_state->PrettyUC(aContainingBlockHeight, height, 16);
  9960. printf(" cb=%s,%s", width, height);
  9961. DR_state->PrettyUC(aState->AvailableWidth(), width, 16);
  9962. DR_state->PrettyUC(aState->AvailableHeight(), height, 16);
  9963. printf(" as=%s,%s", width, height);
  9964. DR_state->PrintMargin("b", aBorder);
  9965. DR_state->PrintMargin("p", aPadding);
  9966. putchar('\n');
  9967. }
  9968. return treeNode;
  9969. }
  9970. /* static */ void
  9971. ReflowInput::DisplayInitConstraintsExit(nsIFrame* aFrame,
  9972. ReflowInput* aState,
  9973. void* aValue)
  9974. {
  9975. NS_PRECONDITION(aFrame, "non-null frame required");
  9976. NS_PRECONDITION(aState, "non-null state required");
  9977. if (!DR_state->mActive) return;
  9978. if (!aValue) return;
  9979. DR_FrameTreeNode* treeNode = (DR_FrameTreeNode*)aValue;
  9980. if (treeNode->mDisplay) {
  9981. DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
  9982. char cmiw[16], cw[16], cmxw[16], cmih[16], ch[16], cmxh[16];
  9983. DR_state->PrettyUC(aState->ComputedMinWidth(), cmiw, 16);
  9984. DR_state->PrettyUC(aState->ComputedWidth(), cw, 16);
  9985. DR_state->PrettyUC(aState->ComputedMaxWidth(), cmxw, 16);
  9986. DR_state->PrettyUC(aState->ComputedMinHeight(), cmih, 16);
  9987. DR_state->PrettyUC(aState->ComputedHeight(), ch, 16);
  9988. DR_state->PrettyUC(aState->ComputedMaxHeight(), cmxh, 16);
  9989. printf("InitConstraints= cw=(%s <= %s <= %s) ch=(%s <= %s <= %s)",
  9990. cmiw, cw, cmxw, cmih, ch, cmxh);
  9991. DR_state->PrintMargin("co", &aState->ComputedPhysicalOffsets());
  9992. putchar('\n');
  9993. }
  9994. DR_state->DeleteTreeNode(*treeNode);
  9995. }
  9996. /* static */ void*
  9997. SizeComputationInput::DisplayInitOffsetsEnter(nsIFrame* aFrame,
  9998. SizeComputationInput* aState,
  9999. nscoord aPercentBasis,
  10000. const nsMargin* aBorder,
  10001. const nsMargin* aPadding)
  10002. {
  10003. NS_PRECONDITION(aFrame, "non-null frame required");
  10004. NS_PRECONDITION(aState, "non-null state required");
  10005. if (!DR_state->mInited) DR_state->Init();
  10006. if (!DR_state->mActive) return nullptr;
  10007. // aState is not necessarily a ReflowInput
  10008. DR_FrameTreeNode* treeNode = DR_state->CreateTreeNode(aFrame, nullptr);
  10009. if (treeNode && treeNode->mDisplay) {
  10010. DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
  10011. char pctBasisStr[16];
  10012. WritingMode wm = aState->GetWritingMode();
  10013. DR_state->PrettyUC(aPercentBasis, pctBasisStr, 16);
  10014. printf("InitOffsets pct_basis=%s", pctBasisStr);
  10015. DR_state->PrintMargin("b", aBorder);
  10016. DR_state->PrintMargin("p", aPadding);
  10017. putchar('\n');
  10018. }
  10019. return treeNode;
  10020. }
  10021. /* static */ void
  10022. SizeComputationInput::DisplayInitOffsetsExit(nsIFrame* aFrame,
  10023. SizeComputationInput* aState,
  10024. void* aValue)
  10025. {
  10026. NS_PRECONDITION(aFrame, "non-null frame required");
  10027. NS_PRECONDITION(aState, "non-null state required");
  10028. if (!DR_state->mActive) return;
  10029. if (!aValue) return;
  10030. DR_FrameTreeNode* treeNode = (DR_FrameTreeNode*)aValue;
  10031. if (treeNode->mDisplay) {
  10032. DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
  10033. printf("InitOffsets=");
  10034. DR_state->PrintMargin("m", &aState->ComputedPhysicalMargin());
  10035. DR_state->PrintMargin("p", &aState->ComputedPhysicalPadding());
  10036. DR_state->PrintMargin("p+b", &aState->ComputedPhysicalBorderPadding());
  10037. putchar('\n');
  10038. }
  10039. DR_state->DeleteTreeNode(*treeNode);
  10040. }
  10041. /* static */ void*
  10042. ReflowInput::DisplayInitFrameTypeEnter(nsIFrame* aFrame,
  10043. ReflowInput* aState)
  10044. {
  10045. NS_PRECONDITION(aFrame, "non-null frame required");
  10046. NS_PRECONDITION(aState, "non-null state required");
  10047. if (!DR_state->mInited) DR_state->Init();
  10048. if (!DR_state->mActive) return nullptr;
  10049. // we don't print anything here
  10050. return DR_state->CreateTreeNode(aFrame, aState);
  10051. }
  10052. /* static */ void
  10053. ReflowInput::DisplayInitFrameTypeExit(nsIFrame* aFrame,
  10054. ReflowInput* aState,
  10055. void* aValue)
  10056. {
  10057. NS_PRECONDITION(aFrame, "non-null frame required");
  10058. NS_PRECONDITION(aState, "non-null state required");
  10059. if (!DR_state->mActive) return;
  10060. if (!aValue) return;
  10061. DR_FrameTreeNode* treeNode = (DR_FrameTreeNode*)aValue;
  10062. if (treeNode->mDisplay) {
  10063. DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
  10064. printf("InitFrameType");
  10065. const nsStyleDisplay *disp = aState->mStyleDisplay;
  10066. if (aFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW)
  10067. printf(" out-of-flow");
  10068. if (aFrame->GetPrevInFlow())
  10069. printf(" prev-in-flow");
  10070. if (aFrame->IsAbsolutelyPositioned())
  10071. printf(" abspos");
  10072. if (aFrame->IsFloating())
  10073. printf(" float");
  10074. // This array must exactly match the StyleDisplay enum.
  10075. const char *const displayTypes[] = {
  10076. "none", "block", "inline", "inline-block", "list-item", "table",
  10077. "inline-table", "table-row-group", "table-column", "table-column",
  10078. "table-column-group", "table-header-group", "table-footer-group",
  10079. "table-row", "table-cell", "table-caption", "flex", "inline-flex",
  10080. "grid", "inline-grid", "ruby", "ruby-base", "ruby-base-container",
  10081. "ruby-text", "ruby-text-container", "contents", "-webkit-box",
  10082. "-webkit-inline-box", "box", "inline-box",
  10083. #ifdef MOZ_XUL
  10084. "grid", "inline-grid", "grid-group", "grid-line", "stack",
  10085. "inline-stack", "deck", "groupbox", "popup",
  10086. #endif
  10087. };
  10088. const uint32_t display = static_cast<uint32_t>(disp->mDisplay);
  10089. if (display >= ArrayLength(displayTypes))
  10090. printf(" display=%u", display);
  10091. else
  10092. printf(" display=%s", displayTypes[display]);
  10093. // This array must exactly match the NS_CSS_FRAME_TYPE constants.
  10094. const char *const cssFrameTypes[] = {
  10095. "unknown", "inline", "block", "floating", "absolute", "internal-table"
  10096. };
  10097. nsCSSFrameType bareType = NS_FRAME_GET_TYPE(aState->mFrameType);
  10098. bool repNoBlock = NS_FRAME_IS_REPLACED_NOBLOCK(aState->mFrameType);
  10099. bool repBlock = NS_FRAME_IS_REPLACED_CONTAINS_BLOCK(aState->mFrameType);
  10100. if (bareType >= ArrayLength(cssFrameTypes)) {
  10101. printf(" result=type %u", bareType);
  10102. } else {
  10103. printf(" result=%s", cssFrameTypes[bareType]);
  10104. }
  10105. printf("%s%s\n", repNoBlock ? " +rep" : "", repBlock ? " +repBlk" : "");
  10106. }
  10107. DR_state->DeleteTreeNode(*treeNode);
  10108. }
  10109. #endif
  10110. // End Display Reflow
  10111. #endif