HTMLTableEditor.cpp 114 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453
  1. /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. #include <stdio.h>
  6. #include "mozilla/HTMLEditor.h"
  7. #include "HTMLEditUtils.h"
  8. #include "mozilla/Assertions.h"
  9. #include "mozilla/EditorUtils.h"
  10. #include "mozilla/dom/Selection.h"
  11. #include "mozilla/dom/Element.h"
  12. #include "nsAString.h"
  13. #include "nsAlgorithm.h"
  14. #include "nsCOMPtr.h"
  15. #include "nsDebug.h"
  16. #include "nsError.h"
  17. #include "nsGkAtoms.h"
  18. #include "nsIAtom.h"
  19. #include "nsIContent.h"
  20. #include "nsIDOMElement.h"
  21. #include "nsIDOMNode.h"
  22. #include "nsIEditor.h"
  23. #include "nsIFrame.h"
  24. #include "nsINode.h"
  25. #include "nsIPresShell.h"
  26. #include "nsISupportsUtils.h"
  27. #include "nsITableCellLayout.h" // For efficient access to table cell
  28. #include "nsITableEditor.h"
  29. #include "nsLiteralString.h"
  30. #include "nsQueryFrame.h"
  31. #include "nsRange.h"
  32. #include "nsString.h"
  33. #include "nsTArray.h"
  34. #include "nsTableCellFrame.h"
  35. #include "nsTableWrapperFrame.h"
  36. #include "nscore.h"
  37. #include <algorithm>
  38. namespace mozilla {
  39. using namespace dom;
  40. /**
  41. * Stack based helper class for restoring selection after table edit.
  42. */
  43. class MOZ_STACK_CLASS AutoSelectionSetterAfterTableEdit final
  44. {
  45. private:
  46. nsCOMPtr<nsITableEditor> mTableEditor;
  47. nsCOMPtr<nsIDOMElement> mTable;
  48. int32_t mCol, mRow, mDirection, mSelected;
  49. public:
  50. AutoSelectionSetterAfterTableEdit(nsITableEditor* aTableEditor,
  51. nsIDOMElement* aTable,
  52. int32_t aRow,
  53. int32_t aCol,
  54. int32_t aDirection,
  55. bool aSelected)
  56. : mTableEditor(aTableEditor)
  57. , mTable(aTable)
  58. , mCol(aCol)
  59. , mRow(aRow)
  60. , mDirection(aDirection)
  61. , mSelected(aSelected)
  62. {
  63. }
  64. ~AutoSelectionSetterAfterTableEdit()
  65. {
  66. if (mTableEditor) {
  67. mTableEditor->SetSelectionAfterTableEdit(mTable, mRow, mCol, mDirection,
  68. mSelected);
  69. }
  70. }
  71. // This is needed to abort the caret reset in the destructor
  72. // when one method yields control to another
  73. void CancelSetCaret()
  74. {
  75. mTableEditor = nullptr;
  76. mTable = nullptr;
  77. }
  78. };
  79. NS_IMETHODIMP
  80. HTMLEditor::InsertCell(nsIDOMElement* aCell,
  81. int32_t aRowSpan,
  82. int32_t aColSpan,
  83. bool aAfter,
  84. bool aIsHeader,
  85. nsIDOMElement** aNewCell)
  86. {
  87. NS_ENSURE_TRUE(aCell, NS_ERROR_NULL_POINTER);
  88. if (aNewCell) {
  89. *aNewCell = nullptr;
  90. }
  91. // And the parent and offsets needed to do an insert
  92. nsCOMPtr<nsIDOMNode> cellParent;
  93. nsresult rv = aCell->GetParentNode(getter_AddRefs(cellParent));
  94. NS_ENSURE_SUCCESS(rv, rv);
  95. NS_ENSURE_TRUE(cellParent, NS_ERROR_NULL_POINTER);
  96. int32_t cellOffset = GetChildOffset(aCell, cellParent);
  97. nsCOMPtr<nsIDOMElement> newCell;
  98. rv = CreateElementWithDefaults(aIsHeader ? NS_LITERAL_STRING("th") :
  99. NS_LITERAL_STRING("tb"),
  100. getter_AddRefs(newCell));
  101. if (NS_FAILED(rv)) {
  102. return rv;
  103. }
  104. if (!newCell) {
  105. return NS_ERROR_FAILURE;
  106. }
  107. //Optional: return new cell created
  108. if (aNewCell) {
  109. *aNewCell = newCell.get();
  110. NS_ADDREF(*aNewCell);
  111. }
  112. if (aRowSpan > 1) {
  113. // Note: Do NOT use editor transaction for this
  114. nsAutoString newRowSpan;
  115. newRowSpan.AppendInt(aRowSpan, 10);
  116. newCell->SetAttribute(NS_LITERAL_STRING("rowspan"), newRowSpan);
  117. }
  118. if (aColSpan > 1) {
  119. // Note: Do NOT use editor transaction for this
  120. nsAutoString newColSpan;
  121. newColSpan.AppendInt(aColSpan, 10);
  122. newCell->SetAttribute(NS_LITERAL_STRING("colspan"), newColSpan);
  123. }
  124. if (aAfter) {
  125. cellOffset++;
  126. }
  127. //Don't let Rules System change the selection
  128. AutoTransactionsConserveSelection dontChangeSelection(this);
  129. return InsertNode(newCell, cellParent, cellOffset);
  130. }
  131. NS_IMETHODIMP
  132. HTMLEditor::SetColSpan(nsIDOMElement* aCell,
  133. int32_t aColSpan)
  134. {
  135. NS_ENSURE_TRUE(aCell, NS_ERROR_NULL_POINTER);
  136. nsAutoString newSpan;
  137. newSpan.AppendInt(aColSpan, 10);
  138. return SetAttribute(aCell, NS_LITERAL_STRING("colspan"), newSpan);
  139. }
  140. NS_IMETHODIMP
  141. HTMLEditor::SetRowSpan(nsIDOMElement* aCell,
  142. int32_t aRowSpan)
  143. {
  144. NS_ENSURE_TRUE(aCell, NS_ERROR_NULL_POINTER);
  145. nsAutoString newSpan;
  146. newSpan.AppendInt(aRowSpan, 10);
  147. return SetAttribute(aCell, NS_LITERAL_STRING("rowspan"), newSpan);
  148. }
  149. NS_IMETHODIMP
  150. HTMLEditor::InsertTableCell(int32_t aNumber,
  151. bool aAfter)
  152. {
  153. nsCOMPtr<nsIDOMElement> table;
  154. nsCOMPtr<nsIDOMElement> curCell;
  155. nsCOMPtr<nsIDOMNode> cellParent;
  156. int32_t cellOffset, startRowIndex, startColIndex;
  157. nsresult rv = GetCellContext(nullptr,
  158. getter_AddRefs(table),
  159. getter_AddRefs(curCell),
  160. getter_AddRefs(cellParent), &cellOffset,
  161. &startRowIndex, &startColIndex);
  162. NS_ENSURE_SUCCESS(rv, rv);
  163. // Don't fail if no cell found
  164. NS_ENSURE_TRUE(curCell, NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND);
  165. // Get more data for current cell in row we are inserting at (we need COLSPAN)
  166. int32_t curStartRowIndex, curStartColIndex, rowSpan, colSpan, actualRowSpan, actualColSpan;
  167. bool isSelected;
  168. rv = GetCellDataAt(table, startRowIndex, startColIndex,
  169. getter_AddRefs(curCell),
  170. &curStartRowIndex, &curStartColIndex, &rowSpan, &colSpan,
  171. &actualRowSpan, &actualColSpan, &isSelected);
  172. NS_ENSURE_SUCCESS(rv, rv);
  173. NS_ENSURE_TRUE(curCell, NS_ERROR_FAILURE);
  174. int32_t newCellIndex = aAfter ? (startColIndex+colSpan) : startColIndex;
  175. //We control selection resetting after the insert...
  176. AutoSelectionSetterAfterTableEdit setCaret(this, table, startRowIndex,
  177. newCellIndex, ePreviousColumn,
  178. false);
  179. //...so suppress Rules System selection munging
  180. AutoTransactionsConserveSelection dontChangeSelection(this);
  181. for (int32_t i = 0; i < aNumber; i++) {
  182. nsCOMPtr<nsIDOMElement> newCell;
  183. rv = CreateElementWithDefaults(NS_LITERAL_STRING("td"),
  184. getter_AddRefs(newCell));
  185. if (NS_SUCCEEDED(rv) && newCell) {
  186. if (aAfter) {
  187. cellOffset++;
  188. }
  189. rv = InsertNode(newCell, cellParent, cellOffset);
  190. if (NS_FAILED(rv)) {
  191. break;
  192. }
  193. }
  194. }
  195. // XXX This is perhaps the result of the last call of InsertNode() or
  196. // CreateElementWithDefaults().
  197. return rv;
  198. }
  199. NS_IMETHODIMP
  200. HTMLEditor::GetFirstRow(nsIDOMElement* aTableElement,
  201. nsIDOMNode** aRowNode)
  202. {
  203. NS_ENSURE_TRUE(aRowNode, NS_ERROR_NULL_POINTER);
  204. *aRowNode = nullptr;
  205. NS_ENSURE_TRUE(aTableElement, NS_ERROR_NULL_POINTER);
  206. nsCOMPtr<nsIDOMElement> tableElement;
  207. nsresult rv = GetElementOrParentByTagName(NS_LITERAL_STRING("table"),
  208. aTableElement,
  209. getter_AddRefs(tableElement));
  210. NS_ENSURE_SUCCESS(rv, rv);
  211. NS_ENSURE_TRUE(tableElement, NS_ERROR_NULL_POINTER);
  212. nsCOMPtr<nsIDOMNode> tableChild;
  213. rv = tableElement->GetFirstChild(getter_AddRefs(tableChild));
  214. NS_ENSURE_SUCCESS(rv, rv);
  215. while (tableChild) {
  216. nsCOMPtr<nsIContent> content = do_QueryInterface(tableChild);
  217. if (content) {
  218. if (content->IsHTMLElement(nsGkAtoms::tr)) {
  219. // Found a row directly under <table>
  220. *aRowNode = tableChild;
  221. NS_ADDREF(*aRowNode);
  222. return NS_OK;
  223. }
  224. // Look for row in one of the row container elements
  225. if (content->IsAnyOfHTMLElements(nsGkAtoms::tbody,
  226. nsGkAtoms::thead,
  227. nsGkAtoms::tfoot)) {
  228. nsCOMPtr<nsIDOMNode> rowNode;
  229. rv = tableChild->GetFirstChild(getter_AddRefs(rowNode));
  230. NS_ENSURE_SUCCESS(rv, rv);
  231. // We can encounter textnodes here -- must find a row
  232. while (rowNode && !HTMLEditUtils::IsTableRow(rowNode)) {
  233. nsCOMPtr<nsIDOMNode> nextNode;
  234. rv = rowNode->GetNextSibling(getter_AddRefs(nextNode));
  235. NS_ENSURE_SUCCESS(rv, rv);
  236. rowNode = nextNode;
  237. }
  238. if (rowNode) {
  239. *aRowNode = rowNode.get();
  240. NS_ADDREF(*aRowNode);
  241. return NS_OK;
  242. }
  243. }
  244. }
  245. // Here if table child was a CAPTION or COLGROUP
  246. // or child of a row parent wasn't a row (bad HTML?),
  247. // or first child was a textnode
  248. // Look in next table child
  249. nsCOMPtr<nsIDOMNode> nextChild;
  250. rv = tableChild->GetNextSibling(getter_AddRefs(nextChild));
  251. NS_ENSURE_SUCCESS(rv, rv);
  252. tableChild = nextChild;
  253. }
  254. // If here, row was not found
  255. return NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND;
  256. }
  257. NS_IMETHODIMP
  258. HTMLEditor::GetNextRow(nsIDOMNode* aCurrentRowNode,
  259. nsIDOMNode** aRowNode)
  260. {
  261. NS_ENSURE_TRUE(aRowNode, NS_ERROR_NULL_POINTER);
  262. *aRowNode = nullptr;
  263. NS_ENSURE_TRUE(aCurrentRowNode, NS_ERROR_NULL_POINTER);
  264. if (!HTMLEditUtils::IsTableRow(aCurrentRowNode)) {
  265. return NS_ERROR_FAILURE;
  266. }
  267. nsCOMPtr<nsIDOMNode> nextRow;
  268. nsresult rv = aCurrentRowNode->GetNextSibling(getter_AddRefs(nextRow));
  269. NS_ENSURE_SUCCESS(rv, rv);
  270. nsCOMPtr<nsIDOMNode> nextNode;
  271. // Skip over any textnodes here
  272. while (nextRow && !HTMLEditUtils::IsTableRow(nextRow)) {
  273. rv = nextRow->GetNextSibling(getter_AddRefs(nextNode));
  274. NS_ENSURE_SUCCESS(rv, rv);
  275. nextRow = nextNode;
  276. }
  277. if (nextRow) {
  278. *aRowNode = nextRow.get();
  279. NS_ADDREF(*aRowNode);
  280. return NS_OK;
  281. }
  282. // No row found, search for rows in other table sections
  283. nsCOMPtr<nsIDOMNode> rowParent;
  284. rv = aCurrentRowNode->GetParentNode(getter_AddRefs(rowParent));
  285. NS_ENSURE_SUCCESS(rv, rv);
  286. NS_ENSURE_TRUE(rowParent, NS_ERROR_NULL_POINTER);
  287. nsCOMPtr<nsIDOMNode> parentSibling;
  288. rv = rowParent->GetNextSibling(getter_AddRefs(parentSibling));
  289. NS_ENSURE_SUCCESS(rv, rv);
  290. while (parentSibling) {
  291. rv = parentSibling->GetFirstChild(getter_AddRefs(nextRow));
  292. NS_ENSURE_SUCCESS(rv, rv);
  293. // We can encounter textnodes here -- must find a row
  294. while (nextRow && !HTMLEditUtils::IsTableRow(nextRow)) {
  295. rv = nextRow->GetNextSibling(getter_AddRefs(nextNode));
  296. NS_ENSURE_SUCCESS(rv, rv);
  297. nextRow = nextNode;
  298. }
  299. if (nextRow) {
  300. *aRowNode = nextRow.get();
  301. NS_ADDREF(*aRowNode);
  302. return NS_OK;
  303. }
  304. // We arrive here only if a table section has no children
  305. // or first child of section is not a row (bad HTML or more "_moz_text" nodes!)
  306. // So look for another section sibling
  307. rv = parentSibling->GetNextSibling(getter_AddRefs(nextNode));
  308. NS_ENSURE_SUCCESS(rv, rv);
  309. parentSibling = nextNode;
  310. }
  311. // If here, row was not found
  312. return NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND;
  313. }
  314. nsresult
  315. HTMLEditor::GetLastCellInRow(nsIDOMNode* aRowNode,
  316. nsIDOMNode** aCellNode)
  317. {
  318. NS_ENSURE_TRUE(aCellNode, NS_ERROR_NULL_POINTER);
  319. *aCellNode = nullptr;
  320. NS_ENSURE_TRUE(aRowNode, NS_ERROR_NULL_POINTER);
  321. nsCOMPtr<nsIDOMNode> rowChild;
  322. nsresult rv = aRowNode->GetLastChild(getter_AddRefs(rowChild));
  323. NS_ENSURE_SUCCESS(rv, rv);
  324. while (rowChild && !HTMLEditUtils::IsTableCell(rowChild)) {
  325. // Skip over textnodes
  326. nsCOMPtr<nsIDOMNode> previousChild;
  327. rv = rowChild->GetPreviousSibling(getter_AddRefs(previousChild));
  328. NS_ENSURE_SUCCESS(rv, rv);
  329. rowChild = previousChild;
  330. }
  331. if (rowChild) {
  332. *aCellNode = rowChild.get();
  333. NS_ADDREF(*aCellNode);
  334. return NS_OK;
  335. }
  336. // If here, cell was not found
  337. return NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND;
  338. }
  339. NS_IMETHODIMP
  340. HTMLEditor::InsertTableColumn(int32_t aNumber,
  341. bool aAfter)
  342. {
  343. RefPtr<Selection> selection;
  344. nsCOMPtr<nsIDOMElement> table;
  345. nsCOMPtr<nsIDOMElement> curCell;
  346. int32_t startRowIndex, startColIndex;
  347. nsresult rv = GetCellContext(getter_AddRefs(selection),
  348. getter_AddRefs(table),
  349. getter_AddRefs(curCell),
  350. nullptr, nullptr,
  351. &startRowIndex, &startColIndex);
  352. NS_ENSURE_SUCCESS(rv, rv);
  353. // Don't fail if no cell found
  354. NS_ENSURE_TRUE(curCell, NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND);
  355. // Get more data for current cell (we need ROWSPAN)
  356. int32_t curStartRowIndex, curStartColIndex, rowSpan, colSpan, actualRowSpan, actualColSpan;
  357. bool isSelected;
  358. rv = GetCellDataAt(table, startRowIndex, startColIndex,
  359. getter_AddRefs(curCell),
  360. &curStartRowIndex, &curStartColIndex,
  361. &rowSpan, &colSpan,
  362. &actualRowSpan, &actualColSpan, &isSelected);
  363. NS_ENSURE_SUCCESS(rv, rv);
  364. NS_ENSURE_TRUE(curCell, NS_ERROR_FAILURE);
  365. AutoEditBatch beginBatching(this);
  366. // Prevent auto insertion of BR in new cell until we're done
  367. AutoRules beginRulesSniffing(this, EditAction::insertNode, nsIEditor::eNext);
  368. // Use column after current cell if requested
  369. if (aAfter) {
  370. startColIndex += actualColSpan;
  371. //Detect when user is adding after a COLSPAN=0 case
  372. // Assume they want to stop the "0" behavior and
  373. // really add a new column. Thus we set the
  374. // colspan to its true value
  375. if (!colSpan) {
  376. SetColSpan(curCell, actualColSpan);
  377. }
  378. }
  379. int32_t rowCount, colCount, rowIndex;
  380. rv = GetTableSize(table, &rowCount, &colCount);
  381. NS_ENSURE_SUCCESS(rv, rv);
  382. //We reset caret in destructor...
  383. AutoSelectionSetterAfterTableEdit setCaret(this, table, startRowIndex,
  384. startColIndex, ePreviousRow,
  385. false);
  386. //.. so suppress Rules System selection munging
  387. AutoTransactionsConserveSelection dontChangeSelection(this);
  388. // If we are inserting after all existing columns
  389. // Make sure table is "well formed"
  390. // before appending new column
  391. if (startColIndex >= colCount) {
  392. NormalizeTable(table);
  393. }
  394. nsCOMPtr<nsIDOMNode> rowNode;
  395. for (rowIndex = 0; rowIndex < rowCount; rowIndex++) {
  396. if (startColIndex < colCount) {
  397. // We are inserting before an existing column
  398. rv = GetCellDataAt(table, rowIndex, startColIndex,
  399. getter_AddRefs(curCell),
  400. &curStartRowIndex, &curStartColIndex,
  401. &rowSpan, &colSpan,
  402. &actualRowSpan, &actualColSpan, &isSelected);
  403. NS_ENSURE_SUCCESS(rv, rv);
  404. // Don't fail entire process if we fail to find a cell
  405. // (may fail just in particular rows with < adequate cells per row)
  406. if (curCell) {
  407. if (curStartColIndex < startColIndex) {
  408. // We have a cell spanning this location
  409. // Simply increase its colspan to keep table rectangular
  410. // Note: we do nothing if colsSpan=0,
  411. // since it should automatically span the new column
  412. if (colSpan > 0) {
  413. SetColSpan(curCell, colSpan+aNumber);
  414. }
  415. } else {
  416. // Simply set selection to the current cell
  417. // so we can let InsertTableCell() do the work
  418. // Insert a new cell before current one
  419. selection->Collapse(curCell, 0);
  420. rv = InsertTableCell(aNumber, false);
  421. }
  422. }
  423. } else {
  424. // Get current row and append new cells after last cell in row
  425. if (!rowIndex) {
  426. rv = GetFirstRow(table.get(), getter_AddRefs(rowNode));
  427. if (NS_WARN_IF(NS_FAILED(rv))) {
  428. return rv;
  429. }
  430. } else {
  431. nsCOMPtr<nsIDOMNode> nextRow;
  432. rv = GetNextRow(rowNode.get(), getter_AddRefs(nextRow));
  433. if (NS_WARN_IF(NS_FAILED(rv))) {
  434. return rv;
  435. }
  436. rowNode = nextRow;
  437. }
  438. if (rowNode) {
  439. nsCOMPtr<nsIDOMNode> lastCell;
  440. rv = GetLastCellInRow(rowNode, getter_AddRefs(lastCell));
  441. NS_ENSURE_SUCCESS(rv, rv);
  442. NS_ENSURE_TRUE(lastCell, NS_ERROR_FAILURE);
  443. curCell = do_QueryInterface(lastCell);
  444. if (curCell) {
  445. // Simply add same number of cells to each row
  446. // Although tempted to check cell indexes for curCell,
  447. // the effects of COLSPAN>1 in some cells makes this futile!
  448. // We must use NormalizeTable first to assure
  449. // that there are cells in each cellmap location
  450. selection->Collapse(curCell, 0);
  451. rv = InsertTableCell(aNumber, true);
  452. }
  453. }
  454. }
  455. }
  456. // XXX This is perhaps the result of the last call of InsertTableCell().
  457. return rv;
  458. }
  459. NS_IMETHODIMP
  460. HTMLEditor::InsertTableRow(int32_t aNumber,
  461. bool aAfter)
  462. {
  463. nsCOMPtr<nsIDOMElement> table;
  464. nsCOMPtr<nsIDOMElement> curCell;
  465. int32_t startRowIndex, startColIndex;
  466. nsresult rv = GetCellContext(nullptr,
  467. getter_AddRefs(table),
  468. getter_AddRefs(curCell),
  469. nullptr, nullptr,
  470. &startRowIndex, &startColIndex);
  471. NS_ENSURE_SUCCESS(rv, rv);
  472. // Don't fail if no cell found
  473. NS_ENSURE_TRUE(curCell, NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND);
  474. // Get more data for current cell in row we are inserting at (we need COLSPAN)
  475. int32_t curStartRowIndex, curStartColIndex, rowSpan, colSpan, actualRowSpan, actualColSpan;
  476. bool isSelected;
  477. rv = GetCellDataAt(table, startRowIndex, startColIndex,
  478. getter_AddRefs(curCell),
  479. &curStartRowIndex, &curStartColIndex,
  480. &rowSpan, &colSpan,
  481. &actualRowSpan, &actualColSpan, &isSelected);
  482. NS_ENSURE_SUCCESS(rv, rv);
  483. NS_ENSURE_TRUE(curCell, NS_ERROR_FAILURE);
  484. int32_t rowCount, colCount;
  485. rv = GetTableSize(table, &rowCount, &colCount);
  486. NS_ENSURE_SUCCESS(rv, rv);
  487. AutoEditBatch beginBatching(this);
  488. // Prevent auto insertion of BR in new cell until we're done
  489. AutoRules beginRulesSniffing(this, EditAction::insertNode, nsIEditor::eNext);
  490. if (aAfter) {
  491. // Use row after current cell
  492. startRowIndex += actualRowSpan;
  493. //Detect when user is adding after a ROWSPAN=0 case
  494. // Assume they want to stop the "0" behavior and
  495. // really add a new row. Thus we set the
  496. // rowspan to its true value
  497. if (!rowSpan) {
  498. SetRowSpan(curCell, actualRowSpan);
  499. }
  500. }
  501. //We control selection resetting after the insert...
  502. AutoSelectionSetterAfterTableEdit setCaret(this, table, startRowIndex,
  503. startColIndex, ePreviousColumn,
  504. false);
  505. //...so suppress Rules System selection munging
  506. AutoTransactionsConserveSelection dontChangeSelection(this);
  507. nsCOMPtr<nsIDOMElement> cellForRowParent;
  508. int32_t cellsInRow = 0;
  509. if (startRowIndex < rowCount) {
  510. // We are inserting above an existing row
  511. // Get each cell in the insert row to adjust for COLSPAN effects while we
  512. // count how many cells are needed
  513. int32_t colIndex = 0;
  514. while (NS_SUCCEEDED(GetCellDataAt(table, startRowIndex, colIndex,
  515. getter_AddRefs(curCell),
  516. &curStartRowIndex, &curStartColIndex,
  517. &rowSpan, &colSpan,
  518. &actualRowSpan, &actualColSpan,
  519. &isSelected))) {
  520. if (curCell) {
  521. if (curStartRowIndex < startRowIndex) {
  522. // We have a cell spanning this location
  523. // Simply increase its rowspan
  524. //Note that if rowSpan == 0, we do nothing,
  525. // since that cell should automatically extend into the new row
  526. if (rowSpan > 0) {
  527. SetRowSpan(curCell, rowSpan+aNumber);
  528. }
  529. } else {
  530. // We have a cell in the insert row
  531. // Count the number of cells we need to add to the new row
  532. cellsInRow += actualColSpan;
  533. // Save cell we will use below
  534. if (!cellForRowParent) {
  535. cellForRowParent = curCell;
  536. }
  537. }
  538. // Next cell in row
  539. colIndex += actualColSpan;
  540. } else {
  541. colIndex++;
  542. }
  543. }
  544. } else {
  545. // We are adding a new row after all others
  546. // If it weren't for colspan=0 effect,
  547. // we could simply use colCount for number of new cells...
  548. // XXX colspan=0 support has now been removed in table layout so maybe this can be cleaned up now? (bug 1243183)
  549. cellsInRow = colCount;
  550. // ...but we must compensate for all cells with rowSpan = 0 in the last row
  551. int32_t lastRow = rowCount-1;
  552. int32_t tempColIndex = 0;
  553. while (NS_SUCCEEDED(GetCellDataAt(table, lastRow, tempColIndex,
  554. getter_AddRefs(curCell),
  555. &curStartRowIndex, &curStartColIndex,
  556. &rowSpan, &colSpan,
  557. &actualRowSpan, &actualColSpan,
  558. &isSelected))) {
  559. if (!rowSpan) {
  560. cellsInRow -= actualColSpan;
  561. }
  562. tempColIndex += actualColSpan;
  563. // Save cell from the last row that we will use below
  564. if (!cellForRowParent && curStartRowIndex == lastRow) {
  565. cellForRowParent = curCell;
  566. }
  567. }
  568. }
  569. if (cellsInRow > 0) {
  570. // The row parent and offset where we will insert new row
  571. nsCOMPtr<nsIDOMNode> parentOfRow;
  572. int32_t newRowOffset;
  573. NS_NAMED_LITERAL_STRING(trStr, "tr");
  574. if (!cellForRowParent) {
  575. return NS_ERROR_FAILURE;
  576. }
  577. nsCOMPtr<nsIDOMElement> parentRow;
  578. rv = GetElementOrParentByTagName(trStr, cellForRowParent,
  579. getter_AddRefs(parentRow));
  580. NS_ENSURE_SUCCESS(rv, rv);
  581. NS_ENSURE_TRUE(parentRow, NS_ERROR_NULL_POINTER);
  582. parentRow->GetParentNode(getter_AddRefs(parentOfRow));
  583. NS_ENSURE_TRUE(parentOfRow, NS_ERROR_NULL_POINTER);
  584. newRowOffset = GetChildOffset(parentRow, parentOfRow);
  585. // Adjust for when adding past the end
  586. if (aAfter && startRowIndex >= rowCount) {
  587. newRowOffset++;
  588. }
  589. for (int32_t row = 0; row < aNumber; row++) {
  590. // Create a new row
  591. nsCOMPtr<nsIDOMElement> newRow;
  592. rv = CreateElementWithDefaults(trStr, getter_AddRefs(newRow));
  593. if (NS_SUCCEEDED(rv)) {
  594. NS_ENSURE_TRUE(newRow, NS_ERROR_FAILURE);
  595. for (int32_t i = 0; i < cellsInRow; i++) {
  596. nsCOMPtr<nsIDOMElement> newCell;
  597. rv = CreateElementWithDefaults(NS_LITERAL_STRING("td"),
  598. getter_AddRefs(newCell));
  599. NS_ENSURE_SUCCESS(rv, rv);
  600. NS_ENSURE_TRUE(newCell, NS_ERROR_FAILURE);
  601. // Don't use transaction system yet! (not until entire row is inserted)
  602. nsCOMPtr<nsIDOMNode>resultNode;
  603. rv = newRow->AppendChild(newCell, getter_AddRefs(resultNode));
  604. NS_ENSURE_SUCCESS(rv, rv);
  605. }
  606. // Use transaction system to insert the entire row+cells
  607. // (Note that rows are inserted at same childoffset each time)
  608. rv = InsertNode(newRow, parentOfRow, newRowOffset);
  609. NS_ENSURE_SUCCESS(rv, rv);
  610. }
  611. }
  612. }
  613. // XXX This might be the result of the last call of
  614. // CreateElementWithDefaults(), otherwise, NS_OK.
  615. return rv;
  616. }
  617. // Editor helper only
  618. // XXX Code changed for bug 217717 and now we don't need aSelection param
  619. // TODO: Remove aSelection param
  620. nsresult
  621. HTMLEditor::DeleteTable2(nsIDOMElement* aTable,
  622. Selection* aSelection)
  623. {
  624. NS_ENSURE_TRUE(aTable, NS_ERROR_NULL_POINTER);
  625. // Select the table
  626. nsresult rv = ClearSelection();
  627. if (NS_WARN_IF(NS_FAILED(rv))) {
  628. return rv;
  629. }
  630. rv = AppendNodeToSelectionAsRange(aTable);
  631. NS_ENSURE_SUCCESS(rv, rv);
  632. return DeleteSelection(nsIEditor::eNext, nsIEditor::eStrip);
  633. }
  634. NS_IMETHODIMP
  635. HTMLEditor::DeleteTable()
  636. {
  637. RefPtr<Selection> selection;
  638. nsCOMPtr<nsIDOMElement> table;
  639. nsresult rv = GetCellContext(getter_AddRefs(selection),
  640. getter_AddRefs(table),
  641. nullptr, nullptr, nullptr, nullptr, nullptr);
  642. NS_ENSURE_SUCCESS(rv, rv);
  643. AutoEditBatch beginBatching(this);
  644. return DeleteTable2(table, selection);
  645. }
  646. NS_IMETHODIMP
  647. HTMLEditor::DeleteTableCell(int32_t aNumber)
  648. {
  649. RefPtr<Selection> selection;
  650. nsCOMPtr<nsIDOMElement> table;
  651. nsCOMPtr<nsIDOMElement> cell;
  652. int32_t startRowIndex, startColIndex;
  653. nsresult rv = GetCellContext(getter_AddRefs(selection),
  654. getter_AddRefs(table),
  655. getter_AddRefs(cell),
  656. nullptr, nullptr,
  657. &startRowIndex, &startColIndex);
  658. NS_ENSURE_SUCCESS(rv, rv);
  659. // Don't fail if we didn't find a table or cell
  660. NS_ENSURE_TRUE(table && cell, NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND);
  661. AutoEditBatch beginBatching(this);
  662. // Prevent rules testing until we're done
  663. AutoRules beginRulesSniffing(this, EditAction::deleteNode, nsIEditor::eNext);
  664. nsCOMPtr<nsIDOMElement> firstCell;
  665. nsCOMPtr<nsIDOMRange> range;
  666. rv = GetFirstSelectedCell(getter_AddRefs(range), getter_AddRefs(firstCell));
  667. NS_ENSURE_SUCCESS(rv, rv);
  668. int32_t rangeCount;
  669. rv = selection->GetRangeCount(&rangeCount);
  670. NS_ENSURE_SUCCESS(rv, rv);
  671. if (firstCell && rangeCount > 1) {
  672. // When > 1 selected cell,
  673. // ignore aNumber and use selected cells
  674. cell = firstCell;
  675. int32_t rowCount, colCount;
  676. rv = GetTableSize(table, &rowCount, &colCount);
  677. NS_ENSURE_SUCCESS(rv, rv);
  678. // Get indexes -- may be different than original cell
  679. rv = GetCellIndexes(cell, &startRowIndex, &startColIndex);
  680. NS_ENSURE_SUCCESS(rv, rv);
  681. // The setCaret object will call AutoSelectionSetterAfterTableEdit in its
  682. // destructor
  683. AutoSelectionSetterAfterTableEdit setCaret(this, table, startRowIndex,
  684. startColIndex, ePreviousColumn,
  685. false);
  686. AutoTransactionsConserveSelection dontChangeSelection(this);
  687. bool checkToDeleteRow = true;
  688. bool checkToDeleteColumn = true;
  689. while (cell) {
  690. bool deleteRow = false;
  691. bool deleteCol = false;
  692. if (checkToDeleteRow) {
  693. // Optimize to delete an entire row
  694. // Clear so we don't repeat AllCellsInRowSelected within the same row
  695. checkToDeleteRow = false;
  696. deleteRow = AllCellsInRowSelected(table, startRowIndex, colCount);
  697. if (deleteRow) {
  698. // First, find the next cell in a different row
  699. // to continue after we delete this row
  700. int32_t nextRow = startRowIndex;
  701. while (nextRow == startRowIndex) {
  702. rv = GetNextSelectedCell(nullptr, getter_AddRefs(cell));
  703. NS_ENSURE_SUCCESS(rv, rv);
  704. if (!cell) {
  705. break;
  706. }
  707. rv = GetCellIndexes(cell, &nextRow, &startColIndex);
  708. NS_ENSURE_SUCCESS(rv, rv);
  709. }
  710. // Delete entire row
  711. rv = DeleteRow(table, startRowIndex);
  712. NS_ENSURE_SUCCESS(rv, rv);
  713. if (cell) {
  714. // For the next cell: Subtract 1 for row we deleted
  715. startRowIndex = nextRow - 1;
  716. // Set true since we know we will look at a new row next
  717. checkToDeleteRow = true;
  718. }
  719. }
  720. }
  721. if (!deleteRow) {
  722. if (checkToDeleteColumn) {
  723. // Optimize to delete an entire column
  724. // Clear this so we don't repeat AllCellsInColSelected within the same Col
  725. checkToDeleteColumn = false;
  726. deleteCol = AllCellsInColumnSelected(table, startColIndex, colCount);
  727. if (deleteCol) {
  728. // First, find the next cell in a different column
  729. // to continue after we delete this column
  730. int32_t nextCol = startColIndex;
  731. while (nextCol == startColIndex) {
  732. rv = GetNextSelectedCell(nullptr, getter_AddRefs(cell));
  733. NS_ENSURE_SUCCESS(rv, rv);
  734. if (!cell) {
  735. break;
  736. }
  737. rv = GetCellIndexes(cell, &startRowIndex, &nextCol);
  738. NS_ENSURE_SUCCESS(rv, rv);
  739. }
  740. // Delete entire Col
  741. rv = DeleteColumn(table, startColIndex);
  742. NS_ENSURE_SUCCESS(rv, rv);
  743. if (cell) {
  744. // For the next cell, subtract 1 for col. deleted
  745. startColIndex = nextCol - 1;
  746. // Set true since we know we will look at a new column next
  747. checkToDeleteColumn = true;
  748. }
  749. }
  750. }
  751. if (!deleteCol) {
  752. // First get the next cell to delete
  753. nsCOMPtr<nsIDOMElement> nextCell;
  754. rv = GetNextSelectedCell(getter_AddRefs(range),
  755. getter_AddRefs(nextCell));
  756. NS_ENSURE_SUCCESS(rv, rv);
  757. // Then delete the cell
  758. rv = DeleteNode(cell);
  759. NS_ENSURE_SUCCESS(rv, rv);
  760. // The next cell to delete
  761. cell = nextCell;
  762. if (cell) {
  763. rv = GetCellIndexes(cell, &startRowIndex, &startColIndex);
  764. NS_ENSURE_SUCCESS(rv, rv);
  765. }
  766. }
  767. }
  768. }
  769. } else {
  770. for (int32_t i = 0; i < aNumber; i++) {
  771. rv = GetCellContext(getter_AddRefs(selection),
  772. getter_AddRefs(table),
  773. getter_AddRefs(cell),
  774. nullptr, nullptr,
  775. &startRowIndex, &startColIndex);
  776. NS_ENSURE_SUCCESS(rv, rv);
  777. // Don't fail if no cell found
  778. NS_ENSURE_TRUE(cell, NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND);
  779. if (GetNumberOfCellsInRow(table, startRowIndex) == 1) {
  780. nsCOMPtr<nsIDOMElement> parentRow;
  781. rv = GetElementOrParentByTagName(NS_LITERAL_STRING("tr"), cell,
  782. getter_AddRefs(parentRow));
  783. NS_ENSURE_SUCCESS(rv, rv);
  784. NS_ENSURE_TRUE(parentRow, NS_ERROR_NULL_POINTER);
  785. // We should delete the row instead,
  786. // but first check if its the only row left
  787. // so we can delete the entire table
  788. int32_t rowCount, colCount;
  789. rv = GetTableSize(table, &rowCount, &colCount);
  790. NS_ENSURE_SUCCESS(rv, rv);
  791. if (rowCount == 1) {
  792. return DeleteTable2(table, selection);
  793. }
  794. // We need to call DeleteTableRow to handle cells with rowspan
  795. rv = DeleteTableRow(1);
  796. NS_ENSURE_SUCCESS(rv, rv);
  797. } else {
  798. // More than 1 cell in the row
  799. // The setCaret object will call AutoSelectionSetterAfterTableEdit in its
  800. // destructor
  801. AutoSelectionSetterAfterTableEdit setCaret(this, table, startRowIndex,
  802. startColIndex, ePreviousColumn,
  803. false);
  804. AutoTransactionsConserveSelection dontChangeSelection(this);
  805. rv = DeleteNode(cell);
  806. // If we fail, don't try to delete any more cells???
  807. NS_ENSURE_SUCCESS(rv, rv);
  808. }
  809. }
  810. }
  811. return NS_OK;
  812. }
  813. NS_IMETHODIMP
  814. HTMLEditor::DeleteTableCellContents()
  815. {
  816. RefPtr<Selection> selection;
  817. nsCOMPtr<nsIDOMElement> table;
  818. nsCOMPtr<nsIDOMElement> cell;
  819. int32_t startRowIndex, startColIndex;
  820. nsresult rv = GetCellContext(getter_AddRefs(selection),
  821. getter_AddRefs(table),
  822. getter_AddRefs(cell),
  823. nullptr, nullptr,
  824. &startRowIndex, &startColIndex);
  825. NS_ENSURE_SUCCESS(rv, rv);
  826. // Don't fail if no cell found
  827. NS_ENSURE_TRUE(cell, NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND);
  828. AutoEditBatch beginBatching(this);
  829. // Prevent rules testing until we're done
  830. AutoRules beginRulesSniffing(this, EditAction::deleteNode, nsIEditor::eNext);
  831. //Don't let Rules System change the selection
  832. AutoTransactionsConserveSelection dontChangeSelection(this);
  833. nsCOMPtr<nsIDOMElement> firstCell;
  834. nsCOMPtr<nsIDOMRange> range;
  835. rv = GetFirstSelectedCell(getter_AddRefs(range), getter_AddRefs(firstCell));
  836. NS_ENSURE_SUCCESS(rv, rv);
  837. if (firstCell) {
  838. cell = firstCell;
  839. rv = GetCellIndexes(cell, &startRowIndex, &startColIndex);
  840. NS_ENSURE_SUCCESS(rv, rv);
  841. }
  842. AutoSelectionSetterAfterTableEdit setCaret(this, table, startRowIndex,
  843. startColIndex, ePreviousColumn,
  844. false);
  845. while (cell) {
  846. DeleteCellContents(cell);
  847. if (firstCell) {
  848. // We doing a selected cells, so do all of them
  849. rv = GetNextSelectedCell(nullptr, getter_AddRefs(cell));
  850. NS_ENSURE_SUCCESS(rv, rv);
  851. } else {
  852. cell = nullptr;
  853. }
  854. }
  855. return NS_OK;
  856. }
  857. NS_IMETHODIMP
  858. HTMLEditor::DeleteCellContents(nsIDOMElement* aCell)
  859. {
  860. NS_ENSURE_TRUE(aCell, NS_ERROR_NULL_POINTER);
  861. // Prevent rules testing until we're done
  862. AutoRules beginRulesSniffing(this, EditAction::deleteNode, nsIEditor::eNext);
  863. nsCOMPtr<nsIDOMNode> child;
  864. bool hasChild;
  865. aCell->HasChildNodes(&hasChild);
  866. while (hasChild) {
  867. aCell->GetLastChild(getter_AddRefs(child));
  868. nsresult rv = DeleteNode(child);
  869. NS_ENSURE_SUCCESS(rv, rv);
  870. aCell->HasChildNodes(&hasChild);
  871. }
  872. return NS_OK;
  873. }
  874. NS_IMETHODIMP
  875. HTMLEditor::DeleteTableColumn(int32_t aNumber)
  876. {
  877. RefPtr<Selection> selection;
  878. nsCOMPtr<nsIDOMElement> table;
  879. nsCOMPtr<nsIDOMElement> cell;
  880. int32_t startRowIndex, startColIndex, rowCount, colCount;
  881. nsresult rv = GetCellContext(getter_AddRefs(selection),
  882. getter_AddRefs(table),
  883. getter_AddRefs(cell),
  884. nullptr, nullptr,
  885. &startRowIndex, &startColIndex);
  886. NS_ENSURE_SUCCESS(rv, rv);
  887. // Don't fail if no cell found
  888. NS_ENSURE_TRUE(table && cell, NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND);
  889. rv = GetTableSize(table, &rowCount, &colCount);
  890. NS_ENSURE_SUCCESS(rv, rv);
  891. // Shortcut the case of deleting all columns in table
  892. if (!startColIndex && aNumber >= colCount) {
  893. return DeleteTable2(table, selection);
  894. }
  895. // Check for counts too high
  896. aNumber = std::min(aNumber,(colCount-startColIndex));
  897. AutoEditBatch beginBatching(this);
  898. // Prevent rules testing until we're done
  899. AutoRules beginRulesSniffing(this, EditAction::deleteNode, nsIEditor::eNext);
  900. // Test if deletion is controlled by selected cells
  901. nsCOMPtr<nsIDOMElement> firstCell;
  902. nsCOMPtr<nsIDOMRange> range;
  903. rv = GetFirstSelectedCell(getter_AddRefs(range), getter_AddRefs(firstCell));
  904. NS_ENSURE_SUCCESS(rv, rv);
  905. int32_t rangeCount;
  906. rv = selection->GetRangeCount(&rangeCount);
  907. NS_ENSURE_SUCCESS(rv, rv);
  908. if (firstCell && rangeCount > 1) {
  909. // Fetch indexes again - may be different for selected cells
  910. rv = GetCellIndexes(firstCell, &startRowIndex, &startColIndex);
  911. NS_ENSURE_SUCCESS(rv, rv);
  912. }
  913. //We control selection resetting after the insert...
  914. AutoSelectionSetterAfterTableEdit setCaret(this, table, startRowIndex,
  915. startColIndex, ePreviousRow,
  916. false);
  917. if (firstCell && rangeCount > 1) {
  918. // Use selected cells to determine what rows to delete
  919. cell = firstCell;
  920. while (cell) {
  921. if (cell != firstCell) {
  922. rv = GetCellIndexes(cell, &startRowIndex, &startColIndex);
  923. NS_ENSURE_SUCCESS(rv, rv);
  924. }
  925. // Find the next cell in a different column
  926. // to continue after we delete this column
  927. int32_t nextCol = startColIndex;
  928. while (nextCol == startColIndex) {
  929. rv = GetNextSelectedCell(getter_AddRefs(range), getter_AddRefs(cell));
  930. NS_ENSURE_SUCCESS(rv, rv);
  931. if (!cell) {
  932. break;
  933. }
  934. rv = GetCellIndexes(cell, &startRowIndex, &nextCol);
  935. NS_ENSURE_SUCCESS(rv, rv);
  936. }
  937. rv = DeleteColumn(table, startColIndex);
  938. NS_ENSURE_SUCCESS(rv, rv);
  939. }
  940. } else {
  941. for (int32_t i = 0; i < aNumber; i++) {
  942. rv = DeleteColumn(table, startColIndex);
  943. NS_ENSURE_SUCCESS(rv, rv);
  944. }
  945. }
  946. return NS_OK;
  947. }
  948. NS_IMETHODIMP
  949. HTMLEditor::DeleteColumn(nsIDOMElement* aTable,
  950. int32_t aColIndex)
  951. {
  952. NS_ENSURE_TRUE(aTable, NS_ERROR_NULL_POINTER);
  953. nsCOMPtr<nsIDOMElement> cell;
  954. int32_t startRowIndex, startColIndex, rowSpan, colSpan, actualRowSpan, actualColSpan;
  955. bool isSelected;
  956. int32_t rowIndex = 0;
  957. do {
  958. nsresult rv =
  959. GetCellDataAt(aTable, rowIndex, aColIndex, getter_AddRefs(cell),
  960. &startRowIndex, &startColIndex, &rowSpan, &colSpan,
  961. &actualRowSpan, &actualColSpan, &isSelected);
  962. NS_ENSURE_SUCCESS(rv, rv);
  963. if (cell) {
  964. // Find cells that don't start in column we are deleting
  965. if (startColIndex < aColIndex || colSpan > 1 || !colSpan) {
  966. // We have a cell spanning this location
  967. // Decrease its colspan to keep table rectangular,
  968. // but if colSpan=0, it will adjust automatically
  969. if (colSpan > 0) {
  970. NS_ASSERTION((colSpan > 1),"Bad COLSPAN in DeleteTableColumn");
  971. SetColSpan(cell, colSpan-1);
  972. }
  973. if (startColIndex == aColIndex) {
  974. // Cell is in column to be deleted, but must have colspan > 1,
  975. // so delete contents of cell instead of cell itself
  976. // (We must have reset colspan above)
  977. DeleteCellContents(cell);
  978. }
  979. // To next cell in column
  980. rowIndex += actualRowSpan;
  981. } else {
  982. // Delete the cell
  983. if (GetNumberOfCellsInRow(aTable, rowIndex) == 1) {
  984. // Only 1 cell in row - delete the row
  985. nsCOMPtr<nsIDOMElement> parentRow;
  986. rv = GetElementOrParentByTagName(NS_LITERAL_STRING("tr"), cell,
  987. getter_AddRefs(parentRow));
  988. NS_ENSURE_SUCCESS(rv, rv);
  989. if (!parentRow) {
  990. return NS_ERROR_NULL_POINTER;
  991. }
  992. // But first check if its the only row left
  993. // so we can delete the entire table
  994. // (This should never happen but it's the safe thing to do)
  995. int32_t rowCount, colCount;
  996. rv = GetTableSize(aTable, &rowCount, &colCount);
  997. NS_ENSURE_SUCCESS(rv, rv);
  998. if (rowCount == 1) {
  999. RefPtr<Selection> selection = GetSelection();
  1000. NS_ENSURE_TRUE(selection, NS_ERROR_FAILURE);
  1001. return DeleteTable2(aTable, selection);
  1002. }
  1003. // Delete the row by placing caret in cell we were to delete
  1004. // We need to call DeleteTableRow to handle cells with rowspan
  1005. rv = DeleteRow(aTable, startRowIndex);
  1006. NS_ENSURE_SUCCESS(rv, rv);
  1007. // Note that we don't incremenet rowIndex
  1008. // since a row was deleted and "next"
  1009. // row now has current rowIndex
  1010. } else {
  1011. // A more "normal" deletion
  1012. rv = DeleteNode(cell);
  1013. NS_ENSURE_SUCCESS(rv, rv);
  1014. //Skip over any rows spanned by this cell
  1015. rowIndex += actualRowSpan;
  1016. }
  1017. }
  1018. }
  1019. } while (cell);
  1020. return NS_OK;
  1021. }
  1022. NS_IMETHODIMP
  1023. HTMLEditor::DeleteTableRow(int32_t aNumber)
  1024. {
  1025. RefPtr<Selection> selection;
  1026. nsCOMPtr<nsIDOMElement> table;
  1027. nsCOMPtr<nsIDOMElement> cell;
  1028. int32_t startRowIndex, startColIndex;
  1029. int32_t rowCount, colCount;
  1030. nsresult rv = GetCellContext(getter_AddRefs(selection),
  1031. getter_AddRefs(table),
  1032. getter_AddRefs(cell),
  1033. nullptr, nullptr,
  1034. &startRowIndex, &startColIndex);
  1035. NS_ENSURE_SUCCESS(rv, rv);
  1036. // Don't fail if no cell found
  1037. NS_ENSURE_TRUE(cell, NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND);
  1038. rv = GetTableSize(table, &rowCount, &colCount);
  1039. NS_ENSURE_SUCCESS(rv, rv);
  1040. // Shortcut the case of deleting all rows in table
  1041. if (!startRowIndex && aNumber >= rowCount) {
  1042. return DeleteTable2(table, selection);
  1043. }
  1044. AutoEditBatch beginBatching(this);
  1045. // Prevent rules testing until we're done
  1046. AutoRules beginRulesSniffing(this, EditAction::deleteNode, nsIEditor::eNext);
  1047. nsCOMPtr<nsIDOMElement> firstCell;
  1048. nsCOMPtr<nsIDOMRange> range;
  1049. rv = GetFirstSelectedCell(getter_AddRefs(range), getter_AddRefs(firstCell));
  1050. NS_ENSURE_SUCCESS(rv, rv);
  1051. int32_t rangeCount;
  1052. rv = selection->GetRangeCount(&rangeCount);
  1053. NS_ENSURE_SUCCESS(rv, rv);
  1054. if (firstCell && rangeCount > 1) {
  1055. // Fetch indexes again - may be different for selected cells
  1056. rv = GetCellIndexes(firstCell, &startRowIndex, &startColIndex);
  1057. NS_ENSURE_SUCCESS(rv, rv);
  1058. }
  1059. //We control selection resetting after the insert...
  1060. AutoSelectionSetterAfterTableEdit setCaret(this, table, startRowIndex,
  1061. startColIndex, ePreviousRow,
  1062. false);
  1063. // Don't change selection during deletions
  1064. AutoTransactionsConserveSelection dontChangeSelection(this);
  1065. if (firstCell && rangeCount > 1) {
  1066. // Use selected cells to determine what rows to delete
  1067. cell = firstCell;
  1068. while (cell) {
  1069. if (cell != firstCell) {
  1070. rv = GetCellIndexes(cell, &startRowIndex, &startColIndex);
  1071. NS_ENSURE_SUCCESS(rv, rv);
  1072. }
  1073. // Find the next cell in a different row
  1074. // to continue after we delete this row
  1075. int32_t nextRow = startRowIndex;
  1076. while (nextRow == startRowIndex) {
  1077. rv = GetNextSelectedCell(getter_AddRefs(range), getter_AddRefs(cell));
  1078. NS_ENSURE_SUCCESS(rv, rv);
  1079. if (!cell) break;
  1080. rv = GetCellIndexes(cell, &nextRow, &startColIndex);
  1081. NS_ENSURE_SUCCESS(rv, rv);
  1082. }
  1083. // Delete entire row
  1084. rv = DeleteRow(table, startRowIndex);
  1085. NS_ENSURE_SUCCESS(rv, rv);
  1086. }
  1087. } else {
  1088. // Check for counts too high
  1089. aNumber = std::min(aNumber,(rowCount-startRowIndex));
  1090. for (int32_t i = 0; i < aNumber; i++) {
  1091. rv = DeleteRow(table, startRowIndex);
  1092. // If failed in current row, try the next
  1093. if (NS_FAILED(rv)) {
  1094. startRowIndex++;
  1095. }
  1096. // Check if there's a cell in the "next" row
  1097. rv = GetCellAt(table, startRowIndex, startColIndex, getter_AddRefs(cell));
  1098. NS_ENSURE_SUCCESS(rv, rv);
  1099. if (!cell) {
  1100. break;
  1101. }
  1102. }
  1103. }
  1104. return NS_OK;
  1105. }
  1106. // Helper that doesn't batch or change the selection
  1107. NS_IMETHODIMP
  1108. HTMLEditor::DeleteRow(nsIDOMElement* aTable,
  1109. int32_t aRowIndex)
  1110. {
  1111. NS_ENSURE_TRUE(aTable, NS_ERROR_NULL_POINTER);
  1112. nsCOMPtr<nsIDOMElement> cell;
  1113. nsCOMPtr<nsIDOMElement> cellInDeleteRow;
  1114. int32_t startRowIndex, startColIndex, rowSpan, colSpan, actualRowSpan, actualColSpan;
  1115. bool isSelected;
  1116. int32_t colIndex = 0;
  1117. // Prevent rules testing until we're done
  1118. AutoRules beginRulesSniffing(this, EditAction::deleteNode, nsIEditor::eNext);
  1119. // The list of cells we will change rowspan in
  1120. // and the new rowspan values for each
  1121. nsTArray<nsCOMPtr<nsIDOMElement> > spanCellList;
  1122. nsTArray<int32_t> newSpanList;
  1123. int32_t rowCount, colCount;
  1124. nsresult rv = GetTableSize(aTable, &rowCount, &colCount);
  1125. NS_ENSURE_SUCCESS(rv, rv);
  1126. // Scan through cells in row to do rowspan adjustments
  1127. // Note that after we delete row, startRowIndex will point to the
  1128. // cells in the next row to be deleted
  1129. do {
  1130. if (aRowIndex >= rowCount || colIndex >= colCount) {
  1131. break;
  1132. }
  1133. rv = GetCellDataAt(aTable, aRowIndex, colIndex, getter_AddRefs(cell),
  1134. &startRowIndex, &startColIndex, &rowSpan, &colSpan,
  1135. &actualRowSpan, &actualColSpan, &isSelected);
  1136. // We don't fail if we don't find a cell, so this must be real bad
  1137. if (NS_FAILED(rv)) {
  1138. return rv;
  1139. }
  1140. // Compensate for cells that don't start or extend below the row we are deleting
  1141. if (cell) {
  1142. if (startRowIndex < aRowIndex) {
  1143. // Cell starts in row above us
  1144. // Decrease its rowspan to keep table rectangular
  1145. // but we don't need to do this if rowspan=0,
  1146. // since it will automatically adjust
  1147. if (rowSpan > 0) {
  1148. // Build list of cells to change rowspan
  1149. // We can't do it now since it upsets cell map,
  1150. // so we will do it after deleting the row
  1151. spanCellList.AppendElement(cell);
  1152. newSpanList.AppendElement(std::max((aRowIndex - startRowIndex), actualRowSpan-1));
  1153. }
  1154. } else {
  1155. if (rowSpan > 1) {
  1156. // Cell spans below row to delete, so we must insert new cells to
  1157. // keep rows below. Note that we test "rowSpan" so we don't do this
  1158. // if rowSpan = 0 (automatic readjustment).
  1159. int32_t aboveRowToInsertNewCellInto = aRowIndex - startRowIndex + 1;
  1160. int32_t numOfRawSpanRemainingBelow = actualRowSpan - 1;
  1161. rv = SplitCellIntoRows(aTable, startRowIndex, startColIndex,
  1162. aboveRowToInsertNewCellInto,
  1163. numOfRawSpanRemainingBelow, nullptr);
  1164. NS_ENSURE_SUCCESS(rv, rv);
  1165. }
  1166. if (!cellInDeleteRow) {
  1167. cellInDeleteRow = cell; // Reference cell to find row to delete
  1168. }
  1169. }
  1170. // Skip over other columns spanned by this cell
  1171. colIndex += actualColSpan;
  1172. }
  1173. } while (cell);
  1174. // Things are messed up if we didn't find a cell in the row!
  1175. NS_ENSURE_TRUE(cellInDeleteRow, NS_ERROR_FAILURE);
  1176. // Delete the entire row
  1177. nsCOMPtr<nsIDOMElement> parentRow;
  1178. rv = GetElementOrParentByTagName(NS_LITERAL_STRING("tr"), cellInDeleteRow,
  1179. getter_AddRefs(parentRow));
  1180. NS_ENSURE_SUCCESS(rv, rv);
  1181. if (parentRow) {
  1182. rv = DeleteNode(parentRow);
  1183. NS_ENSURE_SUCCESS(rv, rv);
  1184. }
  1185. // Now we can set new rowspans for cells stored above
  1186. for (uint32_t i = 0, n = spanCellList.Length(); i < n; i++) {
  1187. nsIDOMElement *cellPtr = spanCellList[i];
  1188. if (cellPtr) {
  1189. rv = SetRowSpan(cellPtr, newSpanList[i]);
  1190. NS_ENSURE_SUCCESS(rv, rv);
  1191. }
  1192. }
  1193. return NS_OK;
  1194. }
  1195. NS_IMETHODIMP
  1196. HTMLEditor::SelectTable()
  1197. {
  1198. nsCOMPtr<nsIDOMElement> table;
  1199. nsresult rv = GetElementOrParentByTagName(NS_LITERAL_STRING("table"), nullptr,
  1200. getter_AddRefs(table));
  1201. NS_ENSURE_SUCCESS(rv, rv);
  1202. // Don't fail if we didn't find a table
  1203. NS_ENSURE_TRUE(table, NS_OK);
  1204. rv = ClearSelection();
  1205. if (NS_FAILED(rv)) {
  1206. return rv;
  1207. }
  1208. return AppendNodeToSelectionAsRange(table);
  1209. }
  1210. NS_IMETHODIMP
  1211. HTMLEditor::SelectTableCell()
  1212. {
  1213. nsCOMPtr<nsIDOMElement> cell;
  1214. nsresult rv = GetElementOrParentByTagName(NS_LITERAL_STRING("td"), nullptr,
  1215. getter_AddRefs(cell));
  1216. NS_ENSURE_SUCCESS(rv, rv);
  1217. NS_ENSURE_TRUE(cell, NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND);
  1218. rv = ClearSelection();
  1219. if (NS_FAILED(rv)) {
  1220. return rv;
  1221. }
  1222. return AppendNodeToSelectionAsRange(cell);
  1223. }
  1224. NS_IMETHODIMP
  1225. HTMLEditor::SelectBlockOfCells(nsIDOMElement* aStartCell,
  1226. nsIDOMElement* aEndCell)
  1227. {
  1228. NS_ENSURE_TRUE(aStartCell && aEndCell, NS_ERROR_NULL_POINTER);
  1229. RefPtr<Selection> selection = GetSelection();
  1230. NS_ENSURE_TRUE(selection, NS_ERROR_FAILURE);
  1231. NS_NAMED_LITERAL_STRING(tableStr, "table");
  1232. nsCOMPtr<nsIDOMElement> table;
  1233. nsresult rv = GetElementOrParentByTagName(tableStr, aStartCell,
  1234. getter_AddRefs(table));
  1235. NS_ENSURE_SUCCESS(rv, rv);
  1236. NS_ENSURE_TRUE(table, NS_ERROR_FAILURE);
  1237. nsCOMPtr<nsIDOMElement> endTable;
  1238. rv = GetElementOrParentByTagName(tableStr, aEndCell,
  1239. getter_AddRefs(endTable));
  1240. NS_ENSURE_SUCCESS(rv, rv);
  1241. NS_ENSURE_TRUE(endTable, NS_ERROR_FAILURE);
  1242. // We can only select a block if within the same table,
  1243. // so do nothing if not within one table
  1244. if (table != endTable) {
  1245. return NS_OK;
  1246. }
  1247. int32_t startRowIndex, startColIndex, endRowIndex, endColIndex;
  1248. // Get starting and ending cells' location in the cellmap
  1249. rv = GetCellIndexes(aStartCell, &startRowIndex, &startColIndex);
  1250. if (NS_FAILED(rv)) {
  1251. return rv;
  1252. }
  1253. rv = GetCellIndexes(aEndCell, &endRowIndex, &endColIndex);
  1254. if (NS_FAILED(rv)) {
  1255. return rv;
  1256. }
  1257. // Suppress nsISelectionListener notification
  1258. // until all selection changes are finished
  1259. SelectionBatcher selectionBatcher(selection);
  1260. // Examine all cell nodes in current selection and
  1261. // remove those outside the new block cell region
  1262. int32_t minColumn = std::min(startColIndex, endColIndex);
  1263. int32_t minRow = std::min(startRowIndex, endRowIndex);
  1264. int32_t maxColumn = std::max(startColIndex, endColIndex);
  1265. int32_t maxRow = std::max(startRowIndex, endRowIndex);
  1266. nsCOMPtr<nsIDOMElement> cell;
  1267. int32_t currentRowIndex, currentColIndex;
  1268. nsCOMPtr<nsIDOMRange> range;
  1269. rv = GetFirstSelectedCell(getter_AddRefs(range), getter_AddRefs(cell));
  1270. NS_ENSURE_SUCCESS(rv, rv);
  1271. if (rv == NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND) {
  1272. return NS_OK;
  1273. }
  1274. while (cell) {
  1275. rv = GetCellIndexes(cell, &currentRowIndex, &currentColIndex);
  1276. NS_ENSURE_SUCCESS(rv, rv);
  1277. if (currentRowIndex < maxRow || currentRowIndex > maxRow ||
  1278. currentColIndex < maxColumn || currentColIndex > maxColumn) {
  1279. selection->RemoveRange(range);
  1280. // Since we've removed the range, decrement pointer to next range
  1281. mSelectedCellIndex--;
  1282. }
  1283. rv = GetNextSelectedCell(getter_AddRefs(range), getter_AddRefs(cell));
  1284. NS_ENSURE_SUCCESS(rv, rv);
  1285. }
  1286. int32_t rowSpan, colSpan, actualRowSpan, actualColSpan;
  1287. bool isSelected;
  1288. for (int32_t row = minRow; row <= maxRow; row++) {
  1289. for (int32_t col = minColumn; col <= maxColumn;
  1290. col += std::max(actualColSpan, 1)) {
  1291. rv = GetCellDataAt(table, row, col, getter_AddRefs(cell),
  1292. &currentRowIndex, &currentColIndex,
  1293. &rowSpan, &colSpan,
  1294. &actualRowSpan, &actualColSpan, &isSelected);
  1295. if (NS_FAILED(rv)) {
  1296. break;
  1297. }
  1298. // Skip cells that already selected or are spanned from previous locations
  1299. if (!isSelected && cell &&
  1300. row == currentRowIndex && col == currentColIndex) {
  1301. rv = AppendNodeToSelectionAsRange(cell);
  1302. if (NS_FAILED(rv)) {
  1303. break;
  1304. }
  1305. }
  1306. }
  1307. }
  1308. // NS_OK, otherwise, the last failure of GetCellDataAt() or
  1309. // AppendNodeToSelectionAsRange().
  1310. return rv;
  1311. }
  1312. NS_IMETHODIMP
  1313. HTMLEditor::SelectAllTableCells()
  1314. {
  1315. nsCOMPtr<nsIDOMElement> cell;
  1316. nsresult rv = GetElementOrParentByTagName(NS_LITERAL_STRING("td"), nullptr,
  1317. getter_AddRefs(cell));
  1318. NS_ENSURE_SUCCESS(rv, rv);
  1319. // Don't fail if we didn't find a cell
  1320. NS_ENSURE_TRUE(cell, NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND);
  1321. nsCOMPtr<nsIDOMElement> startCell = cell;
  1322. // Get parent table
  1323. nsCOMPtr<nsIDOMElement> table;
  1324. rv = GetElementOrParentByTagName(NS_LITERAL_STRING("table"), cell,
  1325. getter_AddRefs(table));
  1326. NS_ENSURE_SUCCESS(rv, rv);
  1327. if (!table) {
  1328. return NS_ERROR_NULL_POINTER;
  1329. }
  1330. int32_t rowCount, colCount;
  1331. rv = GetTableSize(table, &rowCount, &colCount);
  1332. NS_ENSURE_SUCCESS(rv, rv);
  1333. RefPtr<Selection> selection = GetSelection();
  1334. NS_ENSURE_TRUE(selection, NS_ERROR_FAILURE);
  1335. // Suppress nsISelectionListener notification
  1336. // until all selection changes are finished
  1337. SelectionBatcher selectionBatcher(selection);
  1338. // It is now safe to clear the selection
  1339. // BE SURE TO RESET IT BEFORE LEAVING!
  1340. rv = ClearSelection();
  1341. // Select all cells in the same column as current cell
  1342. bool cellSelected = false;
  1343. int32_t rowSpan, colSpan, actualRowSpan, actualColSpan, currentRowIndex, currentColIndex;
  1344. bool isSelected;
  1345. for (int32_t row = 0; row < rowCount; row++) {
  1346. for (int32_t col = 0; col < colCount; col += std::max(actualColSpan, 1)) {
  1347. rv = GetCellDataAt(table, row, col, getter_AddRefs(cell),
  1348. &currentRowIndex, &currentColIndex,
  1349. &rowSpan, &colSpan,
  1350. &actualRowSpan, &actualColSpan, &isSelected);
  1351. if (NS_FAILED(rv)) {
  1352. break;
  1353. }
  1354. // Skip cells that are spanned from previous rows or columns
  1355. if (cell && row == currentRowIndex && col == currentColIndex) {
  1356. rv = AppendNodeToSelectionAsRange(cell);
  1357. if (NS_FAILED(rv)) {
  1358. break;
  1359. }
  1360. cellSelected = true;
  1361. }
  1362. }
  1363. }
  1364. // Safety code to select starting cell if nothing else was selected
  1365. if (!cellSelected) {
  1366. return AppendNodeToSelectionAsRange(startCell);
  1367. }
  1368. // NS_OK, otherwise, the error of ClearSelection() when there is no column or
  1369. // the last failure of GetCellDataAt() or AppendNodeToSelectionAsRange().
  1370. return rv;
  1371. }
  1372. NS_IMETHODIMP
  1373. HTMLEditor::SelectTableRow()
  1374. {
  1375. nsCOMPtr<nsIDOMElement> cell;
  1376. nsresult rv = GetElementOrParentByTagName(NS_LITERAL_STRING("td"), nullptr,
  1377. getter_AddRefs(cell));
  1378. NS_ENSURE_SUCCESS(rv, rv);
  1379. // Don't fail if we didn't find a cell
  1380. NS_ENSURE_TRUE(cell, NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND);
  1381. nsCOMPtr<nsIDOMElement> startCell = cell;
  1382. // Get table and location of cell:
  1383. RefPtr<Selection> selection;
  1384. nsCOMPtr<nsIDOMElement> table;
  1385. int32_t startRowIndex, startColIndex;
  1386. rv = GetCellContext(getter_AddRefs(selection),
  1387. getter_AddRefs(table),
  1388. getter_AddRefs(cell),
  1389. nullptr, nullptr,
  1390. &startRowIndex, &startColIndex);
  1391. NS_ENSURE_SUCCESS(rv, rv);
  1392. NS_ENSURE_TRUE(table, NS_ERROR_FAILURE);
  1393. int32_t rowCount, colCount;
  1394. rv = GetTableSize(table, &rowCount, &colCount);
  1395. NS_ENSURE_SUCCESS(rv, rv);
  1396. //Note: At this point, we could get first and last cells in row,
  1397. // then call SelectBlockOfCells, but that would take just
  1398. // a little less code, so the following is more efficient
  1399. // Suppress nsISelectionListener notification
  1400. // until all selection changes are finished
  1401. SelectionBatcher selectionBatcher(selection);
  1402. // It is now safe to clear the selection
  1403. // BE SURE TO RESET IT BEFORE LEAVING!
  1404. rv = ClearSelection();
  1405. // Select all cells in the same row as current cell
  1406. bool cellSelected = false;
  1407. int32_t rowSpan, colSpan, actualRowSpan, actualColSpan, currentRowIndex, currentColIndex;
  1408. bool isSelected;
  1409. for (int32_t col = 0; col < colCount; col += std::max(actualColSpan, 1)) {
  1410. rv = GetCellDataAt(table, startRowIndex, col, getter_AddRefs(cell),
  1411. &currentRowIndex, &currentColIndex, &rowSpan, &colSpan,
  1412. &actualRowSpan, &actualColSpan, &isSelected);
  1413. if (NS_FAILED(rv)) {
  1414. break;
  1415. }
  1416. // Skip cells that are spanned from previous rows or columns
  1417. if (cell && currentRowIndex == startRowIndex && currentColIndex == col) {
  1418. rv = AppendNodeToSelectionAsRange(cell);
  1419. if (NS_FAILED(rv)) {
  1420. break;
  1421. }
  1422. cellSelected = true;
  1423. }
  1424. }
  1425. // Safety code to select starting cell if nothing else was selected
  1426. if (!cellSelected) {
  1427. return AppendNodeToSelectionAsRange(startCell);
  1428. }
  1429. // NS_OK, otherwise, the error of ClearSelection() when there is no column or
  1430. // the last failure of GetCellDataAt() or AppendNodeToSelectionAsRange().
  1431. return rv;
  1432. }
  1433. NS_IMETHODIMP
  1434. HTMLEditor::SelectTableColumn()
  1435. {
  1436. nsCOMPtr<nsIDOMElement> cell;
  1437. nsresult rv = GetElementOrParentByTagName(NS_LITERAL_STRING("td"), nullptr,
  1438. getter_AddRefs(cell));
  1439. NS_ENSURE_SUCCESS(rv, rv);
  1440. // Don't fail if we didn't find a cell
  1441. NS_ENSURE_TRUE(cell, NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND);
  1442. nsCOMPtr<nsIDOMElement> startCell = cell;
  1443. // Get location of cell:
  1444. RefPtr<Selection> selection;
  1445. nsCOMPtr<nsIDOMElement> table;
  1446. int32_t startRowIndex, startColIndex;
  1447. rv = GetCellContext(getter_AddRefs(selection),
  1448. getter_AddRefs(table),
  1449. getter_AddRefs(cell),
  1450. nullptr, nullptr,
  1451. &startRowIndex, &startColIndex);
  1452. NS_ENSURE_SUCCESS(rv, rv);
  1453. NS_ENSURE_TRUE(table, NS_ERROR_FAILURE);
  1454. int32_t rowCount, colCount;
  1455. rv = GetTableSize(table, &rowCount, &colCount);
  1456. NS_ENSURE_SUCCESS(rv, rv);
  1457. // Suppress nsISelectionListener notification
  1458. // until all selection changes are finished
  1459. SelectionBatcher selectionBatcher(selection);
  1460. // It is now safe to clear the selection
  1461. // BE SURE TO RESET IT BEFORE LEAVING!
  1462. rv = ClearSelection();
  1463. // Select all cells in the same column as current cell
  1464. bool cellSelected = false;
  1465. int32_t rowSpan, colSpan, actualRowSpan, actualColSpan, currentRowIndex, currentColIndex;
  1466. bool isSelected;
  1467. for (int32_t row = 0; row < rowCount; row += std::max(actualRowSpan, 1)) {
  1468. rv = GetCellDataAt(table, row, startColIndex, getter_AddRefs(cell),
  1469. &currentRowIndex, &currentColIndex, &rowSpan, &colSpan,
  1470. &actualRowSpan, &actualColSpan, &isSelected);
  1471. if (NS_FAILED(rv)) {
  1472. break;
  1473. }
  1474. // Skip cells that are spanned from previous rows or columns
  1475. if (cell && currentRowIndex == row && currentColIndex == startColIndex) {
  1476. rv = AppendNodeToSelectionAsRange(cell);
  1477. if (NS_FAILED(rv)) {
  1478. break;
  1479. }
  1480. cellSelected = true;
  1481. }
  1482. }
  1483. // Safety code to select starting cell if nothing else was selected
  1484. if (!cellSelected) {
  1485. return AppendNodeToSelectionAsRange(startCell);
  1486. }
  1487. // NS_OK, otherwise, the error of ClearSelection() when there is no row or
  1488. // the last failure of GetCellDataAt() or AppendNodeToSelectionAsRange().
  1489. return rv;
  1490. }
  1491. NS_IMETHODIMP
  1492. HTMLEditor::SplitTableCell()
  1493. {
  1494. nsCOMPtr<nsIDOMElement> table;
  1495. nsCOMPtr<nsIDOMElement> cell;
  1496. int32_t startRowIndex, startColIndex, actualRowSpan, actualColSpan;
  1497. // Get cell, table, etc. at selection anchor node
  1498. nsresult rv = GetCellContext(nullptr,
  1499. getter_AddRefs(table),
  1500. getter_AddRefs(cell),
  1501. nullptr, nullptr,
  1502. &startRowIndex, &startColIndex);
  1503. NS_ENSURE_SUCCESS(rv, rv);
  1504. if (!table || !cell) {
  1505. return NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND;
  1506. }
  1507. // We need rowspan and colspan data
  1508. rv = GetCellSpansAt(table, startRowIndex, startColIndex,
  1509. actualRowSpan, actualColSpan);
  1510. NS_ENSURE_SUCCESS(rv, rv);
  1511. // Must have some span to split
  1512. if (actualRowSpan <= 1 && actualColSpan <= 1) {
  1513. return NS_OK;
  1514. }
  1515. AutoEditBatch beginBatching(this);
  1516. // Prevent auto insertion of BR in new cell until we're done
  1517. AutoRules beginRulesSniffing(this, EditAction::insertNode, nsIEditor::eNext);
  1518. // We reset selection
  1519. AutoSelectionSetterAfterTableEdit setCaret(this, table, startRowIndex,
  1520. startColIndex, ePreviousColumn,
  1521. false);
  1522. //...so suppress Rules System selection munging
  1523. AutoTransactionsConserveSelection dontChangeSelection(this);
  1524. nsCOMPtr<nsIDOMElement> newCell;
  1525. int32_t rowIndex = startRowIndex;
  1526. int32_t rowSpanBelow, colSpanAfter;
  1527. // Split up cell row-wise first into rowspan=1 above, and the rest below,
  1528. // whittling away at the cell below until no more extra span
  1529. for (rowSpanBelow = actualRowSpan-1; rowSpanBelow >= 0; rowSpanBelow--) {
  1530. // We really split row-wise only if we had rowspan > 1
  1531. if (rowSpanBelow > 0) {
  1532. rv = SplitCellIntoRows(table, rowIndex, startColIndex, 1, rowSpanBelow,
  1533. getter_AddRefs(newCell));
  1534. NS_ENSURE_SUCCESS(rv, rv);
  1535. CopyCellBackgroundColor(newCell, cell);
  1536. }
  1537. int32_t colIndex = startColIndex;
  1538. // Now split the cell with rowspan = 1 into cells if it has colSpan > 1
  1539. for (colSpanAfter = actualColSpan-1; colSpanAfter > 0; colSpanAfter--) {
  1540. rv = SplitCellIntoColumns(table, rowIndex, colIndex, 1, colSpanAfter,
  1541. getter_AddRefs(newCell));
  1542. NS_ENSURE_SUCCESS(rv, rv);
  1543. CopyCellBackgroundColor(newCell, cell);
  1544. colIndex++;
  1545. }
  1546. // Point to the new cell and repeat
  1547. rowIndex++;
  1548. }
  1549. return NS_OK;
  1550. }
  1551. nsresult
  1552. HTMLEditor::CopyCellBackgroundColor(nsIDOMElement* destCell,
  1553. nsIDOMElement* sourceCell)
  1554. {
  1555. NS_ENSURE_TRUE(destCell && sourceCell, NS_ERROR_NULL_POINTER);
  1556. // Copy backgournd color to new cell
  1557. NS_NAMED_LITERAL_STRING(bgcolor, "bgcolor");
  1558. nsAutoString color;
  1559. bool isSet;
  1560. nsresult rv = GetAttributeValue(sourceCell, bgcolor, color, &isSet);
  1561. if (NS_FAILED(rv)) {
  1562. return rv;
  1563. }
  1564. if (!isSet) {
  1565. return NS_OK;
  1566. }
  1567. return SetAttribute(destCell, bgcolor, color);
  1568. }
  1569. NS_IMETHODIMP
  1570. HTMLEditor::SplitCellIntoColumns(nsIDOMElement* aTable,
  1571. int32_t aRowIndex,
  1572. int32_t aColIndex,
  1573. int32_t aColSpanLeft,
  1574. int32_t aColSpanRight,
  1575. nsIDOMElement** aNewCell)
  1576. {
  1577. NS_ENSURE_TRUE(aTable, NS_ERROR_NULL_POINTER);
  1578. if (aNewCell) {
  1579. *aNewCell = nullptr;
  1580. }
  1581. nsCOMPtr<nsIDOMElement> cell;
  1582. int32_t startRowIndex, startColIndex, rowSpan, colSpan, actualRowSpan, actualColSpan;
  1583. bool isSelected;
  1584. nsresult rv =
  1585. GetCellDataAt(aTable, aRowIndex, aColIndex, getter_AddRefs(cell),
  1586. &startRowIndex, &startColIndex,
  1587. &rowSpan, &colSpan,
  1588. &actualRowSpan, &actualColSpan, &isSelected);
  1589. NS_ENSURE_SUCCESS(rv, rv);
  1590. NS_ENSURE_TRUE(cell, NS_ERROR_NULL_POINTER);
  1591. // We can't split!
  1592. if (actualColSpan <= 1 || (aColSpanLeft + aColSpanRight) > actualColSpan) {
  1593. return NS_OK;
  1594. }
  1595. // Reduce colspan of cell to split
  1596. rv = SetColSpan(cell, aColSpanLeft);
  1597. NS_ENSURE_SUCCESS(rv, rv);
  1598. // Insert new cell after using the remaining span
  1599. // and always get the new cell so we can copy the background color;
  1600. nsCOMPtr<nsIDOMElement> newCell;
  1601. rv = InsertCell(cell, actualRowSpan, aColSpanRight, true, false,
  1602. getter_AddRefs(newCell));
  1603. NS_ENSURE_SUCCESS(rv, rv);
  1604. if (!newCell) {
  1605. return NS_OK;
  1606. }
  1607. if (aNewCell) {
  1608. NS_ADDREF(*aNewCell = newCell.get());
  1609. }
  1610. return CopyCellBackgroundColor(newCell, cell);
  1611. }
  1612. NS_IMETHODIMP
  1613. HTMLEditor::SplitCellIntoRows(nsIDOMElement* aTable,
  1614. int32_t aRowIndex,
  1615. int32_t aColIndex,
  1616. int32_t aRowSpanAbove,
  1617. int32_t aRowSpanBelow,
  1618. nsIDOMElement** aNewCell)
  1619. {
  1620. NS_ENSURE_TRUE(aTable, NS_ERROR_NULL_POINTER);
  1621. if (aNewCell) *aNewCell = nullptr;
  1622. nsCOMPtr<nsIDOMElement> cell;
  1623. int32_t startRowIndex, startColIndex, rowSpan, colSpan, actualRowSpan, actualColSpan;
  1624. bool isSelected;
  1625. nsresult rv =
  1626. GetCellDataAt(aTable, aRowIndex, aColIndex, getter_AddRefs(cell),
  1627. &startRowIndex, &startColIndex,
  1628. &rowSpan, &colSpan,
  1629. &actualRowSpan, &actualColSpan, &isSelected);
  1630. NS_ENSURE_SUCCESS(rv, rv);
  1631. NS_ENSURE_TRUE(cell, NS_ERROR_NULL_POINTER);
  1632. // We can't split!
  1633. if (actualRowSpan <= 1 || (aRowSpanAbove + aRowSpanBelow) > actualRowSpan) {
  1634. return NS_OK;
  1635. }
  1636. int32_t rowCount, colCount;
  1637. rv = GetTableSize(aTable, &rowCount, &colCount);
  1638. NS_ENSURE_SUCCESS(rv, rv);
  1639. nsCOMPtr<nsIDOMElement> cell2;
  1640. nsCOMPtr<nsIDOMElement> lastCellFound;
  1641. int32_t startRowIndex2, startColIndex2, rowSpan2, colSpan2, actualRowSpan2, actualColSpan2;
  1642. bool isSelected2;
  1643. int32_t colIndex = 0;
  1644. bool insertAfter = (startColIndex > 0);
  1645. // This is the row we will insert new cell into
  1646. int32_t rowBelowIndex = startRowIndex+aRowSpanAbove;
  1647. // Find a cell to insert before or after
  1648. for (;;) {
  1649. // Search for a cell to insert before
  1650. rv = GetCellDataAt(aTable, rowBelowIndex,
  1651. colIndex, getter_AddRefs(cell2),
  1652. &startRowIndex2, &startColIndex2, &rowSpan2, &colSpan2,
  1653. &actualRowSpan2, &actualColSpan2, &isSelected2);
  1654. // If we fail here, it could be because row has bad rowspan values,
  1655. // such as all cells having rowspan > 1 (Call FixRowSpan first!)
  1656. if (NS_FAILED(rv) || !cell) {
  1657. return NS_ERROR_FAILURE;
  1658. }
  1659. // Skip over cells spanned from above (like the one we are splitting!)
  1660. if (cell2 && startRowIndex2 == rowBelowIndex) {
  1661. if (!insertAfter) {
  1662. // Inserting before, so stop at first cell in row we want to insert
  1663. // into.
  1664. break;
  1665. }
  1666. // New cell isn't first in row,
  1667. // so stop after we find the cell just before new cell's column
  1668. if (startColIndex2 + actualColSpan2 == startColIndex) {
  1669. break;
  1670. }
  1671. // If cell found is AFTER desired new cell colum,
  1672. // we have multiple cells with rowspan > 1 that
  1673. // prevented us from finding a cell to insert after...
  1674. if (startColIndex2 > startColIndex) {
  1675. // ... so instead insert before the cell we found
  1676. insertAfter = false;
  1677. break;
  1678. }
  1679. lastCellFound = cell2;
  1680. }
  1681. // Skip to next available cellmap location
  1682. colIndex += std::max(actualColSpan2, 1);
  1683. // Done when past end of total number of columns
  1684. if (colIndex > colCount) {
  1685. break;
  1686. }
  1687. }
  1688. if (!cell2 && lastCellFound) {
  1689. // Edge case where we didn't find a cell to insert after
  1690. // or before because column(s) before desired column
  1691. // and all columns after it are spanned from above.
  1692. // We can insert after the last cell we found
  1693. cell2 = lastCellFound;
  1694. insertAfter = true; // Should always be true, but let's be sure
  1695. }
  1696. // Reduce rowspan of cell to split
  1697. rv = SetRowSpan(cell, aRowSpanAbove);
  1698. NS_ENSURE_SUCCESS(rv, rv);
  1699. // Insert new cell after using the remaining span
  1700. // and always get the new cell so we can copy the background color;
  1701. nsCOMPtr<nsIDOMElement> newCell;
  1702. rv = InsertCell(cell2, aRowSpanBelow, actualColSpan, insertAfter, false,
  1703. getter_AddRefs(newCell));
  1704. NS_ENSURE_SUCCESS(rv, rv);
  1705. if (!newCell) {
  1706. return NS_OK;
  1707. }
  1708. if (aNewCell) {
  1709. NS_ADDREF(*aNewCell = newCell.get());
  1710. }
  1711. return CopyCellBackgroundColor(newCell, cell2);
  1712. }
  1713. NS_IMETHODIMP
  1714. HTMLEditor::SwitchTableCellHeaderType(nsIDOMElement* aSourceCell,
  1715. nsIDOMElement** aNewCell)
  1716. {
  1717. nsCOMPtr<Element> sourceCell = do_QueryInterface(aSourceCell);
  1718. NS_ENSURE_TRUE(sourceCell, NS_ERROR_NULL_POINTER);
  1719. AutoEditBatch beginBatching(this);
  1720. // Prevent auto insertion of BR in new cell created by ReplaceContainer
  1721. AutoRules beginRulesSniffing(this, EditAction::insertNode, nsIEditor::eNext);
  1722. // Save current selection to restore when done
  1723. // This is needed so ReplaceContainer can monitor selection
  1724. // when replacing nodes
  1725. RefPtr<Selection> selection = GetSelection();
  1726. NS_ENSURE_TRUE(selection, NS_ERROR_FAILURE);
  1727. AutoSelectionRestorer selectionRestorer(selection, this);
  1728. // Set to the opposite of current type
  1729. nsCOMPtr<nsIAtom> atom = EditorBase::GetTag(aSourceCell);
  1730. nsIAtom* newCellType = atom == nsGkAtoms::td ? nsGkAtoms::th : nsGkAtoms::td;
  1731. // This creates new node, moves children, copies attributes (true)
  1732. // and manages the selection!
  1733. nsCOMPtr<Element> newNode = ReplaceContainer(sourceCell, newCellType,
  1734. nullptr, nullptr, EditorBase::eCloneAttributes);
  1735. NS_ENSURE_TRUE(newNode, NS_ERROR_FAILURE);
  1736. // Return the new cell
  1737. if (aNewCell) {
  1738. nsCOMPtr<nsIDOMElement> newElement = do_QueryInterface(newNode);
  1739. *aNewCell = newElement.get();
  1740. NS_ADDREF(*aNewCell);
  1741. }
  1742. return NS_OK;
  1743. }
  1744. NS_IMETHODIMP
  1745. HTMLEditor::JoinTableCells(bool aMergeNonContiguousContents)
  1746. {
  1747. nsCOMPtr<nsIDOMElement> table;
  1748. nsCOMPtr<nsIDOMElement> targetCell;
  1749. int32_t startRowIndex, startColIndex, rowSpan, colSpan, actualRowSpan, actualColSpan;
  1750. bool isSelected;
  1751. nsCOMPtr<nsIDOMElement> cell2;
  1752. int32_t startRowIndex2, startColIndex2, rowSpan2, colSpan2, actualRowSpan2, actualColSpan2;
  1753. bool isSelected2;
  1754. // Get cell, table, etc. at selection anchor node
  1755. nsresult rv = GetCellContext(nullptr,
  1756. getter_AddRefs(table),
  1757. getter_AddRefs(targetCell),
  1758. nullptr, nullptr,
  1759. &startRowIndex, &startColIndex);
  1760. NS_ENSURE_SUCCESS(rv, rv);
  1761. if (!table || !targetCell) {
  1762. return NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND;
  1763. }
  1764. AutoEditBatch beginBatching(this);
  1765. //Don't let Rules System change the selection
  1766. AutoTransactionsConserveSelection dontChangeSelection(this);
  1767. // Note: We dont' use AutoSelectionSetterAfterTableEdit here so the selection
  1768. // is retained after joining. This leaves the target cell selected
  1769. // as well as the "non-contiguous" cells, so user can see what happened.
  1770. nsCOMPtr<nsIDOMElement> firstCell;
  1771. int32_t firstRowIndex, firstColIndex;
  1772. rv = GetFirstSelectedCellInTable(&firstRowIndex, &firstColIndex,
  1773. getter_AddRefs(firstCell));
  1774. NS_ENSURE_SUCCESS(rv, rv);
  1775. bool joinSelectedCells = false;
  1776. if (firstCell) {
  1777. nsCOMPtr<nsIDOMElement> secondCell;
  1778. rv = GetNextSelectedCell(nullptr, getter_AddRefs(secondCell));
  1779. NS_ENSURE_SUCCESS(rv, rv);
  1780. // If only one cell is selected, join with cell to the right
  1781. joinSelectedCells = (secondCell != nullptr);
  1782. }
  1783. if (joinSelectedCells) {
  1784. // We have selected cells: Join just contiguous cells
  1785. // and just merge contents if not contiguous
  1786. int32_t rowCount, colCount;
  1787. rv = GetTableSize(table, &rowCount, &colCount);
  1788. NS_ENSURE_SUCCESS(rv, rv);
  1789. // Get spans for cell we will merge into
  1790. int32_t firstRowSpan, firstColSpan;
  1791. rv = GetCellSpansAt(table, firstRowIndex, firstColIndex,
  1792. firstRowSpan, firstColSpan);
  1793. NS_ENSURE_SUCCESS(rv, rv);
  1794. // This defines the last indexes along the "edges"
  1795. // of the contiguous block of cells, telling us
  1796. // that we can join adjacent cells to the block
  1797. // Start with same as the first values,
  1798. // then expand as we find adjacent selected cells
  1799. int32_t lastRowIndex = firstRowIndex;
  1800. int32_t lastColIndex = firstColIndex;
  1801. int32_t rowIndex, colIndex;
  1802. // First pass: Determine boundaries of contiguous rectangular block
  1803. // that we will join into one cell,
  1804. // favoring adjacent cells in the same row
  1805. for (rowIndex = firstRowIndex; rowIndex <= lastRowIndex; rowIndex++) {
  1806. int32_t currentRowCount = rowCount;
  1807. // Be sure each row doesn't have rowspan errors
  1808. rv = FixBadRowSpan(table, rowIndex, rowCount);
  1809. NS_ENSURE_SUCCESS(rv, rv);
  1810. // Adjust rowcount by number of rows we removed
  1811. lastRowIndex -= (currentRowCount-rowCount);
  1812. bool cellFoundInRow = false;
  1813. bool lastRowIsSet = false;
  1814. int32_t lastColInRow = 0;
  1815. int32_t firstColInRow = firstColIndex;
  1816. for (colIndex = firstColIndex; colIndex < colCount;
  1817. colIndex += std::max(actualColSpan2, 1)) {
  1818. rv = GetCellDataAt(table, rowIndex, colIndex, getter_AddRefs(cell2),
  1819. &startRowIndex2, &startColIndex2,
  1820. &rowSpan2, &colSpan2,
  1821. &actualRowSpan2, &actualColSpan2, &isSelected2);
  1822. NS_ENSURE_SUCCESS(rv, rv);
  1823. if (isSelected2) {
  1824. if (!cellFoundInRow) {
  1825. // We've just found the first selected cell in this row
  1826. firstColInRow = colIndex;
  1827. }
  1828. if (rowIndex > firstRowIndex && firstColInRow != firstColIndex) {
  1829. // We're in at least the second row,
  1830. // but left boundary is "ragged" (not the same as 1st row's start)
  1831. //Let's just end block on previous row
  1832. // and keep previous lastColIndex
  1833. //TODO: We could try to find the Maximum firstColInRow
  1834. // so our block can still extend down more rows?
  1835. lastRowIndex = std::max(0,rowIndex - 1);
  1836. lastRowIsSet = true;
  1837. break;
  1838. }
  1839. // Save max selected column in this row, including extra colspan
  1840. lastColInRow = colIndex + (actualColSpan2-1);
  1841. cellFoundInRow = true;
  1842. } else if (cellFoundInRow) {
  1843. // No cell or not selected, but at least one cell in row was found
  1844. if (rowIndex > (firstRowIndex + 1) && colIndex <= lastColIndex) {
  1845. // Cell is in a column less than current right border in
  1846. // the third or higher selected row, so stop block at the previous row
  1847. lastRowIndex = std::max(0,rowIndex - 1);
  1848. lastRowIsSet = true;
  1849. }
  1850. // We're done with this row
  1851. break;
  1852. }
  1853. } // End of column loop
  1854. // Done with this row
  1855. if (cellFoundInRow) {
  1856. if (rowIndex == firstRowIndex) {
  1857. // First row always initializes the right boundary
  1858. lastColIndex = lastColInRow;
  1859. }
  1860. // If we didn't determine last row above...
  1861. if (!lastRowIsSet) {
  1862. if (colIndex < lastColIndex) {
  1863. // (don't think we ever get here?)
  1864. // Cell is in a column less than current right boundary,
  1865. // so stop block at the previous row
  1866. lastRowIndex = std::max(0,rowIndex - 1);
  1867. } else {
  1868. // Go on to examine next row
  1869. lastRowIndex = rowIndex+1;
  1870. }
  1871. }
  1872. // Use the minimum col we found so far for right boundary
  1873. lastColIndex = std::min(lastColIndex, lastColInRow);
  1874. } else {
  1875. // No selected cells in this row -- stop at row above
  1876. // and leave last column at its previous value
  1877. lastRowIndex = std::max(0,rowIndex - 1);
  1878. }
  1879. }
  1880. // The list of cells we will delete after joining
  1881. nsTArray<nsCOMPtr<nsIDOMElement> > deleteList;
  1882. // 2nd pass: Do the joining and merging
  1883. for (rowIndex = 0; rowIndex < rowCount; rowIndex++) {
  1884. for (colIndex = 0; colIndex < colCount;
  1885. colIndex += std::max(actualColSpan2, 1)) {
  1886. rv = GetCellDataAt(table, rowIndex, colIndex, getter_AddRefs(cell2),
  1887. &startRowIndex2, &startColIndex2,
  1888. &rowSpan2, &colSpan2,
  1889. &actualRowSpan2, &actualColSpan2, &isSelected2);
  1890. NS_ENSURE_SUCCESS(rv, rv);
  1891. // If this is 0, we are past last cell in row, so exit the loop
  1892. if (!actualColSpan2) {
  1893. break;
  1894. }
  1895. // Merge only selected cells (skip cell we're merging into, of course)
  1896. if (isSelected2 && cell2 != firstCell) {
  1897. if (rowIndex >= firstRowIndex && rowIndex <= lastRowIndex &&
  1898. colIndex >= firstColIndex && colIndex <= lastColIndex) {
  1899. // We are within the join region
  1900. // Problem: It is very tricky to delete cells as we merge,
  1901. // since that will upset the cellmap
  1902. // Instead, build a list of cells to delete and do it later
  1903. NS_ASSERTION(startRowIndex2 == rowIndex, "JoinTableCells: StartRowIndex is in row above");
  1904. if (actualColSpan2 > 1) {
  1905. //Check if cell "hangs" off the boundary because of colspan > 1
  1906. // Use split methods to chop off excess
  1907. int32_t extraColSpan = (startColIndex2 + actualColSpan2) - (lastColIndex+1);
  1908. if ( extraColSpan > 0) {
  1909. rv = SplitCellIntoColumns(table, startRowIndex2, startColIndex2,
  1910. actualColSpan2 - extraColSpan,
  1911. extraColSpan, nullptr);
  1912. NS_ENSURE_SUCCESS(rv, rv);
  1913. }
  1914. }
  1915. rv = MergeCells(firstCell, cell2, false);
  1916. NS_ENSURE_SUCCESS(rv, rv);
  1917. // Add cell to list to delete
  1918. deleteList.AppendElement(cell2.get());
  1919. } else if (aMergeNonContiguousContents) {
  1920. // Cell is outside join region -- just merge the contents
  1921. rv = MergeCells(firstCell, cell2, false);
  1922. NS_ENSURE_SUCCESS(rv, rv);
  1923. }
  1924. }
  1925. }
  1926. }
  1927. // All cell contents are merged. Delete the empty cells we accumulated
  1928. // Prevent rules testing until we're done
  1929. AutoRules beginRulesSniffing(this, EditAction::deleteNode,
  1930. nsIEditor::eNext);
  1931. for (uint32_t i = 0, n = deleteList.Length(); i < n; i++) {
  1932. nsIDOMElement *elementPtr = deleteList[i];
  1933. if (elementPtr) {
  1934. nsCOMPtr<nsIDOMNode> node = do_QueryInterface(elementPtr);
  1935. rv = DeleteNode(node);
  1936. NS_ENSURE_SUCCESS(rv, rv);
  1937. }
  1938. }
  1939. // Cleanup selection: remove ranges where cells were deleted
  1940. RefPtr<Selection> selection = GetSelection();
  1941. NS_ENSURE_TRUE(selection, NS_ERROR_FAILURE);
  1942. int32_t rangeCount;
  1943. rv = selection->GetRangeCount(&rangeCount);
  1944. NS_ENSURE_SUCCESS(rv, rv);
  1945. RefPtr<nsRange> range;
  1946. for (int32_t i = 0; i < rangeCount; i++) {
  1947. range = selection->GetRangeAt(i);
  1948. NS_ENSURE_TRUE(range, NS_ERROR_FAILURE);
  1949. nsCOMPtr<nsIDOMElement> deletedCell;
  1950. GetCellFromRange(range, getter_AddRefs(deletedCell));
  1951. if (!deletedCell) {
  1952. selection->RemoveRange(range);
  1953. rangeCount--;
  1954. i--;
  1955. }
  1956. }
  1957. // Set spans for the cell everthing merged into
  1958. rv = SetRowSpan(firstCell, lastRowIndex-firstRowIndex+1);
  1959. NS_ENSURE_SUCCESS(rv, rv);
  1960. rv = SetColSpan(firstCell, lastColIndex-firstColIndex+1);
  1961. NS_ENSURE_SUCCESS(rv, rv);
  1962. // Fixup disturbances in table layout
  1963. NormalizeTable(table);
  1964. } else {
  1965. // Joining with cell to the right -- get rowspan and colspan data of target cell
  1966. rv = GetCellDataAt(table, startRowIndex, startColIndex,
  1967. getter_AddRefs(targetCell),
  1968. &startRowIndex, &startColIndex, &rowSpan, &colSpan,
  1969. &actualRowSpan, &actualColSpan, &isSelected);
  1970. NS_ENSURE_SUCCESS(rv, rv);
  1971. NS_ENSURE_TRUE(targetCell, NS_ERROR_NULL_POINTER);
  1972. // Get data for cell to the right
  1973. rv = GetCellDataAt(table, startRowIndex, startColIndex + actualColSpan,
  1974. getter_AddRefs(cell2),
  1975. &startRowIndex2, &startColIndex2, &rowSpan2, &colSpan2,
  1976. &actualRowSpan2, &actualColSpan2, &isSelected2);
  1977. NS_ENSURE_SUCCESS(rv, rv);
  1978. if (!cell2) {
  1979. return NS_OK; // Don't fail if there's no cell
  1980. }
  1981. // sanity check
  1982. NS_ASSERTION((startRowIndex >= startRowIndex2),"JoinCells: startRowIndex < startRowIndex2");
  1983. // Figure out span of merged cell starting from target's starting row
  1984. // to handle case of merged cell starting in a row above
  1985. int32_t spanAboveMergedCell = startRowIndex - startRowIndex2;
  1986. int32_t effectiveRowSpan2 = actualRowSpan2 - spanAboveMergedCell;
  1987. if (effectiveRowSpan2 > actualRowSpan) {
  1988. // Cell to the right spans into row below target
  1989. // Split off portion below target cell's bottom-most row
  1990. rv = SplitCellIntoRows(table, startRowIndex2, startColIndex2,
  1991. spanAboveMergedCell+actualRowSpan,
  1992. effectiveRowSpan2-actualRowSpan, nullptr);
  1993. NS_ENSURE_SUCCESS(rv, rv);
  1994. }
  1995. // Move contents from cell to the right
  1996. // Delete the cell now only if it starts in the same row
  1997. // and has enough row "height"
  1998. rv = MergeCells(targetCell, cell2,
  1999. (startRowIndex2 == startRowIndex) &&
  2000. (effectiveRowSpan2 >= actualRowSpan));
  2001. NS_ENSURE_SUCCESS(rv, rv);
  2002. if (effectiveRowSpan2 < actualRowSpan) {
  2003. // Merged cell is "shorter"
  2004. // (there are cells(s) below it that are row-spanned by target cell)
  2005. // We could try splitting those cells, but that's REAL messy,
  2006. // so the safest thing to do is NOT really join the cells
  2007. return NS_OK;
  2008. }
  2009. if (spanAboveMergedCell > 0) {
  2010. // Cell we merged started in a row above the target cell
  2011. // Reduce rowspan to give room where target cell will extend its colspan
  2012. rv = SetRowSpan(cell2, spanAboveMergedCell);
  2013. NS_ENSURE_SUCCESS(rv, rv);
  2014. }
  2015. // Reset target cell's colspan to encompass cell to the right
  2016. rv = SetColSpan(targetCell, actualColSpan+actualColSpan2);
  2017. NS_ENSURE_SUCCESS(rv, rv);
  2018. }
  2019. return NS_OK;
  2020. }
  2021. NS_IMETHODIMP
  2022. HTMLEditor::MergeCells(nsCOMPtr<nsIDOMElement> aTargetCell,
  2023. nsCOMPtr<nsIDOMElement> aCellToMerge,
  2024. bool aDeleteCellToMerge)
  2025. {
  2026. nsCOMPtr<dom::Element> targetCell = do_QueryInterface(aTargetCell);
  2027. nsCOMPtr<dom::Element> cellToMerge = do_QueryInterface(aCellToMerge);
  2028. NS_ENSURE_TRUE(targetCell && cellToMerge, NS_ERROR_NULL_POINTER);
  2029. // Prevent rules testing until we're done
  2030. AutoRules beginRulesSniffing(this, EditAction::deleteNode, nsIEditor::eNext);
  2031. // Don't need to merge if cell is empty
  2032. if (!IsEmptyCell(cellToMerge)) {
  2033. // Get index of last child in target cell
  2034. // If we fail or don't have children,
  2035. // we insert at index 0
  2036. int32_t insertIndex = 0;
  2037. // Start inserting just after last child
  2038. uint32_t len = targetCell->GetChildCount();
  2039. if (len == 1 && IsEmptyCell(targetCell)) {
  2040. // Delete the empty node
  2041. nsIContent* cellChild = targetCell->GetFirstChild();
  2042. nsresult rv = DeleteNode(cellChild->AsDOMNode());
  2043. NS_ENSURE_SUCCESS(rv, rv);
  2044. insertIndex = 0;
  2045. } else {
  2046. insertIndex = (int32_t)len;
  2047. }
  2048. // Move the contents
  2049. while (cellToMerge->HasChildren()) {
  2050. nsCOMPtr<nsIDOMNode> cellChild = cellToMerge->GetLastChild()->AsDOMNode();
  2051. nsresult rv = DeleteNode(cellChild);
  2052. NS_ENSURE_SUCCESS(rv, rv);
  2053. rv = InsertNode(cellChild, aTargetCell, insertIndex);
  2054. NS_ENSURE_SUCCESS(rv, rv);
  2055. }
  2056. }
  2057. // Delete cells whose contents were moved
  2058. if (aDeleteCellToMerge) {
  2059. return DeleteNode(aCellToMerge);
  2060. }
  2061. return NS_OK;
  2062. }
  2063. NS_IMETHODIMP
  2064. HTMLEditor::FixBadRowSpan(nsIDOMElement* aTable,
  2065. int32_t aRowIndex,
  2066. int32_t& aNewRowCount)
  2067. {
  2068. NS_ENSURE_TRUE(aTable, NS_ERROR_NULL_POINTER);
  2069. int32_t rowCount, colCount;
  2070. nsresult rv = GetTableSize(aTable, &rowCount, &colCount);
  2071. NS_ENSURE_SUCCESS(rv, rv);
  2072. nsCOMPtr<nsIDOMElement>cell;
  2073. int32_t startRowIndex, startColIndex, rowSpan, colSpan, actualRowSpan, actualColSpan;
  2074. bool isSelected;
  2075. int32_t minRowSpan = -1;
  2076. int32_t colIndex;
  2077. for (colIndex = 0; colIndex < colCount;
  2078. colIndex += std::max(actualColSpan, 1)) {
  2079. rv = GetCellDataAt(aTable, aRowIndex, colIndex, getter_AddRefs(cell),
  2080. &startRowIndex, &startColIndex, &rowSpan, &colSpan,
  2081. &actualRowSpan, &actualColSpan, &isSelected);
  2082. // NOTE: This is a *real* failure.
  2083. // GetCellDataAt passes if cell is missing from cellmap
  2084. if (NS_FAILED(rv)) {
  2085. return rv;
  2086. }
  2087. if (!cell) {
  2088. break;
  2089. }
  2090. if (rowSpan > 0 &&
  2091. startRowIndex == aRowIndex &&
  2092. (rowSpan < minRowSpan || minRowSpan == -1)) {
  2093. minRowSpan = rowSpan;
  2094. }
  2095. NS_ASSERTION((actualColSpan > 0),"ActualColSpan = 0 in FixBadRowSpan");
  2096. }
  2097. if (minRowSpan > 1) {
  2098. // The amount to reduce everyone's rowspan
  2099. // so at least one cell has rowspan = 1
  2100. int32_t rowsReduced = minRowSpan - 1;
  2101. for (colIndex = 0; colIndex < colCount;
  2102. colIndex += std::max(actualColSpan, 1)) {
  2103. rv = GetCellDataAt(aTable, aRowIndex, colIndex, getter_AddRefs(cell),
  2104. &startRowIndex, &startColIndex, &rowSpan, &colSpan,
  2105. &actualRowSpan, &actualColSpan, &isSelected);
  2106. if (NS_FAILED(rv)) {
  2107. return rv;
  2108. }
  2109. // Fixup rowspans only for cells starting in current row
  2110. if (cell && rowSpan > 0 &&
  2111. startRowIndex == aRowIndex &&
  2112. startColIndex == colIndex ) {
  2113. rv = SetRowSpan(cell, rowSpan-rowsReduced);
  2114. if (NS_FAILED(rv)) {
  2115. return rv;
  2116. }
  2117. }
  2118. NS_ASSERTION((actualColSpan > 0),"ActualColSpan = 0 in FixBadRowSpan");
  2119. }
  2120. }
  2121. return GetTableSize(aTable, &aNewRowCount, &colCount);
  2122. }
  2123. NS_IMETHODIMP
  2124. HTMLEditor::FixBadColSpan(nsIDOMElement* aTable,
  2125. int32_t aColIndex,
  2126. int32_t& aNewColCount)
  2127. {
  2128. NS_ENSURE_TRUE(aTable, NS_ERROR_NULL_POINTER);
  2129. int32_t rowCount, colCount;
  2130. nsresult rv = GetTableSize(aTable, &rowCount, &colCount);
  2131. NS_ENSURE_SUCCESS(rv, rv);
  2132. nsCOMPtr<nsIDOMElement> cell;
  2133. int32_t startRowIndex, startColIndex, rowSpan, colSpan, actualRowSpan, actualColSpan;
  2134. bool isSelected;
  2135. int32_t minColSpan = -1;
  2136. int32_t rowIndex;
  2137. for (rowIndex = 0; rowIndex < rowCount;
  2138. rowIndex += std::max(actualRowSpan, 1)) {
  2139. rv = GetCellDataAt(aTable, rowIndex, aColIndex, getter_AddRefs(cell),
  2140. &startRowIndex, &startColIndex, &rowSpan, &colSpan,
  2141. &actualRowSpan, &actualColSpan, &isSelected);
  2142. // NOTE: This is a *real* failure.
  2143. // GetCellDataAt passes if cell is missing from cellmap
  2144. if (NS_FAILED(rv)) {
  2145. return rv;
  2146. }
  2147. if (!cell) {
  2148. break;
  2149. }
  2150. if (colSpan > 0 &&
  2151. startColIndex == aColIndex &&
  2152. (colSpan < minColSpan || minColSpan == -1)) {
  2153. minColSpan = colSpan;
  2154. }
  2155. NS_ASSERTION((actualRowSpan > 0),"ActualRowSpan = 0 in FixBadColSpan");
  2156. }
  2157. if (minColSpan > 1) {
  2158. // The amount to reduce everyone's colspan
  2159. // so at least one cell has colspan = 1
  2160. int32_t colsReduced = minColSpan - 1;
  2161. for (rowIndex = 0; rowIndex < rowCount;
  2162. rowIndex += std::max(actualRowSpan, 1)) {
  2163. rv = GetCellDataAt(aTable, rowIndex, aColIndex, getter_AddRefs(cell),
  2164. &startRowIndex, &startColIndex, &rowSpan, &colSpan,
  2165. &actualRowSpan, &actualColSpan, &isSelected);
  2166. if (NS_FAILED(rv)) {
  2167. return rv;
  2168. }
  2169. // Fixup colspans only for cells starting in current column
  2170. if (cell && colSpan > 0 &&
  2171. startColIndex == aColIndex &&
  2172. startRowIndex == rowIndex) {
  2173. rv = SetColSpan(cell, colSpan-colsReduced);
  2174. if (NS_FAILED(rv)) {
  2175. return rv;
  2176. }
  2177. }
  2178. NS_ASSERTION((actualRowSpan > 0),"ActualRowSpan = 0 in FixBadColSpan");
  2179. }
  2180. }
  2181. return GetTableSize(aTable, &rowCount, &aNewColCount);
  2182. }
  2183. NS_IMETHODIMP
  2184. HTMLEditor::NormalizeTable(nsIDOMElement* aTable)
  2185. {
  2186. RefPtr<Selection> selection = GetSelection();
  2187. NS_ENSURE_TRUE(selection, NS_ERROR_FAILURE);
  2188. nsCOMPtr<nsIDOMElement> table;
  2189. nsresult rv = GetElementOrParentByTagName(NS_LITERAL_STRING("table"),
  2190. aTable, getter_AddRefs(table));
  2191. NS_ENSURE_SUCCESS(rv, rv);
  2192. // Don't fail if we didn't find a table
  2193. NS_ENSURE_TRUE(table, NS_OK);
  2194. int32_t rowCount, colCount, rowIndex, colIndex;
  2195. rv = GetTableSize(table, &rowCount, &colCount);
  2196. NS_ENSURE_SUCCESS(rv, rv);
  2197. // Save current selection
  2198. AutoSelectionRestorer selectionRestorer(selection, this);
  2199. AutoEditBatch beginBatching(this);
  2200. // Prevent auto insertion of BR in new cell until we're done
  2201. AutoRules beginRulesSniffing(this, EditAction::insertNode, nsIEditor::eNext);
  2202. nsCOMPtr<nsIDOMElement> cell;
  2203. int32_t startRowIndex, startColIndex, rowSpan, colSpan, actualRowSpan, actualColSpan;
  2204. bool isSelected;
  2205. // Scan all cells in each row to detect bad rowspan values
  2206. for (rowIndex = 0; rowIndex < rowCount; rowIndex++) {
  2207. rv = FixBadRowSpan(table, rowIndex, rowCount);
  2208. NS_ENSURE_SUCCESS(rv, rv);
  2209. }
  2210. // and same for colspans
  2211. for (colIndex = 0; colIndex < colCount; colIndex++) {
  2212. rv = FixBadColSpan(table, colIndex, colCount);
  2213. NS_ENSURE_SUCCESS(rv, rv);
  2214. }
  2215. // Fill in missing cellmap locations with empty cells
  2216. for (rowIndex = 0; rowIndex < rowCount; rowIndex++) {
  2217. nsCOMPtr<nsIDOMElement> previousCellInRow;
  2218. for (colIndex = 0; colIndex < colCount; colIndex++) {
  2219. rv = GetCellDataAt(table, rowIndex, colIndex, getter_AddRefs(cell),
  2220. &startRowIndex, &startColIndex, &rowSpan, &colSpan,
  2221. &actualRowSpan, &actualColSpan, &isSelected);
  2222. // NOTE: This is a *real* failure.
  2223. // GetCellDataAt passes if cell is missing from cellmap
  2224. if (NS_FAILED(rv)) {
  2225. return rv;
  2226. }
  2227. if (!cell) {
  2228. //We are missing a cell at a cellmap location
  2229. #ifdef DEBUG
  2230. printf("NormalizeTable found missing cell at row=%d, col=%d\n",
  2231. rowIndex, colIndex);
  2232. #endif
  2233. // Add a cell after the previous Cell in the current row
  2234. if (!previousCellInRow) {
  2235. // We don't have any cells in this row -- We are really messed up!
  2236. #ifdef DEBUG
  2237. printf("NormalizeTable found no cells in row=%d, col=%d\n",
  2238. rowIndex, colIndex);
  2239. #endif
  2240. return NS_ERROR_FAILURE;
  2241. }
  2242. // Insert a new cell after (true), and return the new cell to us
  2243. rv = InsertCell(previousCellInRow, 1, 1, true, false,
  2244. getter_AddRefs(cell));
  2245. NS_ENSURE_SUCCESS(rv, rv);
  2246. // Set this so we use returned new "cell" to set previousCellInRow below
  2247. if (cell) {
  2248. startRowIndex = rowIndex;
  2249. }
  2250. }
  2251. // Save the last cell found in the same row we are scanning
  2252. if (startRowIndex == rowIndex) {
  2253. previousCellInRow = cell;
  2254. }
  2255. }
  2256. }
  2257. return NS_OK;
  2258. }
  2259. NS_IMETHODIMP
  2260. HTMLEditor::GetCellIndexes(nsIDOMElement* aCell,
  2261. int32_t* aRowIndex,
  2262. int32_t* aColIndex)
  2263. {
  2264. NS_ENSURE_ARG_POINTER(aRowIndex);
  2265. *aColIndex=0; // initialize out params
  2266. NS_ENSURE_ARG_POINTER(aColIndex);
  2267. *aRowIndex=0;
  2268. if (!aCell) {
  2269. // Get the selected cell or the cell enclosing the selection anchor
  2270. nsCOMPtr<nsIDOMElement> cell;
  2271. nsresult rv = GetElementOrParentByTagName(NS_LITERAL_STRING("td"), nullptr,
  2272. getter_AddRefs(cell));
  2273. if (NS_FAILED(rv) || !cell) {
  2274. return NS_ERROR_FAILURE;
  2275. }
  2276. aCell = cell;
  2277. }
  2278. nsCOMPtr<nsIPresShell> ps = GetPresShell();
  2279. NS_ENSURE_TRUE(ps, NS_ERROR_NOT_INITIALIZED);
  2280. nsCOMPtr<nsIContent> nodeAsContent( do_QueryInterface(aCell) );
  2281. NS_ENSURE_TRUE(nodeAsContent, NS_ERROR_FAILURE);
  2282. // frames are not ref counted, so don't use an nsCOMPtr
  2283. nsIFrame *layoutObject = nodeAsContent->GetPrimaryFrame();
  2284. NS_ENSURE_TRUE(layoutObject, NS_ERROR_FAILURE);
  2285. nsITableCellLayout *cellLayoutObject = do_QueryFrame(layoutObject);
  2286. NS_ENSURE_TRUE(cellLayoutObject, NS_ERROR_FAILURE);
  2287. return cellLayoutObject->GetCellIndexes(*aRowIndex, *aColIndex);
  2288. }
  2289. nsTableWrapperFrame*
  2290. HTMLEditor::GetTableFrame(nsIDOMElement* aTable)
  2291. {
  2292. NS_ENSURE_TRUE(aTable, nullptr);
  2293. nsCOMPtr<nsIContent> nodeAsContent( do_QueryInterface(aTable) );
  2294. NS_ENSURE_TRUE(nodeAsContent, nullptr);
  2295. return do_QueryFrame(nodeAsContent->GetPrimaryFrame());
  2296. }
  2297. //Return actual number of cells (a cell with colspan > 1 counts as just 1)
  2298. int32_t
  2299. HTMLEditor::GetNumberOfCellsInRow(nsIDOMElement* aTable,
  2300. int32_t rowIndex)
  2301. {
  2302. int32_t cellCount = 0;
  2303. nsCOMPtr<nsIDOMElement> cell;
  2304. int32_t colIndex = 0;
  2305. do {
  2306. int32_t startRowIndex, startColIndex, rowSpan, colSpan, actualRowSpan, actualColSpan;
  2307. bool isSelected;
  2308. nsresult rv =
  2309. GetCellDataAt(aTable, rowIndex, colIndex, getter_AddRefs(cell),
  2310. &startRowIndex, &startColIndex, &rowSpan, &colSpan,
  2311. &actualRowSpan, &actualColSpan, &isSelected);
  2312. NS_ENSURE_SUCCESS(rv, 0);
  2313. if (cell) {
  2314. // Only count cells that start in row we are working with
  2315. if (startRowIndex == rowIndex) {
  2316. cellCount++;
  2317. }
  2318. //Next possible location for a cell
  2319. colIndex += actualColSpan;
  2320. } else {
  2321. colIndex++;
  2322. }
  2323. } while (cell);
  2324. return cellCount;
  2325. }
  2326. NS_IMETHODIMP
  2327. HTMLEditor::GetTableSize(nsIDOMElement* aTable,
  2328. int32_t* aRowCount,
  2329. int32_t* aColCount)
  2330. {
  2331. NS_ENSURE_ARG_POINTER(aRowCount);
  2332. NS_ENSURE_ARG_POINTER(aColCount);
  2333. *aRowCount = 0;
  2334. *aColCount = 0;
  2335. nsCOMPtr<nsIDOMElement> table;
  2336. // Get the selected talbe or the table enclosing the selection anchor
  2337. nsresult rv = GetElementOrParentByTagName(NS_LITERAL_STRING("table"), aTable,
  2338. getter_AddRefs(table));
  2339. NS_ENSURE_SUCCESS(rv, rv);
  2340. NS_ENSURE_TRUE(table, NS_ERROR_FAILURE);
  2341. nsTableWrapperFrame* tableFrame = GetTableFrame(table.get());
  2342. NS_ENSURE_TRUE(tableFrame, NS_ERROR_FAILURE);
  2343. *aRowCount = tableFrame->GetRowCount();
  2344. *aColCount = tableFrame->GetColCount();
  2345. return NS_OK;
  2346. }
  2347. NS_IMETHODIMP
  2348. HTMLEditor::GetCellDataAt(nsIDOMElement* aTable,
  2349. int32_t aRowIndex,
  2350. int32_t aColIndex,
  2351. nsIDOMElement** aCell,
  2352. int32_t* aStartRowIndex,
  2353. int32_t* aStartColIndex,
  2354. int32_t* aRowSpan,
  2355. int32_t* aColSpan,
  2356. int32_t* aActualRowSpan,
  2357. int32_t* aActualColSpan,
  2358. bool* aIsSelected)
  2359. {
  2360. NS_ENSURE_ARG_POINTER(aStartRowIndex);
  2361. NS_ENSURE_ARG_POINTER(aStartColIndex);
  2362. NS_ENSURE_ARG_POINTER(aRowSpan);
  2363. NS_ENSURE_ARG_POINTER(aColSpan);
  2364. NS_ENSURE_ARG_POINTER(aActualRowSpan);
  2365. NS_ENSURE_ARG_POINTER(aActualColSpan);
  2366. NS_ENSURE_ARG_POINTER(aIsSelected);
  2367. NS_ENSURE_TRUE(aCell, NS_ERROR_NULL_POINTER);
  2368. *aStartRowIndex = 0;
  2369. *aStartColIndex = 0;
  2370. *aRowSpan = 0;
  2371. *aColSpan = 0;
  2372. *aActualRowSpan = 0;
  2373. *aActualColSpan = 0;
  2374. *aIsSelected = false;
  2375. *aCell = nullptr;
  2376. if (!aTable) {
  2377. // Get the selected table or the table enclosing the selection anchor
  2378. nsCOMPtr<nsIDOMElement> table;
  2379. nsresult rv =
  2380. GetElementOrParentByTagName(NS_LITERAL_STRING("table"), nullptr,
  2381. getter_AddRefs(table));
  2382. NS_ENSURE_SUCCESS(rv, rv);
  2383. if (!table) {
  2384. return NS_ERROR_FAILURE;
  2385. }
  2386. aTable = table;
  2387. }
  2388. nsTableWrapperFrame* tableFrame = GetTableFrame(aTable);
  2389. NS_ENSURE_TRUE(tableFrame, NS_ERROR_FAILURE);
  2390. nsTableCellFrame* cellFrame =
  2391. tableFrame->GetCellFrameAt(aRowIndex, aColIndex);
  2392. if (!cellFrame) {
  2393. return NS_ERROR_FAILURE;
  2394. }
  2395. *aIsSelected = cellFrame->IsSelected();
  2396. *aStartRowIndex = cellFrame->RowIndex();
  2397. *aStartColIndex = cellFrame->ColIndex();
  2398. *aRowSpan = cellFrame->GetRowSpan();
  2399. *aColSpan = cellFrame->GetColSpan();
  2400. *aActualRowSpan = tableFrame->GetEffectiveRowSpanAt(aRowIndex, aColIndex);
  2401. *aActualColSpan = tableFrame->GetEffectiveColSpanAt(aRowIndex, aColIndex);
  2402. nsCOMPtr<nsIDOMElement> domCell = do_QueryInterface(cellFrame->GetContent());
  2403. domCell.forget(aCell);
  2404. return NS_OK;
  2405. }
  2406. // When all you want is the cell
  2407. NS_IMETHODIMP
  2408. HTMLEditor::GetCellAt(nsIDOMElement* aTable,
  2409. int32_t aRowIndex,
  2410. int32_t aColIndex,
  2411. nsIDOMElement** aCell)
  2412. {
  2413. NS_ENSURE_ARG_POINTER(aCell);
  2414. *aCell = nullptr;
  2415. if (!aTable) {
  2416. // Get the selected table or the table enclosing the selection anchor
  2417. nsCOMPtr<nsIDOMElement> table;
  2418. nsresult rv =
  2419. GetElementOrParentByTagName(NS_LITERAL_STRING("table"), nullptr,
  2420. getter_AddRefs(table));
  2421. NS_ENSURE_SUCCESS(rv, rv);
  2422. NS_ENSURE_TRUE(table, NS_ERROR_FAILURE);
  2423. aTable = table;
  2424. }
  2425. nsTableWrapperFrame* tableFrame = GetTableFrame(aTable);
  2426. if (!tableFrame) {
  2427. *aCell = nullptr;
  2428. return NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND;
  2429. }
  2430. nsCOMPtr<nsIDOMElement> domCell =
  2431. do_QueryInterface(tableFrame->GetCellAt(aRowIndex, aColIndex));
  2432. domCell.forget(aCell);
  2433. return NS_OK;
  2434. }
  2435. // When all you want are the rowspan and colspan (not exposed in nsITableEditor)
  2436. NS_IMETHODIMP
  2437. HTMLEditor::GetCellSpansAt(nsIDOMElement* aTable,
  2438. int32_t aRowIndex,
  2439. int32_t aColIndex,
  2440. int32_t& aActualRowSpan,
  2441. int32_t& aActualColSpan)
  2442. {
  2443. nsTableWrapperFrame* tableFrame = GetTableFrame(aTable);
  2444. if (!tableFrame) {
  2445. return NS_ERROR_FAILURE;
  2446. }
  2447. aActualRowSpan = tableFrame->GetEffectiveRowSpanAt(aRowIndex, aColIndex);
  2448. aActualColSpan = tableFrame->GetEffectiveColSpanAt(aRowIndex, aColIndex);
  2449. return NS_OK;
  2450. }
  2451. nsresult
  2452. HTMLEditor::GetCellContext(Selection** aSelection,
  2453. nsIDOMElement** aTable,
  2454. nsIDOMElement** aCell,
  2455. nsIDOMNode** aCellParent,
  2456. int32_t* aCellOffset,
  2457. int32_t* aRowIndex,
  2458. int32_t* aColIndex)
  2459. {
  2460. // Initialize return pointers
  2461. if (aSelection) {
  2462. *aSelection = nullptr;
  2463. }
  2464. if (aTable) {
  2465. *aTable = nullptr;
  2466. }
  2467. if (aCell) {
  2468. *aCell = nullptr;
  2469. }
  2470. if (aCellParent) {
  2471. *aCellParent = nullptr;
  2472. }
  2473. if (aCellOffset) {
  2474. *aCellOffset = 0;
  2475. }
  2476. if (aRowIndex) {
  2477. *aRowIndex = 0;
  2478. }
  2479. if (aColIndex) {
  2480. *aColIndex = 0;
  2481. }
  2482. RefPtr<Selection> selection = GetSelection();
  2483. NS_ENSURE_TRUE(selection, NS_ERROR_FAILURE);
  2484. if (aSelection) {
  2485. *aSelection = selection.get();
  2486. NS_ADDREF(*aSelection);
  2487. }
  2488. nsCOMPtr <nsIDOMElement> table;
  2489. nsCOMPtr <nsIDOMElement> cell;
  2490. // Caller may supply the cell...
  2491. if (aCell && *aCell) {
  2492. cell = *aCell;
  2493. }
  2494. // ...but if not supplied,
  2495. // get cell if it's the child of selection anchor node,
  2496. // or get the enclosing by a cell
  2497. if (!cell) {
  2498. // Find a selected or enclosing table element
  2499. nsCOMPtr<nsIDOMElement> cellOrTableElement;
  2500. int32_t selectedCount;
  2501. nsAutoString tagName;
  2502. nsresult rv =
  2503. GetSelectedOrParentTableElement(tagName, &selectedCount,
  2504. getter_AddRefs(cellOrTableElement));
  2505. NS_ENSURE_SUCCESS(rv, rv);
  2506. if (tagName.EqualsLiteral("table")) {
  2507. // We have a selected table, not a cell
  2508. if (aTable) {
  2509. *aTable = cellOrTableElement.get();
  2510. NS_ADDREF(*aTable);
  2511. }
  2512. return NS_OK;
  2513. }
  2514. if (!tagName.EqualsLiteral("td")) {
  2515. return NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND;
  2516. }
  2517. // We found a cell
  2518. cell = cellOrTableElement;
  2519. }
  2520. if (aCell) {
  2521. *aCell = cell.get();
  2522. NS_ADDREF(*aCell);
  2523. }
  2524. // Get containing table
  2525. nsresult rv = GetElementOrParentByTagName(NS_LITERAL_STRING("table"), cell,
  2526. getter_AddRefs(table));
  2527. NS_ENSURE_SUCCESS(rv, rv);
  2528. // Cell must be in a table, so fail if not found
  2529. NS_ENSURE_TRUE(table, NS_ERROR_FAILURE);
  2530. if (aTable) {
  2531. *aTable = table.get();
  2532. NS_ADDREF(*aTable);
  2533. }
  2534. // Get the rest of the related data only if requested
  2535. if (aRowIndex || aColIndex) {
  2536. int32_t rowIndex, colIndex;
  2537. // Get current cell location so we can put caret back there when done
  2538. rv = GetCellIndexes(cell, &rowIndex, &colIndex);
  2539. if (NS_FAILED(rv)) {
  2540. return rv;
  2541. }
  2542. if (aRowIndex) {
  2543. *aRowIndex = rowIndex;
  2544. }
  2545. if (aColIndex) {
  2546. *aColIndex = colIndex;
  2547. }
  2548. }
  2549. if (aCellParent) {
  2550. nsCOMPtr <nsIDOMNode> cellParent;
  2551. // Get the immediate parent of the cell
  2552. rv = cell->GetParentNode(getter_AddRefs(cellParent));
  2553. NS_ENSURE_SUCCESS(rv, rv);
  2554. // Cell has to have a parent, so fail if not found
  2555. NS_ENSURE_TRUE(cellParent, NS_ERROR_FAILURE);
  2556. *aCellParent = cellParent.get();
  2557. NS_ADDREF(*aCellParent);
  2558. if (aCellOffset) {
  2559. *aCellOffset = GetChildOffset(cell, cellParent);
  2560. }
  2561. }
  2562. return NS_OK;
  2563. }
  2564. nsresult
  2565. HTMLEditor::GetCellFromRange(nsRange* aRange,
  2566. nsIDOMElement** aCell)
  2567. {
  2568. // Note: this might return a node that is outside of the range.
  2569. // Use carefully.
  2570. NS_ENSURE_TRUE(aRange && aCell, NS_ERROR_NULL_POINTER);
  2571. *aCell = nullptr;
  2572. nsCOMPtr<nsIDOMNode> startParent;
  2573. nsresult rv = aRange->GetStartContainer(getter_AddRefs(startParent));
  2574. NS_ENSURE_SUCCESS(rv, rv);
  2575. NS_ENSURE_TRUE(startParent, NS_ERROR_FAILURE);
  2576. uint32_t startOffset = aRange->StartOffset();
  2577. nsCOMPtr<nsIDOMNode> childNode =
  2578. GetChildAt(startParent, static_cast<int32_t>(startOffset));
  2579. // This means selection is probably at a text node (or end of doc?)
  2580. if (!childNode) {
  2581. return NS_ERROR_FAILURE;
  2582. }
  2583. nsCOMPtr<nsIDOMNode> endParent;
  2584. rv = aRange->GetEndContainer(getter_AddRefs(endParent));
  2585. NS_ENSURE_SUCCESS(rv, rv);
  2586. NS_ENSURE_TRUE(startParent, NS_ERROR_FAILURE);
  2587. // If a cell is deleted, the range is collapse
  2588. // (startOffset == aRange->EndOffset())
  2589. // so tell caller the cell wasn't found
  2590. if (startParent == endParent &&
  2591. aRange->EndOffset() == startOffset+1 &&
  2592. HTMLEditUtils::IsTableCell(childNode)) {
  2593. // Should we also test if frame is selected? (Use GetCellDataAt())
  2594. // (Let's not for now -- more efficient)
  2595. nsCOMPtr<nsIDOMElement> cellElement = do_QueryInterface(childNode);
  2596. *aCell = cellElement.get();
  2597. NS_ADDREF(*aCell);
  2598. return NS_OK;
  2599. }
  2600. return NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND;
  2601. }
  2602. NS_IMETHODIMP
  2603. HTMLEditor::GetFirstSelectedCell(nsIDOMRange** aRange,
  2604. nsIDOMElement** aCell)
  2605. {
  2606. NS_ENSURE_TRUE(aCell, NS_ERROR_NULL_POINTER);
  2607. *aCell = nullptr;
  2608. if (aRange) {
  2609. *aRange = nullptr;
  2610. }
  2611. RefPtr<Selection> selection = GetSelection();
  2612. NS_ENSURE_TRUE(selection, NS_ERROR_FAILURE);
  2613. RefPtr<nsRange> range = selection->GetRangeAt(0);
  2614. NS_ENSURE_TRUE(range, NS_ERROR_FAILURE);
  2615. mSelectedCellIndex = 0;
  2616. nsresult rv = GetCellFromRange(range, aCell);
  2617. // Failure here probably means selection is in a text node,
  2618. // so there's no selected cell
  2619. if (NS_FAILED(rv)) {
  2620. return NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND;
  2621. }
  2622. // No cell means range was collapsed (cell was deleted)
  2623. if (!*aCell) {
  2624. return NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND;
  2625. }
  2626. if (aRange) {
  2627. *aRange = range.get();
  2628. NS_ADDREF(*aRange);
  2629. }
  2630. // Setup for next cell
  2631. mSelectedCellIndex = 1;
  2632. return NS_OK;
  2633. }
  2634. NS_IMETHODIMP
  2635. HTMLEditor::GetNextSelectedCell(nsIDOMRange** aRange,
  2636. nsIDOMElement** aCell)
  2637. {
  2638. NS_ENSURE_TRUE(aCell, NS_ERROR_NULL_POINTER);
  2639. *aCell = nullptr;
  2640. if (aRange) {
  2641. *aRange = nullptr;
  2642. }
  2643. RefPtr<Selection> selection = GetSelection();
  2644. NS_ENSURE_TRUE(selection, NS_ERROR_FAILURE);
  2645. int32_t rangeCount = selection->RangeCount();
  2646. // Don't even try if index exceeds range count
  2647. if (mSelectedCellIndex >= rangeCount) {
  2648. return NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND;
  2649. }
  2650. // Scan through ranges to find next valid selected cell
  2651. RefPtr<nsRange> range;
  2652. for (; mSelectedCellIndex < rangeCount; mSelectedCellIndex++) {
  2653. range = selection->GetRangeAt(mSelectedCellIndex);
  2654. NS_ENSURE_TRUE(range, NS_ERROR_FAILURE);
  2655. nsresult rv = GetCellFromRange(range, aCell);
  2656. // Failure here means the range doesn't contain a cell
  2657. NS_ENSURE_SUCCESS(rv, NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND);
  2658. // We found a selected cell
  2659. if (*aCell) {
  2660. break;
  2661. }
  2662. // If we didn't find a cell, continue to next range in selection
  2663. }
  2664. // No cell means all remaining ranges were collapsed (cells were deleted)
  2665. NS_ENSURE_TRUE(*aCell, NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND);
  2666. if (aRange) {
  2667. *aRange = range.get();
  2668. NS_ADDREF(*aRange);
  2669. }
  2670. // Setup for next cell
  2671. mSelectedCellIndex++;
  2672. return NS_OK;
  2673. }
  2674. NS_IMETHODIMP
  2675. HTMLEditor::GetFirstSelectedCellInTable(int32_t* aRowIndex,
  2676. int32_t* aColIndex,
  2677. nsIDOMElement** aCell)
  2678. {
  2679. NS_ENSURE_TRUE(aCell, NS_ERROR_NULL_POINTER);
  2680. *aCell = nullptr;
  2681. if (aRowIndex) {
  2682. *aRowIndex = 0;
  2683. }
  2684. if (aColIndex) {
  2685. *aColIndex = 0;
  2686. }
  2687. nsCOMPtr<nsIDOMElement> cell;
  2688. nsresult rv = GetFirstSelectedCell(nullptr, getter_AddRefs(cell));
  2689. NS_ENSURE_SUCCESS(rv, rv);
  2690. NS_ENSURE_TRUE(cell, NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND);
  2691. *aCell = cell.get();
  2692. NS_ADDREF(*aCell);
  2693. // Also return the row and/or column if requested
  2694. if (aRowIndex || aColIndex) {
  2695. int32_t startRowIndex, startColIndex;
  2696. rv = GetCellIndexes(cell, &startRowIndex, &startColIndex);
  2697. if (NS_FAILED(rv)) {
  2698. return rv;
  2699. }
  2700. if (aRowIndex) {
  2701. *aRowIndex = startRowIndex;
  2702. }
  2703. if (aColIndex) {
  2704. *aColIndex = startColIndex;
  2705. }
  2706. }
  2707. return NS_OK;
  2708. }
  2709. NS_IMETHODIMP
  2710. HTMLEditor::SetSelectionAfterTableEdit(nsIDOMElement* aTable,
  2711. int32_t aRow,
  2712. int32_t aCol,
  2713. int32_t aDirection,
  2714. bool aSelected)
  2715. {
  2716. NS_ENSURE_TRUE(aTable, NS_ERROR_NOT_INITIALIZED);
  2717. RefPtr<Selection> selection = GetSelection();
  2718. if (!selection) {
  2719. return NS_ERROR_FAILURE;
  2720. }
  2721. nsCOMPtr<nsIDOMElement> cell;
  2722. bool done = false;
  2723. do {
  2724. nsresult rv = GetCellAt(aTable, aRow, aCol, getter_AddRefs(cell));
  2725. if (NS_FAILED(rv)) {
  2726. break;
  2727. }
  2728. if (cell) {
  2729. if (aSelected) {
  2730. // Reselect the cell
  2731. return SelectElement(cell);
  2732. } else {
  2733. // Set the caret to deepest first child
  2734. // but don't go into nested tables
  2735. // TODO: Should we really be placing the caret at the END
  2736. // of the cell content?
  2737. nsCOMPtr<nsINode> cellNode = do_QueryInterface(cell);
  2738. if (cellNode) {
  2739. CollapseSelectionToDeepestNonTableFirstChild(selection, cellNode);
  2740. }
  2741. return NS_OK;
  2742. }
  2743. } else {
  2744. // Setup index to find another cell in the
  2745. // direction requested, but move in
  2746. // other direction if already at beginning of row or column
  2747. switch (aDirection) {
  2748. case ePreviousColumn:
  2749. if (!aCol) {
  2750. if (aRow > 0) {
  2751. aRow--;
  2752. } else {
  2753. done = true;
  2754. }
  2755. } else {
  2756. aCol--;
  2757. }
  2758. break;
  2759. case ePreviousRow:
  2760. if (!aRow) {
  2761. if (aCol > 0) {
  2762. aCol--;
  2763. } else {
  2764. done = true;
  2765. }
  2766. } else {
  2767. aRow--;
  2768. }
  2769. break;
  2770. default:
  2771. done = true;
  2772. }
  2773. }
  2774. } while (!done);
  2775. // We didn't find a cell
  2776. // Set selection to just before the table
  2777. nsCOMPtr<nsIDOMNode> tableParent;
  2778. nsresult rv = aTable->GetParentNode(getter_AddRefs(tableParent));
  2779. if (NS_SUCCEEDED(rv) && tableParent) {
  2780. int32_t tableOffset = GetChildOffset(aTable, tableParent);
  2781. return selection->Collapse(tableParent, tableOffset);
  2782. }
  2783. // Last resort: Set selection to start of doc
  2784. // (it's very bad to not have a valid selection!)
  2785. return SetSelectionAtDocumentStart(selection);
  2786. }
  2787. NS_IMETHODIMP
  2788. HTMLEditor::GetSelectedOrParentTableElement(nsAString& aTagName,
  2789. int32_t* aSelectedCount,
  2790. nsIDOMElement** aTableElement)
  2791. {
  2792. NS_ENSURE_ARG_POINTER(aTableElement);
  2793. NS_ENSURE_ARG_POINTER(aSelectedCount);
  2794. *aTableElement = nullptr;
  2795. aTagName.Truncate();
  2796. *aSelectedCount = 0;
  2797. RefPtr<Selection> selection = GetSelection();
  2798. NS_ENSURE_TRUE(selection, NS_ERROR_FAILURE);
  2799. // Try to get the first selected cell
  2800. nsCOMPtr<nsIDOMElement> tableOrCellElement;
  2801. nsresult rv = GetFirstSelectedCell(nullptr,
  2802. getter_AddRefs(tableOrCellElement));
  2803. NS_ENSURE_SUCCESS(rv, rv);
  2804. NS_NAMED_LITERAL_STRING(tdName, "td");
  2805. if (tableOrCellElement) {
  2806. // Each cell is in its own selection range,
  2807. // so count signals multiple-cell selection
  2808. rv = selection->GetRangeCount(aSelectedCount);
  2809. NS_ENSURE_SUCCESS(rv, rv);
  2810. aTagName = tdName;
  2811. } else {
  2812. nsCOMPtr<nsIDOMNode> anchorNode;
  2813. rv = selection->GetAnchorNode(getter_AddRefs(anchorNode));
  2814. if (NS_FAILED(rv)) {
  2815. return rv;
  2816. }
  2817. NS_ENSURE_TRUE(anchorNode, NS_ERROR_FAILURE);
  2818. nsCOMPtr<nsIDOMNode> selectedNode;
  2819. // Get child of anchor node, if exists
  2820. bool hasChildren;
  2821. anchorNode->HasChildNodes(&hasChildren);
  2822. if (hasChildren) {
  2823. int32_t anchorOffset;
  2824. rv = selection->GetAnchorOffset(&anchorOffset);
  2825. NS_ENSURE_SUCCESS(rv, rv);
  2826. selectedNode = GetChildAt(anchorNode, anchorOffset);
  2827. if (!selectedNode) {
  2828. selectedNode = anchorNode;
  2829. // If anchor doesn't have a child, we can't be selecting a table element,
  2830. // so don't do the following:
  2831. } else {
  2832. nsCOMPtr<nsIAtom> atom = EditorBase::GetTag(selectedNode);
  2833. if (atom == nsGkAtoms::td) {
  2834. tableOrCellElement = do_QueryInterface(selectedNode);
  2835. aTagName = tdName;
  2836. // Each cell is in its own selection range,
  2837. // so count signals multiple-cell selection
  2838. rv = selection->GetRangeCount(aSelectedCount);
  2839. NS_ENSURE_SUCCESS(rv, rv);
  2840. } else if (atom == nsGkAtoms::table) {
  2841. tableOrCellElement = do_QueryInterface(selectedNode);
  2842. aTagName.AssignLiteral("table");
  2843. *aSelectedCount = 1;
  2844. } else if (atom == nsGkAtoms::tr) {
  2845. tableOrCellElement = do_QueryInterface(selectedNode);
  2846. aTagName.AssignLiteral("tr");
  2847. *aSelectedCount = 1;
  2848. }
  2849. }
  2850. }
  2851. if (!tableOrCellElement) {
  2852. // Didn't find a table element -- find a cell parent
  2853. rv = GetElementOrParentByTagName(tdName, anchorNode,
  2854. getter_AddRefs(tableOrCellElement));
  2855. if (NS_FAILED(rv)) {
  2856. return rv;
  2857. }
  2858. if (tableOrCellElement) {
  2859. aTagName = tdName;
  2860. }
  2861. }
  2862. }
  2863. if (tableOrCellElement) {
  2864. *aTableElement = tableOrCellElement.get();
  2865. NS_ADDREF(*aTableElement);
  2866. }
  2867. return NS_OK;
  2868. }
  2869. NS_IMETHODIMP
  2870. HTMLEditor::GetSelectedCellsType(nsIDOMElement* aElement,
  2871. uint32_t* aSelectionType)
  2872. {
  2873. NS_ENSURE_ARG_POINTER(aSelectionType);
  2874. *aSelectionType = 0;
  2875. // Be sure we have a table element
  2876. // (if aElement is null, this uses selection's anchor node)
  2877. nsCOMPtr<nsIDOMElement> table;
  2878. nsresult rv =
  2879. GetElementOrParentByTagName(NS_LITERAL_STRING("table"), aElement,
  2880. getter_AddRefs(table));
  2881. NS_ENSURE_SUCCESS(rv, rv);
  2882. int32_t rowCount, colCount;
  2883. rv = GetTableSize(table, &rowCount, &colCount);
  2884. NS_ENSURE_SUCCESS(rv, rv);
  2885. // Traverse all selected cells
  2886. nsCOMPtr<nsIDOMElement> selectedCell;
  2887. rv = GetFirstSelectedCell(nullptr, getter_AddRefs(selectedCell));
  2888. NS_ENSURE_SUCCESS(rv, rv);
  2889. if (rv == NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND) {
  2890. return NS_OK;
  2891. }
  2892. // We have at least one selected cell, so set return value
  2893. *aSelectionType = nsISelectionPrivate::TABLESELECTION_CELL;
  2894. // Store indexes of each row/col to avoid duplication of searches
  2895. nsTArray<int32_t> indexArray;
  2896. bool allCellsInRowAreSelected = false;
  2897. bool allCellsInColAreSelected = false;
  2898. while (NS_SUCCEEDED(rv) && selectedCell) {
  2899. // Get the cell's location in the cellmap
  2900. int32_t startRowIndex, startColIndex;
  2901. rv = GetCellIndexes(selectedCell, &startRowIndex, &startColIndex);
  2902. if (NS_FAILED(rv)) {
  2903. return rv;
  2904. }
  2905. if (!indexArray.Contains(startColIndex)) {
  2906. indexArray.AppendElement(startColIndex);
  2907. allCellsInRowAreSelected = AllCellsInRowSelected(table, startRowIndex, colCount);
  2908. // We're done as soon as we fail for any row
  2909. if (!allCellsInRowAreSelected) {
  2910. break;
  2911. }
  2912. }
  2913. rv = GetNextSelectedCell(nullptr, getter_AddRefs(selectedCell));
  2914. }
  2915. if (allCellsInRowAreSelected) {
  2916. *aSelectionType = nsISelectionPrivate::TABLESELECTION_ROW;
  2917. return NS_OK;
  2918. }
  2919. // Test for columns
  2920. // Empty the indexArray
  2921. indexArray.Clear();
  2922. // Start at first cell again
  2923. rv = GetFirstSelectedCell(nullptr, getter_AddRefs(selectedCell));
  2924. while (NS_SUCCEEDED(rv) && selectedCell) {
  2925. // Get the cell's location in the cellmap
  2926. int32_t startRowIndex, startColIndex;
  2927. rv = GetCellIndexes(selectedCell, &startRowIndex, &startColIndex);
  2928. if (NS_FAILED(rv)) {
  2929. return rv;
  2930. }
  2931. if (!indexArray.Contains(startRowIndex)) {
  2932. indexArray.AppendElement(startColIndex);
  2933. allCellsInColAreSelected = AllCellsInColumnSelected(table, startColIndex, rowCount);
  2934. // We're done as soon as we fail for any column
  2935. if (!allCellsInRowAreSelected) {
  2936. break;
  2937. }
  2938. }
  2939. rv = GetNextSelectedCell(nullptr, getter_AddRefs(selectedCell));
  2940. }
  2941. if (allCellsInColAreSelected) {
  2942. *aSelectionType = nsISelectionPrivate::TABLESELECTION_COLUMN;
  2943. }
  2944. return NS_OK;
  2945. }
  2946. bool
  2947. HTMLEditor::AllCellsInRowSelected(nsIDOMElement* aTable,
  2948. int32_t aRowIndex,
  2949. int32_t aNumberOfColumns)
  2950. {
  2951. NS_ENSURE_TRUE(aTable, false);
  2952. int32_t curStartRowIndex, curStartColIndex, rowSpan, colSpan, actualRowSpan, actualColSpan;
  2953. bool isSelected;
  2954. for (int32_t col = 0; col < aNumberOfColumns;
  2955. col += std::max(actualColSpan, 1)) {
  2956. nsCOMPtr<nsIDOMElement> cell;
  2957. nsresult rv = GetCellDataAt(aTable, aRowIndex, col, getter_AddRefs(cell),
  2958. &curStartRowIndex, &curStartColIndex,
  2959. &rowSpan, &colSpan,
  2960. &actualRowSpan, &actualColSpan, &isSelected);
  2961. NS_ENSURE_SUCCESS(rv, false);
  2962. // If no cell, we may have a "ragged" right edge,
  2963. // so return TRUE only if we already found a cell in the row
  2964. NS_ENSURE_TRUE(cell, (col > 0) ? true : false);
  2965. // Return as soon as a non-selected cell is found
  2966. NS_ENSURE_TRUE(isSelected, false);
  2967. NS_ASSERTION((actualColSpan > 0),"ActualColSpan = 0 in AllCellsInRowSelected");
  2968. }
  2969. return true;
  2970. }
  2971. bool
  2972. HTMLEditor::AllCellsInColumnSelected(nsIDOMElement* aTable,
  2973. int32_t aColIndex,
  2974. int32_t aNumberOfRows)
  2975. {
  2976. NS_ENSURE_TRUE(aTable, false);
  2977. int32_t curStartRowIndex, curStartColIndex, rowSpan, colSpan, actualRowSpan, actualColSpan;
  2978. bool isSelected;
  2979. for (int32_t row = 0; row < aNumberOfRows;
  2980. row += std::max(actualRowSpan, 1)) {
  2981. nsCOMPtr<nsIDOMElement> cell;
  2982. nsresult rv = GetCellDataAt(aTable, row, aColIndex, getter_AddRefs(cell),
  2983. &curStartRowIndex, &curStartColIndex,
  2984. &rowSpan, &colSpan,
  2985. &actualRowSpan, &actualColSpan, &isSelected);
  2986. NS_ENSURE_SUCCESS(rv, false);
  2987. // If no cell, we must have a "ragged" right edge on the last column
  2988. // so return TRUE only if we already found a cell in the row
  2989. NS_ENSURE_TRUE(cell, (row > 0) ? true : false);
  2990. // Return as soon as a non-selected cell is found
  2991. NS_ENSURE_TRUE(isSelected, false);
  2992. }
  2993. return true;
  2994. }
  2995. bool
  2996. HTMLEditor::IsEmptyCell(dom::Element* aCell)
  2997. {
  2998. MOZ_ASSERT(aCell);
  2999. // Check if target only contains empty text node or <br>
  3000. nsCOMPtr<nsINode> cellChild = aCell->GetFirstChild();
  3001. if (!cellChild) {
  3002. return false;
  3003. }
  3004. nsCOMPtr<nsINode> nextChild = cellChild->GetNextSibling();
  3005. if (nextChild) {
  3006. return false;
  3007. }
  3008. // We insert a single break into a cell by default
  3009. // to have some place to locate a cursor -- it is dispensable
  3010. if (cellChild->IsHTMLElement(nsGkAtoms::br)) {
  3011. return true;
  3012. }
  3013. bool isEmpty;
  3014. // Or check if no real content
  3015. nsresult rv = IsEmptyNode(cellChild, &isEmpty, false, false);
  3016. NS_ENSURE_SUCCESS(rv, false);
  3017. return isEmpty;
  3018. }
  3019. } // namespace mozilla