nsCellMap.cpp 86 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715
  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 "nsTArray.h"
  6. #include "nsCellMap.h"
  7. #include "nsTableFrame.h"
  8. #include "nsTableCellFrame.h"
  9. #include "nsTableRowFrame.h"
  10. #include "nsTableRowGroupFrame.h"
  11. #include <algorithm>
  12. using namespace mozilla;
  13. static void
  14. SetDamageArea(int32_t aStartCol,
  15. int32_t aStartRow,
  16. int32_t aColCount,
  17. int32_t aRowCount,
  18. TableArea& aDamageArea)
  19. {
  20. NS_ASSERTION(aStartCol >= 0, "negative col index");
  21. NS_ASSERTION(aStartRow >= 0, "negative row index");
  22. NS_ASSERTION(aColCount >= 0, "negative col count");
  23. NS_ASSERTION(aRowCount >= 0, "negative row count");
  24. aDamageArea.StartCol() = aStartCol;
  25. aDamageArea.StartRow() = aStartRow;
  26. aDamageArea.ColCount() = aColCount;
  27. aDamageArea.RowCount() = aRowCount;
  28. }
  29. // Empty static array used for SafeElementAt() calls on mRows.
  30. static nsCellMap::CellDataArray * sEmptyRow;
  31. // CellData
  32. CellData::CellData(nsTableCellFrame* aOrigCell)
  33. {
  34. MOZ_COUNT_CTOR(CellData);
  35. static_assert(sizeof(mOrigCell) == sizeof(mBits),
  36. "mOrigCell and mBits must be the same size");
  37. mOrigCell = aOrigCell;
  38. }
  39. CellData::~CellData()
  40. {
  41. MOZ_COUNT_DTOR(CellData);
  42. }
  43. BCCellData::BCCellData(nsTableCellFrame* aOrigCell)
  44. :CellData(aOrigCell)
  45. {
  46. MOZ_COUNT_CTOR(BCCellData);
  47. }
  48. BCCellData::~BCCellData()
  49. {
  50. MOZ_COUNT_DTOR(BCCellData);
  51. }
  52. // nsTableCellMap
  53. nsTableCellMap::nsTableCellMap(nsTableFrame& aTableFrame,
  54. bool aBorderCollapse)
  55. :mTableFrame(aTableFrame), mFirstMap(nullptr), mBCInfo(nullptr)
  56. {
  57. MOZ_COUNT_CTOR(nsTableCellMap);
  58. nsTableFrame::RowGroupArray orderedRowGroups;
  59. aTableFrame.OrderRowGroups(orderedRowGroups);
  60. nsTableRowGroupFrame* prior = nullptr;
  61. for (uint32_t rgX = 0; rgX < orderedRowGroups.Length(); rgX++) {
  62. nsTableRowGroupFrame* rgFrame = orderedRowGroups[rgX];
  63. InsertGroupCellMap(rgFrame, prior);
  64. prior = rgFrame;
  65. }
  66. if (aBorderCollapse) {
  67. mBCInfo = new BCInfo();
  68. }
  69. }
  70. nsTableCellMap::~nsTableCellMap()
  71. {
  72. MOZ_COUNT_DTOR(nsTableCellMap);
  73. nsCellMap* cellMap = mFirstMap;
  74. while (cellMap) {
  75. nsCellMap* next = cellMap->GetNextSibling();
  76. delete cellMap;
  77. cellMap = next;
  78. }
  79. if (mBCInfo) {
  80. DeleteIEndBEndBorders();
  81. delete mBCInfo;
  82. }
  83. }
  84. // Get the bcData holding the border segments of the iEnd edge of the table
  85. BCData*
  86. nsTableCellMap::GetIEndMostBorder(int32_t aRowIndex)
  87. {
  88. if (!mBCInfo) ABORT1(nullptr);
  89. int32_t numRows = mBCInfo->mIEndBorders.Length();
  90. if (aRowIndex < numRows) {
  91. return &mBCInfo->mIEndBorders.ElementAt(aRowIndex);
  92. }
  93. mBCInfo->mIEndBorders.SetLength(aRowIndex+1);
  94. return &mBCInfo->mIEndBorders.ElementAt(aRowIndex);
  95. }
  96. // Get the bcData holding the border segments of the bEnd edge of the table
  97. BCData*
  98. nsTableCellMap::GetBEndMostBorder(int32_t aColIndex)
  99. {
  100. if (!mBCInfo) ABORT1(nullptr);
  101. int32_t numCols = mBCInfo->mBEndBorders.Length();
  102. if (aColIndex < numCols) {
  103. return &mBCInfo->mBEndBorders.ElementAt(aColIndex);
  104. }
  105. mBCInfo->mBEndBorders.SetLength(aColIndex+1);
  106. return &mBCInfo->mBEndBorders.ElementAt(aColIndex);
  107. }
  108. // delete the borders corresponding to the iEnd and bEnd edges of the table
  109. void
  110. nsTableCellMap::DeleteIEndBEndBorders()
  111. {
  112. if (mBCInfo) {
  113. mBCInfo->mBEndBorders.Clear();
  114. mBCInfo->mIEndBorders.Clear();
  115. }
  116. }
  117. void
  118. nsTableCellMap::InsertGroupCellMap(nsCellMap* aPrevMap,
  119. nsCellMap& aNewMap)
  120. {
  121. nsCellMap* next;
  122. if (aPrevMap) {
  123. next = aPrevMap->GetNextSibling();
  124. aPrevMap->SetNextSibling(&aNewMap);
  125. }
  126. else {
  127. next = mFirstMap;
  128. mFirstMap = &aNewMap;
  129. }
  130. aNewMap.SetNextSibling(next);
  131. }
  132. void nsTableCellMap::InsertGroupCellMap(nsTableRowGroupFrame* aNewGroup,
  133. nsTableRowGroupFrame*& aPrevGroup)
  134. {
  135. nsCellMap* newMap = new nsCellMap(aNewGroup, mBCInfo != nullptr);
  136. nsCellMap* prevMap = nullptr;
  137. nsCellMap* lastMap = mFirstMap;
  138. if (aPrevGroup) {
  139. nsCellMap* map = mFirstMap;
  140. while (map) {
  141. lastMap = map;
  142. if (map->GetRowGroup() == aPrevGroup) {
  143. prevMap = map;
  144. break;
  145. }
  146. map = map->GetNextSibling();
  147. }
  148. }
  149. if (!prevMap) {
  150. if (aPrevGroup) {
  151. prevMap = lastMap;
  152. aPrevGroup = (prevMap) ? prevMap->GetRowGroup() : nullptr;
  153. }
  154. else {
  155. aPrevGroup = nullptr;
  156. }
  157. }
  158. InsertGroupCellMap(prevMap, *newMap);
  159. }
  160. void nsTableCellMap::RemoveGroupCellMap(nsTableRowGroupFrame* aGroup)
  161. {
  162. nsCellMap* map = mFirstMap;
  163. nsCellMap* prior = nullptr;
  164. while (map) {
  165. if (map->GetRowGroup() == aGroup) {
  166. nsCellMap* next = map->GetNextSibling();
  167. if (mFirstMap == map) {
  168. mFirstMap = next;
  169. }
  170. else {
  171. prior->SetNextSibling(next);
  172. }
  173. delete map;
  174. break;
  175. }
  176. prior = map;
  177. map = map->GetNextSibling();
  178. }
  179. }
  180. static nsCellMap*
  181. FindMapFor(const nsTableRowGroupFrame* aRowGroup,
  182. nsCellMap* aStart,
  183. const nsCellMap* aEnd)
  184. {
  185. for (nsCellMap* map = aStart; map != aEnd; map = map->GetNextSibling()) {
  186. if (aRowGroup == map->GetRowGroup()) {
  187. return map;
  188. }
  189. }
  190. return nullptr;
  191. }
  192. nsCellMap*
  193. nsTableCellMap::GetMapFor(const nsTableRowGroupFrame* aRowGroup,
  194. nsCellMap* aStartHint) const
  195. {
  196. NS_PRECONDITION(aRowGroup, "Must have a rowgroup");
  197. NS_ASSERTION(!aRowGroup->GetPrevInFlow(), "GetMapFor called with continuation");
  198. if (aStartHint) {
  199. nsCellMap* map = FindMapFor(aRowGroup, aStartHint, nullptr);
  200. if (map) {
  201. return map;
  202. }
  203. }
  204. nsCellMap* map = FindMapFor(aRowGroup, mFirstMap, aStartHint);
  205. if (map) {
  206. return map;
  207. }
  208. // if aRowGroup is a repeated header or footer find the header or footer it was repeated from
  209. if (aRowGroup->IsRepeatable()) {
  210. nsTableFrame* fifTable = static_cast<nsTableFrame*>(mTableFrame.FirstInFlow());
  211. const nsStyleDisplay* display = aRowGroup->StyleDisplay();
  212. nsTableRowGroupFrame* rgOrig =
  213. (StyleDisplay::TableHeaderGroup == display->mDisplay) ?
  214. fifTable->GetTHead() : fifTable->GetTFoot();
  215. // find the row group cell map using the original header/footer
  216. if (rgOrig && rgOrig != aRowGroup) {
  217. return GetMapFor(rgOrig, aStartHint);
  218. }
  219. }
  220. return nullptr;
  221. }
  222. void
  223. nsTableCellMap::Synchronize(nsTableFrame* aTableFrame)
  224. {
  225. nsTableFrame::RowGroupArray orderedRowGroups;
  226. AutoTArray<nsCellMap*, 8> maps;
  227. aTableFrame->OrderRowGroups(orderedRowGroups);
  228. if (!orderedRowGroups.Length()) {
  229. return;
  230. }
  231. // XXXbz this fails if orderedRowGroups is missing some row groups
  232. // (due to OOM when appending to the array, e.g. -- we leak maps in
  233. // that case).
  234. // Scope |map| outside the loop so we can use it as a hint.
  235. nsCellMap* map = nullptr;
  236. for (uint32_t rgX = 0; rgX < orderedRowGroups.Length(); rgX++) {
  237. nsTableRowGroupFrame* rgFrame = orderedRowGroups[rgX];
  238. map = GetMapFor(static_cast<nsTableRowGroupFrame*>(rgFrame->FirstInFlow()),
  239. map);
  240. if (map) {
  241. if (!maps.AppendElement(map)) {
  242. delete map;
  243. map = nullptr;
  244. NS_WARNING("Could not AppendElement");
  245. break;
  246. }
  247. }
  248. }
  249. if (maps.IsEmpty()) {
  250. MOZ_ASSERT(!mFirstMap);
  251. return;
  252. }
  253. int32_t mapIndex = maps.Length() - 1; // Might end up -1
  254. nsCellMap* nextMap = maps.ElementAt(mapIndex);
  255. nextMap->SetNextSibling(nullptr);
  256. for (mapIndex-- ; mapIndex >= 0; mapIndex--) {
  257. nsCellMap* map = maps.ElementAt(mapIndex);
  258. map->SetNextSibling(nextMap);
  259. nextMap = map;
  260. }
  261. mFirstMap = nextMap;
  262. }
  263. bool
  264. nsTableCellMap::HasMoreThanOneCell(int32_t aRowIndex) const
  265. {
  266. int32_t rowIndex = aRowIndex;
  267. nsCellMap* map = mFirstMap;
  268. while (map) {
  269. if (map->GetRowCount() > rowIndex) {
  270. return map->HasMoreThanOneCell(rowIndex);
  271. }
  272. rowIndex -= map->GetRowCount();
  273. map = map->GetNextSibling();
  274. }
  275. return false;
  276. }
  277. int32_t
  278. nsTableCellMap::GetNumCellsOriginatingInRow(int32_t aRowIndex) const
  279. {
  280. int32_t rowIndex = aRowIndex;
  281. nsCellMap* map = mFirstMap;
  282. while (map) {
  283. if (map->GetRowCount() > rowIndex) {
  284. return map->GetNumCellsOriginatingInRow(rowIndex);
  285. }
  286. rowIndex -= map->GetRowCount();
  287. map = map->GetNextSibling();
  288. }
  289. return 0;
  290. }
  291. int32_t
  292. nsTableCellMap::GetEffectiveRowSpan(int32_t aRowIndex,
  293. int32_t aColIndex) const
  294. {
  295. int32_t rowIndex = aRowIndex;
  296. nsCellMap* map = mFirstMap;
  297. while (map) {
  298. if (map->GetRowCount() > rowIndex) {
  299. return map->GetRowSpan(rowIndex, aColIndex, true);
  300. }
  301. rowIndex -= map->GetRowCount();
  302. map = map->GetNextSibling();
  303. }
  304. NS_NOTREACHED("Bogus row index?");
  305. return 0;
  306. }
  307. int32_t
  308. nsTableCellMap::GetEffectiveColSpan(int32_t aRowIndex,
  309. int32_t aColIndex) const
  310. {
  311. int32_t rowIndex = aRowIndex;
  312. nsCellMap* map = mFirstMap;
  313. while (map) {
  314. if (map->GetRowCount() > rowIndex) {
  315. return map->GetEffectiveColSpan(*this, rowIndex, aColIndex);
  316. }
  317. rowIndex -= map->GetRowCount();
  318. map = map->GetNextSibling();
  319. }
  320. NS_NOTREACHED("Bogus row index?");
  321. return 0;
  322. }
  323. nsTableCellFrame*
  324. nsTableCellMap::GetCellFrame(int32_t aRowIndex,
  325. int32_t aColIndex,
  326. CellData& aData,
  327. bool aUseRowIfOverlap) const
  328. {
  329. int32_t rowIndex = aRowIndex;
  330. nsCellMap* map = mFirstMap;
  331. while (map) {
  332. if (map->GetRowCount() > rowIndex) {
  333. return map->GetCellFrame(rowIndex, aColIndex, aData, aUseRowIfOverlap);
  334. }
  335. rowIndex -= map->GetRowCount();
  336. map = map->GetNextSibling();
  337. }
  338. return nullptr;
  339. }
  340. nsColInfo*
  341. nsTableCellMap::GetColInfoAt(int32_t aColIndex)
  342. {
  343. int32_t numColsToAdd = aColIndex + 1 - mCols.Length();
  344. if (numColsToAdd > 0) {
  345. AddColsAtEnd(numColsToAdd); // XXX this could fail to add cols in theory
  346. }
  347. return &mCols.ElementAt(aColIndex);
  348. }
  349. int32_t
  350. nsTableCellMap::GetRowCount() const
  351. {
  352. int32_t numRows = 0;
  353. nsCellMap* map = mFirstMap;
  354. while (map) {
  355. numRows += map->GetRowCount();
  356. map = map->GetNextSibling();
  357. }
  358. return numRows;
  359. }
  360. CellData*
  361. nsTableCellMap::GetDataAt(int32_t aRowIndex,
  362. int32_t aColIndex) const
  363. {
  364. int32_t rowIndex = aRowIndex;
  365. nsCellMap* map = mFirstMap;
  366. while (map) {
  367. if (map->GetRowCount() > rowIndex) {
  368. return map->GetDataAt(rowIndex, aColIndex);
  369. }
  370. rowIndex -= map->GetRowCount();
  371. map = map->GetNextSibling();
  372. }
  373. return nullptr;
  374. }
  375. void
  376. nsTableCellMap::AddColsAtEnd(uint32_t aNumCols)
  377. {
  378. if (!mCols.AppendElements(aNumCols)) {
  379. NS_WARNING("Could not AppendElement");
  380. }
  381. if (mBCInfo) {
  382. if (!mBCInfo->mBEndBorders.AppendElements(aNumCols)) {
  383. NS_WARNING("Could not AppendElement");
  384. }
  385. }
  386. }
  387. void
  388. nsTableCellMap::RemoveColsAtEnd()
  389. {
  390. // Remove the cols at the end which don't have originating cells or cells spanning
  391. // into them. Only do this if the col was created as eColAnonymousCell
  392. int32_t numCols = GetColCount();
  393. int32_t lastGoodColIndex = mTableFrame.GetIndexOfLastRealCol();
  394. for (int32_t colX = numCols - 1; (colX >= 0) && (colX > lastGoodColIndex); colX--) {
  395. nsColInfo& colInfo = mCols.ElementAt(colX);
  396. if ((colInfo.mNumCellsOrig <= 0) && (colInfo.mNumCellsSpan <= 0)) {
  397. mCols.RemoveElementAt(colX);
  398. if (mBCInfo) {
  399. int32_t count = mBCInfo->mBEndBorders.Length();
  400. if (colX < count) {
  401. mBCInfo->mBEndBorders.RemoveElementAt(colX);
  402. }
  403. }
  404. }
  405. else break; // only remove until we encounter the 1st valid one
  406. }
  407. }
  408. void
  409. nsTableCellMap::ClearCols()
  410. {
  411. mCols.Clear();
  412. if (mBCInfo)
  413. mBCInfo->mBEndBorders.Clear();
  414. }
  415. void
  416. nsTableCellMap::InsertRows(nsTableRowGroupFrame* aParent,
  417. nsTArray<nsTableRowFrame*>& aRows,
  418. int32_t aFirstRowIndex,
  419. bool aConsiderSpans,
  420. TableArea& aDamageArea)
  421. {
  422. int32_t numNewRows = aRows.Length();
  423. if ((numNewRows <= 0) || (aFirstRowIndex < 0)) ABORT0();
  424. int32_t rowIndex = aFirstRowIndex;
  425. int32_t rgStartRowIndex = 0;
  426. nsCellMap* cellMap = mFirstMap;
  427. while (cellMap) {
  428. nsTableRowGroupFrame* rg = cellMap->GetRowGroup();
  429. if (rg == aParent) {
  430. cellMap->InsertRows(*this, aRows, rowIndex, aConsiderSpans,
  431. rgStartRowIndex, aDamageArea);
  432. #ifdef DEBUG_TABLE_CELLMAP
  433. Dump("after InsertRows");
  434. #endif
  435. if (mBCInfo) {
  436. int32_t count = mBCInfo->mIEndBorders.Length();
  437. if (aFirstRowIndex < count) {
  438. for (int32_t rowX = aFirstRowIndex; rowX < aFirstRowIndex + numNewRows; rowX++) {
  439. mBCInfo->mIEndBorders.InsertElementAt(rowX);
  440. }
  441. }
  442. else {
  443. GetIEndMostBorder(aFirstRowIndex); // this will create missing entries
  444. for (int32_t rowX = aFirstRowIndex + 1; rowX < aFirstRowIndex + numNewRows; rowX++) {
  445. mBCInfo->mIEndBorders.AppendElement();
  446. }
  447. }
  448. }
  449. return;
  450. }
  451. int32_t rowCount = cellMap->GetRowCount();
  452. rgStartRowIndex += rowCount;
  453. rowIndex -= rowCount;
  454. cellMap = cellMap->GetNextSibling();
  455. }
  456. NS_ERROR("Attempt to insert row into wrong map.");
  457. }
  458. void
  459. nsTableCellMap::RemoveRows(int32_t aFirstRowIndex,
  460. int32_t aNumRowsToRemove,
  461. bool aConsiderSpans,
  462. TableArea& aDamageArea)
  463. {
  464. int32_t rowIndex = aFirstRowIndex;
  465. int32_t rgStartRowIndex = 0;
  466. nsCellMap* cellMap = mFirstMap;
  467. while (cellMap) {
  468. int32_t rowCount = cellMap->GetRowCount();
  469. if (rowCount > rowIndex) {
  470. cellMap->RemoveRows(*this, rowIndex, aNumRowsToRemove, aConsiderSpans,
  471. rgStartRowIndex, aDamageArea);
  472. if (mBCInfo) {
  473. for (int32_t rowX = aFirstRowIndex + aNumRowsToRemove - 1; rowX >= aFirstRowIndex; rowX--) {
  474. if (uint32_t(rowX) < mBCInfo->mIEndBorders.Length()) {
  475. mBCInfo->mIEndBorders.RemoveElementAt(rowX);
  476. }
  477. }
  478. }
  479. break;
  480. }
  481. rgStartRowIndex += rowCount;
  482. rowIndex -= rowCount;
  483. cellMap = cellMap->GetNextSibling();
  484. }
  485. #ifdef DEBUG_TABLE_CELLMAP
  486. Dump("after RemoveRows");
  487. #endif
  488. }
  489. CellData*
  490. nsTableCellMap::AppendCell(nsTableCellFrame& aCellFrame,
  491. int32_t aRowIndex,
  492. bool aRebuildIfNecessary,
  493. TableArea& aDamageArea)
  494. {
  495. MOZ_ASSERT(&aCellFrame == aCellFrame.FirstInFlow(),
  496. "invalid call on continuing frame");
  497. nsIFrame* rgFrame = aCellFrame.GetParent(); // get the row
  498. if (!rgFrame) return 0;
  499. rgFrame = rgFrame->GetParent(); // get the row group
  500. if (!rgFrame) return 0;
  501. CellData* result = nullptr;
  502. int32_t rowIndex = aRowIndex;
  503. int32_t rgStartRowIndex = 0;
  504. nsCellMap* cellMap = mFirstMap;
  505. while (cellMap) {
  506. if (cellMap->GetRowGroup() == rgFrame) {
  507. result = cellMap->AppendCell(*this, &aCellFrame, rowIndex,
  508. aRebuildIfNecessary, rgStartRowIndex,
  509. aDamageArea);
  510. break;
  511. }
  512. int32_t rowCount = cellMap->GetRowCount();
  513. rgStartRowIndex += rowCount;
  514. rowIndex -= rowCount;
  515. cellMap = cellMap->GetNextSibling();
  516. }
  517. #ifdef DEBUG_TABLE_CELLMAP
  518. Dump("after AppendCell");
  519. #endif
  520. return result;
  521. }
  522. void
  523. nsTableCellMap::InsertCells(nsTArray<nsTableCellFrame*>& aCellFrames,
  524. int32_t aRowIndex,
  525. int32_t aColIndexBefore,
  526. TableArea& aDamageArea)
  527. {
  528. int32_t rowIndex = aRowIndex;
  529. int32_t rgStartRowIndex = 0;
  530. nsCellMap* cellMap = mFirstMap;
  531. while (cellMap) {
  532. int32_t rowCount = cellMap->GetRowCount();
  533. if (rowCount > rowIndex) {
  534. cellMap->InsertCells(*this, aCellFrames, rowIndex, aColIndexBefore,
  535. rgStartRowIndex, aDamageArea);
  536. break;
  537. }
  538. rgStartRowIndex += rowCount;
  539. rowIndex -= rowCount;
  540. cellMap = cellMap->GetNextSibling();
  541. }
  542. #ifdef DEBUG_TABLE_CELLMAP
  543. Dump("after InsertCells");
  544. #endif
  545. }
  546. void
  547. nsTableCellMap::RemoveCell(nsTableCellFrame* aCellFrame,
  548. int32_t aRowIndex,
  549. TableArea& aDamageArea)
  550. {
  551. if (!aCellFrame) ABORT0();
  552. MOZ_ASSERT(aCellFrame == aCellFrame->FirstInFlow(),
  553. "invalid call on continuing frame");
  554. int32_t rowIndex = aRowIndex;
  555. int32_t rgStartRowIndex = 0;
  556. nsCellMap* cellMap = mFirstMap;
  557. while (cellMap) {
  558. int32_t rowCount = cellMap->GetRowCount();
  559. if (rowCount > rowIndex) {
  560. cellMap->RemoveCell(*this, aCellFrame, rowIndex, rgStartRowIndex,
  561. aDamageArea);
  562. #ifdef DEBUG_TABLE_CELLMAP
  563. Dump("after RemoveCell");
  564. #endif
  565. return;
  566. }
  567. rgStartRowIndex += rowCount;
  568. rowIndex -= rowCount;
  569. cellMap = cellMap->GetNextSibling();
  570. }
  571. // if we reach this point - the cell did not get removed, the caller of this routine
  572. // will delete the cell and the cellmap will probably hold a reference to
  573. // the deleted cell which will cause a subsequent crash when this cell is
  574. // referenced later
  575. NS_ERROR("nsTableCellMap::RemoveCell - could not remove cell");
  576. }
  577. void
  578. nsTableCellMap::RebuildConsideringCells(nsCellMap* aCellMap,
  579. nsTArray<nsTableCellFrame*>* aCellFrames,
  580. int32_t aRowIndex,
  581. int32_t aColIndex,
  582. bool aInsert,
  583. TableArea& aDamageArea)
  584. {
  585. int32_t numOrigCols = GetColCount();
  586. ClearCols();
  587. nsCellMap* cellMap = mFirstMap;
  588. int32_t rowCount = 0;
  589. while (cellMap) {
  590. if (cellMap == aCellMap) {
  591. cellMap->RebuildConsideringCells(*this, numOrigCols, aCellFrames,
  592. aRowIndex, aColIndex, aInsert);
  593. }
  594. else {
  595. cellMap->RebuildConsideringCells(*this, numOrigCols, nullptr, -1, 0,
  596. false);
  597. }
  598. rowCount += cellMap->GetRowCount();
  599. cellMap = cellMap->GetNextSibling();
  600. }
  601. SetDamageArea(0, 0, GetColCount(), rowCount, aDamageArea);
  602. }
  603. void
  604. nsTableCellMap::RebuildConsideringRows(nsCellMap* aCellMap,
  605. int32_t aStartRowIndex,
  606. nsTArray<nsTableRowFrame*>* aRowsToInsert,
  607. int32_t aNumRowsToRemove,
  608. TableArea& aDamageArea)
  609. {
  610. NS_PRECONDITION(!aRowsToInsert || aNumRowsToRemove == 0,
  611. "Can't handle both removing and inserting rows at once");
  612. int32_t numOrigCols = GetColCount();
  613. ClearCols();
  614. nsCellMap* cellMap = mFirstMap;
  615. int32_t rowCount = 0;
  616. while (cellMap) {
  617. if (cellMap == aCellMap) {
  618. cellMap->RebuildConsideringRows(*this, aStartRowIndex, aRowsToInsert,
  619. aNumRowsToRemove);
  620. }
  621. else {
  622. cellMap->RebuildConsideringCells(*this, numOrigCols, nullptr, -1, 0,
  623. false);
  624. }
  625. rowCount += cellMap->GetRowCount();
  626. cellMap = cellMap->GetNextSibling();
  627. }
  628. SetDamageArea(0, 0, GetColCount(), rowCount, aDamageArea);
  629. }
  630. int32_t
  631. nsTableCellMap::GetNumCellsOriginatingInCol(int32_t aColIndex) const
  632. {
  633. int32_t colCount = mCols.Length();
  634. if ((aColIndex >= 0) && (aColIndex < colCount)) {
  635. return mCols.ElementAt(aColIndex).mNumCellsOrig;
  636. }
  637. else {
  638. NS_ERROR("nsCellMap::GetNumCellsOriginatingInCol - bad col index");
  639. return 0;
  640. }
  641. }
  642. #ifdef DEBUG
  643. void
  644. nsTableCellMap::Dump(char* aString) const
  645. {
  646. if (aString)
  647. printf("%s \n", aString);
  648. printf("***** START TABLE CELL MAP DUMP ***** %p\n", (void*)this);
  649. // output col info
  650. int32_t colCount = mCols.Length();
  651. printf ("cols array orig/span-> %p", (void*)this);
  652. for (int32_t colX = 0; colX < colCount; colX++) {
  653. const nsColInfo& colInfo = mCols.ElementAt(colX);
  654. printf ("%d=%d/%d ", colX, colInfo.mNumCellsOrig, colInfo.mNumCellsSpan);
  655. }
  656. printf(" cols in cache %d\n", int(mTableFrame.GetColCache().Length()));
  657. nsCellMap* cellMap = mFirstMap;
  658. while (cellMap) {
  659. cellMap->Dump(nullptr != mBCInfo);
  660. cellMap = cellMap->GetNextSibling();
  661. }
  662. if (nullptr != mBCInfo) {
  663. printf("***** block-end borders *****\n");
  664. nscoord size;
  665. BCBorderOwner owner;
  666. LogicalSide side;
  667. bool segStart;
  668. bool bevel;
  669. int32_t colIndex;
  670. int32_t numCols = mBCInfo->mBEndBorders.Length();
  671. for (int32_t i = 0; i <= 2; i++) {
  672. printf("\n ");
  673. for (colIndex = 0; colIndex < numCols; colIndex++) {
  674. BCData& cd = mBCInfo->mBEndBorders.ElementAt(colIndex);
  675. if (0 == i) {
  676. size = cd.GetBStartEdge(owner, segStart);
  677. printf("t=%d%X%d ", int32_t(size), owner, segStart);
  678. }
  679. else if (1 == i) {
  680. size = cd.GetIStartEdge(owner, segStart);
  681. printf("l=%d%X%d ", int32_t(size), owner, segStart);
  682. }
  683. else {
  684. size = cd.GetCorner(side, bevel);
  685. printf("c=%d%X%d ", int32_t(size), side, bevel);
  686. }
  687. }
  688. BCData& cd = mBCInfo->mBEndIEndCorner;
  689. if (0 == i) {
  690. size = cd.GetBStartEdge(owner, segStart);
  691. printf("t=%d%X%d ", int32_t(size), owner, segStart);
  692. }
  693. else if (1 == i) {
  694. size = cd.GetIStartEdge(owner, segStart);
  695. printf("l=%d%X%d ", int32_t(size), owner, segStart);
  696. }
  697. else {
  698. size = cd.GetCorner(side, bevel);
  699. printf("c=%d%X%d ", int32_t(size), side, bevel);
  700. }
  701. }
  702. printf("\n");
  703. }
  704. printf("***** END TABLE CELL MAP DUMP *****\n");
  705. }
  706. #endif
  707. nsTableCellFrame*
  708. nsTableCellMap::GetCellInfoAt(int32_t aRowIndex,
  709. int32_t aColIndex,
  710. bool* aOriginates,
  711. int32_t* aColSpan) const
  712. {
  713. int32_t rowIndex = aRowIndex;
  714. nsCellMap* cellMap = mFirstMap;
  715. while (cellMap) {
  716. if (cellMap->GetRowCount() > rowIndex) {
  717. return cellMap->GetCellInfoAt(*this, rowIndex, aColIndex, aOriginates, aColSpan);
  718. }
  719. rowIndex -= cellMap->GetRowCount();
  720. cellMap = cellMap->GetNextSibling();
  721. }
  722. return nullptr;
  723. }
  724. int32_t
  725. nsTableCellMap::GetIndexByRowAndColumn(int32_t aRow, int32_t aColumn) const
  726. {
  727. int32_t index = 0;
  728. int32_t colCount = mCols.Length();
  729. int32_t rowIndex = aRow;
  730. nsCellMap* cellMap = mFirstMap;
  731. while (cellMap) {
  732. int32_t rowCount = cellMap->GetRowCount();
  733. if (rowIndex >= rowCount) {
  734. // If the rowCount is less than the rowIndex, this means that the index is
  735. // not within the current map. If so, get the index of the last cell in
  736. // the last row.
  737. rowIndex -= rowCount;
  738. int32_t cellMapIdx = cellMap->GetHighestIndex(colCount);
  739. if (cellMapIdx != -1)
  740. index += cellMapIdx + 1;
  741. } else {
  742. // Index is in valid range for this cellmap, so get the index of rowIndex
  743. // and aColumn.
  744. int32_t cellMapIdx = cellMap->GetIndexByRowAndColumn(colCount, rowIndex,
  745. aColumn);
  746. if (cellMapIdx == -1)
  747. return -1; // no cell at the given row and column.
  748. index += cellMapIdx;
  749. return index; // no need to look through further maps here
  750. }
  751. cellMap = cellMap->GetNextSibling();
  752. }
  753. return -1;
  754. }
  755. void
  756. nsTableCellMap::GetRowAndColumnByIndex(int32_t aIndex,
  757. int32_t *aRow, int32_t *aColumn) const
  758. {
  759. *aRow = -1;
  760. *aColumn = -1;
  761. int32_t colCount = mCols.Length();
  762. int32_t previousRows = 0;
  763. int32_t index = aIndex;
  764. nsCellMap* cellMap = mFirstMap;
  765. while (cellMap) {
  766. int32_t rowCount = cellMap->GetRowCount();
  767. // Determine the highest possible index in this map to see
  768. // if wanted index is in here.
  769. int32_t cellMapIdx = cellMap->GetHighestIndex(colCount);
  770. if (cellMapIdx == -1) {
  771. // The index is not within this map, increase the total row index
  772. // accordingly.
  773. previousRows += rowCount;
  774. } else {
  775. if (index > cellMapIdx) {
  776. // The index is not within this map, so decrease it by the cellMapIdx
  777. // determined index and increase the total row index accordingly.
  778. index -= cellMapIdx + 1;
  779. previousRows += rowCount;
  780. } else {
  781. cellMap->GetRowAndColumnByIndex(colCount, index, aRow, aColumn);
  782. // If there were previous indexes, take them into account.
  783. *aRow += previousRows;
  784. return; // no need to look any further.
  785. }
  786. }
  787. cellMap = cellMap->GetNextSibling();
  788. }
  789. }
  790. bool nsTableCellMap::RowIsSpannedInto(int32_t aRowIndex,
  791. int32_t aNumEffCols) const
  792. {
  793. int32_t rowIndex = aRowIndex;
  794. nsCellMap* cellMap = mFirstMap;
  795. while (cellMap) {
  796. if (cellMap->GetRowCount() > rowIndex) {
  797. return cellMap->RowIsSpannedInto(rowIndex, aNumEffCols);
  798. }
  799. rowIndex -= cellMap->GetRowCount();
  800. cellMap = cellMap->GetNextSibling();
  801. }
  802. return false;
  803. }
  804. bool nsTableCellMap::RowHasSpanningCells(int32_t aRowIndex,
  805. int32_t aNumEffCols) const
  806. {
  807. int32_t rowIndex = aRowIndex;
  808. nsCellMap* cellMap = mFirstMap;
  809. while (cellMap) {
  810. if (cellMap->GetRowCount() > rowIndex) {
  811. return cellMap->RowHasSpanningCells(rowIndex, aNumEffCols);
  812. }
  813. rowIndex -= cellMap->GetRowCount();
  814. cellMap = cellMap->GetNextSibling();
  815. }
  816. return false;
  817. }
  818. void
  819. nsTableCellMap::ResetBStartStart(LogicalSide aSide,
  820. nsCellMap& aCellMap,
  821. uint32_t aRowIndex,
  822. uint32_t aColIndex,
  823. bool aIsBEndIEnd)
  824. {
  825. if (!mBCInfo || aIsBEndIEnd) ABORT0();
  826. BCCellData* cellData;
  827. BCData* bcData = nullptr;
  828. switch(aSide) {
  829. case eLogicalSideBEnd:
  830. aRowIndex++;
  831. MOZ_FALLTHROUGH;
  832. case eLogicalSideBStart:
  833. cellData = (BCCellData*)aCellMap.GetDataAt(aRowIndex, aColIndex);
  834. if (cellData) {
  835. bcData = &cellData->mData;
  836. }
  837. else {
  838. NS_ASSERTION(aSide == eLogicalSideBEnd, "program error");
  839. // try the next row group
  840. nsCellMap* cellMap = aCellMap.GetNextSibling();
  841. if (cellMap) {
  842. cellData = (BCCellData*)cellMap->GetDataAt(0, aColIndex);
  843. if (cellData) {
  844. bcData = &cellData->mData;
  845. }
  846. else {
  847. bcData = GetBEndMostBorder(aColIndex);
  848. }
  849. }
  850. }
  851. break;
  852. case eLogicalSideIEnd:
  853. aColIndex++;
  854. MOZ_FALLTHROUGH;
  855. case eLogicalSideIStart:
  856. cellData = (BCCellData*)aCellMap.GetDataAt(aRowIndex, aColIndex);
  857. if (cellData) {
  858. bcData = &cellData->mData;
  859. }
  860. else {
  861. NS_ASSERTION(aSide == eLogicalSideIEnd, "program error");
  862. bcData = GetIEndMostBorder(aRowIndex);
  863. }
  864. break;
  865. }
  866. if (bcData) {
  867. bcData->SetBStartStart(false);
  868. }
  869. }
  870. // store the aSide border segment at coord = (aRowIndex, aColIndex). For bStart/iStart, store
  871. // the info at coord. For bEnd/iStart store it at the adjacent location so that it is
  872. // bStart/iStart at that location. If the new location is at the iEnd or bEnd edge of the
  873. // table, then store it one of the special arrays (iEnd-most borders, bEnd-most borders).
  874. void
  875. nsTableCellMap::SetBCBorderEdge(LogicalSide aSide,
  876. nsCellMap& aCellMap,
  877. uint32_t aCellMapStart,
  878. uint32_t aRowIndex,
  879. uint32_t aColIndex,
  880. uint32_t aLength,
  881. BCBorderOwner aOwner,
  882. nscoord aSize,
  883. bool aChanged)
  884. {
  885. if (!mBCInfo) ABORT0();
  886. BCCellData* cellData;
  887. int32_t lastIndex, xIndex, yIndex;
  888. int32_t xPos = aColIndex;
  889. int32_t yPos = aRowIndex;
  890. int32_t rgYPos = aRowIndex - aCellMapStart;
  891. bool changed;
  892. switch(aSide) {
  893. case eLogicalSideBEnd:
  894. rgYPos++;
  895. yPos++;
  896. MOZ_FALLTHROUGH;
  897. case eLogicalSideBStart:
  898. lastIndex = xPos + aLength - 1;
  899. for (xIndex = xPos; xIndex <= lastIndex; xIndex++) {
  900. changed = aChanged && (xIndex == xPos);
  901. BCData* bcData = nullptr;
  902. cellData = (BCCellData*)aCellMap.GetDataAt(rgYPos, xIndex);
  903. if (!cellData) {
  904. int32_t numRgRows = aCellMap.GetRowCount();
  905. if (yPos < numRgRows) { // add a dead cell data
  906. TableArea damageArea;
  907. cellData = (BCCellData*)aCellMap.AppendCell(*this, nullptr, rgYPos,
  908. false, 0, damageArea);
  909. if (!cellData) ABORT0();
  910. }
  911. else {
  912. NS_ASSERTION(aSide == eLogicalSideBEnd, "program error");
  913. // try the next non empty row group
  914. nsCellMap* cellMap = aCellMap.GetNextSibling();
  915. while (cellMap && (0 == cellMap->GetRowCount())) {
  916. cellMap = cellMap->GetNextSibling();
  917. }
  918. if (cellMap) {
  919. cellData = (BCCellData*)cellMap->GetDataAt(0, xIndex);
  920. if (!cellData) { // add a dead cell
  921. TableArea damageArea;
  922. cellData = (BCCellData*)cellMap->AppendCell(*this, nullptr, 0,
  923. false, 0,
  924. damageArea);
  925. }
  926. }
  927. else { // must be at the end of the table
  928. bcData = GetBEndMostBorder(xIndex);
  929. }
  930. }
  931. }
  932. if (!bcData && cellData) {
  933. bcData = &cellData->mData;
  934. }
  935. if (bcData) {
  936. bcData->SetBStartEdge(aOwner, aSize, changed);
  937. }
  938. else NS_ERROR("Cellmap: BStart edge not found");
  939. }
  940. break;
  941. case eLogicalSideIEnd:
  942. xPos++;
  943. MOZ_FALLTHROUGH;
  944. case eLogicalSideIStart:
  945. // since bStart, bEnd borders were set, there should already be a cellData entry
  946. lastIndex = rgYPos + aLength - 1;
  947. for (yIndex = rgYPos; yIndex <= lastIndex; yIndex++) {
  948. changed = aChanged && (yIndex == rgYPos);
  949. cellData = (BCCellData*)aCellMap.GetDataAt(yIndex, xPos);
  950. if (cellData) {
  951. cellData->mData.SetIStartEdge(aOwner, aSize, changed);
  952. }
  953. else {
  954. NS_ASSERTION(aSide == eLogicalSideIEnd, "program error");
  955. BCData* bcData = GetIEndMostBorder(yIndex + aCellMapStart);
  956. if (bcData) {
  957. bcData->SetIStartEdge(aOwner, aSize, changed);
  958. }
  959. else NS_ERROR("Cellmap: IStart edge not found");
  960. }
  961. }
  962. break;
  963. }
  964. }
  965. // store corner info (aOwner, aSubSize, aBevel). For aCorner = eBStartIStart, store the info at
  966. // (aRowIndex, aColIndex). For eBStartIEnd, store it in the entry to the iEnd-wards where
  967. // it would be BStartIStart. For eBEndIEnd, store it in the entry to the bEnd-wards. etc.
  968. void
  969. nsTableCellMap::SetBCBorderCorner(Corner aCorner,
  970. nsCellMap& aCellMap,
  971. uint32_t aCellMapStart,
  972. uint32_t aRowIndex,
  973. uint32_t aColIndex,
  974. LogicalSide aOwner,
  975. nscoord aSubSize,
  976. bool aBevel,
  977. bool aIsBEndIEnd)
  978. {
  979. if (!mBCInfo) ABORT0();
  980. if (aIsBEndIEnd) {
  981. mBCInfo->mBEndIEndCorner.SetCorner(aSubSize, aOwner, aBevel);
  982. return;
  983. }
  984. int32_t xPos = aColIndex;
  985. int32_t yPos = aRowIndex;
  986. int32_t rgYPos = aRowIndex - aCellMapStart;
  987. if (eBStartIEnd == aCorner) {
  988. xPos++;
  989. }
  990. else if (eBEndIEnd == aCorner) {
  991. xPos++;
  992. rgYPos++;
  993. yPos++;
  994. }
  995. else if (eBEndIStart == aCorner) {
  996. rgYPos++;
  997. yPos++;
  998. }
  999. BCCellData* cellData = nullptr;
  1000. BCData* bcData = nullptr;
  1001. if (GetColCount() <= xPos) {
  1002. NS_ASSERTION(xPos == GetColCount(), "program error");
  1003. // at the iEnd edge of the table as we checked the corner before
  1004. NS_ASSERTION(!aIsBEndIEnd, "should be handled before");
  1005. bcData = GetIEndMostBorder(yPos);
  1006. }
  1007. else {
  1008. cellData = (BCCellData*)aCellMap.GetDataAt(rgYPos, xPos);
  1009. if (!cellData) {
  1010. int32_t numRgRows = aCellMap.GetRowCount();
  1011. if (yPos < numRgRows) { // add a dead cell data
  1012. TableArea damageArea;
  1013. cellData = (BCCellData*)aCellMap.AppendCell(*this, nullptr, rgYPos,
  1014. false, 0, damageArea);
  1015. }
  1016. else {
  1017. // try the next non empty row group
  1018. nsCellMap* cellMap = aCellMap.GetNextSibling();
  1019. while (cellMap && (0 == cellMap->GetRowCount())) {
  1020. cellMap = cellMap->GetNextSibling();
  1021. }
  1022. if (cellMap) {
  1023. cellData = (BCCellData*)cellMap->GetDataAt(0, xPos);
  1024. if (!cellData) { // add a dead cell
  1025. TableArea damageArea;
  1026. cellData = (BCCellData*)cellMap->AppendCell(*this, nullptr, 0,
  1027. false, 0, damageArea);
  1028. }
  1029. }
  1030. else { // must be at the bEnd of the table
  1031. bcData = GetBEndMostBorder(xPos);
  1032. }
  1033. }
  1034. }
  1035. }
  1036. if (!bcData && cellData) {
  1037. bcData = &cellData->mData;
  1038. }
  1039. if (bcData) {
  1040. bcData->SetCorner(aSubSize, aOwner, aBevel);
  1041. }
  1042. else NS_ERROR("program error: Corner not found");
  1043. }
  1044. nsCellMap::nsCellMap(nsTableRowGroupFrame* aRowGroup, bool aIsBC)
  1045. : mRows(8), mContentRowCount(0), mRowGroupFrame(aRowGroup),
  1046. mNextSibling(nullptr), mIsBC(aIsBC),
  1047. mPresContext(aRowGroup->PresContext())
  1048. {
  1049. MOZ_COUNT_CTOR(nsCellMap);
  1050. NS_ASSERTION(mPresContext, "Must have prescontext");
  1051. }
  1052. nsCellMap::~nsCellMap()
  1053. {
  1054. MOZ_COUNT_DTOR(nsCellMap);
  1055. uint32_t mapRowCount = mRows.Length();
  1056. for (uint32_t rowX = 0; rowX < mapRowCount; rowX++) {
  1057. CellDataArray &row = mRows[rowX];
  1058. uint32_t colCount = row.Length();
  1059. for (uint32_t colX = 0; colX < colCount; colX++) {
  1060. DestroyCellData(row[colX]);
  1061. }
  1062. }
  1063. }
  1064. /* static */
  1065. void
  1066. nsCellMap::Init()
  1067. {
  1068. MOZ_ASSERT(!sEmptyRow, "How did that happen?");
  1069. sEmptyRow = new nsCellMap::CellDataArray();
  1070. }
  1071. /* static */
  1072. void
  1073. nsCellMap::Shutdown()
  1074. {
  1075. delete sEmptyRow;
  1076. sEmptyRow = nullptr;
  1077. }
  1078. nsTableCellFrame*
  1079. nsCellMap::GetCellFrame(int32_t aRowIndexIn,
  1080. int32_t aColIndexIn,
  1081. CellData& aData,
  1082. bool aUseRowIfOverlap) const
  1083. {
  1084. int32_t rowIndex = aRowIndexIn - aData.GetRowSpanOffset();
  1085. int32_t colIndex = aColIndexIn - aData.GetColSpanOffset();
  1086. if (aData.IsOverlap()) {
  1087. if (aUseRowIfOverlap) {
  1088. colIndex = aColIndexIn;
  1089. }
  1090. else {
  1091. rowIndex = aRowIndexIn;
  1092. }
  1093. }
  1094. CellData* data =
  1095. mRows.SafeElementAt(rowIndex, *sEmptyRow).SafeElementAt(colIndex);
  1096. if (data) {
  1097. return data->GetCellFrame();
  1098. }
  1099. return nullptr;
  1100. }
  1101. int32_t
  1102. nsCellMap::GetHighestIndex(int32_t aColCount)
  1103. {
  1104. int32_t index = -1;
  1105. int32_t rowCount = mRows.Length();
  1106. for (int32_t rowIdx = 0; rowIdx < rowCount; rowIdx++) {
  1107. const CellDataArray& row = mRows[rowIdx];
  1108. for (int32_t colIdx = 0; colIdx < aColCount; colIdx++) {
  1109. CellData* data = row.SafeElementAt(colIdx);
  1110. // No data means row doesn't have more cells.
  1111. if (!data)
  1112. break;
  1113. if (data->IsOrig())
  1114. index++;
  1115. }
  1116. }
  1117. return index;
  1118. }
  1119. int32_t
  1120. nsCellMap::GetIndexByRowAndColumn(int32_t aColCount,
  1121. int32_t aRow, int32_t aColumn) const
  1122. {
  1123. if (uint32_t(aRow) >= mRows.Length())
  1124. return -1;
  1125. int32_t index = -1;
  1126. int32_t lastColsIdx = aColCount - 1;
  1127. // Find row index of the cell where row span is started.
  1128. const CellDataArray& row = mRows[aRow];
  1129. CellData* data = row.SafeElementAt(aColumn);
  1130. int32_t origRow = data ? aRow - data->GetRowSpanOffset() : aRow;
  1131. // Calculate cell index.
  1132. for (int32_t rowIdx = 0; rowIdx <= origRow; rowIdx++) {
  1133. const CellDataArray& row = mRows[rowIdx];
  1134. int32_t colCount = (rowIdx == origRow) ? aColumn : lastColsIdx;
  1135. for (int32_t colIdx = 0; colIdx <= colCount; colIdx++) {
  1136. data = row.SafeElementAt(colIdx);
  1137. // No data means row doesn't have more cells.
  1138. if (!data)
  1139. break;
  1140. if (data->IsOrig())
  1141. index++;
  1142. }
  1143. }
  1144. // Given row and column don't point to the cell.
  1145. if (!data)
  1146. return -1;
  1147. return index;
  1148. }
  1149. void
  1150. nsCellMap::GetRowAndColumnByIndex(int32_t aColCount, int32_t aIndex,
  1151. int32_t *aRow, int32_t *aColumn) const
  1152. {
  1153. *aRow = -1;
  1154. *aColumn = -1;
  1155. int32_t index = aIndex;
  1156. int32_t rowCount = mRows.Length();
  1157. for (int32_t rowIdx = 0; rowIdx < rowCount; rowIdx++) {
  1158. const CellDataArray& row = mRows[rowIdx];
  1159. for (int32_t colIdx = 0; colIdx < aColCount; colIdx++) {
  1160. CellData* data = row.SafeElementAt(colIdx);
  1161. // The row doesn't have more cells.
  1162. if (!data)
  1163. break;
  1164. if (data->IsOrig())
  1165. index--;
  1166. if (index < 0) {
  1167. *aRow = rowIdx;
  1168. *aColumn = colIdx;
  1169. return;
  1170. }
  1171. }
  1172. }
  1173. }
  1174. bool nsCellMap::Grow(nsTableCellMap& aMap,
  1175. int32_t aNumRows,
  1176. int32_t aRowIndex)
  1177. {
  1178. NS_ASSERTION(aNumRows >= 1, "Why are we calling this?");
  1179. // Get the number of cols we want to use for preallocating the row arrays.
  1180. int32_t numCols = aMap.GetColCount();
  1181. if (numCols == 0) {
  1182. numCols = 4;
  1183. }
  1184. uint32_t startRowIndex = (aRowIndex >= 0) ? aRowIndex : mRows.Length();
  1185. NS_ASSERTION(startRowIndex <= mRows.Length(), "Missing grow call inbetween");
  1186. return mRows.InsertElementsAt(startRowIndex, aNumRows, numCols) != nullptr;
  1187. }
  1188. void nsCellMap::GrowRow(CellDataArray& aRow,
  1189. int32_t aNumCols)
  1190. {
  1191. // Have to have the cast to get the template to do the right thing.
  1192. aRow.InsertElementsAt(aRow.Length(), aNumCols, (CellData*)nullptr);
  1193. }
  1194. void
  1195. nsCellMap::InsertRows(nsTableCellMap& aMap,
  1196. nsTArray<nsTableRowFrame*>& aRows,
  1197. int32_t aFirstRowIndex,
  1198. bool aConsiderSpans,
  1199. int32_t aRgFirstRowIndex,
  1200. TableArea& aDamageArea)
  1201. {
  1202. int32_t numCols = aMap.GetColCount();
  1203. NS_ASSERTION(aFirstRowIndex >= 0, "nsCellMap::InsertRows called with negative rowIndex");
  1204. if (uint32_t(aFirstRowIndex) > mRows.Length()) {
  1205. // create (aFirstRowIndex - mRows.Length()) empty rows up to aFirstRowIndex
  1206. int32_t numEmptyRows = aFirstRowIndex - mRows.Length();
  1207. if (!Grow(aMap, numEmptyRows)) {
  1208. return;
  1209. }
  1210. }
  1211. if (!aConsiderSpans) {
  1212. // update mContentRowCount, since non-empty rows will be added
  1213. mContentRowCount = std::max(aFirstRowIndex, mContentRowCount);
  1214. ExpandWithRows(aMap, aRows, aFirstRowIndex, aRgFirstRowIndex, aDamageArea);
  1215. return;
  1216. }
  1217. // if any cells span into or out of the row being inserted, then rebuild
  1218. bool spansCauseRebuild = CellsSpanInOrOut(aFirstRowIndex,
  1219. aFirstRowIndex, 0, numCols - 1);
  1220. // update mContentRowCount, since non-empty rows will be added
  1221. mContentRowCount = std::max(aFirstRowIndex, mContentRowCount);
  1222. // if any of the new cells span out of the new rows being added, then rebuild
  1223. // XXX it would be better to only rebuild the portion of the map that follows the new rows
  1224. if (!spansCauseRebuild && (uint32_t(aFirstRowIndex) < mRows.Length())) {
  1225. spansCauseRebuild = CellsSpanOut(aRows);
  1226. }
  1227. if (spansCauseRebuild) {
  1228. aMap.RebuildConsideringRows(this, aFirstRowIndex, &aRows, 0, aDamageArea);
  1229. }
  1230. else {
  1231. ExpandWithRows(aMap, aRows, aFirstRowIndex, aRgFirstRowIndex, aDamageArea);
  1232. }
  1233. }
  1234. void
  1235. nsCellMap::RemoveRows(nsTableCellMap& aMap,
  1236. int32_t aFirstRowIndex,
  1237. int32_t aNumRowsToRemove,
  1238. bool aConsiderSpans,
  1239. int32_t aRgFirstRowIndex,
  1240. TableArea& aDamageArea)
  1241. {
  1242. int32_t numRows = mRows.Length();
  1243. int32_t numCols = aMap.GetColCount();
  1244. if (aFirstRowIndex >= numRows) {
  1245. // reduce the content based row count based on the function arguments
  1246. // as they are known to be real rows even if the cell map did not create
  1247. // rows for them before.
  1248. mContentRowCount -= aNumRowsToRemove;
  1249. return;
  1250. }
  1251. if (!aConsiderSpans) {
  1252. ShrinkWithoutRows(aMap, aFirstRowIndex, aNumRowsToRemove, aRgFirstRowIndex,
  1253. aDamageArea);
  1254. return;
  1255. }
  1256. int32_t endRowIndex = aFirstRowIndex + aNumRowsToRemove - 1;
  1257. if (endRowIndex >= numRows) {
  1258. NS_ERROR("nsCellMap::RemoveRows tried to remove too many rows");
  1259. endRowIndex = numRows - 1;
  1260. }
  1261. bool spansCauseRebuild = CellsSpanInOrOut(aFirstRowIndex, endRowIndex,
  1262. 0, numCols - 1);
  1263. if (spansCauseRebuild) {
  1264. aMap.RebuildConsideringRows(this, aFirstRowIndex, nullptr, aNumRowsToRemove,
  1265. aDamageArea);
  1266. }
  1267. else {
  1268. ShrinkWithoutRows(aMap, aFirstRowIndex, aNumRowsToRemove, aRgFirstRowIndex,
  1269. aDamageArea);
  1270. }
  1271. }
  1272. CellData*
  1273. nsCellMap::AppendCell(nsTableCellMap& aMap,
  1274. nsTableCellFrame* aCellFrame,
  1275. int32_t aRowIndex,
  1276. bool aRebuildIfNecessary,
  1277. int32_t aRgFirstRowIndex,
  1278. TableArea& aDamageArea,
  1279. int32_t* aColToBeginSearch)
  1280. {
  1281. NS_ASSERTION(!!aMap.mBCInfo == mIsBC, "BC state mismatch");
  1282. int32_t origNumMapRows = mRows.Length();
  1283. int32_t origNumCols = aMap.GetColCount();
  1284. bool zeroRowSpan = false;
  1285. int32_t rowSpan = (aCellFrame) ? GetRowSpanForNewCell(aCellFrame, aRowIndex,
  1286. zeroRowSpan) : 1;
  1287. // add new rows if necessary
  1288. int32_t endRowIndex = aRowIndex + rowSpan - 1;
  1289. if (endRowIndex >= origNumMapRows) {
  1290. // XXXbz handle allocation failures?
  1291. Grow(aMap, 1 + endRowIndex - origNumMapRows);
  1292. }
  1293. // get the first null or dead CellData in the desired row. It will equal origNumCols if there are none
  1294. CellData* origData = nullptr;
  1295. int32_t startColIndex = 0;
  1296. if (aColToBeginSearch)
  1297. startColIndex = *aColToBeginSearch;
  1298. for (; startColIndex < origNumCols; startColIndex++) {
  1299. CellData* data = GetDataAt(aRowIndex, startColIndex);
  1300. if (!data)
  1301. break;
  1302. // The border collapse code relies on having multiple dead cell data entries
  1303. // in a row.
  1304. if (data->IsDead() && aCellFrame) {
  1305. origData = data;
  1306. break;
  1307. }
  1308. }
  1309. // We found the place to append the cell, when the next cell is appended
  1310. // the next search does not need to duplicate the search but can start
  1311. // just at the next cell.
  1312. if (aColToBeginSearch)
  1313. *aColToBeginSearch = startColIndex + 1;
  1314. int32_t colSpan = aCellFrame ? aCellFrame->GetColSpan() : 1;
  1315. // if the new cell could potentially span into other rows and collide with
  1316. // originating cells there, we will play it safe and just rebuild the map
  1317. if (aRebuildIfNecessary && (aRowIndex < mContentRowCount - 1) && (rowSpan > 1)) {
  1318. AutoTArray<nsTableCellFrame*, 1> newCellArray;
  1319. newCellArray.AppendElement(aCellFrame);
  1320. aMap.RebuildConsideringCells(this, &newCellArray, aRowIndex, startColIndex, true, aDamageArea);
  1321. return origData;
  1322. }
  1323. mContentRowCount = std::max(mContentRowCount, aRowIndex + 1);
  1324. // add new cols to the table map if necessary
  1325. int32_t endColIndex = startColIndex + colSpan - 1;
  1326. if (endColIndex >= origNumCols) {
  1327. NS_ASSERTION(aCellFrame, "dead cells should not require new columns");
  1328. aMap.AddColsAtEnd(1 + endColIndex - origNumCols);
  1329. }
  1330. // Setup CellData for this cell
  1331. if (origData) {
  1332. NS_ASSERTION(origData->IsDead(), "replacing a non dead cell is a memory leak");
  1333. if (aCellFrame) { // do nothing to replace a dead cell with a dead cell
  1334. origData->Init(aCellFrame);
  1335. // we are replacing a dead cell, increase the number of cells
  1336. // originating at this column
  1337. nsColInfo* colInfo = aMap.GetColInfoAt(startColIndex);
  1338. NS_ASSERTION(colInfo, "access to a non existing column");
  1339. if (colInfo) {
  1340. colInfo->mNumCellsOrig++;
  1341. }
  1342. }
  1343. }
  1344. else {
  1345. origData = AllocCellData(aCellFrame);
  1346. if (!origData) ABORT1(origData);
  1347. SetDataAt(aMap, *origData, aRowIndex, startColIndex);
  1348. }
  1349. if (aRebuildIfNecessary) {
  1350. //the caller depends on the damageArea
  1351. // The special case for zeroRowSpan is to adjust for the '2' in
  1352. // GetRowSpanForNewCell.
  1353. uint32_t height = zeroRowSpan ? endRowIndex - aRowIndex :
  1354. 1 + endRowIndex - aRowIndex;
  1355. SetDamageArea(startColIndex, aRgFirstRowIndex + aRowIndex,
  1356. 1 + endColIndex - startColIndex, height, aDamageArea);
  1357. }
  1358. if (!aCellFrame) {
  1359. return origData;
  1360. }
  1361. // initialize the cell frame
  1362. aCellFrame->SetColIndex(startColIndex);
  1363. // Create CellData objects for the rows that this cell spans. Set
  1364. // their mOrigCell to nullptr and their mSpanData to point to data.
  1365. for (int32_t rowX = aRowIndex; rowX <= endRowIndex; rowX++) {
  1366. // The row at rowX will need to have at least endColIndex columns
  1367. mRows[rowX].SetCapacity(endColIndex);
  1368. for (int32_t colX = startColIndex; colX <= endColIndex; colX++) {
  1369. if ((rowX != aRowIndex) || (colX != startColIndex)) { // skip orig cell data done above
  1370. CellData* cellData = GetDataAt(rowX, colX);
  1371. if (cellData) {
  1372. if (cellData->IsOrig()) {
  1373. NS_ERROR("cannot overlap originating cell");
  1374. continue;
  1375. }
  1376. if (rowX > aRowIndex) { // row spanning into cell
  1377. if (cellData->IsRowSpan()) {
  1378. // do nothing, this can be caused by rowspan which is overlapped
  1379. // by a another cell with a rowspan and a colspan
  1380. }
  1381. else {
  1382. cellData->SetRowSpanOffset(rowX - aRowIndex);
  1383. if (zeroRowSpan) {
  1384. cellData->SetZeroRowSpan(true);
  1385. }
  1386. }
  1387. }
  1388. if (colX > startColIndex) { // col spanning into cell
  1389. if (!cellData->IsColSpan()) {
  1390. if (cellData->IsRowSpan()) {
  1391. cellData->SetOverlap(true);
  1392. }
  1393. cellData->SetColSpanOffset(colX - startColIndex);
  1394. nsColInfo* colInfo = aMap.GetColInfoAt(colX);
  1395. colInfo->mNumCellsSpan++;
  1396. }
  1397. }
  1398. }
  1399. else {
  1400. cellData = AllocCellData(nullptr);
  1401. if (!cellData) return origData;
  1402. if (rowX > aRowIndex) {
  1403. cellData->SetRowSpanOffset(rowX - aRowIndex);
  1404. if (zeroRowSpan) {
  1405. cellData->SetZeroRowSpan(true);
  1406. }
  1407. }
  1408. if (colX > startColIndex) {
  1409. cellData->SetColSpanOffset(colX - startColIndex);
  1410. }
  1411. SetDataAt(aMap, *cellData, rowX, colX);
  1412. }
  1413. }
  1414. }
  1415. }
  1416. #ifdef DEBUG_TABLE_CELLMAP
  1417. printf("appended cell=%p row=%d \n", aCellFrame, aRowIndex);
  1418. aMap.Dump();
  1419. #endif
  1420. return origData;
  1421. }
  1422. bool nsCellMap::CellsSpanOut(nsTArray<nsTableRowFrame*>& aRows) const
  1423. {
  1424. int32_t numNewRows = aRows.Length();
  1425. for (int32_t rowX = 0; rowX < numNewRows; rowX++) {
  1426. nsIFrame* rowFrame = (nsIFrame *) aRows.ElementAt(rowX);
  1427. for (nsIFrame* childFrame : rowFrame->PrincipalChildList()) {
  1428. nsTableCellFrame *cellFrame = do_QueryFrame(childFrame);
  1429. if (cellFrame) {
  1430. bool zeroSpan;
  1431. int32_t rowSpan = GetRowSpanForNewCell(cellFrame, rowX, zeroSpan);
  1432. if (zeroSpan || rowX + rowSpan > numNewRows) {
  1433. return true;
  1434. }
  1435. }
  1436. }
  1437. }
  1438. return false;
  1439. }
  1440. // return true if any cells have rows spans into or out of the region
  1441. // defined by the row and col indices or any cells have colspans into the region
  1442. bool nsCellMap::CellsSpanInOrOut(int32_t aStartRowIndex,
  1443. int32_t aEndRowIndex,
  1444. int32_t aStartColIndex,
  1445. int32_t aEndColIndex) const
  1446. {
  1447. /*
  1448. * this routine will watch the cells adjacent to the region or at the edge
  1449. * they are marked with *. The routine will verify whether they span in or
  1450. * are spanned out.
  1451. *
  1452. * startCol endCol
  1453. * r1c1 r1c2 r1c3 r1c4 r1c5 r1rc6 r1c7
  1454. * startrow r2c1 r2c2 *r2c3 *r2c4 *r2c5 *r2rc6 r2c7
  1455. * endrow r3c1 r3c2 *r3c3 r3c4 r3c5 *r3rc6 r3c7
  1456. * r4c1 r4c2 *r4c3 *r4c4 *r4c5 r4rc6 r4c7
  1457. * r5c1 r5c2 r5c3 r5c4 r5c5 r5rc6 r5c7
  1458. */
  1459. int32_t numRows = mRows.Length(); // use the cellmap rows to determine the
  1460. // current cellmap extent.
  1461. for (int32_t colX = aStartColIndex; colX <= aEndColIndex; colX++) {
  1462. CellData* cellData;
  1463. if (aStartRowIndex > 0) {
  1464. cellData = GetDataAt(aStartRowIndex, colX);
  1465. if (cellData && (cellData->IsRowSpan())) {
  1466. return true; // there is a row span into the region
  1467. }
  1468. if ((aStartRowIndex >= mContentRowCount) && (mContentRowCount > 0)) {
  1469. cellData = GetDataAt(mContentRowCount - 1, colX);
  1470. if (cellData && cellData->IsZeroRowSpan()) {
  1471. return true; // When we expand the zerospan it'll span into our row
  1472. }
  1473. }
  1474. }
  1475. if (aEndRowIndex < numRows - 1) { // is there anything below aEndRowIndex
  1476. cellData = GetDataAt(aEndRowIndex + 1, colX);
  1477. if ((cellData) && (cellData->IsRowSpan())) {
  1478. return true; // there is a row span out of the region
  1479. }
  1480. }
  1481. else {
  1482. cellData = GetDataAt(aEndRowIndex, colX);
  1483. if ((cellData) && (cellData->IsRowSpan()) && (mContentRowCount < numRows)) {
  1484. return true; // this cell might be the cause of a dead row
  1485. }
  1486. }
  1487. }
  1488. if (aStartColIndex > 0) {
  1489. for (int32_t rowX = aStartRowIndex; rowX <= aEndRowIndex; rowX++) {
  1490. CellData* cellData = GetDataAt(rowX, aStartColIndex);
  1491. if (cellData && (cellData->IsColSpan())) {
  1492. return true; // there is a col span into the region
  1493. }
  1494. cellData = GetDataAt(rowX, aEndColIndex + 1);
  1495. if (cellData && (cellData->IsColSpan())) {
  1496. return true; // there is a col span out of the region
  1497. }
  1498. }
  1499. }
  1500. return false;
  1501. }
  1502. void nsCellMap::InsertCells(nsTableCellMap& aMap,
  1503. nsTArray<nsTableCellFrame*>& aCellFrames,
  1504. int32_t aRowIndex,
  1505. int32_t aColIndexBefore,
  1506. int32_t aRgFirstRowIndex,
  1507. TableArea& aDamageArea)
  1508. {
  1509. if (aCellFrames.Length() == 0) return;
  1510. NS_ASSERTION(aColIndexBefore >= -1, "index out of range");
  1511. int32_t numCols = aMap.GetColCount();
  1512. if (aColIndexBefore >= numCols) {
  1513. NS_ERROR("Inserting instead of appending cells indicates a serious cellmap error");
  1514. aColIndexBefore = numCols - 1;
  1515. }
  1516. // get the starting col index of the 1st new cells
  1517. int32_t startColIndex;
  1518. for (startColIndex = aColIndexBefore + 1; startColIndex < numCols; startColIndex++) {
  1519. CellData* data = GetDataAt(aRowIndex, startColIndex);
  1520. if (!data || data->IsOrig() || data->IsDead()) {
  1521. // // Not a span. Stop.
  1522. break;
  1523. }
  1524. }
  1525. // record whether inserted cells are going to cause complications due
  1526. // to existing row spans, col spans or table sizing.
  1527. bool spansCauseRebuild = false;
  1528. // check that all cells have the same row span
  1529. int32_t numNewCells = aCellFrames.Length();
  1530. bool zeroRowSpan = false;
  1531. int32_t rowSpan = 0;
  1532. for (int32_t cellX = 0; cellX < numNewCells; cellX++) {
  1533. nsTableCellFrame* cell = aCellFrames.ElementAt(cellX);
  1534. int32_t rowSpan2 = GetRowSpanForNewCell(cell, aRowIndex, zeroRowSpan);
  1535. if (rowSpan == 0) {
  1536. rowSpan = rowSpan2;
  1537. }
  1538. else if (rowSpan != rowSpan2) {
  1539. spansCauseRebuild = true;
  1540. break;
  1541. }
  1542. }
  1543. // check if the new cells will cause the table to add more rows
  1544. if (!spansCauseRebuild) {
  1545. if (mRows.Length() < uint32_t(aRowIndex + rowSpan)) {
  1546. spansCauseRebuild = true;
  1547. }
  1548. }
  1549. if (!spansCauseRebuild) {
  1550. spansCauseRebuild = CellsSpanInOrOut(aRowIndex, aRowIndex + rowSpan - 1,
  1551. startColIndex, numCols - 1);
  1552. }
  1553. if (spansCauseRebuild) {
  1554. aMap.RebuildConsideringCells(this, &aCellFrames, aRowIndex, startColIndex,
  1555. true, aDamageArea);
  1556. }
  1557. else {
  1558. ExpandWithCells(aMap, aCellFrames, aRowIndex, startColIndex, rowSpan,
  1559. zeroRowSpan, aRgFirstRowIndex, aDamageArea);
  1560. }
  1561. }
  1562. void
  1563. nsCellMap::ExpandWithRows(nsTableCellMap& aMap,
  1564. nsTArray<nsTableRowFrame*>& aRowFrames,
  1565. int32_t aStartRowIndexIn,
  1566. int32_t aRgFirstRowIndex,
  1567. TableArea& aDamageArea)
  1568. {
  1569. int32_t startRowIndex = (aStartRowIndexIn >= 0) ? aStartRowIndexIn : 0;
  1570. NS_ASSERTION(uint32_t(startRowIndex) <= mRows.Length(), "caller should have grown cellmap before");
  1571. int32_t numNewRows = aRowFrames.Length();
  1572. mContentRowCount += numNewRows;
  1573. int32_t endRowIndex = startRowIndex + numNewRows - 1;
  1574. // shift the rows after startRowIndex down and insert empty rows that will
  1575. // be filled via the AppendCell call below
  1576. if (!Grow(aMap, numNewRows, startRowIndex)) {
  1577. return;
  1578. }
  1579. int32_t newRowIndex = 0;
  1580. for (int32_t rowX = startRowIndex; rowX <= endRowIndex; rowX++) {
  1581. nsTableRowFrame* rFrame = aRowFrames.ElementAt(newRowIndex);
  1582. // append cells
  1583. int32_t colIndex = 0;
  1584. for (nsIFrame* cFrame : rFrame->PrincipalChildList()) {
  1585. nsTableCellFrame *cellFrame = do_QueryFrame(cFrame);
  1586. if (cellFrame) {
  1587. AppendCell(aMap, cellFrame, rowX, false, aRgFirstRowIndex, aDamageArea,
  1588. &colIndex);
  1589. }
  1590. }
  1591. newRowIndex++;
  1592. }
  1593. // mark all following rows damaged, they might contain a previously set
  1594. // damage area which we can not shift.
  1595. int32_t firstDamagedRow = aRgFirstRowIndex + startRowIndex;
  1596. SetDamageArea(0, firstDamagedRow, aMap.GetColCount(),
  1597. aMap.GetRowCount() - firstDamagedRow, aDamageArea);
  1598. }
  1599. void nsCellMap::ExpandWithCells(nsTableCellMap& aMap,
  1600. nsTArray<nsTableCellFrame*>& aCellFrames,
  1601. int32_t aRowIndex,
  1602. int32_t aColIndex,
  1603. int32_t aRowSpan, // same for all cells
  1604. bool aRowSpanIsZero,
  1605. int32_t aRgFirstRowIndex,
  1606. TableArea& aDamageArea)
  1607. {
  1608. NS_ASSERTION(!!aMap.mBCInfo == mIsBC, "BC state mismatch");
  1609. int32_t endRowIndex = aRowIndex + aRowSpan - 1;
  1610. int32_t startColIndex = aColIndex;
  1611. int32_t endColIndex = aColIndex;
  1612. int32_t numCells = aCellFrames.Length();
  1613. int32_t totalColSpan = 0;
  1614. // add cellData entries for the space taken up by the new cells
  1615. for (int32_t cellX = 0; cellX < numCells; cellX++) {
  1616. nsTableCellFrame* cellFrame = aCellFrames.ElementAt(cellX);
  1617. CellData* origData = AllocCellData(cellFrame); // the originating cell
  1618. if (!origData) return;
  1619. // set the starting and ending col index for the new cell
  1620. int32_t colSpan = cellFrame->GetColSpan();
  1621. totalColSpan += colSpan;
  1622. if (cellX == 0) {
  1623. endColIndex = aColIndex + colSpan - 1;
  1624. }
  1625. else {
  1626. startColIndex = endColIndex + 1;
  1627. endColIndex = startColIndex + colSpan - 1;
  1628. }
  1629. // add the originating cell data and any cell data corresponding to row/col spans
  1630. for (int32_t rowX = aRowIndex; rowX <= endRowIndex; rowX++) {
  1631. CellDataArray& row = mRows[rowX];
  1632. // Pre-allocate all the cells we'll need in this array, setting
  1633. // them to null.
  1634. // Have to have the cast to get the template to do the right thing.
  1635. int32_t insertionIndex = row.Length();
  1636. if (insertionIndex > startColIndex) {
  1637. insertionIndex = startColIndex;
  1638. }
  1639. if (!row.InsertElementsAt(insertionIndex, endColIndex - insertionIndex + 1,
  1640. (CellData*)nullptr) &&
  1641. rowX == aRowIndex) {
  1642. // Failed to insert the slots, and this is the very first row. That
  1643. // means that we need to clean up |origData| before returning, since
  1644. // the cellmap doesn't own it yet.
  1645. DestroyCellData(origData);
  1646. return;
  1647. }
  1648. for (int32_t colX = startColIndex; colX <= endColIndex; colX++) {
  1649. CellData* data = origData;
  1650. if ((rowX != aRowIndex) || (colX != startColIndex)) {
  1651. data = AllocCellData(nullptr);
  1652. if (!data) return;
  1653. if (rowX > aRowIndex) {
  1654. data->SetRowSpanOffset(rowX - aRowIndex);
  1655. if (aRowSpanIsZero) {
  1656. data->SetZeroRowSpan(true);
  1657. }
  1658. }
  1659. if (colX > startColIndex) {
  1660. data->SetColSpanOffset(colX - startColIndex);
  1661. }
  1662. }
  1663. SetDataAt(aMap, *data, rowX, colX);
  1664. }
  1665. }
  1666. cellFrame->SetColIndex(startColIndex);
  1667. }
  1668. int32_t damageHeight = std::min(GetRowGroup()->GetRowCount() - aRowIndex,
  1669. aRowSpan);
  1670. SetDamageArea(aColIndex, aRgFirstRowIndex + aRowIndex,
  1671. 1 + endColIndex - aColIndex, damageHeight, aDamageArea);
  1672. int32_t rowX;
  1673. // update the row and col info due to shifting
  1674. for (rowX = aRowIndex; rowX <= endRowIndex; rowX++) {
  1675. CellDataArray& row = mRows[rowX];
  1676. uint32_t numCols = row.Length();
  1677. uint32_t colX;
  1678. for (colX = aColIndex + totalColSpan; colX < numCols; colX++) {
  1679. CellData* data = row[colX];
  1680. if (data) {
  1681. // increase the origin and span counts beyond the spanned cols
  1682. if (data->IsOrig()) {
  1683. // a cell that gets moved needs adjustment as well as it new orignating col
  1684. data->GetCellFrame()->SetColIndex(colX);
  1685. nsColInfo* colInfo = aMap.GetColInfoAt(colX);
  1686. colInfo->mNumCellsOrig++;
  1687. }
  1688. if (data->IsColSpan()) {
  1689. nsColInfo* colInfo = aMap.GetColInfoAt(colX);
  1690. colInfo->mNumCellsSpan++;
  1691. }
  1692. // decrease the origin and span counts within the spanned cols
  1693. int32_t colX2 = colX - totalColSpan;
  1694. nsColInfo* colInfo2 = aMap.GetColInfoAt(colX2);
  1695. if (data->IsOrig()) {
  1696. // the old originating col of a moved cell needs adjustment
  1697. colInfo2->mNumCellsOrig--;
  1698. }
  1699. if (data->IsColSpan()) {
  1700. colInfo2->mNumCellsSpan--;
  1701. }
  1702. }
  1703. }
  1704. }
  1705. }
  1706. void nsCellMap::ShrinkWithoutRows(nsTableCellMap& aMap,
  1707. int32_t aStartRowIndex,
  1708. int32_t aNumRowsToRemove,
  1709. int32_t aRgFirstRowIndex,
  1710. TableArea& aDamageArea)
  1711. {
  1712. NS_ASSERTION(!!aMap.mBCInfo == mIsBC, "BC state mismatch");
  1713. int32_t endRowIndex = aStartRowIndex + aNumRowsToRemove - 1;
  1714. uint32_t colCount = aMap.GetColCount();
  1715. for (int32_t rowX = endRowIndex; rowX >= aStartRowIndex; --rowX) {
  1716. CellDataArray& row = mRows[rowX];
  1717. uint32_t colX;
  1718. for (colX = 0; colX < colCount; colX++) {
  1719. CellData* data = row.SafeElementAt(colX);
  1720. if (data) {
  1721. // Adjust the column counts.
  1722. if (data->IsOrig()) {
  1723. // Decrement the column count.
  1724. nsColInfo* colInfo = aMap.GetColInfoAt(colX);
  1725. colInfo->mNumCellsOrig--;
  1726. }
  1727. // colspan=0 is only counted as a spanned cell in the 1st col it spans
  1728. else if (data->IsColSpan()) {
  1729. nsColInfo* colInfo = aMap.GetColInfoAt(colX);
  1730. colInfo->mNumCellsSpan--;
  1731. }
  1732. }
  1733. }
  1734. uint32_t rowLength = row.Length();
  1735. // Delete our row information.
  1736. for (colX = 0; colX < rowLength; colX++) {
  1737. DestroyCellData(row[colX]);
  1738. }
  1739. mRows.RemoveElementAt(rowX);
  1740. // Decrement our row and next available index counts.
  1741. mContentRowCount--;
  1742. }
  1743. aMap.RemoveColsAtEnd();
  1744. // mark all following rows damaged, they might contain a previously set
  1745. // damage area which we can not shift.
  1746. int32_t firstDamagedRow = aRgFirstRowIndex + aStartRowIndex;
  1747. SetDamageArea(0, firstDamagedRow, aMap.GetColCount(),
  1748. aMap.GetRowCount() - firstDamagedRow, aDamageArea);
  1749. }
  1750. int32_t nsCellMap::GetEffectiveColSpan(const nsTableCellMap& aMap,
  1751. int32_t aRowIndex,
  1752. int32_t aColIndex) const
  1753. {
  1754. int32_t numColsInTable = aMap.GetColCount();
  1755. int32_t colSpan = 1;
  1756. if (uint32_t(aRowIndex) >= mRows.Length()) {
  1757. return colSpan;
  1758. }
  1759. const CellDataArray& row = mRows[aRowIndex];
  1760. int32_t colX;
  1761. CellData* data;
  1762. int32_t maxCols = numColsInTable;
  1763. bool hitOverlap = false; // XXX this is not ever being set to true
  1764. for (colX = aColIndex + 1; colX < maxCols; colX++) {
  1765. data = row.SafeElementAt(colX);
  1766. if (data) {
  1767. // for an overlapping situation get the colspan from the originating cell and
  1768. // use that as the max number of cols to iterate. Since this is rare, only
  1769. // pay the price of looking up the cell's colspan here.
  1770. if (!hitOverlap && data->IsOverlap()) {
  1771. CellData* origData = row.SafeElementAt(aColIndex);
  1772. if (origData && origData->IsOrig()) {
  1773. nsTableCellFrame* cellFrame = origData->GetCellFrame();
  1774. if (cellFrame) {
  1775. // possible change the number of colums to iterate
  1776. maxCols = std::min(aColIndex + cellFrame->GetColSpan(), maxCols);
  1777. if (colX >= maxCols)
  1778. break;
  1779. }
  1780. }
  1781. }
  1782. if (data->IsColSpan()) {
  1783. colSpan++;
  1784. }
  1785. else {
  1786. break;
  1787. }
  1788. }
  1789. else break;
  1790. }
  1791. return colSpan;
  1792. }
  1793. int32_t
  1794. nsCellMap::GetRowSpanForNewCell(nsTableCellFrame* aCellFrameToAdd,
  1795. int32_t aRowIndex,
  1796. bool& aIsZeroRowSpan) const
  1797. {
  1798. aIsZeroRowSpan = false;
  1799. int32_t rowSpan = aCellFrameToAdd->GetRowSpan();
  1800. if (0 == rowSpan) {
  1801. // Use a min value of 2 for a zero rowspan to make computations easier
  1802. // elsewhere. Zero rowspans are only content dependent!
  1803. rowSpan = std::max(2, mContentRowCount - aRowIndex);
  1804. aIsZeroRowSpan = true;
  1805. }
  1806. return rowSpan;
  1807. }
  1808. bool nsCellMap::HasMoreThanOneCell(int32_t aRowIndex) const
  1809. {
  1810. const CellDataArray& row = mRows.SafeElementAt(aRowIndex, *sEmptyRow);
  1811. uint32_t maxColIndex = row.Length();
  1812. uint32_t count = 0;
  1813. uint32_t colIndex;
  1814. for (colIndex = 0; colIndex < maxColIndex; colIndex++) {
  1815. CellData* cellData = row[colIndex];
  1816. if (cellData && (cellData->GetCellFrame() || cellData->IsRowSpan()))
  1817. count++;
  1818. if (count > 1)
  1819. return true;
  1820. }
  1821. return false;
  1822. }
  1823. int32_t
  1824. nsCellMap::GetNumCellsOriginatingInRow(int32_t aRowIndex) const
  1825. {
  1826. const CellDataArray& row = mRows.SafeElementAt(aRowIndex, *sEmptyRow);
  1827. uint32_t count = 0;
  1828. uint32_t maxColIndex = row.Length();
  1829. uint32_t colIndex;
  1830. for (colIndex = 0; colIndex < maxColIndex; colIndex++) {
  1831. CellData* cellData = row[colIndex];
  1832. if (cellData && cellData->IsOrig())
  1833. count++;
  1834. }
  1835. return count;
  1836. }
  1837. int32_t nsCellMap::GetRowSpan(int32_t aRowIndex,
  1838. int32_t aColIndex,
  1839. bool aGetEffective) const
  1840. {
  1841. int32_t rowSpan = 1;
  1842. int32_t rowCount = (aGetEffective) ? mContentRowCount : mRows.Length();
  1843. int32_t rowX;
  1844. for (rowX = aRowIndex + 1; rowX < rowCount; rowX++) {
  1845. CellData* data = GetDataAt(rowX, aColIndex);
  1846. if (data) {
  1847. if (data->IsRowSpan()) {
  1848. rowSpan++;
  1849. }
  1850. else {
  1851. break;
  1852. }
  1853. }
  1854. else break;
  1855. }
  1856. return rowSpan;
  1857. }
  1858. void nsCellMap::ShrinkWithoutCell(nsTableCellMap& aMap,
  1859. nsTableCellFrame& aCellFrame,
  1860. int32_t aRowIndex,
  1861. int32_t aColIndex,
  1862. int32_t aRgFirstRowIndex,
  1863. TableArea& aDamageArea)
  1864. {
  1865. NS_ASSERTION(!!aMap.mBCInfo == mIsBC, "BC state mismatch");
  1866. uint32_t colX, rowX;
  1867. // get the rowspan and colspan from the cell map since the content may have changed
  1868. uint32_t numCols = aMap.GetColCount();
  1869. int32_t rowSpan = GetRowSpan(aRowIndex, aColIndex, true);
  1870. uint32_t colSpan = GetEffectiveColSpan(aMap, aRowIndex, aColIndex);
  1871. uint32_t endRowIndex = aRowIndex + rowSpan - 1;
  1872. uint32_t endColIndex = aColIndex + colSpan - 1;
  1873. // adjust the col counts due to the deleted cell before removing it
  1874. for (colX = aColIndex; colX <= endColIndex; colX++) {
  1875. nsColInfo* colInfo = aMap.GetColInfoAt(colX);
  1876. if (colX == uint32_t(aColIndex)) {
  1877. colInfo->mNumCellsOrig--;
  1878. }
  1879. else {
  1880. colInfo->mNumCellsSpan--;
  1881. }
  1882. }
  1883. // remove the deleted cell and cellData entries for it
  1884. for (rowX = aRowIndex; rowX <= endRowIndex; rowX++) {
  1885. CellDataArray& row = mRows[rowX];
  1886. // endIndexForRow points at the first slot we don't want to clean up. This
  1887. // makes the aColIndex == 0 case work right with our unsigned int colX.
  1888. NS_ASSERTION(endColIndex + 1 <= row.Length(), "span beyond the row size!");
  1889. uint32_t endIndexForRow = std::min(endColIndex + 1, uint32_t(row.Length()));
  1890. // Since endIndexForRow <= row.Length(), enough to compare aColIndex to it.
  1891. if (uint32_t(aColIndex) < endIndexForRow) {
  1892. for (colX = endIndexForRow; colX > uint32_t(aColIndex); colX--) {
  1893. DestroyCellData(row[colX-1]);
  1894. }
  1895. row.RemoveElementsAt(aColIndex, endIndexForRow - aColIndex);
  1896. }
  1897. }
  1898. numCols = aMap.GetColCount();
  1899. // update the row and col info due to shifting
  1900. for (rowX = aRowIndex; rowX <= endRowIndex; rowX++) {
  1901. CellDataArray& row = mRows[rowX];
  1902. for (colX = aColIndex; colX < numCols - colSpan; colX++) {
  1903. CellData* data = row.SafeElementAt(colX);
  1904. if (data) {
  1905. if (data->IsOrig()) {
  1906. // a cell that gets moved to the left needs adjustment in its new location
  1907. data->GetCellFrame()->SetColIndex(colX);
  1908. nsColInfo* colInfo = aMap.GetColInfoAt(colX);
  1909. colInfo->mNumCellsOrig++;
  1910. // a cell that gets moved to the left needs adjustment in its old location
  1911. colInfo = aMap.GetColInfoAt(colX + colSpan);
  1912. if (colInfo) {
  1913. colInfo->mNumCellsOrig--;
  1914. }
  1915. }
  1916. else if (data->IsColSpan()) {
  1917. // a cell that gets moved to the left needs adjustment
  1918. // in its new location
  1919. nsColInfo* colInfo = aMap.GetColInfoAt(colX);
  1920. colInfo->mNumCellsSpan++;
  1921. // a cell that gets moved to the left needs adjustment
  1922. // in its old location
  1923. colInfo = aMap.GetColInfoAt(colX + colSpan);
  1924. if (colInfo) {
  1925. colInfo->mNumCellsSpan--;
  1926. }
  1927. }
  1928. }
  1929. }
  1930. }
  1931. aMap.RemoveColsAtEnd();
  1932. SetDamageArea(aColIndex, aRgFirstRowIndex + aRowIndex,
  1933. std::max(0, aMap.GetColCount() - aColIndex - 1),
  1934. 1 + endRowIndex - aRowIndex, aDamageArea);
  1935. }
  1936. void
  1937. nsCellMap::RebuildConsideringRows(nsTableCellMap& aMap,
  1938. int32_t aStartRowIndex,
  1939. nsTArray<nsTableRowFrame*>* aRowsToInsert,
  1940. int32_t aNumRowsToRemove)
  1941. {
  1942. NS_ASSERTION(!!aMap.mBCInfo == mIsBC, "BC state mismatch");
  1943. // copy the old cell map into a new array
  1944. uint32_t numOrigRows = mRows.Length();
  1945. nsTArray<CellDataArray> origRows;
  1946. mRows.SwapElements(origRows);
  1947. int32_t rowNumberChange;
  1948. if (aRowsToInsert) {
  1949. rowNumberChange = aRowsToInsert->Length();
  1950. } else {
  1951. rowNumberChange = -aNumRowsToRemove;
  1952. }
  1953. // adjust mContentRowCount based on the function arguments as they are known to
  1954. // be real rows.
  1955. mContentRowCount += rowNumberChange;
  1956. NS_ASSERTION(mContentRowCount >= 0, "previous mContentRowCount was wrong");
  1957. // mRows is empty now. Grow it to the size we expect it to have.
  1958. if (mContentRowCount) {
  1959. if (!Grow(aMap, mContentRowCount)) {
  1960. // Bail, I guess... Not sure what else we can do here.
  1961. return;
  1962. }
  1963. }
  1964. // aStartRowIndex might be after all existing rows so we should limit the
  1965. // copy to the amount of exisiting rows
  1966. uint32_t copyEndRowIndex = std::min(numOrigRows, uint32_t(aStartRowIndex));
  1967. // rowX keeps track of where we are in mRows while setting up the
  1968. // new cellmap.
  1969. uint32_t rowX = 0;
  1970. TableArea damageArea;
  1971. // put back the rows before the affected ones just as before. Note that we
  1972. // can't just copy the old rows in bit-for-bit, because they might be
  1973. // spanning out into the rows we're adding/removing.
  1974. for ( ; rowX < copyEndRowIndex; rowX++) {
  1975. const CellDataArray& row = origRows[rowX];
  1976. uint32_t numCols = row.Length();
  1977. for (uint32_t colX = 0; colX < numCols; colX++) {
  1978. // put in the original cell from the cell map
  1979. const CellData* data = row.ElementAt(colX);
  1980. if (data && data->IsOrig()) {
  1981. AppendCell(aMap, data->GetCellFrame(), rowX, false, 0, damageArea);
  1982. }
  1983. }
  1984. }
  1985. // Now handle the new rows being inserted, if any.
  1986. uint32_t copyStartRowIndex;
  1987. rowX = aStartRowIndex;
  1988. if (aRowsToInsert) {
  1989. // add in the new cells and create rows if necessary
  1990. int32_t numNewRows = aRowsToInsert->Length();
  1991. for (int32_t newRowX = 0; newRowX < numNewRows; newRowX++) {
  1992. nsTableRowFrame* rFrame = aRowsToInsert->ElementAt(newRowX);
  1993. for (nsIFrame* cFrame : rFrame->PrincipalChildList()) {
  1994. nsTableCellFrame *cellFrame = do_QueryFrame(cFrame);
  1995. if (cellFrame) {
  1996. AppendCell(aMap, cellFrame, rowX, false, 0, damageArea);
  1997. }
  1998. }
  1999. rowX++;
  2000. }
  2001. copyStartRowIndex = aStartRowIndex;
  2002. }
  2003. else {
  2004. copyStartRowIndex = aStartRowIndex + aNumRowsToRemove;
  2005. }
  2006. // put back the rows after the affected ones just as before. Again, we can't
  2007. // just copy the old bits because that would not handle the new rows spanning
  2008. // out or our earlier old rows spanning through the damaged area.
  2009. for (uint32_t copyRowX = copyStartRowIndex; copyRowX < numOrigRows;
  2010. copyRowX++) {
  2011. const CellDataArray& row = origRows[copyRowX];
  2012. uint32_t numCols = row.Length();
  2013. for (uint32_t colX = 0; colX < numCols; colX++) {
  2014. // put in the original cell from the cell map
  2015. CellData* data = row.ElementAt(colX);
  2016. if (data && data->IsOrig()) {
  2017. AppendCell(aMap, data->GetCellFrame(), rowX, false, 0, damageArea);
  2018. }
  2019. }
  2020. rowX++;
  2021. }
  2022. // delete the old cell map. Now rowX no longer has anything to do with mRows
  2023. for (rowX = 0; rowX < numOrigRows; rowX++) {
  2024. CellDataArray& row = origRows[rowX];
  2025. uint32_t len = row.Length();
  2026. for (uint32_t colX = 0; colX < len; colX++) {
  2027. DestroyCellData(row[colX]);
  2028. }
  2029. }
  2030. }
  2031. void
  2032. nsCellMap::RebuildConsideringCells(nsTableCellMap& aMap,
  2033. int32_t aNumOrigCols,
  2034. nsTArray<nsTableCellFrame*>* aCellFrames,
  2035. int32_t aRowIndex,
  2036. int32_t aColIndex,
  2037. bool aInsert)
  2038. {
  2039. NS_ASSERTION(!!aMap.mBCInfo == mIsBC, "BC state mismatch");
  2040. // copy the old cell map into a new array
  2041. int32_t numOrigRows = mRows.Length();
  2042. nsTArray<CellDataArray> origRows;
  2043. mRows.SwapElements(origRows);
  2044. int32_t numNewCells = (aCellFrames) ? aCellFrames->Length() : 0;
  2045. // the new cells might extend the previous column number
  2046. NS_ASSERTION(aNumOrigCols >= aColIndex, "Appending cells far beyond cellmap data?!");
  2047. int32_t numCols = aInsert ? std::max(aNumOrigCols, aColIndex + 1) : aNumOrigCols;
  2048. // build the new cell map. Hard to say what, if anything, we can preallocate
  2049. // here... Should come back to that sometime, perhaps.
  2050. int32_t rowX;
  2051. TableArea damageArea;
  2052. for (rowX = 0; rowX < numOrigRows; rowX++) {
  2053. const CellDataArray& row = origRows[rowX];
  2054. for (int32_t colX = 0; colX < numCols; colX++) {
  2055. if ((rowX == aRowIndex) && (colX == aColIndex)) {
  2056. if (aInsert) { // put in the new cells
  2057. for (int32_t cellX = 0; cellX < numNewCells; cellX++) {
  2058. nsTableCellFrame* cell = aCellFrames->ElementAt(cellX);
  2059. if (cell) {
  2060. AppendCell(aMap, cell, rowX, false, 0, damageArea);
  2061. }
  2062. }
  2063. }
  2064. else {
  2065. continue; // do not put the deleted cell back
  2066. }
  2067. }
  2068. // put in the original cell from the cell map
  2069. CellData* data = row.SafeElementAt(colX);
  2070. if (data && data->IsOrig()) {
  2071. AppendCell(aMap, data->GetCellFrame(), rowX, false, 0, damageArea);
  2072. }
  2073. }
  2074. }
  2075. if (aInsert && numOrigRows <= aRowIndex) { // append the new cells below the last original row
  2076. NS_ASSERTION (numOrigRows == aRowIndex, "Appending cells far beyond the last row");
  2077. for (int32_t cellX = 0; cellX < numNewCells; cellX++) {
  2078. nsTableCellFrame* cell = aCellFrames->ElementAt(cellX);
  2079. if (cell) {
  2080. AppendCell(aMap, cell, aRowIndex, false, 0, damageArea);
  2081. }
  2082. }
  2083. }
  2084. // delete the old cell map
  2085. for (rowX = 0; rowX < numOrigRows; rowX++) {
  2086. CellDataArray& row = origRows[rowX];
  2087. uint32_t len = row.Length();
  2088. for (uint32_t colX = 0; colX < len; colX++) {
  2089. DestroyCellData(row.SafeElementAt(colX));
  2090. }
  2091. }
  2092. // expand the cellmap to cover empty content rows
  2093. if (mRows.Length() < uint32_t(mContentRowCount)) {
  2094. Grow(aMap, mContentRowCount - mRows.Length());
  2095. }
  2096. }
  2097. void nsCellMap::RemoveCell(nsTableCellMap& aMap,
  2098. nsTableCellFrame* aCellFrame,
  2099. int32_t aRowIndex,
  2100. int32_t aRgFirstRowIndex,
  2101. TableArea& aDamageArea)
  2102. {
  2103. uint32_t numRows = mRows.Length();
  2104. if (uint32_t(aRowIndex) >= numRows) {
  2105. NS_ERROR("bad arg in nsCellMap::RemoveCell");
  2106. return;
  2107. }
  2108. int32_t numCols = aMap.GetColCount();
  2109. // Now aRowIndex is guaranteed OK.
  2110. // get the starting col index of the cell to remove
  2111. int32_t startColIndex;
  2112. for (startColIndex = 0; startColIndex < numCols; startColIndex++) {
  2113. CellData* data = mRows[aRowIndex].SafeElementAt(startColIndex);
  2114. if (data && (data->IsOrig()) && (aCellFrame == data->GetCellFrame())) {
  2115. break; // we found the col index
  2116. }
  2117. }
  2118. int32_t rowSpan = GetRowSpan(aRowIndex, startColIndex, false);
  2119. // record whether removing the cells is going to cause complications due
  2120. // to existing row spans, col spans or table sizing.
  2121. bool spansCauseRebuild = CellsSpanInOrOut(aRowIndex,
  2122. aRowIndex + rowSpan - 1,
  2123. startColIndex, numCols - 1);
  2124. // XXX if the cell has a col span to the end of the map, and the end has no originating
  2125. // cells, we need to assume that this the only such cell, and rebuild so that there are
  2126. // no extraneous cols at the end. The same is true for removing rows.
  2127. if (!aCellFrame->GetRowSpan() || !aCellFrame->GetColSpan())
  2128. spansCauseRebuild = true;
  2129. if (spansCauseRebuild) {
  2130. aMap.RebuildConsideringCells(this, nullptr, aRowIndex, startColIndex, false,
  2131. aDamageArea);
  2132. }
  2133. else {
  2134. ShrinkWithoutCell(aMap, *aCellFrame, aRowIndex, startColIndex,
  2135. aRgFirstRowIndex, aDamageArea);
  2136. }
  2137. }
  2138. #ifdef DEBUG
  2139. void nsCellMap::Dump(bool aIsBorderCollapse) const
  2140. {
  2141. printf("\n ***** START GROUP CELL MAP DUMP ***** %p\n", (void*)this);
  2142. nsTableRowGroupFrame* rg = GetRowGroup();
  2143. const nsStyleDisplay* display = rg->StyleDisplay();
  2144. switch (display->mDisplay) {
  2145. case StyleDisplay::TableHeaderGroup:
  2146. printf(" thead ");
  2147. break;
  2148. case StyleDisplay::TableFooterGroup:
  2149. printf(" tfoot ");
  2150. break;
  2151. case StyleDisplay::TableRowGroup:
  2152. printf(" tbody ");
  2153. break;
  2154. default:
  2155. printf("HUH? wrong display type on rowgroup");
  2156. }
  2157. uint32_t mapRowCount = mRows.Length();
  2158. printf("mapRowCount=%u tableRowCount=%d\n", mapRowCount, mContentRowCount);
  2159. uint32_t rowIndex, colIndex;
  2160. for (rowIndex = 0; rowIndex < mapRowCount; rowIndex++) {
  2161. const CellDataArray& row = mRows[rowIndex];
  2162. printf(" row %d : ", rowIndex);
  2163. uint32_t colCount = row.Length();
  2164. for (colIndex = 0; colIndex < colCount; colIndex++) {
  2165. CellData* cd = row[colIndex];
  2166. if (cd) {
  2167. if (cd->IsOrig()) {
  2168. printf("C%d,%d ", rowIndex, colIndex);
  2169. } else {
  2170. if (cd->IsRowSpan()) {
  2171. printf("R ");
  2172. }
  2173. if (cd->IsColSpan()) {
  2174. printf("C ");
  2175. }
  2176. if (!(cd->IsRowSpan() && cd->IsColSpan())) {
  2177. printf(" ");
  2178. }
  2179. printf(" ");
  2180. }
  2181. } else {
  2182. printf("---- ");
  2183. }
  2184. }
  2185. if (aIsBorderCollapse) {
  2186. nscoord size;
  2187. BCBorderOwner owner;
  2188. LogicalSide side;
  2189. bool segStart;
  2190. bool bevel;
  2191. for (int32_t i = 0; i <= 2; i++) {
  2192. printf("\n ");
  2193. for (colIndex = 0; colIndex < colCount; colIndex++) {
  2194. BCCellData* cd = (BCCellData *)row[colIndex];
  2195. if (cd) {
  2196. if (0 == i) {
  2197. size = cd->mData.GetBStartEdge(owner, segStart);
  2198. printf("t=%d%d%d ", int32_t(size), owner, segStart);
  2199. }
  2200. else if (1 == i) {
  2201. size = cd->mData.GetIStartEdge(owner, segStart);
  2202. printf("l=%d%d%d ", int32_t(size), owner, segStart);
  2203. }
  2204. else {
  2205. size = cd->mData.GetCorner(side, bevel);
  2206. printf("c=%d%d%d ", int32_t(size), side, bevel);
  2207. }
  2208. }
  2209. }
  2210. }
  2211. }
  2212. printf("\n");
  2213. }
  2214. // output info mapping Ci,j to cell address
  2215. uint32_t cellCount = 0;
  2216. for (uint32_t rIndex = 0; rIndex < mapRowCount; rIndex++) {
  2217. const CellDataArray& row = mRows[rIndex];
  2218. uint32_t colCount = row.Length();
  2219. printf(" ");
  2220. for (colIndex = 0; colIndex < colCount; colIndex++) {
  2221. CellData* cd = row[colIndex];
  2222. if (cd) {
  2223. if (cd->IsOrig()) {
  2224. nsTableCellFrame* cellFrame = cd->GetCellFrame();
  2225. uint32_t cellFrameColIndex = cellFrame->ColIndex();
  2226. printf("C%d,%d=%p(%u) ", rIndex, colIndex, (void*)cellFrame,
  2227. cellFrameColIndex);
  2228. cellCount++;
  2229. }
  2230. }
  2231. }
  2232. printf("\n");
  2233. }
  2234. printf(" ***** END GROUP CELL MAP DUMP *****\n");
  2235. }
  2236. #endif
  2237. CellData*
  2238. nsCellMap::GetDataAt(int32_t aMapRowIndex,
  2239. int32_t aColIndex) const
  2240. {
  2241. return
  2242. mRows.SafeElementAt(aMapRowIndex, *sEmptyRow).SafeElementAt(aColIndex);
  2243. }
  2244. // only called if the cell at aMapRowIndex, aColIndex is null or dead
  2245. // (the latter from ExpandZeroColSpans (XXXmats which has now been removed -
  2246. // are there other ways cells may be dead?)).
  2247. void nsCellMap::SetDataAt(nsTableCellMap& aMap,
  2248. CellData& aNewCell,
  2249. int32_t aMapRowIndex,
  2250. int32_t aColIndex)
  2251. {
  2252. NS_ASSERTION(!!aMap.mBCInfo == mIsBC, "BC state mismatch");
  2253. if (uint32_t(aMapRowIndex) >= mRows.Length()) {
  2254. NS_ERROR("SetDataAt called with row index > num rows");
  2255. return;
  2256. }
  2257. CellDataArray& row = mRows[aMapRowIndex];
  2258. // the table map may need cols added
  2259. int32_t numColsToAdd = aColIndex + 1 - aMap.GetColCount();
  2260. if (numColsToAdd > 0) {
  2261. aMap.AddColsAtEnd(numColsToAdd);
  2262. }
  2263. // the row may need cols added
  2264. numColsToAdd = aColIndex + 1 - row.Length();
  2265. if (numColsToAdd > 0) {
  2266. // XXXbz need to handle allocation failures.
  2267. GrowRow(row, numColsToAdd);
  2268. }
  2269. DestroyCellData(row[aColIndex]);
  2270. row.ReplaceElementsAt(aColIndex, 1, &aNewCell);
  2271. // update the originating cell counts if cell originates in this row, col
  2272. nsColInfo* colInfo = aMap.GetColInfoAt(aColIndex);
  2273. if (colInfo) {
  2274. if (aNewCell.IsOrig()) {
  2275. colInfo->mNumCellsOrig++;
  2276. }
  2277. else if (aNewCell.IsColSpan()) {
  2278. colInfo->mNumCellsSpan++;
  2279. }
  2280. }
  2281. else NS_ERROR("SetDataAt called with col index > table map num cols");
  2282. }
  2283. nsTableCellFrame*
  2284. nsCellMap::GetCellInfoAt(const nsTableCellMap& aMap,
  2285. int32_t aRowX,
  2286. int32_t aColX,
  2287. bool* aOriginates,
  2288. int32_t* aColSpan) const
  2289. {
  2290. if (aOriginates) {
  2291. *aOriginates = false;
  2292. }
  2293. CellData* data = GetDataAt(aRowX, aColX);
  2294. nsTableCellFrame* cellFrame = nullptr;
  2295. if (data) {
  2296. if (data->IsOrig()) {
  2297. cellFrame = data->GetCellFrame();
  2298. if (aOriginates)
  2299. *aOriginates = true;
  2300. }
  2301. else {
  2302. cellFrame = GetCellFrame(aRowX, aColX, *data, true);
  2303. }
  2304. if (cellFrame && aColSpan) {
  2305. uint32_t initialColIndex = cellFrame->ColIndex();
  2306. *aColSpan = GetEffectiveColSpan(aMap, aRowX, initialColIndex);
  2307. }
  2308. }
  2309. return cellFrame;
  2310. }
  2311. bool nsCellMap::RowIsSpannedInto(int32_t aRowIndex,
  2312. int32_t aNumEffCols) const
  2313. {
  2314. if ((0 > aRowIndex) || (aRowIndex >= mContentRowCount)) {
  2315. return false;
  2316. }
  2317. for (int32_t colIndex = 0; colIndex < aNumEffCols; colIndex++) {
  2318. CellData* cd = GetDataAt(aRowIndex, colIndex);
  2319. if (cd) { // there's really a cell at (aRowIndex, colIndex)
  2320. if (cd->IsSpan()) { // the cell at (aRowIndex, colIndex) is the result of a span
  2321. if (cd->IsRowSpan() && GetCellFrame(aRowIndex, colIndex, *cd, true)) { // XXX why the last check
  2322. return true;
  2323. }
  2324. }
  2325. }
  2326. }
  2327. return false;
  2328. }
  2329. bool nsCellMap::RowHasSpanningCells(int32_t aRowIndex,
  2330. int32_t aNumEffCols) const
  2331. {
  2332. if ((0 > aRowIndex) || (aRowIndex >= mContentRowCount)) {
  2333. return false;
  2334. }
  2335. if (aRowIndex != mContentRowCount - 1) {
  2336. // aRowIndex is not the last row, so we check the next row after aRowIndex for spanners
  2337. for (int32_t colIndex = 0; colIndex < aNumEffCols; colIndex++) {
  2338. CellData* cd = GetDataAt(aRowIndex, colIndex);
  2339. if (cd && (cd->IsOrig())) { // cell originates
  2340. CellData* cd2 = GetDataAt(aRowIndex + 1, colIndex);
  2341. if (cd2 && cd2->IsRowSpan()) { // cd2 is spanned by a row
  2342. if (cd->GetCellFrame() == GetCellFrame(aRowIndex + 1, colIndex, *cd2, true)) {
  2343. return true;
  2344. }
  2345. }
  2346. }
  2347. }
  2348. }
  2349. return false;
  2350. }
  2351. void nsCellMap::DestroyCellData(CellData* aData)
  2352. {
  2353. if (!aData) {
  2354. return;
  2355. }
  2356. if (mIsBC) {
  2357. BCCellData* bcData = static_cast<BCCellData*>(aData);
  2358. bcData->~BCCellData();
  2359. mPresContext->FreeToShell(sizeof(BCCellData), bcData);
  2360. } else {
  2361. aData->~CellData();
  2362. mPresContext->FreeToShell(sizeof(CellData), aData);
  2363. }
  2364. }
  2365. CellData* nsCellMap::AllocCellData(nsTableCellFrame* aOrigCell)
  2366. {
  2367. if (mIsBC) {
  2368. BCCellData* data = (BCCellData*)
  2369. mPresContext->AllocateFromShell(sizeof(BCCellData));
  2370. if (data) {
  2371. new (data) BCCellData(aOrigCell);
  2372. }
  2373. return data;
  2374. }
  2375. CellData* data = (CellData*)
  2376. mPresContext->AllocateFromShell(sizeof(CellData));
  2377. if (data) {
  2378. new (data) CellData(aOrigCell);
  2379. }
  2380. return data;
  2381. }
  2382. void
  2383. nsCellMapColumnIterator::AdvanceRowGroup()
  2384. {
  2385. do {
  2386. mCurMapStart += mCurMapContentRowCount;
  2387. mCurMap = mCurMap->GetNextSibling();
  2388. if (!mCurMap) {
  2389. // Set mCurMapContentRowCount and mCurMapRelevantRowCount to 0 in case
  2390. // mCurMap has no next sibling. This can happen if we just handled the
  2391. // last originating cell. Future calls will end up with mFoundCells ==
  2392. // mOrigCells, but for this one mFoundCells was definitely not big enough
  2393. // if we got here.
  2394. mCurMapContentRowCount = 0;
  2395. mCurMapRelevantRowCount = 0;
  2396. break;
  2397. }
  2398. mCurMapContentRowCount = mCurMap->GetRowCount();
  2399. uint32_t rowArrayLength = mCurMap->mRows.Length();
  2400. mCurMapRelevantRowCount = std::min(mCurMapContentRowCount, rowArrayLength);
  2401. } while (0 == mCurMapRelevantRowCount);
  2402. NS_ASSERTION(mCurMapRelevantRowCount != 0 || !mCurMap,
  2403. "How did that happen?");
  2404. // Set mCurMapRow to 0, since cells can't span across table row groups.
  2405. mCurMapRow = 0;
  2406. }
  2407. void
  2408. nsCellMapColumnIterator::IncrementRow(int32_t aIncrement)
  2409. {
  2410. NS_PRECONDITION(aIncrement >= 0, "Bogus increment");
  2411. NS_PRECONDITION(mCurMap, "Bogus mOrigCells?");
  2412. if (aIncrement == 0) {
  2413. AdvanceRowGroup();
  2414. }
  2415. else {
  2416. mCurMapRow += aIncrement;
  2417. if (mCurMapRow >= mCurMapRelevantRowCount) {
  2418. AdvanceRowGroup();
  2419. }
  2420. }
  2421. }
  2422. nsTableCellFrame*
  2423. nsCellMapColumnIterator::GetNextFrame(int32_t* aRow, int32_t* aColSpan)
  2424. {
  2425. // Fast-path for the case when we don't have anything left in the column and
  2426. // we know it.
  2427. if (mFoundCells == mOrigCells) {
  2428. *aRow = 0;
  2429. *aColSpan = 1;
  2430. return nullptr;
  2431. }
  2432. while (1) {
  2433. NS_ASSERTION(mCurMapRow < mCurMapRelevantRowCount, "Bogus mOrigCells?");
  2434. // Safe to just get the row (which is faster than calling GetDataAt(), but
  2435. // there may not be that many cells in it, so have to use SafeElementAt for
  2436. // the mCol.
  2437. const nsCellMap::CellDataArray& row = mCurMap->mRows[mCurMapRow];
  2438. CellData* cellData = row.SafeElementAt(mCol);
  2439. if (!cellData || cellData->IsDead()) {
  2440. // Could hit this if there are fewer cells in this row than others, for
  2441. // example.
  2442. IncrementRow(1);
  2443. continue;
  2444. }
  2445. if (cellData->IsColSpan()) {
  2446. // Look up the originating data for this cell, advance by its relative rowspan.
  2447. int32_t rowspanOffset = cellData->GetRowSpanOffset();
  2448. nsTableCellFrame* cellFrame = mCurMap->GetCellFrame(mCurMapRow, mCol, *cellData, false);
  2449. NS_ASSERTION(cellFrame,"Must have usable originating data here");
  2450. int32_t rowSpan = cellFrame->GetRowSpan();
  2451. if (rowSpan == 0) {
  2452. AdvanceRowGroup();
  2453. }
  2454. else {
  2455. IncrementRow(rowSpan - rowspanOffset);
  2456. }
  2457. continue;
  2458. }
  2459. NS_ASSERTION(cellData->IsOrig(),
  2460. "Must have originating cellData by this point. "
  2461. "See comment on mCurMapRow in header.");
  2462. nsTableCellFrame* cellFrame = cellData->GetCellFrame();
  2463. NS_ASSERTION(cellFrame, "Orig data without cellframe?");
  2464. *aRow = mCurMapStart + mCurMapRow;
  2465. *aColSpan = mCurMap->GetEffectiveColSpan(*mMap, mCurMapRow, mCol);
  2466. IncrementRow(cellFrame->GetRowSpan());
  2467. ++mFoundCells;
  2468. MOZ_ASSERT(cellData == mMap->GetDataAt(*aRow, mCol),
  2469. "Giving caller bogus row?");
  2470. return cellFrame;
  2471. }
  2472. NS_NOTREACHED("Can't get here");
  2473. return nullptr;
  2474. }