Opera 12.15 Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

OpDocumentEdit.cpp 212KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844684568466847684868496850685168526853685468556856685768586859686068616862686368646865686668676868686968706871687268736874687568766877687868796880688168826883688468856886688768886889689068916892689368946895689668976898689969006901690269036904690569066907690869096910691169126913691469156916691769186919692069216922692369246925692669276928692969306931693269336934693569366937693869396940694169426943694469456946694769486949695069516952695369546955695669576958695969606961696269636964696569666967696869696970697169726973697469756976697769786979698069816982698369846985698669876988698969906991699269936994699569966997699869997000700170027003700470057006700770087009701070117012701370147015701670177018701970207021702270237024702570267027702870297030703170327033703470357036703770387039704070417042704370447045704670477048704970507051705270537054705570567057705870597060706170627063706470657066706770687069707070717072707370747075707670777078707970807081708270837084708570867087708870897090709170927093709470957096709770987099710071017102710371047105710671077108710971107111711271137114711571167117711871197120712171227123712471257126712771287129713071317132713371347135713671377138713971407141714271437144714571467147714871497150715171527153715471557156715771587159716071617162716371647165716671677168716971707171717271737174717571767177717871797180718171827183718471857186718771887189719071917192719371947195719671977198719972007201720272037204720572067207720872097210721172127213721472157216721772187219722072217222722372247225722672277228722972307231723272337234723572367237723872397240724172427243724472457246724772487249725072517252725372547255725672577258725972607261726272637264726572667267726872697270727172727273727472757276727772787279728072817282728372847285728672877288728972907291729272937294729572967297729872997300730173027303730473057306730773087309731073117312731373147315731673177318731973207321732273237324732573267327732873297330733173327333733473357336733773387339734073417342734373447345734673477348734973507351735273537354735573567357735873597360736173627363736473657366736773687369737073717372737373747375737673777378737973807381738273837384738573867387738873897390739173927393739473957396739773987399740074017402
  1. /* -*- Mode: c++; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*-
  2. *
  3. * Copyright (C) 1995-2011 Opera Software ASA. All rights reserved.
  4. *
  5. * This file is part of the Opera web browser.
  6. * It may not be distributed under any circumstances.
  7. */
  8. #include "core/pch.h"
  9. #ifdef DOCUMENT_EDIT_SUPPORT
  10. #include "modules/documentedit/OpDocumentEdit.h"
  11. #include "modules/documentedit/OpDocumentEditUtils.h"
  12. #include "modules/hardcore/mh/constant.h"
  13. #include "modules/doc/html_doc.h"
  14. #include "modules/dochand/win.h"
  15. #include "modules/pi/OpClipboard.h"
  16. #include "modules/util/tempbuf.h"
  17. #include "modules/layout/box/box.h"
  18. #include "modules/layout/layout_workplace.h"
  19. #include "modules/display/coreview/coreview.h"
  20. #include "modules/style/css_property_list.h"
  21. #include "modules/logdoc/htm_lex.h"
  22. #include "modules/logdoc/logdoc_util.h" // for GetFirstFontNumber
  23. #include "modules/logdoc/selection.h"
  24. #include "modules/logdoc/html5parser.h"
  25. // == Some local util stuff ==================================
  26. //#define DEBUG_DOCUMENT_EDIT
  27. #ifdef DEBUG_DOCUMENT_EDIT
  28. # define DUMPDEBUGTREE m_doc->GetLogicalDocument()->GetRoot()->DumpDebugTree();
  29. # define DUMPDEBUGTREE_ELM(elm) elm->DumpDebugTree();
  30. #else
  31. # define DUMPDEBUGTREE
  32. # define DUMPDEBUGTREEE_ELM(elm)
  33. #endif
  34. BOOL IsDummyElement(HTML_Element* helm)
  35. {
  36. DEBUG_CHECKER_STATIC();
  37. return (helm->Type() == HE_TEXT && helm->GetTextContentLength() == 1 && helm->TextContent()[0] == document_edit_dummy_str[0]);
  38. }
  39. BOOL HasAttribute(HTML_Element* helm, short attr)
  40. {
  41. DEBUG_CHECKER_STATIC();
  42. if (attr == ATTR_NULL)
  43. return TRUE;
  44. return helm->HasAttr(attr);
  45. }
  46. BOOL ContainsLinebreak(const uni_char* text, int len)
  47. {
  48. DEBUG_CHECKER_STATIC();
  49. for(int i = 0; i < len; i++)
  50. if (text[i] == '\r' || text[i] == '\n')
  51. return TRUE;
  52. return FALSE;
  53. }
  54. void Replace(OpString& str, const char* what, const char* with)
  55. {
  56. DEBUG_CHECKER_STATIC();
  57. int pos;
  58. while((pos = str.FindI(what)) != KNotFound)
  59. {
  60. str.Delete(pos, op_strlen(what));
  61. str.Insert(pos, with);
  62. }
  63. }
  64. BOOL IsHeader(HTML_Element* helm)
  65. {
  66. DEBUG_CHECKER_STATIC();
  67. switch(helm->Type())
  68. {
  69. case HE_H1:
  70. case HE_H2:
  71. case HE_H3:
  72. case HE_H4:
  73. case HE_H5:
  74. case HE_H6:
  75. return TRUE;
  76. }
  77. return FALSE;
  78. }
  79. BOOL IsStyleElementType(HTML_ElementType type)
  80. {
  81. DEBUG_CHECKER_STATIC();
  82. switch(type)
  83. {
  84. case HE_FONT:
  85. case HE_BIG:
  86. case HE_SMALL:
  87. case HE_STRONG:
  88. case HE_B:
  89. case HE_EM:
  90. case HE_U:
  91. case HE_STRIKE:
  92. case HE_SUB:
  93. case HE_SUP:
  94. case HE_SPAN:
  95. return TRUE;
  96. }
  97. return FALSE;
  98. }
  99. BOOL ElementHandlesAlignAttribute(HTML_Element *helm)
  100. {
  101. DEBUG_CHECKER_STATIC();
  102. return TRUE;
  103. }
  104. BOOL ChildrenShouldInheritAlignment(HTML_Element *helm)
  105. {
  106. DEBUG_CHECKER_STATIC();
  107. switch(helm->Type())
  108. {
  109. case HE_TABLE:
  110. return FALSE;
  111. }
  112. return TRUE;
  113. }
  114. BOOL ElementHandlesMarginStyle(HTML_Element *helm)
  115. {
  116. DEBUG_CHECKER_STATIC();
  117. switch(helm->Type())
  118. {
  119. case HE_TR:
  120. case HE_TD:
  121. case HE_TH:
  122. case HE_TBODY:
  123. case HE_THEAD:
  124. case HE_TFOOT:
  125. return FALSE;
  126. }
  127. return TRUE;
  128. }
  129. HTML_Element *GetMatchingParent(BOOL match_value, HTML_Element *helm, BOOL (*func)(HTML_Element*,void*), void *func_arg)
  130. {
  131. DEBUG_CHECKER_STATIC();
  132. helm = helm->ParentActual();
  133. while(helm && helm->Type() != HE_BODY)
  134. {
  135. if(func(helm,func_arg) == match_value)
  136. return helm;
  137. helm = helm->ParentActual();
  138. }
  139. return NULL;
  140. }
  141. // The following are functions that might be used as arguments to OpDocumentEdit::GetSelectionMatchesFunction...
  142. BOOL IsNonLeftAligned(HTML_Element *helm, void *dont_care_about_me)
  143. {
  144. DEBUG_CHECKER_STATIC();
  145. return helm->GetAttr(ATTR_ALIGN, ITEM_TYPE_NUM, (void*)CSS_VALUE_left) != (void*)CSS_VALUE_left;
  146. }
  147. BOOL IsAlignedAs(HTML_Element *helm, void *CSS_align_value)
  148. {
  149. DEBUG_CHECKER_STATIC();
  150. return helm->GetAttr(ATTR_ALIGN, ITEM_TYPE_NUM, (void*)CSS_VALUE_left) == CSS_align_value;
  151. }
  152. BOOL StaticIsMatchingType(HTML_Element *helm, void *elm_types)
  153. {
  154. DEBUG_CHECKER_STATIC();
  155. HTML_ElementType *types = (HTML_ElementType*)elm_types;
  156. while(*types != HE_UNKNOWN)
  157. {
  158. if(helm->Type() == *types)
  159. return TRUE;
  160. types++;
  161. }
  162. return FALSE;
  163. }
  164. // End of functions for GetSelectionMatchesFunction.............................
  165. // The following are functions that might be used as arguments to OpDocumentEdit::ApplyFunctionBetween...
  166. OP_STATUS SetNewHref(HTML_Element *helm, void *arg, BOOL &ret)
  167. {
  168. DEBUG_CHECKER_STATIC();
  169. OP_STATUS status;
  170. if(!helm || !arg)
  171. {
  172. OP_ASSERT(FALSE);
  173. return OpStatus::ERR;
  174. }
  175. ret = FALSE;
  176. if(helm->Type() != HE_A)
  177. return OpStatus::OK;
  178. void **args = (void**)arg;
  179. OpDocumentEdit *edit = (OpDocumentEdit*)args[0];
  180. const uni_char *value = (const uni_char*)args[1];
  181. edit->OnElementChange(helm);
  182. status = helm->SetAttribute(edit->GetDoc(), ATTR_HREF, NULL, NS_IDX_DEFAULT, value, uni_strlen(value), NULL, FALSE);
  183. edit->OnElementChanged(helm);
  184. ret = OpStatus::IsSuccess(status);
  185. return status;
  186. }
  187. // End of functions for ApplyFunctionBetween.............................
  188. /** Returns FALSE if helm is a TEXT element that is non-empty but only contains chars <= 32,
  189. or <=31 if whitespace_is_valid==TRUE. */
  190. BOOL IsElmValidInListBlock(HTML_Element *helm, BOOL whitespace_is_valid = FALSE)
  191. {
  192. DEBUG_CHECKER_STATIC();
  193. if(!helm)
  194. return FALSE;
  195. int max_invalid = whitespace_is_valid ? 31 : 32;
  196. if(helm->Type() == HE_TEXT && helm->GetTextContentLength())
  197. {
  198. const uni_char *txt = helm->TextContent();
  199. while(*txt && *txt <= max_invalid)
  200. txt++;
  201. if(!*txt)
  202. return FALSE;
  203. }
  204. return TRUE;
  205. }
  206. BOOL IsValidListBlock(SiblingBlock block, BOOL whitespace_is_valid = FALSE)
  207. {
  208. DEBUG_CHECKER_STATIC();
  209. if(block.IsEmpty())
  210. return FALSE;
  211. HTML_Element *helm = block.start;
  212. while(TRUE)
  213. {
  214. if(IsElmValidInListBlock(helm,whitespace_is_valid))
  215. return TRUE;
  216. if(helm == block.stop)
  217. break;
  218. helm = helm->Suc();
  219. OP_ASSERT(helm);
  220. }
  221. return FALSE;
  222. }
  223. HTML_Element *GetAncestorOfType(HTML_Element *helm, HTML_ElementType type)
  224. {
  225. DEBUG_CHECKER_STATIC();
  226. while(helm && helm->Type() != type)
  227. helm = helm->ParentActual();
  228. return helm;
  229. }
  230. HTML_Element *GetParentListElm(HTML_Element *elm)
  231. {
  232. DEBUG_CHECKER_STATIC();
  233. while(elm)
  234. {
  235. if(elm->Type() == HE_OL || elm->Type() == HE_UL)
  236. return elm;
  237. elm = elm->Parent();
  238. }
  239. return NULL;
  240. }
  241. HTML_Element *GetRootList(HTML_Element *elm)
  242. {
  243. DEBUG_CHECKER_STATIC();
  244. HTML_Element *root_list = NULL;
  245. OP_ASSERT(elm);
  246. if(!elm)
  247. return NULL;
  248. elm = elm->Parent();
  249. while(elm && elm->Type() != HE_BODY)
  250. {
  251. if(elm->Type() == HE_OL || elm->Type() == HE_UL)
  252. root_list = elm;
  253. elm = elm->Parent();
  254. }
  255. return root_list;
  256. }
  257. INT32 GetListNestling(HTML_Element *elm)
  258. {
  259. DEBUG_CHECKER_STATIC();
  260. INT32 nestling = 0;
  261. OP_ASSERT(elm);
  262. if(!elm)
  263. return 0;
  264. elm = elm->Parent();
  265. while(elm && elm->Type() != HE_BODY)
  266. {
  267. if(elm->Type() == HE_OL || elm->Type() == HE_UL)
  268. nestling++;
  269. elm = elm->Parent();
  270. }
  271. return nestling;
  272. }
  273. void SetOrdering(SELECTION_ORDERING &ordering, HTML_ElementType type)
  274. {
  275. DEBUG_CHECKER_STATIC();
  276. OP_ASSERT(type == HE_OL || type == HE_UL);
  277. if(ordering == UNKNOWN)
  278. ordering = type == HE_OL ? ORDERED : UN_ORDERED;
  279. else if((type == HE_OL) ^ (ordering == ORDERED))
  280. ordering = SPLIT_ORDER;
  281. }
  282. BOOL HasActualBeside(HTML_Element *root, HTML_Element *helm, BOOL check_left)
  283. {
  284. DEBUG_CHECKER_STATIC();
  285. OP_ASSERT(root && helm && helm != root && root->IsAncestorOf(helm) && root->IsIncludedActual());
  286. if(check_left)
  287. {
  288. HTML_Element *actual = helm->PrevActual();
  289. while(actual != root)
  290. {
  291. if(!actual->IsAncestorOf(helm))
  292. return TRUE;
  293. actual = actual->PrevActual();
  294. }
  295. }
  296. else
  297. return root->IsAncestorOf(helm->NextActual());
  298. return FALSE;
  299. }
  300. BOOL CharMightCollapse(uni_char ch)
  301. {
  302. DEBUG_CHECKER_STATIC();
  303. return uni_collapsing_sp(ch) || ch == '\n' || ch == '\r' || ch == '\t';
  304. }
  305. // == OpDocumentEdit ===========================================
  306. OpDocumentEdit::OpDocumentEdit()
  307. : m_doc(NULL)
  308. , m_caret(this)
  309. , m_selection(this)
  310. , m_undo_stack(this)
  311. , m_layout_modifier(this)
  312. #ifdef INTERNAL_SPELLCHECK_SUPPORT
  313. , m_spell_session(NULL)
  314. , m_has_spellchecked(FALSE)
  315. , m_word_iterator(this,TRUE,TRUE)
  316. , m_replace_word(this,FALSE,FALSE)
  317. , m_background_updater(this,FALSE,FALSE)
  318. , m_pending_spell_first(NULL)
  319. , m_pending_spell_last(NULL)
  320. , m_delay_misspell_word_info(NULL)
  321. , m_doc_has_changed(FALSE)
  322. , m_last_helm_spelled(NULL)
  323. , m_enable_spellcheck_later(FALSE)
  324. , m_blocking_spellcheck(FALSE)
  325. , m_by_user(FALSE)
  326. #endif // INTERNAL_SPELLCHECK_SUPPORT
  327. , m_pending_styles_lock(0)
  328. , m_begin_count(0)
  329. , m_logtree_changed(FALSE)
  330. , m_usecss(FALSE)
  331. , m_readonly(FALSE)
  332. , m_wants_tab(FALSE)
  333. , m_body_is_root(TRUE)
  334. , m_autodetect_direction(FALSE)
  335. , m_blockquote_split(FALSE)
  336. , m_plain_text_mode(FALSE)
  337. #ifdef WIDGETS_IME_SUPPORT
  338. # ifndef DOCUMENTEDIT_DISABLE_IME_SUPPORT
  339. , m_imstring(NULL)
  340. , m_ime_string_elm(NULL)
  341. , im_waiting_first_compose(FALSE)
  342. # endif
  343. #endif
  344. , m_content_pending_helm(NULL)
  345. , m_listener(NULL)
  346. #ifdef _DOCEDIT_DEBUG
  347. , m_random_seed_initialized(FALSE)
  348. , m_edit(this)
  349. #endif // _DOCEDIT_DEBUG
  350. , m_recreate_caret(FALSE)
  351. , m_paragraph_element_type(HE_P)
  352. , m_is_focusing(FALSE)
  353. {
  354. DEBUG_CHECKER_CONSTRUCTOR();
  355. }
  356. OP_STATUS OpDocumentEdit::Construct(OpDocumentEdit** obj, FramesDocument* doc, BOOL designmode)
  357. {
  358. DEBUG_CHECKER_STATIC();
  359. *obj = OP_NEW(OpDocumentEdit, ());
  360. if (*obj == NULL || OpStatus::IsError((*obj)->Init(doc, designmode)))
  361. {
  362. OP_DELETE(*obj);
  363. *obj = NULL;
  364. return OpStatus::ERR_NO_MEMORY;
  365. }
  366. return OpStatus::OK;
  367. }
  368. OpDocumentEdit::~OpDocumentEdit()
  369. {
  370. DEBUG_CHECKER(TRUE);
  371. if (g_input_manager)
  372. {
  373. // OpInputContext::~OpInputContext does this too, but then it's to late for our virtual OnKeyboardInputLost to be called.
  374. g_input_manager->ReleaseInputContext(this);
  375. }
  376. // Clear unused temporary elements that might have been inserted along the way.
  377. m_caret.DeleteRemoveWhenMoveIfUntouched(NULL);
  378. ClearPendingStyles();
  379. #ifdef INTERNAL_SPELLCHECK_SUPPORT
  380. DisableSpellcheckInternal(FALSE /*by_user*/, TRUE /*force*/);
  381. #endif // INTERNAL_SPELLCHECK_SUPPORT
  382. g_main_message_handler->UnsetCallBacks(this);
  383. #ifdef USE_OP_CLIPBOARD
  384. g_clipboard_manager->UnregisterListener(this);
  385. #endif // USE_OP_CLIPBOARD
  386. }
  387. OP_STATUS OpDocumentEdit::Init(FramesDocument* doc, BOOL designmode)
  388. {
  389. if (!doc || !doc->GetLogicalDocument())
  390. return OpStatus::ERR;
  391. DEBUG_CHECKER(TRUE);
  392. m_doc = doc;
  393. m_body_is_root = designmode;
  394. SetParentInputContext(m_doc->GetVisualDevice());
  395. m_undo_stack.Clear();
  396. if (!doc->IsReflowing())
  397. {
  398. ReflowAndUpdate();
  399. Begin();
  400. RETURN_IF_ERROR(CollapseWhitespace());
  401. End();
  402. if (designmode && m_doc->GetVisualDevice()->IsFocused())
  403. SetFocus(FOCUS_REASON_OTHER);
  404. }
  405. return designmode ? m_caret.Init(FALSE /* !doc->IsReflowing() */) : OpStatus::OK;
  406. }
  407. void OpDocumentEdit::InitEditableRoot(HTML_Element* root)
  408. {
  409. DEBUG_CHECKER(TRUE);
  410. HTML_Element* body = GetBody();
  411. if (!root || !body)
  412. return;
  413. if (root->IsAncestorOf(body))
  414. root = body;
  415. if (!body->IsAncestorOf(root))
  416. return;
  417. m_body_is_root = FALSE;
  418. }
  419. void OpDocumentEdit::UninitEditableRoot(HTML_Element* root)
  420. {
  421. DEBUG_CHECKER(TRUE);
  422. if (root->IsAncestorOf(m_caret.GetElement()))
  423. {
  424. ReleaseFocus();
  425. m_caret.Set(NULL, 0);
  426. }
  427. }
  428. void OpDocumentEdit::FocusEditableRoot(HTML_Element* helm, FOCUS_REASON reason)
  429. {
  430. DEBUG_CHECKER(TRUE);
  431. HTML_Element* ec = GetFocusableEditableContainer(helm);
  432. if (ec && !ec->GetDisabled())
  433. {
  434. if (ec->Type() != HE_BODY)
  435. {
  436. // If we want to focus a editable container, place the caret in it, and if there is no editable
  437. // childelement, we must create it.
  438. HTML_Element* ee = FindEditableElement(ec, TRUE, FALSE, TRUE);
  439. if (!ee || !ec->IsAncestorOf(ee) || !m_caret.GetElement() || !ec->IsAncestorOf(m_caret.GetElement()))
  440. m_caret.Init(TRUE, ec);
  441. }
  442. m_caret.RestartBlink();
  443. SetFocus(reason);
  444. if (reason == FOCUS_REASON_MOUSE)
  445. g_input_manager->SetMouseInputContext(this);
  446. }
  447. }
  448. OP_STATUS OpDocumentEdit::Clear()
  449. {
  450. DEBUG_CHECKER(TRUE);
  451. HTML_Element* root_elm = GetBody();
  452. while(root_elm && root_elm->FirstChild())
  453. DeleteElement(root_elm->FirstChild());
  454. ReflowAndUpdate();
  455. m_undo_stack.Clear();
  456. return m_caret.Init(TRUE);
  457. }
  458. OP_STATUS OpDocumentEdit::CollapseWhitespace()
  459. {
  460. DEBUG_CHECKER(TRUE);
  461. if (!GetBody())
  462. return OpStatus::OK;
  463. // Convert linebreaks in text into whitespace (as the layout does).
  464. // Otherwise they will be treated as <br> when when copied and pasted again and we'll get
  465. // a lot of new lines where we should not.
  466. // IE and Mozilla also does this when a document is set to designmode.
  467. if (m_doc->IsReflowing())
  468. return OpStatus::OK;
  469. ReflowAndUpdate();
  470. return OpStatus::OK;
  471. }
  472. void OpDocumentEdit::Paint(VisualDevice* vis_dev)
  473. {
  474. DEBUG_CHECKER(TRUE);
  475. m_layout_modifier.Paint(vis_dev);
  476. }
  477. BOOL OpDocumentEdit::HandleMouseEvent(HTML_Element* helm, DOM_EventType event, int x, long y, MouseButton button)
  478. {
  479. DEBUG_CHECKER(TRUE);
  480. BOOL handled = m_layout_modifier.HandleMouseEvent(helm, event, x, y, button);
  481. if (!handled && event == ONMOUSEDOWN)
  482. {
  483. FocusEditableRoot(helm, FOCUS_REASON_MOUSE);
  484. #if defined(_X11_SELECTION_POLICY_)
  485. if (button == MOUSE_BUTTON_3 && GetEditableContainer(helm))
  486. {
  487. g_clipboard_manager->SetMouseSelectionMode(TRUE);
  488. if (g_clipboard_manager->HasText())
  489. {
  490. g_clipboard_manager->Paste(this, m_doc, m_caret.GetElement());
  491. }
  492. g_clipboard_manager->SetMouseSelectionMode(FALSE);
  493. handled = TRUE; // Must set to TRUE, otherwise we get bug #217331
  494. }
  495. #endif
  496. }
  497. return handled;
  498. }
  499. BOOL OpDocumentEdit::IsLayoutModifiable(HTML_Element* helm)
  500. {
  501. DEBUG_CHECKER(TRUE);
  502. return m_layout_modifier.IsLayoutModifiable(helm);
  503. }
  504. CursorType OpDocumentEdit::GetCursorType(HTML_Element* helm, int x, int y)
  505. {
  506. DEBUG_CHECKER(TRUE);
  507. if (!m_body_is_root && !m_caret.IsElementEditable(helm))
  508. return CURSOR_AUTO;
  509. return m_layout_modifier.GetCursorType(helm, x, y);
  510. }
  511. #ifdef SUPPORT_TEXT_DIRECTION
  512. BOOL OpDocumentEdit::SetRTL(bool is_rtl)
  513. {
  514. if (GetRTL() == (BOOL)is_rtl)
  515. return FALSE;
  516. DEBUG_CHECKER(TRUE);
  517. HTML_Element* helm = GetEditableContainer(m_caret.GetElement());
  518. if (helm)
  519. {
  520. BeginChange(helm);
  521. OnElementChange(helm);
  522. helm->SetAttribute(m_doc, ATTR_DIR, NULL, NS_IDX_DEFAULT, is_rtl ? UNI_L("rtl") : UNI_L("ltr"), 3, NULL, FALSE);
  523. OnElementChanged(helm);
  524. EndChange(helm);
  525. if (m_listener)
  526. m_listener->OnTextDirectionChanged(is_rtl);
  527. return TRUE;
  528. }
  529. return FALSE;
  530. }
  531. #endif // SUPPORT_TEXT_DIRECTION
  532. void OpDocumentEdit::AutodetectDirection()
  533. {
  534. #ifdef DOCUMENTEDIT_AUTODETECT_DIRECTION
  535. if (!m_autodetect_direction)
  536. return;
  537. HTML_Element *body = GetBody();
  538. if (body)
  539. {
  540. HTML_Element *text = FindElementAfterOfType(body, HE_TEXT, TRUE);
  541. BOOL detected = FALSE;
  542. if (text)
  543. {
  544. for (const uni_char* c = text->TextContent(); !detected && c && *c; c++)
  545. {
  546. switch (Unicode::GetBidiCategory(*c))
  547. {
  548. case BIDI_R:
  549. case BIDI_AL:
  550. if (SetRTL(TRUE))
  551. m_undo_stack.MergeLastChanges();
  552. detected = TRUE;
  553. break;
  554. case BIDI_L:
  555. if (SetRTL(FALSE))
  556. m_undo_stack.MergeLastChanges();
  557. detected = TRUE;
  558. break;
  559. }
  560. }
  561. }
  562. }
  563. #endif // DOCUMENTEDIT_AUTODETECT_DIRECTION
  564. }
  565. void OpDocumentEdit::Copy(BOOL cut)
  566. {
  567. DEBUG_CHECKER(TRUE);
  568. #ifdef USE_OP_CLIPBOARD
  569. HTML_Element* target_elm = m_layout_modifier.IsActive() ? m_layout_modifier.m_helm : (m_selection.HasContent() ? m_selection.GetStartElement() : NULL);
  570. if (cut)
  571. {
  572. REPORT_AND_RETURN_IF_ERROR(g_clipboard_manager->Cut(this, GetDoc()->GetWindow()->GetUrlContextId(), m_doc, target_elm))
  573. }
  574. else
  575. {
  576. REPORT_AND_RETURN_IF_ERROR(g_clipboard_manager->Copy(this, GetDoc()->GetWindow()->GetUrlContextId(), m_doc, target_elm))
  577. }
  578. #endif // USE_OP_CLIPBOARD
  579. }
  580. void OpDocumentEdit::Paste()
  581. {
  582. #ifdef USE_OP_CLIPBOARD
  583. HTML_Element* target = m_selection.HasContent() ? m_selection.GetStartElement() : m_caret.GetElement();
  584. g_clipboard_manager->Paste(this, m_doc, target);
  585. #endif // USE_OP_CLIPBOARD
  586. }
  587. #ifdef USE_OP_CLIPBOARD
  588. void OpDocumentEdit::OnCopy(OpClipboard* clipboard)
  589. {
  590. DEBUG_CHECKER(TRUE);
  591. #ifdef USE_OP_CLIPBOARD
  592. # ifdef CLIPBOARD_HTML_SUPPORT
  593. if (m_layout_modifier.IsActive())
  594. {
  595. # ifdef _X11_SELECTION_POLICY_
  596. if (!g_clipboard_manager->GetMouseSelectionMode())
  597. # endif // _X11_SELECTION_POLICY_
  598. {
  599. OpString htmltext;
  600. REPORT_AND_RETURN_IF_ERROR(GetTextHTMLFromElement(htmltext, m_layout_modifier.m_helm, TRUE));
  601. if (htmltext.Length())
  602. {
  603. REPORT_AND_RETURN_IF_ERROR(clipboard->PlaceTextHTML(htmltext.CStr(), UNI_L(""), GetDoc()->GetWindow()->GetUrlContextId()))
  604. }
  605. }
  606. return;
  607. }
  608. # endif
  609. if (!m_selection.HasContent())
  610. return;
  611. OpString text;
  612. REPORT_AND_RETURN_IF_ERROR(m_selection.GetText(text));
  613. if (!text.Length())
  614. return;
  615. # ifdef CLIPBOARD_HTML_SUPPORT
  616. # ifdef _X11_SELECTION_POLICY_
  617. if (!g_clipboard_manager->GetMouseSelectionMode())
  618. # else // _X11_SELECTION_POLICY_
  619. if (TRUE)
  620. # endif // _X11_SELECTION_POLICY_
  621. {
  622. OpString htmltext;
  623. REPORT_AND_RETURN_IF_ERROR(m_selection.GetTextHTML(htmltext));
  624. if (htmltext.Length())
  625. {
  626. REPORT_AND_RETURN_IF_ERROR(clipboard->PlaceTextHTML(htmltext.CStr(), text.CStr(), GetDoc()->GetWindow()->GetUrlContextId()))
  627. }
  628. }
  629. else
  630. REPORT_AND_RETURN_IF_ERROR(clipboard->PlaceText(text.CStr(), GetDoc()->GetWindow()->GetUrlContextId()))
  631. # else
  632. REPORT_AND_RETURN_IF_ERROR(clipboard->PlaceText(text.CStr(), GetDoc()->GetWindow()->GetUrlContextId()))
  633. # endif
  634. #endif // USE_OP_CLIPBOARD
  635. }
  636. void OpDocumentEdit::OnPaste(OpClipboard* clipboard)
  637. {
  638. if(m_readonly)
  639. return;
  640. DEBUG_CHECKER(TRUE);
  641. OpString text;
  642. BOOL take_text = TRUE;
  643. # ifdef CLIPBOARD_HTML_SUPPORT
  644. if (!m_plain_text_mode
  645. # ifdef _X11_SELECTION_POLICY_
  646. && !clipboard->GetMouseSelectionMode()
  647. # endif // _X11_SELECTION_POLICY_
  648. && clipboard->HasTextHTML())
  649. {
  650. REPORT_AND_RETURN_IF_ERROR((clipboard->GetTextHTML(text)));
  651. REPORT_AND_RETURN_IF_ERROR(InsertTextHTML(text.CStr(), text.Length(), NULL, NULL, NULL));
  652. take_text = FALSE;
  653. }
  654. # endif
  655. if (take_text)
  656. {
  657. if (clipboard->HasText())
  658. {
  659. REPORT_AND_RETURN_IF_ERROR((clipboard->GetText(text)));
  660. REPORT_AND_RETURN_IF_ERROR(InsertText(text.CStr(), text.Length()));
  661. }
  662. else
  663. return;
  664. }
  665. ScrollIfNeeded();
  666. m_caret.UpdateWantedX();
  667. }
  668. #endif // USE_OP_CLIPBOARD
  669. void OpDocumentEdit::Undo()
  670. {
  671. DEBUG_CHECKER(TRUE);
  672. if (m_undo_stack.CanUndo())
  673. {
  674. Begin();
  675. if (m_selection.HasContent())
  676. m_selection.SelectNothing();
  677. m_undo_stack.Undo();
  678. End();
  679. ScrollIfNeeded();
  680. m_caret.UpdateWantedX();
  681. }
  682. }
  683. void OpDocumentEdit::Redo()
  684. {
  685. DEBUG_CHECKER(TRUE);
  686. if (m_undo_stack.CanRedo())
  687. {
  688. Begin();
  689. if (m_selection.HasContent())
  690. m_selection.SelectNothing();
  691. m_undo_stack.Redo();
  692. End();
  693. ScrollIfNeeded();
  694. m_caret.UpdateWantedX();
  695. }
  696. }
  697. OP_STATUS OpDocumentEdit::SetText(const uni_char* text)
  698. {
  699. DEBUG_CHECKER(TRUE);
  700. Begin();
  701. RETURN_IF_ERROR(Clear());
  702. OP_STATUS status = InsertText(text, uni_strlen(text));
  703. m_undo_stack.Clear();
  704. End();
  705. return status;
  706. }
  707. OP_STATUS OpDocumentEdit::SetTextHTML(const uni_char* text)
  708. {
  709. DEBUG_CHECKER(TRUE);
  710. Begin();
  711. RETURN_IF_ERROR(Clear());
  712. OP_STATUS status = InsertTextHTML(text, uni_strlen(text), NULL, NULL, NULL, TIDY_LEVEL_AGGRESSIVE);
  713. m_undo_stack.Clear();
  714. End();
  715. return status;
  716. }
  717. OP_STATUS OpDocumentEdit::GetText(OpString& text, BOOL block_quotes_as_text)
  718. {
  719. DEBUG_CHECKER(TRUE);
  720. if (!GetBody())
  721. return text.Set(UNI_L(""));
  722. TextSelection text_selection;
  723. text_selection.SetNewSelection(GetDoc(), GetBody(), FALSE, FALSE, TRUE);
  724. int len = text_selection.GetSelectionAsText(GetDoc(), NULL, 0, TRUE, block_quotes_as_text);
  725. if (text.Reserve(len + 1) == NULL)
  726. return OpStatus::ERR_NO_MEMORY;
  727. text_selection.GetSelectionAsText(GetDoc(), text.CStr(), len + 1, TRUE, block_quotes_as_text);
  728. return OpStatus::OK;
  729. }
  730. OP_STATUS OpDocumentEdit::GetTextHTML(OpString& text)
  731. {
  732. DEBUG_CHECKER(TRUE);
  733. HTML_Element* body = GetBody();
  734. if (body)
  735. return GetTextHTMLFromElement(text, body, FALSE);
  736. else
  737. return OpStatus::OK;
  738. }
  739. void OpDocumentEdit::OnDOMChangedSelection()
  740. {
  741. DEBUG_CHECKER(TRUE);
  742. if (TextSelection* sel = m_doc->GetTextSelection())
  743. {
  744. SelectionBoundaryPoint focus_point = *sel->GetFocusPoint();
  745. HTML_Element* focus_elm = focus_point.GetElement();
  746. HTML_Element* edit_root = GetEditableContainer(focus_elm);
  747. if (focus_elm && edit_root && sel->IsEmpty())
  748. {
  749. // Focus point inside the editable block so we must make sure to make it suitable for a caret.
  750. HTML_Element* caret_elm = focus_elm;
  751. HTML_Element* elm_to_put_caret_after = NULL;
  752. int caret_offset = focus_point.GetOffset(); // offset here means a number of a child element.
  753. m_caret.StoreRealCaretPlacement(caret_elm, caret_offset);
  754. BOOL force_br = FALSE;
  755. if (!caret_elm->IsText())
  756. {
  757. caret_elm = focus_elm->FirstChildActualStyle();
  758. force_br = !caret_elm;
  759. while (caret_offset > 0)
  760. {
  761. elm_to_put_caret_after = caret_elm;
  762. caret_elm = caret_elm->SucActualStyle();
  763. --caret_offset;
  764. }
  765. force_br = force_br || (caret_elm && !caret_elm->FirstChildActualStyle());
  766. }
  767. if ((!caret_elm || !IsElementValidForCaret(caret_elm, TRUE, FALSE, TRUE)) && !IsStandaloneElement(focus_elm))
  768. {
  769. /* Looks like the selection point is an element a caret normally can not be placed in.
  770. * However if it's not a standalone element, init the caret in it to allow placing
  771. * the caret in the empty selection.
  772. */
  773. caret_elm = m_caret.CreateTemporaryCaretHelm(focus_elm, elm_to_put_caret_after, !IsNoTextContainer(focus_elm) && !force_br);
  774. if (!caret_elm)
  775. {
  776. m_doc->GetWindow()->RaiseCondition(OpStatus::ERR_NO_MEMORY);
  777. return;
  778. }
  779. caret_offset = 0;
  780. }
  781. else if (!caret_elm && elm_to_put_caret_after)
  782. {
  783. caret_elm = elm_to_put_caret_after;
  784. caret_offset = caret_elm->IsText() ? caret_elm->GetTextContentLength() : 0;
  785. }
  786. m_caret.Set(caret_elm, caret_offset);
  787. if (IsFocused())
  788. {
  789. if (caret_elm)
  790. m_doc->GetCaretPainter()->RestartBlink();
  791. else
  792. m_doc->GetCaretPainter()->StopBlink();
  793. }
  794. m_caret.CleanTemporaryCaretTextElement(FALSE);
  795. }
  796. }
  797. }
  798. /* static */
  799. SelectionBoundaryPoint OldStyleTextSelectionPoint::ConvertFromOldStyleSelectionPoint(const OldStyleTextSelectionPoint& point)
  800. {
  801. HTML_Element* elm = point.GetElement();
  802. int offset = point.GetOffset();
  803. if (!elm)
  804. return SelectionBoundaryPoint();
  805. // We have a slight incompatibility between the caret representation here and the selection
  806. // implementation so we need to do some conversion. Will be removed when (if?) the caret
  807. // is moved into the normal selection.
  808. SelectionBoundaryPoint return_value = TextSelection::ConvertFromOldStyle(elm, offset);
  809. return_value.SetBindDirection(point.GetBindDirection());
  810. return return_value;
  811. }
  812. BOOL OpDocumentEdit::GetSelection(SelectionBoundaryPoint &anchor, SelectionBoundaryPoint &focus)
  813. {
  814. DEBUG_CHECKER(TRUE);
  815. if (m_recreate_caret && !m_caret.GetElement() && !m_caret.m_parent_candidate)
  816. {
  817. ReflowAndUpdate();
  818. CheckLogTreeChanged(FALSE);
  819. m_caret.Init(TRUE, NULL);
  820. }
  821. m_recreate_caret = FALSE;
  822. if (m_caret.GetElement())
  823. {
  824. OldStyleTextSelectionPoint caret_point;
  825. caret_point.SetLogicalPosition(m_caret.GetElement(), m_caret.GetOffset());
  826. SelectionBoundaryPoint dom_compatible_caret_point = OldStyleTextSelectionPoint::ConvertFromOldStyleSelectionPoint(caret_point);
  827. if (m_selection.HasContent())
  828. {
  829. TextSelection* text_selection = m_doc->GetTextSelection();
  830. anchor = *text_selection->GetAnchorPoint();
  831. focus = *text_selection->GetFocusPoint();
  832. }
  833. else if (m_layout_modifier.IsActive())
  834. {
  835. anchor = OldStyleTextSelectionPoint::ConvertFromOldStyleSelectionPoint(GetTextSelectionPoint(m_layout_modifier.m_helm, 0));
  836. focus = anchor;
  837. }
  838. else
  839. {
  840. anchor = dom_compatible_caret_point;
  841. focus = dom_compatible_caret_point;
  842. }
  843. return TRUE;
  844. }
  845. else if (m_caret.m_parent_candidate)
  846. {
  847. anchor = OldStyleTextSelectionPoint::ConvertFromOldStyleSelectionPoint(GetTextSelectionPoint(m_caret.m_parent_candidate, 0));
  848. focus = anchor;
  849. }
  850. return FALSE;
  851. }
  852. void OpDocumentEdit::ClearPendingStyles()
  853. {
  854. DEBUG_CHECKER(TRUE);
  855. if(m_pending_styles_lock)
  856. return;
  857. OP_DOCUMENT_EDIT_PENDING_STYLES* pending_style = (OP_DOCUMENT_EDIT_PENDING_STYLES*) m_pending_styles.First();
  858. while (pending_style)
  859. {
  860. OP_DOCUMENT_EDIT_PENDING_STYLES* suc = (OP_DOCUMENT_EDIT_PENDING_STYLES*) pending_style->Suc();
  861. DeleteElement(pending_style->helm);
  862. pending_style->Out();
  863. OP_DELETE(pending_style);
  864. pending_style = suc;
  865. }
  866. }
  867. OP_STATUS OpDocumentEdit::InsertStyleElementLayoutModified(HTML_Element* helm)
  868. {
  869. DEBUG_CHECKER(TRUE);
  870. HTML_Element *target = m_layout_modifier.m_helm;
  871. DUMPDEBUGTREE
  872. helm->PrecedeSafe(m_doc, target);
  873. target->OutSafe(m_doc, FALSE);
  874. target->UnderSafe(m_doc, helm);
  875. helm->MarkExtraDirty(m_doc);
  876. target->MarkExtraDirty(m_doc);
  877. DUMPDEBUGTREE
  878. ReflowAndUpdate();
  879. m_caret.UpdatePos();
  880. return OpStatus::OK;
  881. }
  882. OP_STATUS OpDocumentEdit::InsertStyleElementSingle(HTML_Element* helm, HTML_ElementType exclude_type, BOOL allow_nestling)
  883. {
  884. DEBUG_CHECKER(TRUE);
  885. // Get text as html, remove it and add it again. This way, we will get the selected text under its own set of
  886. // styletags. The we can easily run through them and remove the tags of type type and move the children up one level.
  887. SelectionState state = GetSelectionState(FALSE, FALSE, TRUE, TRUE);
  888. if(!state.IsValid())
  889. {
  890. OP_ASSERT(FALSE); // This function should ONLY be called when editable content is selected!
  891. DeleteElement(helm);
  892. return OpStatus::ERR;
  893. }
  894. OP_STATUS status = OpStatus::OK;
  895. OpString text;
  896. RETURN_IF_ERROR(m_selection.GetTextHTML(text,FALSE));
  897. HTML_Element *shared_containing_elm = GetSharedContainingElement(state.editable_start_elm,state.editable_stop_elm);
  898. m_selection.SelectNothing();
  899. m_caret.LockUpdatePos(TRUE);
  900. m_selection.RemoveContent(FALSE, state.editable_start_elm, state.editable_stop_elm, state.editable_start_ofs, state.editable_stop_ofs);
  901. // Make sure caret is inside shared_containing_elm in order to not create problems in InserTextHTML
  902. while(!shared_containing_elm->IsAncestorOf(m_caret.GetElement()))
  903. {
  904. if(shared_containing_elm->Precedes(m_caret.GetElement()))
  905. m_caret.Move(FALSE,FALSE);
  906. else
  907. m_caret.Move(TRUE,FALSE);
  908. }
  909. DUMPDEBUGTREE
  910. HTML_Element *result_start = NULL, *result_stop = NULL;
  911. status = InsertTextHTML(text, text.Length(), &result_start, &result_stop, NULL, TIDY_LEVEL_AGGRESSIVE);
  912. if (!result_start)
  913. {
  914. // InsertTextHTML Did not produce anything. Use the caretelement as referenceelement.
  915. result_start = m_caret.GetElement();
  916. result_stop = m_caret.GetElement();
  917. }
  918. HTML_Element *start_sel_element = (HTML_Element*)result_start->FirstLeaf();
  919. DUMPDEBUGTREE
  920. m_caret.LockUpdatePos(FALSE,FALSE);
  921. m_caret.Place(m_caret.GetElement(),m_caret.GetOffset());
  922. RETURN_IF_ERROR(status);
  923. helm->PrecedeSafe(m_doc, result_start);
  924. helm->MarkExtraDirty(m_doc);
  925. // mark result_start->result_stop extra dirty???
  926. MoveSiblingBlock(SiblingBlock(result_start,result_stop),helm);
  927. HTML_Element* new_caret_elm = FindEditableElement(start_sel_element, TRUE, TRUE, FALSE);
  928. Tidy(result_start, result_stop, TRUE);
  929. ReflowAndUpdate();
  930. m_caret.UpdatePos();
  931. OldStyleTextSelectionPoint s1 = GetTextSelectionPoint(new_caret_elm, 0);
  932. OldStyleTextSelectionPoint s2 = GetTextSelectionPoint(m_caret.GetElement(), m_caret.GetOffset());
  933. m_selection.Select(&s1, &s2);
  934. return OpStatus::OK;
  935. }
  936. OP_STATUS OpDocumentEdit::InsertStyleElementMultiple(HTML_Element* helm, HTML_ElementType exclude_type, BOOL allow_nestling)
  937. {
  938. DEBUG_CHECKER(TRUE);
  939. SelectionState selection_state = GetSelectionState(TRUE, FALSE, TRUE, TRUE);
  940. if(!selection_state.IsValid())
  941. {
  942. OP_ASSERT(FALSE); // This function should ONLY be called when editable content is selected!
  943. DeleteElement(helm);
  944. return OpStatus::ERR;
  945. }
  946. HTML_Element* start_elm = selection_state.editable_start_elm;
  947. HTML_Element* stop_elm = selection_state.editable_stop_elm;
  948. int start_ofs = selection_state.editable_start_ofs;
  949. int stop_ofs = selection_state.editable_stop_ofs;
  950. BOOL single_element = (start_elm == stop_elm);
  951. // Split start and stop so we can insert the style on only the selected parts.
  952. SplitElement(stop_elm, stop_ofs);
  953. BOOL split1 = SplitElement(start_elm, start_ofs);
  954. if (split1)
  955. start_elm = start_elm->NextActual();
  956. if (single_element)
  957. stop_elm = start_elm;
  958. OP_STATUS status = OpStatus::OK;
  959. // Run through the selection and insert several instances of helm where it is needed.
  960. HTML_Element* tmp = start_elm;
  961. while(tmp)
  962. {
  963. // FIX: insert fewer elements by setting it outside friendly elements.
  964. if ((tmp->Type() == HE_TEXT || tmp->Type() == HE_BR || (tmp->Type() == HE_IMG && helm->Type() == HE_A)) && !(exclude_type && GetHasStyleInternal(tmp,exclude_type,ATTR_NULL)))
  965. {
  966. HTML_Element* new_style = NewCopyOfElement(helm,TRUE);
  967. if (!new_style)
  968. {
  969. status = OpStatus::ERR_NO_MEMORY;
  970. break;
  971. }
  972. new_style->PrecedeSafe(m_doc, tmp);
  973. tmp->OutSafe(m_doc, FALSE);
  974. tmp->UnderSafe(m_doc, new_style);
  975. new_style->MarkExtraDirty(m_doc);
  976. }
  977. if (tmp == stop_elm)
  978. break;
  979. tmp = tmp->NextActual();
  980. }
  981. DeleteElement(helm);
  982. DUMPDEBUGTREE
  983. RestoreSelectionState(selection_state);
  984. return status;
  985. }
  986. OP_STATUS OpDocumentEdit::InsertStyleElement(HTML_Element* helm, HTML_ElementType exclude_type, BOOL allow_nestling, HTML_ElementType must_be_below_this_type)
  987. {
  988. DEBUG_CHECKER(TRUE);
  989. SelectionState state = GetSelectionState(FALSE);
  990. if (state.HasEditableContent())
  991. {
  992. // Run through the selection and insert several instances of helm where it is needed.
  993. HTML_Element* shared_containing_elm = GetSharedContainingElement(state.editable_start_elm, state.editable_stop_elm);
  994. BeginChange(shared_containing_elm);
  995. HTML_Element* start_elm = state.editable_start_elm;
  996. HTML_Element* stop_elm = state.editable_stop_elm;
  997. BOOL need_multiple = (exclude_type && GetHasStyle(exclude_type)) ||
  998. (must_be_below_this_type && GetHasStyle(must_be_below_this_type)) ||
  999. !IsFriends(start_elm, stop_elm, TRUE, TRUE, TRUE);
  1000. if (need_multiple || start_elm == stop_elm)
  1001. InsertStyleElementMultiple(helm,exclude_type,allow_nestling);
  1002. else
  1003. InsertStyleElementSingle(helm,exclude_type,allow_nestling);
  1004. EndChange(shared_containing_elm);
  1005. }
  1006. else if (m_layout_modifier.IsActive())
  1007. {
  1008. HTML_Element *parent = m_layout_modifier.m_helm->ParentActual();
  1009. RETURN_IF_MEMORY_ERROR(BeginChange(parent));
  1010. OP_STATUS status = InsertStyleElementLayoutModified(helm);
  1011. RETURN_IF_MEMORY_ERROR(EndChange(parent));
  1012. return status;
  1013. }
  1014. else
  1015. {
  1016. if(exclude_type && GetHasPendingStyle(exclude_type))
  1017. {
  1018. DeleteElement(helm);
  1019. return OpStatus::OK;
  1020. }
  1021. // No selection. Insert helm at the caretposition with a empty textelement.
  1022. /* HTML_Element *new_content = NewTextElement(document_edit_dummy_str, 1);
  1023. if (!new_content)
  1024. return OpStatus::ERR_NO_MEMORY;
  1025. new_content->UnderSafe(helm);
  1026. InsertElement(helm);
  1027. m_caret.Place(new_content, 0);*/
  1028. // No selection. Add the style to the pending list so it will be added when text is added (if the caret isn't
  1029. // moved away from the current spot).
  1030. // First check if it's already in the pending list and in that case remove it.
  1031. OP_DOCUMENT_EDIT_PENDING_STYLES *pending_style;
  1032. if(!allow_nestling)
  1033. {
  1034. pending_style = (OP_DOCUMENT_EDIT_PENDING_STYLES*) m_pending_styles.First();
  1035. while (pending_style)
  1036. {
  1037. if (IsMatchingStyle(pending_style->helm, helm->Type(), ATTR_NULL))
  1038. {
  1039. DeleteElement(pending_style->helm);
  1040. pending_style->Out();
  1041. OP_DELETE(pending_style);
  1042. DeleteElement(helm);
  1043. return OpStatus::OK;
  1044. }
  1045. pending_style = (OP_DOCUMENT_EDIT_PENDING_STYLES*) pending_style->Suc();
  1046. }
  1047. }
  1048. pending_style = OP_NEW(OP_DOCUMENT_EDIT_PENDING_STYLES, ());
  1049. if (!pending_style)
  1050. return OpStatus::ERR_NO_MEMORY;
  1051. pending_style->helm = helm;
  1052. if(must_be_below_this_type)
  1053. pending_style->Into(&m_pending_styles);
  1054. else
  1055. pending_style->IntoStart(&m_pending_styles);
  1056. }
  1057. return OpStatus::OK;
  1058. }
  1059. void OpDocumentEdit::InsertStyle(HTML_ElementType type, HTML_ElementType exclude_type, BOOL allow_nestling, HTML_ElementType must_be_below_this_type)
  1060. {
  1061. DEBUG_CHECKER(TRUE);
  1062. if(exclude_type && GetHasStyle(exclude_type,ATTR_NULL,TRUE))
  1063. return; // Everything should be excluded!
  1064. HTML_Element *new_elm = NewElement(type);
  1065. if (!new_elm)
  1066. {
  1067. ReportOOM();
  1068. return;
  1069. }
  1070. REPORT_AND_RETURN_IF_ERROR(InsertStyleElement(new_elm,exclude_type,allow_nestling,must_be_below_this_type));
  1071. }
  1072. void OpDocumentEdit::InsertFont(short attr, void* val)
  1073. {
  1074. DEBUG_CHECKER(TRUE);
  1075. OpDocumentEditUndoRedoAutoGroup autogroup(&m_undo_stack);
  1076. if (GetHasStyle(HE_FONT, attr))
  1077. RemoveStyle(HE_FONT, attr);
  1078. HTML_Element *new_elm = NewElement(HE_FONT);
  1079. if (!new_elm)
  1080. {
  1081. ReportOOM();
  1082. return;
  1083. }
  1084. if (attr == ATTR_FACE)
  1085. {
  1086. void *value = NULL;
  1087. ItemType item_type;
  1088. BOOL need_free;
  1089. BOOL is_event;
  1090. HtmlAttrEntry hae[2];
  1091. hae[0].attr = ATTR_FACE;
  1092. hae[0].value = static_cast<uni_char*>(val);
  1093. hae[0].value_len = uni_strlen(hae[0].value);
  1094. hae[1].attr = ATTR_NULL;
  1095. if (OpStatus::IsMemoryError(new_elm->ConstructAttrVal(m_doc->GetHLDocProfile(), &hae[0], FALSE, value, item_type, need_free, is_event, hae, NULL)))
  1096. {
  1097. ReportOOM();
  1098. return;
  1099. }
  1100. new_elm->SetAttr(ATTR_FACE, item_type, value, need_free, NS_IDX_DEFAULT, FALSE, FALSE, FALSE, is_event);
  1101. }
  1102. else
  1103. new_elm->SetAttr(attr, ITEM_TYPE_NUM, val);
  1104. REPORT_AND_RETURN_IF_ERROR(InsertStyleElement(new_elm));
  1105. }
  1106. void OpDocumentEdit::InsertFontColor(UINT32 color)
  1107. {
  1108. DEBUG_CHECKER(TRUE);
  1109. InsertFont(ATTR_COLOR, reinterpret_cast<void*>(color));
  1110. }
  1111. void OpDocumentEdit::InsertFontFace(const uni_char* fontface)
  1112. {
  1113. DEBUG_CHECKER(TRUE);
  1114. InsertFont(ATTR_FACE, (void*)fontface);
  1115. }
  1116. void OpDocumentEdit::InsertFontSize(UINT32 size)
  1117. {
  1118. DEBUG_CHECKER(TRUE);
  1119. InsertFont(ATTR_SIZE, reinterpret_cast<void*>(size));
  1120. }
  1121. BOOL OpDocumentEdit::IsMatchingStyle(HTML_Element* helm, HTML_ElementType type, short attr)
  1122. {
  1123. DEBUG_CHECKER(TRUE);
  1124. if (type == HE_ANY && IsFriendlyElement(helm) /*&& HasAttribute(helm, attr)*/ && !IsStandaloneElement(helm))
  1125. return TRUE;
  1126. return (helm->Type() == type && HasAttribute(helm, attr));
  1127. }
  1128. BOOL OpDocumentEdit::IsAnyOfTypes(HTML_Element *helm, HTML_ElementType *types, short attr)
  1129. {
  1130. DEBUG_CHECKER(TRUE);
  1131. while(*types != HE_UNKNOWN)
  1132. {
  1133. if(IsMatchingStyle(helm,*types,attr))
  1134. return TRUE;
  1135. types++;
  1136. }
  1137. return FALSE;
  1138. }
  1139. HTML_Element *OpDocumentEdit::GetRootOfTypes(HTML_Element *helm, HTML_ElementType *types, short attr)
  1140. {
  1141. DEBUG_CHECKER(TRUE);
  1142. HTML_Element *root = NULL;
  1143. while(helm)
  1144. {
  1145. if(IsAnyOfTypes(helm,types,attr))
  1146. root = helm;
  1147. helm = helm->ParentActual();
  1148. }
  1149. return root;
  1150. }
  1151. HTML_Element* OpDocumentEdit::ExtractTreeBeside(HTML_Element *root, HTML_Element *helm, BOOL extract_left)
  1152. {
  1153. DEBUG_CHECKER(TRUE);
  1154. HTML_Element *tmp = helm;
  1155. OP_ASSERT(root->IsAncestorOf(helm));
  1156. while(tmp != root)
  1157. {
  1158. if(extract_left ? tmp->Pred() : tmp->Suc())
  1159. break;
  1160. tmp = tmp->Parent();
  1161. }
  1162. if(tmp == root)
  1163. {
  1164. OP_ASSERT(FALSE);
  1165. return NULL;
  1166. }
  1167. HTML_Element *new_tree = NULL;
  1168. while(tmp != root)
  1169. {
  1170. HTML_Element *parent = tmp->Parent();
  1171. HTML_Element *top = NewCopyOfElement(parent,TRUE);
  1172. if(!top)
  1173. {
  1174. while(new_tree && new_tree->FirstLeaf())
  1175. DeleteElement((HTML_Element*)new_tree->FirstLeaf());
  1176. ReportOOM();
  1177. return NULL;
  1178. }
  1179. if(extract_left)
  1180. {
  1181. while(parent->FirstChild() != tmp)
  1182. {
  1183. helm = parent->FirstChild();
  1184. helm->OutSafe(m_doc, FALSE);
  1185. helm->UnderSafe(m_doc,top);
  1186. }
  1187. }
  1188. else
  1189. {
  1190. while(tmp->Suc())
  1191. {
  1192. helm = tmp->Suc();
  1193. helm->OutSafe(m_doc, FALSE);
  1194. helm->UnderSafe(m_doc,top);
  1195. }
  1196. }
  1197. if(new_tree)
  1198. new_tree->UnderSafe(m_doc,top);
  1199. new_tree = top;
  1200. tmp = parent;
  1201. }
  1202. return new_tree;
  1203. }
  1204. OP_STATUS OpDocumentEdit::ExtractElementsTo(HTML_Element *start_elm, HTML_Element *stop_elm, HTML_Element *old_root, HTML_Element *new_root, HTML_Element *after_me)
  1205. {
  1206. DEBUG_CHECKER(TRUE);
  1207. OP_ASSERT(new_root);
  1208. if(!start_elm && !stop_elm)
  1209. {
  1210. if(!old_root)
  1211. {
  1212. OP_ASSERT(FALSE);
  1213. return OpStatus::ERR;
  1214. }
  1215. SiblingBlock block(old_root->FirstChildActual(),old_root->LastChildActual());
  1216. if(!block.IsEmpty())
  1217. MoveSiblingBlock(block,new_root,after_me);
  1218. return OpStatus::OK;
  1219. }
  1220. if(!start_elm || !stop_elm)
  1221. {
  1222. HTML_Element *dummy_elm;
  1223. if(!start_elm)
  1224. GetBlockStartStopInternal(&start_elm,&dummy_elm,stop_elm);
  1225. else
  1226. GetBlockStartStopInternal(&dummy_elm,&stop_elm,start_elm);
  1227. OP_ASSERT(start_elm && stop_elm);
  1228. }
  1229. if(!old_root)
  1230. {
  1231. old_root = GetSharedContainingElement(start_elm,stop_elm);
  1232. OP_ASSERT(old_root);
  1233. }
  1234. if(!old_root->IsAncestorOf(start_elm) || !old_root->IsAncestorOf(stop_elm))
  1235. {
  1236. OP_ASSERT(FALSE);
  1237. return OpStatus::ERR;
  1238. }
  1239. while(start_elm->Parent() != old_root)
  1240. {
  1241. HTML_Element *parent = start_elm->Parent();
  1242. if(parent->FirstChild() != start_elm)
  1243. {
  1244. HTML_Element *new_parent = NewCopyOfElement(parent,TRUE);
  1245. if(!new_parent)
  1246. {
  1247. ReportOOM();
  1248. return OpStatus::ERR_NO_MEMORY;
  1249. }
  1250. new_parent->PrecedeSafe(m_doc,parent);
  1251. SiblingBlock block(parent->FirstChildActual(),start_elm->PredActual());
  1252. MoveSiblingBlock(block,new_parent);
  1253. }
  1254. start_elm = parent;
  1255. }
  1256. while(stop_elm->Parent() != old_root)
  1257. {
  1258. HTML_Element *parent = stop_elm->Parent();
  1259. if(parent->LastChild() != stop_elm)
  1260. {
  1261. HTML_Element *new_parent = NewCopyOfElement(parent,TRUE);
  1262. if(!new_parent)
  1263. {
  1264. ReportOOM();
  1265. return OpStatus::ERR_NO_MEMORY;
  1266. }
  1267. new_parent->FollowSafe(m_doc,parent);
  1268. SiblingBlock block(stop_elm->SucActual(),parent->LastChildActual());
  1269. MoveSiblingBlock(block,new_parent);
  1270. }
  1271. stop_elm = parent;
  1272. }
  1273. SiblingBlock block(start_elm,stop_elm);
  1274. MoveSiblingBlock(block,new_root,after_me);
  1275. return OpStatus::OK;
  1276. }
  1277. void OpDocumentEdit::RemoveStyleElementMultiple(HTML_ElementType type, short attr, BOOL just_one_level)
  1278. {
  1279. DEBUG_CHECKER(TRUE);
  1280. SelectionState selection_state = GetSelectionState(TRUE, FALSE, TRUE, TRUE);
  1281. if(!selection_state.IsValid())
  1282. return;
  1283. HTML_Element* start_elm = selection_state.editable_start_elm;
  1284. HTML_Element* stop_elm = selection_state.editable_stop_elm;
  1285. int start_ofs = selection_state.editable_start_ofs;
  1286. int stop_ofs = selection_state.editable_stop_ofs;
  1287. OP_ASSERT(start_elm != stop_elm);
  1288. HTML_Element* shared_containing_elm = GetSharedContainingElement(start_elm, stop_elm);
  1289. BeginChange(shared_containing_elm);
  1290. // Possibly split start- and stop-elements in order to only remove style from selected text
  1291. SplitElement(stop_elm, stop_ofs);
  1292. BOOL split1 = SplitElement(start_elm, start_ofs);
  1293. if(split1)
  1294. {
  1295. // If split1 is true, the element was split, and this is safe:
  1296. // coverity[returned_null: FALSE]
  1297. start_elm = start_elm->SucActual();
  1298. }
  1299. HTML_Element *tmp = start_elm;
  1300. while(tmp->Parent() != shared_containing_elm)
  1301. tmp = tmp->Parent();
  1302. BOOL start_elm_deleted = FALSE; // It MIGHT happen that start_elm is a style element that is deleted
  1303. while(tmp)
  1304. {
  1305. HTML_Element* tmp_next = (HTML_Element*) tmp->Next();
  1306. BOOL is_start_elm_ancestor = !start_elm_deleted && tmp->IsAncestorOf(start_elm);
  1307. if(IsMatchingStyle(tmp, type, attr) && tmp->IsIncludedActual() &&
  1308. (start_elm_deleted || is_start_elm_ancestor || !tmp->Precedes(start_elm)))
  1309. {
  1310. // We might need to split the tree to the left of start_elm or to the right of
  1311. // stop_elm in order not remove style from text before/after selection
  1312. if(is_start_elm_ancestor && start_elm->FirstLeaf() != tmp->FirstLeaf() &&
  1313. HasActualBeside(tmp,start_elm,TRUE))
  1314. {
  1315. HTML_Element *left_tree = ExtractTreeBeside(tmp,start_elm,TRUE);
  1316. if(!left_tree)
  1317. return;
  1318. left_tree->PrecedeSafe(m_doc,tmp);
  1319. }
  1320. BOOL is_stop_elm_ancestor = tmp->IsAncestorOf(stop_elm);
  1321. if(is_stop_elm_ancestor && stop_elm->LastLeaf() != tmp->LastLeaf() &&
  1322. HasActualBeside(tmp,stop_elm,FALSE))
  1323. {
  1324. HTML_Element *right_tree = ExtractTreeBeside(tmp,stop_elm,FALSE);
  1325. if(!right_tree)
  1326. return;
  1327. right_tree->FollowSafe(m_doc,tmp);
  1328. }
  1329. // Move children of the deleted style up one level...
  1330. SiblingBlock children = SiblingBlock(tmp->FirstChildActual(),tmp->LastChildActual());
  1331. MoveSiblingBlock(children,tmp->Parent(),tmp->Pred());
  1332. DeleteElement(tmp);
  1333. if(start_elm == tmp)
  1334. start_elm_deleted = TRUE;
  1335. if(just_one_level && is_stop_elm_ancestor)
  1336. break;
  1337. if(just_one_level)
  1338. {
  1339. if(!children.IsEmpty())
  1340. {
  1341. // Don't search the children of the deleted style when we're just removing one level
  1342. tmp_next = (HTML_Element*)children.stop->NextSibling();
  1343. if(!tmp_next)
  1344. {
  1345. OP_ASSERT(FALSE);
  1346. break;
  1347. }
  1348. }
  1349. }
  1350. else if(!children.IsEmpty())
  1351. tmp_next = children.start;
  1352. }
  1353. if(tmp == stop_elm)
  1354. break;
  1355. tmp = tmp_next;
  1356. }
  1357. shared_containing_elm->MarkExtraDirty(m_doc);
  1358. RestoreSelectionState(selection_state);
  1359. EndChange(shared_containing_elm);
  1360. }
  1361. void OpDocumentEdit::RemoveStyleElementSingle(HTML_ElementType type, short attr, BOOL just_one_level)
  1362. {
  1363. DEBUG_CHECKER(TRUE);
  1364. SelectionState state = GetSelectionState(FALSE, FALSE, TRUE, TRUE);
  1365. if(!state.IsValid())
  1366. return;
  1367. HTML_Element* shared_containing_elm = GetSharedContainingElement(state.editable_start_elm, state.editable_stop_elm);
  1368. OP_STATUS status = BeginChange(shared_containing_elm);
  1369. REPORT_AND_RETURN_IF_ERROR(status);
  1370. // Remove the content and insert it again. This is to have all selected text undependent of the
  1371. // surrounding text so we then can remove the elements of type from that section.
  1372. // Create a dummy element after the branch we are removing so the caret will jump to it if everything in this
  1373. // branch is removed in RemoveSelection. (Must do this to get the text back at the correct place.)
  1374. HTML_Element* dummy_elm = NewTextElement(document_edit_dummy_str, 1);
  1375. HTML_Element* dummy_tmp = shared_containing_elm->LastChildActual();
  1376. while(dummy_tmp && !dummy_tmp->IsAncestorOf(state.editable_stop_elm))
  1377. {
  1378. dummy_tmp = dummy_tmp->PredActual();
  1379. }
  1380. if(!dummy_tmp || !dummy_elm)
  1381. {
  1382. OP_ASSERT(FALSE);
  1383. DeleteElement(dummy_elm);
  1384. AbortChange();
  1385. return;
  1386. }
  1387. dummy_elm->FollowSafe(m_doc, dummy_tmp);
  1388. OpString text;
  1389. status = m_selection.GetTextHTML(text,FALSE);
  1390. if (OpStatus::IsError(status))
  1391. {
  1392. if (OpStatus::IsMemoryError(status))
  1393. ReportOOM();
  1394. AbortChange();
  1395. return;
  1396. }
  1397. m_selection.SelectNothing();
  1398. m_caret.LockUpdatePos(TRUE);
  1399. m_selection.RemoveContent(FALSE, state.editable_start_elm, state.editable_stop_elm, state.editable_start_ofs, state.editable_stop_ofs);
  1400. DUMPDEBUGTREE
  1401. HTML_Element *result_start = NULL, *result_stop = NULL;
  1402. status = InsertTextHTML(text, text.Length(), &result_start, &result_stop, NULL);
  1403. if (OpStatus::IsError(status))
  1404. {
  1405. if (OpStatus::IsMemoryError(status))
  1406. ReportOOM();
  1407. AbortChange();
  1408. return;
  1409. }
  1410. m_caret.LockUpdatePos(FALSE,FALSE);
  1411. m_caret.Place(m_caret.GetElement(),m_caret.GetOffset());
  1412. if (result_stop)
  1413. {
  1414. HTML_Element* last_leaf = result_stop->LastLeafActual();
  1415. if (last_leaf)
  1416. result_stop = last_leaf;
  1417. }
  1418. HTML_Element *start_sel_element = result_start ? result_start->FirstLeafActual() : NULL;
  1419. DUMPDEBUGTREE
  1420. HTML_Element* tmp = result_start;
  1421. // Remove all elements of type type. If there is children, move them up to the parent.
  1422. while(tmp)
  1423. {
  1424. HTML_Element* tmp_next = (HTML_Element*) tmp->NextActual();
  1425. if (IsMatchingStyle(tmp, type, attr))
  1426. {
  1427. DUMPDEBUGTREE
  1428. if (result_start == tmp)
  1429. result_start = FindEditableElement(tmp, TRUE, FALSE, FALSE);
  1430. if (result_stop == tmp)
  1431. {
  1432. //result_stop = FindElementBeforeOfType(tmp, HE_TEXT);
  1433. OP_ASSERT(0); // Can this still happen?
  1434. }
  1435. SiblingBlock children = SiblingBlock(tmp->FirstChildActual(),tmp->LastChildActual());
  1436. BOOL do_break = just_one_level && tmp->IsAncestorOf(result_stop);
  1437. MoveSiblingBlock(children,tmp->ParentActual(),tmp->PredActual());
  1438. DeleteElement(tmp);
  1439. if(do_break)
  1440. break;
  1441. if(just_one_level && !children.IsEmpty())
  1442. tmp_next = (HTML_Element*)children.stop->NextSiblingActual();
  1443. DUMPDEBUGTREE
  1444. }
  1445. // Check if we've reached the end of the elements we should move, including some ugly
  1446. // hack just in case we passed result_stop without noticing (FIXME)
  1447. if (tmp == result_stop || (tmp_next && result_stop && !tmp_next->Precedes(result_stop)))
  1448. break;
  1449. tmp = tmp_next;
  1450. }
  1451. ReflowAndUpdate();
  1452. HTML_Element* new_caret_elm = start_sel_element;
  1453. int new_caret_ofs = 0;
  1454. if (GetNearestCaretPos(start_sel_element, &new_caret_elm, &new_caret_ofs, TRUE, TRUE) ||
  1455. GetNearestCaretPos(start_sel_element, &new_caret_elm, &new_caret_ofs, FALSE, TRUE))
  1456. {
  1457. OldStyleTextSelectionPoint s1 = GetTextSelectionPoint(new_caret_elm, new_caret_ofs);
  1458. OldStyleTextSelectionPoint s2 = GetTextSelectionPoint(m_caret.GetElement(), m_caret.GetOffset());
  1459. m_selection.Select(&s1, &s2);
  1460. }
  1461. m_caret.UpdatePos();
  1462. status = EndChange(shared_containing_elm, TIDY_LEVEL_AGGRESSIVE);
  1463. }
  1464. void OpDocumentEdit::RemoveStyle(HTML_ElementType type, short attr, BOOL just_one_level)
  1465. {
  1466. DEBUG_CHECKER(TRUE);
  1467. OP_ASSERT(GetHasStyle(type, attr));
  1468. SelectionState state = GetSelectionState(FALSE, FALSE, TRUE, TRUE);
  1469. if (state.HasEditableContent())
  1470. {
  1471. BOOL need_multiple = !IsFriends(state.editable_start_elm, state.editable_stop_elm, TRUE, TRUE, TRUE);
  1472. if (need_multiple)
  1473. RemoveStyleElementMultiple(type, attr, just_one_level);
  1474. else
  1475. RemoveStyleElementSingle(type, attr, just_one_level);
  1476. }
  1477. else
  1478. {
  1479. m_selection.SelectNothing();
  1480. OP_DOCUMENT_EDIT_PENDING_STYLES *pending_style = (OP_DOCUMENT_EDIT_PENDING_STYLES*) m_pending_styles.First();
  1481. while (pending_style)
  1482. {
  1483. OP_DOCUMENT_EDIT_PENDING_STYLES *suc_style = (OP_DOCUMENT_EDIT_PENDING_STYLES*) pending_style->Suc();
  1484. if (IsMatchingStyle(pending_style->helm, type, ATTR_NULL))
  1485. {
  1486. DeleteElement(pending_style->helm);
  1487. pending_style->Out();
  1488. OP_DELETE(pending_style);
  1489. if(just_one_level)
  1490. return;
  1491. }
  1492. pending_style = suc_style;
  1493. }
  1494. if(!m_caret.GetElement() || !GetHasStyle(type, attr, FALSE, FALSE))
  1495. return;
  1496. HTML_Element* containing_elm = m_doc->GetCaret()->GetContainingElementActual(m_caret.GetElement());
  1497. BOOL in_dummy = FALSE;
  1498. if (m_caret.GetElement()->Type() == HE_TEXT && m_caret.GetElement()->GetTextContentLength() == 0)
  1499. // Simple way to destroy dummy (in tidy) if there is one.
  1500. in_dummy = TRUE;
  1501. // Create a temporary copy of the current branch up to
  1502. // containing_elm, excluding the style we are removing.
  1503. HTML_Element* tmp = NewTextElement(document_edit_dummy_str, 1);
  1504. if (!tmp)
  1505. {
  1506. ReportOOM();
  1507. return;
  1508. }
  1509. HTML_Element* parent = m_caret.GetElement()->ParentActual();
  1510. // If just_one_level==TRUE -> after not copying one element with matching style,
  1511. // copy the rest even though they are matching.
  1512. BOOL omit_matching = TRUE;
  1513. while (parent != containing_elm)
  1514. {
  1515. if (!omit_matching || !IsMatchingStyle(parent, type, attr))
  1516. {
  1517. HTML_Element* new_tmp = NewCopyOfElement(parent,TRUE);
  1518. if (new_tmp)
  1519. tmp->UnderSafe(m_doc, new_tmp);
  1520. else
  1521. {
  1522. ReportOOM();
  1523. break;
  1524. }
  1525. tmp = new_tmp;
  1526. }
  1527. else if(just_one_level)
  1528. omit_matching = FALSE;
  1529. parent = parent->ParentActual();
  1530. }
  1531. OpString text;
  1532. GetTextHTMLFromElement(text, tmp, TRUE);
  1533. DeleteElement(tmp);
  1534. // Insert it with containing_elm as split_root
  1535. InsertTextHTML(text, text.Length(), NULL, NULL, containing_elm, in_dummy ? TIDY_LEVEL_AGGRESSIVE : TIDY_LEVEL_NORMAL);
  1536. }
  1537. }
  1538. BOOL OpDocumentEdit::GetHasStyleInternal(HTML_Element* helm, HTML_ElementType type, short attr)
  1539. {
  1540. DEBUG_CHECKER(TRUE);
  1541. return GetStyleElementInternal(helm,type,attr) != NULL;
  1542. }
  1543. HTML_Element *OpDocumentEdit::GetStyleElementInternal(HTML_Element* helm, HTML_ElementType type, short attr)
  1544. {
  1545. DEBUG_CHECKER(TRUE);
  1546. if(!helm)
  1547. return NULL;
  1548. HTML_Element* tmp = helm->Parent();
  1549. while(tmp && tmp->Type() != HE_BODY)
  1550. {
  1551. if (IsMatchingStyle(tmp, type, attr))
  1552. return tmp;
  1553. tmp = tmp->ParentActual();
  1554. }
  1555. return NULL;
  1556. }
  1557. BOOL OpDocumentEdit::GetHasBlockTypesInternal(HTML_Element *helm, HTML_ElementType *types, short attr)
  1558. {
  1559. DEBUG_CHECKER(TRUE);
  1560. HTML_Element* tmp = helm ? helm->Parent() : NULL;
  1561. while(tmp && tmp->Type() != HE_BODY)
  1562. {
  1563. if(IsAnyOfTypes(tmp,types,attr))
  1564. return TRUE;
  1565. tmp = tmp->ParentActual();
  1566. }
  1567. return FALSE;
  1568. }
  1569. HTML_Element* OpDocumentEdit::GetTopMostParentOfType(HTML_Element *helm, HTML_ElementType type)
  1570. {
  1571. HTML_Element* candidate = NULL;
  1572. while (helm)
  1573. {
  1574. if (helm->IsMatchingType(type, NS_HTML))
  1575. candidate = helm;
  1576. helm = helm->ParentActual();
  1577. }
  1578. return candidate;
  1579. }
  1580. BOOL OpDocumentEdit::GetHasPendingStyle(HTML_ElementType type, short attr)
  1581. {
  1582. DEBUG_CHECKER(TRUE);
  1583. OP_DOCUMENT_EDIT_PENDING_STYLES* pending_style = (OP_DOCUMENT_EDIT_PENDING_STYLES*) m_pending_styles.First();
  1584. while (pending_style)
  1585. {
  1586. if(IsMatchingStyle(pending_style->helm,type,attr))
  1587. return TRUE;
  1588. pending_style = (OP_DOCUMENT_EDIT_PENDING_STYLES*) pending_style->Suc();
  1589. }
  1590. return FALSE;
  1591. }
  1592. BOOL OpDocumentEdit::GetHasStyle(HTML_ElementType type, short attr, BOOL all_must_have_style, BOOL include_pending_styles)
  1593. {
  1594. DEBUG_CHECKER(TRUE);
  1595. SelectionState state = GetSelectionState(FALSE);
  1596. if (state.HasEditableContent())
  1597. {
  1598. // Check if some elements inside the selection has type.
  1599. HTML_Element* start_elm = state.editable_start_elm;
  1600. HTML_Element* stop_elm = state.editable_stop_elm;
  1601. if(start_elm != stop_elm)
  1602. {
  1603. HTML_Element* tmp = start_elm->NextActual();
  1604. while(tmp != stop_elm)
  1605. {
  1606. if (IsMatchingStyle(tmp, type, attr))
  1607. {
  1608. if(!all_must_have_style)
  1609. return TRUE;
  1610. else // This might not be enough, because all TEXT/BR elements must be under the style
  1611. {
  1612. if(tmp->IsAncestorOf(stop_elm))
  1613. break;
  1614. tmp = (HTML_Element*)tmp->NextSiblingActual();
  1615. continue;
  1616. }
  1617. }
  1618. else if(all_must_have_style && (tmp->Type() == HE_TEXT || tmp->Type() == HE_BR))
  1619. {
  1620. HTML_Element *style_elm = GetStyleElementInternal(tmp,type,attr);
  1621. if(!style_elm)
  1622. return FALSE;
  1623. if(style_elm->IsAncestorOf(stop_elm))
  1624. break;
  1625. tmp = (HTML_Element*)style_elm->NextSiblingActual();
  1626. continue;
  1627. }
  1628. tmp = (HTML_Element*) tmp->NextActual();
  1629. }
  1630. }
  1631. // Check if the start or stop is under a element of type type.
  1632. // Don't care about the start if the selectionpoint is at the end of it.
  1633. if (GetHasStyleInternal(start_elm, type, attr))
  1634. {
  1635. if(!all_must_have_style)
  1636. return TRUE;
  1637. }
  1638. else if(all_must_have_style)
  1639. return FALSE;
  1640. return GetHasStyleInternal(stop_elm, type, attr);
  1641. }
  1642. else
  1643. {
  1644. return (include_pending_styles && GetHasPendingStyle(type,attr)) || GetHasStyleInternal(m_caret.GetElement(), type, attr);
  1645. }
  1646. }
  1647. short OpDocumentEdit::GetFontSize()
  1648. {
  1649. DEBUG_CHECKER(TRUE);
  1650. // if (!m_selection.HasContent())
  1651. {
  1652. OP_DOCUMENT_EDIT_PENDING_STYLES* pending_style = (OP_DOCUMENT_EDIT_PENDING_STYLES*) m_pending_styles.First();
  1653. while (pending_style)
  1654. {
  1655. if (pending_style->helm->IsMatchingType(HE_FONT, NS_HTML) && pending_style->helm->HasAttr(ATTR_SIZE))
  1656. return static_cast<short>(pending_style->helm->GetNumAttr(ATTR_SIZE));
  1657. pending_style = (OP_DOCUMENT_EDIT_PENDING_STYLES*) pending_style->Suc();
  1658. }
  1659. HTML_Element* tmp = m_caret.GetElement();
  1660. while(tmp)
  1661. {
  1662. if (tmp->GetFontSizeDefined())
  1663. return (short) tmp->GetFontSize();
  1664. tmp = tmp->Parent();
  1665. }
  1666. }
  1667. return 3; // The default
  1668. }
  1669. const uni_char* OpDocumentEdit::GetFontFace()
  1670. {
  1671. DEBUG_CHECKER(TRUE);
  1672. // if (!m_selection.HasContent())
  1673. {
  1674. OP_DOCUMENT_EDIT_PENDING_STYLES* pending_style = (OP_DOCUMENT_EDIT_PENDING_STYLES*) m_pending_styles.First();
  1675. while (pending_style)
  1676. {
  1677. if (pending_style->helm->IsMatchingType(HE_FONT, NS_HTML) && pending_style->helm->HasAttr(ATTR_FACE))
  1678. return pending_style->helm->GetAttrValue(ATTR_FACE, NS_IDX_HTML);
  1679. pending_style = (OP_DOCUMENT_EDIT_PENDING_STYLES*) pending_style->Suc();
  1680. }
  1681. HTML_Element* tmp = m_caret.GetElement();
  1682. while(tmp)
  1683. {
  1684. if (tmp->Type() == HE_FONT && HasAttribute(tmp, ATTR_FACE))
  1685. {
  1686. return tmp->GetAttrValue(ATTR_FACE, NS_IDX_HTML);
  1687. }
  1688. tmp = tmp->Parent();
  1689. }
  1690. }
  1691. const uni_char *const result = UNI_L(""); // ADS 1.2 can't cope with returning it directly !
  1692. return result;
  1693. }
  1694. static OP_STATUS FormatDeclaration(TempBuffer *tmp_buffer, CSS_decl *decl)
  1695. {
  1696. TRAPD(status, CSS::FormatDeclarationL(tmp_buffer, decl, FALSE, CSS_FORMAT_COMPUTED_STYLE));
  1697. return status;
  1698. }
  1699. OP_STATUS OpDocumentEdit::GetFontFace(TempBuffer &output)
  1700. {
  1701. OP_DOCUMENT_EDIT_PENDING_STYLES* pending_style = (OP_DOCUMENT_EDIT_PENDING_STYLES*) m_pending_styles.First();
  1702. while (pending_style)
  1703. {
  1704. if (pending_style->helm->IsMatchingType(HE_FONT, NS_HTML) && pending_style->helm->HasAttr(ATTR_FACE))
  1705. return output.Append(pending_style->helm->GetAttrValue(ATTR_FACE, NS_IDX_HTML));
  1706. pending_style = (OP_DOCUMENT_EDIT_PENDING_STYLES*) pending_style->Suc();
  1707. }
  1708. HTML_Element* tmp = m_caret.GetElement();
  1709. while(tmp)
  1710. {
  1711. // Handle font att
  1712. if (tmp->Type() == HE_FONT && HasAttribute(tmp, ATTR_FACE))
  1713. return output.Append(tmp->GetAttrValue(ATTR_FACE, NS_IDX_HTML));
  1714. // Handle inline style
  1715. CSS_property_list* prop_list = tmp->GetCSS_Style();
  1716. CSS_decl *decl = prop_list ? prop_list->GetFirstDecl() : NULL;
  1717. while (decl)
  1718. {
  1719. if (decl->GetProperty() == CSS_PROPERTY_font_family)
  1720. {
  1721. OP_STATUS status = FormatDeclaration(&output, decl);
  1722. if (OpStatus::IsSuccess(status))
  1723. return OpStatus::OK;
  1724. }
  1725. decl = decl->Suc();
  1726. }
  1727. tmp = tmp->ParentActual();
  1728. }
  1729. return OpStatus::OK;
  1730. }
  1731. void OpDocumentEdit::GetBlockStartStopInternal(HTML_Element** start, HTML_Element** stop, HTML_Element* from)
  1732. {
  1733. DEBUG_CHECKER(TRUE);
  1734. if(!from)
  1735. {
  1736. OP_ASSERT(FALSE);
  1737. start = stop = NULL;
  1738. return;
  1739. }
  1740. HTML_Element* tmp = from;
  1741. while(tmp->PrevActual() && IsFriends(tmp->PrevActual(), from, TRUE, TRUE))
  1742. tmp = tmp->PrevActual();
  1743. *start = tmp;
  1744. tmp = from;
  1745. while(tmp->NextActual() && IsFriends(from, tmp->NextActual(), TRUE, TRUE))
  1746. tmp = tmp->NextActual();
  1747. // Include the br at the end of the block.
  1748. if (tmp->NextActual() && IsEndingBr(tmp->NextActual()))
  1749. tmp = tmp->NextActual();
  1750. *stop = tmp;
  1751. }
  1752. void OpDocumentEdit::GetBlockStartStop(HTML_Element** start, HTML_Element** stop)
  1753. {
  1754. DEBUG_CHECKER(TRUE);
  1755. ReflowAndUpdate();
  1756. SelectionState state = GetSelectionState(FALSE);
  1757. if (state.HasEditableContent())
  1758. {
  1759. OP_ASSERT(state.editable_start_elm == state.editable_stop_elm || state.editable_start_elm->Precedes(state.editable_stop_elm));
  1760. HTML_Element *start1, *stop1, *start2, *stop2;
  1761. GetBlockStartStopInternal(&start1, &stop1, state.editable_start_elm);
  1762. GetBlockStartStopInternal(&start2, &stop2, state.editable_stop_elm);
  1763. *start = start1;
  1764. *stop = stop2;
  1765. }
  1766. else
  1767. {
  1768. GetBlockStartStopInternal(start, stop, m_caret.GetElement());
  1769. }
  1770. }
  1771. BOOL OpDocumentEdit::HasBlockElementChildren(HTML_Element *helm)
  1772. {
  1773. DEBUG_CHECKER(TRUE);
  1774. HTML_Element *child = helm->FirstChildActual();
  1775. while(child)
  1776. {
  1777. if(IsBlockElement(child))
  1778. return TRUE;
  1779. child = child->SucActual();
  1780. }
  1781. return FALSE;
  1782. }
  1783. BOOL OpDocumentEdit::GetEditableSubrange(HTML_Element *&start_elm, HTML_Element *&stop_elm, int &start_ofs, int &stop_ofs)
  1784. {
  1785. DEBUG_CHECKER(TRUE);
  1786. if(!start_elm || !stop_elm)
  1787. return FALSE;
  1788. HTML_Element *new_start_elm = start_elm, *new_stop_elm = stop_elm;
  1789. int new_start_ofs = start_ofs, new_stop_ofs = stop_ofs;
  1790. if(new_start_elm->Type() == HE_BR)
  1791. new_start_ofs = 0;
  1792. if(new_stop_elm->Type() == HE_BR)
  1793. new_stop_ofs = 0;
  1794. int valid_ofs = 0;
  1795. BOOL has_valid_ofs = GetLastValidCaretOfs(new_start_elm,valid_ofs);
  1796. if(!has_valid_ofs || (start_ofs >= valid_ofs && new_start_elm->Type() != HE_BR))
  1797. {
  1798. if(new_start_elm == new_stop_elm)
  1799. return FALSE;
  1800. do
  1801. {
  1802. new_start_elm = new_start_elm->Next();
  1803. } while(new_start_elm && !IsElementValidForCaret(new_start_elm) && new_start_elm != new_stop_elm);
  1804. if(!new_start_elm || !IsElementValidForCaret(new_start_elm))
  1805. return FALSE;
  1806. new_start_ofs = 0;
  1807. }
  1808. BOOL is_before_stop = TRUE;
  1809. if(IsElementValidForCaret(new_stop_elm))
  1810. {
  1811. GetValidCaretPosFrom(new_stop_elm,0,new_stop_elm,valid_ofs);
  1812. is_before_stop = new_stop_ofs <= valid_ofs && new_stop_elm->Type() != HE_BR;
  1813. }
  1814. if(is_before_stop)
  1815. {
  1816. if(new_start_elm == new_stop_elm)
  1817. return FALSE;
  1818. do
  1819. {
  1820. new_stop_elm = new_stop_elm->Prev();
  1821. } while(new_stop_elm && !IsElementValidForCaret(new_stop_elm) && new_start_elm != new_stop_elm);
  1822. if(!new_stop_elm) // otherwise new_stop_elm is valid for caret (because new_start_elm is valid)
  1823. return FALSE;
  1824. if(new_stop_elm->Type() == HE_TEXT)
  1825. new_stop_ofs = new_stop_elm->GetTextContentLength();
  1826. else
  1827. GetLastValidCaretOfs(new_stop_elm,new_stop_ofs);
  1828. }
  1829. start_elm = new_start_elm;
  1830. stop_elm = new_stop_elm;
  1831. start_ofs = new_start_ofs;
  1832. stop_ofs = new_stop_ofs;
  1833. return TRUE;
  1834. }
  1835. BOOL OpDocumentEdit::ActualizeSelectionState(SelectionState &state)
  1836. {
  1837. HTML_Element *tmp;
  1838. BOOL adjusted = FALSE;
  1839. if(!state.HasContent())
  1840. {
  1841. OP_ASSERT(FALSE); // This function should only be used when state has content!
  1842. return FALSE;
  1843. }
  1844. if(!state.start_elm->IsIncludedActual())
  1845. {
  1846. adjusted = TRUE;
  1847. if(!state.start_ofs && state.start_elm->PrevActual() &&
  1848. state.start_elm->PrevActual()->IsAncestorOf(state.start_elm))
  1849. {
  1850. state.start_elm = state.start_elm->PrevActual();
  1851. }
  1852. else
  1853. {
  1854. if(state.start_ofs)
  1855. {
  1856. if(state.start_elm->IsAncestorOf(state.stop_elm))
  1857. return FALSE;
  1858. state.start_elm = (HTML_Element*)state.start_elm->NextSibling();
  1859. }
  1860. else
  1861. {
  1862. state.start_elm = state.start_elm->Next();
  1863. }
  1864. while(state.start_elm)
  1865. {
  1866. if(state.start_elm->GetInserted() <= HE_INSERTED_FIRST_HIDDEN_BY_ACTUAL)
  1867. break;
  1868. if(state.start_elm == state.stop_elm)
  1869. return FALSE;
  1870. state.start_elm = state.start_elm->Next();
  1871. }
  1872. if(!state.start_elm)
  1873. return FALSE;
  1874. state.start_ofs = 0;
  1875. }
  1876. }
  1877. if(!state.stop_elm->IsIncludedActual())
  1878. {
  1879. adjusted = TRUE;
  1880. if(state.stop_ofs)
  1881. {
  1882. tmp = state.stop_elm->LastLeaf();
  1883. if(!tmp)
  1884. tmp = state.stop_elm;
  1885. if(state.stop_elm->ParentActual() && !state.stop_elm->ParentActual()->IsAncestorOf(tmp->NextActual()))
  1886. {
  1887. state.stop_elm = state.stop_elm->ParentActual();
  1888. goto stop_found;
  1889. }
  1890. for(tmp = state.stop_elm->LastLeaf(); tmp && tmp != state.stop_elm ; tmp = tmp->Prev())
  1891. {
  1892. if(tmp->IsIncludedActual())
  1893. {
  1894. state.stop_elm = tmp;
  1895. goto stop_found;
  1896. }
  1897. }
  1898. }
  1899. for(tmp = state.stop_elm; tmp; tmp = tmp->Prev())
  1900. {
  1901. if(!tmp->IsAncestorOf(state.stop_elm) && tmp->GetInserted() <= HE_INSERTED_FIRST_HIDDEN_BY_ACTUAL)
  1902. {
  1903. state.stop_elm = tmp;
  1904. goto stop_found;
  1905. }
  1906. }
  1907. stop_found:
  1908. state.stop_ofs = state.stop_elm->Type() == HE_TEXT ? state.stop_elm->GetTextContentLength() : 1;
  1909. }
  1910. if(adjusted)
  1911. {
  1912. OP_ASSERT(!(state.stop_elm->Precedes(state.start_elm) || (state.start_elm == state.stop_elm && state.start_ofs > state.stop_ofs)));
  1913. OP_ASSERT(state.start_elm->IsIncludedActual() && state.stop_elm->IsIncludedActual());
  1914. return state.HasContent();
  1915. }
  1916. return TRUE;
  1917. }
  1918. SelectionState OpDocumentEdit::GetSelectionState(BOOL de_select, BOOL de_caret, BOOL require_editable, BOOL actual_only)
  1919. {
  1920. DEBUG_CHECKER(TRUE);
  1921. // Assume that we never want to reset the caret and return no selection state.
  1922. // I have no idea why this function was once changed to do the opposite (unintentional?).
  1923. // We still let GetValidCaretPosFrom change it if it wants though.
  1924. SelectionState state;
  1925. state.caret_elm = m_caret.GetElement();
  1926. state.caret_ofs = m_caret.GetOffset();
  1927. if(m_selection.HasContent())
  1928. {
  1929. state.start_elm = m_selection.GetStartElement(actual_only);
  1930. state.stop_elm = m_selection.GetStopElement(actual_only);
  1931. state.start_ofs = m_selection.GetStartOfs();
  1932. state.stop_ofs = m_selection.GetStopOfs();
  1933. TextSelection::ConvertPointToOldStyle(SelectionBoundaryPoint(state.start_elm, state.start_ofs), state.start_elm, state.start_ofs);
  1934. TextSelection::ConvertPointToOldStyle(SelectionBoundaryPoint(state.stop_elm, state.stop_ofs), state.stop_elm, state.stop_ofs);
  1935. if(!m_caret.IsElementEditable(state.start_elm) || !m_caret.IsElementEditable(state.stop_elm))
  1936. return SelectionState();
  1937. //if(ActualizeSelectionState(state))
  1938. {
  1939. state.editable_start_elm = state.start_elm;
  1940. state.editable_stop_elm = state.stop_elm;
  1941. state.editable_start_ofs = state.start_ofs;
  1942. state.editable_stop_ofs = state.stop_ofs;
  1943. if(!GetEditableSubrange(state.editable_start_elm, state.editable_stop_elm, state.editable_start_ofs, state.editable_stop_ofs))
  1944. {
  1945. state.editable_start_elm = state.editable_stop_elm = NULL;
  1946. }
  1947. if(state.editable_start_elm || !require_editable)
  1948. {
  1949. if(de_select)
  1950. {
  1951. m_selection.SelectNothing();
  1952. state.removed_selection = TRUE;
  1953. }
  1954. if(de_caret && state.caret_elm)
  1955. {
  1956. m_caret.Set(NULL,0);
  1957. state.removed_caret = TRUE;
  1958. }
  1959. return state;
  1960. }
  1961. }
  1962. }
  1963. if(!state.caret_elm)
  1964. return SelectionState();
  1965. state.start_elm = state.stop_elm = state.caret_elm;
  1966. state.start_ofs = state.stop_ofs = state.caret_ofs;
  1967. state.editable_start_elm = state.editable_stop_elm = state.caret_elm;
  1968. state.editable_start_ofs = state.editable_stop_ofs = state.caret_ofs;
  1969. state.caret_at_end = m_selection.IsEndPointFocusPoint();
  1970. if(de_caret)
  1971. {
  1972. m_caret.Set(NULL,0);
  1973. state.removed_caret = TRUE;
  1974. }
  1975. return state;
  1976. }
  1977. void OpDocumentEdit::RestoreSelectionState(SelectionState state)
  1978. {
  1979. DEBUG_CHECKER(TRUE);
  1980. OP_ASSERT(state.start_elm->IsIncludedActual());
  1981. OP_ASSERT(state.stop_elm->IsIncludedActual());
  1982. ReflowAndUpdate();
  1983. if(state.removed_selection)
  1984. {
  1985. AdjustTextOfs(state.start_elm,state.start_ofs);
  1986. AdjustTextOfs(state.stop_elm,state.stop_ofs);
  1987. OldStyleTextSelectionPoint s1 = GetTextSelectionPoint(state.start_elm, state.start_ofs);
  1988. OldStyleTextSelectionPoint s2 = GetTextSelectionPoint(state.stop_elm, state.stop_ofs);
  1989. m_selection.Select(&s1, &s2, state.caret_at_end);
  1990. }
  1991. else if(state.caret_elm)
  1992. {
  1993. AdjustTextOfs(state.caret_elm,state.caret_ofs);
  1994. HTML_Element *old_caret_elm = m_caret.GetElement();
  1995. int old_caret_offset = m_caret.GetOffset();
  1996. OldStyleTextSelectionPoint s1 = GetTextSelectionPoint(state.caret_elm, state.caret_ofs);
  1997. OldStyleTextSelectionPoint s2 = s1;
  1998. m_selection.Select(&s1, &s2, state.caret_at_end);
  1999. // The caret could be set outside the editable element.
  2000. if (old_caret_elm && !m_caret.GetElement())
  2001. {
  2002. SelectionBoundaryPoint s1(old_caret_elm, old_caret_offset);
  2003. SelectionBoundaryPoint s2 = s1;
  2004. m_doc->SetSelection(&s1, &s2, state.caret_at_end);
  2005. }
  2006. }
  2007. }
  2008. BOOL OpDocumentEdit::AdjustTextOfs(HTML_Element *&helm, int &ofs)
  2009. {
  2010. DEBUG_CHECKER(TRUE);
  2011. if(!helm || helm->Type() != HE_TEXT || helm->GetTextContentLength() > ofs)
  2012. return FALSE;
  2013. HTML_Element *next_helm = NULL;
  2014. if(helm->GetTextContentLength() == ofs)
  2015. {
  2016. next_helm = FindEditableElement(helm,TRUE,FALSE,FALSE);
  2017. if(next_helm && next_helm->Type() == HE_TEXT && IsFriends(helm,next_helm))
  2018. {
  2019. helm = next_helm;
  2020. ofs = 0;
  2021. return TRUE;
  2022. }
  2023. return FALSE;
  2024. }
  2025. int count = helm->GetTextContentLength();
  2026. next_helm = helm;
  2027. HTML_Element *last_helm = helm;
  2028. int last_ofs = helm->GetTextContentLength();
  2029. for(;;)
  2030. {
  2031. next_helm = FindEditableElement(next_helm,TRUE,FALSE,TRUE);
  2032. if(!next_helm)
  2033. break;
  2034. if(next_helm->Type() == HE_TEXT)
  2035. {
  2036. int len = next_helm->GetTextContentLength();
  2037. if(count+len >= ofs)
  2038. {
  2039. helm = next_helm;
  2040. ofs = ofs - count;
  2041. return TRUE;
  2042. }
  2043. count += len;
  2044. last_helm = next_helm;
  2045. last_ofs = len;
  2046. }
  2047. }
  2048. if(last_helm != helm) // ok... the desired offset cant be found in the document, set helm+ofs to end of last text-element
  2049. {
  2050. helm = last_helm;
  2051. ofs = last_ofs;
  2052. return TRUE;
  2053. }
  2054. return FALSE;
  2055. }
  2056. void OpDocumentEdit::RemoveBlockTypes(HTML_ElementType *types, short attr, BOOL just_one_level, HTML_ElementType exclude_at_bottom_type)
  2057. {
  2058. DEBUG_CHECKER(TRUE);
  2059. if(!GetHasBlockTypes(types,attr))
  2060. return;
  2061. SelectionState selection_state = GetSelectionState(TRUE, FALSE, TRUE, TRUE);
  2062. if(!selection_state.IsValid())
  2063. return;
  2064. HTML_Element *start_elm = selection_state.editable_start_elm;
  2065. HTML_Element *stop_elm = selection_state.editable_stop_elm;
  2066. HTML_Element *dummy_elm;
  2067. GetBlockStartStopInternal(&start_elm,&dummy_elm,start_elm);
  2068. GetBlockStartStopInternal(&dummy_elm,&stop_elm,stop_elm);
  2069. HTML_Element *tmp = GetSharedContainingElement(start_elm,stop_elm);
  2070. if(!tmp)
  2071. {
  2072. OP_ASSERT(FALSE);
  2073. return;
  2074. }
  2075. HTML_Element *shared_containing_elm = tmp;
  2076. /* Make sure shared_containing_elm is outside of any elements that should be removed,
  2077. * but don't search past the contentEditable element (if there is one). */
  2078. while(tmp && tmp->Type() != HE_BODY && !tmp->IsContentEditable(FALSE /*inherit*/))
  2079. {
  2080. if(IsAnyOfTypes(tmp,types,attr))
  2081. shared_containing_elm = tmp->ParentActual();
  2082. tmp = tmp->ParentActual();
  2083. }
  2084. OP_STATUS status = BeginChange(shared_containing_elm);
  2085. REPORT_AND_RETURN_IF_ERROR(status);
  2086. tmp = start_elm;
  2087. while(tmp->Parent() != shared_containing_elm)
  2088. tmp = tmp->Parent();
  2089. BOOL start_elm_deleted = FALSE; // It MIGHT happen that start_elm is a block element that is deleted
  2090. while(tmp)
  2091. {
  2092. HTML_Element* tmp_next = (HTML_Element*) tmp->Next();
  2093. BOOL is_start_elm_ancestor = !start_elm_deleted && tmp->IsAncestorOf(start_elm);
  2094. if(IsAnyOfTypes(tmp, types, attr) && !tmp->IsContentEditable(FALSE /*inherit*/) && tmp->IsIncludedActual() &&
  2095. (start_elm_deleted || is_start_elm_ancestor || !tmp->Precedes(start_elm)) &&
  2096. !(tmp->Type() == exclude_at_bottom_type && !HasBlockElementChildren(tmp)))
  2097. {
  2098. if(is_start_elm_ancestor && start_elm->FirstLeaf() != tmp->FirstLeaf() &&
  2099. HasActualBeside(tmp,start_elm,TRUE))
  2100. {
  2101. HTML_Element *left_tree = ExtractTreeBeside(tmp,start_elm,TRUE);
  2102. if(!left_tree)
  2103. {
  2104. AbortChange();
  2105. return;
  2106. }
  2107. left_tree->PrecedeSafe(m_doc,tmp);
  2108. }
  2109. BOOL is_stop_elm_ancestor = tmp->IsAncestorOf(stop_elm);
  2110. if(is_stop_elm_ancestor && stop_elm->LastLeaf() != tmp->LastLeaf() &&
  2111. HasActualBeside(tmp,stop_elm,FALSE))
  2112. {
  2113. HTML_Element *right_tree = ExtractTreeBeside(tmp,stop_elm,FALSE);
  2114. if(!right_tree)
  2115. {
  2116. AbortChange();
  2117. return;
  2118. }
  2119. right_tree->FollowSafe(m_doc,tmp);
  2120. }
  2121. SiblingBlock children = SiblingBlock(tmp->FirstChildActual(),tmp->LastChildActual());
  2122. MoveSiblingBlock(children,tmp->Parent(),tmp->Pred());
  2123. DeleteElement(tmp);
  2124. if(tmp == start_elm)
  2125. start_elm_deleted = TRUE;
  2126. if(just_one_level && is_stop_elm_ancestor)
  2127. break;
  2128. if(just_one_level)
  2129. {
  2130. if(!children.IsEmpty())
  2131. {
  2132. tmp_next = (HTML_Element*)children.stop->NextSibling();
  2133. if(!tmp_next)
  2134. {
  2135. OP_ASSERT(FALSE);
  2136. break;
  2137. }
  2138. }
  2139. }
  2140. else if(!children.IsEmpty())
  2141. tmp_next = children.start;
  2142. }
  2143. if(tmp == stop_elm)
  2144. break;
  2145. tmp = tmp_next;
  2146. }
  2147. shared_containing_elm->MarkExtraDirty(m_doc);
  2148. RestoreSelectionState(selection_state);
  2149. EndChange(shared_containing_elm);
  2150. }
  2151. OP_STATUS OpDocumentEdit::InsertBlockElementMultiple(HTML_Element *helm, BOOL exclude_lists, BOOL only_over_cursor, BOOL dont_insert_where_already_exists, HTML_ElementType *will_be_removed_types)
  2152. {
  2153. DEBUG_CHECKER(TRUE);
  2154. OP_STATUS status = OpStatus::OK;
  2155. SelectionState selection_state = GetSelectionState();
  2156. if(!selection_state.IsValid())
  2157. {
  2158. if(!only_over_cursor)
  2159. DeleteElement(helm);
  2160. return OpStatus::ERR;
  2161. }
  2162. HTML_Element *start_elm = NULL, *stop_elm = NULL;
  2163. if(only_over_cursor)
  2164. {
  2165. HTML_Element* real_elm = m_caret.m_real_caret_elm.GetElm();
  2166. if (m_caret.IsUnmodifiedTemporaryCaretTextElement() && real_elm)
  2167. {
  2168. m_caret.CleanTemporaryCaretTextElement(TRUE);
  2169. SelectionBoundaryPoint sel_point(real_elm, m_caret.m_real_caret_elm_off);
  2170. m_caret.Place(sel_point);
  2171. }
  2172. start_elm = m_caret.GetElement();
  2173. stop_elm = start_elm;
  2174. if(!start_elm)
  2175. return OpStatus::ERR;
  2176. }
  2177. else
  2178. {
  2179. start_elm = selection_state.editable_start_elm;
  2180. stop_elm = selection_state.editable_stop_elm;
  2181. }
  2182. HTML_Element *dummy_elm;
  2183. GetBlockStartStopInternal(&start_elm,&dummy_elm,start_elm);
  2184. GetBlockStartStopInternal(&dummy_elm,&stop_elm,stop_elm);
  2185. HTML_Element *shared_containing_elm = GetSharedContainingElement(start_elm,stop_elm);
  2186. BeginChange(shared_containing_elm);
  2187. // Run through the selection and insert several instances of helm where it is needed.
  2188. HTML_Element* tmp = start_elm;
  2189. while(tmp)
  2190. {
  2191. HTML_Element *tmp_next = tmp->NextActual();
  2192. if(only_over_cursor || ((tmp->Type() == HE_TEXT || tmp->Type() == HE_BR) && !(exclude_lists && GetParentListElm(tmp))))
  2193. {
  2194. HTML_Element *left_elm, *right_elm;
  2195. GetBlockStartStopInternal(&left_elm,&right_elm,tmp);
  2196. left_elm = (HTML_Element*)left_elm->FirstLeaf(); // should not be necessary...
  2197. right_elm = (HTML_Element*)right_elm->LastLeaf(); // should not be necessary...
  2198. HTML_Element *left_under_block = left_elm;
  2199. HTML_Element *right_under_block = right_elm;
  2200. while(!IsBlockElement(left_under_block->Parent()))
  2201. left_under_block = left_under_block->Parent();
  2202. while(!IsBlockElement(right_under_block->Parent()))
  2203. right_under_block = right_under_block->Parent();
  2204. if(left_under_block->Parent() != right_under_block->Parent())
  2205. {
  2206. OP_ASSERT(FALSE);
  2207. status = OpStatus::ERR;
  2208. break;
  2209. }
  2210. if(dont_insert_where_already_exists)
  2211. {
  2212. HTML_Element *current_block_parent = left_under_block->Parent();
  2213. BOOL dont_insert = FALSE;
  2214. while(current_block_parent)
  2215. {
  2216. BOOL cover_start_stop = current_block_parent->FirstLeaf() == left_elm && current_block_parent->LastLeaf() == right_elm;
  2217. if(current_block_parent->Type() == helm->Type())
  2218. {
  2219. dont_insert = cover_start_stop;
  2220. break;
  2221. }
  2222. if(!will_be_removed_types || !IsAnyOfTypes(current_block_parent, will_be_removed_types))
  2223. break;
  2224. if(!cover_start_stop)
  2225. break;
  2226. current_block_parent = current_block_parent->Parent();
  2227. }
  2228. if(dont_insert)
  2229. {
  2230. if(current_block_parent->IsAncestorOf(stop_elm))
  2231. break;
  2232. tmp = (HTML_Element*)current_block_parent->NextSibling();
  2233. continue;
  2234. }
  2235. }
  2236. // Due to the possible presence of BR element, we might need split the tree in order
  2237. // to insert blocks over BR terminated lines.
  2238. if(left_under_block->FirstLeaf() != left_elm)
  2239. {
  2240. HTML_Element *left_tree = ExtractTreeBeside(left_under_block,left_elm,TRUE);
  2241. if(!left_tree)
  2242. {
  2243. status = OpStatus::ERR_NO_MEMORY;
  2244. break;
  2245. }
  2246. left_tree->PrecedeSafe(m_doc,left_under_block);
  2247. }
  2248. if(right_under_block->LastLeaf() != right_elm)
  2249. {
  2250. HTML_Element *right_tree = ExtractTreeBeside(right_under_block,right_elm,FALSE);
  2251. if(!right_tree)
  2252. {
  2253. status = OpStatus::ERR_NO_MEMORY;
  2254. break;
  2255. }
  2256. right_tree->FollowSafe(m_doc,right_under_block);
  2257. }
  2258. SiblingBlock block_childs = SiblingBlock(left_under_block,right_under_block);
  2259. // Don't insert if all children are text-elements with just "\n\r" etc,
  2260. // then the possible tree-split above was unnecessary, but no harm done.
  2261. if(IsValidListBlock(block_childs))
  2262. {
  2263. HTML_Element* new_block = only_over_cursor ? helm : NewCopyOfElement(helm,TRUE);
  2264. if (!new_block)
  2265. {
  2266. status = OpStatus::ERR_NO_MEMORY;
  2267. break;
  2268. }
  2269. new_block->PrecedeSafe(m_doc, block_childs.start);
  2270. // Don't access block_childs.stop after MoveSiblingBlock because it may be already gone if it's not "actual".
  2271. tmp_next = block_childs.stop->NextSiblingActual();
  2272. MoveSiblingBlock(block_childs,new_block);
  2273. new_block->MarkExtraDirty(m_doc);
  2274. if(only_over_cursor || new_block->IsAncestorOf(stop_elm))
  2275. break;
  2276. }
  2277. }
  2278. if (tmp == stop_elm)
  2279. break;
  2280. tmp = tmp_next;
  2281. }
  2282. if(!only_over_cursor)
  2283. DeleteElement(helm);
  2284. DUMPDEBUGTREE
  2285. RestoreSelectionState(selection_state);
  2286. if(OpStatus::IsSuccess(status))
  2287. EndChange(shared_containing_elm);
  2288. else
  2289. AbortChange();
  2290. return status;
  2291. }
  2292. BOOL OpDocumentEdit::GetHasBlockTypes(HTML_ElementType *types, short attr)
  2293. {
  2294. DEBUG_CHECKER(TRUE);
  2295. SelectionState state = GetSelectionState(FALSE);
  2296. if (state.HasEditableContent())
  2297. {
  2298. // Check if some elements inside the selection has any of types.
  2299. HTML_Element* start_elm = state.editable_start_elm;
  2300. HTML_Element* stop_elm = state.editable_stop_elm;
  2301. HTML_Element* tmp = start_elm;
  2302. while(tmp != stop_elm)
  2303. {
  2304. if(IsAnyOfTypes(tmp,types,attr))
  2305. return TRUE;
  2306. tmp = (HTML_Element*) tmp->NextActual();
  2307. }
  2308. // Check if the start or stop is under a element of any of types
  2309. if (GetHasBlockTypesInternal(start_elm, types, attr) || GetHasBlockTypesInternal(stop_elm, types, attr))
  2310. return TRUE;
  2311. }
  2312. else
  2313. {
  2314. return GetHasBlockTypesInternal(m_caret.GetElement(), types, attr);
  2315. }
  2316. return FALSE;
  2317. }
  2318. BOOL OpDocumentEdit::GetHasBlockType(HTML_ElementType type, short attr)
  2319. {
  2320. DEBUG_CHECKER(TRUE);
  2321. HTML_ElementType types[] = {type,HE_UNKNOWN};
  2322. return GetHasBlockTypes(types,attr);
  2323. }
  2324. BOOL OpDocumentEdit::GetSelectionMatchesFunction(BOOL (*func)(HTML_Element*,void*), void *func_arg,
  2325. BOOL (*must_match)(HTML_Element*,void*), void *must_match_arg,
  2326. BOOL all_must_match, BOOL all_ancestors_must_match)
  2327. {
  2328. DEBUG_CHECKER(TRUE);
  2329. BOOL found = FALSE;
  2330. if(all_ancestors_must_match && (!all_must_match || must_match))
  2331. {
  2332. OP_ASSERT(FALSE);
  2333. all_must_match = TRUE;
  2334. must_match = NULL;
  2335. }
  2336. SelectionState state = GetSelectionState(FALSE);
  2337. if (state.HasEditableContent())
  2338. {
  2339. HTML_Element* start_elm = state.editable_start_elm;
  2340. HTML_Element* stop_elm = state.editable_stop_elm;
  2341. if(start_elm != stop_elm)
  2342. {
  2343. HTML_Element* tmp = start_elm->NextActual();
  2344. while(tmp != stop_elm)
  2345. {
  2346. if (func(tmp,func_arg))
  2347. {
  2348. if(!all_must_match)
  2349. return TRUE;
  2350. found = TRUE;
  2351. if(!all_ancestors_must_match)
  2352. {
  2353. if(tmp->IsAncestorOf(stop_elm))
  2354. break;
  2355. tmp = (HTML_Element*)tmp->NextSiblingActual();
  2356. continue;
  2357. }
  2358. }
  2359. else if(all_must_match && (!must_match || must_match(tmp,must_match_arg)))
  2360. {
  2361. if(all_ancestors_must_match)
  2362. return FALSE;
  2363. HTML_Element *match_elm = GetMatchingParent(TRUE,tmp,func,func_arg);
  2364. if(!match_elm)
  2365. return FALSE;
  2366. if(match_elm->IsAncestorOf(stop_elm))
  2367. break;
  2368. tmp = (HTML_Element*)match_elm->NextSiblingActual();
  2369. continue;
  2370. }
  2371. tmp = (HTML_Element*) tmp->NextActual();
  2372. }
  2373. }
  2374. // Check start_elm + stop_elm
  2375. BOOL start_matches = func(start_elm,func_arg);
  2376. BOOL stop_matches = func(stop_elm,func_arg);
  2377. if(all_ancestors_must_match) // all_must_match == TRUE
  2378. return start_matches && stop_matches && !GetMatchingParent(FALSE,start_elm,func,func_arg) && !GetMatchingParent(FALSE,stop_elm,func,func_arg);
  2379. start_matches = start_matches || GetMatchingParent(TRUE,start_elm,func,func_arg);
  2380. stop_matches = stop_matches || GetMatchingParent(TRUE,stop_elm,func,func_arg);
  2381. if(all_must_match)
  2382. {
  2383. if(start_matches && stop_matches)
  2384. return TRUE;
  2385. if(start_matches || stop_matches || found)
  2386. {
  2387. if(!start_matches && must_match && !must_match(start_elm,must_match_arg))
  2388. start_matches = !GetMatchingParent(TRUE,start_elm,must_match,must_match_arg);
  2389. if(!stop_matches && must_match && !must_match(stop_elm,must_match_arg))
  2390. stop_matches = !GetMatchingParent(TRUE,stop_elm,must_match,must_match_arg);
  2391. return start_matches && stop_matches;
  2392. }
  2393. return FALSE;
  2394. }
  2395. return start_matches || stop_matches; // found == FALSE
  2396. }
  2397. else
  2398. {
  2399. HTML_Element *helm = m_layout_modifier.IsActive() ? m_layout_modifier.m_helm : m_caret.GetElement();
  2400. if(helm)
  2401. {
  2402. BOOL matches = func(helm,func_arg);
  2403. if(all_ancestors_must_match)
  2404. return matches && !GetMatchingParent(FALSE,helm,func,func_arg);
  2405. return matches || GetMatchingParent(TRUE,helm,func,func_arg);
  2406. }
  2407. }
  2408. return FALSE;
  2409. }
  2410. OP_STATUS OpDocumentEdit::ApplyFunctionBetween(HTML_Element *start_elm, HTML_Element *stop_elm, OP_STATUS (*func)(HTML_Element*,void*,BOOL&), void *func_arg, int *call_count, int *true_count, BOOL only_actual)
  2411. {
  2412. DEBUG_CHECKER(TRUE);
  2413. if(call_count)
  2414. *call_count = 0;
  2415. if(true_count)
  2416. *true_count = 0;
  2417. if((!start_elm && !stop_elm) || !func)
  2418. {
  2419. OP_ASSERT(FALSE);
  2420. return OpStatus::OK;
  2421. }
  2422. HTML_Element *container = NULL;
  2423. if(!start_elm || !stop_elm)
  2424. {
  2425. if((container = GetEditableContainer(start_elm ? start_elm : stop_elm)) == NULL)
  2426. {
  2427. // This might happen when there's no <body> and e.g. <html> is contentEditable.
  2428. OP_ASSERT(!"Editing when there's no <body>?");
  2429. return OpStatus::OK;
  2430. }
  2431. if(start_elm)
  2432. stop_elm = container->LastLeaf() ? container->LastLeaf() : container;
  2433. else
  2434. start_elm = container;
  2435. }
  2436. if(!container)
  2437. {
  2438. if((container = GetEditableContainer(start_elm)) == NULL)
  2439. {
  2440. // This might happen when there's no <body> and e.g. <html> is contentEditable.
  2441. OP_ASSERT(!"Editing when there's no <body>?");
  2442. return OpStatus::OK;
  2443. }
  2444. if(!container->IsAncestorOf(stop_elm))
  2445. {
  2446. OP_ASSERT(FALSE);
  2447. stop_elm = container->LastLeaf() ? container->LastLeaf() : container;
  2448. }
  2449. }
  2450. HTML_Element *helm = start_elm;
  2451. BOOL going_up = FALSE;
  2452. for(;;)
  2453. {
  2454. if(!helm)
  2455. {
  2456. OP_ASSERT(FALSE);
  2457. return OpStatus::OK;
  2458. }
  2459. if(!only_actual || helm->IsIncludedActual())
  2460. {
  2461. BOOL ret = FALSE;
  2462. if(call_count)
  2463. (*call_count)++;
  2464. RETURN_IF_ERROR(func(helm,func_arg,ret));
  2465. if(ret && true_count)
  2466. (*true_count)++;
  2467. }
  2468. if(helm == stop_elm)
  2469. {
  2470. if(going_up)
  2471. break;
  2472. going_up = TRUE;
  2473. helm = start_elm;
  2474. if(start_elm == container)
  2475. break;
  2476. stop_elm = container;
  2477. }
  2478. helm = going_up ? helm->Parent() : helm->Next();
  2479. }
  2480. return OpStatus::OK;
  2481. }
  2482. SiblingBlock OpDocumentEdit::GetBlockSiblings(HTML_Element *helm, BOOL stop_at_br, HTML_Element *stop_pred, HTML_Element *stop_suc)
  2483. {
  2484. DEBUG_CHECKER(TRUE);
  2485. if(!helm || IsBlockElement(helm) || helm == stop_pred || helm == stop_suc)
  2486. return SiblingBlock(helm,helm);
  2487. SiblingBlock block;
  2488. HTML_Element *tmp;
  2489. tmp = helm;
  2490. while(tmp->Pred() && !IsBlockElement(tmp->Pred())
  2491. && !(stop_at_br && tmp->Pred()->Type() == HE_BR) && tmp->Pred() != stop_pred)
  2492. {
  2493. tmp = tmp->Pred();
  2494. }
  2495. block.start = tmp;
  2496. tmp = helm;
  2497. while(tmp->Suc() && !IsBlockElement(tmp->Suc())
  2498. && !(stop_at_br && tmp->Type() == HE_BR) && tmp->Suc() != stop_suc)
  2499. {
  2500. tmp = tmp->Suc();
  2501. }
  2502. block.stop = tmp;
  2503. return block;
  2504. }
  2505. void OpDocumentEdit::AdjustStartStopToBlocks(HTML_Element *&start_elm, HTML_Element *&stop_elm)
  2506. {
  2507. DEBUG_CHECKER(TRUE);
  2508. HTML_Element *tmp;
  2509. OP_ASSERT(start_elm && stop_elm && (start_elm == stop_elm || start_elm->Precedes(stop_elm)));
  2510. if(start_elm && !IsBlockElement(start_elm))
  2511. {
  2512. tmp = m_doc->GetCaret()->GetContainingElementActual(start_elm);
  2513. OP_ASSERT(GetBody() && GetBody()->IsAncestorOf(tmp));
  2514. if(tmp != GetBody())
  2515. start_elm = tmp;
  2516. else
  2517. {
  2518. while(start_elm->ParentActual() != tmp)
  2519. start_elm = start_elm->ParentActual();
  2520. while(start_elm->PredActual() && !IsBlockElement(start_elm->PredActual()))
  2521. start_elm = start_elm->PredActual();
  2522. }
  2523. }
  2524. if(stop_elm && !IsBlockElement(stop_elm))
  2525. {
  2526. tmp = m_doc->GetCaret()->GetContainingElementActual(stop_elm);
  2527. OP_ASSERT(GetBody() && GetBody()->IsAncestorOf(tmp));
  2528. if(tmp != GetBody())
  2529. stop_elm = tmp;
  2530. else
  2531. {
  2532. while(stop_elm->ParentActual() != tmp)
  2533. stop_elm = stop_elm->ParentActual();
  2534. while(stop_elm->SucActual() && !IsBlockElement(stop_elm->SucActual()))
  2535. stop_elm = stop_elm->SucActual();
  2536. }
  2537. }
  2538. }
  2539. void OpDocumentEdit::AdjustStartStopToActual(HTML_Element *&start_elm, HTML_Element *&stop_elm)
  2540. {
  2541. DEBUG_CHECKER(TRUE);
  2542. BOOL non_actual = FALSE;
  2543. if(!start_elm->IsIncludedActual())
  2544. {
  2545. non_actual = TRUE;
  2546. if(start_elm == stop_elm)
  2547. {
  2548. start_elm = start_elm->FirstLeafActual();
  2549. stop_elm = stop_elm->LastLeafActual();
  2550. return;
  2551. }
  2552. start_elm = start_elm->NextActual();
  2553. if(start_elm && start_elm->FirstLeafActual())
  2554. start_elm = start_elm->FirstLeafActual();
  2555. }
  2556. if(!stop_elm->IsIncludedActual())
  2557. {
  2558. non_actual = TRUE;
  2559. stop_elm = stop_elm->PrevSiblingActual();
  2560. if(stop_elm && stop_elm->LastLeafActual())
  2561. stop_elm = stop_elm->LastLeafActual();
  2562. }
  2563. if(non_actual)
  2564. {
  2565. if(!start_elm || !stop_elm || (start_elm != stop_elm && !start_elm->Precedes(stop_elm)))
  2566. {
  2567. start_elm = stop_elm = NULL;
  2568. return;
  2569. }
  2570. }
  2571. }
  2572. void OpDocumentEdit::AdjustStartStopNotBreakTypes(HTML_Element *&start_elm, HTML_Element *&stop_elm, HTML_ElementType *types)
  2573. {
  2574. DEBUG_CHECKER(TRUE);
  2575. if(!start_elm || !stop_elm)
  2576. {
  2577. OP_ASSERT(FALSE);
  2578. return;
  2579. }
  2580. OP_ASSERT(start_elm == stop_elm || start_elm->Precedes(stop_elm));
  2581. AdjustStartStopToActual(start_elm,stop_elm);
  2582. if(!start_elm)
  2583. return;
  2584. HTML_Element *start_break = GetRootOfTypes(start_elm,types);
  2585. HTML_Element *stop_break = GetRootOfTypes(stop_elm,types);
  2586. if(!start_break && !stop_break)
  2587. return;
  2588. BOOL select_nothing = FALSE;
  2589. if(start_break == stop_break)
  2590. select_nothing = TRUE;
  2591. else if(start_break && stop_break)
  2592. {
  2593. HTML_Element *next_sibling = start_break->NextSiblingActual();
  2594. if(!next_sibling || next_sibling == stop_break || next_sibling->IsAncestorOf(stop_break))
  2595. select_nothing = TRUE;
  2596. }
  2597. if(select_nothing)
  2598. {
  2599. start_elm = stop_elm = NULL;
  2600. return;
  2601. }
  2602. if(start_break && !start_break->IsAncestorOf(start_elm->PrevSiblingActual()))
  2603. start_break = NULL;
  2604. if(stop_break && !stop_break->IsAncestorOf(stop_elm->NextSiblingActual()))
  2605. stop_break = NULL;
  2606. if(!start_break && !stop_break)
  2607. return;
  2608. if(start_break)
  2609. {
  2610. start_elm = start_break->NextSiblingActual();
  2611. if(start_elm && start_elm->FirstLeafActual())
  2612. start_elm = start_elm->FirstLeafActual();
  2613. }
  2614. if(stop_break)
  2615. {
  2616. stop_elm = stop_break->PrevSiblingActual();
  2617. if(stop_elm && stop_elm->LastLeafActual())
  2618. stop_elm = stop_elm->LastLeafActual();
  2619. }
  2620. }
  2621. HTML_Element *OpDocumentEdit::AdjustStartStopCloserRoot(HTML_Element *&start_elm, HTML_Element *&stop_elm)
  2622. {
  2623. DEBUG_CHECKER(TRUE);
  2624. HTML_Element *before_start = start_elm->PrevSiblingActual();
  2625. HTML_Element *after_stop = stop_elm->NextSiblingActual();
  2626. HTML_Element *shared_containing_elm = GetSharedContainingElement(start_elm,stop_elm);
  2627. // Let's set shared_containing_elm+start_elm+stop_elm as close to the root as possible
  2628. // If all cells in a table are selected (and nothing around) we want to change the
  2629. // cell-content and not the table itself
  2630. HTML_Element *body = GetBody();
  2631. while(shared_containing_elm != body &&
  2632. !shared_containing_elm->IsAncestorOf(before_start) &&
  2633. !shared_containing_elm->IsAncestorOf(after_stop) &&
  2634. shared_containing_elm->ParentActual() &&
  2635. shared_containing_elm->ParentActual()->Type() != HE_TABLE
  2636. )
  2637. {
  2638. shared_containing_elm = shared_containing_elm->ParentActual();
  2639. }
  2640. while(start_elm->ParentActual() != shared_containing_elm &&
  2641. !start_elm->ParentActual()->IsAncestorOf(before_start))
  2642. {
  2643. start_elm = start_elm->ParentActual();
  2644. }
  2645. while(stop_elm->ParentActual() != shared_containing_elm &&
  2646. !stop_elm->ParentActual()->IsAncestorOf(after_stop))
  2647. {
  2648. stop_elm = stop_elm->ParentActual();
  2649. }
  2650. return shared_containing_elm;
  2651. }
  2652. void OpDocumentEdit::JustifySelection(CSSValue align)
  2653. {
  2654. DEBUG_CHECKER(TRUE);
  2655. SelectionState selection_state = GetSelectionState();
  2656. if(!selection_state.IsValid())
  2657. return;
  2658. OP_STATUS status = OpStatus::OK;
  2659. HTML_Element *start_elm = selection_state.editable_start_elm;
  2660. HTML_Element *stop_elm = selection_state.editable_stop_elm;
  2661. AdjustStartStopToBlocks(start_elm,stop_elm);
  2662. HTML_Element *shared_containing_elm = AdjustStartStopCloserRoot(start_elm,stop_elm);
  2663. BeginChange(shared_containing_elm);
  2664. // is_removing_attr will be != NULL while removing ATTR_ALIGN from children where we've
  2665. // set alignment on an ancestor where ChildrenShouldInheritAlignment(ancestor) == TRUE.
  2666. BOOL is_removing_attr = FALSE;
  2667. HTML_Element *next_to_set = NULL; // When we should stop removing
  2668. HTML_Element *tmp = start_elm;
  2669. HTML_Element *after_justify = stop_elm->NextSiblingActual();
  2670. if(!GetBody()->IsAncestorOf(after_justify))
  2671. after_justify = NULL; // after_justify was probably HEAD or something...
  2672. while(tmp != after_justify && tmp)
  2673. {
  2674. if(is_removing_attr && tmp == next_to_set)
  2675. is_removing_attr = FALSE;
  2676. if(is_removing_attr)
  2677. {
  2678. if(tmp->HasAttr(ATTR_ALIGN))
  2679. {
  2680. OnElementChange(tmp);
  2681. tmp->RemoveAttribute(ATTR_ALIGN);
  2682. OnElementChanged(tmp);
  2683. }
  2684. if(!ChildrenShouldInheritAlignment(tmp))
  2685. {
  2686. tmp = tmp->NextSiblingActual();
  2687. continue;
  2688. }
  2689. }
  2690. else
  2691. {
  2692. // Place DIV outside inline elements, we won't hit after_justify as it has been set above to
  2693. // not be an inline element Suc() another inline element.
  2694. if(!IsBlockElement(tmp))
  2695. {
  2696. if(!(tmp->Type() == HE_TEXT && tmp->GetTextContentLength() && IsWhiteSpaceOnly(tmp->TextContent())))
  2697. {
  2698. // Add also "non-actual" elements under DIV
  2699. SiblingBlock under_div = GetBlockSiblings(tmp);
  2700. HTML_Element* helm = NewElement(HE_DIV);
  2701. if(!helm || OpStatus::IsError(status = SetAlignAttrFromCSSValue(helm,align)))
  2702. break;
  2703. helm->PrecedeSafe(m_doc,under_div.start);
  2704. // If under_div.stop is not actual it may disappear in MoveSiblingBlock.
  2705. tmp = under_div.stop->NextSiblingActual();
  2706. MoveSiblingBlock(under_div,helm);
  2707. continue;
  2708. }
  2709. }
  2710. else if(!tmp->IsAncestorOf(after_justify) && ElementHandlesAlignAttribute(tmp))
  2711. {
  2712. SetAlignAttrFromCSSValue(tmp,align);
  2713. tmp->MarkDirty(m_doc);
  2714. if(ChildrenShouldInheritAlignment(tmp)) // Let's remove alignment from the children
  2715. {
  2716. next_to_set = tmp->NextSiblingActual();
  2717. is_removing_attr = TRUE;
  2718. }
  2719. else
  2720. {
  2721. tmp = tmp->NextSiblingActual();
  2722. continue;
  2723. }
  2724. }
  2725. }
  2726. tmp = tmp->NextActual();
  2727. }
  2728. RestoreSelectionState(selection_state);
  2729. if(OpStatus::IsError(status))
  2730. AbortChange();
  2731. else
  2732. EndChange(shared_containing_elm,TIDY_LEVEL_MINIMAL);
  2733. }
  2734. OP_STATUS OpDocumentEdit::IndentSelection(int px)
  2735. {
  2736. DEBUG_CHECKER(TRUE);
  2737. OP_STATUS status = OpStatus::OK;
  2738. SelectionState selection_state = GetSelectionState(TRUE, FALSE, TRUE, TRUE);
  2739. if(!selection_state.IsValid())
  2740. return status;
  2741. BOOL indent = px > 0;
  2742. HTML_Element *start_elm = selection_state.editable_start_elm;
  2743. HTML_Element *stop_elm = selection_state.editable_stop_elm;
  2744. HTML_ElementType li_types[] = {HE_OL, HE_UL, HE_UNKNOWN};
  2745. AdjustStartStopNotBreakTypes(start_elm,stop_elm,li_types);
  2746. if(!start_elm || !stop_elm)
  2747. {
  2748. RestoreSelectionState(selection_state);
  2749. return status;
  2750. }
  2751. AdjustStartStopToBlocks(start_elm,stop_elm);
  2752. HTML_Element *shared_containing_elm = AdjustStartStopCloserRoot(start_elm,stop_elm);
  2753. BeginChange(shared_containing_elm);
  2754. // is_removing_attr will be != NULL while removing ATTR_ALIGN from children where we've
  2755. // set alignment on an ancestor where ChildrenShouldInheritAlignment(ancestor) == TRUE.
  2756. HTML_Element *tmp = start_elm;
  2757. HTML_Element *after_indent = stop_elm->NextSiblingActual();
  2758. if(!GetBody()->IsAncestorOf(after_indent))
  2759. after_indent = NULL; // after_indent was probably HEAD or something...
  2760. while(tmp && tmp != after_indent && OpStatus::IsSuccess(status))
  2761. {
  2762. // Place DIV outside inline elements, we won't hit after_indent as it has been set in AdjustStartStopToBlocks
  2763. // not be an inline element Suc() another inline element.
  2764. if(!IsBlockElement(tmp))
  2765. {
  2766. if(indent && !(tmp->Type() == HE_TEXT && tmp->GetTextContentLength() && IsWhiteSpaceOnly(tmp->TextContent())))
  2767. {
  2768. // Add also "non-actual" elements under DIV
  2769. SiblingBlock under_div = GetBlockSiblings(tmp);
  2770. HTML_Element* helm = NewElement(HE_DIV);
  2771. if(!helm)
  2772. {
  2773. status = OpStatus::ERR_NO_MEMORY;
  2774. break;
  2775. }
  2776. helm->PrecedeSafe(m_doc,under_div.start);
  2777. // If under_div.stop is not actual it may disappear in MoveSiblingBlock.
  2778. tmp = under_div.stop->NextSiblingActual();
  2779. MoveSiblingBlock(under_div,helm);
  2780. status = SetCSSIndent(helm,px);
  2781. continue;
  2782. }
  2783. }
  2784. else if(!tmp->IsAncestorOf(after_indent) && ElementHandlesMarginStyle(tmp))
  2785. {
  2786. if(IsAnyOfTypes(tmp,li_types))
  2787. {
  2788. tmp = tmp->NextSiblingActual();
  2789. continue;
  2790. }
  2791. int before_indent;
  2792. if(OpStatus::IsError(status = GetCSSIndent(tmp,before_indent)))
  2793. break;
  2794. if(indent || before_indent)
  2795. {
  2796. if(OpStatus::IsError(status = SetCSSIndent(tmp,MAX(before_indent+px,0))))
  2797. break;
  2798. tmp->MarkDirty(m_doc);
  2799. tmp = tmp->NextSiblingActual();
  2800. continue;
  2801. }
  2802. }
  2803. tmp = tmp->NextActual();
  2804. }
  2805. RestoreSelectionState(selection_state);
  2806. if(OpStatus::IsError(status))
  2807. {
  2808. if(OpStatus::IsMemoryError(status))
  2809. ReportOOM();
  2810. AbortChange();
  2811. }
  2812. else
  2813. EndChange(shared_containing_elm,TIDY_LEVEL_MINIMAL);
  2814. return status;
  2815. }
  2816. OP_STATUS OpDocumentEdit::GetCSSIndent(HTML_Element *helm, int &result_px)
  2817. {
  2818. DEBUG_CHECKER(TRUE);
  2819. //result_px = 0;
  2820. //CSS_property_list *props = helm->GetCSS_Style();
  2821. //if(!props)
  2822. // return OpStatus::OK;
  2823. //
  2824. //CSS_decl *p = props->GetFirstDecl();
  2825. //for(p = props->GetFirstDecl(); p && p->GetProperty() != CSS_PROPERTY_margin_left; p = p->Suc());
  2826. //if(p)
  2827. // result_px = p->GetNumberValue(0);
  2828. //return OpStatus::OK;
  2829. result_px = 0;
  2830. Head prop_list;
  2831. HLDocProfile *hld_profile = m_doc->GetHLDocProfile();
  2832. LayoutProperties* lprops = LayoutProperties::CreateCascade(helm, prop_list, hld_profile);
  2833. if(lprops)
  2834. {
  2835. result_px = MAX(lprops->GetProps()->margin_left,0);
  2836. }
  2837. prop_list.Clear();
  2838. return OpStatus::OK;
  2839. }
  2840. static OP_STATUS AddDecl(CSS_property_list *props, int px)
  2841. {
  2842. TRAPD(status, props->AddDeclL(CSS_PROPERTY_margin_left, (float)px, CSS_PX, TRUE, CSS_decl::ORIGIN_USER));
  2843. return status;
  2844. }
  2845. OP_STATUS OpDocumentEdit::SetCSSIndent(HTML_Element *helm, int px)
  2846. {
  2847. DEBUG_CHECKER(TRUE);
  2848. OP_STATUS status = OpStatus::OK;
  2849. OnElementChange(helm);
  2850. CSS_property_list *props = helm->GetCSS_Style();
  2851. if(!props)
  2852. {
  2853. props = OP_NEW(CSS_property_list, ());
  2854. if (!props)
  2855. return OpStatus::ERR_NO_MEMORY;
  2856. props->Ref();
  2857. if(OpStatus::IsError(status = helm->SetCSS_Style(props)))
  2858. {
  2859. props->Unref();
  2860. return status;
  2861. }
  2862. }
  2863. CSS_decl *p;
  2864. if((p = props->RemoveDecl(CSS_PROPERTY_margin_left)) != NULL)
  2865. p->Unref();
  2866. status = AddDecl(props, px);
  2867. if(OpStatus::IsSuccess(status))
  2868. status = m_doc->GetHLDocProfile()->GetLayoutWorkplace()->ApplyPropertyChanges(helm, 0, FALSE);
  2869. OnElementChanged(helm);
  2870. return status;
  2871. }
  2872. OP_STATUS OpDocumentEdit::RemoveInlinePropertyBetween(HTML_Element *start_elm, HTML_Element *stop_elm, int prop, BOOL only_block_elements)
  2873. {
  2874. DEBUG_CHECKER(TRUE);
  2875. OP_STATUS status = OpStatus::OK;
  2876. HTML_Element *shared_containing_elm = NULL;
  2877. if(!start_elm || !stop_elm)
  2878. return status;
  2879. HTML_Element *tmp = start_elm;
  2880. while(tmp)
  2881. {
  2882. CSS_property_list *props;
  2883. if((!only_block_elements || IsBlockElement(tmp)) &&
  2884. tmp->IsIncludedActual() &&
  2885. (props = tmp->GetCSS_Style()))
  2886. {
  2887. CSS_decl *p;
  2888. for(p = props->GetFirstDecl(); p && p->GetProperty() != prop; p = p->Suc()) {}
  2889. if(p)
  2890. {
  2891. if(!shared_containing_elm)
  2892. {
  2893. shared_containing_elm = GetSharedContainingElement(start_elm,stop_elm);
  2894. BeginChange(shared_containing_elm);
  2895. }
  2896. OnElementChange(tmp);
  2897. if((p = props->RemoveDecl(prop)) != NULL)
  2898. p->Unref();
  2899. status = m_doc->GetHLDocProfile()->GetLayoutWorkplace()->ApplyPropertyChanges(tmp, 0, FALSE);
  2900. OnElementChanged(tmp);
  2901. }
  2902. }
  2903. if(tmp == stop_elm)
  2904. break;
  2905. tmp = tmp->Next();
  2906. }
  2907. if(shared_containing_elm)
  2908. EndChange(shared_containing_elm);
  2909. return status;
  2910. }
  2911. OP_STATUS OpDocumentEdit::SetAlignAttrFromCSSValue(HTML_Element *helm, CSSValue value)
  2912. {
  2913. DEBUG_CHECKER(TRUE);
  2914. OP_ASSERT(helm && !helm->IsText());
  2915. const uni_char *align =
  2916. value == CSS_VALUE_center ? UNI_L("center") :
  2917. value == CSS_VALUE_left ? UNI_L("left") :
  2918. value == CSS_VALUE_right ? UNI_L("right") : UNI_L("justify");
  2919. OnElementChange(helm);
  2920. OP_STATUS status = helm->SetAttribute(m_doc->GetLogicalDocument(), ATTR_XML, UNI_L("align"), NS_IDX_DEFAULT, align, uni_strlen(align), NULL, TRUE);
  2921. OnElementChanged(helm);
  2922. return status;
  2923. }
  2924. void OpDocumentEdit::CleanAroundBlock(SiblingBlock block)
  2925. {
  2926. DEBUG_CHECKER(TRUE);
  2927. if(block.IsEmpty())
  2928. return;
  2929. SiblingBlock remaining;
  2930. HTML_Element *parent = block.start->Parent();
  2931. if(parent->Type() == HE_OL || parent->Type() == HE_UL || parent->Type() == HE_LI)
  2932. {
  2933. if(block.start->Pred())
  2934. {
  2935. remaining = SiblingBlock(parent->FirstChild(),block.start->Pred());
  2936. CleanUnnecessaryElementsInBlock(&remaining);
  2937. }
  2938. if(block.stop->Suc())
  2939. {
  2940. remaining = SiblingBlock(block.stop->Suc(),parent->LastChild());
  2941. CleanUnnecessaryElementsInBlock(&remaining);
  2942. }
  2943. }
  2944. }
  2945. OP_STATUS OpDocumentEdit::SplitListAroundAndMoveBlock(SiblingBlock block, HTML_Element *new_parent,
  2946. HTML_Element *after_me, HTML_Element *&split_parent, HTML_Element *&split_pred)
  2947. {
  2948. DEBUG_CHECKER(TRUE);
  2949. OP_ASSERT(!block.IsEmpty() && block.start->Parent() == block.stop->Parent());
  2950. HTML_Element *first_pred,*first_suc,*second_pred,*second_suc;
  2951. HTML_Element *parent = block.start->ParentActual();
  2952. HTML_Element *parent_parent = parent->ParentActual();
  2953. HTML_Element *new_li = NULL;
  2954. // Create new LI element right away to simplify things a bit,
  2955. // this element might be unnecessary and will in that case be removed below
  2956. if(parent_parent->Type() == HE_LI)
  2957. {
  2958. new_li = NEW_HTML_Element();
  2959. if(new_li == NULL)
  2960. return OpStatus::ERR_NO_MEMORY;
  2961. if(OpStatus::IsError(new_li->Construct(m_doc->GetHLDocProfile(),parent_parent,TRUE/*???*/)))
  2962. {
  2963. DeleteElement(new_li);
  2964. return OpStatus::ERR_NO_MEMORY;
  2965. }
  2966. new_li->SetInserted(HE_INSERTED_BY_DOM);
  2967. new_li->SetEndTagFound(TRUE);
  2968. new_li->RemoveAttribute(ATTR_ID);
  2969. }
  2970. CleanAroundBlock(block);
  2971. first_pred = block.start->Pred();
  2972. first_suc = block.stop->Suc();
  2973. MoveSiblingBlock(block,new_parent,after_me);
  2974. if(!first_pred && !first_suc) //remove list
  2975. {
  2976. second_pred = parent->Pred();
  2977. if (second_pred && second_pred->GetIsListMarkerPseudoElement())
  2978. second_pred = NULL;
  2979. second_suc = parent->Suc();
  2980. DeleteElement(parent);
  2981. }
  2982. else if(first_pred && first_suc) //split list
  2983. {
  2984. HTML_Element *new_list = NEW_HTML_Element();
  2985. second_pred = parent;
  2986. second_suc = new_list;
  2987. if(new_list == NULL)
  2988. {
  2989. DeleteElement(new_li);
  2990. return OpStatus::ERR_NO_MEMORY;
  2991. }
  2992. if(OpStatus::IsError(new_list->Construct(m_doc->GetHLDocProfile(),parent,TRUE/*???*/)))
  2993. {
  2994. DeleteElement(new_li);
  2995. DeleteElement(new_list);
  2996. return OpStatus::ERR_NO_MEMORY;
  2997. }
  2998. new_list->SetInserted(HE_INSERTED_BY_DOM);
  2999. new_list->SetEndTagFound(TRUE);
  3000. new_list->RemoveAttribute(ATTR_ID);
  3001. SiblingBlock cont_block = SiblingBlock(first_suc,parent->LastChild());
  3002. new_list->FollowSafe(m_doc,parent);
  3003. MoveSiblingBlock(cont_block,new_list);
  3004. }
  3005. else if(first_suc) //keep lower range of list
  3006. {
  3007. second_pred = parent->Pred();
  3008. if (second_pred && second_pred->GetIsListMarkerPseudoElement())
  3009. second_pred = NULL;
  3010. second_suc = parent;
  3011. }
  3012. else // keep higher range of list
  3013. {
  3014. second_pred = parent;
  3015. second_suc = parent->Suc();
  3016. }
  3017. if(parent_parent->Type() != HE_LI)
  3018. {
  3019. split_parent = parent_parent;
  3020. split_pred = second_pred;
  3021. return OpStatus::OK;
  3022. }
  3023. // If the list (probably) we moved block from was inside a LI element, this element
  3024. // should be splitted as well.
  3025. parent = parent_parent;
  3026. parent_parent = parent->Parent();
  3027. SiblingBlock remaining_over;
  3028. if (second_pred)
  3029. {
  3030. HTML_Element* start = parent->FirstChild();
  3031. if (start && start->GetIsListMarkerPseudoElement())
  3032. start = start->Suc();
  3033. remaining_over = SiblingBlock(start, second_pred);
  3034. }
  3035. SiblingBlock remaining_under;
  3036. if (second_suc)
  3037. {
  3038. HTML_Element* end = parent->LastChild();
  3039. if (end && end->GetIsListMarkerPseudoElement())
  3040. end = NULL;
  3041. remaining_under = SiblingBlock(second_suc, end);
  3042. }
  3043. CleanUnnecessaryElementsInBlock(&remaining_over);
  3044. CleanUnnecessaryElementsInBlock(&remaining_under);
  3045. split_parent = parent_parent;
  3046. if(remaining_over.IsEmpty() && remaining_under.IsEmpty())
  3047. {
  3048. split_pred = parent->Pred();
  3049. DeleteElement(parent);
  3050. DeleteElement(new_li);
  3051. }
  3052. else if(!remaining_over.IsEmpty() && !remaining_under.IsEmpty())
  3053. {
  3054. split_pred = parent;
  3055. new_li->FollowSafe(m_doc,parent);
  3056. MoveSiblingBlock(remaining_under,new_li);
  3057. }
  3058. else if(remaining_over.IsEmpty())
  3059. {
  3060. split_pred = parent->Pred();
  3061. DeleteElement(new_li);
  3062. }
  3063. else
  3064. {
  3065. split_pred = parent;
  3066. DeleteElement(new_li);
  3067. }
  3068. return OpStatus::OK;
  3069. }
  3070. SiblingBlock OpDocumentEdit::GetSucListBlock(HTML_Element *root, SiblingBlock block)
  3071. {
  3072. DEBUG_CHECKER(TRUE);
  3073. OP_ASSERT(block.start->Parent() == block.stop->Parent());
  3074. BOOL return_always = block.start->Parent() == root
  3075. || block.start->Parent()->Type() == HE_OL
  3076. || block.start->Parent()->Type() == HE_UL;
  3077. HTML_Element *helm = block.stop->Suc();
  3078. while(helm)
  3079. {
  3080. HTML_Element *next_elm = helm->FirstChild();
  3081. if(next_elm)
  3082. {
  3083. BOOL go_down = TRUE;
  3084. while(next_elm != helm)
  3085. {
  3086. if(go_down)
  3087. {
  3088. if(next_elm->FirstChild())
  3089. next_elm = next_elm->FirstChild();
  3090. else
  3091. go_down = FALSE;
  3092. }
  3093. else
  3094. {
  3095. if(next_elm->Parent()->Type() == HE_OL || next_elm->Parent()->Type() == HE_UL)
  3096. {
  3097. block = GetBlockSiblings(next_elm);
  3098. OP_ASSERT(block.start == next_elm);
  3099. if(IsValidListBlock(block))
  3100. return block;
  3101. }
  3102. if(next_elm->Suc())
  3103. {
  3104. next_elm = next_elm->Suc();
  3105. go_down = TRUE;
  3106. }
  3107. else
  3108. next_elm = next_elm->Parent();
  3109. }
  3110. }
  3111. }
  3112. if(return_always)
  3113. {
  3114. block = GetBlockSiblings(helm);
  3115. OP_ASSERT(block.start == helm);
  3116. if(IsValidListBlock(block))
  3117. return block;
  3118. }
  3119. block = GetBlockSiblings(helm);
  3120. helm = block.stop->Suc();
  3121. }
  3122. return SiblingBlock();
  3123. }
  3124. SiblingBlock OpDocumentEdit::GetNextListBlock(HTML_Element *root, SiblingBlock block)
  3125. {
  3126. DEBUG_CHECKER(TRUE);
  3127. SiblingBlock next_block;
  3128. HTML_Element *helm = block.start;
  3129. SiblingBlock suc_list_block;
  3130. while(helm != GetBody() && (suc_list_block = GetSucListBlock(root,block)).IsEmpty())
  3131. {
  3132. helm = helm->Parent();
  3133. if(!helm || helm == root)
  3134. return SiblingBlock();
  3135. block = GetBlockSiblings(helm);
  3136. }
  3137. if(helm == GetBody())
  3138. return SiblingBlock();
  3139. OP_ASSERT(block.start->Parent() == block.stop->Parent());
  3140. return suc_list_block;
  3141. }
  3142. void OpDocumentEdit::MoveSiblingBlock(SiblingBlock block, HTML_Element *new_parent, HTML_Element *after_me)
  3143. {
  3144. DEBUG_CHECKER(TRUE);
  3145. if(block.IsEmpty())
  3146. return;
  3147. OP_ASSERT(new_parent);
  3148. OP_ASSERT(!after_me || after_me->Parent() == new_parent);
  3149. HTML_Element *next,*tmp = block.start;
  3150. HTML_Element *caret_helm = m_caret.GetElement();
  3151. int caret_ofs = m_caret.GetOffset();
  3152. if(!after_me)
  3153. {
  3154. next = tmp->SucActual();
  3155. tmp->OutSafe(m_doc, FALSE);
  3156. if(new_parent->FirstChildActual())
  3157. tmp->PrecedeSafe(m_doc,new_parent->FirstChildActual());
  3158. else
  3159. tmp->UnderSafe(m_doc,new_parent);
  3160. after_me = tmp;
  3161. if(tmp == block.stop)
  3162. tmp = NULL;
  3163. else
  3164. tmp = next;
  3165. }
  3166. while(tmp)
  3167. {
  3168. next = tmp->SucActual();
  3169. tmp->OutSafe(m_doc, FALSE);
  3170. tmp->FollowSafe(m_doc,after_me);
  3171. if(tmp == block.stop)
  3172. break;
  3173. after_me = tmp;
  3174. tmp = next;
  3175. }
  3176. // If the caret moved during the operation, move it back.
  3177. if(caret_helm && (caret_helm != m_caret.GetElement() || caret_ofs != m_caret.GetOffset()))
  3178. {
  3179. m_caret.Set(caret_helm,caret_ofs);
  3180. m_caret.UpdatePos();
  3181. }
  3182. }
  3183. void OpDocumentEdit::CleanUnnecessaryElementsInBlock(SiblingBlock *block, BOOL save_at_least_one)
  3184. {
  3185. DEBUG_CHECKER(TRUE);
  3186. if(block->IsEmpty() || (save_at_least_one && block->start == block->stop))
  3187. return;
  3188. HTML_Element *last_ok_helm = NULL;
  3189. HTML_Element *end_helm = block->stop->Suc();
  3190. for(HTML_Element *helm = block->start; helm != end_helm;)
  3191. {
  3192. OP_ASSERT(helm);
  3193. if(!IsElmValidInListBlock(helm) && (!save_at_least_one || (helm != block->stop || last_ok_helm)))
  3194. {
  3195. if(helm == block->start)
  3196. block->start = helm == block->stop ? NULL : helm->Suc();
  3197. HTML_Element *next = helm->Suc();
  3198. if(helm == m_caret_elm_copy)
  3199. m_caret_elm_copy = NULL;
  3200. if(helm == m_start_sel_copy.GetElement() || helm == m_stop_sel_copy.GetElement())
  3201. {
  3202. m_start_sel_copy = OldStyleTextSelectionPoint();
  3203. m_stop_sel_copy = OldStyleTextSelectionPoint();
  3204. }
  3205. DeleteElement(helm);
  3206. helm = next;
  3207. continue;
  3208. }
  3209. last_ok_helm = helm;
  3210. helm = helm->Suc();
  3211. }
  3212. OP_ASSERT(!save_at_least_one || last_ok_helm);
  3213. block->stop = last_ok_helm;
  3214. }
  3215. OP_STATUS OpDocumentEdit::InsertAndOrToggleListOrdering(HTML_Element *shared_elm,
  3216. SiblingBlock start_block, SiblingBlock stop_block, BOOL ordered)
  3217. {
  3218. DEBUG_CHECKER(TRUE);
  3219. INT32 nestling = GetListNestling(start_block.start);
  3220. SiblingBlock block = start_block;
  3221. HTML_Element *current_list = NULL;
  3222. // Check if the list containing start_block has the same list-type as ordered specifies.
  3223. // Then will all other items be added to this list - and no new list will be created.
  3224. if(nestling)
  3225. {
  3226. HTML_Element *tmp_list = GetParentListElm(start_block.start);
  3227. if(!((tmp_list->Type() == HE_OL) ^ ordered))
  3228. {
  3229. OP_ASSERT(block != stop_block);
  3230. current_list = tmp_list;
  3231. block = GetNextListBlock(shared_elm,block);
  3232. nestling = GetListNestling(block.start);
  3233. OP_ASSERT(!block.IsEmpty());
  3234. }
  3235. }
  3236. while(TRUE)
  3237. {
  3238. OP_ASSERT(!block.IsEmpty());
  3239. if(block.IsEmpty())
  3240. return OpStatus::ERR;
  3241. BOOL is_last_block = block == stop_block;
  3242. HTML_Element *parent_list = nestling ? GetParentListElm(block.start) : NULL;
  3243. if(!parent_list) // block is not in any list
  3244. {
  3245. OP_ASSERT(block.start->Parent() == shared_elm);
  3246. HTML_Element *old_suc = block.stop->Suc();
  3247. HTML_Element *new_current_list = NULL;
  3248. // Replace BR with empty string
  3249. if(block.start == block.stop && block.start->Type() == HE_BR)
  3250. {
  3251. HTML_Element* dummy_elm = NewTextElement(document_edit_dummy_str, 1);
  3252. if(!dummy_elm)
  3253. return OpStatus::ERR_NO_MEMORY;
  3254. dummy_elm->FollowSafe(m_doc,block.start);
  3255. if(m_caret_elm_copy == block.start)
  3256. m_caret_elm_copy = dummy_elm;
  3257. //FIXME: start and stop selection points should be updated to the new element, but the following lines of code doesn't work...
  3258. //if(m_start_sel_copy.GetElement() == block.start)
  3259. // m_start_sel_copy.SetTextElement(dummy_elm);
  3260. //if(m_stop_sel_copy.GetElement() == block.start)
  3261. // m_stop_sel_copy.SetTextElement(dummy_elm);
  3262. if(m_start_sel_copy.GetElement() == block.start || m_stop_sel_copy.GetElement() == block.start)
  3263. {
  3264. m_start_sel_copy = OldStyleTextSelectionPoint();
  3265. m_stop_sel_copy = OldStyleTextSelectionPoint();
  3266. }
  3267. DeleteElement(block.start);
  3268. block = SiblingBlock(dummy_elm,dummy_elm);
  3269. }
  3270. else // Discard and remove this block if it doesn't contain any "necessary" elements
  3271. {
  3272. if(is_last_block)
  3273. {
  3274. CleanUnnecessaryElementsInBlock(&block);
  3275. if(block.IsEmpty())
  3276. break;
  3277. }
  3278. else
  3279. {
  3280. SiblingBlock next_block = GetNextListBlock(shared_elm,block);
  3281. CleanUnnecessaryElementsInBlock(&block);
  3282. if(block.IsEmpty())
  3283. {
  3284. block = next_block;
  3285. nestling = GetListNestling(block.start);
  3286. continue;
  3287. }
  3288. }
  3289. }
  3290. // Create new HE_LI and put block under
  3291. BOOL transform_p_to_li = block.start->Type() == m_paragraph_element_type;
  3292. BOOL already_li = block.start->Type() == HE_LI;
  3293. HTML_Element *list_helm = already_li ? block.start :
  3294. (transform_p_to_li ? NEW_HTML_Element() : NewElement(HE_LI));
  3295. if(!list_helm && !already_li)
  3296. return OpStatus::ERR_NO_MEMORY;
  3297. if(!current_list)
  3298. {
  3299. new_current_list = NewElement(ordered ? HE_OL : HE_UL);
  3300. if(!new_current_list)
  3301. {
  3302. if(!already_li)
  3303. DeleteElement(list_helm);
  3304. return OpStatus::ERR_NO_MEMORY;
  3305. }
  3306. current_list = new_current_list;
  3307. if(old_suc)
  3308. current_list->PrecedeSafe(m_doc,old_suc);
  3309. else
  3310. current_list->UnderSafe(m_doc,shared_elm);
  3311. }
  3312. if(transform_p_to_li) // "Transform" P to LI
  3313. {
  3314. OP_ASSERT(block.start == block.stop);
  3315. HTML_Element *p_elm = block.start;
  3316. if(OpStatus::IsError(list_helm->Construct(m_doc->GetHLDocProfile(),p_elm)))
  3317. {
  3318. DeleteElement(list_helm);
  3319. if(new_current_list)
  3320. DeleteElement(new_current_list);
  3321. return OpStatus::ERR_NO_MEMORY;
  3322. }
  3323. list_helm->SetType(HE_LI);
  3324. list_helm->SetInserted(HE_INSERTED_BY_DOM);
  3325. list_helm->SetEndTagFound(TRUE);
  3326. list_helm->RemoveAttribute(ATTR_ID);
  3327. list_helm->UnderSafe(m_doc,current_list);
  3328. SiblingBlock copy_block = SiblingBlock(p_elm->FirstChild(), p_elm->LastChild());
  3329. CleanUnnecessaryElementsInBlock(&copy_block);
  3330. if(!copy_block.IsEmpty())
  3331. MoveSiblingBlock(copy_block, list_helm);
  3332. else // Create "dummy-element" and put it into the new LI element.
  3333. {
  3334. HTML_Element* dummy_elm = NewTextElement(document_edit_dummy_str, 1);
  3335. if(!dummy_elm)
  3336. {
  3337. if(new_current_list)
  3338. DeleteElement(new_current_list);
  3339. return OpStatus::ERR_NO_MEMORY;
  3340. }
  3341. dummy_elm->UnderSafe(m_doc,list_helm);
  3342. }
  3343. if(m_start_sel_copy.GetElement() == p_elm || m_stop_sel_copy.GetElement() == p_elm)
  3344. {
  3345. m_start_sel_copy = OldStyleTextSelectionPoint();
  3346. m_stop_sel_copy = OldStyleTextSelectionPoint();
  3347. }
  3348. DeleteElement(p_elm);
  3349. // Update block so that next call to GetNextListBlock will not end up in disaster...
  3350. block = SiblingBlock(list_helm,list_helm);
  3351. }
  3352. else if(!already_li)// Just move the block to the new LI element
  3353. {
  3354. CleanUnnecessaryElementsInBlock(&block,TRUE);
  3355. list_helm->UnderSafe(m_doc,current_list);
  3356. MoveSiblingBlock(block, list_helm);
  3357. }
  3358. else
  3359. {
  3360. list_helm->OutSafe(m_doc, FALSE);
  3361. list_helm->UnderSafe(m_doc,current_list);
  3362. }
  3363. }
  3364. else if(parent_list != current_list) // Move element already in list to current_list
  3365. {
  3366. OP_ASSERT(block.start->Parent() == shared_elm || block.start->Parent() == parent_list);
  3367. HTML_Element *split_parent, *split_pred;
  3368. if(current_list)
  3369. {
  3370. if(block.start->Parent()->IsAncestorOf(current_list))
  3371. {
  3372. MoveSiblingBlock(block,current_list,current_list->LastChild());
  3373. }
  3374. else
  3375. {
  3376. HTML_Element *after_me = current_list->LastChild();
  3377. for(HTML_Element *tmp = block.start; tmp; tmp = tmp->Parent())
  3378. {
  3379. if(tmp->Parent() == current_list)
  3380. {
  3381. after_me = tmp->Pred();
  3382. break;
  3383. }
  3384. }
  3385. RETURN_IF_ERROR(SplitListAroundAndMoveBlock(block,current_list,after_me,
  3386. split_parent,split_pred));
  3387. // Clear lists and list elements that have now possibly become empty
  3388. HTML_Element *parent = split_parent;
  3389. while(parent->Type() == HE_OL || parent->Type() == HE_UL || parent->Type() == HE_LI)
  3390. {
  3391. SiblingBlock remaining = SiblingBlock(parent->FirstChild(),parent->LastChild());
  3392. CleanUnnecessaryElementsInBlock(&remaining);
  3393. if(!remaining.IsEmpty())
  3394. break;
  3395. HTML_Element *new_parent = parent->Parent();
  3396. if(m_start_sel_copy.GetElement() == parent || m_stop_sel_copy.GetElement() == parent)
  3397. {
  3398. m_start_sel_copy = OldStyleTextSelectionPoint();
  3399. m_stop_sel_copy = OldStyleTextSelectionPoint();
  3400. }
  3401. DeleteElement(parent);
  3402. parent = new_parent;
  3403. }
  3404. }
  3405. }
  3406. else // Create new current_list
  3407. {
  3408. current_list = NewElement(ordered ? HE_OL : HE_UL);
  3409. if(!current_list)
  3410. return OpStatus::ERR_NO_MEMORY;
  3411. // Create a new list element for inserting current_list in if split_parent
  3412. // is a list, if not - this element is unnecessary and will be removed below
  3413. // but it's created in advance for simplicity.
  3414. HTML_Element *new_li = NewElement(HE_LI);
  3415. if(new_li == NULL)
  3416. {
  3417. DeleteElement(current_list);
  3418. return OpStatus::ERR_NO_MEMORY;
  3419. }
  3420. OP_STATUS status = SplitListAroundAndMoveBlock(block,current_list,NULL,
  3421. split_parent,split_pred);
  3422. if(OpStatus::IsError(status))
  3423. {
  3424. DeleteElement(current_list);
  3425. DeleteElement(new_li);
  3426. return status;
  3427. }
  3428. // The new list should be encapsulated inside the list element created above.
  3429. if(split_parent->Type() == HE_OL || split_parent->Type() == HE_UL)
  3430. {
  3431. current_list->UnderSafe(m_doc,new_li);
  3432. if(split_pred)
  3433. new_li->FollowSafe(m_doc,split_pred);
  3434. else if(split_parent->FirstChild())
  3435. new_li->PrecedeSafe(m_doc,split_parent->FirstChild());
  3436. else
  3437. new_li->UnderSafe(m_doc,split_parent);
  3438. }
  3439. else
  3440. {
  3441. if(split_pred)
  3442. current_list->FollowSafe(m_doc,split_pred);
  3443. else if(split_parent->FirstChild())
  3444. current_list->PrecedeSafe(m_doc,split_parent->FirstChild());
  3445. else
  3446. current_list->UnderSafe(m_doc,split_parent);
  3447. DeleteElement(new_li);
  3448. }
  3449. }
  3450. }
  3451. // else... helm is already in current_list
  3452. if(is_last_block)
  3453. break;
  3454. block = GetNextListBlock(shared_elm,block);
  3455. nestling = GetListNestling(block.start);
  3456. }
  3457. return OpStatus::OK;
  3458. }
  3459. OP_STATUS OpDocumentEdit::IncreaseListNestling()
  3460. {
  3461. DEBUG_CHECKER(TRUE);
  3462. HTML_Element *start_elm,*stop_elm;
  3463. OP_STATUS status = OpStatus::OK;
  3464. SelectionState selection_state = GetSelectionState(TRUE, FALSE, TRUE, TRUE);
  3465. if(!selection_state.IsValid())
  3466. return status;
  3467. start_elm = selection_state.editable_start_elm;
  3468. stop_elm = selection_state.editable_stop_elm;
  3469. HTML_Element *shared_containing_elm = GetSharedContainingElement(start_elm,stop_elm);
  3470. if(!shared_containing_elm)
  3471. return status;
  3472. HTML_Element* tmp = GetRootList(shared_containing_elm);
  3473. if(tmp)
  3474. shared_containing_elm = tmp;
  3475. SiblingBlock start_block,stop_block;
  3476. // Move start_elm and stop_elm up in the tree to the nearest child under a list or under shared_containing_elm.
  3477. while(start_elm && start_elm->Parent() && start_elm->Parent() != shared_containing_elm && start_elm->Parent()->Type() != HE_OL && start_elm->Parent()->Type() != HE_UL)
  3478. start_elm = start_elm->Parent();
  3479. start_block = GetBlockSiblings(start_elm);
  3480. while(stop_elm && stop_elm->Parent() && stop_elm->Parent() != shared_containing_elm && stop_elm->Parent()->Type() != HE_OL && stop_elm->Parent()->Type() != HE_UL)
  3481. stop_elm = stop_elm->Parent();
  3482. stop_block = GetBlockSiblings(stop_elm);
  3483. HTML_Element *change_elm = ((!shared_containing_elm->IsIncludedActual()) ? shared_containing_elm->ParentActual() : shared_containing_elm);
  3484. BeginChange(change_elm);
  3485. SiblingBlock block = start_block;
  3486. while(!block.IsEmpty())
  3487. {
  3488. HTML_Element *parent = block.start->Parent();
  3489. OP_ASSERT(block.start->IsIncludedActual());
  3490. OP_ASSERT(block.stop->IsIncludedActual());
  3491. // We're only intrested in items that are already in a list
  3492. if (parent->Type() == HE_OL || parent->Type() == HE_UL)
  3493. {
  3494. HTML_Element *pred = block.start->Pred();
  3495. HTML_Element *suc = block.stop->Suc();
  3496. HTML_Element *list = NULL;
  3497. if(pred && pred->Type() == parent->Type()) // move element(s) to list above
  3498. {
  3499. list = pred;
  3500. MoveSiblingBlock(block,pred,pred->LastChild());
  3501. }
  3502. else if(suc && suc->Type() == parent->Type()) // move element(s) to list below
  3503. MoveSiblingBlock(block,suc,NULL);
  3504. else // Let's create a new more deeply nestled list
  3505. {
  3506. list = NewCopyOfElement(parent,TRUE);
  3507. if(!list)
  3508. {
  3509. status = OpStatus::ERR_NO_MEMORY;
  3510. ReportOOM();
  3511. break;
  3512. }
  3513. if(suc)
  3514. list->PrecedeSafe(m_doc,suc);
  3515. else
  3516. list->UnderSafe(m_doc,parent);
  3517. MoveSiblingBlock(block,list,NULL);
  3518. }
  3519. // If true -> we moved the element(s) to the list above and can now concat this list with list below
  3520. if(suc && list && suc->Type() == list->Type())
  3521. {
  3522. MoveSiblingBlock(SiblingBlock(suc->FirstChild(),suc->LastChild()),list,list->LastChild());
  3523. DeleteElement(suc);
  3524. }
  3525. parent->MarkExtraDirty(m_doc);
  3526. }
  3527. if (block == stop_block)
  3528. break;
  3529. block = GetNextListBlock(shared_containing_elm,block);
  3530. }
  3531. RestoreSelectionState(selection_state);
  3532. if(OpStatus::IsSuccess(status))
  3533. EndChange(change_elm);
  3534. else
  3535. AbortChange();
  3536. return status;
  3537. }
  3538. OP_STATUS OpDocumentEdit::DecreaseListNestling()
  3539. {
  3540. DEBUG_CHECKER(TRUE);
  3541. HTML_Element *start_elm,*stop_elm;
  3542. OP_STATUS status = OpStatus::OK;
  3543. SelectionState selection_state = GetSelectionState(TRUE, FALSE, TRUE, TRUE);
  3544. if(!selection_state.IsValid())
  3545. return status;
  3546. start_elm = selection_state.editable_start_elm;
  3547. stop_elm = selection_state.editable_stop_elm;
  3548. HTML_Element *shared_containing_elm = GetSharedContainingElement(start_elm,stop_elm);
  3549. if(!shared_containing_elm)
  3550. return status;
  3551. HTML_Element* tmp = GetRootList(shared_containing_elm);
  3552. if(tmp)
  3553. shared_containing_elm = tmp;
  3554. HTML_Element *change_elm;
  3555. HTML_Element *iter = shared_containing_elm;
  3556. // Find the shared container being outside of any list.
  3557. do
  3558. {
  3559. change_elm = iter;
  3560. iter = iter->Parent();
  3561. }
  3562. while (change_elm->IsMatchingType(Markup::HTE_UL, NS_HTML) || change_elm->IsMatchingType(Markup::HTE_OL, NS_HTML) || (change_elm->IsMatchingType(Markup::HTE_LI, NS_HTML)));
  3563. change_elm = ((!change_elm->IsIncludedActual()) ? change_elm->ParentActual() : change_elm);
  3564. SiblingBlock start_block,stop_block;
  3565. while(start_elm && start_elm->Parent() && start_elm->Parent() != shared_containing_elm && start_elm->Parent()->Type() != HE_OL && start_elm->Parent()->Type() != HE_UL)
  3566. start_elm = start_elm->Parent();
  3567. start_block = GetBlockSiblings(start_elm);
  3568. while(stop_elm && stop_elm->Parent() && stop_elm->Parent() != shared_containing_elm && stop_elm->Parent()->Type() != HE_OL && stop_elm->Parent()->Type() != HE_UL)
  3569. stop_elm = stop_elm->Parent();
  3570. stop_block = GetBlockSiblings(stop_elm);
  3571. BeginChange(change_elm);
  3572. status = DecreaseMaxListNestling(shared_containing_elm,start_block,stop_block,0);
  3573. change_elm->MarkExtraDirty(m_doc);
  3574. RestoreSelectionState(selection_state);
  3575. if(OpStatus::IsSuccess(status))
  3576. EndChange(change_elm);
  3577. else
  3578. AbortChange();
  3579. return status;
  3580. }
  3581. OP_STATUS OpDocumentEdit::DecreaseMaxListNestling(HTML_Element *shared_elm, SiblingBlock start_block, SiblingBlock stop_block, INT32 max_nestling)
  3582. {
  3583. DEBUG_CHECKER(TRUE);
  3584. INT32 nestling = GetListNestling(start_block.start);
  3585. SiblingBlock block = start_block;
  3586. while(TRUE)
  3587. {
  3588. BOOL is_last_block = block == stop_block;
  3589. BOOL next_block_already_found = FALSE;
  3590. OP_ASSERT(!block.IsEmpty());
  3591. if(block.IsEmpty())
  3592. return OpStatus::ERR;
  3593. // Only perform this operation on items that are maximally nestled.
  3594. if(nestling && nestling >= max_nestling)
  3595. {
  3596. OP_ASSERT(block.start->Parent() == shared_elm || block.start->Parent()->Type() == HE_OL || block.start->Parent()->Type() == HE_UL);
  3597. HTML_Element *split_parent, *split_pred;
  3598. HTML_Element *container = NewElement(m_paragraph_element_type); // just a temporary element...
  3599. if(container == NULL)
  3600. return OpStatus::ERR_NO_MEMORY;
  3601. container->FollowSafe(m_doc, shared_elm); // Make the container part of the tree.
  3602. OP_STATUS status = SplitListAroundAndMoveBlock(block,container,NULL,split_parent,split_pred);
  3603. if(OpStatus::IsError(status))
  3604. {
  3605. DeleteElement(container);
  3606. return status;
  3607. }
  3608. NonActualElementPosition split_pred_info;
  3609. RETURN_IF_ERROR(split_pred_info.Construct(split_pred));
  3610. // If the new parent is not a list and the block is a list-item (LI),
  3611. // then convert it to a paragraph element.
  3612. if(block.start->Type() == HE_LI && split_parent->Type() != HE_OL && split_parent->Type() != HE_UL)
  3613. {
  3614. OP_ASSERT(block.start == block.stop);
  3615. HTML_Element *li_elm = block.start;
  3616. HTML_Element *first_child_actual = li_elm->FirstChildActual();
  3617. HTML_Element *last_child_actual = li_elm->LastChildActual();
  3618. SiblingBlock child_block = SiblingBlock(first_child_actual, last_child_actual);
  3619. CleanUnnecessaryElementsInBlock(&child_block);
  3620. if(!child_block.IsEmpty())
  3621. {
  3622. HTML_Element *p_elm;
  3623. BOOL move_from_li_to_p = FALSE;
  3624. // LI just contains one paragraph element, don't create any new
  3625. if(first_child_actual->Type() == m_paragraph_element_type && first_child_actual == last_child_actual)
  3626. {
  3627. p_elm = first_child_actual;
  3628. p_elm->OutSafe(m_doc, FALSE);
  3629. }
  3630. else
  3631. {
  3632. p_elm = NEW_HTML_Element();
  3633. if(p_elm == NULL || OpStatus::IsError(p_elm->Construct(m_doc->GetHLDocProfile(),li_elm)))
  3634. {
  3635. DeleteElement(p_elm);
  3636. DeleteElement(container);
  3637. return OpStatus::ERR_NO_MEMORY;
  3638. }
  3639. p_elm->SetType(m_paragraph_element_type);
  3640. p_elm->SetInserted(HE_INSERTED_BY_DOM);
  3641. p_elm->SetEndTagFound(TRUE);
  3642. p_elm->RemoveAttribute(ATTR_ID);
  3643. move_from_li_to_p = TRUE;
  3644. }
  3645. split_pred = split_pred_info.Get();
  3646. if(split_pred)
  3647. p_elm->FollowSafe(m_doc,split_pred);
  3648. else if(split_parent->FirstChild())
  3649. p_elm->PrecedeSafe(m_doc,split_parent->FirstChild());
  3650. else
  3651. p_elm->UnderSafe(m_doc,split_parent);
  3652. // Move children of the LI element to the new paragraph element.
  3653. if (move_from_li_to_p)
  3654. MoveSiblingBlock(SiblingBlock(first_child_actual,last_child_actual), p_elm);
  3655. // Update block so that next call to GetNextListBlock will not end up in disaster...
  3656. block = SiblingBlock(p_elm,p_elm);
  3657. if (m_start_sel_copy.GetElement() == li_elm)
  3658. m_start_sel_copy = GetTextSelectionPoint(p_elm, m_start_sel_copy.GetElementCharacterOffset());
  3659. if (m_stop_sel_copy.GetElement() == li_elm)
  3660. m_stop_sel_copy = GetTextSelectionPoint(p_elm, m_stop_sel_copy.GetElementCharacterOffset());
  3661. }
  3662. else // if LI is empty -> just remove it
  3663. {
  3664. if(!is_last_block)
  3665. {
  3666. // "hack" for finding next block...
  3667. split_pred = split_pred_info.Get();
  3668. if(split_pred)
  3669. container->FollowSafe(m_doc,split_pred);
  3670. else if(split_parent->FirstChild())
  3671. container->PrecedeSafe(m_doc,split_parent->FirstChild());
  3672. else
  3673. container->UnderSafe(m_doc,split_parent);
  3674. block = GetNextListBlock(shared_elm,block);
  3675. next_block_already_found = TRUE;
  3676. }
  3677. if (m_start_sel_copy.GetElement() == li_elm)
  3678. {
  3679. if (li_elm->Precedes(m_stop_sel_copy.GetElement()))
  3680. m_start_sel_copy = GetTextSelectionPoint(li_elm->NextActual(), 0);
  3681. else
  3682. {
  3683. m_start_sel_copy = OldStyleTextSelectionPoint();
  3684. m_stop_sel_copy = OldStyleTextSelectionPoint();
  3685. }
  3686. }
  3687. else if (m_stop_sel_copy.GetElement() == li_elm)
  3688. {
  3689. if (li_elm->Precedes(m_start_sel_copy.GetElement()))
  3690. {
  3691. HTML_Element *prev = li_elm->PrevActual();
  3692. m_stop_sel_copy = GetTextSelectionPoint(prev, prev->Type() == HE_TEXT ? prev->GetTextContentLength() : 1);
  3693. }
  3694. else
  3695. {
  3696. m_start_sel_copy = OldStyleTextSelectionPoint();
  3697. m_stop_sel_copy = OldStyleTextSelectionPoint();
  3698. }
  3699. }
  3700. }
  3701. DeleteElement(li_elm); // delete LI
  3702. }
  3703. else
  3704. {
  3705. // No conversion needed, just copy the block to the new parent.
  3706. split_pred = split_pred_info.Get();
  3707. MoveSiblingBlock(SiblingBlock(container->FirstChild(),container->LastChild()), split_parent, split_pred);
  3708. }
  3709. DeleteElement(container);
  3710. }
  3711. if(is_last_block)
  3712. break;
  3713. if(!next_block_already_found)
  3714. block = GetNextListBlock(shared_elm,block);
  3715. nestling = GetListNestling(block.start);
  3716. }
  3717. return OpStatus::OK;
  3718. }
  3719. void OpDocumentEdit::ToggleInsertList(BOOL ordered)
  3720. {
  3721. DEBUG_CHECKER(TRUE);
  3722. m_undo_stack.BeginGroup();
  3723. HTML_ElementType block_quote[] = {HE_BLOCKQUOTE,HE_UNKNOWN};
  3724. RemoveBlockTypes(block_quote);
  3725. OP_STATUS status;
  3726. SiblingBlock start, stop, block;
  3727. INT32 nestling, max_nestling, min_nestling;
  3728. SELECTION_ORDERING ordering = UNKNOWN;
  3729. BOOL had_content = m_selection.HasContent();
  3730. HTML_Element *old_caret = m_caret.GetElement();
  3731. m_caret_elm_copy = old_caret;
  3732. if(had_content)
  3733. {
  3734. start = GetBlockSiblings(m_selection.GetStartElement(TRUE));
  3735. stop = GetBlockSiblings(m_selection.GetStopElement(TRUE));
  3736. m_start_sel_copy = GetTextSelectionPoint(m_selection.GetStartElement(TRUE), m_selection.GetStartOfs());
  3737. m_stop_sel_copy = GetTextSelectionPoint(m_selection.GetStopElement(TRUE), m_selection.GetStopOfs());
  3738. }
  3739. else
  3740. {
  3741. m_start_sel_copy = OldStyleTextSelectionPoint();
  3742. m_stop_sel_copy = OldStyleTextSelectionPoint();
  3743. start = GetBlockSiblings(m_caret.GetElement());
  3744. stop = start;
  3745. }
  3746. if(!(start.start && start.stop && stop.start && stop.stop))
  3747. {
  3748. m_undo_stack.EndGroup();
  3749. return;
  3750. }
  3751. HTML_Element* shared_containing_elm = GetSharedContainingElement(start.start, stop.stop);
  3752. //FIXME: Should support making several lists in several table-cells
  3753. HTML_ElementType avoid_containers[] = { HE_TABLE, HE_TBODY, HE_TR, HE_UNKNOWN };
  3754. if(IsAnyOfTypes(shared_containing_elm,avoid_containers))
  3755. {
  3756. m_undo_stack.EndGroup();
  3757. return;
  3758. }
  3759. if(had_content)
  3760. m_selection.SelectNothing();
  3761. HTML_Element *helm;
  3762. // Adjust shared_containing_elm up to the nearest enclosing OL, UL or BODY element
  3763. // or to the closest parent of a block-element that is a shared containing element.
  3764. if(shared_containing_elm->Type() == m_paragraph_element_type)
  3765. shared_containing_elm = shared_containing_elm->Parent();
  3766. for(helm = shared_containing_elm; helm; helm = helm->ParentActual())
  3767. {
  3768. if(helm->Type() == HE_OL || helm->Type() == HE_UL /*|| helm->Type() == HE_BODY*/)
  3769. {
  3770. shared_containing_elm = helm;
  3771. break;
  3772. }
  3773. }
  3774. // Adjust start and stop up in the tree so that they are placed immediately under
  3775. // shared_containing_elm or the nearest enclosing list element.
  3776. if(start.start != shared_containing_elm)
  3777. {
  3778. if(start == stop)
  3779. {
  3780. while(TRUE)
  3781. {
  3782. HTML_Element *parent = start.start->Parent();
  3783. if(parent == shared_containing_elm || parent->Type() == HE_OL || parent->Type() == HE_UL)
  3784. break;
  3785. start = GetBlockSiblings(parent);
  3786. stop = start;
  3787. }
  3788. }
  3789. else
  3790. {
  3791. while(TRUE)
  3792. {
  3793. HTML_Element *parent = start.start->Parent();
  3794. if(parent == shared_containing_elm || parent->Type() == HE_OL || parent->Type() == HE_UL
  3795. /*|| parent->IsAncestorOf(stop.start)*/)
  3796. {
  3797. break;
  3798. }
  3799. start = GetBlockSiblings(parent);
  3800. }
  3801. while(TRUE)
  3802. {
  3803. HTML_Element *parent = stop.start->Parent();
  3804. if(parent == shared_containing_elm || parent->Type() == HE_OL || parent->Type() == HE_UL
  3805. /*|| parent->IsAncestorOf(start.stop)*/)
  3806. {
  3807. break;
  3808. }
  3809. stop = GetBlockSiblings(parent);
  3810. }
  3811. }
  3812. }
  3813. // Not supposed to happen... but take care of this anyway in order to prevent crashes.
  3814. if(!IsValidListBlock(start) || !IsValidListBlock(stop))
  3815. {
  3816. m_undo_stack.EndGroup();
  3817. return;
  3818. }
  3819. nestling = GetListNestling(start.start);
  3820. max_nestling = nestling;
  3821. min_nestling = nestling;
  3822. BOOL different_root_lists = FALSE;
  3823. if(nestling)
  3824. SetOrdering(ordering,GetParentListElm(start.start)->Type());
  3825. // Iterate through (none, some or all of) the list elements in order to determine if items
  3826. // should be inserted in a new/existing list by InsertAndOrToggleListOrdering - or if the
  3827. // maximum list-nestling should be decreased by DecreaseMaxListNestling.
  3828. //
  3829. // InsertAndOrToggleListOrdering should be used if:
  3830. //
  3831. // 1. There are some items that are not in any list.
  3832. // 2. All items are in lists but the list type of the most deeply nestled lists (OL/UL) they
  3833. // participate in is not coherent.
  3834. // 3. All items are in lists but they are contained in different root-lists (the lists in the
  3835. // top of the list hierarchy)
  3836. //
  3837. // Otherwise should DecreaseMaxListNestling be used, the maximum list nestling is also found
  3838. // here.
  3839. block = start;
  3840. HTML_Element *root_list = GetRootList(block.start);
  3841. while(block != stop && nestling && !different_root_lists)
  3842. {
  3843. block = GetNextListBlock(shared_containing_elm,block);
  3844. OP_ASSERT(!block.IsEmpty());
  3845. if(block.IsEmpty())
  3846. {
  3847. m_undo_stack.EndGroup();
  3848. return;
  3849. }
  3850. nestling = GetListNestling(block.start);
  3851. max_nestling = MAX(max_nestling,nestling);
  3852. min_nestling = MIN(min_nestling,nestling);
  3853. if(nestling)
  3854. {
  3855. HTML_Element *tmp_root = GetRootList(block.start);
  3856. if(tmp_root != root_list)
  3857. different_root_lists = TRUE;
  3858. SetOrdering(ordering,GetParentListElm(block.start)->Type());
  3859. }
  3860. }
  3861. BOOL insert = min_nestling == 0 || (ordering != ORDERED && ordered) ||
  3862. (ordering != UN_ORDERED && !ordered) || different_root_lists;
  3863. // The root-element for where the changes will apply is set so it's not inside any list
  3864. // because we might "shuffle" things around a bit later.
  3865. HTML_Element *change_elm = shared_containing_elm;
  3866. for(helm = change_elm; helm; helm = helm->Parent())
  3867. {
  3868. if(helm->Type() == HE_OL || helm->Type() == HE_UL || helm->Type() == HE_LI)
  3869. change_elm = helm->Parent();
  3870. }
  3871. if(!change_elm->IsIncludedActual())
  3872. change_elm = change_elm->ParentActual();
  3873. // Set shared_containing_elm to it's parent if it's a list because the list might be splitted.
  3874. if(shared_containing_elm->Type() == HE_OL || shared_containing_elm->Type() == HE_UL)
  3875. shared_containing_elm = shared_containing_elm->Parent();
  3876. BeginChange(change_elm);
  3877. if(insert)
  3878. {
  3879. RemoveInlinePropertyBetween(start.start,stop.stop,CSS_PROPERTY_margin_left,TRUE);
  3880. LockPendingStyles(TRUE);
  3881. status = InsertAndOrToggleListOrdering(shared_containing_elm,start,stop,ordered);
  3882. LockPendingStyles(FALSE);
  3883. }
  3884. else
  3885. status = DecreaseMaxListNestling(shared_containing_elm,start,stop,max_nestling);
  3886. if(OpStatus::IsError(status))
  3887. {
  3888. AbortChange();
  3889. if(OpStatus::IsMemoryError(status))
  3890. ReportOOM();
  3891. m_undo_stack.EndGroup();
  3892. return;
  3893. }
  3894. change_elm->MarkExtraDirty(m_doc); // Seems necessary, don't know why because UnderSafe and other "Safe" functions are used for manipulating the tree.
  3895. if(m_start_sel_copy.GetElement() || old_caret != m_caret_elm_copy)
  3896. {
  3897. ReflowAndUpdate();
  3898. if(m_start_sel_copy.GetElement()) // restore selection
  3899. m_selection.Select(&m_start_sel_copy,&m_stop_sel_copy);
  3900. if(old_caret != m_caret_elm_copy) // change caret element if the old element has been deleted.
  3901. {
  3902. LockPendingStyles(TRUE);
  3903. m_caret.Set(m_caret_elm_copy, 0);
  3904. if(m_caret_elm_copy)
  3905. {
  3906. m_caret.GetElement()->MarkExtraDirty(m_doc);
  3907. m_caret.UpdatePos();
  3908. }
  3909. LockPendingStyles(FALSE);
  3910. }
  3911. }
  3912. LockPendingStyles(TRUE);
  3913. EndChange(change_elm,TIDY_LEVEL_MINIMAL);
  3914. LockPendingStyles(FALSE);
  3915. m_undo_stack.EndGroup();
  3916. }
  3917. OP_STATUS OpDocumentEdit::CreateStyleTreeCopyOf(HTML_Element *src_helm, HTML_Element *src_containing_elm, HTML_Element *&new_top_helm, HTML_Element *&new_bottom_helm, BOOL put_empty_string_at_bottom, BOOL make_empty_dummy)
  3918. {
  3919. if (!src_helm)
  3920. return OpStatus::ERR;
  3921. DEBUG_CHECKER(TRUE);
  3922. new_top_helm = NULL;
  3923. new_bottom_helm = NULL;
  3924. OP_ASSERT(src_helm);
  3925. if(!src_containing_elm)
  3926. src_containing_elm = m_doc->GetCaret()->GetContainingElementActual(src_helm);
  3927. OP_ASSERT(src_containing_elm->IsAncestorOf(src_helm));
  3928. if(put_empty_string_at_bottom)
  3929. {
  3930. HTML_Element* new_text_helm = NULL;
  3931. if(make_empty_dummy)
  3932. new_text_helm = NewElement(HE_BR, TRUE);
  3933. else
  3934. new_text_helm = NewTextElement(UNI_L(""), 0);
  3935. if(!new_text_helm)
  3936. return OpStatus::ERR_NO_MEMORY;
  3937. new_top_helm = new_text_helm;
  3938. new_bottom_helm = new_text_helm;
  3939. }
  3940. while(src_helm != src_containing_elm)
  3941. {
  3942. if(IsStyleElementType(src_helm->Type()))
  3943. {
  3944. HTML_Element *new_helm = NewCopyOfElement(src_helm,TRUE);
  3945. if(!new_helm)
  3946. {
  3947. while(new_bottom_helm)
  3948. {
  3949. HTML_Element *tmp = new_bottom_helm->Parent();
  3950. DeleteElement(new_bottom_helm);
  3951. new_bottom_helm = tmp;
  3952. }
  3953. return OpStatus::ERR_NO_MEMORY;
  3954. }
  3955. if(!new_top_helm)
  3956. {
  3957. new_top_helm = new_helm;
  3958. new_bottom_helm = new_helm;
  3959. }
  3960. else
  3961. {
  3962. new_top_helm->UnderSafe(m_doc,new_helm);
  3963. new_top_helm = new_helm;
  3964. }
  3965. }
  3966. src_helm = src_helm->ParentActual();
  3967. }
  3968. return OpStatus::OK;
  3969. }
  3970. void OpDocumentEdit::InsertBreak(BOOL break_list, BOOL new_paragraph)
  3971. {
  3972. DEBUG_CHECKER(TRUE);
  3973. ReflowAndUpdate();
  3974. if (m_selection.HasContent())
  3975. {
  3976. m_selection.RemoveContent();
  3977. m_selection.SelectNothing();
  3978. }
  3979. if(m_caret.GetElement() && m_layout_modifier.IsActive() && m_layout_modifier.m_helm == m_caret.GetElement())
  3980. m_layout_modifier.Delete();
  3981. HTML_Element* real_elm = m_caret.m_real_caret_elm.GetElm();
  3982. if (m_caret.IsUnmodifiedTemporaryCaretTextElement() && real_elm)
  3983. {
  3984. m_caret.CleanTemporaryCaretTextElement(TRUE);
  3985. SelectionBoundaryPoint sel_point(real_elm, m_caret.m_real_caret_elm_off);
  3986. m_caret.Place(sel_point);
  3987. }
  3988. OP_ASSERT(m_caret.GetElement());
  3989. if (!m_caret.GetElement())
  3990. return; // Sanitycheck. Should not happen but sometimes *everything* was removed above.
  3991. HTML_Element* containing_elm = m_doc->GetCaret()->GetContainingElementActual(m_caret.GetElement());
  3992. HTML_Element* tmp = containing_elm;
  3993. if(!containing_elm)
  3994. return;
  3995. HTML_Element* top_editable_parent = GetTopEditableParent(containing_elm);
  3996. // The containing element might be inside a list-element, then we want to break that list-element
  3997. while(tmp && top_editable_parent && tmp != top_editable_parent->Parent())
  3998. {
  3999. if (tmp->IsMatchingType(HE_LI, NS_HTML))
  4000. {
  4001. containing_elm = tmp;
  4002. break;
  4003. }
  4004. tmp = tmp->ParentActual();
  4005. }
  4006. if (containing_elm->Type() == HE_LI && break_list && !containing_elm->IsContentEditable(FALSE))
  4007. {
  4008. int dummy;
  4009. HTML_Element *editable = NULL;
  4010. GetOneStepBeside(FALSE,m_caret.GetElement(),m_caret.GetOffset(),editable,dummy);
  4011. BOOL at_start = !containing_elm->IsAncestorOf(editable);
  4012. GetOneStepBeside(TRUE,m_caret.GetElement(),m_caret.GetOffset(),editable,dummy);
  4013. BOOL at_end = !containing_elm->IsAncestorOf(editable);
  4014. if (at_start && at_end)
  4015. {
  4016. // Was breaking a empty HE_LI so we will remove the HE_LI and make a empty HE_P instead (or HE_LI if we're breaking a nestled list).
  4017. HTML_Element* parent = containing_elm->ParentActual();
  4018. void *align = containing_elm->GetAttr(ATTR_ALIGN,ITEM_TYPE_NUM,NULL);
  4019. if(!align)
  4020. align = parent->GetAttr(ATTR_ALIGN,ITEM_TYPE_NUM,NULL);
  4021. // If we end up in another list we should create a HE_LI
  4022. BOOL create_li = FALSE;
  4023. if (parent->Type() == HE_OL || parent->Type() == HE_UL)
  4024. {
  4025. parent = parent->ParentActual();
  4026. create_li = parent->Type() == HE_OL || parent->Type() == HE_UL;
  4027. }
  4028. OP_STATUS status = BeginChange(parent);
  4029. OpString tmp;
  4030. const uni_char *tag = create_li ? UNI_L("li") : HTM_Lex::GetTagString(m_paragraph_element_type);
  4031. ReportIfOOM(tmp.AppendFormat(UNI_L("<%s>%s</%s>"), tag, document_edit_dummy_str, tag));
  4032. HTML_Element *result_start = NULL, *result_stop = NULL;
  4033. HTML_Element *top_helm, *bottom_helm;
  4034. // First, let's copy the style-elements over the caret so we keep the style in the new HE_P/HE_LI.
  4035. if (OpStatus::IsSuccess(status = CreateStyleTreeCopyOf(m_caret.GetElement(),containing_elm,
  4036. top_helm,bottom_helm,FALSE,FALSE)))
  4037. {
  4038. // Split the list and insert the new element between the two parts.
  4039. status = InsertTextHTML(tmp, uni_strlen(tmp),&result_start, &result_stop, parent);
  4040. if(OpStatus::IsSuccess(status) && result_start)
  4041. {
  4042. if(result_start == result_stop && result_start->FirstChild() == result_stop->LastChild() && result_start->FirstChild())
  4043. {
  4044. HTML_Element *empty_str = result_start->FirstChild();
  4045. empty_str->SetText(m_doc,document_edit_dummy_str,1);
  4046. if(top_helm) // Insert the style-elements under the new P/LI element and above the dummy text element
  4047. {
  4048. empty_str->OutSafe(m_doc, FALSE);
  4049. top_helm->UnderSafe(m_doc,result_start);
  4050. empty_str->UnderSafe(m_doc,bottom_helm);
  4051. m_caret.Place(empty_str,0);
  4052. }
  4053. if(align && !result_start->IsText())
  4054. SetAlignAttrFromCSSValue(result_start,(CSSValue)(INTPTR)align);
  4055. }
  4056. else //FIXME: If some elements where inserted due to CSS in InserTextHTML, we currently just skip the style-copying.
  4057. DeleteElement(top_helm);
  4058. }
  4059. else
  4060. {
  4061. if(OpStatus::IsSuccess(status))
  4062. status = OpStatus::ERR;
  4063. DeleteElement(top_helm);
  4064. }
  4065. parent->MarkExtraDirty(m_doc);
  4066. }
  4067. if(OpStatus::IsSuccess(status))
  4068. {
  4069. // If the lower part of the splitted list is empty - let's remove it.
  4070. HTML_Element *after = result_stop->SucActual();
  4071. if(after && after->IsAncestorOf(after->NextActual()))
  4072. after = after->NextActual();
  4073. HTML_Element *end_change = after ? after : result_stop;
  4074. status = EndChange(parent,result_start,end_change,TRUE,TIDY_LEVEL_AGGRESSIVE);
  4075. }
  4076. else
  4077. AbortChange();
  4078. }
  4079. else if (at_end)
  4080. {
  4081. // Was at the end of last element, or of element before ending BR
  4082. // Add a new LI following the current one
  4083. HTML_Element* parent = containing_elm->Parent();
  4084. parent->Parent()->MarkDirty(m_doc, FALSE, TRUE); // Only for the repaint
  4085. BeginChange(parent);
  4086. HTML_Element* new_li = NewElement(HE_LI);
  4087. void *align = containing_elm->GetAttr(ATTR_ALIGN,ITEM_TYPE_NUM,NULL);
  4088. HTML_Element *top_helm,*bottom_helm;
  4089. if(new_li && OpStatus::IsSuccess(CreateStyleTreeCopyOf(m_caret.GetElement(),containing_elm,top_helm,bottom_helm,TRUE,FALSE)))
  4090. {
  4091. if(align)
  4092. new_li->SetAttr(ATTR_ALIGN,ITEM_TYPE_NUM,align);
  4093. top_helm->UnderSafe(m_doc, new_li);
  4094. new_li->FollowSafe(m_doc, containing_elm);
  4095. top_helm->MarkExtraDirty(m_doc);
  4096. m_caret.Place(bottom_helm, 0);
  4097. }
  4098. EndChange(parent, TIDY_LEVEL_NORMAL);
  4099. }
  4100. else
  4101. {
  4102. m_undo_stack.BeginGroup();
  4103. // Insert a new HE_LI at the caretposition
  4104. containing_elm->MarkExtraDirty(m_doc);
  4105. void *align = containing_elm->GetAttr(ATTR_ALIGN,ITEM_TYPE_NUM,NULL);
  4106. BOOL insert_before = (m_caret.GetOffset() == 0);
  4107. OpString tmp;
  4108. ReportIfOOM(tmp.AppendFormat(UNI_L("<li>%s</li>"), document_edit_dummy_str));
  4109. HTML_Element* result_start;
  4110. OP_STATUS status = InsertTextHTML(tmp, tmp.Length(), &result_start, NULL, containing_elm->Parent());
  4111. if (OpStatus::IsMemoryError(status))
  4112. ReportOOM();
  4113. if (result_start)
  4114. {
  4115. if (result_start->IsText())
  4116. {
  4117. // Probably parsed into a <plaintext> node or something
  4118. // similar. Undo what we can.
  4119. m_undo_stack.EndGroup();
  4120. Undo();
  4121. m_undo_stack.Clear(FALSE, TRUE);
  4122. return;
  4123. }
  4124. else
  4125. {
  4126. if (align)
  4127. SetAlignAttrFromCSSValue(result_start, (CSSValue)(INTPTR)align);
  4128. HTML_Element* helm = result_start;
  4129. m_caret.Place(helm->NextActual(), 0); // place at dummy
  4130. helm->NextActual()->MarkExtraDirty(m_doc);
  4131. }
  4132. }
  4133. if (!insert_before)
  4134. {
  4135. OpInputAction action(OpInputAction::ACTION_DELETE);
  4136. EditAction(&action);
  4137. }
  4138. m_undo_stack.EndGroup();
  4139. }
  4140. }
  4141. #ifdef DOCUMENTEDIT_SPLIT_BLOCKQUOTE
  4142. else if (m_blockquote_split && GetTopMostParentOfType(containing_elm, HE_BLOCKQUOTE))
  4143. {
  4144. containing_elm = GetTopMostParentOfType(containing_elm, HE_BLOCKQUOTE);
  4145. HTML_Element* split_root = m_doc->GetCaret()->GetContainingElementActual(containing_elm);
  4146. OpString tmp_str;
  4147. const uni_char *tag = HTM_Lex::GetTagString(m_paragraph_element_type);
  4148. ReportIfOOM(tmp_str.AppendFormat(UNI_L("<%s><br></%s>"), tag, tag));
  4149. HTML_Element *result_start = NULL, *result_stop = NULL;
  4150. InsertTextHTML(tmp_str, tmp_str.Length(), &result_start, &result_stop, split_root);
  4151. // Make sure we set the InsertedAutomatically flag so the br element can be removed automatically too.
  4152. if (result_start && result_start->FirstChild() && result_start->FirstChild()->Type() == HE_BR)
  4153. SetInsertedAutomatically(result_start->FirstChild(), TRUE);
  4154. }
  4155. #endif // DOCUMENTEDIT_SPLIT_BLOCKQUOTE
  4156. #ifdef DOCUMENT_EDIT_USE_PARAGRAPH_BREAK
  4157. else if (new_paragraph)
  4158. {
  4159. // In IE, a PRE element is split, like DIV and P instead of inserting <br> (which is only done when hitting shift+enter)
  4160. // Just disabling the following check will make that happen in Opera to, but i'm not sure what's the expected/best behaviour.
  4161. if(IsInPreFormatted(containing_elm))
  4162. {
  4163. InsertBreak(break_list, FALSE);
  4164. return;
  4165. }
  4166. OpDocumentEditUndoRedoAutoGroup autogroup(&m_undo_stack);
  4167. BOOL is_at_start_after_child_container;
  4168. BOOL is_at_end_before_child_container;
  4169. BOOL is_at_start = m_caret.IsAtStartOrEndOfBlock(TRUE, &is_at_start_after_child_container);
  4170. BOOL is_at_end = m_caret.IsAtStartOrEndOfBlock(FALSE, &is_at_end_before_child_container);
  4171. HTML_Element* split_root = m_doc->GetCaret()->GetContainingElementActual(containing_elm);
  4172. HTML_Element* current_p_elm = NULL;
  4173. // Check if it's a blocklevel element we should split, or create new paragraph under it using InsertBlockElementMultiple
  4174. if (!containing_elm->IsContentEditable() &&
  4175. // Theese elements will be split, instead of getting new P blocks inside.
  4176. (containing_elm->Type() == HE_P ||
  4177. containing_elm->Type() == HE_DIV ||
  4178. containing_elm->Type() == HE_PRE ||
  4179. IsHeader(containing_elm)
  4180. // ...More?
  4181. ))
  4182. {
  4183. current_p_elm = containing_elm;
  4184. }
  4185. else
  4186. {
  4187. //OP_STATUS status = BeginChange(containing_elm);
  4188. // Insert new paragraph element over this block
  4189. current_p_elm = NewElement(m_paragraph_element_type);
  4190. DoceditRef holder;
  4191. holder.SetElm(current_p_elm);
  4192. if (!current_p_elm || OpStatus::IsError(InsertBlockElementMultiple(current_p_elm,FALSE,TRUE)))//InsertOverBlock(current_p_elm, current_p_elm);
  4193. {
  4194. ReportOOM();
  4195. DeleteElement(current_p_elm);
  4196. return;
  4197. }
  4198. //status = EndChange(containing_elm, TIDY_LEVEL_NORMAL);
  4199. split_root = containing_elm;
  4200. }
  4201. // Spec says that at ending position of a header, we should follow with a new p tag.
  4202. BOOL force_p = FALSE;
  4203. if (is_at_end && IsHeader(containing_elm))
  4204. force_p = TRUE;
  4205. OpString tmp_str;
  4206. const uni_char *tag = HTM_Lex::GetTagString(m_paragraph_element_type);
  4207. ReportIfOOM(tmp_str.AppendFormat(UNI_L("<%s><br></%s>"), tag, tag));
  4208. if (!force_p)
  4209. {
  4210. // Quick and dirty way to insert a new copy of what we already have, with the same styles as we already have.
  4211. // First extract the html as string from a copy of the element, and use that for insertion later.
  4212. HTML_Element* tmp_element = NewCopyOfElement(current_p_elm);
  4213. if (tmp_element)
  4214. {
  4215. // Remove the ID attribute
  4216. tmp_element->RemoveAttribute(ATTR_ID);
  4217. // Insert child text node containing dumme element for caret.
  4218. HTML_Element *top_helm, *bottom_helm;
  4219. if (!containing_elm->IsAncestorOf(m_caret.GetElement()))
  4220. containing_elm = m_doc->GetCaret()->GetContainingElementActual(m_caret.GetElement());
  4221. if (OpStatus::IsSuccess(CreateStyleTreeCopyOf(m_caret.GetElement(), containing_elm,
  4222. top_helm,bottom_helm,TRUE,TRUE)))
  4223. {
  4224. top_helm->Under(tmp_element);
  4225. GetTextHTMLFromElement(tmp_str, tmp_element, TRUE);
  4226. }
  4227. }
  4228. DeleteElement(tmp_element);
  4229. }
  4230. // Insert a new paragraph. Either inside and split, or before or after.
  4231. if (!is_at_start && !is_at_end)
  4232. {
  4233. HTML_Element *result_start = NULL, *result_stop = NULL;
  4234. InsertTextHTML(tmp_str, tmp_str.Length(), &result_start, &result_stop, split_root);
  4235. // Make sure we set the InsertedAutomatically flag so the br element can be removed automatically too.
  4236. if (result_start && result_start->FirstChild() && result_start->FirstChild()->Type() == HE_BR)
  4237. SetInsertedAutomatically(result_start->FirstChild(), TRUE);
  4238. if (IsHeader(containing_elm))
  4239. {
  4240. // Backspace so the new p block of this line is removed and next line moved up untouched (we just want to split headers)
  4241. OpInputAction action(OpInputAction::ACTION_BACKSPACE);
  4242. EditAction(&action);
  4243. m_caret.Move(TRUE, FALSE);
  4244. }
  4245. else if (!is_at_end_before_child_container && !is_at_start_after_child_container)
  4246. {
  4247. // Delete so next block is moved up to this line
  4248. OpInputAction action(OpInputAction::ACTION_DELETE);
  4249. EditAction(&action);
  4250. }
  4251. }
  4252. else
  4253. {
  4254. m_caret.Set(current_p_elm, is_at_start ? 0 : 1);
  4255. HTML_Element *result_start = NULL, *result_stop = NULL;
  4256. InsertTextHTML(tmp_str, tmp_str.Length(), &result_start, &result_stop, split_root);
  4257. // Make sure we set the InsertedAutomatically flag so the br element can be removed automatically too.
  4258. if (result_start && result_start->FirstChild() && result_start->FirstChild()->Type() == HE_BR)
  4259. SetInsertedAutomatically(result_start->FirstChild(), TRUE);
  4260. if (is_at_start)
  4261. m_caret.Move(TRUE, FALSE);
  4262. else
  4263. m_caret.SetToValidPos();
  4264. }
  4265. }
  4266. #endif // DOCUMENT_EDIT_USE_PARAGRAPH_BREAK
  4267. else
  4268. {
  4269. // Make sure we set the InsertedAutomatically flag to FALSE if we already have a BR element so the br element isn't removed in the process.
  4270. if (m_caret.GetElement()->Type() == HE_BR)
  4271. SetInsertedAutomatically(m_caret.GetElement(), FALSE);
  4272. // If there is no ending BR and the caret is at the last element, we have to insert 2 BR. (One to end the
  4273. // current line and one to create a new line).
  4274. HTML_Element* containing_element = containing_elm;
  4275. BOOL add_ending_enter = FALSE;
  4276. if(m_caret.GetElement() == containing_element->LastLeaf() && m_caret.GetElement()->Type() != HE_BR)
  4277. {
  4278. int last_ofs = 0;
  4279. GetLastValidCaretOfs(m_caret.GetElement(),last_ofs);
  4280. if(m_caret.GetOffset() >= last_ofs)
  4281. add_ending_enter = TRUE;
  4282. }
  4283. HTML_Element *new_elm = NewElement(HE_BR);
  4284. if (!new_elm)
  4285. {
  4286. ReportOOM();
  4287. return;
  4288. }
  4289. DUMPDEBUGTREE
  4290. HTML_Element* sibling_element = NULL;
  4291. BOOL is_at_start = m_caret.IsAtStartOrEndOfBlock(TRUE);
  4292. BOOL is_at_end = m_caret.IsAtStartOrEndOfBlock(FALSE);
  4293. if(is_at_end && is_at_start)
  4294. add_ending_enter = FALSE;
  4295. if (is_at_end || is_at_start)
  4296. {
  4297. #ifndef DOCUMENT_EDIT_USE_PARAGRAPH_BREAK
  4298. // Let shift+break always insert <br> (even in headers) when we have paragraphbreak as default
  4299. if (IsHeader(containing_element))
  4300. sibling_element = containing_element;
  4301. else
  4302. #endif
  4303. sibling_element = m_caret.GetElement()->ParentActual();
  4304. while (sibling_element && sibling_element->Type() != HE_A)
  4305. sibling_element = sibling_element->ParentActual();
  4306. }
  4307. BOOL finished = FALSE;
  4308. if (sibling_element && m_undo_stack.IsValidAsChangeElm(sibling_element->ParentActual()))
  4309. {
  4310. // Create a new line after the header, instead of inside it.
  4311. HTML_Element* parent = sibling_element->ParentActual();
  4312. BeginChange(parent);
  4313. if (is_at_end)
  4314. new_elm->FollowSafe(m_doc, sibling_element);
  4315. else
  4316. new_elm->PrecedeSafe(m_doc, sibling_element);
  4317. if(!m_caret.IsElementEditable(new_elm))
  4318. {
  4319. new_elm->OutSafe(m_doc, FALSE);
  4320. AbortChange();
  4321. }
  4322. else
  4323. {
  4324. m_caret.Set(new_elm, 0);
  4325. if (is_at_end && IsFriendlyElement(sibling_element))
  4326. InsertBreak(break_list);
  4327. EndChange(parent);
  4328. finished = TRUE;
  4329. }
  4330. }
  4331. if(!finished)
  4332. {
  4333. HTML_Element* parent = m_caret.GetElement()->ParentActual();
  4334. BeginChange(parent);
  4335. InsertElement(new_elm);
  4336. if (add_ending_enter)
  4337. {
  4338. m_caret.Set(new_elm, 0);
  4339. InsertBreak(break_list);
  4340. }
  4341. EndChange(parent);
  4342. }
  4343. DUMPDEBUGTREE
  4344. m_caret.RestartBlink();
  4345. }
  4346. }
  4347. OP_STATUS OpDocumentEdit::ClonePendingStyles(Head &head)
  4348. {
  4349. OP_DOCUMENT_EDIT_PENDING_STYLES *pending_style = (OP_DOCUMENT_EDIT_PENDING_STYLES*) m_pending_styles.First();
  4350. while (pending_style)
  4351. {
  4352. OP_DOCUMENT_EDIT_PENDING_STYLES *clone_style = OP_NEW(OP_DOCUMENT_EDIT_PENDING_STYLES, ());
  4353. HTML_Element *clone_helm = NewElement(pending_style->helm->Type());
  4354. if (clone_style && clone_helm)
  4355. {
  4356. clone_style->helm = clone_helm;
  4357. clone_style->Into(&head);
  4358. }
  4359. else
  4360. {
  4361. OP_DELETE(clone_style);
  4362. OP_DELETE(clone_helm);
  4363. return OpStatus::ERR_NO_MEMORY;
  4364. }
  4365. pending_style = (OP_DOCUMENT_EDIT_PENDING_STYLES *) pending_style->Suc();
  4366. }
  4367. return OpStatus::OK;
  4368. }
  4369. void OpDocumentEdit::AddPendingStyles(Head &head)
  4370. {
  4371. OP_DOCUMENT_EDIT_PENDING_STYLES *pending_style;
  4372. while ((pending_style = (OP_DOCUMENT_EDIT_PENDING_STYLES*) head.First()) != 0)
  4373. {
  4374. pending_style->Out();
  4375. pending_style->Into(&m_pending_styles);
  4376. }
  4377. }
  4378. OP_STATUS OpDocumentEdit::InsertPendingStyles(HTML_Element** outmost_element)
  4379. {
  4380. if (m_pending_styles.First())
  4381. {
  4382. // New text element under the new styles in m_pending_styles
  4383. HTML_Element *new_text_content = NewTextElement(UNI_L(""), 0);
  4384. if(!new_text_content)
  4385. return OpStatus::ERR_NO_MEMORY;
  4386. // So the tidy operation knows we are adding content soon.
  4387. m_content_pending_helm = new_text_content;
  4388. // We have pending style elements. Insert them all under each other, with the caret at the bottom.
  4389. // Then proceed with the textinsertion.
  4390. m_caret.LockUpdatePos(TRUE);
  4391. OP_DOCUMENT_EDIT_PENDING_STYLES* pending_style;
  4392. Head temp_list;
  4393. while ((pending_style = (OP_DOCUMENT_EDIT_PENDING_STYLES*) m_pending_styles.First()) != 0)
  4394. {
  4395. // Move to a temporary list. m_pending_styles will be cleared in InsertElement.
  4396. pending_style->Out();
  4397. pending_style->Into(&temp_list);
  4398. }
  4399. HTML_Element *top_style = ((OP_DOCUMENT_EDIT_PENDING_STYLES*)(temp_list.First()))->helm;
  4400. HTML_Element *bottom_style = top_style;
  4401. if (outmost_element != NULL)
  4402. *outmost_element = top_style;
  4403. pending_style = (OP_DOCUMENT_EDIT_PENDING_STYLES*)temp_list.First();
  4404. pending_style->Out();
  4405. OP_DELETE(pending_style);
  4406. while ((pending_style = (OP_DOCUMENT_EDIT_PENDING_STYLES*) temp_list.First()) != 0)
  4407. {
  4408. pending_style->helm->UnderSafe(m_doc,bottom_style);
  4409. bottom_style = pending_style->helm;
  4410. pending_style->Out();
  4411. OP_DELETE(pending_style);
  4412. }
  4413. new_text_content->UnderSafe(m_doc,bottom_style);
  4414. InsertElement(top_style);
  4415. m_caret.Set(new_text_content, 0);
  4416. m_caret.LockUpdatePos(FALSE);
  4417. // We can now unset m_content_pending_helm since we will add the text now.
  4418. m_content_pending_helm = NULL;
  4419. }
  4420. else if (outmost_element != NULL)
  4421. *outmost_element = NULL;
  4422. return OpStatus::OK;
  4423. }
  4424. void OpDocumentEdit::InsertElement(HTML_Element* helm)
  4425. {
  4426. DEBUG_CHECKER(TRUE);
  4427. HTML_Element* parent = m_caret.m_parent_candidate;
  4428. if (!parent)
  4429. {
  4430. parent = m_caret.GetElement();
  4431. if (parent && IsStandaloneElement(parent))
  4432. parent = parent->ParentActual();
  4433. if (!parent)
  4434. return;
  4435. }
  4436. BeginChange(parent);
  4437. if (m_caret.m_parent_candidate)
  4438. {
  4439. if (IsStandaloneElement(m_caret.m_parent_candidate))
  4440. helm->FollowSafe(m_doc, m_caret.m_parent_candidate);
  4441. else
  4442. helm->UnderSafe(m_doc, m_caret.m_parent_candidate);
  4443. }
  4444. else
  4445. {
  4446. // If the caret is inside a textelement we have to split the textelement in 2.
  4447. SplitElement(m_caret.GetElement(), m_caret.GetOffset());
  4448. // Insert helm
  4449. if (IsStandaloneElement(m_caret.GetElement()))
  4450. {
  4451. if (m_caret.GetOffset() == 0)
  4452. helm->PrecedeSafe(m_doc, m_caret.GetElement());
  4453. else
  4454. helm->FollowSafe(m_doc, m_caret.GetElement());
  4455. }
  4456. else
  4457. {
  4458. int offset = m_caret.GetOffset();
  4459. HTML_Element* follower = parent->FirstChildActual();
  4460. while (offset > 0 && follower)
  4461. {
  4462. follower = follower->SucActual();
  4463. offset--;
  4464. }
  4465. if (follower)
  4466. helm->PrecedeSafe(m_doc, follower);
  4467. else
  4468. helm->UnderSafe(m_doc, parent);
  4469. }
  4470. }
  4471. ReflowAndUpdate();
  4472. //int old_caret_ofs = m_caret.GetOffset();
  4473. HTML_Element* old_caret_elm = m_caret.GetElement();
  4474. // Insertion of the new element happened after the caret so we'll need to move the caret.
  4475. // We can't do it with Move if the caret is currently at a <br> since Move() will
  4476. // sometimes move the caret too far in that case. Otherwise we'll use Move().
  4477. if (!(m_caret.GetOffset() == 0 && helm->Type() == HE_BR))
  4478. {
  4479. m_caret.Move(TRUE, FALSE);
  4480. // Make sure we didn't moved outside the parent (WHY?????????????)
  4481. //if (!parent->IsAncestorOf(m_caret.GetElement()) || m_caret.GetElement() == old_caret_elm && m_caret.GetOffset() == old_caret_ofs)
  4482. //{
  4483. // m_caret.Set(old_caret_elm, old_caret_ofs);
  4484. // m_caret.Move(FALSE,TRUE);
  4485. // if (!parent->IsAncestorOf(m_caret.GetElement()))
  4486. // m_caret.Set(old_caret_elm, old_caret_ofs);
  4487. //}
  4488. }
  4489. else if (helm->IsMatchingType(HE_BR, NS_HTML) && helm->NextActual())
  4490. {
  4491. // Instead of moving the caret, just put it where we want it. There is a risk that it will end up at an
  4492. // invisible position but this is less of a problem than that the caret doesn't move at all.
  4493. OldStyleTextSelectionPoint point(helm, 1);
  4494. m_selection.Select(&point, &point, TRUE); // Put the caret after the newly inserted break.
  4495. }
  4496. // If the old caretelement was a empty textelement, we can now delete it.
  4497. if (old_caret_elm != m_caret.GetElement() && old_caret_elm->Type() == HE_TEXT && old_caret_elm->GetTextContentLength() == 0)
  4498. DeleteElement(old_caret_elm);
  4499. EndChange(parent);
  4500. }
  4501. OP_STATUS OpDocumentEdit::InsertTextWithLinebreaks(const uni_char* text, INT32 len, BOOL allow_append)
  4502. {
  4503. DEBUG_CHECKER(TRUE);
  4504. OP_STATUS status = OpStatus::OK;
  4505. if(!m_caret.GetElement())
  4506. {
  4507. OP_ASSERT(FALSE);
  4508. return OpStatus::ERR;
  4509. }
  4510. OpDocumentEditUndoRedoAutoGroup autogroup(&m_undo_stack);
  4511. HTML_Element* parent = m_caret.GetElement()->ParentActual();
  4512. if (!(IsDummyElement(m_caret.GetElement()) || m_caret.GetElement()->GetTextContentLength() == 0))
  4513. // Cause the current textelement to be split up, so our new elements and linebreaks can follow.
  4514. status = InsertTextHTML(document_edit_dummy_str, 1, NULL, NULL, parent);
  4515. status = BeginChange(parent);
  4516. HTML_Element *follow_elm = m_caret.GetElement();
  4517. int ofs = 0;
  4518. while(TRUE)
  4519. {
  4520. int line_start = ofs;
  4521. while(ofs < len && text[ofs] != '\r' && text[ofs] != '\n')
  4522. ofs++;
  4523. BOOL first_line = (line_start == 0);
  4524. BOOL last_line = (ofs >= len);
  4525. int line_len = ofs - line_start;
  4526. if (ofs < len - 1 && text[ofs] == '\r' && text[ofs + 1] == '\n')
  4527. ofs++;
  4528. ofs++;
  4529. if (line_len > 0)
  4530. {
  4531. // Insert text element.
  4532. if (first_line && m_caret.GetElement() && m_caret.GetElement()->Type() == HE_TEXT)
  4533. {
  4534. SetElementText(m_caret.GetElement(), &text[line_start], line_len);
  4535. follow_elm = m_caret.GetElement();
  4536. }
  4537. else
  4538. {
  4539. HTML_Element *text_elm = NewTextElement(&text[line_start], line_len);
  4540. if (!text_elm)
  4541. break;
  4542. /* If the caret is to the left of a non-text element then the
  4543. * text we're inserting should precede said element. */
  4544. if (first_line && m_caret.GetOffset() == 0)
  4545. text_elm->PrecedeSafe(m_doc, follow_elm);
  4546. else
  4547. text_elm->FollowSafe(m_doc, follow_elm);
  4548. follow_elm = text_elm;
  4549. }
  4550. }
  4551. if (last_line)
  4552. break;
  4553. // Insert linebreak
  4554. HTML_Element *br_elm = NewElement(HE_BR);
  4555. if (!br_elm)
  4556. break;
  4557. br_elm->FollowSafe(m_doc, follow_elm);
  4558. follow_elm = br_elm;
  4559. }
  4560. if (follow_elm->IsMatchingType(HE_BR, NS_HTML))
  4561. {
  4562. OldStyleTextSelectionPoint point(follow_elm, 1);
  4563. m_selection.Select(&point, &point, TRUE); // Put the caret after the newly inserted break.
  4564. }
  4565. else
  4566. m_caret.Place(follow_elm, follow_elm->GetTextContentLength(), FALSE, FALSE);
  4567. m_caret.UpdateWantedX();
  4568. status = EndChange(parent);
  4569. return status;
  4570. }
  4571. BOOL OpDocumentEdit::IsBeforeCollapsedOrEdge(HTML_Element* helm)
  4572. {
  4573. DEBUG_CHECKER(TRUE);
  4574. HTML_Element *before = helm;
  4575. do
  4576. {
  4577. before = before->PrevActual();
  4578. if (!before || !IsFriends(helm, before, TRUE, TRUE) || IsCollapsed(before))
  4579. return TRUE;
  4580. } while(before->Type() != HE_TEXT || before->GetTextContentLength() == 0);
  4581. if(CharMightCollapse(before->TextContent()[before->GetTextContentLength()-1]))
  4582. return TRUE;
  4583. return FALSE;
  4584. }
  4585. BOOL OpDocumentEdit::IsAfterCollapsedOrEdge(HTML_Element* helm)
  4586. {
  4587. DEBUG_CHECKER(TRUE);
  4588. HTML_Element *after = helm;
  4589. do
  4590. {
  4591. after = after->NextActual();
  4592. if (!after || !IsFriends(helm, after, TRUE, TRUE) || IsCollapsed(after))
  4593. return TRUE;
  4594. } while(after->Type() != HE_TEXT || after->GetTextContentLength() == 0);
  4595. if(CharMightCollapse(after->TextContent()[0]))
  4596. return TRUE;
  4597. return FALSE;
  4598. }
  4599. BOOL OpDocumentEdit::RemoveNBSPIfPossible(HTML_Element* helm)
  4600. {
  4601. DEBUG_CHECKER(TRUE);
  4602. if(!helm || helm->Type() != HE_TEXT || !helm->GetTextContentLength())
  4603. return FALSE;
  4604. OpString str;
  4605. if(OpStatus::IsError(str.Set(helm->TextContent())))
  4606. {
  4607. ReportOOM();
  4608. return FALSE;
  4609. }
  4610. int i;
  4611. int len = helm->GetTextContentLength();
  4612. BOOL changed = FALSE;
  4613. if (len > 0 && !IsInPreFormatted(helm))
  4614. {
  4615. // We might need a nbsp at the beginning or end
  4616. if (uni_collapsing_sp(str.CStr()[0]))
  4617. {
  4618. str.CStr()[0] = 0xA0;
  4619. changed = TRUE;
  4620. }
  4621. if (uni_collapsing_sp(str.CStr()[len - 1]))
  4622. {
  4623. str.CStr()[len - 1] = 0xA0;
  4624. changed = TRUE;
  4625. }
  4626. }
  4627. for(i=0;i<len;i++)
  4628. {
  4629. if(str.CStr()[i] != 0xA0)
  4630. continue;
  4631. if((!i && IsBeforeCollapsedOrEdge(helm)) || (i == len-1 && IsAfterCollapsedOrEdge(helm)))
  4632. continue;
  4633. if((!i || !uni_collapsing_sp(str.CStr()[i-1])) && !(i < len-1 && uni_collapsing_sp(str.CStr()[i+1])))
  4634. {
  4635. str.CStr()[i] = ' ';
  4636. changed = TRUE;
  4637. }
  4638. }
  4639. if(changed)
  4640. SetElementText(helm,str.CStr());
  4641. return changed;
  4642. }
  4643. /*void UnCollapseLastCollapsing(uni_char *buf)
  4644. {
  4645. while(uni_collapsing_sp(buf[1])) buf++;
  4646. *buf = 0xA0;
  4647. }*/
  4648. BOOL OpDocumentEdit::IsInPreFormatted(HTML_Element *helm)
  4649. {
  4650. DEBUG_CHECKER(TRUE);
  4651. if(!helm)
  4652. return FALSE;
  4653. Head prop_list;
  4654. HLDocProfile *hld_profile = m_doc->GetHLDocProfile();
  4655. LayoutProperties* lprops = LayoutProperties::CreateCascade(helm, prop_list, hld_profile);
  4656. BOOL in_pre = lprops && (lprops->GetProps()->white_space == CSS_VALUE_pre || lprops->GetProps()->white_space == CSS_VALUE_pre_wrap);
  4657. prop_list.Clear();
  4658. return in_pre;
  4659. }
  4660. OP_STATUS OpDocumentEdit::InsertText(const uni_char *text, INT32 len, BOOL allow_append, BOOL delete_selection)
  4661. {
  4662. DEBUG_CHECKER(TRUE);
  4663. if(len <= 0)
  4664. return OpStatus::OK;
  4665. OP_STATUS status;
  4666. if(!m_caret.GetElement())
  4667. {
  4668. LockPendingStyles(TRUE);
  4669. m_caret.Init(TRUE);
  4670. LockPendingStyles(FALSE);
  4671. if(!m_caret.GetElement())
  4672. {
  4673. OP_ASSERT(FALSE);
  4674. return OpStatus::ERR;
  4675. }
  4676. }
  4677. OpDocumentEditWsPreserver preserver(this);
  4678. OpDocumentEditWsPreserverContainer preserver_container(&preserver, this);
  4679. OpDocumentEditUndoRedoAutoGroup autogroup(&m_undo_stack);
  4680. m_caret.LockUpdatePos(TRUE);
  4681. BOOL had_selection = m_selection.HasContent();
  4682. #ifdef INTERNAL_SPELLCHECK_SUPPORT
  4683. SpellWordInfoObject old_spell_word_info;
  4684. if(m_spell_session && !had_selection)
  4685. old_spell_word_info.Set(m_caret.GetElement());
  4686. #endif
  4687. if (delete_selection)
  4688. DeleteSelectedContent();
  4689. if (ContainsLinebreak(text, len))
  4690. {
  4691. status = InsertTextWithLinebreaks(text, len, allow_append);
  4692. m_caret.LockUpdatePos(FALSE);
  4693. return status;
  4694. }
  4695. if (m_caret.GetElement() && m_caret.GetElement()->Type() == HE_TEXT && m_caret.GetElement()->ParentActual() && m_caret.GetElement()->ParentActual()->Type() == HE_A)
  4696. {
  4697. // If we stand at the end of a link, we should insert the text after the link instead of inside it.
  4698. // Otherwise it would be very hard for the user to continue writing after making a link.
  4699. int last_valid_ofs = 0;
  4700. if (GetLastValidCaretOfs(m_caret.GetElement(), last_valid_ofs) && m_caret.GetOffset() == last_valid_ofs)
  4701. {
  4702. // Check if we have text following the link. If we do, we do nothing.
  4703. HTML_Element *containing_element = m_doc->GetCaret()->GetContainingElement(m_caret.GetElement());
  4704. HTML_Element *next_helm = NULL;
  4705. int next_ofs = 0;
  4706. BOOL last = GetBestCaretPosFrom(m_caret.GetElement(), next_helm, next_ofs);
  4707. if (!last || !containing_element->IsAncestorOf(next_helm) || next_helm->Type() == HE_BR ||
  4708. // If the best pos precedes the caret, the following position wasn't as good so that must also mean we're at 'the end' of something.
  4709. next_helm->Precedes(m_caret.GetElement()))
  4710. {
  4711. HTML_Element *candidate = m_caret.GetElement();
  4712. HTML_Element *containing_element = m_doc->GetCaret()->GetContainingElement(m_caret.GetElement());
  4713. while (candidate && candidate->ParentActual() != containing_element && candidate->ParentActual() && candidate->ParentActual()->LastChild() == candidate)
  4714. candidate = candidate->ParentActual();
  4715. if (candidate && candidate != m_caret.GetElement())
  4716. m_caret.Set(candidate, 1);
  4717. }
  4718. }
  4719. }
  4720. int flags = (allow_append) ? CHANGE_FLAGS_ALLOW_APPEND : CHANGE_FLAGS_NONE;
  4721. status = InsertPendingStyles();
  4722. if (OpStatus::IsError(status))
  4723. {
  4724. m_caret.LockUpdatePos(FALSE);
  4725. return status;
  4726. }
  4727. if (m_caret.m_parent_candidate)
  4728. {
  4729. // We have a parent candidate so try to reinitialize the caret there.
  4730. // This might happen if something tried to place the caret in a empty element (via DOM).
  4731. // Init call will create a textelement if needed.
  4732. m_caret.Init(TRUE, m_caret.m_parent_candidate);
  4733. }
  4734. if (!m_caret.GetElement())
  4735. return OpStatus::ERR;
  4736. if (m_caret.GetElement()->Type() != HE_TEXT)
  4737. {
  4738. // We are trying to insert text in something else than a textelement. Create a empty textelement first.
  4739. HTML_Element* root = m_caret.GetElement()->ParentActual();
  4740. if (!root) // Trying to insert something in the very root.
  4741. return OpStatus::ERR;
  4742. BeginChange(root, flags);
  4743. HTML_Element* new_elm = NewTextElement(document_edit_dummy_str, 1);
  4744. if (!new_elm)
  4745. {
  4746. AbortChange();
  4747. m_caret.LockUpdatePos(FALSE);
  4748. return OpStatus::ERR_NO_MEMORY;
  4749. }
  4750. // So the tidy operation knows we are adding content soon.
  4751. m_content_pending_helm = new_elm;
  4752. if (m_caret.IsElementEditable(root))
  4753. {
  4754. if (m_caret.GetOffset() == 1)
  4755. new_elm->FollowSafe(m_doc, m_caret.GetElement());
  4756. else
  4757. new_elm->PrecedeSafe(m_doc, m_caret.GetElement());
  4758. }
  4759. else
  4760. new_elm->UnderSafe(m_doc, m_caret.GetElement());
  4761. new_elm->MarkExtraDirty(m_doc);
  4762. m_caret.Set(new_elm, 0);
  4763. EndChange(root);
  4764. }
  4765. else
  4766. {
  4767. // Since the text insertion is not a deep change, it won't tidy away automatic BR.
  4768. // If we have one, and need to tidy it away, we will do a deep change here to remove it.
  4769. HTML_Element *containing_element = m_doc->GetCaret()->GetContainingElementActual(m_caret.GetElement());
  4770. if (containing_element && HasAutoInsertedBR(containing_element) && !NeedAutoInsertedBR(containing_element))
  4771. {
  4772. // So the tidy operation knows we are adding content soon.
  4773. m_content_pending_helm = m_caret.GetElement();
  4774. BeginChange(containing_element, flags);
  4775. EndChange(containing_element);
  4776. }
  4777. }
  4778. HTML_Element* root = m_caret.GetElement();
  4779. status = BeginChange(root, flags);
  4780. // We can now unset m_content_pending_helm since we will add the text now.
  4781. m_content_pending_helm = NULL;
  4782. if (IsDummyElement(m_caret.GetElement()))
  4783. {
  4784. // This was a dummyelement. Delete the content before adding the real content.
  4785. SetElementText(m_caret.GetElement(), UNI_L(""));
  4786. }
  4787. // Take out the text from the element, add the text we should insert and set it back to the element.
  4788. HTML_Element *he = m_caret.GetElement();
  4789. int pos;
  4790. OpString str;
  4791. if (OpStatus::IsError(str.Set(he->TextContent())))
  4792. goto error;
  4793. pos = MIN(str.Length(), m_caret.GetOffset());
  4794. if(!had_selection)
  4795. preserver.SetRemoveRange(he,he,pos,pos);
  4796. status = str.Insert(pos, text, len);
  4797. if (OpStatus::IsError(status))
  4798. goto error;
  4799. if(!IsInPreFormatted(he))
  4800. {
  4801. // If we are not in pre-formatted layout, we should convert tabs and starting and ending whitespace into nonbreaking space.
  4802. for(int i = 0; i < len; i++)
  4803. {
  4804. if (str.CStr()[pos + i] == '\t')
  4805. {
  4806. str.CStr()[pos + i] = 0xA0;
  4807. str.Insert(pos + i, "\xA0\xA0\xA0", 3);
  4808. len += 3;
  4809. i += 3;
  4810. }
  4811. }
  4812. if(uni_collapsing_sp(str.CStr()[pos]) || uni_collapsing_sp(str.CStr()[pos+len-1]))
  4813. {
  4814. if(uni_collapsing_sp(str.CStr()[pos]))
  4815. str.CStr()[pos] = 0xA0;
  4816. if(uni_collapsing_sp(str.CStr()[pos+len-1]))
  4817. str.CStr()[pos+len-1] = 0xA0;
  4818. }
  4819. }
  4820. SetElementText(he, str);
  4821. if(!had_selection)
  4822. preserver.WsPreserve();
  4823. RemoveNBSPIfPossible(he);
  4824. // Update
  4825. m_caret.LockUpdatePos(FALSE);
  4826. m_caret.Place(m_caret.GetElement(), m_caret.GetOffset() + len, FALSE, TRUE);
  4827. m_caret.UpdateWantedX();
  4828. #ifdef INTERNAL_SPELLCHECK_SUPPORT
  4829. DoSpellWordInfoUpdate(&old_spell_word_info);
  4830. #endif // INTERNAL_SPELLCHECK_SUPPORT
  4831. return EndChange(root);
  4832. error:
  4833. AbortChange();
  4834. m_caret.LockUpdatePos(FALSE);
  4835. return OpStatus::ERR_NO_MEMORY;
  4836. }
  4837. OP_STATUS OpDocumentEdit::InsertPlainText(const uni_char *text, INT32 len)
  4838. {
  4839. DEBUG_CHECKER(TRUE);
  4840. DeleteSelectedContent();
  4841. if(len <= 0)
  4842. return OpStatus::OK;
  4843. if(!m_caret.GetElement())
  4844. {
  4845. // Code is unfortunately dependant on m_caret.m_helm. Will be fixed in the next redesign/rewrite.
  4846. return OpStatus::ERR;
  4847. }
  4848. m_caret.LockUpdatePos(TRUE);
  4849. OpDocumentEditUndoRedoAutoGroup autogroup(&m_undo_stack);
  4850. if (m_caret.m_parent_candidate && m_caret.IsElementEditable(m_caret.m_parent_candidate))
  4851. {
  4852. // We have a parent candidate so try to reinitialize the caret there.
  4853. // This might happen if something tried to place the caret in a empty element (via DOM).
  4854. // Init call will create a textelement if needed.
  4855. m_caret.Init(TRUE, m_caret.m_parent_candidate);
  4856. }
  4857. OP_STATUS status;
  4858. if (m_caret.GetElement()->Type() != HE_TEXT)
  4859. {
  4860. // We are trying to insert text in something else than a textelement. Create a empty textelement first.
  4861. HTML_Element* root = m_caret.GetElement()->ParentActual();
  4862. status = BeginChange(root);
  4863. HTML_Element* new_elm = NewTextElement(document_edit_dummy_str, 1);
  4864. if (!new_elm)
  4865. {
  4866. AbortChange();
  4867. m_caret.LockUpdatePos(FALSE);
  4868. return OpStatus::ERR_NO_MEMORY;
  4869. }
  4870. if (m_caret.IsElementEditable(root))
  4871. {
  4872. if (m_caret.GetOffset() == 1)
  4873. new_elm->FollowSafe(m_doc, m_caret.GetElement());
  4874. else
  4875. new_elm->PrecedeSafe(m_doc, m_caret.GetElement());
  4876. }
  4877. else
  4878. new_elm->UnderSafe(m_doc, m_caret.GetElement());
  4879. new_elm->MarkExtraDirty(m_doc);
  4880. m_caret.Set(new_elm, 0);
  4881. status = EndChange(root);
  4882. }
  4883. HTML_Element* root = m_caret.GetElement();
  4884. status = BeginChange(root);
  4885. if (IsDummyElement(m_caret.GetElement()))
  4886. {
  4887. // This was a dummyelement. Delete the content before adding the real content.
  4888. SetElementText(m_caret.GetElement(), UNI_L(""));
  4889. }
  4890. // Take out the text from the element, add the text we should insert and set it back to the element.
  4891. HTML_Element *he = m_caret.GetElement();
  4892. int pos;
  4893. OpString str;
  4894. if (OpStatus::IsError(str.Set(he->TextContent())))
  4895. goto error;
  4896. pos = MIN(str.Length(), m_caret.GetOffset());
  4897. status = str.Insert(pos, text, len);
  4898. if (OpStatus::IsError(status))
  4899. goto error;
  4900. SetElementText(he, str);
  4901. m_caret.LockUpdatePos(FALSE);
  4902. m_caret.Place(m_caret.GetElement(), m_caret.GetOffset() + len, TRUE, FALSE);
  4903. m_caret.UpdateWantedX();
  4904. return EndChange(root);
  4905. error:
  4906. AbortChange();
  4907. m_caret.LockUpdatePos(FALSE);
  4908. return OpStatus::ERR_NO_MEMORY;
  4909. }
  4910. OP_STATUS OpDocumentEdit::InsertTextHTML(const uni_char* text, INT32 len, HTML_Element** result_start, HTML_Element** result_stop, HTML_Element* split_root, TIDY_LEVEL tidy_level, BOOL delete_selection)
  4911. {
  4912. DEBUG_CHECKER(TRUE);
  4913. OpDocumentEditUndoRedoAutoGroup autogroup(&m_undo_stack);
  4914. if (delete_selection)
  4915. DeleteSelectedContent();
  4916. if (!text || !len)
  4917. return OpStatus::OK;
  4918. if(!m_caret.GetElement())
  4919. {
  4920. // Code is unfortunately dependant on m_caret.m_helm. Will be fixed in the next redesign/rewrite.
  4921. return OpStatus::ERR;
  4922. }
  4923. // Must copy text so we are sure it's not a const string. (SetInnerHTML can do nasty things with the data).
  4924. OpString temp_text;
  4925. RETURN_IF_ERROR(temp_text.Set(text, len));
  4926. if (!temp_text.Length())
  4927. return OpStatus::OK;
  4928. // Create temp root for the parsed text. then add all content after the splitted caretelement.
  4929. HTML_Element* tmproot = NewElement(HE_DOC_ROOT);
  4930. if (!tmproot)
  4931. return OpStatus::ERR_NO_MEMORY;
  4932. // We'll use the parent of the caret as context
  4933. OP_STATUS status = tmproot->SetInnerHTML(m_doc, temp_text, temp_text.Length(), m_caret.GetElement()->ParentActual());
  4934. if (OpStatus::IsError(status))
  4935. {
  4936. DeleteElement(tmproot);
  4937. return status;
  4938. }
  4939. #ifdef DEBUG_DOCUMENT_EDIT
  4940. DUMPDEBUGTREE_ELM(tmproot);
  4941. #endif // DEBUG_DOCUMENT_EDIT
  4942. Tidy(tmproot, tmproot, FALSE, tidy_level, TRUE);
  4943. // If there was a body, use the body as root.
  4944. HTML_Element* resultroot = FindElementAfterOfType(tmproot, HE_BODY);
  4945. if (!resultroot)
  4946. resultroot = tmproot;
  4947. // Find out where we are going to place the caret when it's done. (The last editable element)
  4948. HTML_Element* last_text_helm;
  4949. for(last_text_helm = resultroot->LastLeafActual();
  4950. last_text_helm && !IsElementValidForCaret(last_text_helm, FALSE, TRUE);
  4951. last_text_helm = last_text_helm->PrevActual()) {}
  4952. if (m_caret.m_parent_candidate)
  4953. {
  4954. // We have a parent candidate so try to reinitialize the caret there.
  4955. // This might happen if something tried to place the caret in a empty element (via DOM).
  4956. // Init call will create a textelement if needed.
  4957. m_caret.Init(TRUE, m_caret.m_parent_candidate);
  4958. }
  4959. // FIX: See if it only contains friendly elements. In that case we always want to use containing element as root
  4960. // even if split_root is something else.
  4961. HLDocProfile *hld_profile = m_doc->GetHLDocProfile();
  4962. HTML_Element* current_root_helm = split_root ? split_root : m_doc->GetCaret()->GetContainingElementActual(m_caret.GetElement());
  4963. /* BOOL friendly = TRUE;
  4964. HTML_Element* tmp = resultroot->FirstChild();
  4965. while(tmp && resultroot->IsAnchestorOf(tmp))
  4966. {
  4967. if (tmp->IsContainingElement())
  4968. {
  4969. friendly = FALSE;
  4970. break;
  4971. }
  4972. tmp = tmp->Next();
  4973. }
  4974. if (friendly)
  4975. current_root_helm = GetContainingElementActual(m_caret.GetElement());*/
  4976. // Insert it
  4977. status = BeginChange(current_root_helm); // FIXME: OOM
  4978. OP_ASSERT(m_caret.GetElement() || !"If it happens, you probably have a bug. Modifications to the tree of elements above should not change the caret");
  4979. if (m_caret.GetElement()) ///< Check should not be needed but better safe than sorry
  4980. SplitElement(m_caret.GetElement(), m_caret.GetOffset());
  4981. HTML_Element* current_top_elm = m_caret.GetElement();
  4982. while(current_top_elm && current_top_elm->ParentActual() != current_root_helm)
  4983. current_top_elm = current_top_elm->ParentActual();
  4984. OP_ASSERT(current_top_elm);
  4985. if (!current_top_elm)
  4986. {
  4987. DeleteElement(tmproot);
  4988. EndChange(current_root_helm);
  4989. return OpStatus::ERR;
  4990. }
  4991. if (result_start)
  4992. *result_start = resultroot->FirstChild();
  4993. if (result_stop)
  4994. *result_stop = resultroot->LastChild();
  4995. DUMPDEBUGTREE
  4996. // Add all parseresult after current_top_elm (or before if caret is at toplevel at position 0).
  4997. HTML_Element* tmp = resultroot->FirstChild();
  4998. if (!tmp)
  4999. {
  5000. DeleteElement(tmproot);
  5001. return EndChange(current_root_helm, tidy_level);
  5002. }
  5003. tmp->OutSafe(static_cast<FramesDocument*>(NULL), FALSE);
  5004. if (current_top_elm == m_caret.GetElement() && m_caret.GetOffset() == 0)
  5005. tmp->PrecedeSafe(m_doc, current_top_elm);
  5006. else if (current_top_elm->Type() == HE_TEXT || current_top_elm->Type() == HE_BR)
  5007. tmp->FollowSafe(m_doc, current_top_elm);
  5008. else
  5009. {
  5010. // tmp->UnderSafe(current_top_elm);
  5011. tmp->FollowSafe(m_doc, current_top_elm);
  5012. }
  5013. tmp->MarkExtraDirty(m_doc);
  5014. // HTML_Element* first_inserted_elm = tmp;
  5015. HTML_Element* following_elm = tmp;
  5016. while(resultroot->FirstChild())
  5017. {
  5018. tmp = resultroot->FirstChild();
  5019. tmp->OutSafe(static_cast<FramesDocument*>(NULL), FALSE);
  5020. tmp->FollowSafe(m_doc, following_elm);
  5021. tmp->MarkExtraDirty(m_doc);
  5022. following_elm = tmp;
  5023. }
  5024. DUMPDEBUGTREE
  5025. if (m_caret.GetElement() && current_top_elm != m_caret.GetElement())
  5026. {
  5027. // We splitted a styled textelement.
  5028. // Make a copy of the treebranch that contains the splitted text. Remove the last part in the original and the
  5029. // first part of the copy. Then add the copy after the inserted text.
  5030. HTML_Element* copytree = NewCopyOfElement(current_top_elm);
  5031. if (!copytree || OpStatus::IsError(copytree->DeepClone(hld_profile, current_top_elm)))
  5032. {
  5033. AbortChange();
  5034. DeleteElement(tmproot);
  5035. DeleteElement(copytree);
  5036. return OpStatus::ERR_NO_MEMORY;
  5037. }
  5038. HTML_Element* first_elm_after_split = ((m_caret.GetOffset() == 0 && m_caret.GetElement()->IsIncludedActual()) ? m_caret.GetElement() : m_caret.GetElement()->NextSiblingActual());
  5039. HTML_Element* first_elm_after_split_in_copy = NULL;
  5040. // Find the first_elm_after_split_in_copy
  5041. tmp = current_top_elm;
  5042. first_elm_after_split_in_copy = copytree;
  5043. // while(tmp != first_elm_after_split && current_top_elm->IsAncestorOf(tmp))
  5044. while(tmp != first_elm_after_split && first_elm_after_split_in_copy)
  5045. {
  5046. tmp = (HTML_Element*) tmp->NextActual();
  5047. first_elm_after_split_in_copy = (HTML_Element*) first_elm_after_split_in_copy->NextActual();
  5048. }
  5049. // Remove everything after caretpos in the original tree.
  5050. tmp = first_elm_after_split;
  5051. HTML_Element *prev_first_elm_after_split = first_elm_after_split->PrevSiblingActual();
  5052. while(tmp && current_top_elm->IsAncestorOf(tmp))//tmp->ParentActual() != current_root_helm)
  5053. {
  5054. HTML_Element* next_elm = (HTML_Element*) tmp->NextActual();
  5055. if (!tmp->IsAncestorOf(prev_first_elm_after_split))
  5056. {
  5057. next_elm = tmp->NextSiblingActual();
  5058. DeleteElement(tmp);
  5059. if(next_elm == current_root_helm || !current_root_helm->IsAncestorOf(next_elm))
  5060. break;
  5061. }
  5062. tmp = next_elm;
  5063. }
  5064. tmp = copytree->FirstChild();
  5065. while(tmp && tmp != first_elm_after_split_in_copy)
  5066. {
  5067. HTML_Element* next_elm = (HTML_Element*) tmp->NextActual();
  5068. if (!tmp->IsAncestorOf(first_elm_after_split_in_copy))
  5069. {
  5070. next_elm = tmp->NextSiblingActual();
  5071. DeleteElement(tmp);
  5072. }
  5073. tmp = next_elm;
  5074. }
  5075. /*#ifdef DEBUG_DOCUMENT_EDIT
  5076. copytree->DumpDebugTree();
  5077. #endif*/
  5078. // Insert copytree after the new inserted text.
  5079. if(copytree->FirstChild())
  5080. {
  5081. copytree->FollowSafe(m_doc, following_elm);
  5082. copytree->MarkExtraDirty(m_doc);
  5083. }
  5084. else
  5085. DeleteElement(copytree);
  5086. }
  5087. current_root_helm->MarkDirty(m_doc, FALSE, TRUE);
  5088. // Find out where to put the caret.
  5089. /*HTML_Element* last_inserted_helm = following_elm->LastLeaf();
  5090. HTML_Element* last_text_helm = FindEditableElement(first_inserted_elm, TRUE, TRUE, FALSE);
  5091. while(last_text_helm && last_text_helm->Precedes(last_inserted_helm))
  5092. {
  5093. HTML_Element* next = FindEditableElement(last_text_helm, TRUE, FALSE, FALSE);
  5094. if (next && !last_inserted_helm->Precedes(next))
  5095. last_text_helm = next;
  5096. else
  5097. break;
  5098. }
  5099. if (last_inserted_helm->Precedes(last_text_helm))
  5100. last_text_helm = NULL;
  5101. if (last_text_helm)
  5102. m_caret.Place(last_text_helm, last_text_helm->GetTextContentLength());
  5103. else if (following_elm->SucActual())
  5104. {
  5105. last_text_helm = following_elm->SucActual();
  5106. m_caret.Place(last_text_helm, 0);
  5107. }
  5108. else
  5109. {
  5110. last_text_helm = following_elm->LastLeaf();
  5111. m_caret.Place(last_text_helm, last_text_helm->GetTextContentLength());
  5112. }*/
  5113. // Place the caret
  5114. if (last_text_helm)
  5115. {
  5116. int text_helm_ofs = 0;
  5117. if (IsEndingBr(last_text_helm) && last_text_helm->NextActual())
  5118. {
  5119. // Don't place the caret on a ending br (it isn't layouted anyway)
  5120. // Try put it after it.
  5121. HTML_Element *next_actual = last_text_helm->NextActual();
  5122. if (next_actual->Type() == HE_TEXT || next_actual->Type() == HE_BR)
  5123. last_text_helm = next_actual;
  5124. GetFirstValidCaretOfs(last_text_helm, text_helm_ofs);
  5125. }
  5126. else
  5127. GetLastValidCaretOfs(last_text_helm, text_helm_ofs);
  5128. m_caret.Place(last_text_helm, text_helm_ofs);
  5129. }
  5130. else if (!m_caret.GetElement())
  5131. {
  5132. // The caret element was removed above. Create a dummyelement so the undostack won't freak out.
  5133. HTML_Element *text_elm = NewTextElement(document_edit_dummy_str, 1);
  5134. text_elm->FollowSafe(m_doc, current_top_elm);
  5135. text_elm->MarkExtraDirty(m_doc);
  5136. m_caret.Place(text_elm, 0);
  5137. }
  5138. DeleteElement(tmproot);
  5139. return EndChange(current_root_helm, tidy_level);
  5140. }
  5141. void OpDocumentEdit::DeleteSelectedContent(BOOL aggressive)
  5142. {
  5143. DEBUG_CHECKER(TRUE);
  5144. if (m_layout_modifier.IsActive())
  5145. {
  5146. m_layout_modifier.Delete();
  5147. }
  5148. if (m_selection.HasContent())
  5149. {
  5150. m_selection.RemoveContent(aggressive);
  5151. m_selection.SelectNothing();
  5152. }
  5153. }
  5154. void OpDocumentEdit::Begin()
  5155. {
  5156. DEBUG_CHECKER(TRUE);
  5157. m_caret.LockUpdatePos(TRUE);
  5158. m_begin_count++;
  5159. }
  5160. void OpDocumentEdit::End()
  5161. {
  5162. DEBUG_CHECKER(TRUE);
  5163. m_begin_count--;
  5164. m_caret.LockUpdatePos(FALSE);
  5165. #ifdef INTERNAL_SPELLCHECK_SUPPORT
  5166. if(!m_begin_count)
  5167. RunPendingSpellCheck();
  5168. #endif // INTERNAL_SPELLCHECK_SUPPORT
  5169. }
  5170. void OpDocumentEdit::Abort()
  5171. {
  5172. DEBUG_CHECKER(TRUE);
  5173. m_begin_count--;
  5174. m_caret.LockUpdatePos(FALSE);
  5175. #ifdef INTERNAL_SPELLCHECK_SUPPORT
  5176. if(!m_begin_count)
  5177. RunPendingSpellCheck();
  5178. #endif // INTERNAL_SPELLCHECK_SUPPORT
  5179. }
  5180. OP_STATUS OpDocumentEdit::BeginChange(HTML_Element* containing_elm, int flags)
  5181. {
  5182. DEBUG_CHECKER(FALSE);
  5183. Begin();
  5184. return m_undo_stack.BeginChange(containing_elm, flags);
  5185. }
  5186. OP_STATUS OpDocumentEdit::EndChange(HTML_Element* containing_elm, TIDY_LEVEL tidy_level)
  5187. {
  5188. DEBUG_CHECKER(FALSE);
  5189. return EndChange(containing_elm,containing_elm,containing_elm,FALSE,tidy_level);
  5190. }
  5191. OP_STATUS OpDocumentEdit::EndChange(HTML_Element* containing_elm, HTML_Element *start_elm, HTML_Element *stop_elm, BOOL include_start_stop, TIDY_LEVEL tidy_level)
  5192. {
  5193. DEBUG_CHECKER(FALSE);
  5194. Tidy(start_elm, stop_elm, include_start_stop, tidy_level, FALSE, containing_elm);
  5195. ReflowAndUpdate();
  5196. OP_STATUS ret = m_undo_stack.EndChange(containing_elm);
  5197. End();
  5198. // Something changed, so we will have to call the direction autodetection code now, if we are the last EndChange.
  5199. if (m_begin_count == 0)
  5200. AutodetectDirection();
  5201. DUMPDEBUGTREE
  5202. return ret;
  5203. }
  5204. void OpDocumentEdit::AbortChange()
  5205. {
  5206. DEBUG_CHECKER(FALSE);
  5207. m_undo_stack.AbortChange();
  5208. Abort();
  5209. }
  5210. void OpDocumentEdit::ReflowAndUpdate()
  5211. {
  5212. DEBUG_CHECKER(TRUE);
  5213. if (!GetRoot() || GetRoot()->IsDirty())
  5214. if (!m_doc->IsReflowing() && !m_doc->IsUndisplaying())
  5215. m_doc->Reflow(FALSE, TRUE);
  5216. }
  5217. void OpDocumentEdit::OnScaleChanged()
  5218. {
  5219. DEBUG_CHECKER(TRUE);
  5220. m_caret.UpdatePos();
  5221. m_caret.UpdateWantedX();
  5222. ScrollIfNeeded();
  5223. }
  5224. void OpDocumentEdit::OnLayoutMoved()
  5225. {
  5226. DEBUG_CHECKER(TRUE);
  5227. m_caret.UpdatePos();
  5228. if (m_layout_modifier.IsActive())
  5229. m_layout_modifier.UpdateRect();
  5230. }
  5231. void OpDocumentEdit::ReportOOM()
  5232. {
  5233. DEBUG_CHECKER(TRUE);
  5234. g_memory_manager->RaiseCondition(OpStatus::ERR_NO_MEMORY);
  5235. }
  5236. void OpDocumentEdit::ReportIfOOM(OP_STATUS status)
  5237. {
  5238. DEBUG_CHECKER(TRUE);
  5239. if (OpStatus::IsMemoryError(status))
  5240. ReportOOM();
  5241. }
  5242. void OpDocumentEdit::ScrollIfNeeded()
  5243. {
  5244. DEBUG_CHECKER(TRUE);
  5245. if (!m_caret.IsValid()) // Avoid scrolling if the caret isn't valid (not visible, probably no layoutbox)
  5246. return;
  5247. ReflowAndUpdate();
  5248. OpRect rect = m_caret.GetCaretRectInDocument();
  5249. HTML_Element* ec = GetEditableContainer(m_caret.GetElement());
  5250. if(m_doc->GetHtmlDocument())
  5251. // We might need to scroll a scrollable container and update caretpos again.
  5252. m_doc->ScrollToRect(rect, SCROLL_ALIGN_NEAREST, FALSE, VIEWPORT_CHANGE_REASON_DOCUMENTEDIT, ec ? m_caret.GetElement() : NULL);
  5253. }
  5254. void OpDocumentEdit::OnReflow()
  5255. {
  5256. DEBUG_CHECKER(TRUE);
  5257. TextSelection* sel = m_doc->GetTextSelection();
  5258. // Initialize the caret only when there's no selection or a selection is not being updated.
  5259. // If there's a selection we may be reflowing to find elements for its end points (because the caret == a selection).
  5260. if(!m_caret.GetElement() && (!sel || !sel->IsBeingUpdated()))
  5261. m_caret.Init(FALSE);
  5262. if (m_layout_modifier.IsActive())
  5263. m_layout_modifier.UpdateRect();
  5264. }
  5265. void OpDocumentEdit::OnFocus(BOOL focus,FOCUS_REASON reason)
  5266. {
  5267. DEBUG_CHECKER(TRUE);
  5268. if (focus && !m_caret.GetElement())
  5269. m_caret.Init(TRUE, NULL, TRUE);
  5270. #ifdef INTERNAL_SPELLCHECK_SUPPORT
  5271. m_enable_spellcheck_later = focus && !m_spell_session && !m_by_user;
  5272. #endif // INTERNAL_SPELLCHECK_SUPPORT
  5273. if (focus)
  5274. {
  5275. #ifdef INTERNAL_SPELLCHECK_SUPPORT
  5276. if(m_enable_spellcheck_later && g_internal_spellcheck->SpellcheckEnabledByDefault())
  5277. {
  5278. OpString pref_lang;
  5279. BOOL has_pl = GetPreferredLanguage(pref_lang);
  5280. EnableSpellcheckInternal(FALSE /*by_user*/, has_pl ? pref_lang.CStr() : NULL);
  5281. m_enable_spellcheck_later = false;
  5282. }
  5283. #endif // INTERNAL_SPELLCHECK_SUPPORT
  5284. if (m_doc->GetHtmlDocument())
  5285. {
  5286. HTML_Element* ec = GetEditableContainer(m_caret.GetElement());
  5287. if (ec)
  5288. m_doc->GetHtmlDocument()->SetFocusedElement(ec, FALSE);
  5289. }
  5290. m_caret.RestartBlink();
  5291. }
  5292. else
  5293. {
  5294. m_caret.StopBlink();
  5295. #ifdef INTERNAL_SPELLCHECK_SUPPORT
  5296. if(m_delay_misspell_word_info)
  5297. {
  5298. m_delay_misspell_word_info = NULL;
  5299. RepaintElement(m_caret.GetElement());
  5300. }
  5301. #endif // INTERNAL_SPELLCHECK_SUPPORT
  5302. }
  5303. #if defined(WIDGETS_IME_SUPPORT) && !defined(DOCUMENTEDIT_DISABLE_IME_SUPPORT)
  5304. VisualDevice* vd = m_doc->GetVisualDevice();
  5305. if (vd->GetView())
  5306. {
  5307. vd->GetView()->GetOpView()->SetInputMethodMode(focus ? OpView::IME_MODE_TEXT : OpView::IME_MODE_UNKNOWN, OpView::IME_CONTEXT_DEFAULT, NULL);
  5308. if (!focus)
  5309. vd->GetView()->GetOpView()->AbortInputMethodComposing();
  5310. }
  5311. #endif // WIDGETS_IME_SUPPORT && !DOCUMENTEDIT_DISABLE_IME_SUPPORT
  5312. }
  5313. void OpDocumentEdit::CheckLogTreeChanged(BOOL caused_by_user)
  5314. {
  5315. DEBUG_CHECKER(TRUE);
  5316. if (m_logtree_changed)
  5317. {
  5318. Begin();
  5319. m_undo_stack.Clear();
  5320. if (!m_caret.GetElement())
  5321. m_caret.Init(FALSE /* TRUE */);
  5322. m_logtree_changed = FALSE;
  5323. CollapseWhitespace();
  5324. End();
  5325. }
  5326. else if (!m_caret.GetElement())
  5327. {
  5328. if (caused_by_user)
  5329. m_undo_stack.Clear();
  5330. m_caret.Init(FALSE /* caused_by_user */);
  5331. }
  5332. }
  5333. void OpDocumentEdit::OnElementInserted(HTML_Element* elm)
  5334. {
  5335. DEBUG_CHECKER(TRUE);
  5336. OpDocumentEditInternalEventListener *listener = (OpDocumentEditInternalEventListener*)m_internal_event_listeners.First();
  5337. while(listener)
  5338. {
  5339. OpDocumentEditInternalEventListener *next_listener = (OpDocumentEditInternalEventListener *)(listener->Suc());
  5340. listener->OnElementInserted(elm);
  5341. listener = next_listener;
  5342. }
  5343. #ifdef INTERNAL_SPELLCHECK_SUPPORT
  5344. if(m_spell_session)
  5345. SpellInvalidateAround(elm);
  5346. else if ((m_enable_spellcheck_later || (!m_by_user && elm->SpellcheckEnabledByAttr() == HTML_Element::SPC_ENABLE)) && g_internal_spellcheck->SpellcheckEnabledByDefault())
  5347. {
  5348. OpString pref_lang;
  5349. BOOL has_pl = GetPreferredLanguage(pref_lang);
  5350. EnableSpellcheckInternal(FALSE /*by_user*/, has_pl ? pref_lang.CStr() : NULL);
  5351. m_enable_spellcheck_later = FALSE;
  5352. }
  5353. #endif // INTERNAL_SPELLCHECK_SUPPORT
  5354. if (m_begin_count == 0) // Deleted from outside documenteditor (by script).
  5355. m_logtree_changed = TRUE;
  5356. }
  5357. void OpDocumentEdit::OnElementChange(HTML_Element* elm)
  5358. {
  5359. OpDocumentEditInternalEventListener *listener = (OpDocumentEditInternalEventListener*)m_internal_event_listeners.First();
  5360. while(listener)
  5361. {
  5362. OpDocumentEditInternalEventListener *next_listener = (OpDocumentEditInternalEventListener *)(listener->Suc());
  5363. listener->OnElementChange(elm);
  5364. listener = next_listener;
  5365. }
  5366. }
  5367. void OpDocumentEdit::OnElementChanged(HTML_Element* elm)
  5368. {
  5369. OpDocumentEditInternalEventListener *listener = (OpDocumentEditInternalEventListener*)m_internal_event_listeners.First();
  5370. while(listener)
  5371. {
  5372. OpDocumentEditInternalEventListener *next_listener = (OpDocumentEditInternalEventListener *)(listener->Suc());
  5373. listener->OnElementChanged(elm);
  5374. listener = next_listener;
  5375. }
  5376. }
  5377. void OpDocumentEdit::OnBeforeElementOut(HTML_Element* elm)
  5378. {
  5379. DEBUG_CHECKER(TRUE);
  5380. OpDocumentEditAutoLink auto_link(elm, &m_before_out_elements);
  5381. #ifdef INTERNAL_SPELLCHECK_SUPPORT
  5382. m_doc_has_changed = TRUE;
  5383. if(m_spell_session)
  5384. SpellInvalidateAround(elm, TRUE);
  5385. if(elm->IsAncestorOf(m_last_helm_spelled))
  5386. m_last_helm_spelled = NULL;
  5387. OP_ASSERT(!elm->IsAncestorOf(m_pending_spell_first) && !elm->IsAncestorOf(m_pending_spell_last));
  5388. #endif // INTERNAL_SPLLCHECK_SUPPORT
  5389. m_caret.m_remove_when_move_elm = NULL;
  5390. OpDocumentEditInternalEventListener *listener = (OpDocumentEditInternalEventListener*)m_internal_event_listeners.First();
  5391. while(listener)
  5392. {
  5393. OpDocumentEditInternalEventListener *next_listener = (OpDocumentEditInternalEventListener *)(listener->Suc());
  5394. listener->OnElementOut(elm);
  5395. listener = next_listener;
  5396. }
  5397. }
  5398. BOOL OpDocumentEdit::IsBeforeOutElm(HTML_Element *elm)
  5399. {
  5400. OpDocumentEditAutoLink *link;
  5401. for(link = (OpDocumentEditAutoLink*)m_before_out_elements.First(); link; link = (OpDocumentEditAutoLink*)link->Suc())
  5402. if(link->GetObject() && ((HTML_Element*)(link->GetObject()))->IsAncestorOf(elm))
  5403. return TRUE;
  5404. return FALSE;
  5405. }
  5406. void OpDocumentEdit::OnElementRemoved(HTML_Element* elm)
  5407. {
  5408. DEBUG_CHECKER(TRUE);
  5409. #ifdef INTERNAL_SPELLCHECK_SUPPORT
  5410. OP_ASSERT(!elm->IsAncestorOf(m_pending_spell_first) && !elm->IsAncestorOf(m_pending_spell_last));
  5411. #endif // INTERNAL_SPELLCHECK_SUPPORT
  5412. m_caret.m_remove_when_move_elm = NULL;
  5413. if (m_begin_count == 0) // Deleted from outside documenteditor (by script).
  5414. {
  5415. if (elm == m_caret.GetElement() || elm->IsAncestorOf(m_caret.GetElement()))
  5416. { // Dont let the caret point to the removed element.
  5417. HTML_Element *body = GetBody();
  5418. if(!body || elm->IsAncestorOf(body))
  5419. m_caret.Set(NULL,0);
  5420. else
  5421. m_caret.Init(FALSE);
  5422. }
  5423. m_logtree_changed = TRUE;
  5424. }
  5425. #ifdef WIDGETS_IME_SUPPORT
  5426. #ifndef DOCUMENTEDIT_DISABLE_IME_SUPPORT
  5427. if (m_ime_string_elm == elm)
  5428. m_ime_string_elm = NULL;
  5429. #endif // !DOCUMENTEDIT_DISABLE_IME_SUPPORT
  5430. #endif // WIDGETS_IME_SUPPORT
  5431. if (elm->IsAncestorOf(m_caret.m_parent_candidate))
  5432. m_caret.m_parent_candidate = NULL;
  5433. if (elm->IsAncestorOf(m_layout_modifier.m_helm))
  5434. m_layout_modifier.Unactivate();
  5435. m_recreate_caret = !m_caret.GetElement() && !m_caret.m_parent_candidate;
  5436. if (!m_caret.GetElement())
  5437. PostRecreateCaretMessage();
  5438. }
  5439. void OpDocumentEdit::OnElementDeleted(HTML_Element* elm)
  5440. {
  5441. DEBUG_CHECKER(TRUE);
  5442. #ifdef INTERNAL_SPELLCHECK_SUPPORT
  5443. OP_ASSERT(!elm->IsAncestorOf(m_pending_spell_first) && !elm->IsAncestorOf(m_pending_spell_last));
  5444. // There seems to be many situations where the above asserts trig and we crash later.
  5445. // NULL'ing the pointers here for now so we at least doesn't crash.
  5446. if (elm->IsAncestorOf(m_pending_spell_first) || elm->IsAncestorOf(m_pending_spell_last))
  5447. {
  5448. m_pending_spell_first = m_pending_spell_last = NULL;
  5449. }
  5450. #endif // INTERNAL_SPELLCHECK_SUPPORT
  5451. OpDocumentEditInternalEventListener *listener = (OpDocumentEditInternalEventListener*)m_internal_event_listeners.First();
  5452. while(listener)
  5453. {
  5454. OpDocumentEditInternalEventListener *next_listener = (OpDocumentEditInternalEventListener *)(listener->Suc());
  5455. listener->OnElementDeleted(elm);
  5456. listener = next_listener;
  5457. }
  5458. OP_ASSERT(elm != m_content_pending_helm);
  5459. if (elm == m_content_pending_helm)
  5460. m_content_pending_helm = NULL;
  5461. m_caret.m_remove_when_move_elm = NULL;
  5462. if (elm->IsAncestorOf(m_caret.GetElement()))
  5463. OnBeforeElementOut(elm);
  5464. if (elm->IsAncestorOf(m_caret.m_parent_candidate))
  5465. m_caret.m_parent_candidate = NULL;
  5466. if (elm->IsAncestorOf(m_layout_modifier.m_helm))
  5467. m_layout_modifier.Unactivate();
  5468. if (!GetRoot()->IsAncestorOf(elm))
  5469. return;
  5470. if (m_begin_count == 0) // Deleted from outside documenteditor (by script).
  5471. m_logtree_changed = TRUE;
  5472. }
  5473. void OpDocumentEdit::OnTextConvertedToTextGroup(HTML_Element* elm)
  5474. {
  5475. #ifdef INTERNAL_SPELLCHECK_SUPPORT
  5476. // The spell checker points to text elements, not to textgroups. If a text element
  5477. // changes we need to modify the spell checker as well.
  5478. if (m_pending_spell_first == elm)
  5479. m_pending_spell_first = elm->FirstChild();
  5480. if (m_pending_spell_last == elm)
  5481. m_pending_spell_last = elm->FirstChild();
  5482. m_word_iterator.OnTextConvertedToTextGroup(elm);
  5483. #endif // INTERNAL_SPELLCHECK_SUPPORT
  5484. }
  5485. void OpDocumentEdit::OnTextChange(HTML_Element *elm)
  5486. {
  5487. OnElementChange(elm);
  5488. }
  5489. void OpDocumentEdit::OnTextChanged(HTML_Element *elm)
  5490. {
  5491. OnElementChanged(elm);
  5492. #ifdef INTERNAL_SPELLCHECK_SUPPORT
  5493. m_doc_has_changed = TRUE;
  5494. if(elm->Type() == HE_TEXT && m_spell_session && !IsInBeforeElementOut())
  5495. SpellInvalidateAround(elm);
  5496. #endif // INTERNAL_SPELLCHECK_SUPPORT
  5497. }
  5498. void OpDocumentEdit::OnTextElmGetsLayoutWords(HTML_Element *elm)
  5499. {
  5500. #ifdef INTERNAL_SPELLCHECK_SUPPORT
  5501. m_doc_has_changed = TRUE;
  5502. if(elm->Type() == HE_TEXT && m_spell_session && !IsInBeforeElementOut())
  5503. SpellInvalidateAround(elm);
  5504. #endif // INTERNAL_SPELLCHECK_SUPPORT
  5505. }
  5506. BOOL OpDocumentEdit::LineIsEmpty(HTML_Element *helm)
  5507. {
  5508. DEBUG_CHECKER(TRUE);
  5509. if(!helm)
  5510. {
  5511. OP_ASSERT(FALSE);
  5512. return TRUE;
  5513. }
  5514. if((helm->GetTextContentLength() && !IsCollapsed(helm)) || (IsStandaloneElement(helm) && helm->Type() != HE_BR && helm->Type() != HE_TEXT))
  5515. return FALSE;
  5516. HTML_Element *tmp = helm->PrevActual();
  5517. while(tmp)
  5518. {
  5519. if(!IsFriends(tmp,helm,TRUE,TRUE,FALSE))
  5520. break;
  5521. if(IsStandaloneElement(tmp) || !IsCollapsed(tmp))
  5522. return FALSE;
  5523. tmp = tmp->PrevActual();
  5524. }
  5525. tmp = helm->NextActual();
  5526. while(tmp)
  5527. {
  5528. if(!IsFriends(helm,tmp,TRUE,TRUE,FALSE))
  5529. break;
  5530. if(IsStandaloneElement(tmp) || !IsCollapsed(tmp))
  5531. return FALSE;
  5532. tmp = tmp->NextActual();
  5533. }
  5534. return TRUE;
  5535. }
  5536. BOOL OpDocumentEdit::NeedAutoInsertedBR(HTML_Element *containing_element, BOOL ignore_current_auto_inserted_br)
  5537. {
  5538. if (containing_element->Type() == HE_LI)
  5539. return FALSE; ///< Not good, but layout collapse list items if we put a br in them! (oddly enough!)
  5540. HTML_Element *tmp = containing_element->FirstChildActual();
  5541. while (tmp && containing_element->IsAncestorOf(tmp))
  5542. {
  5543. if (ignore_current_auto_inserted_br && tmp->Type() == HE_BR && GetInsertedAutomatically(tmp))
  5544. ; // continue
  5545. else if (tmp->Type() == HE_TEXT && tmp == m_content_pending_helm)
  5546. return FALSE;
  5547. else if (tmp->Type() == HE_TEXT && !IsCollapsed(tmp) && tmp->GetTextContentLength())
  5548. return FALSE;
  5549. else if (IsStandaloneElement(tmp) && tmp->Type() != HE_TEXT)
  5550. return FALSE;
  5551. else if (IsBlockElement(tmp))
  5552. return FALSE;
  5553. tmp = tmp->NextActual();
  5554. }
  5555. return TRUE;
  5556. }
  5557. BOOL OpDocumentEdit::HasAutoInsertedBR(HTML_Element *containing_element)
  5558. {
  5559. HTML_Element *tmp = containing_element->FirstChildActual();
  5560. while (tmp && containing_element->IsAncestorOf(tmp))
  5561. {
  5562. if (tmp->Type() == HE_BR && GetInsertedAutomatically(tmp))
  5563. return TRUE;
  5564. tmp = tmp->NextActual();
  5565. }
  5566. return FALSE;
  5567. }
  5568. BOOL OpDocumentEdit::WillEndLineCollapseIfWs(uni_char *buf, HTML_Element *helm)
  5569. {
  5570. DEBUG_CHECKER(TRUE);
  5571. if(!helm)
  5572. {
  5573. OP_ASSERT(FALSE);
  5574. return FALSE;
  5575. }
  5576. if(buf && *buf)
  5577. {
  5578. while(uni_collapsing_sp(*++buf)) {}
  5579. if(*buf)
  5580. return FALSE;
  5581. }
  5582. HTML_Element *after = helm;
  5583. do
  5584. {
  5585. after = after->NextActual();
  5586. if (!after || !IsFriends(helm, after))
  5587. return TRUE;
  5588. } while(after->Type() != HE_TEXT || after->GetTextContentLength() == 0 || IsCollapsed(after));
  5589. return FALSE;
  5590. }
  5591. BOOL OpDocumentEdit::IsCollapsed(HTML_Element* helm)
  5592. {
  5593. DEBUG_CHECKER(TRUE);
  5594. if (!helm->GetLayoutBox())
  5595. return TRUE;
  5596. if(helm->Type() == HE_TEXT)
  5597. {
  5598. OpDocumentEditWordIterator iter(helm,this);
  5599. if(OpStatus::IsSuccess(iter.GetStatus()))
  5600. return iter.IsCollapsed();
  5601. }
  5602. return FALSE;
  5603. }
  5604. HTML_Element *OpDocumentEdit::GetEdgeHelmMightWsCollapse(HTML_Element *helm, BOOL forward)
  5605. {
  5606. DEBUG_CHECKER(TRUE);
  5607. int idx;
  5608. helm = forward ? helm->NextActual() : helm->PrevActual();
  5609. while(helm && (helm->Type() != HE_TEXT || !helm->GetTextContentLength()))
  5610. helm = forward ? helm->NextActual() : helm->PrevActual();
  5611. OpDocumentEditWordIterator iter(helm,this);
  5612. if(OpStatus::IsError(iter.GetStatus()))
  5613. return NULL;
  5614. idx = forward ? 0 : helm->GetTextContentLength()-1;
  5615. return uni_collapsing_sp(helm->TextContent()[idx]) && !iter.IsCharCollapsed(idx) ? helm : NULL;
  5616. }
  5617. HTML_Element* OpDocumentEdit::FindEditableElement(HTML_Element* from_helm, BOOL forward, BOOL include_current, BOOL require_box, BOOL include_ending_br, HTML_Element* helm_to_remove)
  5618. {
  5619. DEBUG_CHECKER(TRUE);
  5620. HTML_Element *editable_helm = NULL;
  5621. HTML_Element *helm = from_helm;
  5622. HTML_Element *body = GetBody();
  5623. if (!body || !helm)
  5624. return NULL;
  5625. if (!include_current)
  5626. {
  5627. helm = (forward ? helm->NextActual() : helm->PrevActual());
  5628. if (helm_to_remove && helm_to_remove->IsAncestorOf(helm))
  5629. helm = (forward ? helm->NextActual() : helm->PrevActual());
  5630. }
  5631. // Exit if helm is outside of body, but not if helm is (temporarily) detached from the tree.
  5632. if (!body->IsAncestorOf(helm) && GetRoot()->IsAncestorOf(helm))
  5633. return NULL;
  5634. while(helm && helm != body)
  5635. {
  5636. if (IsElementValidForCaret(helm, TRUE, include_ending_br, FALSE, helm_to_remove))
  5637. {
  5638. //if (require_box && !helm->GetLayoutBox() && helm->IsDirty())
  5639. //FIX: Reflow here so we don't have to do it always from other places.
  5640. if (!require_box || helm->GetLayoutBox())
  5641. {
  5642. editable_helm = helm;
  5643. break;
  5644. }
  5645. }
  5646. helm = (forward ? helm->NextActual() : helm->PrevActual());
  5647. if (helm_to_remove && helm_to_remove->IsAncestorOf(helm))
  5648. helm = (forward ? helm->NextActual() : helm->PrevActual());
  5649. }
  5650. return editable_helm;
  5651. }
  5652. BOOL OpDocumentEdit::IsEndingBr(HTML_Element* helm, HTML_Element* helm_to_remove)
  5653. {
  5654. DEBUG_CHECKER(TRUE);
  5655. if (helm->Type() != HE_BR)
  5656. return FALSE;
  5657. // Handles the case when the BR is ending but not in the same branch.
  5658. // <I>gggggggggggggg</I><BR>
  5659. HTML_Element* prev_helm = FindEditableElement(helm, FALSE, FALSE, TRUE, TRUE, helm_to_remove);
  5660. return (prev_helm && prev_helm->Type() != HE_BR && IsFriends(prev_helm, helm, TRUE, TRUE, TRUE));
  5661. }
  5662. BOOL OpDocumentEdit::GetNearestCaretPos(HTML_Element* from_helm, HTML_Element** nearest_helm, int* nearest_ofs, BOOL forward, BOOL include_current, HTML_Element* helm_to_remove)
  5663. {
  5664. DEBUG_CHECKER(TRUE);
  5665. HTML_Element* helm = FindEditableElement(from_helm, forward, include_current, TRUE, FALSE, helm_to_remove);
  5666. if (!helm)
  5667. return FALSE;
  5668. if (forward)
  5669. {
  5670. *nearest_ofs = 0;
  5671. }
  5672. else
  5673. {
  5674. if(helm->Type() == HE_TEXT)
  5675. *nearest_ofs = helm->GetTextContentLength();
  5676. else
  5677. *nearest_ofs = helm->Type() == HE_BR ? 0 : 1;
  5678. }
  5679. *nearest_helm = helm;
  5680. return TRUE;
  5681. }
  5682. BOOL OpDocumentEdit::GetBestCaretPosFrom(HTML_Element *helm, HTML_Element *&new_helm, int &new_ofs, BOOL3 prefer_first, BOOL must_be_friends, HTML_Element* helm_to_remove)
  5683. {
  5684. DEBUG_CHECKER(TRUE);
  5685. HTML_Element *prev_helm = NULL, *next_helm = NULL;
  5686. int prev_ofs = 0, next_ofs = 0;
  5687. GetNearestCaretPos(helm,&prev_helm,&prev_ofs,FALSE,FALSE, helm_to_remove);
  5688. if(must_be_friends && !IsFriends(prev_helm,helm,TRUE,TRUE))
  5689. {
  5690. prev_helm = NULL;
  5691. prev_ofs = 0;
  5692. }
  5693. GetNearestCaretPos(helm->NextSiblingActual(),&next_helm,&next_ofs,TRUE,TRUE, helm_to_remove);
  5694. if(must_be_friends && !IsFriends(helm,next_helm,TRUE,TRUE))
  5695. {
  5696. next_helm = NULL;
  5697. next_ofs = 0;
  5698. }
  5699. if(!prev_helm || !next_helm)
  5700. {
  5701. new_helm = prev_helm ? prev_helm : next_helm;
  5702. new_ofs = prev_ofs | next_ofs;
  5703. return !!new_helm;
  5704. }
  5705. BOOL pick_first = IsFriends(prev_helm,helm,TRUE,TRUE,TRUE);
  5706. if(prefer_first == NO)
  5707. pick_first = pick_first && !IsFriends(helm,next_helm,TRUE,TRUE);
  5708. if(pick_first)
  5709. {
  5710. new_helm = prev_helm;
  5711. new_ofs = prev_ofs;
  5712. }
  5713. else
  5714. {
  5715. new_helm = next_helm;
  5716. new_ofs = next_ofs;
  5717. }
  5718. return TRUE;
  5719. }
  5720. BOOL OpDocumentEdit::GetValidCaretPosFrom(HTML_Element *helm, int ofs, HTML_Element *&new_helm, int &new_ofs)
  5721. {
  5722. DEBUG_CHECKER(TRUE);
  5723. if(!helm)
  5724. return FALSE;
  5725. if(IsElementValidForCaret(helm))
  5726. {
  5727. new_helm = helm;
  5728. if(helm->Type() == HE_TEXT)
  5729. {
  5730. OpDocumentEditWordIterator iter(helm,this);
  5731. iter.SnapToValidCaretOfs(ofs,new_ofs);
  5732. }
  5733. else if(helm->Type() == HE_BR)
  5734. new_ofs = 0;
  5735. else
  5736. new_ofs = MAX(MIN(ofs,1),0);
  5737. return TRUE;
  5738. }
  5739. HTML_Element *candidate_helm = NULL;
  5740. int candidate_ofs = 0;
  5741. BOOL found = FALSE;
  5742. if(helm->FirstChildActual())
  5743. {
  5744. BOOL beginning = ofs <= 0;
  5745. if(beginning)
  5746. {
  5747. if(GetNearestCaretPos(helm,&candidate_helm,&candidate_ofs,TRUE,FALSE))
  5748. found = helm->IsAncestorOf(candidate_helm);
  5749. }
  5750. else
  5751. {
  5752. if(GetNearestCaretPos(helm->LastLeafActual(),&candidate_helm,&candidate_ofs,FALSE,TRUE))
  5753. found = helm->IsAncestorOf(candidate_helm);
  5754. }
  5755. }
  5756. if(!found && !GetBestCaretPosFrom(helm,candidate_helm,candidate_ofs))
  5757. {
  5758. candidate_helm = NULL;
  5759. candidate_ofs = 0;
  5760. }
  5761. else
  5762. found = TRUE;
  5763. new_helm = candidate_helm;
  5764. new_ofs = candidate_ofs;
  5765. return found;
  5766. }
  5767. BOOL OpDocumentEdit::GetLastValidCaretOfs(HTML_Element *helm, int &ofs)
  5768. {
  5769. DEBUG_CHECKER(TRUE);
  5770. if(!helm)
  5771. return FALSE;
  5772. if(helm->Type() == HE_TEXT)
  5773. {
  5774. OpDocumentEditWordIterator iter(helm,this);
  5775. if(OpStatus::IsError(iter.GetStatus()) || !iter.GetLastValidCaretOfs(ofs))
  5776. return FALSE;
  5777. }
  5778. else
  5779. ofs = 1;
  5780. return TRUE;
  5781. }
  5782. BOOL OpDocumentEdit::GetFirstValidCaretOfs(HTML_Element *helm, int &ofs)
  5783. {
  5784. DEBUG_CHECKER(TRUE);
  5785. if(!helm)
  5786. return FALSE;
  5787. if(helm->Type() == HE_TEXT)
  5788. {
  5789. OpDocumentEditWordIterator iter(helm, this);
  5790. if(OpStatus::IsError(iter.GetStatus()) || !iter.GetFirstValidCaretOfs(ofs))
  5791. return FALSE;
  5792. }
  5793. else
  5794. ofs = 0;
  5795. return TRUE;
  5796. }
  5797. HTML_Element* OpDocumentEdit::FindElementBeforeOfType(HTML_Element* helm, HTML_ElementType type, BOOL require_box)
  5798. {
  5799. DEBUG_CHECKER(TRUE);
  5800. // FIX: reflow if helm doesn't have a layoutbox and is dirty.
  5801. helm = helm ? helm->PrevActual() : NULL;
  5802. while(helm && (helm->Type() != type || (require_box && !helm->GetLayoutBox())))
  5803. helm = helm->PrevActual();
  5804. return helm;
  5805. }
  5806. HTML_Element* OpDocumentEdit::FindElementAfterOfType(HTML_Element* helm, HTML_ElementType type, BOOL require_box)
  5807. {
  5808. DEBUG_CHECKER(TRUE);
  5809. // FIX: reflow if helm doesn't have a layoutbox and is dirty.
  5810. helm = helm ? helm->NextActual() : NULL;
  5811. while(helm && (helm->Type() != type || (require_box && !helm->GetLayoutBox())))
  5812. helm = helm->NextActual();
  5813. return helm;
  5814. }
  5815. HTML_Element* OpDocumentEdit::MakeSureHasValidEdgeCaretPos(HTML_Element *helm, HTML_Element *container, BOOL at_end)
  5816. {
  5817. DEBUG_CHECKER(TRUE);
  5818. HTML_Element *new_helm = NULL, *existing_helm = NULL;
  5819. if(!helm && !container)
  5820. return NULL;
  5821. if(helm && container && !container->IsAncestorOf(helm))
  5822. {
  5823. OP_ASSERT(FALSE);
  5824. return NULL;
  5825. }
  5826. else if(helm && !container)
  5827. {
  5828. container = GetEditableContainer(helm);
  5829. if(!container)
  5830. return NULL;
  5831. }
  5832. if(IsStandaloneElement(container))
  5833. return NULL;
  5834. if(container->FirstChildActual())
  5835. {
  5836. if(at_end)
  5837. existing_helm = FindEditableElement(container->LastLeafActual(),FALSE,TRUE,TRUE);
  5838. else
  5839. existing_helm = FindEditableElement(container,TRUE,FALSE,TRUE);
  5840. if(!container->IsAncestorOf(existing_helm))
  5841. existing_helm = NULL;
  5842. }
  5843. else
  5844. existing_helm = NULL;
  5845. if(!existing_helm)
  5846. {
  5847. new_helm = NewTextElement(UNI_L(""),0);
  5848. if(!new_helm)
  5849. {
  5850. ReportOOM();
  5851. return NULL;
  5852. }
  5853. new_helm->UnderSafe(m_doc,container);
  5854. return new_helm;
  5855. }
  5856. HTML_Element *before_blocker = NULL, *after_blocker = NULL;
  5857. HTML_Element *stop = container->NextSiblingActual();
  5858. HTML_ElementType blocker_types[] = {HE_TABLE, HE_HR, HE_UNKNOWN};
  5859. helm = container->FirstChild();
  5860. BOOL found_existing = FALSE;
  5861. while(helm && helm != stop)
  5862. {
  5863. if(helm == existing_helm)
  5864. found_existing = TRUE;
  5865. else if(IsAnyOfTypes(helm,blocker_types))
  5866. {
  5867. if(!found_existing)
  5868. {
  5869. before_blocker = helm;
  5870. if(helm->IsAncestorOf(existing_helm))
  5871. after_blocker = helm;
  5872. }
  5873. else if(!after_blocker || after_blocker->IsAncestorOf(helm))
  5874. after_blocker = helm;
  5875. }
  5876. helm = helm->NextActual();
  5877. }
  5878. if((after_blocker && at_end) || (before_blocker && !at_end))
  5879. {
  5880. if(at_end)
  5881. new_helm = m_caret.CreateTemporaryCaretHelm(after_blocker->Parent(),after_blocker);
  5882. else
  5883. new_helm = m_caret.CreateTemporaryCaretHelm(before_blocker->Parent(),before_blocker->Pred());
  5884. }
  5885. // Add empty text element to the right or left of a non-editable element
  5886. // inside an editable element to be able to place the caret there.
  5887. if (!new_helm && at_end && !m_caret.IsElementEditable(container->LastChildActual()))
  5888. {
  5889. new_helm = NewTextElement(document_edit_dummy_str, 1);
  5890. BeginChange(container);
  5891. new_helm->UnderSafe(m_doc, container);
  5892. EndChange(container, TIDY_LEVEL_NONE);
  5893. }
  5894. else if (!new_helm && !at_end && !m_caret.IsElementEditable(container->FirstChildActual()))
  5895. {
  5896. new_helm = NewTextElement(document_edit_dummy_str, 1);
  5897. BeginChange(container);
  5898. new_helm->PrecedeSafe(m_doc, container->FirstChild());
  5899. EndChange(container, TIDY_LEVEL_NONE);
  5900. }
  5901. return new_helm;
  5902. }
  5903. HTML_Element* OpDocumentEdit::NewTextElement(const uni_char* text, int len)
  5904. {
  5905. DEBUG_CHECKER(TRUE);
  5906. HTML_Element *new_elm = NEW_HTML_Element();
  5907. HLDocProfile *hld_profile = m_doc->GetHLDocProfile();
  5908. if (!new_elm)
  5909. return NULL;
  5910. if (OpStatus::IsMemoryError(new_elm->Construct(hld_profile, text, len)))
  5911. {
  5912. DeleteElement(new_elm);
  5913. return NULL;
  5914. }
  5915. return new_elm;
  5916. }
  5917. HTML_Element* OpDocumentEdit::NewElement(HTML_ElementType type, BOOL set_automatic_flag)
  5918. {
  5919. DEBUG_CHECKER(TRUE);
  5920. HTML_Element *new_elm = NEW_HTML_Element();
  5921. HLDocProfile *hld_profile = m_doc->GetHLDocProfile();
  5922. if (!new_elm)
  5923. return NULL;
  5924. if (OpStatus::IsMemoryError(new_elm->Construct(hld_profile, NS_IDX_HTML, type, NULL, HE_INSERTED_BY_DOM))
  5925. || (set_automatic_flag && OpStatus::IsError(SetInsertedAutomatically(new_elm, TRUE)))
  5926. )
  5927. {
  5928. DeleteElement(new_elm);
  5929. return NULL;
  5930. }
  5931. new_elm->SetEndTagFound();
  5932. return new_elm;
  5933. }
  5934. HTML_Element* OpDocumentEdit::NewCopyOfElement(HTML_Element* helm, BOOL remove_id)
  5935. {
  5936. DEBUG_CHECKER(TRUE);
  5937. OP_ASSERT(helm->IsIncludedActual() || helm->GetInserted() == HE_INSERTED_BY_IME);
  5938. HTML_Element *new_elm = NEW_HTML_Element();
  5939. HLDocProfile *hld_profile = m_doc->GetHLDocProfile();
  5940. if (!new_elm)
  5941. return NULL;
  5942. if (OpStatus::IsMemoryError(new_elm->Construct(hld_profile, helm)))
  5943. {
  5944. DeleteElement(new_elm);
  5945. return NULL;
  5946. }
  5947. new_elm->SetEndTagFound();
  5948. if(remove_id)
  5949. new_elm->RemoveAttribute(ATTR_ID);
  5950. return new_elm;
  5951. }
  5952. void OpDocumentEdit::SetElementText(HTML_Element* helm, const uni_char* text, int len)
  5953. {
  5954. DEBUG_CHECKER(TRUE);
  5955. OP_ASSERT(helm->Type() == HE_TEXT);
  5956. if (len == -1)
  5957. len = uni_strlen(text);
  5958. if (OpStatus::IsError(helm->SetText(m_doc, text, len)))
  5959. ReportOOM();
  5960. helm->RemoveCachedTextInfo(m_doc);
  5961. }
  5962. OP_STATUS OpDocumentEdit::SetInsertedAutomatically(HTML_Element* helm, BOOL inserted_automatically)
  5963. {
  5964. return SetSpecialAttr(helm, ATTR_DOCEDIT_AUTO_INSERTED, inserted_automatically);
  5965. }
  5966. BOOL OpDocumentEdit::GetInsertedAutomatically(HTML_Element* helm)
  5967. {
  5968. return GetSpecialAttr(helm, ATTR_DOCEDIT_AUTO_INSERTED);
  5969. }
  5970. OP_STATUS OpDocumentEdit::SetSpecialAttr(HTML_Element* helm, Markup::AttrType attr, BOOL value)
  5971. {
  5972. DEBUG_CHECKER(TRUE);
  5973. return helm->SetSpecialAttr(attr, ITEM_TYPE_NUM, (void*)(INTPTR)value, FALSE, SpecialNs::NS_DOCEDIT) == -1
  5974. ? OpStatus::ERR_NO_MEMORY : OpStatus::OK;
  5975. }
  5976. BOOL OpDocumentEdit::GetSpecialAttr(HTML_Element* helm, Markup::AttrType attr)
  5977. {
  5978. return !!helm->GetSpecialNumAttr(attr, SpecialNs::NS_DOCEDIT);
  5979. }
  5980. BOOL OpDocumentEdit::IsCharCollapsed(HTML_Element *helm, int ofs)
  5981. {
  5982. DEBUG_CHECKER(TRUE);
  5983. OP_ASSERT(helm && helm->Type() == HE_TEXT && ofs >= 0 && ofs < helm->GetTextContentLength());
  5984. OpDocumentEditWordIterator iter(helm,this);
  5985. if(OpStatus::IsError(iter.GetStatus()))
  5986. return FALSE;
  5987. return iter.IsCharCollapsed(ofs);
  5988. }
  5989. BOOL OpDocumentEdit::DeleteTextInElement(HTML_Element* helm, INT32 start_ofs, INT32 len)
  5990. {
  5991. DEBUG_CHECKER(TRUE);
  5992. if (len == 0 || helm->Type() != HE_TEXT)
  5993. return FALSE;
  5994. OpString str;
  5995. if (OpStatus::IsError(str.Set(helm->TextContent())))
  5996. ReportOOM();
  5997. OP_ASSERT(start_ofs >= 0);
  5998. start_ofs = MAX(start_ofs, 0);
  5999. OP_ASSERT(len <= helm->GetTextContentLength());
  6000. len = MIN(len, helm->GetTextContentLength());
  6001. str.Delete(start_ofs, len);
  6002. SetElementText(helm, str);
  6003. return TRUE;
  6004. }
  6005. BOOL OpDocumentEdit::SplitElement(HTML_Element* helm, INT32 ofs)
  6006. {
  6007. DEBUG_CHECKER(TRUE);
  6008. if (helm->Type() != HE_TEXT)
  6009. return FALSE;
  6010. if (ofs != 0 && ofs != helm->GetTextContentLength())
  6011. {
  6012. // Create second part element
  6013. const uni_char* second_part = helm->TextContent() + ofs;
  6014. HTML_Element* new_elm = NewTextElement(second_part, uni_strlen(second_part));
  6015. if (!new_elm)
  6016. {
  6017. ReportOOM();
  6018. return FALSE;
  6019. }
  6020. else
  6021. {
  6022. // Delete second part from the first element.
  6023. DeleteTextInElement(helm, ofs, helm->GetTextContentLength() - ofs);
  6024. // Insert second part
  6025. new_elm->FollowSafe(m_doc, helm);
  6026. new_elm->MarkExtraDirty(m_doc);
  6027. }
  6028. return TRUE;
  6029. }
  6030. return FALSE;
  6031. }
  6032. /*
  6033. FIX:
  6034. HTMLArea.isBlockElement = function(el) {
  6035. var blockTags = " body form textarea fieldset ul ol dl li div " +
  6036. "p h1 h2 h3 h4 h5 h6 quote pre table thead " +
  6037. "tbody tfoot tr td iframe address ";
  6038. return (blockTags.indexOf(" " + el.tagName.toLowerCase() + " ") != -1);
  6039. };
  6040. HTMLArea.needsClosingTag = function(el) {
  6041. var closingTags = " script style div span tr td tbody table em strong font a ";
  6042. return (closingTags.indexOf(" " + el.tagName.toLowerCase() + " ") != -1);
  6043. };
  6044. */
  6045. void OpDocumentEdit::AddWsPreservingOperation(OpDocumentEditWsPreserver *preserver)
  6046. {
  6047. DEBUG_CHECKER(TRUE);
  6048. if(!preserver)
  6049. return;
  6050. preserver->Out();
  6051. preserver->Into(&m_ws_preservers);
  6052. }
  6053. void OpDocumentEdit::RemoveWsPreservingOperation(OpDocumentEditWsPreserver *preserver)
  6054. {
  6055. DEBUG_CHECKER(TRUE);
  6056. if(preserver)
  6057. preserver->Out();
  6058. }
  6059. BOOL OpDocumentEdit::IsInWsPreservingOperation(HTML_Element *helm, BOOL3 was_collapsed)
  6060. {
  6061. DEBUG_CHECKER(TRUE);
  6062. if(!helm)
  6063. return FALSE;
  6064. OpDocumentEditWsPreserver *p = (OpDocumentEditWsPreserver*)m_ws_preservers.First();
  6065. while(p)
  6066. {
  6067. if(p->GetStartElement() == helm)
  6068. return was_collapsed == MAYBE || p->WasStartElementCollapsed() == (was_collapsed == YES);
  6069. if(p->GetStopElement() == helm)
  6070. return was_collapsed == MAYBE || p->WasStopElementCollapsed() == (was_collapsed == YES);
  6071. p = (OpDocumentEditWsPreserver*)p->Suc();
  6072. }
  6073. return FALSE;
  6074. }
  6075. BOOL OpDocumentEdit::IsElementValidForCaret(HTML_Element *helm, BOOL is_in_tree, BOOL ending_br_is_ok, BOOL valid_if_possible, HTML_Element* helm_to_remove)
  6076. {
  6077. DEBUG_CHECKER(TRUE);
  6078. if(!helm || !helm->IsIncludedActual() || (is_in_tree && !m_caret.IsElementEditable(helm)))
  6079. return FALSE;
  6080. HTML_Element *parent = helm->Parent();
  6081. for( ; parent && !IsReplacedElement(parent); parent = parent->Parent()) {}
  6082. if(parent)
  6083. return FALSE;
  6084. if(helm->Type() == HE_BR)
  6085. return ending_br_is_ok || !IsEndingBr(helm, helm_to_remove);//return TRUE;
  6086. if(helm->Type() == HE_TEXT)
  6087. {
  6088. if(!is_in_tree)
  6089. return TRUE;
  6090. if(IsInWsPreservingOperation(helm,NO)) // This element might for the moment not be valid, but WILL be later
  6091. return TRUE;
  6092. OpDocumentEditWordIterator iter(helm,this);
  6093. return OpStatus::IsSuccess(iter.GetStatus()) && iter.IsValidForCaret(valid_if_possible);
  6094. }
  6095. if(IsReplacedElement(helm))
  6096. return TRUE;
  6097. return FALSE;
  6098. }
  6099. BOOL OpDocumentEdit::IsFriendlyElement(HTML_Element* helm, BOOL include_replaced, BOOL br_is_friendly, BOOL non_editable_is_friendly)
  6100. {
  6101. DEBUG_CHECKER(TRUE);
  6102. if (!m_caret.IsElementEditable(helm) && !non_editable_is_friendly)
  6103. return FALSE;
  6104. if (!include_replaced && IsStandaloneElement(helm) && helm->Type() != HE_TEXT && helm->Type() != HE_BR)
  6105. return FALSE;
  6106. if (helm->Type() == HE_BR && !br_is_friendly)
  6107. return FALSE;
  6108. return !IsBlockElement(helm);
  6109. }
  6110. BOOL OpDocumentEdit::IsFriends(HTML_Element* helm_a, HTML_Element* helm_b, BOOL include_helm_b, BOOL include_replaced, BOOL br_is_friendly)
  6111. {
  6112. DEBUG_CHECKER(TRUE);
  6113. if(!helm_a || !helm_b)
  6114. return FALSE;
  6115. HTML_Element* unfriendly_parent_a = helm_a->Parent();//Actual();
  6116. HTML_Element* unfriendly_parent_b = helm_b->Parent();//Actual();
  6117. BOOL a_editable = m_caret.IsElementEditable(helm_a);
  6118. BOOL b_editable = m_caret.IsElementEditable(helm_b);
  6119. while(unfriendly_parent_a && IsFriendlyElement(unfriendly_parent_a, include_replaced, br_is_friendly, a_editable))
  6120. unfriendly_parent_a = unfriendly_parent_a->Parent();//Actual();
  6121. while(unfriendly_parent_b && IsFriendlyElement(unfriendly_parent_b, include_replaced, br_is_friendly, b_editable))
  6122. unfriendly_parent_b = unfriendly_parent_b->Parent();//Actual();
  6123. if (unfriendly_parent_a != unfriendly_parent_b)
  6124. return FALSE;
  6125. BOOL friendly = TRUE;
  6126. if (helm_b->Precedes(helm_a))
  6127. {
  6128. HTML_Element* tmp = helm_a;
  6129. helm_a = helm_b;
  6130. helm_b = tmp;
  6131. }
  6132. // Check if there is a unfriendly element between. If there is, return FALSE.
  6133. HTML_Element* tmp = (HTML_Element*) helm_a;
  6134. while(tmp)
  6135. {
  6136. if (tmp == helm_b && !include_helm_b)
  6137. break;
  6138. if (!IsFriendlyElement(tmp, include_replaced, br_is_friendly) /*&& !tmp->GetIsPseudoElement()*/)
  6139. {
  6140. friendly = FALSE;
  6141. break;
  6142. }
  6143. if (tmp == helm_b)
  6144. break;
  6145. tmp = (HTML_Element*) tmp->Next();
  6146. }
  6147. return friendly;
  6148. }
  6149. BOOL OpDocumentEdit::GetContentRectOfElement(HTML_Element *helm, AffinePos &ctm, RECT &rect, BoxRectType type)
  6150. {
  6151. DEBUG_CHECKER(TRUE);
  6152. if(!helm || !helm->GetLayoutBox())
  6153. return FALSE;
  6154. return helm->GetLayoutBox()->GetRect(m_doc, type, ctm, rect);
  6155. }
  6156. BOOL OpDocumentEdit::KeepWhenTidy(HTML_Element* helm)
  6157. {
  6158. DEBUG_CHECKER(TRUE);
  6159. switch(helm->Type())
  6160. {
  6161. case HE_TR:
  6162. case HE_TD:
  6163. case HE_TH:
  6164. case HE_TBODY:
  6165. case HE_THEAD:
  6166. case HE_TFOOT:
  6167. case HE_COLGROUP:
  6168. return TRUE;
  6169. };
  6170. if (helm->IsContentEditable())
  6171. return TRUE;
  6172. if (helm->GetFirstReferenceOfType(ElementRef::DOCEDITELM))
  6173. return TRUE;
  6174. return FALSE;
  6175. }
  6176. BOOL OpDocumentEdit::KeepWhenTidyIfEmpty(HTML_Element* helm)
  6177. {
  6178. DEBUG_CHECKER(TRUE);
  6179. switch(helm->Type())
  6180. {
  6181. case HE_IFRAME:
  6182. case HE_TEXTAREA:
  6183. return TRUE;
  6184. };
  6185. if (helm->IsContentEditable())
  6186. return TRUE;
  6187. if (helm->GetFirstReferenceOfType(ElementRef::DOCEDITELM))
  6188. return TRUE;
  6189. return FALSE;
  6190. }
  6191. BOOL OpDocumentEdit::IsNoTextContainer(HTML_Element* helm)
  6192. {
  6193. DEBUG_CHECKER(TRUE);
  6194. switch(helm->Type())
  6195. {
  6196. case HE_TR:
  6197. case HE_TH:
  6198. case HE_TBODY:
  6199. case HE_THEAD:
  6200. case HE_TFOOT:
  6201. case HE_COLGROUP:
  6202. case HE_IFRAME:
  6203. return TRUE;
  6204. };
  6205. if (helm->GetInserted() == HE_INSERTED_BY_LAYOUT)
  6206. return TRUE;
  6207. return FALSE;
  6208. }
  6209. BOOL OpDocumentEdit::IsEnclosedBy(HTML_Element* helm, HTML_Element* start, HTML_Element* stop)
  6210. {
  6211. DEBUG_CHECKER(TRUE);
  6212. if (start->Precedes(helm))
  6213. {
  6214. if (!helm->IsAncestorOf(stop))
  6215. return TRUE;
  6216. }
  6217. return FALSE;
  6218. }
  6219. BOOL OpDocumentEdit::ContainsTextBetween(HTML_Element* start, HTML_Element* stop)
  6220. {
  6221. DEBUG_CHECKER(TRUE);
  6222. start = (HTML_Element*) start->Next();
  6223. while(start != stop)
  6224. {
  6225. if (start->Type() == HE_TEXT)
  6226. return TRUE;
  6227. start = (HTML_Element*) start->Next();
  6228. }
  6229. return FALSE;
  6230. }
  6231. OldStyleTextSelectionPoint OpDocumentEdit::GetTextSelectionPoint(HTML_Element* helm, int character_offset, BOOL prefer_first)
  6232. {
  6233. DEBUG_CHECKER(TRUE);
  6234. OldStyleTextSelectionPoint sel_point;
  6235. if(!helm)
  6236. return sel_point;
  6237. if(helm->Type() != HE_TEXT)
  6238. character_offset = helm->Type() == HE_BR ? 0 : MAX(MIN(character_offset,1),0);
  6239. else
  6240. {
  6241. OpDocumentEditWordIterator iter(helm,this);
  6242. if(OpStatus::IsError(iter.GetStatus()) || !iter.HasUnCollapsedChar())
  6243. character_offset = 0;
  6244. else
  6245. iter.SnapToValidCaretOfs(character_offset,character_offset);
  6246. }
  6247. sel_point.SetLogicalPosition(helm,character_offset);
  6248. sel_point.SetBindDirection(prefer_first ? SelectionBoundaryPoint::BIND_BACKWARD : SelectionBoundaryPoint::BIND_FORWARD);
  6249. return sel_point;
  6250. }
  6251. OP_STATUS OpDocumentEdit::GetTextHTMLFromNamedElement(OpString& text, const uni_char* element_name, BOOL include_helm)
  6252. {
  6253. if (m_doc->GetLogicalDocument())
  6254. {
  6255. HTML_Element* helm = m_doc->GetLogicalDocument()->GetNamedHE(element_name);
  6256. if (helm)
  6257. return GetTextHTMLFromElement(text, helm, include_helm);
  6258. }
  6259. return OpStatus::ERR;
  6260. }
  6261. BOOL OpDocumentEdit::DeleteNamedElement(const uni_char* element_name)
  6262. {
  6263. if (m_doc->GetLogicalDocument())
  6264. {
  6265. HTML_Element* helm = m_doc->GetLogicalDocument()->GetNamedHE(element_name);
  6266. if (helm)
  6267. {
  6268. DeleteElement(helm);
  6269. return TRUE;
  6270. }
  6271. }
  6272. return FALSE;
  6273. }
  6274. OP_STATUS OpDocumentEdit::GetTextHTMLFromElement(OpString& text, HTML_Element* helm, BOOL include_helm)
  6275. {
  6276. DEBUG_CHECKER(TRUE);
  6277. TempBuffer tmp_buf;
  6278. tmp_buf.SetExpansionPolicy( TempBuffer::AGGRESSIVE );
  6279. tmp_buf.SetCachedLengthPolicy( TempBuffer::TRUSTED );
  6280. OP_STATUS oom_stat = HTML5Parser::SerializeTree(helm, &tmp_buf, HTML5Parser::SerializeTreeOptions().IncludeRoot(include_helm));
  6281. if (OpStatus::IsSuccess(oom_stat))
  6282. oom_stat = text.Set(tmp_buf.GetStorage());
  6283. return oom_stat;
  6284. }
  6285. void OpDocumentEdit::DeleteElement(HTML_Element* helm, OpDocumentEdit* edit, BOOL check_caret)
  6286. {
  6287. #ifdef _DOCEDIT_DEBUG
  6288. OpDocumentEditDebugChecker __docedit_debug_checker__dbg__ = OpDocumentEditDebugChecker(edit,edit,TRUE,TRUE);
  6289. #endif
  6290. if (helm)
  6291. {
  6292. FramesDocument* fdoc = NULL;
  6293. if (edit && edit->GetRoot()->IsAncestorOf(helm))
  6294. fdoc = edit->GetDoc();
  6295. if (fdoc && helm->Parent())
  6296. {
  6297. helm->Parent()->MarkDirty(fdoc, FALSE, TRUE);
  6298. HTML_Document *html_doc = fdoc->GetHtmlDocument();
  6299. if (html_doc && (helm == html_doc->GetHoverHTMLElement() || helm->IsAncestorOf(html_doc->GetHoverHTMLElement())))
  6300. // Avoid crash when lowlevelapplypseudoclasses traverse the hoverelement when it is not in the document anymore.
  6301. html_doc->SetHoverHTMLElement(NULL);
  6302. }
  6303. helm->Remove(fdoc, TRUE);
  6304. if (helm->Clean(fdoc))
  6305. helm->Free(fdoc);
  6306. }
  6307. }
  6308. HTML_Element*
  6309. OpDocumentEdit::GetTopEditableParent(HTML_Element* element)
  6310. {
  6311. if (m_body_is_root)
  6312. return GetBody();
  6313. HTML_Element* top_editable_parent = NULL;
  6314. while (element)
  6315. {
  6316. BOOL3 is_content_editable = element->GetContentEditableValue();
  6317. if (is_content_editable == YES)
  6318. top_editable_parent = element;
  6319. else if (is_content_editable == NO)
  6320. return top_editable_parent;
  6321. element = element->ParentActual();
  6322. }
  6323. return top_editable_parent;
  6324. }
  6325. HTML_Element* OpDocumentEdit::GetSharedContainingElement(HTML_Element* elm1, HTML_Element* elm2)
  6326. {
  6327. DEBUG_CHECKER_STATIC();
  6328. HTML_Element* containing_elm1 = m_doc->GetCaret()->GetContainingElementActual(elm1);
  6329. HTML_Element* containing_elm2 = m_doc->GetCaret()->GetContainingElementActual(elm2);
  6330. if (!containing_elm1)
  6331. containing_elm1 = GetEditableContainer(elm1);
  6332. if (!containing_elm2)
  6333. containing_elm2 = GetEditableContainer(elm2);
  6334. if (containing_elm1 == containing_elm2)
  6335. return containing_elm1;
  6336. while(!containing_elm1->IsAncestorOf(containing_elm2))
  6337. {
  6338. HTML_Element *containing_elm = m_doc->GetCaret()->GetContainingElementActual(containing_elm1);
  6339. if (containing_elm == containing_elm1)
  6340. containing_elm1 = containing_elm1->ParentActual();
  6341. else
  6342. containing_elm1 = containing_elm;
  6343. }
  6344. return containing_elm1;
  6345. }
  6346. HTML_Element* OpDocumentEdit::GetRoot()
  6347. {
  6348. DEBUG_CHECKER(TRUE);
  6349. return m_doc->GetLogicalDocument() ? m_doc->GetLogicalDocument()->GetRoot() : NULL;
  6350. }
  6351. HTML_Element* OpDocumentEdit::GetBody()
  6352. {
  6353. DEBUG_CHECKER(TRUE);
  6354. return FindElementAfterOfType(GetRoot(), HE_BODY);
  6355. }
  6356. HTML_Element* OpDocumentEdit::GetEditableContainer(HTML_Element* helm)
  6357. {
  6358. DEBUG_CHECKER(TRUE);
  6359. HTML_Element *body = GetBody();
  6360. if (m_body_is_root)
  6361. {
  6362. if(body && body->IsAncestorOf(helm))
  6363. return body;
  6364. }
  6365. HTML_Element *tmp = helm, *container = NULL;
  6366. if (!tmp || !body)
  6367. return NULL;
  6368. if (!body->IsAncestorOf(tmp))
  6369. return NULL;
  6370. while (tmp)
  6371. {
  6372. if (tmp->IsContentEditable())
  6373. container = tmp;
  6374. tmp = tmp->ParentActual();
  6375. }
  6376. if (container->IsAncestorOf(body))
  6377. container = body;
  6378. OP_ASSERT(!container || body->IsAncestorOf(container));
  6379. return container;
  6380. }
  6381. HTML_Element* OpDocumentEdit::GetFocusableEditableContainer(HTML_Element* helm)
  6382. {
  6383. DEBUG_CHECKER(TRUE);
  6384. HTML_Element *body = GetBody();
  6385. if (m_body_is_root)
  6386. {
  6387. if(body && body->IsAncestorOf(helm))
  6388. return body;
  6389. }
  6390. HTML_Element *tmp = helm, *container = NULL;
  6391. if (!tmp || !body)
  6392. return NULL;
  6393. if (!body->IsAncestorOf(tmp))
  6394. tmp = body;
  6395. while (tmp)
  6396. {
  6397. if (tmp->IsContentEditable())
  6398. container = tmp;
  6399. tmp = tmp->ParentActual();
  6400. }
  6401. if (container->IsAncestorOf(body))
  6402. container = body;
  6403. return container;
  6404. }
  6405. HTML_Element* OpDocumentEdit::GetHrContainer(HTML_Element *helm)
  6406. {
  6407. DEBUG_CHECKER(TRUE);
  6408. HTML_Element *container = GetEditableContainer(helm);
  6409. if(!container)
  6410. return NULL;
  6411. while(helm != container)
  6412. {
  6413. switch(helm->Type())
  6414. {
  6415. case HE_TD:
  6416. return helm;
  6417. }
  6418. helm = helm->ParentActual();
  6419. }
  6420. return helm;
  6421. }
  6422. void OpDocumentEdit::Tidy(HTML_Element* start_elm, HTML_Element* stop_elm, BOOL include_start_stop, TIDY_LEVEL tidy_level, BOOL keep_dummy, HTML_Element *shared_containing_elm)
  6423. {
  6424. DEBUG_CHECKER(TRUE);
  6425. #ifdef DEBUG_DOCUMENT_EDIT
  6426. if (start_elm == stop_elm && !m_doc->GetLogicalDocument()->GetRoot()->IsAncestorOf(start_elm))
  6427. DUMPDEBUGTREE_ELM(start_elm)
  6428. else
  6429. DUMPDEBUGTREE
  6430. #endif
  6431. if (tidy_level == TIDY_LEVEL_NONE)
  6432. return;
  6433. HTML_Element *old_caret = m_caret.GetElement();
  6434. BOOL is_in_document = GetRoot()->IsAncestorOf(start_elm);
  6435. if (is_in_document)
  6436. ReflowAndUpdate();
  6437. m_undo_stack.SetFlags(CHANGE_FLAGS_USER_INVISIBLE);
  6438. HTML_Element* tmp;
  6439. if (include_start_stop)
  6440. tmp = start_elm;
  6441. else
  6442. {
  6443. tmp = start_elm->Next();
  6444. if (tmp && tmp->GetIsListMarkerPseudoElement())
  6445. /* List marker pseudo element should be treated as integral
  6446. part of list item element and so should be skipped when
  6447. cleaning up. Also it is illegal to remove list marker element
  6448. without marking list item element extra dirty. */
  6449. tmp = static_cast<HTML_Element*>(tmp->NextSibling());
  6450. }
  6451. while(tmp)
  6452. {
  6453. if (!include_start_stop && tmp == stop_elm)
  6454. break;
  6455. if (stop_elm->Precedes(tmp) && !stop_elm->IsAncestorOf(tmp))
  6456. break;
  6457. HTML_Element* next_elm = tmp->Next();
  6458. if (next_elm && next_elm->GetIsListMarkerPseudoElement())
  6459. /* List marker pseudo element should be treated as integral
  6460. part of list item element. */
  6461. next_elm = static_cast<HTML_Element*>(next_elm->NextSibling());
  6462. // If it is a empty textelement we will delete it, but we must also continue with its parents since
  6463. // they may become empty.
  6464. if (tidy_level != TIDY_LEVEL_MINIMAL)
  6465. {
  6466. HTML_Element* tmpremove = tmp;
  6467. while((((!tmpremove->FirstChild() || (tmpremove->FirstChild()->GetIsListMarkerPseudoElement() && !tmpremove->FirstChild()->Suc()))
  6468. && !IsStandaloneElement(tmpremove) && !KeepWhenTidyIfEmpty(tmpremove)) ||
  6469. // Remove inserted elements so that generated branches won't be duplicated.
  6470. (tmpremove->GetInserted() == HE_INSERTED_BY_LAYOUT && tmpremove->Parent() && tmpremove->Parent()->GetIsPseudoElement()) ||
  6471. // Remove empty textelements that has suc or pred. Other must be keept as dummy for caret placement.
  6472. (tmpremove->Type() == HE_TEXT && tmpremove->GetTextContentLength() == 0 &&
  6473. (tidy_level == TIDY_LEVEL_AGGRESSIVE || (tmpremove->Suc() && tmpremove->Suc()->Type() == HE_TEXT) || (tmpremove->Pred() && tmpremove->Pred()->Type() == HE_TEXT)))))
  6474. {
  6475. if(tmpremove == shared_containing_elm)
  6476. {
  6477. next_elm = NULL; // No next element, we're finished!
  6478. break;
  6479. }
  6480. if (KeepWhenTidy(tmpremove))
  6481. {
  6482. // We should not remove this element.
  6483. if (!IsNoTextContainer(tmpremove))
  6484. {
  6485. // Create a empty textelement for the caret.
  6486. HTML_Element *new_content = NewTextElement(UNI_L(""), 0); // FIXME: OOM
  6487. new_content->UnderSafe(m_doc, tmpremove);
  6488. }
  6489. break;
  6490. }
  6491. HTML_Element* tmpremove_parent = tmpremove->ParentActual();
  6492. if (tmpremove->IsAncestorOf(next_elm))
  6493. {
  6494. HTML_Element* potential_next_elm = tmpremove_parent->Next();
  6495. if (shared_containing_elm->IsAncestorOf(potential_next_elm))
  6496. next_elm = potential_next_elm;
  6497. else
  6498. next_elm = NULL;
  6499. }
  6500. DeleteElement(tmpremove);
  6501. tmp = NULL;
  6502. if (tmpremove == stop_elm)
  6503. stop_elm = NULL;
  6504. if (tmpremove == old_caret)
  6505. {
  6506. old_caret = NULL;
  6507. m_caret.Set(NULL, 0);
  6508. }
  6509. // Abort if we are outside our permitted range (between start_elm and stop_elm)
  6510. if (tmpremove == start_elm || (tmpremove_parent == start_elm && !include_start_stop) ||
  6511. (tmpremove_parent != start_elm && tmpremove_parent->IsAncestorOf(start_elm)))
  6512. {
  6513. if (start_elm == tmpremove)
  6514. {
  6515. start_elm = next_elm ? next_elm : tmpremove_parent;
  6516. if(!shared_containing_elm)
  6517. break;
  6518. }
  6519. else
  6520. break;
  6521. }
  6522. tmpremove = tmpremove_parent;
  6523. }
  6524. }
  6525. if (tmp && IsDummyElement(tmp) && !keep_dummy)
  6526. {
  6527. SetElementText(tmp, UNI_L(""));
  6528. }
  6529. // Remove automatically inserted BR elements. (But not if it's needed!)
  6530. else if (tmp && tmp->Type() == HE_BR &&
  6531. GetInsertedAutomatically(tmp) &&
  6532. m_doc->GetCaret()->GetContainingElementActual(tmp) &&
  6533. !NeedAutoInsertedBR(m_doc->GetCaret()->GetContainingElementActual(tmp), TRUE))
  6534. {
  6535. if (tmp == stop_elm)
  6536. stop_elm = NULL;
  6537. if (tmp != start_elm)
  6538. {
  6539. DeleteElement(tmp);
  6540. tmp = NULL;
  6541. }
  6542. }
  6543. if (!stop_elm)
  6544. break;
  6545. tmp = next_elm;
  6546. }
  6547. // If empty there is nothing left, we have to create a empty textelement for the caret.
  6548. if(old_caret && m_caret.GetElement() != old_caret)
  6549. {
  6550. if ((!m_caret.GetElement() || !IsElementValidForCaret(m_caret.GetElement(), TRUE, TRUE) || (!include_start_stop && !start_elm->FirstChild())) && !IsStandaloneElement(start_elm) && !IsNoTextContainer(start_elm))
  6551. {
  6552. // Try to find a valid element first, since we don't want empty textnodes we don't need.
  6553. // Unfortunately FindEditableElement can't be used since it doesn't accept empty textnodes.
  6554. //HTML_Element* caret_candidate = FindEditableElement(start_elm, TRUE, TRUE, FALSE, TRUE, FALSE);
  6555. HTML_Element* caret_candidate = NULL;
  6556. if (stop_elm)
  6557. {
  6558. caret_candidate = FindElementAfterOfType(start_elm, HE_TEXT);
  6559. if (!caret_candidate || (stop_elm->Precedes(caret_candidate) && !stop_elm->IsAncestorOf(caret_candidate)))
  6560. caret_candidate = FindElementAfterOfType(start_elm, HE_BR);
  6561. if (!caret_candidate || (stop_elm->Precedes(caret_candidate) && !stop_elm->IsAncestorOf(caret_candidate)))
  6562. caret_candidate = NULL;
  6563. }
  6564. if (!caret_candidate)
  6565. {
  6566. caret_candidate = NewTextElement(UNI_L(""), 0);
  6567. if (caret_candidate)
  6568. caret_candidate->UnderSafe(m_doc, start_elm);
  6569. }
  6570. if (caret_candidate && is_in_document)
  6571. m_caret.Place(caret_candidate, 0);
  6572. }
  6573. if (!m_caret.GetElement())
  6574. m_caret.PlaceFirst();
  6575. }
  6576. #ifdef DEBUG_DOCUMENT_EDIT
  6577. if (start_elm == stop_elm && !m_doc->GetLogicalDocument()->GetRoot()->IsAncestorOf(start_elm))
  6578. DUMPDEBUGTREE_ELM(start_elm)
  6579. else
  6580. DUMPDEBUGTREE
  6581. #endif
  6582. }
  6583. void OpDocumentEdit::HandleCallback(OpMessage msg, MH_PARAM_1 par1, MH_PARAM_2 par2)
  6584. {
  6585. g_main_message_handler->UnsetCallBack(this, msg, par1);
  6586. switch (msg)
  6587. {
  6588. case MSG_DOCEDIT_RECREATE_CARET:
  6589. if (!m_caret.GetElement())
  6590. m_caret.Init(TRUE, 0, FALSE);
  6591. break;
  6592. };
  6593. }
  6594. OP_STATUS OpDocumentEdit::PostRecreateCaretMessage()
  6595. {
  6596. const unsigned long delay = 10;
  6597. if (!g_main_message_handler->HasCallBack(this, MSG_DOCEDIT_RECREATE_CARET, (INTPTR) this))
  6598. {
  6599. RETURN_IF_ERROR(g_main_message_handler->SetCallBack(this, MSG_DOCEDIT_RECREATE_CARET, (INTPTR) this));
  6600. RETURN_IF_ERROR(g_main_message_handler->PostDelayedMessage(MSG_DOCEDIT_RECREATE_CARET, (MH_PARAM_1) this, 0, delay));
  6601. }
  6602. return OpStatus::OK;
  6603. }
  6604. #endif // DOCUMENT_EDIT_SUPPORT