nsSelection.cpp 207 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812
  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. /*
  6. * Implementation of selection: nsISelection,nsISelectionPrivate and nsFrameSelection
  7. */
  8. #include "mozilla/dom/Selection.h"
  9. #include "mozilla/Attributes.h"
  10. #include "mozilla/EventStates.h"
  11. #include "nsCOMPtr.h"
  12. #include "nsString.h"
  13. #include "nsFrameSelection.h"
  14. #include "nsISelectionListener.h"
  15. #include "nsContentCID.h"
  16. #include "nsDeviceContext.h"
  17. #include "nsIContent.h"
  18. #include "nsIDOMNode.h"
  19. #include "nsRange.h"
  20. #include "nsCOMArray.h"
  21. #include "nsITableCellLayout.h"
  22. #include "nsTArray.h"
  23. #include "nsTableWrapperFrame.h"
  24. #include "nsTableCellFrame.h"
  25. #include "nsIScrollableFrame.h"
  26. #include "nsCCUncollectableMarker.h"
  27. #include "nsIContentIterator.h"
  28. #include "nsIDocumentEncoder.h"
  29. #include "nsTextFragment.h"
  30. #include <algorithm>
  31. #include "nsContentUtils.h"
  32. #include "nsGkAtoms.h"
  33. #include "nsIFrameTraversal.h"
  34. #include "nsLayoutUtils.h"
  35. #include "nsLayoutCID.h"
  36. #include "nsBidiPresUtils.h"
  37. static NS_DEFINE_CID(kFrameTraversalCID, NS_FRAMETRAVERSAL_CID);
  38. #include "nsTextFrame.h"
  39. #include "nsIDOMText.h"
  40. #include "nsContentUtils.h"
  41. #include "nsThreadUtils.h"
  42. #include "mozilla/Preferences.h"
  43. #include "nsDOMClassInfoID.h"
  44. #include "nsPresContext.h"
  45. #include "nsIPresShell.h"
  46. #include "nsCaret.h"
  47. #include "AccessibleCaretEventHub.h"
  48. #include "mozilla/MouseEvents.h"
  49. #include "mozilla/TextEvents.h"
  50. #include "nsITimer.h"
  51. #include "nsFrameManager.h"
  52. // notifications
  53. #include "nsIDOMDocument.h"
  54. #include "nsIDocument.h"
  55. #include "nsISelectionController.h"//for the enums
  56. #include "nsAutoCopyListener.h"
  57. #include "SelectionChangeListener.h"
  58. #include "nsCopySupport.h"
  59. #include "nsIClipboard.h"
  60. #include "nsIFrameInlines.h"
  61. #include "nsIBidiKeyboard.h"
  62. #include "nsError.h"
  63. #include "mozilla/dom/Element.h"
  64. #include "mozilla/dom/ShadowRoot.h"
  65. #include "mozilla/ErrorResult.h"
  66. #include "mozilla/dom/SelectionBinding.h"
  67. #include "mozilla/AsyncEventDispatcher.h"
  68. #include "mozilla/Telemetry.h"
  69. #include "mozilla/layers/ScrollInputMethods.h"
  70. #include "nsViewManager.h"
  71. #include "nsIEditor.h"
  72. #include "nsIHTMLEditor.h"
  73. #include "nsFocusManager.h"
  74. using namespace mozilla;
  75. using namespace mozilla::dom;
  76. using mozilla::layers::ScrollInputMethod;
  77. //#define DEBUG_TABLE 1
  78. static bool IsValidSelectionPoint(nsFrameSelection *aFrameSel, nsINode *aNode);
  79. static nsIAtom *GetTag(nsINode *aNode);
  80. // returns the parent
  81. static nsINode* ParentOffset(nsINode *aNode, int32_t *aChildOffset);
  82. static nsINode* GetCellParent(nsINode *aDomNode);
  83. #ifdef PRINT_RANGE
  84. static void printRange(nsRange *aDomRange);
  85. #define DEBUG_OUT_RANGE(x) printRange(x)
  86. #else
  87. #define DEBUG_OUT_RANGE(x)
  88. #endif // PRINT_RANGE
  89. /******************************************************************************
  90. * Utility methods defined in nsISelectionController.idl
  91. ******************************************************************************/
  92. namespace mozilla {
  93. const char*
  94. ToChar(SelectionType aSelectionType)
  95. {
  96. switch (aSelectionType) {
  97. case SelectionType::eInvalid:
  98. return "SelectionType::eInvalid";
  99. case SelectionType::eNone:
  100. return "SelectionType::eNone";
  101. case SelectionType::eNormal:
  102. return "SelectionType::eNormal";
  103. case SelectionType::eSpellCheck:
  104. return "SelectionType::eSpellCheck";
  105. case SelectionType::eIMERawClause:
  106. return "SelectionType::eIMERawClause";
  107. case SelectionType::eIMESelectedRawClause:
  108. return "SelectionType::eIMESelectedRawClause";
  109. case SelectionType::eIMEConvertedClause:
  110. return "SelectionType::eIMEConvertedClause";
  111. case SelectionType::eIMESelectedClause:
  112. return "SelectionType::eIMESelectedClause";
  113. case SelectionType::eAccessibility:
  114. return "SelectionType::eAccessibility";
  115. case SelectionType::eFind:
  116. return "SelectionType::eFind";
  117. case SelectionType::eURLSecondary:
  118. return "SelectionType::eURLSecondary";
  119. case SelectionType::eURLStrikeout:
  120. return "SelectionType::eURLStrikeout";
  121. default:
  122. return "Invalid SelectionType";
  123. }
  124. }
  125. static bool
  126. IsValidSelectionType(RawSelectionType aRawSelectionType)
  127. {
  128. switch (static_cast<SelectionType>(aRawSelectionType)) {
  129. case SelectionType::eNone:
  130. case SelectionType::eNormal:
  131. case SelectionType::eSpellCheck:
  132. case SelectionType::eIMERawClause:
  133. case SelectionType::eIMESelectedRawClause:
  134. case SelectionType::eIMEConvertedClause:
  135. case SelectionType::eIMESelectedClause:
  136. case SelectionType::eAccessibility:
  137. case SelectionType::eFind:
  138. case SelectionType::eURLSecondary:
  139. case SelectionType::eURLStrikeout:
  140. return true;
  141. default:
  142. return false;
  143. }
  144. }
  145. SelectionType
  146. ToSelectionType(RawSelectionType aRawSelectionType)
  147. {
  148. if (!IsValidSelectionType(aRawSelectionType)) {
  149. return SelectionType::eInvalid;
  150. }
  151. return static_cast<SelectionType>(aRawSelectionType);
  152. }
  153. RawSelectionType
  154. ToRawSelectionType(SelectionType aSelectionType)
  155. {
  156. return static_cast<RawSelectionType>(aSelectionType);
  157. }
  158. bool operator &(SelectionType aSelectionType,
  159. RawSelectionType aRawSelectionTypes)
  160. {
  161. return (ToRawSelectionType(aSelectionType) & aRawSelectionTypes) != 0;
  162. }
  163. } // namespace mozilla
  164. /******************************************************************************
  165. * nsPeekOffsetStruct
  166. ******************************************************************************/
  167. //#define DEBUG_SELECTION // uncomment for printf describing every collapse and extend.
  168. //#define DEBUG_NAVIGATION
  169. //#define DEBUG_TABLE_SELECTION 1
  170. nsPeekOffsetStruct::nsPeekOffsetStruct(nsSelectionAmount aAmount,
  171. nsDirection aDirection,
  172. int32_t aStartOffset,
  173. nsPoint aDesiredPos,
  174. bool aJumpLines,
  175. bool aScrollViewStop,
  176. bool aIsKeyboardSelect,
  177. bool aVisual,
  178. bool aExtend,
  179. EWordMovementType aWordMovementType)
  180. : mAmount(aAmount)
  181. , mDirection(aDirection)
  182. , mStartOffset(aStartOffset)
  183. , mDesiredPos(aDesiredPos)
  184. , mWordMovementType(aWordMovementType)
  185. , mJumpLines(aJumpLines)
  186. , mScrollViewStop(aScrollViewStop)
  187. , mIsKeyboardSelect(aIsKeyboardSelect)
  188. , mVisual(aVisual)
  189. , mExtend(aExtend)
  190. , mResultContent()
  191. , mResultFrame(nullptr)
  192. , mContentOffset(0)
  193. , mAttach(CARET_ASSOCIATE_BEFORE)
  194. {
  195. }
  196. struct CachedOffsetForFrame {
  197. CachedOffsetForFrame()
  198. : mCachedFrameOffset(0, 0) // nsPoint ctor
  199. , mLastCaretFrame(nullptr)
  200. , mLastContentOffset(0)
  201. , mCanCacheFrameOffset(false)
  202. {}
  203. nsPoint mCachedFrameOffset; // cached frame offset
  204. nsIFrame* mLastCaretFrame; // store the frame the caret was last drawn in.
  205. int32_t mLastContentOffset; // store last content offset
  206. bool mCanCacheFrameOffset; // cached frame offset is valid?
  207. };
  208. class nsAutoScrollTimer final : public nsITimerCallback
  209. {
  210. public:
  211. NS_DECL_ISUPPORTS
  212. nsAutoScrollTimer()
  213. : mFrameSelection(0), mSelection(0), mPresContext(0), mPoint(0,0), mDelay(30)
  214. {
  215. }
  216. // aPoint is relative to aPresContext's root frame
  217. nsresult Start(nsPresContext *aPresContext, nsPoint &aPoint)
  218. {
  219. mPoint = aPoint;
  220. // Store the presentation context. The timer will be
  221. // stopped by the selection if the prescontext is destroyed.
  222. mPresContext = aPresContext;
  223. mContent = nsIPresShell::GetCapturingContent();
  224. if (!mTimer)
  225. {
  226. nsresult result;
  227. mTimer = do_CreateInstance("@mozilla.org/timer;1", &result);
  228. if (NS_FAILED(result))
  229. return result;
  230. }
  231. return mTimer->InitWithCallback(this, mDelay, nsITimer::TYPE_ONE_SHOT);
  232. }
  233. nsresult Stop()
  234. {
  235. if (mTimer)
  236. {
  237. mTimer->Cancel();
  238. mTimer = nullptr;
  239. }
  240. mContent = nullptr;
  241. return NS_OK;
  242. }
  243. nsresult Init(nsFrameSelection* aFrameSelection, Selection* aSelection)
  244. {
  245. mFrameSelection = aFrameSelection;
  246. mSelection = aSelection;
  247. return NS_OK;
  248. }
  249. nsresult SetDelay(uint32_t aDelay)
  250. {
  251. mDelay = aDelay;
  252. return NS_OK;
  253. }
  254. NS_IMETHOD Notify(nsITimer *timer) override
  255. {
  256. if (mSelection && mPresContext)
  257. {
  258. nsWeakFrame frame =
  259. mContent ? mPresContext->GetPrimaryFrameFor(mContent) : nullptr;
  260. if (!frame)
  261. return NS_OK;
  262. mContent = nullptr;
  263. nsPoint pt = mPoint -
  264. frame->GetOffsetTo(mPresContext->PresShell()->FrameManager()->GetRootFrame());
  265. RefPtr<nsFrameSelection> frameSelection = mFrameSelection;
  266. frameSelection->HandleDrag(frame, pt);
  267. if (!frame.IsAlive())
  268. return NS_OK;
  269. NS_ASSERTION(frame->PresContext() == mPresContext, "document mismatch?");
  270. mSelection->DoAutoScroll(frame, pt);
  271. }
  272. return NS_OK;
  273. }
  274. protected:
  275. virtual ~nsAutoScrollTimer()
  276. {
  277. if (mTimer) {
  278. mTimer->Cancel();
  279. }
  280. }
  281. private:
  282. nsFrameSelection *mFrameSelection;
  283. Selection* mSelection;
  284. nsPresContext *mPresContext;
  285. // relative to mPresContext's root frame
  286. nsPoint mPoint;
  287. nsCOMPtr<nsITimer> mTimer;
  288. nsCOMPtr<nsIContent> mContent;
  289. uint32_t mDelay;
  290. };
  291. NS_IMPL_ISUPPORTS(nsAutoScrollTimer, nsITimerCallback)
  292. nsresult NS_NewDomSelection(nsISelection **aDomSelection)
  293. {
  294. Selection* rlist = new Selection;
  295. *aDomSelection = (nsISelection *)rlist;
  296. NS_ADDREF(rlist);
  297. return NS_OK;
  298. }
  299. static int8_t
  300. GetIndexFromSelectionType(SelectionType aSelectionType)
  301. {
  302. switch (aSelectionType) {
  303. case SelectionType::eNormal:
  304. return 0;
  305. case SelectionType::eSpellCheck:
  306. return 1;
  307. case SelectionType::eIMERawClause:
  308. return 2;
  309. case SelectionType::eIMESelectedRawClause:
  310. return 3;
  311. case SelectionType::eIMEConvertedClause:
  312. return 4;
  313. case SelectionType::eIMESelectedClause:
  314. return 5;
  315. case SelectionType::eAccessibility:
  316. return 6;
  317. case SelectionType::eFind:
  318. return 7;
  319. case SelectionType::eURLSecondary:
  320. return 8;
  321. case SelectionType::eURLStrikeout:
  322. return 9;
  323. default:
  324. return -1;
  325. }
  326. /* NOTREACHED */
  327. }
  328. static SelectionType
  329. GetSelectionTypeFromIndex(int8_t aIndex)
  330. {
  331. static const SelectionType kSelectionTypes[] = {
  332. SelectionType::eNormal,
  333. SelectionType::eSpellCheck,
  334. SelectionType::eIMERawClause,
  335. SelectionType::eIMESelectedRawClause,
  336. SelectionType::eIMEConvertedClause,
  337. SelectionType::eIMESelectedClause,
  338. SelectionType::eAccessibility,
  339. SelectionType::eFind,
  340. SelectionType::eURLSecondary,
  341. SelectionType::eURLStrikeout
  342. };
  343. if (NS_WARN_IF(aIndex < 0) ||
  344. NS_WARN_IF(static_cast<size_t>(aIndex) >= ArrayLength(kSelectionTypes))) {
  345. return SelectionType::eNormal;
  346. }
  347. return kSelectionTypes[aIndex];
  348. }
  349. /*
  350. The limiter is used specifically for the text areas and textfields
  351. In that case it is the DIV tag that is anonymously created for the text
  352. areas/fields. Text nodes and BR nodes fall beneath it. In the case of a
  353. BR node the limiter will be the parent and the offset will point before or
  354. after the BR node. In the case of the text node the parent content is
  355. the text node itself and the offset will be the exact character position.
  356. The offset is not important to check for validity. Simply look at the
  357. passed in content. If it equals the limiter then the selection point is valid.
  358. If its parent it the limiter then the point is also valid. In the case of
  359. NO limiter all points are valid since you are in a topmost iframe. (browser
  360. or composer)
  361. */
  362. bool
  363. IsValidSelectionPoint(nsFrameSelection *aFrameSel, nsINode *aNode)
  364. {
  365. if (!aFrameSel || !aNode)
  366. return false;
  367. nsIContent *limiter = aFrameSel->GetLimiter();
  368. if (limiter && limiter != aNode && limiter != aNode->GetParent()) {
  369. //if newfocus == the limiter. that's ok. but if not there and not parent bad
  370. return false; //not in the right content. tLimiter said so
  371. }
  372. limiter = aFrameSel->GetAncestorLimiter();
  373. return !limiter || nsContentUtils::ContentIsDescendantOf(aNode, limiter);
  374. }
  375. namespace mozilla {
  376. struct MOZ_RAII AutoPrepareFocusRange
  377. {
  378. AutoPrepareFocusRange(Selection* aSelection,
  379. bool aContinueSelection,
  380. bool aMultipleSelection
  381. MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
  382. {
  383. MOZ_GUARD_OBJECT_NOTIFIER_INIT;
  384. if (aSelection->mRanges.Length() <= 1) {
  385. return;
  386. }
  387. if (aSelection->mFrameSelection->IsUserSelectionReason()) {
  388. mUserSelect.emplace(aSelection);
  389. }
  390. bool userSelection = aSelection->mUserInitiated;
  391. nsTArray<RangeData>& ranges = aSelection->mRanges;
  392. if (!userSelection ||
  393. (!aContinueSelection && aMultipleSelection)) {
  394. // Scripted command or the user is starting a new explicit multi-range
  395. // selection.
  396. for (RangeData& entry : ranges) {
  397. entry.mRange->SetIsGenerated(false);
  398. }
  399. return;
  400. }
  401. int16_t reason = aSelection->mFrameSelection->mSelectionChangeReason;
  402. bool isAnchorRelativeOp = (reason & (nsISelectionListener::DRAG_REASON |
  403. nsISelectionListener::MOUSEDOWN_REASON |
  404. nsISelectionListener::MOUSEUP_REASON |
  405. nsISelectionListener::COLLAPSETOSTART_REASON));
  406. if (!isAnchorRelativeOp) {
  407. return;
  408. }
  409. // This operation is against the anchor but our current mAnchorFocusRange
  410. // represents the focus in a multi-range selection. The anchor from a user
  411. // perspective is the most distant generated range on the opposite side.
  412. // Find that range and make it the mAnchorFocusRange.
  413. const size_t len = ranges.Length();
  414. size_t newAnchorFocusIndex = size_t(-1);
  415. if (aSelection->GetDirection() == eDirNext) {
  416. for (size_t i = 0; i < len; ++i) {
  417. if (ranges[i].mRange->IsGenerated()) {
  418. newAnchorFocusIndex = i;
  419. break;
  420. }
  421. }
  422. } else {
  423. size_t i = len;
  424. while (i--) {
  425. if (ranges[i].mRange->IsGenerated()) {
  426. newAnchorFocusIndex = i;
  427. break;
  428. }
  429. }
  430. }
  431. if (newAnchorFocusIndex == size_t(-1)) {
  432. // There are no generated ranges - that's fine.
  433. return;
  434. }
  435. // Setup the new mAnchorFocusRange and mark the old one as generated.
  436. if (aSelection->mAnchorFocusRange) {
  437. aSelection->mAnchorFocusRange->SetIsGenerated(true);
  438. }
  439. nsRange* range = ranges[newAnchorFocusIndex].mRange;
  440. range->SetIsGenerated(false);
  441. aSelection->mAnchorFocusRange = range;
  442. // Remove all generated ranges (including the old mAnchorFocusRange).
  443. RefPtr<nsPresContext> presContext = aSelection->GetPresContext();
  444. size_t i = len;
  445. while (i--) {
  446. range = aSelection->mRanges[i].mRange;
  447. if (range->IsGenerated()) {
  448. range->SetSelection(nullptr);
  449. aSelection->selectFrames(presContext, range, false);
  450. aSelection->mRanges.RemoveElementAt(i);
  451. }
  452. }
  453. if (aSelection->mFrameSelection) {
  454. aSelection->mFrameSelection->InvalidateDesiredPos();
  455. }
  456. }
  457. Maybe<Selection::AutoUserInitiated> mUserSelect;
  458. MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
  459. };
  460. } // namespace mozilla
  461. ////////////BEGIN nsFrameSelection methods
  462. nsFrameSelection::nsFrameSelection()
  463. {
  464. for (size_t i = 0; i < kPresentSelectionTypeCount; i++){
  465. mDomSelections[i] = new Selection(this);
  466. mDomSelections[i]->SetType(GetSelectionTypeFromIndex(i));
  467. }
  468. mBatching = 0;
  469. mChangesDuringBatching = false;
  470. mNotifyFrames = true;
  471. mMouseDoubleDownState = false;
  472. mHint = CARET_ASSOCIATE_BEFORE;
  473. mCaretBidiLevel = BIDI_LEVEL_UNDEFINED;
  474. mKbdBidiLevel = NSBIDI_LTR;
  475. mDragSelectingCells = false;
  476. mSelectingTableCellMode = 0;
  477. mSelectedCellIndex = 0;
  478. nsAutoCopyListener *autoCopy = nullptr;
  479. // Check to see if the autocopy pref is enabled
  480. // and add the autocopy listener if it is
  481. if (Preferences::GetBool("clipboard.autocopy")) {
  482. autoCopy = nsAutoCopyListener::GetInstance(nsIClipboard::kSelectionClipboard);
  483. }
  484. if (autoCopy) {
  485. int8_t index = GetIndexFromSelectionType(SelectionType::eNormal);
  486. if (mDomSelections[index]) {
  487. autoCopy->Listen(mDomSelections[index]);
  488. }
  489. }
  490. mDisplaySelection = nsISelectionController::SELECTION_OFF;
  491. mSelectionChangeReason = nsISelectionListener::NO_REASON;
  492. mDelayedMouseEventValid = false;
  493. // These values are not used since they are only valid when
  494. // mDelayedMouseEventValid is true, and setting mDelayedMouseEventValid
  495. //alwaysoverrides these values.
  496. mDelayedMouseEventIsShift = false;
  497. mDelayedMouseEventClickCount = 0;
  498. }
  499. nsFrameSelection::~nsFrameSelection()
  500. {
  501. }
  502. NS_IMPL_CYCLE_COLLECTION_CLASS(nsFrameSelection)
  503. NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsFrameSelection)
  504. for (size_t i = 0; i < kPresentSelectionTypeCount; ++i) {
  505. tmp->mDomSelections[i] = nullptr;
  506. }
  507. NS_IMPL_CYCLE_COLLECTION_UNLINK(mCellParent)
  508. tmp->mSelectingTableCellMode = 0;
  509. tmp->mDragSelectingCells = false;
  510. NS_IMPL_CYCLE_COLLECTION_UNLINK(mStartSelectedCell)
  511. NS_IMPL_CYCLE_COLLECTION_UNLINK(mEndSelectedCell)
  512. NS_IMPL_CYCLE_COLLECTION_UNLINK(mAppendStartSelectedCell)
  513. NS_IMPL_CYCLE_COLLECTION_UNLINK(mUnselectCellOnMouseUp)
  514. NS_IMPL_CYCLE_COLLECTION_UNLINK(mMaintainRange)
  515. NS_IMPL_CYCLE_COLLECTION_UNLINK(mLimiter)
  516. NS_IMPL_CYCLE_COLLECTION_UNLINK(mAncestorLimiter)
  517. NS_IMPL_CYCLE_COLLECTION_UNLINK_END
  518. NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsFrameSelection)
  519. if (tmp->mShell && tmp->mShell->GetDocument() &&
  520. nsCCUncollectableMarker::InGeneration(cb,
  521. tmp->mShell->GetDocument()->
  522. GetMarkedCCGeneration())) {
  523. return NS_SUCCESS_INTERRUPTED_TRAVERSE;
  524. }
  525. for (size_t i = 0; i < kPresentSelectionTypeCount; ++i) {
  526. NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDomSelections[i])
  527. }
  528. NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCellParent)
  529. NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStartSelectedCell)
  530. NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEndSelectedCell)
  531. NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAppendStartSelectedCell)
  532. NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mUnselectCellOnMouseUp)
  533. NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMaintainRange)
  534. NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLimiter)
  535. NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAncestorLimiter)
  536. NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
  537. NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(nsFrameSelection, AddRef)
  538. NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(nsFrameSelection, Release)
  539. // Get the x (or y, in vertical writing mode) position requested
  540. // by the Key Handling for line-up/down
  541. nsresult
  542. nsFrameSelection::FetchDesiredPos(nsPoint &aDesiredPos)
  543. {
  544. if (!mShell) {
  545. NS_ERROR("fetch desired position failed");
  546. return NS_ERROR_FAILURE;
  547. }
  548. if (mDesiredPosSet) {
  549. aDesiredPos = mDesiredPos;
  550. return NS_OK;
  551. }
  552. RefPtr<nsCaret> caret = mShell->GetCaret();
  553. if (!caret) {
  554. return NS_ERROR_NULL_POINTER;
  555. }
  556. int8_t index = GetIndexFromSelectionType(SelectionType::eNormal);
  557. caret->SetSelection(mDomSelections[index]);
  558. nsRect coord;
  559. nsIFrame* caretFrame = caret->GetGeometry(&coord);
  560. if (!caretFrame) {
  561. return NS_ERROR_FAILURE;
  562. }
  563. nsPoint viewOffset(0, 0);
  564. nsView* view = nullptr;
  565. caretFrame->GetOffsetFromView(viewOffset, &view);
  566. if (view) {
  567. coord += viewOffset;
  568. }
  569. aDesiredPos = coord.TopLeft();
  570. return NS_OK;
  571. }
  572. void
  573. nsFrameSelection::InvalidateDesiredPos() // do not listen to mDesiredPos;
  574. // you must get another.
  575. {
  576. mDesiredPosSet = false;
  577. }
  578. void
  579. nsFrameSelection::SetDesiredPos(nsPoint aPos)
  580. {
  581. mDesiredPos = aPos;
  582. mDesiredPosSet = true;
  583. }
  584. nsresult
  585. nsFrameSelection::ConstrainFrameAndPointToAnchorSubtree(nsIFrame *aFrame,
  586. nsPoint& aPoint,
  587. nsIFrame **aRetFrame,
  588. nsPoint& aRetPoint)
  589. {
  590. //
  591. // The whole point of this method is to return a frame and point that
  592. // that lie within the same valid subtree as the anchor node's frame,
  593. // for use with the method GetContentAndOffsetsFromPoint().
  594. //
  595. // A valid subtree is defined to be one where all the content nodes in
  596. // the tree have a valid parent-child relationship.
  597. //
  598. // If the anchor frame and aFrame are in the same subtree, aFrame will
  599. // be returned in aRetFrame. If they are in different subtrees, we
  600. // return the frame for the root of the subtree.
  601. //
  602. if (!aFrame || !aRetFrame)
  603. return NS_ERROR_NULL_POINTER;
  604. *aRetFrame = aFrame;
  605. aRetPoint = aPoint;
  606. //
  607. // Get the frame and content for the selection's anchor point!
  608. //
  609. nsresult result;
  610. nsCOMPtr<nsIDOMNode> anchorNode;
  611. int32_t anchorOffset = 0;
  612. int8_t index = GetIndexFromSelectionType(SelectionType::eNormal);
  613. if (!mDomSelections[index])
  614. return NS_ERROR_NULL_POINTER;
  615. result = mDomSelections[index]->GetAnchorNode(getter_AddRefs(anchorNode));
  616. if (NS_FAILED(result))
  617. return result;
  618. if (!anchorNode)
  619. return NS_OK;
  620. result = mDomSelections[index]->GetAnchorOffset(&anchorOffset);
  621. if (NS_FAILED(result))
  622. return result;
  623. nsCOMPtr<nsIContent> anchorContent = do_QueryInterface(anchorNode);
  624. if (!anchorContent)
  625. return NS_ERROR_FAILURE;
  626. //
  627. // Now find the root of the subtree containing the anchor's content.
  628. //
  629. NS_ENSURE_STATE(mShell);
  630. nsIContent* anchorRoot = anchorContent->GetSelectionRootContent(mShell);
  631. NS_ENSURE_TRUE(anchorRoot, NS_ERROR_UNEXPECTED);
  632. //
  633. // Now find the root of the subtree containing aFrame's content.
  634. //
  635. nsIContent* content = aFrame->GetContent();
  636. if (content)
  637. {
  638. nsIContent* contentRoot = content->GetSelectionRootContent(mShell);
  639. NS_ENSURE_TRUE(contentRoot, NS_ERROR_UNEXPECTED);
  640. if (anchorRoot == contentRoot)
  641. {
  642. // If the aFrame's content isn't the capturing content, it should be
  643. // a descendant. At this time, we can return simply.
  644. nsIContent* capturedContent = nsIPresShell::GetCapturingContent();
  645. if (capturedContent != content)
  646. {
  647. return NS_OK;
  648. }
  649. // Find the frame under the mouse cursor with the root frame.
  650. // At this time, don't use the anchor's frame because it may not have
  651. // fixed positioned frames.
  652. nsIFrame* rootFrame = mShell->FrameManager()->GetRootFrame();
  653. nsPoint ptInRoot = aPoint + aFrame->GetOffsetTo(rootFrame);
  654. nsIFrame* cursorFrame =
  655. nsLayoutUtils::GetFrameForPoint(rootFrame, ptInRoot);
  656. // If the mouse cursor in on a frame which is descendant of same
  657. // selection root, we can expand the selection to the frame.
  658. if (cursorFrame && cursorFrame->PresContext()->PresShell() == mShell)
  659. {
  660. nsIContent* cursorContent = cursorFrame->GetContent();
  661. NS_ENSURE_TRUE(cursorContent, NS_ERROR_FAILURE);
  662. nsIContent* cursorContentRoot =
  663. cursorContent->GetSelectionRootContent(mShell);
  664. NS_ENSURE_TRUE(cursorContentRoot, NS_ERROR_UNEXPECTED);
  665. if (cursorContentRoot == anchorRoot)
  666. {
  667. *aRetFrame = cursorFrame;
  668. aRetPoint = aPoint + aFrame->GetOffsetTo(cursorFrame);
  669. return NS_OK;
  670. }
  671. }
  672. // Otherwise, e.g., the cursor isn't on any frames (e.g., the mouse
  673. // cursor is out of the window), we should use the frame of the anchor
  674. // root.
  675. }
  676. }
  677. //
  678. // When we can't find a frame which is under the mouse cursor and has a same
  679. // selection root as the anchor node's, we should return the selection root
  680. // frame.
  681. //
  682. *aRetFrame = anchorRoot->GetPrimaryFrame();
  683. if (!*aRetFrame)
  684. return NS_ERROR_FAILURE;
  685. //
  686. // Now make sure that aRetPoint is converted to the same coordinate
  687. // system used by aRetFrame.
  688. //
  689. aRetPoint = aPoint + aFrame->GetOffsetTo(*aRetFrame);
  690. return NS_OK;
  691. }
  692. void
  693. nsFrameSelection::SetCaretBidiLevel(nsBidiLevel aLevel)
  694. {
  695. // If the current level is undefined, we have just inserted new text.
  696. // In this case, we don't want to reset the keyboard language
  697. mCaretBidiLevel = aLevel;
  698. RefPtr<nsCaret> caret;
  699. if (mShell && (caret = mShell->GetCaret())) {
  700. caret->SchedulePaint();
  701. }
  702. return;
  703. }
  704. nsBidiLevel
  705. nsFrameSelection::GetCaretBidiLevel() const
  706. {
  707. return mCaretBidiLevel;
  708. }
  709. void
  710. nsFrameSelection::UndefineCaretBidiLevel()
  711. {
  712. mCaretBidiLevel |= BIDI_LEVEL_UNDEFINED;
  713. }
  714. #ifdef PRINT_RANGE
  715. void printRange(nsRange *aDomRange)
  716. {
  717. if (!aDomRange)
  718. {
  719. printf("NULL nsIDOMRange\n");
  720. }
  721. nsINode* startNode = aDomRange->GetStartParent();
  722. nsINode* endNode = aDomRange->GetEndParent();
  723. int32_t startOffset = aDomRange->StartOffset();
  724. int32_t endOffset = aDomRange->EndOffset();
  725. printf("range: 0x%lx\t start: 0x%lx %ld, \t end: 0x%lx,%ld\n",
  726. (unsigned long)aDomRange,
  727. (unsigned long)startNode, (long)startOffset,
  728. (unsigned long)endNode, (long)endOffset);
  729. }
  730. #endif /* PRINT_RANGE */
  731. static
  732. nsIAtom *GetTag(nsINode *aNode)
  733. {
  734. nsCOMPtr<nsIContent> content = do_QueryInterface(aNode);
  735. if (!content)
  736. {
  737. NS_NOTREACHED("bad node passed to GetTag()");
  738. return nullptr;
  739. }
  740. return content->NodeInfo()->NameAtom();
  741. }
  742. // Returns the parent
  743. nsINode*
  744. ParentOffset(nsINode *aNode, int32_t *aChildOffset)
  745. {
  746. if (!aNode || !aChildOffset)
  747. return nullptr;
  748. nsIContent* parent = aNode->GetParent();
  749. if (parent)
  750. {
  751. *aChildOffset = parent->IndexOf(aNode);
  752. return parent;
  753. }
  754. return nullptr;
  755. }
  756. static nsINode*
  757. GetCellParent(nsINode *aDomNode)
  758. {
  759. if (!aDomNode)
  760. return nullptr;
  761. nsINode* current = aDomNode;
  762. // Start with current node and look for a table cell
  763. while (current)
  764. {
  765. nsIAtom* tag = GetTag(current);
  766. if (tag == nsGkAtoms::td || tag == nsGkAtoms::th)
  767. return current;
  768. current = current->GetParent();
  769. }
  770. return nullptr;
  771. }
  772. void
  773. nsFrameSelection::Init(nsIPresShell *aShell, nsIContent *aLimiter)
  774. {
  775. mShell = aShell;
  776. mDragState = false;
  777. mDesiredPosSet = false;
  778. mLimiter = aLimiter;
  779. mCaretMovementStyle =
  780. Preferences::GetInt("bidi.edit.caret_movement_style", 2);
  781. // This should only ever be initialized on the main thread, so we are OK here.
  782. static bool prefCachesInitialized = false;
  783. if (!prefCachesInitialized) {
  784. prefCachesInitialized = true;
  785. Preferences::AddBoolVarCache(&sSelectionEventsEnabled,
  786. "dom.select_events.enabled", false);
  787. Preferences::AddBoolVarCache(&sSelectionEventsOnTextControlsEnabled,
  788. "dom.select_events.textcontrols.enabled", false);
  789. }
  790. RefPtr<AccessibleCaretEventHub> eventHub = mShell->GetAccessibleCaretEventHub();
  791. if (eventHub) {
  792. int8_t index = GetIndexFromSelectionType(SelectionType::eNormal);
  793. if (mDomSelections[index]) {
  794. mDomSelections[index]->AddSelectionListener(eventHub);
  795. }
  796. }
  797. nsIDocument* doc = aShell->GetDocument();
  798. if (sSelectionEventsEnabled ||
  799. (doc && nsContentUtils::IsSystemPrincipal(doc->NodePrincipal()))) {
  800. int8_t index = GetIndexFromSelectionType(SelectionType::eNormal);
  801. if (mDomSelections[index]) {
  802. // The Selection instance will hold a strong reference to its selectionchangelistener
  803. // so we don't have to worry about that!
  804. RefPtr<SelectionChangeListener> listener = new SelectionChangeListener;
  805. mDomSelections[index]->AddSelectionListener(listener);
  806. }
  807. }
  808. }
  809. bool nsFrameSelection::sSelectionEventsEnabled = false;
  810. bool nsFrameSelection::sSelectionEventsOnTextControlsEnabled = false;
  811. nsresult
  812. nsFrameSelection::MoveCaret(nsDirection aDirection,
  813. bool aContinueSelection,
  814. nsSelectionAmount aAmount,
  815. CaretMovementStyle aMovementStyle)
  816. {
  817. bool visualMovement = aMovementStyle == eVisual ||
  818. (aMovementStyle == eUsePrefStyle &&
  819. (mCaretMovementStyle == 1 ||
  820. (mCaretMovementStyle == 2 && !aContinueSelection)));
  821. NS_ENSURE_STATE(mShell);
  822. // Flush out layout, since we need it to be up to date to do caret
  823. // positioning.
  824. mShell->FlushPendingNotifications(Flush_Layout);
  825. if (!mShell) {
  826. return NS_OK;
  827. }
  828. nsPresContext *context = mShell->GetPresContext();
  829. if (!context)
  830. return NS_ERROR_FAILURE;
  831. bool isCollapsed;
  832. nsPoint desiredPos(0, 0); //we must keep this around and revalidate it when its just UP/DOWN
  833. int8_t index = GetIndexFromSelectionType(SelectionType::eNormal);
  834. RefPtr<Selection> sel = mDomSelections[index];
  835. if (!sel)
  836. return NS_ERROR_NULL_POINTER;
  837. int32_t scrollFlags = Selection::SCROLL_FOR_CARET_MOVE;
  838. nsINode* focusNode = sel->GetFocusNode();
  839. if (focusNode &&
  840. (focusNode->IsEditable() ||
  841. (focusNode->IsElement() &&
  842. focusNode->AsElement()->State().
  843. HasState(NS_EVENT_STATE_MOZ_READWRITE)))) {
  844. // If caret moves in editor, it should cause scrolling even if it's in
  845. // overflow: hidden;.
  846. scrollFlags |= Selection::SCROLL_OVERFLOW_HIDDEN;
  847. }
  848. nsresult result = sel->GetIsCollapsed(&isCollapsed);
  849. if (NS_FAILED(result)) {
  850. return result;
  851. }
  852. int32_t caretStyle = Preferences::GetInt("layout.selection.caret_style", 0);
  853. if (caretStyle == 0
  854. #ifdef XP_WIN
  855. && aAmount != eSelectLine
  856. #endif
  857. ) {
  858. // Put caret at the selection edge in the |aDirection| direction.
  859. caretStyle = 2;
  860. }
  861. bool doCollapse = !isCollapsed && !aContinueSelection && caretStyle == 2 &&
  862. aAmount <= eSelectLine;
  863. if (doCollapse) {
  864. if (aDirection == eDirPrevious) {
  865. PostReason(nsISelectionListener::COLLAPSETOSTART_REASON);
  866. mHint = CARET_ASSOCIATE_AFTER;
  867. } else {
  868. PostReason(nsISelectionListener::COLLAPSETOEND_REASON);
  869. mHint = CARET_ASSOCIATE_BEFORE;
  870. }
  871. } else {
  872. PostReason(nsISelectionListener::KEYPRESS_REASON);
  873. }
  874. AutoPrepareFocusRange prep(sel, aContinueSelection, false);
  875. if (aAmount == eSelectLine) {
  876. result = FetchDesiredPos(desiredPos);
  877. if (NS_FAILED(result)) {
  878. return result;
  879. }
  880. SetDesiredPos(desiredPos);
  881. }
  882. if (doCollapse) {
  883. const nsRange* anchorFocusRange = sel->GetAnchorFocusRange();
  884. if (anchorFocusRange) {
  885. nsINode* node;
  886. int32_t offset;
  887. if (aDirection == eDirPrevious) {
  888. node = anchorFocusRange->GetStartParent();
  889. offset = anchorFocusRange->StartOffset();
  890. } else {
  891. node = anchorFocusRange->GetEndParent();
  892. offset = anchorFocusRange->EndOffset();
  893. }
  894. sel->Collapse(node, offset);
  895. }
  896. sel->ScrollIntoView(nsISelectionController::SELECTION_FOCUS_REGION,
  897. nsIPresShell::ScrollAxis(),
  898. nsIPresShell::ScrollAxis(), scrollFlags);
  899. return NS_OK;
  900. }
  901. nsIFrame *frame;
  902. int32_t offsetused = 0;
  903. result = sel->GetPrimaryFrameForFocusNode(&frame, &offsetused,
  904. visualMovement);
  905. if (NS_FAILED(result) || !frame)
  906. return NS_FAILED(result) ? result : NS_ERROR_FAILURE;
  907. //set data using mLimiter to stop on scroll views. If we have a limiter then we stop peeking
  908. //when we hit scrollable views. If no limiter then just let it go ahead
  909. nsPeekOffsetStruct pos(aAmount, eDirPrevious, offsetused, desiredPos,
  910. true, mLimiter != nullptr, true, visualMovement,
  911. aContinueSelection);
  912. nsBidiDirection paraDir = nsBidiPresUtils::ParagraphDirection(frame);
  913. CaretAssociateHint tHint(mHint); //temporary variable so we dont set mHint until it is necessary
  914. switch (aAmount){
  915. case eSelectCharacter:
  916. case eSelectCluster:
  917. case eSelectWord:
  918. case eSelectWordNoSpace:
  919. InvalidateDesiredPos();
  920. pos.mAmount = aAmount;
  921. pos.mDirection = (visualMovement && paraDir == NSBIDI_RTL)
  922. ? nsDirection(1 - aDirection) : aDirection;
  923. break;
  924. case eSelectLine:
  925. pos.mAmount = aAmount;
  926. pos.mDirection = aDirection;
  927. break;
  928. case eSelectBeginLine:
  929. case eSelectEndLine:
  930. InvalidateDesiredPos();
  931. pos.mAmount = aAmount;
  932. pos.mDirection = (visualMovement && paraDir == NSBIDI_RTL)
  933. ? nsDirection(1 - aDirection) : aDirection;
  934. break;
  935. default:
  936. return NS_ERROR_FAILURE;
  937. }
  938. if (NS_SUCCEEDED(result = frame->PeekOffset(&pos)) && pos.mResultContent)
  939. {
  940. nsIFrame *theFrame;
  941. int32_t currentOffset, frameStart, frameEnd;
  942. if (aAmount <= eSelectWordNoSpace)
  943. {
  944. // For left/right, PeekOffset() sets pos.mResultFrame correctly, but does not set pos.mAttachForward,
  945. // so determine the hint here based on the result frame and offset:
  946. // If we're at the end of a text frame, set the hint to ASSOCIATE_BEFORE to indicate that we
  947. // want the caret displayed at the end of this frame, not at the beginning of the next one.
  948. theFrame = pos.mResultFrame;
  949. theFrame->GetOffsets(frameStart, frameEnd);
  950. currentOffset = pos.mContentOffset;
  951. if (frameEnd == currentOffset && !(frameStart == 0 && frameEnd == 0))
  952. tHint = CARET_ASSOCIATE_BEFORE;
  953. else
  954. tHint = CARET_ASSOCIATE_AFTER;
  955. } else {
  956. // For up/down and home/end, pos.mResultFrame might not be set correctly, or not at all.
  957. // In these cases, get the frame based on the content and hint returned by PeekOffset().
  958. tHint = pos.mAttach;
  959. theFrame = GetFrameForNodeOffset(pos.mResultContent, pos.mContentOffset,
  960. tHint, &currentOffset);
  961. if (!theFrame)
  962. return NS_ERROR_FAILURE;
  963. theFrame->GetOffsets(frameStart, frameEnd);
  964. }
  965. if (context->BidiEnabled())
  966. {
  967. switch (aAmount) {
  968. case eSelectBeginLine:
  969. case eSelectEndLine: {
  970. // In Bidi contexts, PeekOffset calculates pos.mContentOffset
  971. // differently depending on whether the movement is visual or logical.
  972. // For visual movement, pos.mContentOffset depends on the direction-
  973. // ality of the first/last frame on the line (theFrame), and the caret
  974. // directionality must correspond.
  975. FrameBidiData bidiData = theFrame->GetBidiData();
  976. SetCaretBidiLevel(visualMovement ? bidiData.embeddingLevel
  977. : bidiData.baseLevel);
  978. break;
  979. }
  980. default:
  981. // If the current position is not a frame boundary, it's enough just
  982. // to take the Bidi level of the current frame
  983. if ((pos.mContentOffset != frameStart &&
  984. pos.mContentOffset != frameEnd) ||
  985. eSelectLine == aAmount) {
  986. SetCaretBidiLevel(theFrame->GetEmbeddingLevel());
  987. }
  988. else {
  989. BidiLevelFromMove(mShell, pos.mResultContent, pos.mContentOffset,
  990. aAmount, tHint);
  991. }
  992. }
  993. }
  994. result = TakeFocus(pos.mResultContent, pos.mContentOffset, pos.mContentOffset,
  995. tHint, aContinueSelection, false);
  996. } else if (aAmount <= eSelectWordNoSpace && aDirection == eDirNext &&
  997. !aContinueSelection) {
  998. // Collapse selection if PeekOffset failed, we either
  999. // 1. bumped into the BRFrame, bug 207623
  1000. // 2. had select-all in a text input (DIV range), bug 352759.
  1001. bool isBRFrame = frame->GetType() == nsGkAtoms::brFrame;
  1002. sel->Collapse(sel->GetFocusNode(), sel->FocusOffset());
  1003. // Note: 'frame' might be dead here.
  1004. if (!isBRFrame) {
  1005. mHint = CARET_ASSOCIATE_BEFORE; // We're now at the end of the frame to the left.
  1006. }
  1007. result = NS_OK;
  1008. }
  1009. if (NS_SUCCEEDED(result))
  1010. {
  1011. result = mDomSelections[index]->
  1012. ScrollIntoView(nsISelectionController::SELECTION_FOCUS_REGION,
  1013. nsIPresShell::ScrollAxis(), nsIPresShell::ScrollAxis(),
  1014. scrollFlags);
  1015. }
  1016. return result;
  1017. }
  1018. //END nsFrameSelection methods
  1019. //BEGIN nsFrameSelection methods
  1020. NS_IMETHODIMP
  1021. Selection::ToString(nsAString& aReturn)
  1022. {
  1023. // We need Flush_Style here to make sure frames have been created for
  1024. // the selected content. Use mFrameSelection->GetShell() which returns
  1025. // null if the Selection has been disconnected (the shell is Destroyed).
  1026. nsCOMPtr<nsIPresShell> shell =
  1027. mFrameSelection ? mFrameSelection->GetShell() : nullptr;
  1028. if (!shell) {
  1029. aReturn.Truncate();
  1030. return NS_OK;
  1031. }
  1032. shell->FlushPendingNotifications(Flush_Style);
  1033. return ToStringWithFormat("text/plain",
  1034. nsIDocumentEncoder::SkipInvisibleContent,
  1035. 0, aReturn);
  1036. }
  1037. void
  1038. Selection::Stringify(nsAString& aResult)
  1039. {
  1040. // Eat the error code
  1041. ToString(aResult);
  1042. }
  1043. NS_IMETHODIMP
  1044. Selection::ToStringWithFormat(const char* aFormatType, uint32_t aFlags,
  1045. int32_t aWrapCol, nsAString& aReturn)
  1046. {
  1047. ErrorResult result;
  1048. NS_ConvertUTF8toUTF16 format(aFormatType);
  1049. ToStringWithFormat(format, aFlags, aWrapCol, aReturn, result);
  1050. if (result.Failed()) {
  1051. return result.StealNSResult();
  1052. }
  1053. return NS_OK;
  1054. }
  1055. void
  1056. Selection::ToStringWithFormat(const nsAString& aFormatType, uint32_t aFlags,
  1057. int32_t aWrapCol, nsAString& aReturn,
  1058. ErrorResult& aRv)
  1059. {
  1060. nsresult rv = NS_OK;
  1061. NS_ConvertUTF8toUTF16 formatType( NS_DOC_ENCODER_CONTRACTID_BASE );
  1062. formatType.Append(aFormatType);
  1063. nsCOMPtr<nsIDocumentEncoder> encoder =
  1064. do_CreateInstance(NS_ConvertUTF16toUTF8(formatType).get(), &rv);
  1065. if (NS_FAILED(rv)) {
  1066. aRv.Throw(rv);
  1067. return;
  1068. }
  1069. nsIPresShell* shell = GetPresShell();
  1070. if (!shell) {
  1071. aRv.Throw(NS_ERROR_FAILURE);
  1072. return;
  1073. }
  1074. nsIDocument *doc = shell->GetDocument();
  1075. nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(doc);
  1076. NS_ASSERTION(domDoc, "Need a document");
  1077. // Flags should always include OutputSelectionOnly if we're coming from here:
  1078. aFlags |= nsIDocumentEncoder::OutputSelectionOnly;
  1079. nsAutoString readstring;
  1080. readstring.Assign(aFormatType);
  1081. rv = encoder->Init(domDoc, readstring, aFlags);
  1082. if (NS_FAILED(rv)) {
  1083. aRv.Throw(rv);
  1084. return;
  1085. }
  1086. encoder->SetSelection(this);
  1087. if (aWrapCol != 0)
  1088. encoder->SetWrapColumn(aWrapCol);
  1089. rv = encoder->EncodeToString(aReturn);
  1090. if (NS_FAILED(rv)) {
  1091. aRv.Throw(rv);
  1092. }
  1093. }
  1094. NS_IMETHODIMP
  1095. Selection::SetInterlinePosition(bool aHintRight)
  1096. {
  1097. ErrorResult result;
  1098. SetInterlinePosition(aHintRight, result);
  1099. if (result.Failed()) {
  1100. return result.StealNSResult();
  1101. }
  1102. return NS_OK;
  1103. }
  1104. void
  1105. Selection::SetInterlinePosition(bool aHintRight, ErrorResult& aRv)
  1106. {
  1107. if (!mFrameSelection) {
  1108. aRv.Throw(NS_ERROR_NOT_INITIALIZED); // Can't do selection
  1109. return;
  1110. }
  1111. mFrameSelection->SetHint(aHintRight ? CARET_ASSOCIATE_AFTER : CARET_ASSOCIATE_BEFORE);
  1112. }
  1113. NS_IMETHODIMP
  1114. Selection::GetInterlinePosition(bool* aHintRight)
  1115. {
  1116. ErrorResult result;
  1117. *aHintRight = GetInterlinePosition(result);
  1118. if (result.Failed()) {
  1119. return result.StealNSResult();
  1120. }
  1121. return NS_OK;
  1122. }
  1123. bool
  1124. Selection::GetInterlinePosition(ErrorResult& aRv)
  1125. {
  1126. if (!mFrameSelection) {
  1127. aRv.Throw(NS_ERROR_NOT_INITIALIZED); // Can't do selection
  1128. return false;
  1129. }
  1130. return mFrameSelection->GetHint() == CARET_ASSOCIATE_AFTER;
  1131. }
  1132. Nullable<int16_t>
  1133. Selection::GetCaretBidiLevel(mozilla::ErrorResult& aRv) const
  1134. {
  1135. if (!mFrameSelection) {
  1136. aRv.Throw(NS_ERROR_NOT_INITIALIZED);
  1137. return Nullable<int16_t>();
  1138. }
  1139. nsBidiLevel caretBidiLevel = mFrameSelection->GetCaretBidiLevel();
  1140. return (caretBidiLevel & BIDI_LEVEL_UNDEFINED) ?
  1141. Nullable<int16_t>() : Nullable<int16_t>(caretBidiLevel);
  1142. }
  1143. void
  1144. Selection::SetCaretBidiLevel(const Nullable<int16_t>& aCaretBidiLevel, mozilla::ErrorResult& aRv)
  1145. {
  1146. if (!mFrameSelection) {
  1147. aRv.Throw(NS_ERROR_NOT_INITIALIZED);
  1148. return;
  1149. }
  1150. if (aCaretBidiLevel.IsNull()) {
  1151. mFrameSelection->UndefineCaretBidiLevel();
  1152. } else {
  1153. mFrameSelection->SetCaretBidiLevel(aCaretBidiLevel.Value());
  1154. }
  1155. }
  1156. nsPrevNextBidiLevels
  1157. nsFrameSelection::GetPrevNextBidiLevels(nsIContent *aNode,
  1158. uint32_t aContentOffset,
  1159. bool aJumpLines) const
  1160. {
  1161. return GetPrevNextBidiLevels(aNode, aContentOffset, mHint, aJumpLines);
  1162. }
  1163. nsPrevNextBidiLevels
  1164. nsFrameSelection::GetPrevNextBidiLevels(nsIContent* aNode,
  1165. uint32_t aContentOffset,
  1166. CaretAssociateHint aHint,
  1167. bool aJumpLines) const
  1168. {
  1169. // Get the level of the frames on each side
  1170. nsIFrame *currentFrame;
  1171. int32_t currentOffset;
  1172. int32_t frameStart, frameEnd;
  1173. nsDirection direction;
  1174. nsPrevNextBidiLevels levels;
  1175. levels.SetData(nullptr, nullptr, 0, 0);
  1176. currentFrame = GetFrameForNodeOffset(aNode, aContentOffset,
  1177. aHint, &currentOffset);
  1178. if (!currentFrame)
  1179. return levels;
  1180. currentFrame->GetOffsets(frameStart, frameEnd);
  1181. if (0 == frameStart && 0 == frameEnd)
  1182. direction = eDirPrevious;
  1183. else if (frameStart == currentOffset)
  1184. direction = eDirPrevious;
  1185. else if (frameEnd == currentOffset)
  1186. direction = eDirNext;
  1187. else {
  1188. // we are neither at the beginning nor at the end of the frame, so we have no worries
  1189. nsBidiLevel currentLevel = currentFrame->GetEmbeddingLevel();
  1190. levels.SetData(currentFrame, currentFrame, currentLevel, currentLevel);
  1191. return levels;
  1192. }
  1193. nsIFrame *newFrame;
  1194. int32_t offset;
  1195. bool jumpedLine, movedOverNonSelectableText;
  1196. nsresult rv = currentFrame->GetFrameFromDirection(direction, false,
  1197. aJumpLines, true,
  1198. &newFrame, &offset, &jumpedLine,
  1199. &movedOverNonSelectableText);
  1200. if (NS_FAILED(rv))
  1201. newFrame = nullptr;
  1202. FrameBidiData currentBidi = currentFrame->GetBidiData();
  1203. nsBidiLevel currentLevel = currentBidi.embeddingLevel;
  1204. nsBidiLevel newLevel = newFrame ? newFrame->GetEmbeddingLevel()
  1205. : currentBidi.baseLevel;
  1206. // If not jumping lines, disregard br frames, since they might be positioned incorrectly.
  1207. // XXX This could be removed once bug 339786 is fixed.
  1208. if (!aJumpLines) {
  1209. if (currentFrame->GetType() == nsGkAtoms::brFrame) {
  1210. currentFrame = nullptr;
  1211. currentLevel = currentBidi.baseLevel;
  1212. }
  1213. if (newFrame && newFrame->GetType() == nsGkAtoms::brFrame) {
  1214. newFrame = nullptr;
  1215. newLevel = currentBidi.baseLevel;
  1216. }
  1217. }
  1218. if (direction == eDirNext)
  1219. levels.SetData(currentFrame, newFrame, currentLevel, newLevel);
  1220. else
  1221. levels.SetData(newFrame, currentFrame, newLevel, currentLevel);
  1222. return levels;
  1223. }
  1224. nsresult
  1225. nsFrameSelection::GetFrameFromLevel(nsIFrame *aFrameIn,
  1226. nsDirection aDirection,
  1227. nsBidiLevel aBidiLevel,
  1228. nsIFrame **aFrameOut) const
  1229. {
  1230. NS_ENSURE_STATE(mShell);
  1231. nsBidiLevel foundLevel = 0;
  1232. nsIFrame *foundFrame = aFrameIn;
  1233. nsCOMPtr<nsIFrameEnumerator> frameTraversal;
  1234. nsresult result;
  1235. nsCOMPtr<nsIFrameTraversal> trav(do_CreateInstance(kFrameTraversalCID,&result));
  1236. if (NS_FAILED(result))
  1237. return result;
  1238. result = trav->NewFrameTraversal(getter_AddRefs(frameTraversal),
  1239. mShell->GetPresContext(), aFrameIn,
  1240. eLeaf,
  1241. false, // aVisual
  1242. false, // aLockInScrollView
  1243. false, // aFollowOOFs
  1244. false // aSkipPopupChecks
  1245. );
  1246. if (NS_FAILED(result))
  1247. return result;
  1248. do {
  1249. *aFrameOut = foundFrame;
  1250. if (aDirection == eDirNext)
  1251. frameTraversal->Next();
  1252. else
  1253. frameTraversal->Prev();
  1254. foundFrame = frameTraversal->CurrentItem();
  1255. if (!foundFrame)
  1256. return NS_ERROR_FAILURE;
  1257. foundLevel = foundFrame->GetEmbeddingLevel();
  1258. } while (foundLevel > aBidiLevel);
  1259. return NS_OK;
  1260. }
  1261. nsresult
  1262. nsFrameSelection::MaintainSelection(nsSelectionAmount aAmount)
  1263. {
  1264. int8_t index = GetIndexFromSelectionType(SelectionType::eNormal);
  1265. if (!mDomSelections[index])
  1266. return NS_ERROR_NULL_POINTER;
  1267. mMaintainedAmount = aAmount;
  1268. const nsRange* anchorFocusRange =
  1269. mDomSelections[index]->GetAnchorFocusRange();
  1270. if (anchorFocusRange && aAmount != eSelectNoAmount) {
  1271. mMaintainRange = anchorFocusRange->CloneRange();
  1272. return NS_OK;
  1273. }
  1274. mMaintainRange = nullptr;
  1275. return NS_OK;
  1276. }
  1277. /** After moving the caret, its Bidi level is set according to the following rules:
  1278. *
  1279. * After moving over a character with left/right arrow, set to the Bidi level of the last moved over character.
  1280. * After Home and End, set to the paragraph embedding level.
  1281. * After up/down arrow, PageUp/Down, set to the lower level of the 2 surrounding characters.
  1282. * After mouse click, set to the level of the current frame.
  1283. *
  1284. * The following two methods use GetPrevNextBidiLevels to determine the new Bidi level.
  1285. * BidiLevelFromMove is called when the caret is moved in response to a keyboard event
  1286. *
  1287. * @param aPresShell is the presentation shell
  1288. * @param aNode is the content node
  1289. * @param aContentOffset is the new caret position, as an offset into aNode
  1290. * @param aAmount is the amount of the move that gave the caret its new position
  1291. * @param aHint is the hint indicating in what logical direction the caret moved
  1292. */
  1293. void nsFrameSelection::BidiLevelFromMove(nsIPresShell* aPresShell,
  1294. nsIContent* aNode,
  1295. uint32_t aContentOffset,
  1296. nsSelectionAmount aAmount,
  1297. CaretAssociateHint aHint)
  1298. {
  1299. switch (aAmount) {
  1300. // Movement within the line: the new cursor Bidi level is the level of the
  1301. // last character moved over
  1302. case eSelectCharacter:
  1303. case eSelectCluster:
  1304. case eSelectWord:
  1305. case eSelectWordNoSpace:
  1306. case eSelectBeginLine:
  1307. case eSelectEndLine:
  1308. case eSelectNoAmount:
  1309. {
  1310. nsPrevNextBidiLevels levels = GetPrevNextBidiLevels(aNode, aContentOffset,
  1311. aHint, false);
  1312. SetCaretBidiLevel(aHint == CARET_ASSOCIATE_BEFORE ?
  1313. levels.mLevelBefore : levels.mLevelAfter);
  1314. break;
  1315. }
  1316. /*
  1317. // Up and Down: the new cursor Bidi level is the smaller of the two surrounding characters
  1318. case eSelectLine:
  1319. case eSelectParagraph:
  1320. GetPrevNextBidiLevels(aContext, aNode, aContentOffset, &firstFrame, &secondFrame, &firstLevel, &secondLevel);
  1321. aPresShell->SetCaretBidiLevel(std::min(firstLevel, secondLevel));
  1322. break;
  1323. */
  1324. default:
  1325. UndefineCaretBidiLevel();
  1326. }
  1327. }
  1328. /**
  1329. * BidiLevelFromClick is called when the caret is repositioned by clicking the mouse
  1330. *
  1331. * @param aNode is the content node
  1332. * @param aContentOffset is the new caret position, as an offset into aNode
  1333. */
  1334. void nsFrameSelection::BidiLevelFromClick(nsIContent *aNode,
  1335. uint32_t aContentOffset)
  1336. {
  1337. nsIFrame* clickInFrame=nullptr;
  1338. int32_t OffsetNotUsed;
  1339. clickInFrame = GetFrameForNodeOffset(aNode, aContentOffset, mHint, &OffsetNotUsed);
  1340. if (!clickInFrame)
  1341. return;
  1342. SetCaretBidiLevel(clickInFrame->GetEmbeddingLevel());
  1343. }
  1344. bool
  1345. nsFrameSelection::AdjustForMaintainedSelection(nsIContent *aContent,
  1346. int32_t aOffset)
  1347. {
  1348. if (!mMaintainRange)
  1349. return false;
  1350. if (!aContent) {
  1351. return false;
  1352. }
  1353. int8_t index = GetIndexFromSelectionType(SelectionType::eNormal);
  1354. if (!mDomSelections[index])
  1355. return false;
  1356. nsINode* rangeStartNode = mMaintainRange->GetStartParent();
  1357. nsINode* rangeEndNode = mMaintainRange->GetEndParent();
  1358. int32_t rangeStartOffset = mMaintainRange->StartOffset();
  1359. int32_t rangeEndOffset = mMaintainRange->EndOffset();
  1360. int32_t relToStart =
  1361. nsContentUtils::ComparePoints(rangeStartNode, rangeStartOffset,
  1362. aContent, aOffset);
  1363. int32_t relToEnd =
  1364. nsContentUtils::ComparePoints(rangeEndNode, rangeEndOffset,
  1365. aContent, aOffset);
  1366. // If aContent/aOffset is inside the maintained selection, or if it is on the
  1367. // "anchor" side of the maintained selection, we need to do something.
  1368. if ((relToStart < 0 && relToEnd > 0) ||
  1369. (relToStart > 0 &&
  1370. mDomSelections[index]->GetDirection() == eDirNext) ||
  1371. (relToEnd < 0 &&
  1372. mDomSelections[index]->GetDirection() == eDirPrevious)) {
  1373. // Set the current range to the maintained range.
  1374. mDomSelections[index]->ReplaceAnchorFocusRange(mMaintainRange);
  1375. if (relToStart < 0 && relToEnd > 0) {
  1376. // We're inside the maintained selection, just keep it selected.
  1377. return true;
  1378. }
  1379. // Reverse the direction of the selection so that the anchor will be on the
  1380. // far side of the maintained selection, relative to aContent/aOffset.
  1381. mDomSelections[index]->SetDirection(relToStart > 0 ? eDirPrevious : eDirNext);
  1382. }
  1383. return false;
  1384. }
  1385. nsresult
  1386. nsFrameSelection::HandleClick(nsIContent* aNewFocus,
  1387. uint32_t aContentOffset,
  1388. uint32_t aContentEndOffset,
  1389. bool aContinueSelection,
  1390. bool aMultipleSelection,
  1391. CaretAssociateHint aHint)
  1392. {
  1393. if (!aNewFocus)
  1394. return NS_ERROR_INVALID_ARG;
  1395. InvalidateDesiredPos();
  1396. if (!aContinueSelection) {
  1397. mMaintainRange = nullptr;
  1398. if (!IsValidSelectionPoint(this, aNewFocus)) {
  1399. mAncestorLimiter = nullptr;
  1400. }
  1401. }
  1402. // Don't take focus when dragging off of a table
  1403. if (!mDragSelectingCells)
  1404. {
  1405. BidiLevelFromClick(aNewFocus, aContentOffset);
  1406. PostReason(nsISelectionListener::MOUSEDOWN_REASON + nsISelectionListener::DRAG_REASON);
  1407. if (aContinueSelection &&
  1408. AdjustForMaintainedSelection(aNewFocus, aContentOffset))
  1409. return NS_OK; //shift clicked to maintained selection. rejected.
  1410. int8_t index = GetIndexFromSelectionType(SelectionType::eNormal);
  1411. AutoPrepareFocusRange prep(mDomSelections[index], aContinueSelection, aMultipleSelection);
  1412. return TakeFocus(aNewFocus, aContentOffset, aContentEndOffset, aHint,
  1413. aContinueSelection, aMultipleSelection);
  1414. }
  1415. return NS_OK;
  1416. }
  1417. void
  1418. nsFrameSelection::HandleDrag(nsIFrame *aFrame, nsPoint aPoint)
  1419. {
  1420. if (!aFrame || !mShell)
  1421. return;
  1422. nsresult result;
  1423. nsIFrame *newFrame = 0;
  1424. nsPoint newPoint;
  1425. result = ConstrainFrameAndPointToAnchorSubtree(aFrame, aPoint, &newFrame, newPoint);
  1426. if (NS_FAILED(result))
  1427. return;
  1428. if (!newFrame)
  1429. return;
  1430. nsIFrame::ContentOffsets offsets =
  1431. newFrame->GetContentOffsetsFromPoint(newPoint);
  1432. if (!offsets.content)
  1433. return;
  1434. if (newFrame->IsSelected() &&
  1435. AdjustForMaintainedSelection(offsets.content, offsets.offset))
  1436. return;
  1437. // Adjust offsets according to maintained amount
  1438. if (mMaintainRange &&
  1439. mMaintainedAmount != eSelectNoAmount) {
  1440. nsINode* rangenode = mMaintainRange->GetStartParent();
  1441. int32_t rangeOffset = mMaintainRange->StartOffset();
  1442. int32_t relativePosition =
  1443. nsContentUtils::ComparePoints(rangenode, rangeOffset,
  1444. offsets.content, offsets.offset);
  1445. nsDirection direction = relativePosition > 0 ? eDirPrevious : eDirNext;
  1446. nsSelectionAmount amount = mMaintainedAmount;
  1447. if (amount == eSelectBeginLine && direction == eDirNext)
  1448. amount = eSelectEndLine;
  1449. int32_t offset;
  1450. nsIFrame* frame = GetFrameForNodeOffset(offsets.content, offsets.offset,
  1451. CARET_ASSOCIATE_AFTER, &offset);
  1452. if (frame && amount == eSelectWord && direction == eDirPrevious) {
  1453. // To avoid selecting the previous word when at start of word,
  1454. // first move one character forward.
  1455. nsPeekOffsetStruct charPos(eSelectCharacter, eDirNext, offset,
  1456. nsPoint(0, 0), false, mLimiter != nullptr,
  1457. false, false, false);
  1458. if (NS_SUCCEEDED(frame->PeekOffset(&charPos))) {
  1459. frame = charPos.mResultFrame;
  1460. offset = charPos.mContentOffset;
  1461. }
  1462. }
  1463. nsPeekOffsetStruct pos(amount, direction, offset, nsPoint(0, 0),
  1464. false, mLimiter != nullptr, false, false, false);
  1465. if (frame && NS_SUCCEEDED(frame->PeekOffset(&pos)) && pos.mResultContent) {
  1466. offsets.content = pos.mResultContent;
  1467. offsets.offset = pos.mContentOffset;
  1468. }
  1469. }
  1470. HandleClick(offsets.content, offsets.offset, offsets.offset,
  1471. true, false, offsets.associate);
  1472. }
  1473. nsresult
  1474. nsFrameSelection::StartAutoScrollTimer(nsIFrame *aFrame,
  1475. nsPoint aPoint,
  1476. uint32_t aDelay)
  1477. {
  1478. int8_t index = GetIndexFromSelectionType(SelectionType::eNormal);
  1479. if (!mDomSelections[index])
  1480. return NS_ERROR_NULL_POINTER;
  1481. return mDomSelections[index]->StartAutoScrollTimer(aFrame, aPoint, aDelay);
  1482. }
  1483. void
  1484. nsFrameSelection::StopAutoScrollTimer()
  1485. {
  1486. int8_t index = GetIndexFromSelectionType(SelectionType::eNormal);
  1487. if (!mDomSelections[index])
  1488. return;
  1489. mDomSelections[index]->StopAutoScrollTimer();
  1490. }
  1491. /**
  1492. hard to go from nodes to frames, easy the other way!
  1493. */
  1494. nsresult
  1495. nsFrameSelection::TakeFocus(nsIContent* aNewFocus,
  1496. uint32_t aContentOffset,
  1497. uint32_t aContentEndOffset,
  1498. CaretAssociateHint aHint,
  1499. bool aContinueSelection,
  1500. bool aMultipleSelection)
  1501. {
  1502. if (!aNewFocus)
  1503. return NS_ERROR_NULL_POINTER;
  1504. NS_ENSURE_STATE(mShell);
  1505. if (!IsValidSelectionPoint(this,aNewFocus))
  1506. return NS_ERROR_FAILURE;
  1507. // Clear all table selection data
  1508. mSelectingTableCellMode = 0;
  1509. mDragSelectingCells = false;
  1510. mStartSelectedCell = nullptr;
  1511. mEndSelectedCell = nullptr;
  1512. mAppendStartSelectedCell = nullptr;
  1513. mHint = aHint;
  1514. int8_t index = GetIndexFromSelectionType(SelectionType::eNormal);
  1515. if (!mDomSelections[index])
  1516. return NS_ERROR_NULL_POINTER;
  1517. Maybe<Selection::AutoUserInitiated> userSelect;
  1518. if (IsUserSelectionReason()) {
  1519. userSelect.emplace(mDomSelections[index]);
  1520. }
  1521. //traverse through document and unselect crap here
  1522. if (!aContinueSelection) {//single click? setting cursor down
  1523. uint32_t batching = mBatching;//hack to use the collapse code.
  1524. bool changes = mChangesDuringBatching;
  1525. mBatching = 1;
  1526. if (aMultipleSelection) {
  1527. // Remove existing collapsed ranges as there's no point in having
  1528. // non-anchor/focus collapsed ranges.
  1529. mDomSelections[index]->RemoveCollapsedRanges();
  1530. RefPtr<nsRange> newRange = new nsRange(aNewFocus);
  1531. newRange->CollapseTo(aNewFocus, aContentOffset);
  1532. mDomSelections[index]->AddRange(newRange);
  1533. mBatching = batching;
  1534. mChangesDuringBatching = changes;
  1535. } else {
  1536. bool oldDesiredPosSet = mDesiredPosSet; //need to keep old desired position if it was set.
  1537. mDomSelections[index]->Collapse(aNewFocus, aContentOffset);
  1538. mDesiredPosSet = oldDesiredPosSet; //now reset desired pos back.
  1539. mBatching = batching;
  1540. mChangesDuringBatching = changes;
  1541. }
  1542. if (aContentEndOffset != aContentOffset) {
  1543. mDomSelections[index]->Extend(aNewFocus, aContentEndOffset);
  1544. }
  1545. //find out if we are inside a table. if so, find out which one and which cell
  1546. //once we do that, the next time we get a takefocus, check the parent tree.
  1547. //if we are no longer inside same table ,cell then switch to table selection mode.
  1548. // BUT only do this in an editor
  1549. NS_ENSURE_STATE(mShell);
  1550. bool editableCell = false;
  1551. RefPtr<nsPresContext> context = mShell->GetPresContext();
  1552. if (context) {
  1553. nsCOMPtr<nsIHTMLEditor> editor = do_QueryInterface(nsContentUtils::GetHTMLEditor(context));
  1554. if (editor) {
  1555. nsINode* cellparent = GetCellParent(aNewFocus);
  1556. nsCOMPtr<nsINode> editorHostNode = editor->GetActiveEditingHost();
  1557. editableCell = cellparent && editorHostNode &&
  1558. nsContentUtils::ContentIsDescendantOf(cellparent, editorHostNode);
  1559. if (editableCell) {
  1560. mCellParent = cellparent;
  1561. #ifdef DEBUG_TABLE_SELECTION
  1562. printf(" * TakeFocus - Collapsing into new cell\n");
  1563. #endif
  1564. }
  1565. }
  1566. }
  1567. }
  1568. else {
  1569. // Now update the range list:
  1570. if (aContinueSelection && aNewFocus)
  1571. {
  1572. int32_t offset;
  1573. nsINode *cellparent = GetCellParent(aNewFocus);
  1574. if (mCellParent && cellparent && cellparent != mCellParent) //switch to cell selection mode
  1575. {
  1576. #ifdef DEBUG_TABLE_SELECTION
  1577. printf(" * TakeFocus - moving into new cell\n");
  1578. #endif
  1579. WidgetMouseEvent event(false, eVoidEvent, nullptr,
  1580. WidgetMouseEvent::eReal);
  1581. // Start selecting in the cell we were in before
  1582. nsINode* parent = ParentOffset(mCellParent, &offset);
  1583. if (parent)
  1584. HandleTableSelection(parent, offset,
  1585. nsISelectionPrivate::TABLESELECTION_CELL, &event);
  1586. // Find the parent of this new cell and extend selection to it
  1587. parent = ParentOffset(cellparent, &offset);
  1588. // XXXX We need to REALLY get the current key shift state
  1589. // (we'd need to add event listener -- let's not bother for now)
  1590. event.mModifiers &= ~MODIFIER_SHIFT; //aContinueSelection;
  1591. if (parent)
  1592. {
  1593. mCellParent = cellparent;
  1594. // Continue selection into next cell
  1595. HandleTableSelection(parent, offset,
  1596. nsISelectionPrivate::TABLESELECTION_CELL, &event);
  1597. }
  1598. }
  1599. else
  1600. {
  1601. // XXXX Problem: Shift+click in browser is appending text selection to selected table!!!
  1602. // is this the place to erase seleced cells ?????
  1603. if (mDomSelections[index]->GetDirection() == eDirNext && aContentEndOffset > aContentOffset) //didn't go far enough
  1604. {
  1605. mDomSelections[index]->Extend(aNewFocus, aContentEndOffset);//this will only redraw the diff
  1606. }
  1607. else
  1608. mDomSelections[index]->Extend(aNewFocus, aContentOffset);
  1609. }
  1610. }
  1611. }
  1612. // Don't notify selection listeners if batching is on:
  1613. if (GetBatching())
  1614. return NS_OK;
  1615. return NotifySelectionListeners(SelectionType::eNormal);
  1616. }
  1617. SelectionDetails*
  1618. nsFrameSelection::LookUpSelection(nsIContent *aContent,
  1619. int32_t aContentOffset,
  1620. int32_t aContentLength,
  1621. bool aSlowCheck) const
  1622. {
  1623. if (!aContent || !mShell)
  1624. return nullptr;
  1625. SelectionDetails* details = nullptr;
  1626. for (size_t j = 0; j < kPresentSelectionTypeCount; j++) {
  1627. if (mDomSelections[j]) {
  1628. mDomSelections[j]->LookUpSelection(aContent, aContentOffset,
  1629. aContentLength, &details,
  1630. ToSelectionType(1 << j),
  1631. aSlowCheck);
  1632. }
  1633. }
  1634. return details;
  1635. }
  1636. void
  1637. nsFrameSelection::SetDragState(bool aState)
  1638. {
  1639. if (mDragState == aState)
  1640. return;
  1641. mDragState = aState;
  1642. if (!mDragState)
  1643. {
  1644. mDragSelectingCells = false;
  1645. // Notify that reason is mouse up.
  1646. PostReason(nsISelectionListener::MOUSEUP_REASON);
  1647. NotifySelectionListeners(SelectionType::eNormal);
  1648. }
  1649. }
  1650. Selection*
  1651. nsFrameSelection::GetSelection(SelectionType aSelectionType) const
  1652. {
  1653. int8_t index = GetIndexFromSelectionType(aSelectionType);
  1654. if (index < 0)
  1655. return nullptr;
  1656. return mDomSelections[index];
  1657. }
  1658. nsresult
  1659. nsFrameSelection::ScrollSelectionIntoView(SelectionType aSelectionType,
  1660. SelectionRegion aRegion,
  1661. int16_t aFlags) const
  1662. {
  1663. int8_t index = GetIndexFromSelectionType(aSelectionType);
  1664. if (index < 0)
  1665. return NS_ERROR_INVALID_ARG;
  1666. if (!mDomSelections[index])
  1667. return NS_ERROR_NULL_POINTER;
  1668. nsIPresShell::ScrollAxis verticalScroll = nsIPresShell::ScrollAxis();
  1669. int32_t flags = Selection::SCROLL_DO_FLUSH;
  1670. if (aFlags & nsISelectionController::SCROLL_SYNCHRONOUS) {
  1671. flags |= Selection::SCROLL_SYNCHRONOUS;
  1672. } else if (aFlags & nsISelectionController::SCROLL_FIRST_ANCESTOR_ONLY) {
  1673. flags |= Selection::SCROLL_FIRST_ANCESTOR_ONLY;
  1674. }
  1675. if (aFlags & nsISelectionController::SCROLL_OVERFLOW_HIDDEN) {
  1676. flags |= Selection::SCROLL_OVERFLOW_HIDDEN;
  1677. }
  1678. if (aFlags & nsISelectionController::SCROLL_CENTER_VERTICALLY) {
  1679. verticalScroll = nsIPresShell::ScrollAxis(
  1680. nsIPresShell::SCROLL_CENTER, nsIPresShell::SCROLL_IF_NOT_FULLY_VISIBLE);
  1681. }
  1682. if (aFlags & nsISelectionController::SCROLL_FOR_CARET_MOVE) {
  1683. flags |= Selection::SCROLL_FOR_CARET_MOVE;
  1684. }
  1685. // After ScrollSelectionIntoView(), the pending notifications might be
  1686. // flushed and PresShell/PresContext/Frames may be dead. See bug 418470.
  1687. RefPtr<Selection> sel = mDomSelections[index];
  1688. return sel->ScrollIntoView(aRegion, verticalScroll,
  1689. nsIPresShell::ScrollAxis(), flags);
  1690. }
  1691. nsresult
  1692. nsFrameSelection::RepaintSelection(SelectionType aSelectionType)
  1693. {
  1694. int8_t index = GetIndexFromSelectionType(aSelectionType);
  1695. if (index < 0)
  1696. return NS_ERROR_INVALID_ARG;
  1697. if (!mDomSelections[index])
  1698. return NS_ERROR_NULL_POINTER;
  1699. NS_ENSURE_STATE(mShell);
  1700. return mDomSelections[index]->Repaint(mShell->GetPresContext());
  1701. }
  1702. nsIFrame*
  1703. nsFrameSelection::GetFrameForNodeOffset(nsIContent* aNode,
  1704. int32_t aOffset,
  1705. CaretAssociateHint aHint,
  1706. int32_t* aReturnOffset) const
  1707. {
  1708. if (!aNode || !aReturnOffset || !mShell)
  1709. return nullptr;
  1710. if (aOffset < 0)
  1711. return nullptr;
  1712. if (!aNode->GetPrimaryFrame() &&
  1713. !mShell->FrameManager()->GetDisplayContentsStyleFor(aNode)) {
  1714. return nullptr;
  1715. }
  1716. nsIFrame* returnFrame = nullptr;
  1717. nsCOMPtr<nsIContent> theNode;
  1718. while (true) {
  1719. *aReturnOffset = aOffset;
  1720. theNode = aNode;
  1721. if (aNode->IsElement()) {
  1722. int32_t childIndex = 0;
  1723. int32_t numChildren = theNode->GetChildCount();
  1724. if (aHint == CARET_ASSOCIATE_BEFORE) {
  1725. if (aOffset > 0) {
  1726. childIndex = aOffset - 1;
  1727. } else {
  1728. childIndex = aOffset;
  1729. }
  1730. } else {
  1731. NS_ASSERTION(aHint == CARET_ASSOCIATE_AFTER, "unknown direction");
  1732. if (aOffset >= numChildren) {
  1733. if (numChildren > 0) {
  1734. childIndex = numChildren - 1;
  1735. } else {
  1736. childIndex = 0;
  1737. }
  1738. } else {
  1739. childIndex = aOffset;
  1740. }
  1741. }
  1742. if (childIndex > 0 || numChildren > 0) {
  1743. nsCOMPtr<nsIContent> childNode = theNode->GetChildAt(childIndex);
  1744. if (!childNode) {
  1745. break;
  1746. }
  1747. theNode = childNode;
  1748. }
  1749. // Now that we have the child node, check if it too
  1750. // can contain children. If so, descend into child.
  1751. if (theNode->IsElement() &&
  1752. theNode->GetChildCount() &&
  1753. !theNode->HasIndependentSelection()) {
  1754. aNode = theNode;
  1755. aOffset = aOffset > childIndex ? theNode->GetChildCount() : 0;
  1756. continue;
  1757. } else {
  1758. // Check to see if theNode is a text node. If it is, translate
  1759. // aOffset into an offset into the text node.
  1760. nsCOMPtr<nsIDOMText> textNode = do_QueryInterface(theNode);
  1761. if (textNode) {
  1762. if (theNode->GetPrimaryFrame()) {
  1763. if (aOffset > childIndex) {
  1764. uint32_t textLength = 0;
  1765. nsresult rv = textNode->GetLength(&textLength);
  1766. if (NS_FAILED(rv)) {
  1767. break;
  1768. }
  1769. *aReturnOffset = (int32_t)textLength;
  1770. } else {
  1771. *aReturnOffset = 0;
  1772. }
  1773. } else {
  1774. int32_t numChildren = aNode->GetChildCount();
  1775. int32_t newChildIndex =
  1776. aHint == CARET_ASSOCIATE_BEFORE ? childIndex - 1 : childIndex + 1;
  1777. if (newChildIndex >= 0 && newChildIndex < numChildren) {
  1778. nsCOMPtr<nsIContent> newChildNode = aNode->GetChildAt(newChildIndex);
  1779. if (!newChildNode) {
  1780. return nullptr;
  1781. }
  1782. aNode = newChildNode;
  1783. aOffset = aHint == CARET_ASSOCIATE_BEFORE ? aNode->GetChildCount() : 0;
  1784. continue;
  1785. } else {
  1786. // newChildIndex is illegal which means we're at first or last
  1787. // child. Just use original node to get the frame.
  1788. theNode = aNode;
  1789. }
  1790. }
  1791. }
  1792. }
  1793. }
  1794. // If the node is a ShadowRoot, the frame needs to be adjusted,
  1795. // because a ShadowRoot does not get a frame. Its children are rendered
  1796. // as children of the host.
  1797. mozilla::dom::ShadowRoot* shadowRoot =
  1798. mozilla::dom::ShadowRoot::FromNode(theNode);
  1799. if (shadowRoot) {
  1800. theNode = shadowRoot->GetHost();
  1801. }
  1802. returnFrame = theNode->GetPrimaryFrame();
  1803. if (!returnFrame) {
  1804. if (aHint == CARET_ASSOCIATE_BEFORE) {
  1805. if (aOffset > 0) {
  1806. --aOffset;
  1807. continue;
  1808. } else {
  1809. break;
  1810. }
  1811. } else {
  1812. int32_t end = theNode->GetChildCount();
  1813. if (aOffset < end) {
  1814. ++aOffset;
  1815. continue;
  1816. } else {
  1817. break;
  1818. }
  1819. }
  1820. }
  1821. break;
  1822. } // end while
  1823. if (!returnFrame)
  1824. return nullptr;
  1825. // If we ended up here and were asked to position the caret after a visible
  1826. // break, let's return the frame on the next line instead if it exists.
  1827. if (aOffset > 0 && (uint32_t) aOffset >= aNode->Length() &&
  1828. theNode == aNode->GetLastChild()) {
  1829. nsIFrame* newFrame;
  1830. nsLayoutUtils::IsInvisibleBreak(theNode, &newFrame);
  1831. if (newFrame) {
  1832. returnFrame = newFrame;
  1833. *aReturnOffset = 0;
  1834. }
  1835. }
  1836. // find the child frame containing the offset we want
  1837. returnFrame->GetChildFrameContainingOffset(*aReturnOffset, aHint == CARET_ASSOCIATE_AFTER,
  1838. &aOffset, &returnFrame);
  1839. return returnFrame;
  1840. }
  1841. void
  1842. nsFrameSelection::CommonPageMove(bool aForward,
  1843. bool aExtend,
  1844. nsIScrollableFrame* aScrollableFrame)
  1845. {
  1846. // expected behavior for PageMove is to scroll AND move the caret
  1847. // and remain relative position of the caret in view. see Bug 4302.
  1848. //get the frame from the scrollable view
  1849. nsIFrame* scrolledFrame = aScrollableFrame->GetScrolledFrame();
  1850. if (!scrolledFrame)
  1851. return;
  1852. // find out where the caret is.
  1853. // we should know mDesiredPos value of nsFrameSelection, but I havent seen that behavior in other windows applications yet.
  1854. nsISelection* domSel = GetSelection(SelectionType::eNormal);
  1855. if (!domSel) {
  1856. return;
  1857. }
  1858. nsRect caretPos;
  1859. nsIFrame* caretFrame = nsCaret::GetGeometry(domSel, &caretPos);
  1860. if (!caretFrame)
  1861. return;
  1862. //need to adjust caret jump by percentage scroll
  1863. nsSize scrollDelta = aScrollableFrame->GetPageScrollAmount();
  1864. if (aForward)
  1865. caretPos.y += scrollDelta.height;
  1866. else
  1867. caretPos.y -= scrollDelta.height;
  1868. caretPos += caretFrame->GetOffsetTo(scrolledFrame);
  1869. // get a content at desired location
  1870. nsPoint desiredPoint;
  1871. desiredPoint.x = caretPos.x;
  1872. desiredPoint.y = caretPos.y + caretPos.height/2;
  1873. nsIFrame::ContentOffsets offsets =
  1874. scrolledFrame->GetContentOffsetsFromPoint(desiredPoint);
  1875. if (!offsets.content)
  1876. return;
  1877. // scroll one page
  1878. aScrollableFrame->ScrollBy(nsIntPoint(0, aForward ? 1 : -1),
  1879. nsIScrollableFrame::PAGES,
  1880. nsIScrollableFrame::SMOOTH);
  1881. // place the caret
  1882. HandleClick(offsets.content, offsets.offset,
  1883. offsets.offset, aExtend, false, CARET_ASSOCIATE_AFTER);
  1884. }
  1885. nsresult
  1886. nsFrameSelection::PhysicalMove(int16_t aDirection, int16_t aAmount,
  1887. bool aExtend)
  1888. {
  1889. NS_ENSURE_STATE(mShell);
  1890. // Flush out layout, since we need it to be up to date to do caret
  1891. // positioning.
  1892. mShell->FlushPendingNotifications(Flush_Layout);
  1893. if (!mShell) {
  1894. return NS_OK;
  1895. }
  1896. // Check that parameters are safe
  1897. if (aDirection < 0 || aDirection > 3 || aAmount < 0 || aAmount > 1) {
  1898. return NS_ERROR_FAILURE;
  1899. }
  1900. nsPresContext *context = mShell->GetPresContext();
  1901. if (!context) {
  1902. return NS_ERROR_FAILURE;
  1903. }
  1904. int8_t index = GetIndexFromSelectionType(SelectionType::eNormal);
  1905. RefPtr<Selection> sel = mDomSelections[index];
  1906. if (!sel) {
  1907. return NS_ERROR_NULL_POINTER;
  1908. }
  1909. // Map the abstract movement amounts (0-1) to direction-specific
  1910. // selection units.
  1911. static const nsSelectionAmount inlineAmount[] =
  1912. { eSelectCluster, eSelectWord };
  1913. static const nsSelectionAmount blockPrevAmount[] =
  1914. { eSelectLine, eSelectBeginLine };
  1915. static const nsSelectionAmount blockNextAmount[] =
  1916. { eSelectLine, eSelectEndLine };
  1917. struct PhysicalToLogicalMapping {
  1918. nsDirection direction;
  1919. const nsSelectionAmount *amounts;
  1920. };
  1921. static const PhysicalToLogicalMapping verticalLR[4] = {
  1922. { eDirPrevious, blockPrevAmount }, // left
  1923. { eDirNext, blockNextAmount }, // right
  1924. { eDirPrevious, inlineAmount }, // up
  1925. { eDirNext, inlineAmount } // down
  1926. };
  1927. static const PhysicalToLogicalMapping verticalRL[4] = {
  1928. { eDirNext, blockNextAmount },
  1929. { eDirPrevious, blockPrevAmount },
  1930. { eDirPrevious, inlineAmount },
  1931. { eDirNext, inlineAmount }
  1932. };
  1933. static const PhysicalToLogicalMapping horizontal[4] = {
  1934. { eDirPrevious, inlineAmount },
  1935. { eDirNext, inlineAmount },
  1936. { eDirPrevious, blockPrevAmount },
  1937. { eDirNext, blockNextAmount }
  1938. };
  1939. WritingMode wm;
  1940. nsIFrame *frame = nullptr;
  1941. int32_t offsetused = 0;
  1942. if (NS_SUCCEEDED(sel->GetPrimaryFrameForFocusNode(&frame, &offsetused,
  1943. true))) {
  1944. if (frame) {
  1945. if (!frame->StyleContext()->IsTextCombined()) {
  1946. wm = frame->GetWritingMode();
  1947. } else {
  1948. // Using different direction for horizontal-in-vertical would
  1949. // make it hard to navigate via keyboard. Inherit the moving
  1950. // direction from its parent.
  1951. MOZ_ASSERT(frame->GetType() == nsGkAtoms::textFrame);
  1952. wm = frame->GetParent()->GetWritingMode();
  1953. MOZ_ASSERT(wm.IsVertical(), "Text combined "
  1954. "can only appear in vertical text");
  1955. }
  1956. }
  1957. }
  1958. const PhysicalToLogicalMapping& mapping =
  1959. wm.IsVertical()
  1960. ? wm.IsVerticalLR() ? verticalLR[aDirection] : verticalRL[aDirection]
  1961. : horizontal[aDirection];
  1962. nsresult rv = MoveCaret(mapping.direction, aExtend, mapping.amounts[aAmount],
  1963. eVisual);
  1964. if (NS_FAILED(rv)) {
  1965. // If we tried to do a line move, but couldn't move in the given direction,
  1966. // then we'll "promote" this to a line-edge move instead.
  1967. if (mapping.amounts[aAmount] == eSelectLine) {
  1968. rv = MoveCaret(mapping.direction, aExtend, mapping.amounts[aAmount + 1],
  1969. eVisual);
  1970. }
  1971. // And if it was a next-word move that failed (which can happen when
  1972. // eat_space_to_next_word is true, see bug 1153237), then just move forward
  1973. // to the line-edge.
  1974. else if (mapping.amounts[aAmount] == eSelectWord &&
  1975. mapping.direction == eDirNext) {
  1976. rv = MoveCaret(eDirNext, aExtend, eSelectEndLine, eVisual);
  1977. }
  1978. }
  1979. return rv;
  1980. }
  1981. nsresult
  1982. nsFrameSelection::CharacterMove(bool aForward, bool aExtend)
  1983. {
  1984. return MoveCaret(aForward ? eDirNext : eDirPrevious, aExtend, eSelectCluster,
  1985. eUsePrefStyle);
  1986. }
  1987. nsresult
  1988. nsFrameSelection::CharacterExtendForDelete()
  1989. {
  1990. return MoveCaret(eDirNext, true, eSelectCluster, eLogical);
  1991. }
  1992. nsresult
  1993. nsFrameSelection::CharacterExtendForBackspace()
  1994. {
  1995. return MoveCaret(eDirPrevious, true, eSelectCharacter, eLogical);
  1996. }
  1997. nsresult
  1998. nsFrameSelection::WordMove(bool aForward, bool aExtend)
  1999. {
  2000. return MoveCaret(aForward ? eDirNext : eDirPrevious, aExtend, eSelectWord,
  2001. eUsePrefStyle);
  2002. }
  2003. nsresult
  2004. nsFrameSelection::WordExtendForDelete(bool aForward)
  2005. {
  2006. return MoveCaret(aForward ? eDirNext : eDirPrevious, true, eSelectWord,
  2007. eLogical);
  2008. }
  2009. nsresult
  2010. nsFrameSelection::LineMove(bool aForward, bool aExtend)
  2011. {
  2012. return MoveCaret(aForward ? eDirNext : eDirPrevious, aExtend, eSelectLine,
  2013. eUsePrefStyle);
  2014. }
  2015. nsresult
  2016. nsFrameSelection::IntraLineMove(bool aForward, bool aExtend)
  2017. {
  2018. if (aForward) {
  2019. return MoveCaret(eDirNext, aExtend, eSelectEndLine, eLogical);
  2020. } else {
  2021. return MoveCaret(eDirPrevious, aExtend, eSelectBeginLine, eLogical);
  2022. }
  2023. }
  2024. nsresult
  2025. nsFrameSelection::SelectAll()
  2026. {
  2027. nsCOMPtr<nsIContent> rootContent;
  2028. if (mLimiter)
  2029. {
  2030. rootContent = mLimiter;//addrefit
  2031. }
  2032. else if (mAncestorLimiter) {
  2033. rootContent = mAncestorLimiter;
  2034. }
  2035. else
  2036. {
  2037. NS_ENSURE_STATE(mShell);
  2038. nsIDocument *doc = mShell->GetDocument();
  2039. if (!doc)
  2040. return NS_ERROR_FAILURE;
  2041. rootContent = doc->GetRootElement();
  2042. if (!rootContent)
  2043. return NS_ERROR_FAILURE;
  2044. }
  2045. int32_t numChildren = rootContent->GetChildCount();
  2046. PostReason(nsISelectionListener::NO_REASON);
  2047. int8_t index = GetIndexFromSelectionType(SelectionType::eNormal);
  2048. AutoPrepareFocusRange prep(mDomSelections[index], false, false);
  2049. return TakeFocus(rootContent, 0, numChildren, CARET_ASSOCIATE_BEFORE, false, false);
  2050. }
  2051. //////////END FRAMESELECTION
  2052. void
  2053. nsFrameSelection::StartBatchChanges()
  2054. {
  2055. mBatching++;
  2056. }
  2057. void
  2058. nsFrameSelection::EndBatchChanges(int16_t aReason)
  2059. {
  2060. mBatching--;
  2061. NS_ASSERTION(mBatching >=0,"Bad mBatching");
  2062. if (mBatching == 0 && mChangesDuringBatching) {
  2063. int16_t postReason = PopReason() | aReason;
  2064. PostReason(postReason);
  2065. mChangesDuringBatching = false;
  2066. NotifySelectionListeners(SelectionType::eNormal);
  2067. }
  2068. }
  2069. nsresult
  2070. nsFrameSelection::NotifySelectionListeners(SelectionType aSelectionType)
  2071. {
  2072. int8_t index = GetIndexFromSelectionType(aSelectionType);
  2073. if (index >=0 && mDomSelections[index])
  2074. {
  2075. return mDomSelections[index]->NotifySelectionListeners();
  2076. }
  2077. return NS_ERROR_FAILURE;
  2078. }
  2079. // Start of Table Selection methods
  2080. static bool IsCell(nsIContent *aContent)
  2081. {
  2082. return aContent->IsAnyOfHTMLElements(nsGkAtoms::td, nsGkAtoms::th);
  2083. }
  2084. nsITableCellLayout*
  2085. nsFrameSelection::GetCellLayout(nsIContent *aCellContent) const
  2086. {
  2087. NS_ENSURE_TRUE(mShell, nullptr);
  2088. nsITableCellLayout *cellLayoutObject =
  2089. do_QueryFrame(aCellContent->GetPrimaryFrame());
  2090. return cellLayoutObject;
  2091. }
  2092. nsresult
  2093. nsFrameSelection::ClearNormalSelection()
  2094. {
  2095. int8_t index = GetIndexFromSelectionType(SelectionType::eNormal);
  2096. if (!mDomSelections[index])
  2097. return NS_ERROR_NULL_POINTER;
  2098. return mDomSelections[index]->RemoveAllRanges();
  2099. }
  2100. static nsIContent*
  2101. GetFirstSelectedContent(nsRange* aRange)
  2102. {
  2103. if (!aRange) {
  2104. return nullptr;
  2105. }
  2106. NS_PRECONDITION(aRange->GetStartParent(), "Must have start parent!");
  2107. NS_PRECONDITION(aRange->GetStartParent()->IsElement(),
  2108. "Unexpected parent");
  2109. return aRange->GetStartParent()->GetChildAt(aRange->StartOffset());
  2110. }
  2111. // Table selection support.
  2112. // TODO: Separate table methods into a separate nsITableSelection interface
  2113. nsresult
  2114. nsFrameSelection::HandleTableSelection(nsINode* aParentContent,
  2115. int32_t aContentOffset,
  2116. int32_t aTarget,
  2117. WidgetMouseEvent* aMouseEvent)
  2118. {
  2119. NS_ENSURE_TRUE(aParentContent, NS_ERROR_NULL_POINTER);
  2120. NS_ENSURE_TRUE(aMouseEvent, NS_ERROR_NULL_POINTER);
  2121. if (mDragState && mDragSelectingCells && (aTarget & nsISelectionPrivate::TABLESELECTION_TABLE))
  2122. {
  2123. // We were selecting cells and user drags mouse in table border or inbetween cells,
  2124. // just do nothing
  2125. return NS_OK;
  2126. }
  2127. nsresult result = NS_OK;
  2128. nsIContent *childContent = aParentContent->GetChildAt(aContentOffset);
  2129. // When doing table selection, always set the direction to next so
  2130. // we can be sure that anchorNode's offset always points to the
  2131. // selected cell
  2132. int8_t index = GetIndexFromSelectionType(SelectionType::eNormal);
  2133. if (!mDomSelections[index])
  2134. return NS_ERROR_NULL_POINTER;
  2135. mDomSelections[index]->SetDirection(eDirNext);
  2136. // Stack-class to wrap all table selection changes in
  2137. // BeginBatchChanges() / EndBatchChanges()
  2138. SelectionBatcher selectionBatcher(mDomSelections[index]);
  2139. int32_t startRowIndex, startColIndex, curRowIndex, curColIndex;
  2140. if (mDragState && mDragSelectingCells)
  2141. {
  2142. // We are drag-selecting
  2143. if (aTarget != nsISelectionPrivate::TABLESELECTION_TABLE)
  2144. {
  2145. // If dragging in the same cell as last event, do nothing
  2146. if (mEndSelectedCell == childContent)
  2147. return NS_OK;
  2148. #ifdef DEBUG_TABLE_SELECTION
  2149. printf(" mStartSelectedCell = %p, mEndSelectedCell = %p, childContent = %p \n",
  2150. mStartSelectedCell.get(), mEndSelectedCell.get(), childContent);
  2151. #endif
  2152. // aTarget can be any "cell mode",
  2153. // so we can easily drag-select rows and columns
  2154. // Once we are in row or column mode,
  2155. // we can drift into any cell to stay in that mode
  2156. // even if aTarget = TABLESELECTION_CELL
  2157. if (mSelectingTableCellMode == nsISelectionPrivate::TABLESELECTION_ROW ||
  2158. mSelectingTableCellMode == nsISelectionPrivate::TABLESELECTION_COLUMN)
  2159. {
  2160. if (mEndSelectedCell)
  2161. {
  2162. // Also check if cell is in same row/col
  2163. result = GetCellIndexes(mEndSelectedCell, startRowIndex, startColIndex);
  2164. if (NS_FAILED(result)) return result;
  2165. result = GetCellIndexes(childContent, curRowIndex, curColIndex);
  2166. if (NS_FAILED(result)) return result;
  2167. #ifdef DEBUG_TABLE_SELECTION
  2168. printf(" curRowIndex = %d, startRowIndex = %d, curColIndex = %d, startColIndex = %d\n", curRowIndex, startRowIndex, curColIndex, startColIndex);
  2169. #endif
  2170. if ((mSelectingTableCellMode == nsISelectionPrivate::TABLESELECTION_ROW && startRowIndex == curRowIndex) ||
  2171. (mSelectingTableCellMode == nsISelectionPrivate::TABLESELECTION_COLUMN && startColIndex == curColIndex))
  2172. return NS_OK;
  2173. }
  2174. #ifdef DEBUG_TABLE_SELECTION
  2175. printf(" Dragged into a new column or row\n");
  2176. #endif
  2177. // Continue dragging row or column selection
  2178. return SelectRowOrColumn(childContent, mSelectingTableCellMode);
  2179. }
  2180. else if (mSelectingTableCellMode == nsISelectionPrivate::TABLESELECTION_CELL)
  2181. {
  2182. #ifdef DEBUG_TABLE_SELECTION
  2183. printf("HandleTableSelection: Dragged into a new cell\n");
  2184. #endif
  2185. // Trick for quick selection of rows and columns
  2186. // Hold down shift, then start selecting in one direction
  2187. // If next cell dragged into is in same row, select entire row,
  2188. // if next cell is in same column, select entire column
  2189. if (mStartSelectedCell && aMouseEvent->IsShift())
  2190. {
  2191. result = GetCellIndexes(mStartSelectedCell, startRowIndex, startColIndex);
  2192. if (NS_FAILED(result)) return result;
  2193. result = GetCellIndexes(childContent, curRowIndex, curColIndex);
  2194. if (NS_FAILED(result)) return result;
  2195. if (startRowIndex == curRowIndex ||
  2196. startColIndex == curColIndex)
  2197. {
  2198. // Force new selection block
  2199. mStartSelectedCell = nullptr;
  2200. mDomSelections[index]->RemoveAllRanges();
  2201. if (startRowIndex == curRowIndex)
  2202. mSelectingTableCellMode = nsISelectionPrivate::TABLESELECTION_ROW;
  2203. else
  2204. mSelectingTableCellMode = nsISelectionPrivate::TABLESELECTION_COLUMN;
  2205. return SelectRowOrColumn(childContent, mSelectingTableCellMode);
  2206. }
  2207. }
  2208. // Reselect block of cells to new end location
  2209. return SelectBlockOfCells(mStartSelectedCell, childContent);
  2210. }
  2211. }
  2212. // Do nothing if dragging in table, but outside a cell
  2213. return NS_OK;
  2214. }
  2215. else
  2216. {
  2217. // Not dragging -- mouse event is down or up
  2218. if (mDragState)
  2219. {
  2220. #ifdef DEBUG_TABLE_SELECTION
  2221. printf("HandleTableSelection: Mouse down event\n");
  2222. #endif
  2223. // Clear cell we stored in mouse-down
  2224. mUnselectCellOnMouseUp = nullptr;
  2225. if (aTarget == nsISelectionPrivate::TABLESELECTION_CELL)
  2226. {
  2227. bool isSelected = false;
  2228. // Check if we have other selected cells
  2229. nsIContent* previousCellNode =
  2230. GetFirstSelectedContent(GetFirstCellRange());
  2231. if (previousCellNode)
  2232. {
  2233. // We have at least 1 other selected cell
  2234. // Check if new cell is already selected
  2235. nsIFrame *cellFrame = childContent->GetPrimaryFrame();
  2236. if (!cellFrame) return NS_ERROR_NULL_POINTER;
  2237. isSelected = cellFrame->IsSelected();
  2238. }
  2239. else
  2240. {
  2241. // No cells selected -- remove non-cell selection
  2242. mDomSelections[index]->RemoveAllRanges();
  2243. }
  2244. mDragSelectingCells = true; // Signal to start drag-cell-selection
  2245. mSelectingTableCellMode = aTarget;
  2246. // Set start for new drag-selection block (not appended)
  2247. mStartSelectedCell = childContent;
  2248. // The initial block end is same as the start
  2249. mEndSelectedCell = childContent;
  2250. if (isSelected)
  2251. {
  2252. // Remember this cell to (possibly) unselect it on mouseup
  2253. mUnselectCellOnMouseUp = childContent;
  2254. #ifdef DEBUG_TABLE_SELECTION
  2255. printf("HandleTableSelection: Saving mUnselectCellOnMouseUp\n");
  2256. #endif
  2257. }
  2258. else
  2259. {
  2260. // Select an unselected cell
  2261. // but first remove existing selection if not in same table
  2262. if (previousCellNode &&
  2263. !IsInSameTable(previousCellNode, childContent))
  2264. {
  2265. mDomSelections[index]->RemoveAllRanges();
  2266. // Reset selection mode that is cleared in RemoveAllRanges
  2267. mSelectingTableCellMode = aTarget;
  2268. }
  2269. return SelectCellElement(childContent);
  2270. }
  2271. return NS_OK;
  2272. }
  2273. else if (aTarget == nsISelectionPrivate::TABLESELECTION_TABLE)
  2274. {
  2275. //TODO: We currently select entire table when clicked between cells,
  2276. // should we restrict to only around border?
  2277. // *** How do we get location data for cell and click?
  2278. mDragSelectingCells = false;
  2279. mStartSelectedCell = nullptr;
  2280. mEndSelectedCell = nullptr;
  2281. // Remove existing selection and select the table
  2282. mDomSelections[index]->RemoveAllRanges();
  2283. return CreateAndAddRange(aParentContent, aContentOffset);
  2284. }
  2285. else if (aTarget == nsISelectionPrivate::TABLESELECTION_ROW || aTarget == nsISelectionPrivate::TABLESELECTION_COLUMN)
  2286. {
  2287. #ifdef DEBUG_TABLE_SELECTION
  2288. printf("aTarget == %d\n", aTarget);
  2289. #endif
  2290. // Start drag-selecting mode so multiple rows/cols can be selected
  2291. // Note: Currently, nsFrame::GetDataForTableSelection
  2292. // will never call us for row or column selection on mouse down
  2293. mDragSelectingCells = true;
  2294. // Force new selection block
  2295. mStartSelectedCell = nullptr;
  2296. mDomSelections[index]->RemoveAllRanges();
  2297. // Always do this AFTER RemoveAllRanges
  2298. mSelectingTableCellMode = aTarget;
  2299. return SelectRowOrColumn(childContent, aTarget);
  2300. }
  2301. }
  2302. else
  2303. {
  2304. #ifdef DEBUG_TABLE_SELECTION
  2305. printf("HandleTableSelection: Mouse UP event. mDragSelectingCells=%d, mStartSelectedCell=%p\n",
  2306. mDragSelectingCells, mStartSelectedCell.get());
  2307. #endif
  2308. // First check if we are extending a block selection
  2309. int32_t rangeCount;
  2310. result = mDomSelections[index]->GetRangeCount(&rangeCount);
  2311. if (NS_FAILED(result))
  2312. return result;
  2313. if (rangeCount > 0 && aMouseEvent->IsShift() &&
  2314. mAppendStartSelectedCell && mAppendStartSelectedCell != childContent)
  2315. {
  2316. // Shift key is down: append a block selection
  2317. mDragSelectingCells = false;
  2318. return SelectBlockOfCells(mAppendStartSelectedCell, childContent);
  2319. }
  2320. if (mDragSelectingCells)
  2321. mAppendStartSelectedCell = mStartSelectedCell;
  2322. mDragSelectingCells = false;
  2323. mStartSelectedCell = nullptr;
  2324. mEndSelectedCell = nullptr;
  2325. // Any other mouseup actions require that Ctrl or Cmd key is pressed
  2326. // else stop table selection mode
  2327. bool doMouseUpAction = false;
  2328. doMouseUpAction = aMouseEvent->IsControl();
  2329. if (!doMouseUpAction)
  2330. {
  2331. #ifdef DEBUG_TABLE_SELECTION
  2332. printf("HandleTableSelection: Ending cell selection on mouseup: mAppendStartSelectedCell=%p\n",
  2333. mAppendStartSelectedCell.get());
  2334. #endif
  2335. return NS_OK;
  2336. }
  2337. // Unselect a cell only if it wasn't
  2338. // just selected on mousedown
  2339. if( childContent == mUnselectCellOnMouseUp)
  2340. {
  2341. // Scan ranges to find the cell to unselect (the selection range to remove)
  2342. // XXXbz it's really weird that this lives outside the loop, so once we
  2343. // find one we keep looking at it even if we find no more cells...
  2344. nsINode* previousCellParent = nullptr;
  2345. #ifdef DEBUG_TABLE_SELECTION
  2346. printf("HandleTableSelection: Unselecting mUnselectCellOnMouseUp; rangeCount=%d\n", rangeCount);
  2347. #endif
  2348. for( int32_t i = 0; i < rangeCount; i++)
  2349. {
  2350. // Strong reference, because sometimes we want to remove
  2351. // this range, and then we might be the only owner.
  2352. RefPtr<nsRange> range = mDomSelections[index]->GetRangeAt(i);
  2353. if (!range) return NS_ERROR_NULL_POINTER;
  2354. nsINode* parent = range->GetStartParent();
  2355. if (!parent) return NS_ERROR_NULL_POINTER;
  2356. int32_t offset = range->StartOffset();
  2357. // Be sure previous selection is a table cell
  2358. nsIContent* child = parent->GetChildAt(offset);
  2359. if (child && IsCell(child))
  2360. previousCellParent = parent;
  2361. // We're done if we didn't find parent of a previously-selected cell
  2362. if (!previousCellParent) break;
  2363. if (previousCellParent == aParentContent && offset == aContentOffset)
  2364. {
  2365. // Cell is already selected
  2366. if (rangeCount == 1)
  2367. {
  2368. #ifdef DEBUG_TABLE_SELECTION
  2369. printf("HandleTableSelection: Unselecting single selected cell\n");
  2370. #endif
  2371. // This was the only cell selected.
  2372. // Collapse to "normal" selection inside the cell
  2373. mStartSelectedCell = nullptr;
  2374. mEndSelectedCell = nullptr;
  2375. mAppendStartSelectedCell = nullptr;
  2376. //TODO: We need a "Collapse to just before deepest child" routine
  2377. // Even better, should we collapse to just after the LAST deepest child
  2378. // (i.e., at the end of the cell's contents)?
  2379. return mDomSelections[index]->Collapse(childContent, 0);
  2380. }
  2381. #ifdef DEBUG_TABLE_SELECTION
  2382. printf("HandleTableSelection: Removing cell from multi-cell selection\n");
  2383. #endif
  2384. // Unselecting the start of previous block
  2385. // XXX What do we use now!
  2386. if (childContent == mAppendStartSelectedCell)
  2387. mAppendStartSelectedCell = nullptr;
  2388. // Deselect cell by removing its range from selection
  2389. return mDomSelections[index]->RemoveRange(range);
  2390. }
  2391. }
  2392. mUnselectCellOnMouseUp = nullptr;
  2393. }
  2394. }
  2395. }
  2396. return result;
  2397. }
  2398. nsresult
  2399. nsFrameSelection::SelectBlockOfCells(nsIContent *aStartCell, nsIContent *aEndCell)
  2400. {
  2401. NS_ENSURE_TRUE(aStartCell, NS_ERROR_NULL_POINTER);
  2402. NS_ENSURE_TRUE(aEndCell, NS_ERROR_NULL_POINTER);
  2403. mEndSelectedCell = aEndCell;
  2404. nsresult result = NS_OK;
  2405. // If new end cell is in a different table, do nothing
  2406. nsIContent* table = IsInSameTable(aStartCell, aEndCell);
  2407. if (!table) {
  2408. return NS_OK;
  2409. }
  2410. // Get starting and ending cells' location in the cellmap
  2411. int32_t startRowIndex, startColIndex, endRowIndex, endColIndex;
  2412. result = GetCellIndexes(aStartCell, startRowIndex, startColIndex);
  2413. if(NS_FAILED(result)) return result;
  2414. result = GetCellIndexes(aEndCell, endRowIndex, endColIndex);
  2415. if(NS_FAILED(result)) return result;
  2416. if (mDragSelectingCells)
  2417. {
  2418. // Drag selecting: remove selected cells outside of new block limits
  2419. UnselectCells(table, startRowIndex, startColIndex, endRowIndex, endColIndex,
  2420. true);
  2421. }
  2422. // Note that we select block in the direction of user's mouse dragging,
  2423. // which means start cell may be after the end cell in either row or column
  2424. return AddCellsToSelection(table, startRowIndex, startColIndex,
  2425. endRowIndex, endColIndex);
  2426. }
  2427. nsresult
  2428. nsFrameSelection::UnselectCells(nsIContent *aTableContent,
  2429. int32_t aStartRowIndex,
  2430. int32_t aStartColumnIndex,
  2431. int32_t aEndRowIndex,
  2432. int32_t aEndColumnIndex,
  2433. bool aRemoveOutsideOfCellRange)
  2434. {
  2435. int8_t index = GetIndexFromSelectionType(SelectionType::eNormal);
  2436. if (!mDomSelections[index])
  2437. return NS_ERROR_NULL_POINTER;
  2438. nsTableWrapperFrame* tableFrame = do_QueryFrame(aTableContent->GetPrimaryFrame());
  2439. if (!tableFrame)
  2440. return NS_ERROR_FAILURE;
  2441. int32_t minRowIndex = std::min(aStartRowIndex, aEndRowIndex);
  2442. int32_t maxRowIndex = std::max(aStartRowIndex, aEndRowIndex);
  2443. int32_t minColIndex = std::min(aStartColumnIndex, aEndColumnIndex);
  2444. int32_t maxColIndex = std::max(aStartColumnIndex, aEndColumnIndex);
  2445. // Strong reference because we sometimes remove the range
  2446. RefPtr<nsRange> range = GetFirstCellRange();
  2447. nsIContent* cellNode = GetFirstSelectedContent(range);
  2448. NS_PRECONDITION(!range || cellNode, "Must have cellNode if had a range");
  2449. int32_t curRowIndex, curColIndex;
  2450. while (cellNode)
  2451. {
  2452. nsresult result = GetCellIndexes(cellNode, curRowIndex, curColIndex);
  2453. if (NS_FAILED(result))
  2454. return result;
  2455. #ifdef DEBUG_TABLE_SELECTION
  2456. if (!range)
  2457. printf("RemoveCellsToSelection -- range is null\n");
  2458. #endif
  2459. if (range) {
  2460. if (aRemoveOutsideOfCellRange) {
  2461. if (curRowIndex < minRowIndex || curRowIndex > maxRowIndex ||
  2462. curColIndex < minColIndex || curColIndex > maxColIndex) {
  2463. mDomSelections[index]->RemoveRange(range);
  2464. // Since we've removed the range, decrement pointer to next range
  2465. mSelectedCellIndex--;
  2466. }
  2467. } else {
  2468. // Remove cell from selection if it belongs to the given cells range or
  2469. // it is spanned onto the cells range.
  2470. nsTableCellFrame* cellFrame =
  2471. tableFrame->GetCellFrameAt(curRowIndex, curColIndex);
  2472. uint32_t origRowIndex = cellFrame->RowIndex();
  2473. uint32_t origColIndex = cellFrame->ColIndex();
  2474. uint32_t actualRowSpan =
  2475. tableFrame->GetEffectiveRowSpanAt(origRowIndex, origColIndex);
  2476. uint32_t actualColSpan =
  2477. tableFrame->GetEffectiveColSpanAt(curRowIndex, curColIndex);
  2478. if (origRowIndex <= static_cast<uint32_t>(maxRowIndex) && maxRowIndex >= 0 &&
  2479. origRowIndex + actualRowSpan - 1 >= static_cast<uint32_t>(minRowIndex) &&
  2480. origColIndex <= static_cast<uint32_t>(maxColIndex) && maxColIndex >= 0 &&
  2481. origColIndex + actualColSpan - 1 >= static_cast<uint32_t>(minColIndex)) {
  2482. mDomSelections[index]->RemoveRange(range);
  2483. // Since we've removed the range, decrement pointer to next range
  2484. mSelectedCellIndex--;
  2485. }
  2486. }
  2487. }
  2488. range = GetNextCellRange();
  2489. cellNode = GetFirstSelectedContent(range);
  2490. NS_PRECONDITION(!range || cellNode, "Must have cellNode if had a range");
  2491. }
  2492. return NS_OK;
  2493. }
  2494. nsresult
  2495. nsFrameSelection::AddCellsToSelection(nsIContent *aTableContent,
  2496. int32_t aStartRowIndex,
  2497. int32_t aStartColumnIndex,
  2498. int32_t aEndRowIndex,
  2499. int32_t aEndColumnIndex)
  2500. {
  2501. int8_t index = GetIndexFromSelectionType(SelectionType::eNormal);
  2502. if (!mDomSelections[index])
  2503. return NS_ERROR_NULL_POINTER;
  2504. nsTableWrapperFrame* tableFrame = do_QueryFrame(aTableContent->GetPrimaryFrame());
  2505. if (!tableFrame) // Check that |table| is a table.
  2506. return NS_ERROR_FAILURE;
  2507. nsresult result = NS_OK;
  2508. uint32_t row = aStartRowIndex;
  2509. while(true)
  2510. {
  2511. uint32_t col = aStartColumnIndex;
  2512. while(true)
  2513. {
  2514. nsTableCellFrame* cellFrame = tableFrame->GetCellFrameAt(row, col);
  2515. // Skip cells that are spanned from previous locations or are already selected
  2516. if (cellFrame) {
  2517. uint32_t origRow = cellFrame->RowIndex();
  2518. uint32_t origCol = cellFrame->ColIndex();
  2519. if (origRow == row && origCol == col && !cellFrame->IsSelected()) {
  2520. result = SelectCellElement(cellFrame->GetContent());
  2521. if (NS_FAILED(result)) return result;
  2522. }
  2523. }
  2524. // Done when we reach end column
  2525. if (col == static_cast<uint32_t>(aEndColumnIndex)) break;
  2526. if (aStartColumnIndex < aEndColumnIndex)
  2527. col ++;
  2528. else
  2529. col--;
  2530. }
  2531. if (row == static_cast<uint32_t>(aEndRowIndex)) break;
  2532. if (aStartRowIndex < aEndRowIndex)
  2533. row++;
  2534. else
  2535. row--;
  2536. }
  2537. return result;
  2538. }
  2539. nsresult
  2540. nsFrameSelection::RemoveCellsFromSelection(nsIContent *aTable,
  2541. int32_t aStartRowIndex,
  2542. int32_t aStartColumnIndex,
  2543. int32_t aEndRowIndex,
  2544. int32_t aEndColumnIndex)
  2545. {
  2546. return UnselectCells(aTable, aStartRowIndex, aStartColumnIndex,
  2547. aEndRowIndex, aEndColumnIndex, false);
  2548. }
  2549. nsresult
  2550. nsFrameSelection::RestrictCellsToSelection(nsIContent *aTable,
  2551. int32_t aStartRowIndex,
  2552. int32_t aStartColumnIndex,
  2553. int32_t aEndRowIndex,
  2554. int32_t aEndColumnIndex)
  2555. {
  2556. return UnselectCells(aTable, aStartRowIndex, aStartColumnIndex,
  2557. aEndRowIndex, aEndColumnIndex, true);
  2558. }
  2559. nsresult
  2560. nsFrameSelection::SelectRowOrColumn(nsIContent *aCellContent, uint32_t aTarget)
  2561. {
  2562. if (!aCellContent) return NS_ERROR_NULL_POINTER;
  2563. nsIContent* table = GetParentTable(aCellContent);
  2564. if (!table) return NS_ERROR_NULL_POINTER;
  2565. // Get table and cell layout interfaces to access
  2566. // cell data based on cellmap location
  2567. // Frames are not ref counted, so don't use an nsCOMPtr
  2568. nsTableWrapperFrame* tableFrame = do_QueryFrame(table->GetPrimaryFrame());
  2569. if (!tableFrame) return NS_ERROR_FAILURE;
  2570. nsITableCellLayout *cellLayout = GetCellLayout(aCellContent);
  2571. if (!cellLayout) return NS_ERROR_FAILURE;
  2572. // Get location of target cell:
  2573. int32_t rowIndex, colIndex;
  2574. nsresult result = cellLayout->GetCellIndexes(rowIndex, colIndex);
  2575. if (NS_FAILED(result)) return result;
  2576. // Be sure we start at proper beginning
  2577. // (This allows us to select row or col given ANY cell!)
  2578. if (aTarget == nsISelectionPrivate::TABLESELECTION_ROW)
  2579. colIndex = 0;
  2580. if (aTarget == nsISelectionPrivate::TABLESELECTION_COLUMN)
  2581. rowIndex = 0;
  2582. nsCOMPtr<nsIContent> firstCell, lastCell;
  2583. while (true) {
  2584. // Loop through all cells in column or row to find first and last
  2585. nsCOMPtr<nsIContent> curCellContent =
  2586. tableFrame->GetCellAt(rowIndex, colIndex);
  2587. if (!curCellContent)
  2588. break;
  2589. if (!firstCell)
  2590. firstCell = curCellContent;
  2591. lastCell = curCellContent.forget();
  2592. // Move to next cell in cellmap, skipping spanned locations
  2593. if (aTarget == nsISelectionPrivate::TABLESELECTION_ROW)
  2594. colIndex += tableFrame->GetEffectiveRowSpanAt(rowIndex, colIndex);
  2595. else
  2596. rowIndex += tableFrame->GetEffectiveRowSpanAt(rowIndex, colIndex);
  2597. }
  2598. // Use SelectBlockOfCells:
  2599. // This will replace existing selection,
  2600. // but allow unselecting by dragging out of selected region
  2601. if (firstCell && lastCell)
  2602. {
  2603. if (!mStartSelectedCell)
  2604. {
  2605. // We are starting a new block, so select the first cell
  2606. result = SelectCellElement(firstCell);
  2607. if (NS_FAILED(result)) return result;
  2608. mStartSelectedCell = firstCell;
  2609. }
  2610. nsCOMPtr<nsIContent> lastCellContent = do_QueryInterface(lastCell);
  2611. result = SelectBlockOfCells(mStartSelectedCell, lastCellContent);
  2612. // This gets set to the cell at end of row/col,
  2613. // but we need it to be the cell under cursor
  2614. mEndSelectedCell = aCellContent;
  2615. return result;
  2616. }
  2617. #if 0
  2618. // This is a more efficient strategy that appends row to current selection,
  2619. // but doesn't allow dragging OFF of an existing selection to unselect!
  2620. do {
  2621. // Loop through all cells in column or row
  2622. result = tableLayout->GetCellDataAt(rowIndex, colIndex,
  2623. getter_AddRefs(cellElement),
  2624. curRowIndex, curColIndex,
  2625. rowSpan, colSpan,
  2626. actualRowSpan, actualColSpan,
  2627. isSelected);
  2628. if (NS_FAILED(result)) return result;
  2629. // We're done when cell is not found
  2630. if (!cellElement) break;
  2631. // Check spans else we infinitely loop
  2632. NS_ASSERTION(actualColSpan, "actualColSpan is 0!");
  2633. NS_ASSERTION(actualRowSpan, "actualRowSpan is 0!");
  2634. // Skip cells that are already selected or span from outside our region
  2635. if (!isSelected && rowIndex == curRowIndex && colIndex == curColIndex)
  2636. {
  2637. result = SelectCellElement(cellElement);
  2638. if (NS_FAILED(result)) return result;
  2639. }
  2640. // Move to next row or column in cellmap, skipping spanned locations
  2641. if (aTarget == nsISelectionPrivate::TABLESELECTION_ROW)
  2642. colIndex += actualColSpan;
  2643. else
  2644. rowIndex += actualRowSpan;
  2645. }
  2646. while (cellElement);
  2647. #endif
  2648. return NS_OK;
  2649. }
  2650. nsIContent*
  2651. nsFrameSelection::GetFirstCellNodeInRange(nsRange *aRange) const
  2652. {
  2653. if (!aRange) return nullptr;
  2654. nsINode* startParent = aRange->GetStartParent();
  2655. if (!startParent)
  2656. return nullptr;
  2657. int32_t offset = aRange->StartOffset();
  2658. nsIContent* childContent = startParent->GetChildAt(offset);
  2659. if (!childContent)
  2660. return nullptr;
  2661. // Don't return node if not a cell
  2662. if (!IsCell(childContent))
  2663. return nullptr;
  2664. return childContent;
  2665. }
  2666. nsRange*
  2667. nsFrameSelection::GetFirstCellRange()
  2668. {
  2669. int8_t index = GetIndexFromSelectionType(SelectionType::eNormal);
  2670. if (!mDomSelections[index])
  2671. return nullptr;
  2672. nsRange* firstRange = mDomSelections[index]->GetRangeAt(0);
  2673. if (!GetFirstCellNodeInRange(firstRange)) {
  2674. return nullptr;
  2675. }
  2676. // Setup for next cell
  2677. mSelectedCellIndex = 1;
  2678. return firstRange;
  2679. }
  2680. nsRange*
  2681. nsFrameSelection::GetNextCellRange()
  2682. {
  2683. int8_t index = GetIndexFromSelectionType(SelectionType::eNormal);
  2684. if (!mDomSelections[index])
  2685. return nullptr;
  2686. nsRange* range = mDomSelections[index]->GetRangeAt(mSelectedCellIndex);
  2687. // Get first node in next range of selection - test if it's a cell
  2688. if (!GetFirstCellNodeInRange(range)) {
  2689. return nullptr;
  2690. }
  2691. // Setup for next cell
  2692. mSelectedCellIndex++;
  2693. return range;
  2694. }
  2695. nsresult
  2696. nsFrameSelection::GetCellIndexes(nsIContent *aCell,
  2697. int32_t &aRowIndex,
  2698. int32_t &aColIndex)
  2699. {
  2700. if (!aCell) return NS_ERROR_NULL_POINTER;
  2701. aColIndex=0; // initialize out params
  2702. aRowIndex=0;
  2703. nsITableCellLayout *cellLayoutObject = GetCellLayout(aCell);
  2704. if (!cellLayoutObject) return NS_ERROR_FAILURE;
  2705. return cellLayoutObject->GetCellIndexes(aRowIndex, aColIndex);
  2706. }
  2707. nsIContent*
  2708. nsFrameSelection::IsInSameTable(nsIContent *aContent1,
  2709. nsIContent *aContent2) const
  2710. {
  2711. if (!aContent1 || !aContent2) return nullptr;
  2712. nsIContent* tableNode1 = GetParentTable(aContent1);
  2713. nsIContent* tableNode2 = GetParentTable(aContent2);
  2714. // Must be in the same table. Note that we want to return false for
  2715. // the test if both tables are null.
  2716. return (tableNode1 == tableNode2) ? tableNode1 : nullptr;
  2717. }
  2718. nsIContent*
  2719. nsFrameSelection::GetParentTable(nsIContent *aCell) const
  2720. {
  2721. if (!aCell) {
  2722. return nullptr;
  2723. }
  2724. for (nsIContent* parent = aCell->GetParent(); parent;
  2725. parent = parent->GetParent()) {
  2726. if (parent->IsHTMLElement(nsGkAtoms::table)) {
  2727. return parent;
  2728. }
  2729. }
  2730. return nullptr;
  2731. }
  2732. nsresult
  2733. nsFrameSelection::SelectCellElement(nsIContent *aCellElement)
  2734. {
  2735. nsIContent *parent = aCellElement->GetParent();
  2736. // Get child offset
  2737. int32_t offset = parent->IndexOf(aCellElement);
  2738. return CreateAndAddRange(parent, offset);
  2739. }
  2740. nsresult
  2741. Selection::getTableCellLocationFromRange(nsRange* aRange,
  2742. int32_t* aSelectionType,
  2743. int32_t* aRow, int32_t* aCol)
  2744. {
  2745. if (!aRange || !aSelectionType || !aRow || !aCol)
  2746. return NS_ERROR_NULL_POINTER;
  2747. *aSelectionType = nsISelectionPrivate::TABLESELECTION_NONE;
  2748. *aRow = 0;
  2749. *aCol = 0;
  2750. // Must have access to frame selection to get cell info
  2751. if (!mFrameSelection) return NS_OK;
  2752. nsresult result = GetTableSelectionType(aRange, aSelectionType);
  2753. if (NS_FAILED(result)) return result;
  2754. // Don't fail if range does not point to a single table cell,
  2755. // let aSelectionType tell user if we don't have a cell
  2756. if (*aSelectionType != nsISelectionPrivate::TABLESELECTION_CELL)
  2757. return NS_OK;
  2758. // Get the child content (the cell) pointed to by starting node of range
  2759. // We do minimal checking since GetTableSelectionType assures
  2760. // us that this really is a table cell
  2761. nsCOMPtr<nsIContent> content = do_QueryInterface(aRange->GetStartParent());
  2762. if (!content)
  2763. return NS_ERROR_FAILURE;
  2764. nsIContent *child = content->GetChildAt(aRange->StartOffset());
  2765. if (!child)
  2766. return NS_ERROR_FAILURE;
  2767. //Note: This is a non-ref-counted pointer to the frame
  2768. nsITableCellLayout *cellLayout = mFrameSelection->GetCellLayout(child);
  2769. if (NS_FAILED(result))
  2770. return result;
  2771. if (!cellLayout)
  2772. return NS_ERROR_FAILURE;
  2773. return cellLayout->GetCellIndexes(*aRow, *aCol);
  2774. }
  2775. nsresult
  2776. Selection::addTableCellRange(nsRange* aRange, bool* aDidAddRange,
  2777. int32_t* aOutIndex)
  2778. {
  2779. if (!aDidAddRange || !aOutIndex)
  2780. return NS_ERROR_NULL_POINTER;
  2781. *aDidAddRange = false;
  2782. *aOutIndex = -1;
  2783. if (!mFrameSelection)
  2784. return NS_OK;
  2785. if (!aRange)
  2786. return NS_ERROR_NULL_POINTER;
  2787. nsresult result;
  2788. // Get if we are adding a cell selection and the row, col of cell if we are
  2789. int32_t newRow, newCol, tableMode;
  2790. result = getTableCellLocationFromRange(aRange, &tableMode, &newRow, &newCol);
  2791. if (NS_FAILED(result)) return result;
  2792. // If not adding a cell range, we are done here
  2793. if (tableMode != nsISelectionPrivate::TABLESELECTION_CELL)
  2794. {
  2795. mFrameSelection->mSelectingTableCellMode = tableMode;
  2796. // Don't fail if range isn't a selected cell, aDidAddRange tells caller if we didn't proceed
  2797. return NS_OK;
  2798. }
  2799. // Set frame selection mode only if not already set to a table mode
  2800. // so we don't lose the select row and column flags (not detected by getTableCellLocation)
  2801. if (mFrameSelection->mSelectingTableCellMode == TABLESELECTION_NONE)
  2802. mFrameSelection->mSelectingTableCellMode = tableMode;
  2803. *aDidAddRange = true;
  2804. return AddItem(aRange, aOutIndex);
  2805. }
  2806. //TODO: Figure out TABLESELECTION_COLUMN and TABLESELECTION_ALLCELLS
  2807. nsresult
  2808. Selection::GetTableSelectionType(nsIDOMRange* aDOMRange,
  2809. int32_t* aTableSelectionType)
  2810. {
  2811. if (!aDOMRange || !aTableSelectionType)
  2812. return NS_ERROR_NULL_POINTER;
  2813. nsRange* range = static_cast<nsRange*>(aDOMRange);
  2814. *aTableSelectionType = nsISelectionPrivate::TABLESELECTION_NONE;
  2815. // Must have access to frame selection to get cell info
  2816. if(!mFrameSelection) return NS_OK;
  2817. nsINode* startNode = range->GetStartParent();
  2818. if (!startNode) return NS_ERROR_FAILURE;
  2819. nsINode* endNode = range->GetEndParent();
  2820. if (!endNode) return NS_ERROR_FAILURE;
  2821. // Not a single selected node
  2822. if (startNode != endNode) return NS_OK;
  2823. int32_t startOffset = range->StartOffset();
  2824. int32_t endOffset = range->EndOffset();
  2825. // Not a single selected node
  2826. if ((endOffset - startOffset) != 1)
  2827. return NS_OK;
  2828. nsIContent* startContent = static_cast<nsIContent*>(startNode);
  2829. if (!(startNode->IsElement() && startContent->IsHTMLElement())) {
  2830. // Implies a check for being an element; if we ever make this work
  2831. // for non-HTML, need to keep checking for elements.
  2832. return NS_OK;
  2833. }
  2834. if (startContent->IsHTMLElement(nsGkAtoms::tr))
  2835. {
  2836. *aTableSelectionType = nsISelectionPrivate::TABLESELECTION_CELL;
  2837. }
  2838. else //check to see if we are selecting a table or row (column and all cells not done yet)
  2839. {
  2840. nsIContent *child = startNode->GetChildAt(startOffset);
  2841. if (!child)
  2842. return NS_ERROR_FAILURE;
  2843. if (child->IsHTMLElement(nsGkAtoms::table))
  2844. *aTableSelectionType = nsISelectionPrivate::TABLESELECTION_TABLE;
  2845. else if (child->IsHTMLElement(nsGkAtoms::tr))
  2846. *aTableSelectionType = nsISelectionPrivate::TABLESELECTION_ROW;
  2847. }
  2848. return NS_OK;
  2849. }
  2850. nsresult
  2851. nsFrameSelection::CreateAndAddRange(nsINode *aParentNode, int32_t aOffset)
  2852. {
  2853. if (!aParentNode) return NS_ERROR_NULL_POINTER;
  2854. RefPtr<nsRange> range = new nsRange(aParentNode);
  2855. // Set range around child at given offset
  2856. nsresult rv = range->SetStartAndEnd(aParentNode, aOffset,
  2857. aParentNode, aOffset + 1);
  2858. if (NS_WARN_IF(NS_FAILED(rv))) {
  2859. return rv;
  2860. }
  2861. int8_t index = GetIndexFromSelectionType(SelectionType::eNormal);
  2862. if (!mDomSelections[index])
  2863. return NS_ERROR_NULL_POINTER;
  2864. return mDomSelections[index]->AddRange(range);
  2865. }
  2866. // End of Table Selection
  2867. void
  2868. nsFrameSelection::SetAncestorLimiter(nsIContent *aLimiter)
  2869. {
  2870. if (mAncestorLimiter != aLimiter) {
  2871. mAncestorLimiter = aLimiter;
  2872. int8_t index = GetIndexFromSelectionType(SelectionType::eNormal);
  2873. if (!mDomSelections[index])
  2874. return;
  2875. if (!IsValidSelectionPoint(this, mDomSelections[index]->GetFocusNode())) {
  2876. ClearNormalSelection();
  2877. if (mAncestorLimiter) {
  2878. PostReason(nsISelectionListener::NO_REASON);
  2879. TakeFocus(mAncestorLimiter, 0, 0, CARET_ASSOCIATE_BEFORE, false, false);
  2880. }
  2881. }
  2882. }
  2883. }
  2884. //END nsFrameSelection methods
  2885. //BEGIN nsISelection interface implementations
  2886. nsresult
  2887. nsFrameSelection::DeleteFromDocument()
  2888. {
  2889. nsresult res;
  2890. // If we're already collapsed, then we do nothing (bug 719503).
  2891. bool isCollapsed;
  2892. int8_t index = GetIndexFromSelectionType(SelectionType::eNormal);
  2893. if (!mDomSelections[index])
  2894. return NS_ERROR_NULL_POINTER;
  2895. mDomSelections[index]->GetIsCollapsed( &isCollapsed);
  2896. if (isCollapsed)
  2897. {
  2898. return NS_OK;
  2899. }
  2900. RefPtr<Selection> selection = mDomSelections[index];
  2901. for (uint32_t rangeIdx = 0; rangeIdx < selection->RangeCount(); ++rangeIdx) {
  2902. RefPtr<nsRange> range = selection->GetRangeAt(rangeIdx);
  2903. res = range->DeleteContents();
  2904. if (NS_FAILED(res))
  2905. return res;
  2906. }
  2907. // Collapse to the new location.
  2908. // If we deleted one character, then we move back one element.
  2909. // FIXME We don't know how to do this past frame boundaries yet.
  2910. if (isCollapsed)
  2911. mDomSelections[index]->Collapse(mDomSelections[index]->GetAnchorNode(), mDomSelections[index]->AnchorOffset()-1);
  2912. else if (mDomSelections[index]->AnchorOffset() > 0)
  2913. mDomSelections[index]->Collapse(mDomSelections[index]->GetAnchorNode(), mDomSelections[index]->AnchorOffset());
  2914. #ifdef DEBUG
  2915. else
  2916. printf("Don't know how to set selection back past frame boundary\n");
  2917. #endif
  2918. return NS_OK;
  2919. }
  2920. void
  2921. nsFrameSelection::SetDelayedCaretData(WidgetMouseEvent* aMouseEvent)
  2922. {
  2923. if (aMouseEvent) {
  2924. mDelayedMouseEventValid = true;
  2925. mDelayedMouseEventIsShift = aMouseEvent->IsShift();
  2926. mDelayedMouseEventClickCount = aMouseEvent->mClickCount;
  2927. } else {
  2928. mDelayedMouseEventValid = false;
  2929. }
  2930. }
  2931. void
  2932. nsFrameSelection::DisconnectFromPresShell()
  2933. {
  2934. RefPtr<AccessibleCaretEventHub> eventHub = mShell->GetAccessibleCaretEventHub();
  2935. if (eventHub) {
  2936. int8_t index = GetIndexFromSelectionType(SelectionType::eNormal);
  2937. mDomSelections[index]->RemoveSelectionListener(eventHub);
  2938. }
  2939. StopAutoScrollTimer();
  2940. for (size_t i = 0; i < kPresentSelectionTypeCount; i++) {
  2941. mDomSelections[i]->Clear(nullptr);
  2942. }
  2943. mShell = nullptr;
  2944. }
  2945. //END nsISelection interface implementations
  2946. #if 0
  2947. #pragma mark -
  2948. #endif
  2949. // mozilla::dom::Selection implementation
  2950. // note: this can return a nil anchor node
  2951. Selection::Selection()
  2952. : mCachedOffsetForFrame(nullptr)
  2953. , mDirection(eDirNext)
  2954. , mSelectionType(SelectionType::eNormal)
  2955. , mUserInitiated(false)
  2956. , mSelectionChangeBlockerCount(0)
  2957. {
  2958. }
  2959. Selection::Selection(nsFrameSelection* aList)
  2960. : mFrameSelection(aList)
  2961. , mCachedOffsetForFrame(nullptr)
  2962. , mDirection(eDirNext)
  2963. , mSelectionType(SelectionType::eNormal)
  2964. , mUserInitiated(false)
  2965. , mSelectionChangeBlockerCount(0)
  2966. {
  2967. }
  2968. Selection::~Selection()
  2969. {
  2970. setAnchorFocusRange(-1);
  2971. uint32_t count = mRanges.Length();
  2972. for (uint32_t i = 0; i < count; ++i) {
  2973. mRanges[i].mRange->SetSelection(nullptr);
  2974. }
  2975. if (mAutoScrollTimer) {
  2976. mAutoScrollTimer->Stop();
  2977. mAutoScrollTimer = nullptr;
  2978. }
  2979. mScrollEvent.Revoke();
  2980. if (mCachedOffsetForFrame) {
  2981. delete mCachedOffsetForFrame;
  2982. mCachedOffsetForFrame = nullptr;
  2983. }
  2984. }
  2985. nsIDocument*
  2986. Selection::GetParentObject() const
  2987. {
  2988. nsIPresShell* shell = GetPresShell();
  2989. if (shell) {
  2990. return shell->GetDocument();
  2991. }
  2992. return nullptr;
  2993. }
  2994. DocGroup*
  2995. Selection::GetDocGroup() const
  2996. {
  2997. nsIPresShell* shell = GetPresShell();
  2998. if (!shell) {
  2999. return nullptr;
  3000. }
  3001. nsIDocument* doc = shell->GetDocument();
  3002. return doc ? doc->GetDocGroup() : nullptr;
  3003. }
  3004. NS_IMPL_CYCLE_COLLECTION_CLASS(Selection)
  3005. NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Selection)
  3006. // Unlink the selection listeners *before* we do RemoveAllRanges since
  3007. // we don't want to notify the listeners during JS GC (they could be
  3008. // in JS!).
  3009. NS_IMPL_CYCLE_COLLECTION_UNLINK(mSelectionListeners)
  3010. tmp->RemoveAllRanges();
  3011. NS_IMPL_CYCLE_COLLECTION_UNLINK(mFrameSelection)
  3012. NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
  3013. NS_IMPL_CYCLE_COLLECTION_UNLINK_END
  3014. NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Selection)
  3015. {
  3016. uint32_t i, count = tmp->mRanges.Length();
  3017. for (i = 0; i < count; ++i) {
  3018. NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRanges[i].mRange)
  3019. }
  3020. }
  3021. NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAnchorFocusRange)
  3022. NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFrameSelection)
  3023. NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSelectionListeners)
  3024. NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
  3025. NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(Selection)
  3026. // QueryInterface implementation for Selection
  3027. NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Selection)
  3028. NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
  3029. NS_INTERFACE_MAP_ENTRY(nsISelection)
  3030. NS_INTERFACE_MAP_ENTRY(nsISelectionPrivate)
  3031. NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
  3032. NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsISelection)
  3033. NS_INTERFACE_MAP_END
  3034. NS_IMPL_CYCLE_COLLECTING_ADDREF(Selection)
  3035. NS_IMPL_CYCLE_COLLECTING_RELEASE(Selection)
  3036. NS_IMETHODIMP
  3037. Selection::GetAnchorNode(nsIDOMNode** aAnchorNode)
  3038. {
  3039. nsINode* anchorNode = GetAnchorNode();
  3040. if (anchorNode) {
  3041. return CallQueryInterface(anchorNode, aAnchorNode);
  3042. }
  3043. *aAnchorNode = nullptr;
  3044. return NS_OK;
  3045. }
  3046. nsINode*
  3047. Selection::GetAnchorNode()
  3048. {
  3049. if (!mAnchorFocusRange)
  3050. return nullptr;
  3051. if (GetDirection() == eDirNext) {
  3052. return mAnchorFocusRange->GetStartParent();
  3053. }
  3054. return mAnchorFocusRange->GetEndParent();
  3055. }
  3056. NS_IMETHODIMP
  3057. Selection::GetAnchorOffset(int32_t* aAnchorOffset)
  3058. {
  3059. *aAnchorOffset = static_cast<int32_t>(AnchorOffset());
  3060. return NS_OK;
  3061. }
  3062. // note: this can return a nil focus node
  3063. NS_IMETHODIMP
  3064. Selection::GetFocusNode(nsIDOMNode** aFocusNode)
  3065. {
  3066. nsINode* focusNode = GetFocusNode();
  3067. if (focusNode) {
  3068. return CallQueryInterface(focusNode, aFocusNode);
  3069. }
  3070. *aFocusNode = nullptr;
  3071. return NS_OK;
  3072. }
  3073. nsINode*
  3074. Selection::GetFocusNode()
  3075. {
  3076. if (!mAnchorFocusRange)
  3077. return nullptr;
  3078. if (GetDirection() == eDirNext){
  3079. return mAnchorFocusRange->GetEndParent();
  3080. }
  3081. return mAnchorFocusRange->GetStartParent();
  3082. }
  3083. NS_IMETHODIMP
  3084. Selection::GetFocusOffset(int32_t* aFocusOffset)
  3085. {
  3086. *aFocusOffset = static_cast<int32_t>(FocusOffset());
  3087. return NS_OK;
  3088. }
  3089. void
  3090. Selection::setAnchorFocusRange(int32_t indx)
  3091. {
  3092. if (indx >= (int32_t)mRanges.Length())
  3093. return;
  3094. if (indx < 0) //release all
  3095. {
  3096. mAnchorFocusRange = nullptr;
  3097. }
  3098. else{
  3099. mAnchorFocusRange = mRanges[indx].mRange;
  3100. }
  3101. }
  3102. uint32_t
  3103. Selection::AnchorOffset()
  3104. {
  3105. if (!mAnchorFocusRange)
  3106. return 0;
  3107. if (GetDirection() == eDirNext){
  3108. return mAnchorFocusRange->StartOffset();
  3109. }
  3110. return mAnchorFocusRange->EndOffset();
  3111. }
  3112. uint32_t
  3113. Selection::FocusOffset()
  3114. {
  3115. if (!mAnchorFocusRange)
  3116. return 0;
  3117. if (GetDirection() == eDirNext){
  3118. return mAnchorFocusRange->EndOffset();
  3119. }
  3120. return mAnchorFocusRange->StartOffset();
  3121. }
  3122. static nsresult
  3123. CompareToRangeStart(nsINode* aCompareNode, int32_t aCompareOffset,
  3124. nsRange* aRange, int32_t* aCmp)
  3125. {
  3126. nsINode* start = aRange->GetStartParent();
  3127. NS_ENSURE_STATE(aCompareNode && start);
  3128. // If the nodes that we're comparing are not in the same document,
  3129. // assume that aCompareNode will fall at the end of the ranges.
  3130. if (aCompareNode->GetComposedDoc() != start->GetComposedDoc() ||
  3131. !start->GetComposedDoc()) {
  3132. *aCmp = 1;
  3133. } else {
  3134. *aCmp = nsContentUtils::ComparePoints(aCompareNode, aCompareOffset,
  3135. start, aRange->StartOffset());
  3136. }
  3137. return NS_OK;
  3138. }
  3139. static nsresult
  3140. CompareToRangeEnd(nsINode* aCompareNode, int32_t aCompareOffset,
  3141. nsRange* aRange, int32_t* aCmp)
  3142. {
  3143. nsINode* end = aRange->GetEndParent();
  3144. NS_ENSURE_STATE(aCompareNode && end);
  3145. // If the nodes that we're comparing are not in the same document,
  3146. // assume that aCompareNode will fall at the end of the ranges.
  3147. if (aCompareNode->GetComposedDoc() != end->GetComposedDoc() ||
  3148. !end->GetComposedDoc()) {
  3149. *aCmp = 1;
  3150. } else {
  3151. *aCmp = nsContentUtils::ComparePoints(aCompareNode, aCompareOffset,
  3152. end, aRange->EndOffset());
  3153. }
  3154. return NS_OK;
  3155. }
  3156. // Selection::FindInsertionPoint
  3157. //
  3158. // Binary searches the given sorted array of ranges for the insertion point
  3159. // for the given node/offset. The given comparator is used, and the index
  3160. // where the point should appear in the array is placed in *aInsertionPoint.
  3161. //
  3162. // If there is an item in the array equal to the input point, we will return
  3163. // the index of this item.
  3164. nsresult
  3165. Selection::FindInsertionPoint(
  3166. nsTArray<RangeData>* aElementArray,
  3167. nsINode* aPointNode, int32_t aPointOffset,
  3168. nsresult (*aComparator)(nsINode*,int32_t,nsRange*,int32_t*),
  3169. int32_t* aPoint)
  3170. {
  3171. *aPoint = 0;
  3172. int32_t beginSearch = 0;
  3173. int32_t endSearch = aElementArray->Length(); // one beyond what to check
  3174. if (endSearch) {
  3175. int32_t center = endSearch - 1; // Check last index, then binary search
  3176. do {
  3177. nsRange* range = (*aElementArray)[center].mRange;
  3178. int32_t cmp;
  3179. nsresult rv = aComparator(aPointNode, aPointOffset, range, &cmp);
  3180. NS_ENSURE_SUCCESS(rv, rv);
  3181. if (cmp < 0) { // point < cur
  3182. endSearch = center;
  3183. } else if (cmp > 0) { // point > cur
  3184. beginSearch = center + 1;
  3185. } else { // found match, done
  3186. beginSearch = center;
  3187. break;
  3188. }
  3189. center = (endSearch - beginSearch) / 2 + beginSearch;
  3190. } while (endSearch - beginSearch > 0);
  3191. }
  3192. *aPoint = beginSearch;
  3193. return NS_OK;
  3194. }
  3195. // Selection::SubtractRange
  3196. //
  3197. // A helper function that subtracts aSubtract from aRange, and adds
  3198. // 1 or 2 RangeData objects representing the remaining non-overlapping
  3199. // difference to aOutput. It is assumed that the caller has checked that
  3200. // aRange and aSubtract do indeed overlap
  3201. nsresult
  3202. Selection::SubtractRange(RangeData* aRange, nsRange* aSubtract,
  3203. nsTArray<RangeData>* aOutput)
  3204. {
  3205. nsRange* range = aRange->mRange;
  3206. // First we want to compare to the range start
  3207. int32_t cmp;
  3208. nsresult rv = CompareToRangeStart(range->GetStartParent(),
  3209. range->StartOffset(),
  3210. aSubtract, &cmp);
  3211. NS_ENSURE_SUCCESS(rv, rv);
  3212. // Also, make a comparison to the range end
  3213. int32_t cmp2;
  3214. rv = CompareToRangeEnd(range->GetEndParent(),
  3215. range->EndOffset(),
  3216. aSubtract, &cmp2);
  3217. NS_ENSURE_SUCCESS(rv, rv);
  3218. // If the existing range left overlaps the new range (aSubtract) then
  3219. // cmp < 0, and cmp2 < 0
  3220. // If it right overlaps the new range then cmp > 0 and cmp2 > 0
  3221. // If it fully contains the new range, then cmp < 0 and cmp2 > 0
  3222. if (cmp2 > 0) {
  3223. // We need to add a new RangeData to the output, running from
  3224. // the end of aSubtract to the end of range
  3225. RefPtr<nsRange> postOverlap = new nsRange(aSubtract->GetEndParent());
  3226. rv = postOverlap->SetStartAndEnd(
  3227. aSubtract->GetEndParent(), aSubtract->EndOffset(),
  3228. range->GetEndParent(), range->EndOffset());
  3229. if (NS_WARN_IF(NS_FAILED(rv))) {
  3230. return rv;
  3231. }
  3232. if (!postOverlap->Collapsed()) {
  3233. if (!aOutput->InsertElementAt(0, RangeData(postOverlap)))
  3234. return NS_ERROR_OUT_OF_MEMORY;
  3235. (*aOutput)[0].mTextRangeStyle = aRange->mTextRangeStyle;
  3236. }
  3237. }
  3238. if (cmp < 0) {
  3239. // We need to add a new RangeData to the output, running from
  3240. // the start of the range to the start of aSubtract
  3241. RefPtr<nsRange> preOverlap = new nsRange(range->GetStartParent());
  3242. rv = preOverlap->SetStartAndEnd(
  3243. range->GetStartParent(), range->StartOffset(),
  3244. aSubtract->GetStartParent(), aSubtract->StartOffset());
  3245. if (NS_WARN_IF(NS_FAILED(rv))) {
  3246. return rv;
  3247. }
  3248. if (!preOverlap->Collapsed()) {
  3249. if (!aOutput->InsertElementAt(0, RangeData(preOverlap)))
  3250. return NS_ERROR_OUT_OF_MEMORY;
  3251. (*aOutput)[0].mTextRangeStyle = aRange->mTextRangeStyle;
  3252. }
  3253. }
  3254. return NS_OK;
  3255. }
  3256. void
  3257. Selection::UserSelectRangesToAdd(nsRange* aItem, nsTArray<RefPtr<nsRange>>& aRangesToAdd)
  3258. {
  3259. aItem->ExcludeNonSelectableNodes(&aRangesToAdd);
  3260. if (aRangesToAdd.IsEmpty()) {
  3261. ErrorResult err;
  3262. nsINode* node = aItem->GetStartContainer(err);
  3263. if (node && node->IsContent() && node->AsContent()->GetEditingHost()) {
  3264. // A contenteditable node with user-select:none, for example.
  3265. // Allow it to have a collapsed selection (for the caret).
  3266. aItem->Collapse(GetDirection() == eDirPrevious);
  3267. aRangesToAdd.AppendElement(aItem);
  3268. }
  3269. }
  3270. }
  3271. nsresult
  3272. Selection::AddItem(nsRange* aItem, int32_t* aOutIndex, bool aNoStartSelect)
  3273. {
  3274. if (!aItem)
  3275. return NS_ERROR_NULL_POINTER;
  3276. if (!aItem->IsPositioned())
  3277. return NS_ERROR_UNEXPECTED;
  3278. NS_ASSERTION(aOutIndex, "aOutIndex can't be null");
  3279. if (mUserInitiated) {
  3280. AutoTArray<RefPtr<nsRange>, 4> rangesToAdd;
  3281. *aOutIndex = int32_t(mRanges.Length()) - 1;
  3282. nsIDocument* doc = GetParentObject();
  3283. bool selectEventsEnabled =
  3284. nsFrameSelection::sSelectionEventsEnabled ||
  3285. (doc && nsContentUtils::IsSystemPrincipal(doc->NodePrincipal()));
  3286. if (!aNoStartSelect &&
  3287. mSelectionType == SelectionType::eNormal &&
  3288. selectEventsEnabled && Collapsed() &&
  3289. !IsBlockingSelectionChangeEvents()) {
  3290. // First, we generate the ranges to add with a scratch range, which is a
  3291. // clone of the original range passed in. We do this seperately, because the
  3292. // selectstart event could have caused the world to change, and required
  3293. // ranges to be re-generated
  3294. RefPtr<nsRange> scratchRange = aItem->CloneRange();
  3295. UserSelectRangesToAdd(scratchRange, rangesToAdd);
  3296. bool newRangesNonEmpty = rangesToAdd.Length() > 1 ||
  3297. (rangesToAdd.Length() == 1 && !rangesToAdd[0]->Collapsed());
  3298. MOZ_ASSERT(!newRangesNonEmpty || nsContentUtils::IsSafeToRunScript());
  3299. if (newRangesNonEmpty && nsContentUtils::IsSafeToRunScript()) {
  3300. // We consider a selection to be starting if we are currently collapsed,
  3301. // and the selection is becoming uncollapsed, and this is caused by a user
  3302. // initiated event.
  3303. bool defaultAction = true;
  3304. // The spec currently doesn't say that we should dispatch this event
  3305. // on text controls, so for now we only support doing that under a
  3306. // pref, disabled by default.
  3307. // See https://github.com/w3c/selection-api/issues/53.
  3308. bool dispatchEvent = true;
  3309. nsCOMPtr<nsINode> target = aItem->GetStartParent();
  3310. if (nsFrameSelection::sSelectionEventsOnTextControlsEnabled) {
  3311. // Get the first element which isn't in a native anonymous subtree
  3312. while (target && target->IsInNativeAnonymousSubtree()) {
  3313. target = target->GetParent();
  3314. }
  3315. } else {
  3316. if (target->IsInNativeAnonymousSubtree()) {
  3317. // This is a selection under a text control, so don't dispatch the
  3318. // event.
  3319. dispatchEvent = false;
  3320. }
  3321. }
  3322. if (dispatchEvent) {
  3323. nsContentUtils::DispatchTrustedEvent(GetParentObject(), target,
  3324. NS_LITERAL_STRING("selectstart"),
  3325. true, true, &defaultAction);
  3326. if (!defaultAction) {
  3327. return NS_OK;
  3328. }
  3329. // As we just dispatched an event to the DOM, something could have
  3330. // changed under our feet. Re-generate the rangesToAdd array, and ensure
  3331. // that the range we are about to add is still valid.
  3332. if (!aItem->IsPositioned()) {
  3333. return NS_ERROR_UNEXPECTED;
  3334. }
  3335. }
  3336. }
  3337. // The scratch ranges we generated may be invalid now, throw them out
  3338. rangesToAdd.ClearAndRetainStorage();
  3339. }
  3340. // Generate the ranges to add
  3341. UserSelectRangesToAdd(aItem, rangesToAdd);
  3342. size_t newAnchorFocusIndex =
  3343. GetDirection() == eDirPrevious ? 0 : rangesToAdd.Length() - 1;
  3344. for (size_t i = 0; i < rangesToAdd.Length(); ++i) {
  3345. int32_t index;
  3346. nsresult rv = AddItemInternal(rangesToAdd[i], &index);
  3347. NS_ENSURE_SUCCESS(rv, rv);
  3348. if (i == newAnchorFocusIndex) {
  3349. *aOutIndex = index;
  3350. rangesToAdd[i]->SetIsGenerated(false);
  3351. } else {
  3352. rangesToAdd[i]->SetIsGenerated(true);
  3353. }
  3354. }
  3355. return NS_OK;
  3356. }
  3357. return AddItemInternal(aItem, aOutIndex);
  3358. }
  3359. nsresult
  3360. Selection::AddItemInternal(nsRange* aItem, int32_t* aOutIndex)
  3361. {
  3362. MOZ_ASSERT(aItem);
  3363. MOZ_ASSERT(aItem->IsPositioned());
  3364. MOZ_ASSERT(aOutIndex);
  3365. *aOutIndex = -1;
  3366. // a common case is that we have no ranges yet
  3367. if (mRanges.Length() == 0) {
  3368. if (!mRanges.AppendElement(RangeData(aItem)))
  3369. return NS_ERROR_OUT_OF_MEMORY;
  3370. aItem->SetSelection(this);
  3371. *aOutIndex = 0;
  3372. return NS_OK;
  3373. }
  3374. int32_t startIndex, endIndex;
  3375. nsresult rv = GetIndicesForInterval(aItem->GetStartParent(),
  3376. aItem->StartOffset(),
  3377. aItem->GetEndParent(),
  3378. aItem->EndOffset(), false,
  3379. &startIndex, &endIndex);
  3380. NS_ENSURE_SUCCESS(rv, rv);
  3381. if (endIndex == -1) {
  3382. // All ranges start after the given range. We can insert our range at
  3383. // position 0, knowing there are no overlaps (handled below)
  3384. startIndex = 0;
  3385. endIndex = 0;
  3386. } else if (startIndex == -1) {
  3387. // All ranges end before the given range. We can insert our range at
  3388. // the end of the array, knowing there are no overlaps (handled below)
  3389. startIndex = mRanges.Length();
  3390. endIndex = startIndex;
  3391. }
  3392. // If the range is already contained in mRanges, silently succeed
  3393. bool sameRange = EqualsRangeAtPoint(aItem->GetStartParent(),
  3394. aItem->StartOffset(),
  3395. aItem->GetEndParent(),
  3396. aItem->EndOffset(), startIndex);
  3397. if (sameRange) {
  3398. *aOutIndex = startIndex;
  3399. return NS_OK;
  3400. }
  3401. if (startIndex == endIndex) {
  3402. // The new range doesn't overlap any existing ranges
  3403. if (!mRanges.InsertElementAt(startIndex, RangeData(aItem)))
  3404. return NS_ERROR_OUT_OF_MEMORY;
  3405. aItem->SetSelection(this);
  3406. *aOutIndex = startIndex;
  3407. return NS_OK;
  3408. }
  3409. // We now know that at least 1 existing range overlaps with the range that
  3410. // we are trying to add. In fact, the only ranges of interest are those at
  3411. // the two end points, startIndex and endIndex - 1 (which may point to the
  3412. // same range) as these may partially overlap the new range. Any ranges
  3413. // between these indices are fully overlapped by the new range, and so can be
  3414. // removed
  3415. nsTArray<RangeData> overlaps;
  3416. if (!overlaps.InsertElementAt(0, mRanges[startIndex]))
  3417. return NS_ERROR_OUT_OF_MEMORY;
  3418. if (endIndex - 1 != startIndex) {
  3419. if (!overlaps.InsertElementAt(1, mRanges[endIndex - 1]))
  3420. return NS_ERROR_OUT_OF_MEMORY;
  3421. }
  3422. // Remove all the overlapping ranges
  3423. for (int32_t i = startIndex; i < endIndex; ++i) {
  3424. mRanges[i].mRange->SetSelection(nullptr);
  3425. }
  3426. mRanges.RemoveElementsAt(startIndex, endIndex - startIndex);
  3427. nsTArray<RangeData> temp;
  3428. for (int32_t i = overlaps.Length() - 1; i >= 0; i--) {
  3429. nsresult rv = SubtractRange(&overlaps[i], aItem, &temp);
  3430. NS_ENSURE_SUCCESS(rv, rv);
  3431. }
  3432. // Insert the new element into our "leftovers" array
  3433. int32_t insertionPoint;
  3434. rv = FindInsertionPoint(&temp, aItem->GetStartParent(),
  3435. aItem->StartOffset(), CompareToRangeStart,
  3436. &insertionPoint);
  3437. NS_ENSURE_SUCCESS(rv, rv);
  3438. if (!temp.InsertElementAt(insertionPoint, RangeData(aItem)))
  3439. return NS_ERROR_OUT_OF_MEMORY;
  3440. // Merge the leftovers back in to mRanges
  3441. if (!mRanges.InsertElementsAt(startIndex, temp))
  3442. return NS_ERROR_OUT_OF_MEMORY;
  3443. for (uint32_t i = 0; i < temp.Length(); ++i) {
  3444. temp[i].mRange->SetSelection(this);
  3445. }
  3446. *aOutIndex = startIndex + insertionPoint;
  3447. return NS_OK;
  3448. }
  3449. nsresult
  3450. Selection::RemoveItem(nsRange* aItem)
  3451. {
  3452. if (!aItem)
  3453. return NS_ERROR_NULL_POINTER;
  3454. // Find the range's index & remove it. We could use FindInsertionPoint to
  3455. // get O(log n) time, but that requires many expensive DOM comparisons.
  3456. // For even several thousand items, this is probably faster because the
  3457. // comparisons are so fast.
  3458. int32_t idx = -1;
  3459. uint32_t i;
  3460. for (i = 0; i < mRanges.Length(); i ++) {
  3461. if (mRanges[i].mRange == aItem) {
  3462. idx = (int32_t)i;
  3463. break;
  3464. }
  3465. }
  3466. if (idx < 0)
  3467. return NS_ERROR_INVALID_ARG;
  3468. mRanges.RemoveElementAt(idx);
  3469. aItem->SetSelection(nullptr);
  3470. return NS_OK;
  3471. }
  3472. nsresult
  3473. Selection::RemoveCollapsedRanges()
  3474. {
  3475. uint32_t i = 0;
  3476. while (i < mRanges.Length()) {
  3477. if (mRanges[i].mRange->Collapsed()) {
  3478. nsresult rv = RemoveItem(mRanges[i].mRange);
  3479. NS_ENSURE_SUCCESS(rv, rv);
  3480. } else {
  3481. ++i;
  3482. }
  3483. }
  3484. return NS_OK;
  3485. }
  3486. nsresult
  3487. Selection::Clear(nsPresContext* aPresContext)
  3488. {
  3489. setAnchorFocusRange(-1);
  3490. for (uint32_t i = 0; i < mRanges.Length(); ++i) {
  3491. mRanges[i].mRange->SetSelection(nullptr);
  3492. selectFrames(aPresContext, mRanges[i].mRange, false);
  3493. }
  3494. mRanges.Clear();
  3495. // Reset direction so for more dependable table selection range handling
  3496. SetDirection(eDirNext);
  3497. // If this was an ATTENTION selection, change it back to normal now
  3498. if (mFrameSelection &&
  3499. mFrameSelection->GetDisplaySelection() ==
  3500. nsISelectionController::SELECTION_ATTENTION) {
  3501. mFrameSelection->SetDisplaySelection(nsISelectionController::SELECTION_ON);
  3502. }
  3503. return NS_OK;
  3504. }
  3505. NS_IMETHODIMP
  3506. Selection::GetType(int16_t* aType)
  3507. {
  3508. NS_ENSURE_ARG_POINTER(aType);
  3509. *aType = ToRawSelectionType(Type());
  3510. return NS_OK;
  3511. }
  3512. // RangeMatches*Point
  3513. //
  3514. // Compares the range beginning or ending point, and returns true if it
  3515. // exactly matches the given DOM point.
  3516. static inline bool
  3517. RangeMatchesBeginPoint(nsRange* aRange, nsINode* aNode, int32_t aOffset)
  3518. {
  3519. return aRange->GetStartParent() == aNode &&
  3520. static_cast<int32_t>(aRange->StartOffset()) == aOffset;
  3521. }
  3522. static inline bool
  3523. RangeMatchesEndPoint(nsRange* aRange, nsINode* aNode, int32_t aOffset)
  3524. {
  3525. return aRange->GetEndParent() == aNode &&
  3526. static_cast<int32_t>(aRange->EndOffset()) == aOffset;
  3527. }
  3528. // Selection::EqualsRangeAtPoint
  3529. //
  3530. // Utility method for checking equivalence of two ranges.
  3531. bool
  3532. Selection::EqualsRangeAtPoint(
  3533. nsINode* aBeginNode, int32_t aBeginOffset,
  3534. nsINode* aEndNode, int32_t aEndOffset,
  3535. int32_t aRangeIndex)
  3536. {
  3537. if (aRangeIndex >=0 && aRangeIndex < (int32_t) mRanges.Length()) {
  3538. nsRange* range = mRanges[aRangeIndex].mRange;
  3539. if (RangeMatchesBeginPoint(range, aBeginNode, aBeginOffset) &&
  3540. RangeMatchesEndPoint(range, aEndNode, aEndOffset))
  3541. return true;
  3542. }
  3543. return false;
  3544. }
  3545. // Selection::GetRangesForInterval
  3546. //
  3547. // XPCOM wrapper for the nsTArray version
  3548. NS_IMETHODIMP
  3549. Selection::GetRangesForInterval(nsIDOMNode* aBeginNode, int32_t aBeginOffset,
  3550. nsIDOMNode* aEndNode, int32_t aEndOffset,
  3551. bool aAllowAdjacent,
  3552. uint32_t* aResultCount,
  3553. nsIDOMRange*** aResults)
  3554. {
  3555. if (!aBeginNode || ! aEndNode || ! aResultCount || ! aResults)
  3556. return NS_ERROR_NULL_POINTER;
  3557. *aResultCount = 0;
  3558. *aResults = nullptr;
  3559. nsTArray<RefPtr<nsRange>> results;
  3560. ErrorResult result;
  3561. nsCOMPtr<nsINode> beginNode = do_QueryInterface(aBeginNode);
  3562. nsCOMPtr<nsINode> endNode = do_QueryInterface(aEndNode);
  3563. NS_ENSURE_TRUE(beginNode && endNode, NS_ERROR_NULL_POINTER);
  3564. GetRangesForInterval(*beginNode, aBeginOffset, *endNode, aEndOffset,
  3565. aAllowAdjacent, results, result);
  3566. if (result.Failed()) {
  3567. return result.StealNSResult();
  3568. }
  3569. *aResultCount = results.Length();
  3570. if (*aResultCount == 0) {
  3571. return NS_OK;
  3572. }
  3573. *aResults = static_cast<nsIDOMRange**>
  3574. (moz_xmalloc(sizeof(nsIDOMRange*) * *aResultCount));
  3575. NS_ENSURE_TRUE(*aResults, NS_ERROR_OUT_OF_MEMORY);
  3576. for (uint32_t i = 0; i < *aResultCount; i++) {
  3577. (*aResults)[i] = results[i].forget().take();
  3578. }
  3579. return NS_OK;
  3580. }
  3581. void
  3582. Selection::GetRangesForInterval(nsINode& aBeginNode, int32_t aBeginOffset,
  3583. nsINode& aEndNode, int32_t aEndOffset,
  3584. bool aAllowAdjacent,
  3585. nsTArray<RefPtr<nsRange>>& aReturn,
  3586. mozilla::ErrorResult& aRv)
  3587. {
  3588. nsTArray<nsRange*> results;
  3589. nsresult rv = GetRangesForIntervalArray(&aBeginNode, aBeginOffset,
  3590. &aEndNode, aEndOffset,
  3591. aAllowAdjacent, &results);
  3592. if (NS_FAILED(rv)) {
  3593. aRv.Throw(rv);
  3594. return;
  3595. }
  3596. aReturn.SetLength(results.Length());
  3597. for (uint32_t i = 0; i < results.Length(); ++i) {
  3598. aReturn[i] = results[i]; // AddRefs
  3599. }
  3600. }
  3601. // Selection::GetRangesForIntervalArray
  3602. //
  3603. // Fills a nsTArray with the ranges overlapping the range specified by
  3604. // the given endpoints. Ranges in the selection exactly adjacent to the
  3605. // input range are not returned unless aAllowAdjacent is set.
  3606. //
  3607. // For example, if the following ranges were in the selection
  3608. // (assume everything is within the same node)
  3609. //
  3610. // Start Offset: 0 2 7 9
  3611. // End Offset: 2 5 9 10
  3612. //
  3613. // and passed aBeginOffset of 2 and aEndOffset of 9, then with
  3614. // aAllowAdjacent set, all the ranges should be returned. If
  3615. // aAllowAdjacent was false, the ranges [2, 5] and [7, 9] only
  3616. // should be returned
  3617. //
  3618. // Now that overlapping ranges are disallowed, there can be a maximum of
  3619. // 2 adjacent ranges
  3620. nsresult
  3621. Selection::GetRangesForIntervalArray(nsINode* aBeginNode, int32_t aBeginOffset,
  3622. nsINode* aEndNode, int32_t aEndOffset,
  3623. bool aAllowAdjacent,
  3624. nsTArray<nsRange*>* aRanges)
  3625. {
  3626. aRanges->Clear();
  3627. int32_t startIndex, endIndex;
  3628. nsresult res = GetIndicesForInterval(aBeginNode, aBeginOffset,
  3629. aEndNode, aEndOffset, aAllowAdjacent,
  3630. &startIndex, &endIndex);
  3631. NS_ENSURE_SUCCESS(res, res);
  3632. if (startIndex == -1 || endIndex == -1)
  3633. return NS_OK;
  3634. for (int32_t i = startIndex; i < endIndex; i++) {
  3635. if (!aRanges->AppendElement(mRanges[i].mRange))
  3636. return NS_ERROR_OUT_OF_MEMORY;
  3637. }
  3638. return NS_OK;
  3639. }
  3640. // Selection::GetIndicesForInterval
  3641. //
  3642. // Works on the same principle as GetRangesForIntervalArray above, however
  3643. // instead this returns the indices into mRanges between which the
  3644. // overlapping ranges lie.
  3645. nsresult
  3646. Selection::GetIndicesForInterval(nsINode* aBeginNode, int32_t aBeginOffset,
  3647. nsINode* aEndNode, int32_t aEndOffset,
  3648. bool aAllowAdjacent,
  3649. int32_t* aStartIndex, int32_t* aEndIndex)
  3650. {
  3651. int32_t startIndex;
  3652. int32_t endIndex;
  3653. if (!aStartIndex)
  3654. aStartIndex = &startIndex;
  3655. if (!aEndIndex)
  3656. aEndIndex = &endIndex;
  3657. *aStartIndex = -1;
  3658. *aEndIndex = -1;
  3659. if (mRanges.Length() == 0)
  3660. return NS_OK;
  3661. bool intervalIsCollapsed = aBeginNode == aEndNode &&
  3662. aBeginOffset == aEndOffset;
  3663. // Ranges that end before the given interval and begin after the given
  3664. // interval can be discarded
  3665. int32_t endsBeforeIndex;
  3666. if (NS_FAILED(FindInsertionPoint(&mRanges, aEndNode, aEndOffset,
  3667. &CompareToRangeStart,
  3668. &endsBeforeIndex))) {
  3669. return NS_OK;
  3670. }
  3671. if (endsBeforeIndex == 0) {
  3672. nsRange* endRange = mRanges[endsBeforeIndex].mRange;
  3673. // If the interval is strictly before the range at index 0, we can optimize
  3674. // by returning now - all ranges start after the given interval
  3675. if (!RangeMatchesBeginPoint(endRange, aEndNode, aEndOffset))
  3676. return NS_OK;
  3677. // We now know that the start point of mRanges[0].mRange equals the end of
  3678. // the interval. Thus, when aAllowadjacent is true, the caller is always
  3679. // interested in this range. However, when excluding adjacencies, we must
  3680. // remember to include the range when both it and the given interval are
  3681. // collapsed to the same point
  3682. if (!aAllowAdjacent && !(endRange->Collapsed() && intervalIsCollapsed))
  3683. return NS_OK;
  3684. }
  3685. *aEndIndex = endsBeforeIndex;
  3686. int32_t beginsAfterIndex;
  3687. if (NS_FAILED(FindInsertionPoint(&mRanges, aBeginNode, aBeginOffset,
  3688. &CompareToRangeEnd,
  3689. &beginsAfterIndex))) {
  3690. return NS_OK;
  3691. }
  3692. if (beginsAfterIndex == (int32_t) mRanges.Length())
  3693. return NS_OK; // optimization: all ranges are strictly before us
  3694. if (aAllowAdjacent) {
  3695. // At this point, one of the following holds:
  3696. // endsBeforeIndex == mRanges.Length(),
  3697. // endsBeforeIndex points to a range whose start point does not equal the
  3698. // given interval's start point
  3699. // endsBeforeIndex points to a range whose start point equals the given
  3700. // interval's start point
  3701. // In the final case, there can be two such ranges, a collapsed range, and
  3702. // an adjacent range (they will appear in mRanges in that order). For this
  3703. // final case, we need to increment endsBeforeIndex, until one of the
  3704. // first two possibilites hold
  3705. while (endsBeforeIndex < (int32_t) mRanges.Length()) {
  3706. nsRange* endRange = mRanges[endsBeforeIndex].mRange;
  3707. if (!RangeMatchesBeginPoint(endRange, aEndNode, aEndOffset))
  3708. break;
  3709. endsBeforeIndex++;
  3710. }
  3711. // Likewise, one of the following holds:
  3712. // beginsAfterIndex == 0,
  3713. // beginsAfterIndex points to a range whose end point does not equal
  3714. // the given interval's end point
  3715. // beginsOnOrAfter points to a range whose end point equals the given
  3716. // interval's end point
  3717. // In the final case, there can be two such ranges, an adjacent range, and
  3718. // a collapsed range (they will appear in mRanges in that order). For this
  3719. // final case, we only need to take action if both those ranges exist, and
  3720. // we are pointing to the collapsed range - we need to point to the
  3721. // adjacent range
  3722. nsRange* beginRange = mRanges[beginsAfterIndex].mRange;
  3723. if (beginsAfterIndex > 0 && beginRange->Collapsed() &&
  3724. RangeMatchesEndPoint(beginRange, aBeginNode, aBeginOffset)) {
  3725. beginRange = mRanges[beginsAfterIndex - 1].mRange;
  3726. if (RangeMatchesEndPoint(beginRange, aBeginNode, aBeginOffset))
  3727. beginsAfterIndex--;
  3728. }
  3729. } else {
  3730. // See above for the possibilities at this point. The only case where we
  3731. // need to take action is when the range at beginsAfterIndex ends on
  3732. // the given interval's start point, but that range isn't collapsed (a
  3733. // collapsed range should be included in the returned results).
  3734. nsRange* beginRange = mRanges[beginsAfterIndex].mRange;
  3735. if (RangeMatchesEndPoint(beginRange, aBeginNode, aBeginOffset) &&
  3736. !beginRange->Collapsed())
  3737. beginsAfterIndex++;
  3738. // Again, see above for the meaning of endsBeforeIndex at this point.
  3739. // In particular, endsBeforeIndex may point to a collaped range which
  3740. // represents the point at the end of the interval - this range should be
  3741. // included
  3742. if (endsBeforeIndex < (int32_t) mRanges.Length()) {
  3743. nsRange* endRange = mRanges[endsBeforeIndex].mRange;
  3744. if (RangeMatchesBeginPoint(endRange, aEndNode, aEndOffset) &&
  3745. endRange->Collapsed())
  3746. endsBeforeIndex++;
  3747. }
  3748. }
  3749. NS_ASSERTION(beginsAfterIndex <= endsBeforeIndex,
  3750. "Is mRanges not ordered?");
  3751. NS_ENSURE_STATE(beginsAfterIndex <= endsBeforeIndex);
  3752. *aStartIndex = beginsAfterIndex;
  3753. *aEndIndex = endsBeforeIndex;
  3754. return NS_OK;
  3755. }
  3756. NS_IMETHODIMP
  3757. Selection::GetPrimaryFrameForAnchorNode(nsIFrame** aReturnFrame)
  3758. {
  3759. if (!aReturnFrame)
  3760. return NS_ERROR_NULL_POINTER;
  3761. int32_t frameOffset = 0;
  3762. *aReturnFrame = 0;
  3763. nsCOMPtr<nsIContent> content = do_QueryInterface(GetAnchorNode());
  3764. if (content && mFrameSelection)
  3765. {
  3766. *aReturnFrame = mFrameSelection->
  3767. GetFrameForNodeOffset(content, AnchorOffset(),
  3768. mFrameSelection->GetHint(), &frameOffset);
  3769. if (*aReturnFrame)
  3770. return NS_OK;
  3771. }
  3772. return NS_ERROR_FAILURE;
  3773. }
  3774. NS_IMETHODIMP
  3775. Selection::GetPrimaryFrameForFocusNode(nsIFrame** aReturnFrame,
  3776. int32_t* aOffsetUsed,
  3777. bool aVisual)
  3778. {
  3779. if (!aReturnFrame)
  3780. return NS_ERROR_NULL_POINTER;
  3781. nsCOMPtr<nsIContent> content = do_QueryInterface(GetFocusNode());
  3782. if (!content || !mFrameSelection)
  3783. return NS_ERROR_FAILURE;
  3784. int32_t frameOffset = 0;
  3785. *aReturnFrame = 0;
  3786. if (!aOffsetUsed)
  3787. aOffsetUsed = &frameOffset;
  3788. CaretAssociationHint hint = mFrameSelection->GetHint();
  3789. if (aVisual) {
  3790. nsBidiLevel caretBidiLevel = mFrameSelection->GetCaretBidiLevel();
  3791. return nsCaret::GetCaretFrameForNodeOffset(mFrameSelection,
  3792. content, FocusOffset(), hint, caretBidiLevel, aReturnFrame, aOffsetUsed);
  3793. }
  3794. *aReturnFrame = mFrameSelection->
  3795. GetFrameForNodeOffset(content, FocusOffset(),
  3796. hint, aOffsetUsed);
  3797. if (!*aReturnFrame)
  3798. return NS_ERROR_FAILURE;
  3799. return NS_OK;
  3800. }
  3801. //select all content children of aContent
  3802. nsresult
  3803. Selection::SelectAllFramesForContent(nsIContentIterator* aInnerIter,
  3804. nsIContent* aContent,
  3805. bool aSelected)
  3806. {
  3807. nsresult result = aInnerIter->Init(aContent);
  3808. nsIFrame *frame;
  3809. if (NS_SUCCEEDED(result))
  3810. {
  3811. // First select frame of content passed in
  3812. frame = aContent->GetPrimaryFrame();
  3813. if (frame && frame->GetType() == nsGkAtoms::textFrame) {
  3814. nsTextFrame* textFrame = static_cast<nsTextFrame*>(frame);
  3815. textFrame->SetSelectedRange(0, aContent->GetText()->GetLength(),
  3816. aSelected, mSelectionType);
  3817. }
  3818. // Now iterated through the child frames and set them
  3819. while (!aInnerIter->IsDone()) {
  3820. nsCOMPtr<nsIContent> innercontent =
  3821. do_QueryInterface(aInnerIter->GetCurrentNode());
  3822. frame = innercontent->GetPrimaryFrame();
  3823. if (frame) {
  3824. if (frame->GetType() == nsGkAtoms::textFrame) {
  3825. nsTextFrame* textFrame = static_cast<nsTextFrame*>(frame);
  3826. textFrame->SetSelectedRange(0, innercontent->GetText()->GetLength(),
  3827. aSelected, mSelectionType);
  3828. } else {
  3829. frame->InvalidateFrameSubtree(); // frame continuations?
  3830. }
  3831. }
  3832. aInnerIter->Next();
  3833. }
  3834. return NS_OK;
  3835. }
  3836. return NS_ERROR_FAILURE;
  3837. }
  3838. /**
  3839. * The idea of this helper method is to select or deselect "top to bottom",
  3840. * traversing through the frames
  3841. */
  3842. nsresult
  3843. Selection::selectFrames(nsPresContext* aPresContext, nsRange* aRange,
  3844. bool aSelect)
  3845. {
  3846. if (!mFrameSelection || !aPresContext || !aPresContext->GetPresShell()) {
  3847. // nothing to do
  3848. return NS_OK;
  3849. }
  3850. MOZ_ASSERT(aRange);
  3851. if (mFrameSelection->GetTableCellSelection()) {
  3852. nsINode* node = aRange->GetCommonAncestor();
  3853. nsIFrame* frame = node->IsContent() ? node->AsContent()->GetPrimaryFrame()
  3854. : aPresContext->FrameManager()->GetRootFrame();
  3855. if (frame) {
  3856. frame->InvalidateFrameSubtree();
  3857. }
  3858. return NS_OK;
  3859. }
  3860. nsCOMPtr<nsIContentIterator> iter = NS_NewContentSubtreeIterator();
  3861. iter->Init(aRange);
  3862. // Loop through the content iterator for each content node; for each text
  3863. // node, call SetSelected on it:
  3864. nsCOMPtr<nsIContent> content = do_QueryInterface(aRange->GetStartParent());
  3865. if (!content) {
  3866. // Don't warn, bug 1055722
  3867. return NS_ERROR_UNEXPECTED;
  3868. }
  3869. // We must call first one explicitly
  3870. if (content->IsNodeOfType(nsINode::eTEXT)) {
  3871. nsIFrame* frame = content->GetPrimaryFrame();
  3872. // The frame could be an SVG text frame, in which case we'll ignore it.
  3873. if (frame && frame->GetType() == nsGkAtoms::textFrame) {
  3874. nsTextFrame* textFrame = static_cast<nsTextFrame*>(frame);
  3875. uint32_t startOffset = aRange->StartOffset();
  3876. uint32_t endOffset;
  3877. if (aRange->GetEndParent() == content) {
  3878. endOffset = aRange->EndOffset();
  3879. } else {
  3880. endOffset = content->Length();
  3881. }
  3882. textFrame->SetSelectedRange(startOffset, endOffset, aSelect,
  3883. mSelectionType);
  3884. }
  3885. }
  3886. iter->First();
  3887. nsCOMPtr<nsIContentIterator> inneriter = NS_NewContentIterator();
  3888. for (iter->First(); !iter->IsDone(); iter->Next()) {
  3889. content = do_QueryInterface(iter->GetCurrentNode());
  3890. SelectAllFramesForContent(inneriter, content, aSelect);
  3891. }
  3892. // We must now do the last one if it is not the same as the first
  3893. if (aRange->GetEndParent() != aRange->GetStartParent()) {
  3894. nsresult res;
  3895. content = do_QueryInterface(aRange->GetEndParent(), &res);
  3896. NS_ENSURE_SUCCESS(res, res);
  3897. NS_ENSURE_TRUE(content, res);
  3898. if (content->IsNodeOfType(nsINode::eTEXT)) {
  3899. nsIFrame* frame = content->GetPrimaryFrame();
  3900. // The frame could be an SVG text frame, in which case we'll ignore it.
  3901. if (frame && frame->GetType() == nsGkAtoms::textFrame) {
  3902. nsTextFrame* textFrame = static_cast<nsTextFrame*>(frame);
  3903. textFrame->SetSelectedRange(0, aRange->EndOffset(), aSelect,
  3904. mSelectionType);
  3905. }
  3906. }
  3907. }
  3908. return NS_OK;
  3909. }
  3910. // Selection::LookUpSelection
  3911. //
  3912. // This function is called when a node wants to know where the selection is
  3913. // over itself.
  3914. //
  3915. // Usually, this is called when we already know there is a selection over
  3916. // the node in question, and we only need to find the boundaries of it on
  3917. // that node. This is when slowCheck is false--a strict test is not needed.
  3918. // Other times, the caller has no idea, and wants us to test everything,
  3919. // so we are supposed to determine whether there is a selection over the
  3920. // node at all.
  3921. //
  3922. // A previous version of this code used this flag to do less work when
  3923. // inclusion was already known (slowCheck=false). However, our tree
  3924. // structure allows us to quickly determine ranges overlapping the node,
  3925. // so we just ignore the slowCheck flag and do the full test every time.
  3926. //
  3927. // PERFORMANCE: a common case is that we are doing a fast check with exactly
  3928. // one range in the selection. In this case, this function is slower than
  3929. // brute force because of the overhead of checking the tree. We can optimize
  3930. // this case to make it faster by doing the same thing the previous version
  3931. // of this function did in the case of 1 range. This would also mean that
  3932. // the aSlowCheck flag would have meaning again.
  3933. NS_IMETHODIMP
  3934. Selection::LookUpSelection(nsIContent* aContent, int32_t aContentOffset,
  3935. int32_t aContentLength,
  3936. SelectionDetails** aReturnDetails,
  3937. SelectionType aSelectionType,
  3938. bool aSlowCheck)
  3939. {
  3940. nsresult rv;
  3941. if (!aContent || ! aReturnDetails)
  3942. return NS_ERROR_NULL_POINTER;
  3943. // it is common to have no ranges, to optimize that
  3944. if (mRanges.Length() == 0)
  3945. return NS_OK;
  3946. nsTArray<nsRange*> overlappingRanges;
  3947. rv = GetRangesForIntervalArray(aContent, aContentOffset,
  3948. aContent, aContentOffset + aContentLength,
  3949. false,
  3950. &overlappingRanges);
  3951. NS_ENSURE_SUCCESS(rv, rv);
  3952. if (overlappingRanges.Length() == 0)
  3953. return NS_OK;
  3954. for (uint32_t i = 0; i < overlappingRanges.Length(); i++) {
  3955. nsRange* range = overlappingRanges[i];
  3956. nsINode* startNode = range->GetStartParent();
  3957. nsINode* endNode = range->GetEndParent();
  3958. int32_t startOffset = range->StartOffset();
  3959. int32_t endOffset = range->EndOffset();
  3960. int32_t start = -1, end = -1;
  3961. if (startNode == aContent && endNode == aContent) {
  3962. if (startOffset < (aContentOffset + aContentLength) &&
  3963. endOffset > aContentOffset) {
  3964. // this range is totally inside the requested content range
  3965. start = std::max(0, startOffset - aContentOffset);
  3966. end = std::min(aContentLength, endOffset - aContentOffset);
  3967. }
  3968. // otherwise, range is inside the requested node, but does not intersect
  3969. // the requested content range, so ignore it
  3970. } else if (startNode == aContent) {
  3971. if (startOffset < (aContentOffset + aContentLength)) {
  3972. // the beginning of the range is inside the requested node, but the
  3973. // end is outside, select everything from there to the end
  3974. start = std::max(0, startOffset - aContentOffset);
  3975. end = aContentLength;
  3976. }
  3977. } else if (endNode == aContent) {
  3978. if (endOffset > aContentOffset) {
  3979. // the end of the range is inside the requested node, but the beginning
  3980. // is outside, select everything from the beginning to there
  3981. start = 0;
  3982. end = std::min(aContentLength, endOffset - aContentOffset);
  3983. }
  3984. } else {
  3985. // this range does not begin or end in the requested node, but since
  3986. // GetRangesForInterval returned this range, we know it overlaps.
  3987. // Therefore, this node is enclosed in the range, and we select all
  3988. // of it.
  3989. start = 0;
  3990. end = aContentLength;
  3991. }
  3992. if (start < 0)
  3993. continue; // the ranges do not overlap the input range
  3994. SelectionDetails* details = new SelectionDetails;
  3995. details->mNext = *aReturnDetails;
  3996. details->mStart = start;
  3997. details->mEnd = end;
  3998. details->mSelectionType = aSelectionType;
  3999. RangeData *rd = FindRangeData(range);
  4000. if (rd) {
  4001. details->mTextRangeStyle = rd->mTextRangeStyle;
  4002. }
  4003. *aReturnDetails = details;
  4004. }
  4005. return NS_OK;
  4006. }
  4007. NS_IMETHODIMP
  4008. Selection::Repaint(nsPresContext* aPresContext)
  4009. {
  4010. int32_t arrCount = (int32_t)mRanges.Length();
  4011. if (arrCount < 1)
  4012. return NS_OK;
  4013. int32_t i;
  4014. for (i = 0; i < arrCount; i++)
  4015. {
  4016. nsresult rv = selectFrames(aPresContext, mRanges[i].mRange, true);
  4017. if (NS_FAILED(rv)) {
  4018. return rv;
  4019. }
  4020. }
  4021. return NS_OK;
  4022. }
  4023. NS_IMETHODIMP
  4024. Selection::GetCanCacheFrameOffset(bool* aCanCacheFrameOffset)
  4025. {
  4026. NS_ENSURE_ARG_POINTER(aCanCacheFrameOffset);
  4027. if (mCachedOffsetForFrame)
  4028. *aCanCacheFrameOffset = mCachedOffsetForFrame->mCanCacheFrameOffset;
  4029. else
  4030. *aCanCacheFrameOffset = false;
  4031. return NS_OK;
  4032. }
  4033. NS_IMETHODIMP
  4034. Selection::SetCanCacheFrameOffset(bool aCanCacheFrameOffset)
  4035. {
  4036. if (!mCachedOffsetForFrame) {
  4037. mCachedOffsetForFrame = new CachedOffsetForFrame;
  4038. }
  4039. mCachedOffsetForFrame->mCanCacheFrameOffset = aCanCacheFrameOffset;
  4040. // clean up cached frame when turn off cache
  4041. // fix bug 207936
  4042. if (!aCanCacheFrameOffset) {
  4043. mCachedOffsetForFrame->mLastCaretFrame = nullptr;
  4044. }
  4045. return NS_OK;
  4046. }
  4047. NS_IMETHODIMP
  4048. Selection::GetCachedFrameOffset(nsIFrame* aFrame, int32_t inOffset,
  4049. nsPoint& aPoint)
  4050. {
  4051. if (!mCachedOffsetForFrame) {
  4052. mCachedOffsetForFrame = new CachedOffsetForFrame;
  4053. }
  4054. nsresult rv = NS_OK;
  4055. if (mCachedOffsetForFrame->mCanCacheFrameOffset &&
  4056. mCachedOffsetForFrame->mLastCaretFrame &&
  4057. (aFrame == mCachedOffsetForFrame->mLastCaretFrame) &&
  4058. (inOffset == mCachedOffsetForFrame->mLastContentOffset))
  4059. {
  4060. // get cached frame offset
  4061. aPoint = mCachedOffsetForFrame->mCachedFrameOffset;
  4062. }
  4063. else
  4064. {
  4065. // Recalculate frame offset and cache it. Don't cache a frame offset if
  4066. // GetPointFromOffset fails, though.
  4067. rv = aFrame->GetPointFromOffset(inOffset, &aPoint);
  4068. if (NS_SUCCEEDED(rv) && mCachedOffsetForFrame->mCanCacheFrameOffset) {
  4069. mCachedOffsetForFrame->mCachedFrameOffset = aPoint;
  4070. mCachedOffsetForFrame->mLastCaretFrame = aFrame;
  4071. mCachedOffsetForFrame->mLastContentOffset = inOffset;
  4072. }
  4073. }
  4074. return rv;
  4075. }
  4076. NS_IMETHODIMP
  4077. Selection::GetAncestorLimiter(nsIContent** aContent)
  4078. {
  4079. if (mFrameSelection) {
  4080. nsCOMPtr<nsIContent> c = mFrameSelection->GetAncestorLimiter();
  4081. c.forget(aContent);
  4082. }
  4083. return NS_OK;
  4084. }
  4085. NS_IMETHODIMP
  4086. Selection::SetAncestorLimiter(nsIContent* aContent)
  4087. {
  4088. if (mFrameSelection) {
  4089. RefPtr<nsFrameSelection> frameSelection = mFrameSelection;
  4090. frameSelection->SetAncestorLimiter(aContent);
  4091. }
  4092. return NS_OK;
  4093. }
  4094. RangeData*
  4095. Selection::FindRangeData(nsIDOMRange* aRange)
  4096. {
  4097. NS_ENSURE_TRUE(aRange, nullptr);
  4098. for (uint32_t i = 0; i < mRanges.Length(); i++) {
  4099. if (mRanges[i].mRange == aRange)
  4100. return &mRanges[i];
  4101. }
  4102. return nullptr;
  4103. }
  4104. NS_IMETHODIMP
  4105. Selection::SetTextRangeStyle(nsIDOMRange* aRange,
  4106. const TextRangeStyle& aTextRangeStyle)
  4107. {
  4108. NS_ENSURE_ARG_POINTER(aRange);
  4109. RangeData *rd = FindRangeData(aRange);
  4110. if (rd) {
  4111. rd->mTextRangeStyle = aTextRangeStyle;
  4112. }
  4113. return NS_OK;
  4114. }
  4115. nsresult
  4116. Selection::StartAutoScrollTimer(nsIFrame* aFrame, nsPoint& aPoint,
  4117. uint32_t aDelay)
  4118. {
  4119. NS_PRECONDITION(aFrame, "Need a frame");
  4120. nsresult result;
  4121. if (!mFrameSelection)
  4122. return NS_OK;//nothing to do
  4123. if (!mAutoScrollTimer)
  4124. {
  4125. mAutoScrollTimer = new nsAutoScrollTimer();
  4126. result = mAutoScrollTimer->Init(mFrameSelection, this);
  4127. if (NS_FAILED(result))
  4128. return result;
  4129. }
  4130. result = mAutoScrollTimer->SetDelay(aDelay);
  4131. if (NS_FAILED(result))
  4132. return result;
  4133. return DoAutoScroll(aFrame, aPoint);
  4134. }
  4135. nsresult
  4136. Selection::StopAutoScrollTimer()
  4137. {
  4138. if (mAutoScrollTimer) {
  4139. return mAutoScrollTimer->Stop();
  4140. }
  4141. return NS_OK;
  4142. }
  4143. nsresult
  4144. Selection::DoAutoScroll(nsIFrame* aFrame, nsPoint& aPoint)
  4145. {
  4146. NS_PRECONDITION(aFrame, "Need a frame");
  4147. if (mAutoScrollTimer)
  4148. (void)mAutoScrollTimer->Stop();
  4149. nsPresContext* presContext = aFrame->PresContext();
  4150. nsCOMPtr<nsIPresShell> shell = presContext->PresShell();
  4151. nsRootPresContext* rootPC = presContext->GetRootPresContext();
  4152. if (!rootPC)
  4153. return NS_OK;
  4154. nsIFrame* rootmostFrame = rootPC->PresShell()->FrameManager()->GetRootFrame();
  4155. nsWeakFrame weakRootFrame(rootmostFrame);
  4156. nsWeakFrame weakFrame(aFrame);
  4157. // Get the point relative to the root most frame because the scroll we are
  4158. // about to do will change the coordinates of aFrame.
  4159. nsPoint globalPoint = aPoint + aFrame->GetOffsetToCrossDoc(rootmostFrame);
  4160. bool done = false;
  4161. bool didScroll;
  4162. while (true) {
  4163. didScroll = shell->ScrollFrameRectIntoView(
  4164. aFrame, nsRect(aPoint, nsSize(0, 0)),
  4165. nsIPresShell::ScrollAxis(), nsIPresShell::ScrollAxis(),
  4166. 0);
  4167. if (!weakFrame || !weakRootFrame) {
  4168. return NS_OK;
  4169. }
  4170. if (!didScroll && !done) {
  4171. // If aPoint is at the screen edge then try to scroll anyway, once.
  4172. RefPtr<nsDeviceContext> dx = shell->GetViewManager()->GetDeviceContext();
  4173. nsRect screen;
  4174. dx->GetRect(screen);
  4175. nsPoint screenPoint = globalPoint +
  4176. rootmostFrame->GetScreenRectInAppUnits().TopLeft();
  4177. nscoord onePx = nsPresContext::AppUnitsPerCSSPixel();
  4178. nscoord scrollAmount = 10 * onePx;
  4179. if (std::abs(screen.x - screenPoint.x) <= onePx) {
  4180. aPoint.x -= scrollAmount;
  4181. } else if (std::abs(screen.XMost() - screenPoint.x) <= onePx) {
  4182. aPoint.x += scrollAmount;
  4183. } else if (std::abs(screen.y - screenPoint.y) <= onePx) {
  4184. aPoint.y -= scrollAmount;
  4185. } else if (std::abs(screen.YMost() - screenPoint.y) <= onePx) {
  4186. aPoint.y += scrollAmount;
  4187. } else {
  4188. break;
  4189. }
  4190. done = true;
  4191. continue;
  4192. }
  4193. break;
  4194. }
  4195. // Start the AutoScroll timer if necessary.
  4196. if (didScroll && mAutoScrollTimer) {
  4197. nsPoint presContextPoint = globalPoint -
  4198. shell->FrameManager()->GetRootFrame()->GetOffsetToCrossDoc(rootmostFrame);
  4199. mAutoScrollTimer->Start(presContext, presContextPoint);
  4200. }
  4201. return NS_OK;
  4202. }
  4203. /** RemoveAllRanges zeroes the selection
  4204. */
  4205. NS_IMETHODIMP
  4206. Selection::RemoveAllRanges()
  4207. {
  4208. ErrorResult result;
  4209. RemoveAllRanges(result);
  4210. return result.StealNSResult();
  4211. }
  4212. void
  4213. Selection::RemoveAllRanges(ErrorResult& aRv)
  4214. {
  4215. if (!mFrameSelection)
  4216. return; // nothing to do
  4217. RefPtr<nsPresContext> presContext = GetPresContext();
  4218. nsresult result = Clear(presContext);
  4219. if (NS_FAILED(result)) {
  4220. aRv.Throw(result);
  4221. return;
  4222. }
  4223. // Turn off signal for table selection
  4224. RefPtr<nsFrameSelection> frameSelection = mFrameSelection;
  4225. frameSelection->ClearTableCellSelection();
  4226. result = frameSelection->NotifySelectionListeners(GetType());
  4227. // Also need to notify the frames!
  4228. // PresShell::CharacterDataChanged should do that on DocumentChanged
  4229. if (NS_FAILED(result)) {
  4230. aRv.Throw(result);
  4231. }
  4232. }
  4233. /** AddRange adds the specified range to the selection
  4234. * @param aRange is the range to be added
  4235. */
  4236. NS_IMETHODIMP
  4237. Selection::AddRange(nsIDOMRange* aDOMRange)
  4238. {
  4239. if (!aDOMRange) {
  4240. return NS_ERROR_NULL_POINTER;
  4241. }
  4242. nsRange* range = static_cast<nsRange*>(aDOMRange);
  4243. ErrorResult result;
  4244. AddRange(*range, result);
  4245. return result.StealNSResult();
  4246. }
  4247. void
  4248. Selection::AddRange(nsRange& aRange, ErrorResult& aRv)
  4249. {
  4250. return AddRangeInternal(aRange, GetParentObject(), aRv);
  4251. }
  4252. void
  4253. Selection::AddRangeInternal(nsRange& aRange, nsIDocument* aDocument,
  4254. ErrorResult& aRv)
  4255. {
  4256. nsINode* rangeRoot = aRange.GetRoot();
  4257. if (aDocument != rangeRoot && (!rangeRoot ||
  4258. aDocument != rangeRoot->GetComposedDoc())) {
  4259. // http://w3c.github.io/selection-api/#dom-selection-addrange
  4260. // "... if the root of the range's boundary points are the document
  4261. // associated with context object. Otherwise, this method must do nothing."
  4262. return;
  4263. }
  4264. // This inserts a table cell range in proper document order
  4265. // and returns NS_OK if range doesn't contain just one table cell
  4266. bool didAddRange;
  4267. int32_t rangeIndex;
  4268. nsresult result = addTableCellRange(&aRange, &didAddRange, &rangeIndex);
  4269. if (NS_FAILED(result)) {
  4270. aRv.Throw(result);
  4271. return;
  4272. }
  4273. if (!didAddRange) {
  4274. result = AddItem(&aRange, &rangeIndex);
  4275. if (NS_FAILED(result)) {
  4276. aRv.Throw(result);
  4277. return;
  4278. }
  4279. }
  4280. if (rangeIndex < 0) {
  4281. return;
  4282. }
  4283. setAnchorFocusRange(rangeIndex);
  4284. // Make sure the caret appears on the next line, if at a newline
  4285. if (mSelectionType == SelectionType::eNormal) {
  4286. SetInterlinePosition(true);
  4287. }
  4288. RefPtr<nsPresContext> presContext = GetPresContext();
  4289. selectFrames(presContext, &aRange, true);
  4290. if (!mFrameSelection)
  4291. return;//nothing to do
  4292. RefPtr<nsFrameSelection> frameSelection = mFrameSelection;
  4293. result = frameSelection->NotifySelectionListeners(GetType());
  4294. if (NS_FAILED(result)) {
  4295. aRv.Throw(result);
  4296. }
  4297. }
  4298. // Selection::RemoveRange
  4299. //
  4300. // Removes the given range from the selection. The tricky part is updating
  4301. // the flags on the frames that indicate whether they have a selection or
  4302. // not. There could be several selection ranges on the frame, and clearing
  4303. // the bit would cause the selection to not be drawn, even when there is
  4304. // another range on the frame (bug 346185).
  4305. //
  4306. // We therefore find any ranges that intersect the same nodes as the range
  4307. // being removed, and cause them to set the selected bits back on their
  4308. // selected frames after we've cleared the bit from ours.
  4309. nsresult
  4310. Selection::RemoveRange(nsIDOMRange* aDOMRange)
  4311. {
  4312. if (!aDOMRange) {
  4313. return NS_ERROR_INVALID_ARG;
  4314. }
  4315. nsRange* range = static_cast<nsRange*>(aDOMRange);
  4316. ErrorResult result;
  4317. RemoveRange(*range, result);
  4318. return result.StealNSResult();
  4319. }
  4320. void
  4321. Selection::RemoveRange(nsRange& aRange, ErrorResult& aRv)
  4322. {
  4323. nsresult rv = RemoveItem(&aRange);
  4324. if (NS_FAILED(rv)) {
  4325. aRv.Throw(rv);
  4326. return;
  4327. }
  4328. nsINode* beginNode = aRange.GetStartParent();
  4329. nsINode* endNode = aRange.GetEndParent();
  4330. if (!beginNode || !endNode) {
  4331. // Detached range; nothing else to do here.
  4332. return;
  4333. }
  4334. // find out the length of the end node, so we can select all of it
  4335. int32_t beginOffset, endOffset;
  4336. if (endNode->IsNodeOfType(nsINode::eTEXT)) {
  4337. // Get the length of the text. We can't just use the offset because
  4338. // another range could be touching this text node but not intersect our
  4339. // range.
  4340. beginOffset = 0;
  4341. endOffset = static_cast<nsIContent*>(endNode)->TextLength();
  4342. } else {
  4343. // For non-text nodes, the given offsets should be sufficient.
  4344. beginOffset = aRange.StartOffset();
  4345. endOffset = aRange.EndOffset();
  4346. }
  4347. // clear the selected bit from the removed range's frames
  4348. RefPtr<nsPresContext> presContext = GetPresContext();
  4349. selectFrames(presContext, &aRange, false);
  4350. // add back the selected bit for each range touching our nodes
  4351. nsTArray<nsRange*> affectedRanges;
  4352. rv = GetRangesForIntervalArray(beginNode, beginOffset,
  4353. endNode, endOffset,
  4354. true, &affectedRanges);
  4355. if (NS_FAILED(rv)) {
  4356. aRv.Throw(rv);
  4357. return;
  4358. }
  4359. for (uint32_t i = 0; i < affectedRanges.Length(); i++) {
  4360. selectFrames(presContext, affectedRanges[i], true);
  4361. }
  4362. int32_t cnt = mRanges.Length();
  4363. if (&aRange == mAnchorFocusRange) {
  4364. // Reset anchor to LAST range or clear it if there are no ranges.
  4365. setAnchorFocusRange(cnt - 1);
  4366. // When the selection is user-created it makes sense to scroll the range
  4367. // into view. The spell-check selection, however, is created and destroyed
  4368. // in the background. We don't want to scroll in this case or the view
  4369. // might appear to be moving randomly (bug 337871).
  4370. if (mSelectionType != SelectionType::eSpellCheck && cnt > 0) {
  4371. ScrollIntoView(nsISelectionController::SELECTION_FOCUS_REGION);
  4372. }
  4373. }
  4374. if (!mFrameSelection)
  4375. return;//nothing to do
  4376. RefPtr<nsFrameSelection> frameSelection = mFrameSelection;
  4377. rv = frameSelection->NotifySelectionListeners(GetType());
  4378. if (NS_FAILED(rv)) {
  4379. aRv.Throw(rv);
  4380. }
  4381. }
  4382. /*
  4383. * Collapse sets the whole selection to be one point.
  4384. */
  4385. NS_IMETHODIMP
  4386. Selection::Collapse(nsIDOMNode* aParentNode, int32_t aOffset)
  4387. {
  4388. nsCOMPtr<nsINode> parentNode = do_QueryInterface(aParentNode);
  4389. return Collapse(parentNode, aOffset);
  4390. }
  4391. NS_IMETHODIMP
  4392. Selection::CollapseNative(nsINode* aParentNode, int32_t aOffset)
  4393. {
  4394. return Collapse(aParentNode, aOffset);
  4395. }
  4396. nsresult
  4397. Selection::Collapse(nsINode* aParentNode, int32_t aOffset)
  4398. {
  4399. if (!aParentNode)
  4400. return NS_ERROR_INVALID_ARG;
  4401. ErrorResult result;
  4402. Collapse(*aParentNode, static_cast<uint32_t>(aOffset), result);
  4403. return result.StealNSResult();
  4404. }
  4405. void
  4406. Selection::Collapse(nsINode& aParentNode, uint32_t aOffset, ErrorResult& aRv)
  4407. {
  4408. if (!mFrameSelection) {
  4409. aRv.Throw(NS_ERROR_NOT_INITIALIZED); // Can't do selection
  4410. return;
  4411. }
  4412. nsCOMPtr<nsINode> parentNode = &aParentNode;
  4413. RefPtr<nsFrameSelection> frameSelection = mFrameSelection;
  4414. frameSelection->InvalidateDesiredPos();
  4415. if (!IsValidSelectionPoint(frameSelection, parentNode)) {
  4416. aRv.Throw(NS_ERROR_FAILURE);
  4417. return;
  4418. }
  4419. nsresult result;
  4420. RefPtr<nsPresContext> presContext = GetPresContext();
  4421. if (!presContext || presContext->Document() != parentNode->OwnerDoc()) {
  4422. aRv.Throw(NS_ERROR_FAILURE);
  4423. return;
  4424. }
  4425. // Delete all of the current ranges
  4426. Clear(presContext);
  4427. // Turn off signal for table selection
  4428. frameSelection->ClearTableCellSelection();
  4429. // Hack to display the caret on the right line (bug 1237236).
  4430. if (frameSelection->GetHint() != CARET_ASSOCIATE_AFTER &&
  4431. parentNode->IsContent()) {
  4432. int32_t frameOffset;
  4433. nsTextFrame* f =
  4434. do_QueryFrame(nsCaret::GetFrameAndOffset(this, parentNode,
  4435. aOffset, &frameOffset));
  4436. if (f && f->IsAtEndOfLine() && f->HasSignificantTerminalNewline()) {
  4437. if ((parentNode->AsContent() == f->GetContent() &&
  4438. f->GetContentEnd() == int32_t(aOffset)) ||
  4439. (parentNode == f->GetContent()->GetParentNode() &&
  4440. parentNode->IndexOf(f->GetContent()) + 1 == int32_t(aOffset))) {
  4441. frameSelection->SetHint(CARET_ASSOCIATE_AFTER);
  4442. }
  4443. }
  4444. }
  4445. RefPtr<nsRange> range = new nsRange(parentNode);
  4446. result = range->CollapseTo(parentNode, aOffset);
  4447. if (NS_FAILED(result)) {
  4448. aRv.Throw(result);
  4449. return;
  4450. }
  4451. #ifdef DEBUG_SELECTION
  4452. nsCOMPtr<nsIContent> content = do_QueryInterface(parentNode);
  4453. nsCOMPtr<nsIDocument> doc = do_QueryInterface(parentNode);
  4454. printf ("Sel. Collapse to %p %s %d\n", parentNode.get(),
  4455. content ? nsAtomCString(content->NodeInfo()->NameAtom()).get()
  4456. : (doc ? "DOCUMENT" : "???"),
  4457. aOffset);
  4458. #endif
  4459. int32_t rangeIndex = -1;
  4460. result = AddItem(range, &rangeIndex);
  4461. if (NS_FAILED(result)) {
  4462. aRv.Throw(result);
  4463. return;
  4464. }
  4465. setAnchorFocusRange(0);
  4466. selectFrames(presContext, range, true);
  4467. result = frameSelection->NotifySelectionListeners(GetType());
  4468. if (NS_FAILED(result)) {
  4469. aRv.Throw(result);
  4470. }
  4471. }
  4472. /*
  4473. * Sets the whole selection to be one point
  4474. * at the start of the current selection
  4475. */
  4476. NS_IMETHODIMP
  4477. Selection::CollapseToStart()
  4478. {
  4479. ErrorResult result;
  4480. CollapseToStart(result);
  4481. return result.StealNSResult();
  4482. }
  4483. void
  4484. Selection::CollapseToStart(ErrorResult& aRv)
  4485. {
  4486. int32_t cnt;
  4487. nsresult rv = GetRangeCount(&cnt);
  4488. if (NS_FAILED(rv) || cnt <= 0) {
  4489. aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
  4490. return;
  4491. }
  4492. // Get the first range
  4493. nsRange* firstRange = mRanges[0].mRange;
  4494. if (!firstRange) {
  4495. aRv.Throw(NS_ERROR_FAILURE);
  4496. return;
  4497. }
  4498. if (mFrameSelection) {
  4499. int16_t reason = mFrameSelection->PopReason() | nsISelectionListener::COLLAPSETOSTART_REASON;
  4500. mFrameSelection->PostReason(reason);
  4501. }
  4502. nsINode* parent = firstRange->GetStartParent();
  4503. if (!parent) {
  4504. aRv.Throw(NS_ERROR_FAILURE);
  4505. return;
  4506. }
  4507. Collapse(*parent, firstRange->StartOffset(), aRv);
  4508. }
  4509. /*
  4510. * Sets the whole selection to be one point
  4511. * at the end of the current selection
  4512. */
  4513. NS_IMETHODIMP
  4514. Selection::CollapseToEnd()
  4515. {
  4516. ErrorResult result;
  4517. CollapseToEnd(result);
  4518. return result.StealNSResult();
  4519. }
  4520. void
  4521. Selection::CollapseToEnd(ErrorResult& aRv)
  4522. {
  4523. int32_t cnt;
  4524. nsresult rv = GetRangeCount(&cnt);
  4525. if (NS_FAILED(rv) || cnt <= 0) {
  4526. aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
  4527. return;
  4528. }
  4529. // Get the last range
  4530. nsRange* lastRange = mRanges[cnt - 1].mRange;
  4531. if (!lastRange) {
  4532. aRv.Throw(NS_ERROR_FAILURE);
  4533. return;
  4534. }
  4535. if (mFrameSelection) {
  4536. int16_t reason = mFrameSelection->PopReason() | nsISelectionListener::COLLAPSETOEND_REASON;
  4537. mFrameSelection->PostReason(reason);
  4538. }
  4539. nsINode* parent = lastRange->GetEndParent();
  4540. if (!parent) {
  4541. aRv.Throw(NS_ERROR_FAILURE);
  4542. return;
  4543. }
  4544. Collapse(*parent, lastRange->EndOffset(), aRv);
  4545. }
  4546. /*
  4547. * IsCollapsed -- is the whole selection just one point, or unset?
  4548. */
  4549. bool
  4550. Selection::IsCollapsed() const
  4551. {
  4552. uint32_t cnt = mRanges.Length();
  4553. if (cnt == 0) {
  4554. return true;
  4555. }
  4556. if (cnt != 1) {
  4557. return false;
  4558. }
  4559. return mRanges[0].mRange->Collapsed();
  4560. }
  4561. /* virtual */
  4562. bool
  4563. Selection::Collapsed()
  4564. {
  4565. return IsCollapsed();
  4566. }
  4567. NS_IMETHODIMP
  4568. Selection::GetIsCollapsed(bool* aIsCollapsed)
  4569. {
  4570. NS_ENSURE_TRUE(aIsCollapsed, NS_ERROR_NULL_POINTER);
  4571. *aIsCollapsed = IsCollapsed();
  4572. return NS_OK;
  4573. }
  4574. NS_IMETHODIMP
  4575. Selection::GetRangeCount(int32_t* aRangeCount)
  4576. {
  4577. *aRangeCount = (int32_t)RangeCount();
  4578. return NS_OK;
  4579. }
  4580. void
  4581. Selection::GetType(nsAString& aOutType) const
  4582. {
  4583. if (!RangeCount()) {
  4584. aOutType.AssignLiteral("None");
  4585. } else if (IsCollapsed()) {
  4586. aOutType.AssignLiteral("Caret");
  4587. } else {
  4588. aOutType.AssignLiteral("Range");
  4589. }
  4590. }
  4591. NS_IMETHODIMP
  4592. Selection::GetRangeAt(int32_t aIndex, nsIDOMRange** aReturn)
  4593. {
  4594. ErrorResult result;
  4595. *aReturn = GetRangeAt(aIndex, result);
  4596. NS_IF_ADDREF(*aReturn);
  4597. return result.StealNSResult();
  4598. }
  4599. nsRange*
  4600. Selection::GetRangeAt(uint32_t aIndex, ErrorResult& aRv)
  4601. {
  4602. nsRange* range = GetRangeAt(aIndex);
  4603. if (!range) {
  4604. aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
  4605. return nullptr;
  4606. }
  4607. return range;
  4608. }
  4609. nsRange*
  4610. Selection::GetRangeAt(int32_t aIndex) const
  4611. {
  4612. RangeData empty(nullptr);
  4613. return mRanges.SafeElementAt(aIndex, empty).mRange;
  4614. }
  4615. /*
  4616. utility function
  4617. */
  4618. nsresult
  4619. Selection::SetAnchorFocusToRange(nsRange* aRange)
  4620. {
  4621. NS_ENSURE_STATE(mAnchorFocusRange);
  4622. bool collapsed = Collapsed();
  4623. nsresult res = RemoveItem(mAnchorFocusRange);
  4624. if (NS_FAILED(res))
  4625. return res;
  4626. int32_t aOutIndex = -1;
  4627. res = AddItem(aRange, &aOutIndex, !collapsed);
  4628. if (NS_FAILED(res))
  4629. return res;
  4630. setAnchorFocusRange(aOutIndex);
  4631. return NS_OK;
  4632. }
  4633. void
  4634. Selection::ReplaceAnchorFocusRange(nsRange* aRange)
  4635. {
  4636. NS_ENSURE_TRUE_VOID(mAnchorFocusRange);
  4637. RefPtr<nsPresContext> presContext = GetPresContext();
  4638. if (presContext) {
  4639. selectFrames(presContext, mAnchorFocusRange, false);
  4640. SetAnchorFocusToRange(aRange);
  4641. selectFrames(presContext, mAnchorFocusRange, true);
  4642. }
  4643. }
  4644. void
  4645. Selection::AdjustAnchorFocusForMultiRange(nsDirection aDirection)
  4646. {
  4647. if (aDirection == mDirection) {
  4648. return;
  4649. }
  4650. SetDirection(aDirection);
  4651. if (RangeCount() <= 1) {
  4652. return;
  4653. }
  4654. nsRange* firstRange = GetRangeAt(0);
  4655. nsRange* lastRange = GetRangeAt(RangeCount() - 1);
  4656. if (mDirection == eDirPrevious) {
  4657. firstRange->SetIsGenerated(false);
  4658. lastRange->SetIsGenerated(true);
  4659. setAnchorFocusRange(0);
  4660. } else { // aDir == eDirNext
  4661. firstRange->SetIsGenerated(true);
  4662. lastRange->SetIsGenerated(false);
  4663. setAnchorFocusRange(RangeCount() - 1);
  4664. }
  4665. }
  4666. /*
  4667. Notes which might come in handy for extend:
  4668. We can tell the direction of the selection by asking for the anchors selection
  4669. if the begin is less than the end then we know the selection is to the "right".
  4670. else it is a backwards selection.
  4671. a = anchor
  4672. 1 = old cursor
  4673. 2 = new cursor
  4674. if (a <= 1 && 1 <=2) a,1,2 or (a1,2)
  4675. if (a < 2 && 1 > 2) a,2,1
  4676. if (1 < a && a <2) 1,a,2
  4677. if (a > 2 && 2 >1) 1,2,a
  4678. if (2 < a && a <1) 2,a,1
  4679. if (a > 1 && 1 >2) 2,1,a
  4680. then execute
  4681. a 1 2 select from 1 to 2
  4682. a 2 1 deselect from 2 to 1
  4683. 1 a 2 deselect from 1 to a select from a to 2
  4684. 1 2 a deselect from 1 to 2
  4685. 2 1 a = continue selection from 2 to 1
  4686. */
  4687. /*
  4688. * Extend extends the selection away from the anchor.
  4689. * We don't need to know the direction, because we always change the focus.
  4690. */
  4691. NS_IMETHODIMP
  4692. Selection::Extend(nsIDOMNode* aParentNode, int32_t aOffset)
  4693. {
  4694. nsCOMPtr<nsINode> parentNode = do_QueryInterface(aParentNode);
  4695. return Extend(parentNode, aOffset);
  4696. }
  4697. NS_IMETHODIMP
  4698. Selection::ExtendNative(nsINode* aParentNode, int32_t aOffset)
  4699. {
  4700. return Extend(aParentNode, aOffset);
  4701. }
  4702. nsresult
  4703. Selection::Extend(nsINode* aParentNode, int32_t aOffset)
  4704. {
  4705. if (!aParentNode)
  4706. return NS_ERROR_INVALID_ARG;
  4707. ErrorResult result;
  4708. Extend(*aParentNode, static_cast<uint32_t>(aOffset), result);
  4709. return result.StealNSResult();
  4710. }
  4711. void
  4712. Selection::Extend(nsINode& aParentNode, uint32_t aOffset, ErrorResult& aRv)
  4713. {
  4714. // First, find the range containing the old focus point:
  4715. if (!mAnchorFocusRange) {
  4716. aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
  4717. return;
  4718. }
  4719. if (!mFrameSelection) {
  4720. aRv.Throw(NS_ERROR_NOT_INITIALIZED); // Can't do selection
  4721. return;
  4722. }
  4723. nsresult res;
  4724. if (!IsValidSelectionPoint(mFrameSelection, &aParentNode)) {
  4725. aRv.Throw(NS_ERROR_FAILURE);
  4726. return;
  4727. }
  4728. RefPtr<nsPresContext> presContext = GetPresContext();
  4729. if (!presContext || presContext->Document() != aParentNode.OwnerDoc()) {
  4730. aRv.Throw(NS_ERROR_FAILURE);
  4731. return;
  4732. }
  4733. #ifdef DEBUG_SELECTION
  4734. nsDirection oldDirection = GetDirection();
  4735. #endif
  4736. nsINode* anchorNode = GetAnchorNode();
  4737. nsINode* focusNode = GetFocusNode();
  4738. uint32_t anchorOffset = AnchorOffset();
  4739. uint32_t focusOffset = FocusOffset();
  4740. RefPtr<nsRange> range = mAnchorFocusRange->CloneRange();
  4741. nsINode* startNode = range->GetStartParent();
  4742. nsINode* endNode = range->GetEndParent();
  4743. int32_t startOffset = range->StartOffset();
  4744. int32_t endOffset = range->EndOffset();
  4745. //compare anchor to old cursor.
  4746. // We pass |disconnected| to the following ComparePoints calls in order
  4747. // to avoid assertions. ComparePoints returns 1 in the disconnected case
  4748. // and we can end up in various cases below, but it is assumed that in
  4749. // any of the cases we end up, the nsRange implementation will collapse
  4750. // the range to the new point because we can not make a valid range with
  4751. // a disconnected point. This means that whatever range is currently
  4752. // selected will be cleared.
  4753. bool disconnected = false;
  4754. bool shouldClearRange = false;
  4755. int32_t result1 = nsContentUtils::ComparePoints(anchorNode, anchorOffset,
  4756. focusNode, focusOffset,
  4757. &disconnected);
  4758. //compare old cursor to new cursor
  4759. shouldClearRange |= disconnected;
  4760. int32_t result2 = nsContentUtils::ComparePoints(focusNode, focusOffset,
  4761. &aParentNode, aOffset,
  4762. &disconnected);
  4763. //compare anchor to new cursor
  4764. shouldClearRange |= disconnected;
  4765. int32_t result3 = nsContentUtils::ComparePoints(anchorNode, anchorOffset,
  4766. &aParentNode, aOffset,
  4767. &disconnected);
  4768. // If the points are disconnected, the range will be collapsed below,
  4769. // resulting in a range that selects nothing.
  4770. if (shouldClearRange) {
  4771. // Repaint the current range with the selection removed.
  4772. selectFrames(presContext, range, false);
  4773. }
  4774. RefPtr<nsRange> difRange = new nsRange(&aParentNode);
  4775. if ((result1 == 0 && result3 < 0) || (result1 <= 0 && result2 < 0)){//a1,2 a,1,2
  4776. //select from 1 to 2 unless they are collapsed
  4777. range->SetEnd(aParentNode, aOffset, aRv);
  4778. if (aRv.Failed()) {
  4779. return;
  4780. }
  4781. SetDirection(eDirNext);
  4782. res = difRange->SetStartAndEnd(focusNode, focusOffset,
  4783. range->GetEndParent(), range->EndOffset());
  4784. if (NS_FAILED(res)) {
  4785. aRv.Throw(res);
  4786. return;
  4787. }
  4788. selectFrames(presContext, difRange , true);
  4789. res = SetAnchorFocusToRange(range);
  4790. if (NS_FAILED(res)) {
  4791. aRv.Throw(res);
  4792. return;
  4793. }
  4794. }
  4795. else if (result1 == 0 && result3 > 0){//2, a1
  4796. //select from 2 to 1a
  4797. SetDirection(eDirPrevious);
  4798. range->SetStart(aParentNode, aOffset, aRv);
  4799. if (aRv.Failed()) {
  4800. return;
  4801. }
  4802. selectFrames(presContext, range, true);
  4803. res = SetAnchorFocusToRange(range);
  4804. if (NS_FAILED(res)) {
  4805. aRv.Throw(res);
  4806. return;
  4807. }
  4808. }
  4809. else if (result3 <= 0 && result2 >= 0) {//a,2,1 or a2,1 or a,21 or a21
  4810. //deselect from 2 to 1
  4811. res = difRange->SetStartAndEnd(&aParentNode, aOffset,
  4812. focusNode, focusOffset);
  4813. if (NS_FAILED(res)) {
  4814. aRv.Throw(res);
  4815. return;
  4816. }
  4817. range->SetEnd(aParentNode, aOffset, aRv);
  4818. if (aRv.Failed()) {
  4819. return;
  4820. }
  4821. res = SetAnchorFocusToRange(range);
  4822. if (NS_FAILED(res)) {
  4823. aRv.Throw(res);
  4824. return;
  4825. }
  4826. selectFrames(presContext, difRange, false); // deselect now
  4827. difRange->SetEnd(range->GetEndParent(), range->EndOffset());
  4828. selectFrames(presContext, difRange, true); // must reselect last node maybe more
  4829. }
  4830. else if (result1 >= 0 && result3 <= 0) {//1,a,2 or 1a,2 or 1,a2 or 1a2
  4831. if (GetDirection() == eDirPrevious){
  4832. res = range->SetStart(endNode, endOffset);
  4833. if (NS_FAILED(res)) {
  4834. aRv.Throw(res);
  4835. return;
  4836. }
  4837. }
  4838. SetDirection(eDirNext);
  4839. range->SetEnd(aParentNode, aOffset, aRv);
  4840. if (aRv.Failed()) {
  4841. return;
  4842. }
  4843. if (focusNode != anchorNode || focusOffset != anchorOffset) {//if collapsed diff dont do anything
  4844. res = difRange->SetStart(focusNode, focusOffset);
  4845. nsresult tmp = difRange->SetEnd(anchorNode, anchorOffset);
  4846. if (NS_FAILED(tmp)) {
  4847. res = tmp;
  4848. }
  4849. if (NS_FAILED(res)) {
  4850. aRv.Throw(res);
  4851. return;
  4852. }
  4853. res = SetAnchorFocusToRange(range);
  4854. if (NS_FAILED(res)) {
  4855. aRv.Throw(res);
  4856. return;
  4857. }
  4858. //deselect from 1 to a
  4859. selectFrames(presContext, difRange , false);
  4860. }
  4861. else
  4862. {
  4863. res = SetAnchorFocusToRange(range);
  4864. if (NS_FAILED(res)) {
  4865. aRv.Throw(res);
  4866. return;
  4867. }
  4868. }
  4869. //select from a to 2
  4870. selectFrames(presContext, range , true);
  4871. }
  4872. else if (result2 <= 0 && result3 >= 0) {//1,2,a or 12,a or 1,2a or 12a
  4873. //deselect from 1 to 2
  4874. res = difRange->SetStartAndEnd(focusNode, focusOffset,
  4875. &aParentNode, aOffset);
  4876. if (NS_FAILED(res)) {
  4877. aRv.Throw(res);
  4878. return;
  4879. }
  4880. SetDirection(eDirPrevious);
  4881. range->SetStart(aParentNode, aOffset, aRv);
  4882. if (aRv.Failed()) {
  4883. return;
  4884. }
  4885. res = SetAnchorFocusToRange(range);
  4886. if (NS_FAILED(res)) {
  4887. aRv.Throw(res);
  4888. return;
  4889. }
  4890. selectFrames(presContext, difRange , false);
  4891. difRange->SetStart(range->GetStartParent(), range->StartOffset());
  4892. selectFrames(presContext, difRange, true);//must reselect last node
  4893. }
  4894. else if (result3 >= 0 && result1 <= 0) {//2,a,1 or 2a,1 or 2,a1 or 2a1
  4895. if (GetDirection() == eDirNext){
  4896. range->SetEnd(startNode, startOffset);
  4897. }
  4898. SetDirection(eDirPrevious);
  4899. range->SetStart(aParentNode, aOffset, aRv);
  4900. if (aRv.Failed()) {
  4901. return;
  4902. }
  4903. //deselect from a to 1
  4904. if (focusNode != anchorNode || focusOffset!= anchorOffset) {//if collapsed diff dont do anything
  4905. res = difRange->SetStartAndEnd(anchorNode, anchorOffset,
  4906. focusNode, focusOffset);
  4907. nsresult tmp = SetAnchorFocusToRange(range);
  4908. if (NS_FAILED(res)) {
  4909. aRv.Throw(res);
  4910. return;
  4911. }
  4912. selectFrames(presContext, difRange, false);
  4913. }
  4914. else
  4915. {
  4916. res = SetAnchorFocusToRange(range);
  4917. if (NS_FAILED(res)) {
  4918. aRv.Throw(res);
  4919. return;
  4920. }
  4921. }
  4922. //select from 2 to a
  4923. selectFrames(presContext, range , true);
  4924. }
  4925. else if (result2 >= 0 && result1 >= 0) {//2,1,a or 21,a or 2,1a or 21a
  4926. //select from 2 to 1
  4927. range->SetStart(aParentNode, aOffset, aRv);
  4928. if (aRv.Failed()) {
  4929. return;
  4930. }
  4931. SetDirection(eDirPrevious);
  4932. res = difRange->SetStartAndEnd(
  4933. range->GetStartParent(), range->StartOffset(),
  4934. focusNode, focusOffset);
  4935. if (NS_FAILED(res)) {
  4936. aRv.Throw(res);
  4937. return;
  4938. }
  4939. selectFrames(presContext, difRange, true);
  4940. res = SetAnchorFocusToRange(range);
  4941. if (NS_FAILED(res)) {
  4942. aRv.Throw(res);
  4943. return;
  4944. }
  4945. }
  4946. if (mRanges.Length() > 1) {
  4947. for (size_t i = 0; i < mRanges.Length(); ++i) {
  4948. nsRange* range = mRanges[i].mRange;
  4949. MOZ_ASSERT(range->IsInSelection());
  4950. selectFrames(presContext, range, range->IsInSelection());
  4951. }
  4952. }
  4953. DEBUG_OUT_RANGE(range);
  4954. #ifdef DEBUG_SELECTION
  4955. if (GetDirection() != oldDirection) {
  4956. printf(" direction changed to %s\n",
  4957. GetDirection() == eDirNext? "eDirNext":"eDirPrevious");
  4958. }
  4959. nsCOMPtr<nsIContent> content = do_QueryInterface(&aParentNode);
  4960. printf ("Sel. Extend to %p %s %d\n", content.get(),
  4961. nsAtomCString(content->NodeInfo()->NameAtom()).get(), aOffset);
  4962. #endif
  4963. RefPtr<nsFrameSelection> frameSelection = mFrameSelection;
  4964. res = frameSelection->NotifySelectionListeners(GetType());
  4965. if (NS_FAILED(res)) {
  4966. aRv.Throw(res);
  4967. }
  4968. }
  4969. NS_IMETHODIMP
  4970. Selection::SelectAllChildren(nsIDOMNode* aParentNode)
  4971. {
  4972. ErrorResult result;
  4973. nsCOMPtr<nsINode> node = do_QueryInterface(aParentNode);
  4974. NS_ENSURE_TRUE(node, NS_ERROR_INVALID_ARG);
  4975. SelectAllChildren(*node, result);
  4976. return result.StealNSResult();
  4977. }
  4978. void
  4979. Selection::SelectAllChildren(nsINode& aNode, ErrorResult& aRv)
  4980. {
  4981. if (mFrameSelection) {
  4982. mFrameSelection->PostReason(nsISelectionListener::SELECTALL_REASON);
  4983. }
  4984. SelectionBatcher batch(this);
  4985. Collapse(aNode, 0, aRv);
  4986. if (aRv.Failed()) {
  4987. return;
  4988. }
  4989. Extend(aNode, aNode.GetChildCount(), aRv);
  4990. }
  4991. NS_IMETHODIMP
  4992. Selection::ContainsNode(nsIDOMNode* aNode, bool aAllowPartial, bool* aYes)
  4993. {
  4994. if (!aYes) {
  4995. return NS_ERROR_NULL_POINTER;
  4996. }
  4997. *aYes = false;
  4998. nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
  4999. if (!node) {
  5000. return NS_ERROR_NULL_POINTER;
  5001. }
  5002. ErrorResult result;
  5003. *aYes = ContainsNode(*node, aAllowPartial, result);
  5004. return result.StealNSResult();
  5005. }
  5006. bool
  5007. Selection::ContainsNode(nsINode& aNode, bool aAllowPartial, ErrorResult& aRv)
  5008. {
  5009. nsresult rv;
  5010. if (mRanges.Length() == 0) {
  5011. return false;
  5012. }
  5013. // XXXbz this duplicates the GetNodeLength code in nsRange.cpp
  5014. uint32_t nodeLength;
  5015. bool isData = aNode.IsNodeOfType(nsINode::eDATA_NODE);
  5016. if (isData) {
  5017. nodeLength = static_cast<nsIContent&>(aNode).TextLength();
  5018. } else {
  5019. nodeLength = aNode.GetChildCount();
  5020. }
  5021. nsTArray<nsRange*> overlappingRanges;
  5022. rv = GetRangesForIntervalArray(&aNode, 0, &aNode, nodeLength,
  5023. false, &overlappingRanges);
  5024. if (NS_FAILED(rv)) {
  5025. aRv.Throw(rv);
  5026. return false;
  5027. }
  5028. if (overlappingRanges.Length() == 0)
  5029. return false; // no ranges overlap
  5030. // if the caller said partial intersections are OK, we're done
  5031. if (aAllowPartial) {
  5032. return true;
  5033. }
  5034. // text nodes always count as inside
  5035. if (isData) {
  5036. return true;
  5037. }
  5038. // The caller wants to know if the node is entirely within the given range,
  5039. // so we have to check all intersecting ranges.
  5040. for (uint32_t i = 0; i < overlappingRanges.Length(); i++) {
  5041. bool nodeStartsBeforeRange, nodeEndsAfterRange;
  5042. if (NS_SUCCEEDED(nsRange::CompareNodeToRange(&aNode, overlappingRanges[i],
  5043. &nodeStartsBeforeRange,
  5044. &nodeEndsAfterRange))) {
  5045. if (!nodeStartsBeforeRange && !nodeEndsAfterRange) {
  5046. return true;
  5047. }
  5048. }
  5049. }
  5050. return false;
  5051. }
  5052. class PointInRectChecker : public nsLayoutUtils::RectCallback {
  5053. public:
  5054. explicit PointInRectChecker(const nsPoint& aPoint)
  5055. : mPoint(aPoint)
  5056. , mMatchFound(false)
  5057. {
  5058. }
  5059. void AddRect(const nsRect& aRect) override
  5060. {
  5061. mMatchFound = mMatchFound || aRect.Contains(mPoint);
  5062. }
  5063. bool MatchFound()
  5064. {
  5065. return mMatchFound;
  5066. }
  5067. private:
  5068. nsPoint mPoint;
  5069. bool mMatchFound;
  5070. };
  5071. bool
  5072. Selection::ContainsPoint(const nsPoint& aPoint)
  5073. {
  5074. if (IsCollapsed()) {
  5075. return false;
  5076. }
  5077. PointInRectChecker checker(aPoint);
  5078. for (uint32_t i = 0; i < RangeCount(); i++) {
  5079. nsRange* range = GetRangeAt(i);
  5080. nsRange::CollectClientRectsAndText(&checker, nullptr, range,
  5081. range->GetStartParent(), range->StartOffset(),
  5082. range->GetEndParent(), range->EndOffset(),
  5083. true, false);
  5084. if (checker.MatchFound()) {
  5085. return true;
  5086. }
  5087. }
  5088. return false;
  5089. }
  5090. nsPresContext*
  5091. Selection::GetPresContext() const
  5092. {
  5093. nsIPresShell *shell = GetPresShell();
  5094. if (!shell) {
  5095. return nullptr;
  5096. }
  5097. return shell->GetPresContext();
  5098. }
  5099. nsIPresShell*
  5100. Selection::GetPresShell() const
  5101. {
  5102. if (!mFrameSelection)
  5103. return nullptr;//nothing to do
  5104. return mFrameSelection->GetShell();
  5105. }
  5106. nsIFrame *
  5107. Selection::GetSelectionAnchorGeometry(SelectionRegion aRegion, nsRect* aRect)
  5108. {
  5109. if (!mFrameSelection)
  5110. return nullptr; // nothing to do
  5111. NS_ENSURE_TRUE(aRect, nullptr);
  5112. aRect->SetRect(0, 0, 0, 0);
  5113. switch (aRegion) {
  5114. case nsISelectionController::SELECTION_ANCHOR_REGION:
  5115. case nsISelectionController::SELECTION_FOCUS_REGION:
  5116. return GetSelectionEndPointGeometry(aRegion, aRect);
  5117. case nsISelectionController::SELECTION_WHOLE_SELECTION:
  5118. break;
  5119. default:
  5120. return nullptr;
  5121. }
  5122. NS_ASSERTION(aRegion == nsISelectionController::SELECTION_WHOLE_SELECTION,
  5123. "should only be SELECTION_WHOLE_SELECTION here");
  5124. nsRect anchorRect;
  5125. nsIFrame* anchorFrame = GetSelectionEndPointGeometry(
  5126. nsISelectionController::SELECTION_ANCHOR_REGION, &anchorRect);
  5127. if (!anchorFrame)
  5128. return nullptr;
  5129. nsRect focusRect;
  5130. nsIFrame* focusFrame = GetSelectionEndPointGeometry(
  5131. nsISelectionController::SELECTION_FOCUS_REGION, &focusRect);
  5132. if (!focusFrame)
  5133. return nullptr;
  5134. NS_ASSERTION(anchorFrame->PresContext() == focusFrame->PresContext(),
  5135. "points of selection in different documents?");
  5136. // make focusRect relative to anchorFrame
  5137. focusRect += focusFrame->GetOffsetTo(anchorFrame);
  5138. aRect->UnionRectEdges(anchorRect, focusRect);
  5139. return anchorFrame;
  5140. }
  5141. nsIFrame *
  5142. Selection::GetSelectionEndPointGeometry(SelectionRegion aRegion, nsRect* aRect)
  5143. {
  5144. if (!mFrameSelection)
  5145. return nullptr; // nothing to do
  5146. NS_ENSURE_TRUE(aRect, nullptr);
  5147. aRect->SetRect(0, 0, 0, 0);
  5148. nsINode *node = nullptr;
  5149. uint32_t nodeOffset = 0;
  5150. nsIFrame *frame = nullptr;
  5151. switch (aRegion) {
  5152. case nsISelectionController::SELECTION_ANCHOR_REGION:
  5153. node = GetAnchorNode();
  5154. nodeOffset = AnchorOffset();
  5155. break;
  5156. case nsISelectionController::SELECTION_FOCUS_REGION:
  5157. node = GetFocusNode();
  5158. nodeOffset = FocusOffset();
  5159. break;
  5160. default:
  5161. return nullptr;
  5162. }
  5163. if (!node)
  5164. return nullptr;
  5165. nsCOMPtr<nsIContent> content = do_QueryInterface(node);
  5166. NS_ENSURE_TRUE(content.get(), nullptr);
  5167. int32_t frameOffset = 0;
  5168. frame = mFrameSelection->GetFrameForNodeOffset(content, nodeOffset,
  5169. mFrameSelection->GetHint(),
  5170. &frameOffset);
  5171. if (!frame)
  5172. return nullptr;
  5173. // Figure out what node type we have, then get the
  5174. // appropriate rect for it's nodeOffset.
  5175. bool isText = node->IsNodeOfType(nsINode::eTEXT);
  5176. nsPoint pt(0, 0);
  5177. if (isText) {
  5178. nsIFrame* childFrame = nullptr;
  5179. frameOffset = 0;
  5180. nsresult rv =
  5181. frame->GetChildFrameContainingOffset(nodeOffset,
  5182. mFrameSelection->GetHint(),
  5183. &frameOffset, &childFrame);
  5184. if (NS_FAILED(rv))
  5185. return nullptr;
  5186. if (!childFrame)
  5187. return nullptr;
  5188. frame = childFrame;
  5189. // Get the x coordinate of the offset into the text frame.
  5190. rv = GetCachedFrameOffset(frame, nodeOffset, pt);
  5191. if (NS_FAILED(rv))
  5192. return nullptr;
  5193. }
  5194. // Return the rect relative to the frame, with zero width.
  5195. if (isText) {
  5196. aRect->x = pt.x;
  5197. } else if (mFrameSelection->GetHint() == CARET_ASSOCIATE_BEFORE) {
  5198. // It's the frame's right edge we're interested in.
  5199. aRect->x = frame->GetRect().width;
  5200. }
  5201. aRect->height = frame->GetRect().height;
  5202. return frame;
  5203. }
  5204. NS_IMETHODIMP
  5205. Selection::ScrollSelectionIntoViewEvent::Run()
  5206. {
  5207. if (!mSelection)
  5208. return NS_OK; // event revoked
  5209. int32_t flags = Selection::SCROLL_DO_FLUSH |
  5210. Selection::SCROLL_SYNCHRONOUS;
  5211. Selection* sel = mSelection; // workaround to satisfy static analysis
  5212. RefPtr<Selection> kungFuDeathGrip(sel);
  5213. mSelection->mScrollEvent.Forget();
  5214. mSelection->ScrollIntoView(mRegion, mVerticalScroll,
  5215. mHorizontalScroll, mFlags | flags);
  5216. return NS_OK;
  5217. }
  5218. nsresult
  5219. Selection::PostScrollSelectionIntoViewEvent(
  5220. SelectionRegion aRegion,
  5221. int32_t aFlags,
  5222. nsIPresShell::ScrollAxis aVertical,
  5223. nsIPresShell::ScrollAxis aHorizontal)
  5224. {
  5225. // If we've already posted an event, revoke it and place a new one at the
  5226. // end of the queue to make sure that any new pending reflow events are
  5227. // processed before we scroll. This will insure that we scroll to the
  5228. // correct place on screen.
  5229. mScrollEvent.Revoke();
  5230. RefPtr<ScrollSelectionIntoViewEvent> ev =
  5231. new ScrollSelectionIntoViewEvent(this, aRegion, aVertical, aHorizontal,
  5232. aFlags);
  5233. nsresult rv = NS_DispatchToCurrentThread(ev);
  5234. NS_ENSURE_SUCCESS(rv, rv);
  5235. mScrollEvent = ev;
  5236. return NS_OK;
  5237. }
  5238. NS_IMETHODIMP
  5239. Selection::ScrollIntoView(SelectionRegion aRegion, bool aIsSynchronous,
  5240. int16_t aVPercent, int16_t aHPercent)
  5241. {
  5242. ErrorResult result;
  5243. ScrollIntoView(aRegion, aIsSynchronous, aVPercent, aHPercent, result);
  5244. if (result.Failed()) {
  5245. return result.StealNSResult();
  5246. }
  5247. return NS_OK;
  5248. }
  5249. void
  5250. Selection::ScrollIntoView(int16_t aRegion, bool aIsSynchronous,
  5251. int16_t aVPercent, int16_t aHPercent,
  5252. ErrorResult& aRv)
  5253. {
  5254. nsresult rv = ScrollIntoViewInternal(aRegion, aIsSynchronous,
  5255. nsIPresShell::ScrollAxis(aVPercent),
  5256. nsIPresShell::ScrollAxis(aHPercent));
  5257. if (NS_FAILED(rv)) {
  5258. aRv.Throw(rv);
  5259. }
  5260. }
  5261. NS_IMETHODIMP
  5262. Selection::ScrollIntoViewInternal(SelectionRegion aRegion, bool aIsSynchronous,
  5263. nsIPresShell::ScrollAxis aVertical,
  5264. nsIPresShell::ScrollAxis aHorizontal)
  5265. {
  5266. return ScrollIntoView(aRegion, aVertical, aHorizontal,
  5267. aIsSynchronous ? Selection::SCROLL_SYNCHRONOUS : 0);
  5268. }
  5269. nsresult
  5270. Selection::ScrollIntoView(SelectionRegion aRegion,
  5271. nsIPresShell::ScrollAxis aVertical,
  5272. nsIPresShell::ScrollAxis aHorizontal,
  5273. int32_t aFlags)
  5274. {
  5275. if (!mFrameSelection)
  5276. return NS_OK;//nothing to do
  5277. nsCOMPtr<nsIPresShell> presShell = mFrameSelection->GetShell();
  5278. if (!presShell)
  5279. return NS_OK;
  5280. if (mFrameSelection->GetBatching())
  5281. return NS_OK;
  5282. if (!(aFlags & Selection::SCROLL_SYNCHRONOUS))
  5283. return PostScrollSelectionIntoViewEvent(aRegion, aFlags,
  5284. aVertical, aHorizontal);
  5285. // Now that text frame character offsets are always valid (though not
  5286. // necessarily correct), the worst that will happen if we don't flush here
  5287. // is that some callers might scroll to the wrong place. Those should
  5288. // either manually flush if they're in a safe position for it or use the
  5289. // async version of this method.
  5290. if (aFlags & Selection::SCROLL_DO_FLUSH) {
  5291. presShell->FlushPendingNotifications(Flush_Layout);
  5292. // Reget the presshell, since it might have been Destroy'ed.
  5293. presShell = mFrameSelection ? mFrameSelection->GetShell() : nullptr;
  5294. if (!presShell)
  5295. return NS_OK;
  5296. }
  5297. //
  5298. // Scroll the selection region into view.
  5299. //
  5300. nsRect rect;
  5301. nsIFrame* frame = GetSelectionAnchorGeometry(aRegion, &rect);
  5302. if (!frame)
  5303. return NS_ERROR_FAILURE;
  5304. // Scroll vertically to get the caret into view, but only if the container
  5305. // is perceived to be scrollable in that direction (i.e. there is a visible
  5306. // vertical scrollbar or the scroll range is at least one device pixel)
  5307. aVertical.mOnlyIfPerceivedScrollableDirection = true;
  5308. uint32_t flags = 0;
  5309. if (aFlags & Selection::SCROLL_FIRST_ANCESTOR_ONLY) {
  5310. flags |= nsIPresShell::SCROLL_FIRST_ANCESTOR_ONLY;
  5311. }
  5312. if (aFlags & Selection::SCROLL_OVERFLOW_HIDDEN) {
  5313. flags |= nsIPresShell::SCROLL_OVERFLOW_HIDDEN;
  5314. }
  5315. presShell->ScrollFrameRectIntoView(frame, rect, aVertical, aHorizontal,
  5316. flags);
  5317. return NS_OK;
  5318. }
  5319. NS_IMETHODIMP
  5320. Selection::AddSelectionListener(nsISelectionListener* aNewListener)
  5321. {
  5322. if (!aNewListener)
  5323. return NS_ERROR_NULL_POINTER;
  5324. ErrorResult result;
  5325. AddSelectionListener(aNewListener, result);
  5326. if (result.Failed()) {
  5327. return result.StealNSResult();
  5328. }
  5329. return NS_OK;
  5330. }
  5331. void
  5332. Selection::AddSelectionListener(nsISelectionListener* aNewListener,
  5333. ErrorResult& aRv)
  5334. {
  5335. bool result = mSelectionListeners.AppendObject(aNewListener); // AddRefs
  5336. if (!result) {
  5337. aRv.Throw(NS_ERROR_FAILURE);
  5338. }
  5339. }
  5340. NS_IMETHODIMP
  5341. Selection::RemoveSelectionListener(nsISelectionListener* aListenerToRemove)
  5342. {
  5343. if (!aListenerToRemove)
  5344. return NS_ERROR_NULL_POINTER;
  5345. ErrorResult result;
  5346. RemoveSelectionListener(aListenerToRemove, result);
  5347. if (result.Failed()) {
  5348. return result.StealNSResult();
  5349. }
  5350. return NS_OK;
  5351. }
  5352. void
  5353. Selection::RemoveSelectionListener(nsISelectionListener* aListenerToRemove,
  5354. ErrorResult& aRv)
  5355. {
  5356. bool result = mSelectionListeners.RemoveObject(aListenerToRemove); // Releases
  5357. if (!result) {
  5358. aRv.Throw(NS_ERROR_FAILURE);
  5359. }
  5360. }
  5361. nsresult
  5362. Selection::NotifySelectionListeners()
  5363. {
  5364. if (!mFrameSelection)
  5365. return NS_OK;//nothing to do
  5366. RefPtr<nsFrameSelection> frameSelection = mFrameSelection;
  5367. if (frameSelection->GetBatching()) {
  5368. frameSelection->SetDirty();
  5369. return NS_OK;
  5370. }
  5371. nsCOMArray<nsISelectionListener> selectionListeners(mSelectionListeners);
  5372. int32_t cnt = selectionListeners.Count();
  5373. if (cnt != mSelectionListeners.Count()) {
  5374. return NS_ERROR_OUT_OF_MEMORY; // nsCOMArray is fallible
  5375. }
  5376. nsCOMPtr<nsIDOMDocument> domdoc;
  5377. nsIPresShell* ps = GetPresShell();
  5378. if (ps) {
  5379. domdoc = do_QueryInterface(ps->GetDocument());
  5380. }
  5381. short reason = frameSelection->PopReason();
  5382. for (int32_t i = 0; i < cnt; i++) {
  5383. selectionListeners[i]->NotifySelectionChanged(domdoc, this, reason);
  5384. }
  5385. return NS_OK;
  5386. }
  5387. NS_IMETHODIMP
  5388. Selection::StartBatchChanges()
  5389. {
  5390. if (mFrameSelection) {
  5391. RefPtr<nsFrameSelection> frameSelection = mFrameSelection;
  5392. frameSelection->StartBatchChanges();
  5393. }
  5394. return NS_OK;
  5395. }
  5396. NS_IMETHODIMP
  5397. Selection::EndBatchChanges()
  5398. {
  5399. return EndBatchChangesInternal();
  5400. }
  5401. nsresult
  5402. Selection::EndBatchChangesInternal(int16_t aReason)
  5403. {
  5404. if (mFrameSelection) {
  5405. RefPtr<nsFrameSelection> frameSelection = mFrameSelection;
  5406. frameSelection->EndBatchChanges(aReason);
  5407. }
  5408. return NS_OK;
  5409. }
  5410. void
  5411. Selection::AddSelectionChangeBlocker()
  5412. {
  5413. mSelectionChangeBlockerCount++;
  5414. }
  5415. void
  5416. Selection::RemoveSelectionChangeBlocker()
  5417. {
  5418. MOZ_ASSERT(mSelectionChangeBlockerCount > 0,
  5419. "mSelectionChangeBlockerCount has an invalid value - "
  5420. "maybe you have a mismatched RemoveSelectionChangeBlocker?");
  5421. mSelectionChangeBlockerCount--;
  5422. }
  5423. bool
  5424. Selection::IsBlockingSelectionChangeEvents() const
  5425. {
  5426. return mSelectionChangeBlockerCount > 0;
  5427. }
  5428. NS_IMETHODIMP
  5429. Selection::DeleteFromDocument()
  5430. {
  5431. ErrorResult result;
  5432. DeleteFromDocument(result);
  5433. return result.StealNSResult();
  5434. }
  5435. void
  5436. Selection::DeleteFromDocument(ErrorResult& aRv)
  5437. {
  5438. if (!mFrameSelection)
  5439. return;//nothing to do
  5440. RefPtr<nsFrameSelection> frameSelection = mFrameSelection;
  5441. nsresult rv = frameSelection->DeleteFromDocument();
  5442. if (NS_FAILED(rv)) {
  5443. aRv.Throw(rv);
  5444. }
  5445. }
  5446. NS_IMETHODIMP
  5447. Selection::Modify(const nsAString& aAlter, const nsAString& aDirection,
  5448. const nsAString& aGranularity)
  5449. {
  5450. ErrorResult result;
  5451. Modify(aAlter, aDirection, aGranularity, result);
  5452. return result.StealNSResult();
  5453. }
  5454. void
  5455. Selection::Modify(const nsAString& aAlter, const nsAString& aDirection,
  5456. const nsAString& aGranularity, ErrorResult& aRv)
  5457. {
  5458. // Silently exit if there's no selection or no focus node.
  5459. if (!mFrameSelection || !GetAnchorFocusRange() || !GetFocusNode()) {
  5460. return;
  5461. }
  5462. if (!aAlter.LowerCaseEqualsLiteral("move") &&
  5463. !aAlter.LowerCaseEqualsLiteral("extend")) {
  5464. aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
  5465. return;
  5466. }
  5467. if (!aDirection.LowerCaseEqualsLiteral("forward") &&
  5468. !aDirection.LowerCaseEqualsLiteral("backward") &&
  5469. !aDirection.LowerCaseEqualsLiteral("left") &&
  5470. !aDirection.LowerCaseEqualsLiteral("right")) {
  5471. aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
  5472. return;
  5473. }
  5474. // Line moves are always visual.
  5475. bool visual = aDirection.LowerCaseEqualsLiteral("left") ||
  5476. aDirection.LowerCaseEqualsLiteral("right") ||
  5477. aGranularity.LowerCaseEqualsLiteral("line");
  5478. bool forward = aDirection.LowerCaseEqualsLiteral("forward") ||
  5479. aDirection.LowerCaseEqualsLiteral("right");
  5480. bool extend = aAlter.LowerCaseEqualsLiteral("extend");
  5481. nsSelectionAmount amount;
  5482. if (aGranularity.LowerCaseEqualsLiteral("character")) {
  5483. amount = eSelectCluster;
  5484. } else if (aGranularity.LowerCaseEqualsLiteral("word")) {
  5485. amount = eSelectWordNoSpace;
  5486. } else if (aGranularity.LowerCaseEqualsLiteral("line")) {
  5487. amount = eSelectLine;
  5488. } else if (aGranularity.LowerCaseEqualsLiteral("lineboundary")) {
  5489. amount = forward ? eSelectEndLine : eSelectBeginLine;
  5490. } else if (aGranularity.LowerCaseEqualsLiteral("sentence") ||
  5491. aGranularity.LowerCaseEqualsLiteral("sentenceboundary") ||
  5492. aGranularity.LowerCaseEqualsLiteral("paragraph") ||
  5493. aGranularity.LowerCaseEqualsLiteral("paragraphboundary") ||
  5494. aGranularity.LowerCaseEqualsLiteral("documentboundary")) {
  5495. aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
  5496. return;
  5497. } else {
  5498. aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
  5499. return;
  5500. }
  5501. // If the anchor doesn't equal the focus and we try to move without first
  5502. // collapsing the selection, MoveCaret will collapse the selection and quit.
  5503. // To avoid this, we need to collapse the selection first.
  5504. nsresult rv = NS_OK;
  5505. if (!extend) {
  5506. nsINode* focusNode = GetFocusNode();
  5507. // We should have checked earlier that there was a focus node.
  5508. if (!focusNode) {
  5509. aRv.Throw(NS_ERROR_UNEXPECTED);
  5510. return;
  5511. }
  5512. uint32_t focusOffset = FocusOffset();
  5513. Collapse(focusNode, focusOffset);
  5514. }
  5515. // If the paragraph direction of the focused frame is right-to-left,
  5516. // we may have to swap the direction of movement.
  5517. nsIFrame *frame;
  5518. int32_t offset;
  5519. rv = GetPrimaryFrameForFocusNode(&frame, &offset, visual);
  5520. if (NS_SUCCEEDED(rv) && frame) {
  5521. nsBidiDirection paraDir = nsBidiPresUtils::ParagraphDirection(frame);
  5522. if (paraDir == NSBIDI_RTL && visual) {
  5523. if (amount == eSelectBeginLine) {
  5524. amount = eSelectEndLine;
  5525. forward = !forward;
  5526. } else if (amount == eSelectEndLine) {
  5527. amount = eSelectBeginLine;
  5528. forward = !forward;
  5529. }
  5530. }
  5531. }
  5532. // MoveCaret will return an error if it can't move in the specified
  5533. // direction, but we just ignore this error unless it's a line move, in which
  5534. // case we call nsISelectionController::CompleteMove to move the cursor to
  5535. // the beginning/end of the line.
  5536. RefPtr<nsFrameSelection> frameSelection = mFrameSelection;
  5537. rv = frameSelection->MoveCaret(forward ? eDirNext : eDirPrevious,
  5538. extend, amount,
  5539. visual ? nsFrameSelection::eVisual
  5540. : nsFrameSelection::eLogical);
  5541. if (aGranularity.LowerCaseEqualsLiteral("line") && NS_FAILED(rv)) {
  5542. nsCOMPtr<nsISelectionController> shell =
  5543. do_QueryInterface(frameSelection->GetShell());
  5544. if (!shell)
  5545. return;
  5546. shell->CompleteMove(forward, extend);
  5547. }
  5548. }
  5549. /** SelectionLanguageChange modifies the cursor Bidi level after a change in keyboard direction
  5550. * @param aLangRTL is true if the new language is right-to-left or false if the new language is left-to-right
  5551. */
  5552. NS_IMETHODIMP
  5553. Selection::SelectionLanguageChange(bool aLangRTL)
  5554. {
  5555. if (!mFrameSelection)
  5556. return NS_ERROR_NOT_INITIALIZED; // Can't do selection
  5557. RefPtr<nsFrameSelection> frameSelection = mFrameSelection;
  5558. // if the direction of the language hasn't changed, nothing to do
  5559. nsBidiLevel kbdBidiLevel = aLangRTL ? NSBIDI_RTL : NSBIDI_LTR;
  5560. if (kbdBidiLevel == frameSelection->mKbdBidiLevel) {
  5561. return NS_OK;
  5562. }
  5563. frameSelection->mKbdBidiLevel = kbdBidiLevel;
  5564. nsresult result;
  5565. nsIFrame *focusFrame = 0;
  5566. result = GetPrimaryFrameForFocusNode(&focusFrame, nullptr, false);
  5567. if (NS_FAILED(result)) {
  5568. return result;
  5569. }
  5570. if (!focusFrame) {
  5571. return NS_ERROR_FAILURE;
  5572. }
  5573. int32_t frameStart, frameEnd;
  5574. focusFrame->GetOffsets(frameStart, frameEnd);
  5575. RefPtr<nsPresContext> context = GetPresContext();
  5576. nsBidiLevel levelBefore, levelAfter;
  5577. if (!context) {
  5578. return NS_ERROR_FAILURE;
  5579. }
  5580. nsBidiLevel level = focusFrame->GetEmbeddingLevel();
  5581. int32_t focusOffset = static_cast<int32_t>(FocusOffset());
  5582. if ((focusOffset != frameStart) && (focusOffset != frameEnd))
  5583. // the cursor is not at a frame boundary, so the level of both the characters (logically) before and after the cursor
  5584. // is equal to the frame level
  5585. levelBefore = levelAfter = level;
  5586. else {
  5587. // the cursor is at a frame boundary, so use GetPrevNextBidiLevels to find the level of the characters
  5588. // before and after the cursor
  5589. nsCOMPtr<nsIContent> focusContent = do_QueryInterface(GetFocusNode());
  5590. nsPrevNextBidiLevels levels = frameSelection->
  5591. GetPrevNextBidiLevels(focusContent, focusOffset, false);
  5592. levelBefore = levels.mLevelBefore;
  5593. levelAfter = levels.mLevelAfter;
  5594. }
  5595. if (IS_SAME_DIRECTION(levelBefore, levelAfter)) {
  5596. // if cursor is between two characters with the same orientation, changing the keyboard language
  5597. // must toggle the cursor level between the level of the character with the lowest level
  5598. // (if the new language corresponds to the orientation of that character) and this level plus 1
  5599. // (if the new language corresponds to the opposite orientation)
  5600. if ((level != levelBefore) && (level != levelAfter))
  5601. level = std::min(levelBefore, levelAfter);
  5602. if (IS_SAME_DIRECTION(level, kbdBidiLevel))
  5603. frameSelection->SetCaretBidiLevel(level);
  5604. else
  5605. frameSelection->SetCaretBidiLevel(level + 1);
  5606. }
  5607. else {
  5608. // if cursor is between characters with opposite orientations, changing the keyboard language must change
  5609. // the cursor level to that of the adjacent character with the orientation corresponding to the new language.
  5610. if (IS_SAME_DIRECTION(levelBefore, kbdBidiLevel))
  5611. frameSelection->SetCaretBidiLevel(levelBefore);
  5612. else
  5613. frameSelection->SetCaretBidiLevel(levelAfter);
  5614. }
  5615. // The caret might have moved, so invalidate the desired position
  5616. // for future usages of up-arrow or down-arrow
  5617. frameSelection->InvalidateDesiredPos();
  5618. return NS_OK;
  5619. }
  5620. NS_IMETHODIMP_(nsDirection)
  5621. Selection::GetSelectionDirection() {
  5622. return mDirection;
  5623. }
  5624. NS_IMETHODIMP_(void)
  5625. Selection::SetSelectionDirection(nsDirection aDirection) {
  5626. mDirection = aDirection;
  5627. }
  5628. JSObject*
  5629. Selection::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
  5630. {
  5631. return mozilla::dom::SelectionBinding::Wrap(aCx, this, aGivenProto);
  5632. }
  5633. // AutoHideSelectionChanges
  5634. AutoHideSelectionChanges::AutoHideSelectionChanges(const nsFrameSelection* aFrame)
  5635. : AutoHideSelectionChanges(
  5636. aFrame ? aFrame->GetSelection(SelectionType::eNormal) : nullptr)
  5637. {}
  5638. // nsAutoCopyListener
  5639. nsAutoCopyListener* nsAutoCopyListener::sInstance = nullptr;
  5640. NS_IMPL_ISUPPORTS(nsAutoCopyListener, nsISelectionListener)
  5641. /*
  5642. * What we do now:
  5643. * On every selection change, we copy to the clipboard anew, creating a
  5644. * HTML buffer, a transferable, an nsISupportsString and
  5645. * a huge mess every time. This is basically what nsPresShell::DoCopy does
  5646. * to move the selection into the clipboard for Edit->Copy.
  5647. *
  5648. * What we should do, to make our end of the deal faster:
  5649. * Create a singleton transferable with our own magic converter. When selection
  5650. * changes (use a quick cache to detect ``real'' changes), we put the new
  5651. * nsISelection in the transferable. Our magic converter will take care of
  5652. * transferable->whatever-other-format when the time comes to actually
  5653. * hand over the clipboard contents.
  5654. *
  5655. * Other issues:
  5656. * - which X clipboard should we populate?
  5657. * - should we use a different one than Edit->Copy, so that inadvertant
  5658. * selections (or simple clicks, which currently cause a selection
  5659. * notification, regardless of if they're in the document which currently has
  5660. * selection!) don't lose the contents of the ``application''? Or should we
  5661. * just put some intelligence in the ``is this a real selection?'' code to
  5662. * protect our selection against clicks in other documents that don't create
  5663. * selections?
  5664. * - maybe we should just never clear the X clipboard? That would make this
  5665. * problem just go away, which is very tempting.
  5666. *
  5667. * On macOS,
  5668. * nsIClipboard::kSelectionCache is the flag for current selection cache.
  5669. * Set the current selection cache on the parent process in
  5670. * widget cocoa nsClipboard whenever selection changes.
  5671. */
  5672. NS_IMETHODIMP
  5673. nsAutoCopyListener::NotifySelectionChanged(nsIDOMDocument *aDoc,
  5674. nsISelection *aSel, int16_t aReason)
  5675. {
  5676. if (mCachedClipboard == nsIClipboard::kSelectionCache) {
  5677. nsFocusManager* fm = nsFocusManager::GetFocusManager();
  5678. // If no active window, do nothing because a current selection changed
  5679. // cannot occur unless it is in the active window.
  5680. if (!fm->GetActiveWindow()) {
  5681. return NS_OK;
  5682. }
  5683. }
  5684. if (!(aReason & nsISelectionListener::MOUSEUP_REASON ||
  5685. aReason & nsISelectionListener::SELECTALL_REASON ||
  5686. aReason & nsISelectionListener::KEYPRESS_REASON))
  5687. return NS_OK; //dont care if we are still dragging
  5688. bool collapsed;
  5689. if (!aDoc || !aSel ||
  5690. NS_FAILED(aSel->GetIsCollapsed(&collapsed)) || collapsed) {
  5691. #ifdef DEBUG_CLIPBOARD
  5692. fprintf(stderr, "CLIPBOARD: no selection/collapsed selection\n");
  5693. #endif
  5694. // If on macOS, clear the current selection transferable cached
  5695. // on the parent process (nsClipboard) when the selection is empty.
  5696. if (mCachedClipboard == nsIClipboard::kSelectionCache) {
  5697. return nsCopySupport::ClearSelectionCache();
  5698. }
  5699. /* clear X clipboard? */
  5700. return NS_OK;
  5701. }
  5702. nsCOMPtr<nsIDocument> doc = do_QueryInterface(aDoc);
  5703. NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
  5704. // call the copy code
  5705. return nsCopySupport::HTMLCopy(aSel, doc,
  5706. mCachedClipboard, false);
  5707. }
  5708. /**
  5709. * See Bug 1288453.
  5710. *
  5711. * Update the selection cache on repaint to handle when a pre-existing
  5712. * selection becomes active aka the current selection.
  5713. *
  5714. * 1. Change the current selection by click n dragging another selection.
  5715. * - Make a selection on content page. Make a selection in a text editor.
  5716. * - You can click n drag the content selection to make it active again.
  5717. * 2. Change the current selection when switching to a tab with a selection.
  5718. * - Make selection in tab.
  5719. * - Switching tabs will make its respective selection active.
  5720. *
  5721. * Therefore, we only update the selection cache on a repaint
  5722. * if the current selection being repainted is not an empty selection.
  5723. *
  5724. * If the current selection is empty. The current selection cache
  5725. * would be cleared by nsAutoCopyListener::NotifySelectionChanged.
  5726. */
  5727. nsresult
  5728. nsFrameSelection::UpdateSelectionCacheOnRepaintSelection(Selection* aSel)
  5729. {
  5730. nsIPresShell* ps = aSel->GetPresShell();
  5731. if (!ps) {
  5732. return NS_OK;
  5733. }
  5734. nsCOMPtr<nsIDocument> aDoc = ps->GetDocument();
  5735. bool collapsed;
  5736. if (aDoc && aSel &&
  5737. NS_SUCCEEDED(aSel->GetIsCollapsed(&collapsed)) && !collapsed) {
  5738. return nsCopySupport::HTMLCopy(aSel, aDoc,
  5739. nsIClipboard::kSelectionCache, false);
  5740. }
  5741. return NS_OK;
  5742. }
  5743. // SelectionChangeListener
  5744. SelectionChangeListener::RawRangeData::RawRangeData(const nsRange* aRange)
  5745. {
  5746. mozilla::ErrorResult rv;
  5747. mStartParent = aRange->GetStartContainer(rv);
  5748. rv.SuppressException();
  5749. mEndParent = aRange->GetEndContainer(rv);
  5750. rv.SuppressException();
  5751. mStartOffset = aRange->GetStartOffset(rv);
  5752. rv.SuppressException();
  5753. mEndOffset = aRange->GetEndOffset(rv);
  5754. rv.SuppressException();
  5755. }
  5756. bool
  5757. SelectionChangeListener::RawRangeData::Equals(const nsRange* aRange)
  5758. {
  5759. mozilla::ErrorResult rv;
  5760. bool eq = mStartParent == aRange->GetStartContainer(rv);
  5761. rv.SuppressException();
  5762. eq = eq && mEndParent == aRange->GetEndContainer(rv);
  5763. rv.SuppressException();
  5764. eq = eq && mStartOffset == aRange->GetStartOffset(rv);
  5765. rv.SuppressException();
  5766. eq = eq && mEndOffset == aRange->GetEndOffset(rv);
  5767. rv.SuppressException();
  5768. return eq;
  5769. }
  5770. inline void
  5771. ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
  5772. SelectionChangeListener::RawRangeData& aField,
  5773. const char* aName,
  5774. uint32_t aFlags = 0)
  5775. {
  5776. ImplCycleCollectionTraverse(aCallback, aField.mStartParent, "mStartParent", aFlags);
  5777. ImplCycleCollectionTraverse(aCallback, aField.mEndParent, "mEndParent", aFlags);
  5778. }
  5779. NS_IMPL_CYCLE_COLLECTION_CLASS(SelectionChangeListener)
  5780. NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(SelectionChangeListener)
  5781. tmp->mOldRanges.Clear();
  5782. NS_IMPL_CYCLE_COLLECTION_UNLINK_END
  5783. NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(SelectionChangeListener)
  5784. NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOldRanges);
  5785. NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
  5786. NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(SelectionChangeListener)
  5787. NS_INTERFACE_MAP_ENTRY(nsISupports)
  5788. NS_INTERFACE_MAP_ENTRY(nsISelectionListener)
  5789. NS_INTERFACE_MAP_END
  5790. NS_IMPL_CYCLE_COLLECTING_ADDREF(SelectionChangeListener)
  5791. NS_IMPL_CYCLE_COLLECTING_RELEASE(SelectionChangeListener)
  5792. NS_IMETHODIMP
  5793. SelectionChangeListener::NotifySelectionChanged(nsIDOMDocument* aDoc,
  5794. nsISelection* aSel, int16_t aReason)
  5795. {
  5796. RefPtr<Selection> sel = aSel->AsSelection();
  5797. nsIDocument* doc = sel->GetParentObject();
  5798. if (!(doc && nsContentUtils::IsSystemPrincipal(doc->NodePrincipal())) &&
  5799. !nsFrameSelection::sSelectionEventsEnabled) {
  5800. return NS_OK;
  5801. }
  5802. // Check if the ranges have actually changed
  5803. // Don't bother checking this if we are hiding changes.
  5804. if (mOldRanges.Length() == sel->RangeCount() && !sel->IsBlockingSelectionChangeEvents()) {
  5805. bool changed = false;
  5806. for (size_t i = 0; i < mOldRanges.Length(); i++) {
  5807. if (!mOldRanges[i].Equals(sel->GetRangeAt(i))) {
  5808. changed = true;
  5809. break;
  5810. }
  5811. }
  5812. if (!changed) {
  5813. return NS_OK;
  5814. }
  5815. }
  5816. // The ranges have actually changed, update the mOldRanges array
  5817. mOldRanges.ClearAndRetainStorage();
  5818. for (size_t i = 0; i < sel->RangeCount(); i++) {
  5819. mOldRanges.AppendElement(RawRangeData(sel->GetRangeAt(i)));
  5820. }
  5821. // If we are hiding changes, then don't do anything else. We do this after we
  5822. // update mOldRanges so that changes after the changes stop being hidden don't
  5823. // incorrectly trigger a change, even though they didn't change anything
  5824. if (sel->IsBlockingSelectionChangeEvents()) {
  5825. return NS_OK;
  5826. }
  5827. // The spec currently doesn't say that we should dispatch this event on text
  5828. // controls, so for now we only support doing that under a pref, disabled by
  5829. // default.
  5830. // See https://github.com/w3c/selection-api/issues/53.
  5831. if (nsFrameSelection::sSelectionEventsOnTextControlsEnabled) {
  5832. nsCOMPtr<nsINode> target;
  5833. // Check if we should be firing this event to a different node than the
  5834. // document. The limiter of the nsFrameSelection will be within the native
  5835. // anonymous subtree of the node we want to fire the event on. We need to
  5836. // climb up the parent chain to escape the native anonymous subtree, and then
  5837. // fire the event.
  5838. if (const nsFrameSelection* fs = sel->GetFrameSelection()) {
  5839. if (nsCOMPtr<nsIContent> root = fs->GetLimiter()) {
  5840. while (root && root->IsInNativeAnonymousSubtree()) {
  5841. root = root->GetParent();
  5842. }
  5843. target = root.forget();
  5844. }
  5845. }
  5846. // If we didn't get a target before, we can instead fire the event at the document.
  5847. if (!target) {
  5848. nsCOMPtr<nsIDocument> doc = do_QueryInterface(aDoc);
  5849. target = doc.forget();
  5850. }
  5851. if (target) {
  5852. RefPtr<AsyncEventDispatcher> asyncDispatcher =
  5853. new AsyncEventDispatcher(target, NS_LITERAL_STRING("selectionchange"), false);
  5854. asyncDispatcher->PostDOMEvent();
  5855. }
  5856. } else {
  5857. if (const nsFrameSelection* fs = sel->GetFrameSelection()) {
  5858. if (nsCOMPtr<nsIContent> root = fs->GetLimiter()) {
  5859. if (root->IsInNativeAnonymousSubtree()) {
  5860. return NS_OK;
  5861. }
  5862. }
  5863. }
  5864. nsCOMPtr<nsIDocument> doc = do_QueryInterface(aDoc);
  5865. if (doc) {
  5866. RefPtr<AsyncEventDispatcher> asyncDispatcher =
  5867. new AsyncEventDispatcher(doc, NS_LITERAL_STRING("selectionchange"), false);
  5868. asyncDispatcher->PostDOMEvent();
  5869. }
  5870. }
  5871. return NS_OK;
  5872. }