InlineFlowBox.cpp 83 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686
  1. /*
  2. * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
  3. *
  4. * This library is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU Library General Public
  6. * License as published by the Free Software Foundation; either
  7. * version 2 of the License, or (at your option) any later version.
  8. *
  9. * This library is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * Library General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU Library General Public License
  15. * along with this library; see the file COPYING.LIB. If not, write to
  16. * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  17. * Boston, MA 02110-1301, USA.
  18. */
  19. #include "config.h"
  20. #include "InlineFlowBox.h"
  21. #include "CSSPropertyNames.h"
  22. #include "Document.h"
  23. #include "EllipsisBox.h"
  24. #include "Font.h"
  25. #include "GraphicsContext.h"
  26. #include "InlineTextBox.h"
  27. #include "HitTestResult.h"
  28. #include "RenderBlock.h"
  29. #include "RenderInline.h"
  30. #include "RenderLayer.h"
  31. #include "RenderListMarker.h"
  32. #include "RenderRubyBase.h"
  33. #include "RenderRubyRun.h"
  34. #include "RenderRubyText.h"
  35. #include "RenderTableCell.h"
  36. #include "RenderView.h"
  37. #include "RootInlineBox.h"
  38. #include "Text.h"
  39. #include <math.h>
  40. using namespace std;
  41. namespace WebCore {
  42. struct SameSizeAsInlineFlowBox : public InlineBox {
  43. void* pointers[5];
  44. uint32_t bitfields : 23;
  45. };
  46. COMPILE_ASSERT(sizeof(InlineFlowBox) == sizeof(SameSizeAsInlineFlowBox), InlineFlowBox_should_stay_small);
  47. #ifndef NDEBUG
  48. InlineFlowBox::~InlineFlowBox()
  49. {
  50. if (!m_hasBadChildList)
  51. for (InlineBox* child = firstChild(); child; child = child->nextOnLine())
  52. child->setHasBadParent();
  53. }
  54. #endif
  55. LayoutUnit InlineFlowBox::getFlowSpacingLogicalWidth()
  56. {
  57. LayoutUnit totWidth = marginBorderPaddingLogicalLeft() + marginBorderPaddingLogicalRight();
  58. for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) {
  59. if (curr->isInlineFlowBox())
  60. totWidth += toInlineFlowBox(curr)->getFlowSpacingLogicalWidth();
  61. }
  62. return totWidth;
  63. }
  64. IntRect InlineFlowBox::roundedFrameRect() const
  65. {
  66. // Begin by snapping the x and y coordinates to the nearest pixel.
  67. int snappedX = lroundf(x());
  68. int snappedY = lroundf(y());
  69. int snappedMaxX = lroundf(x() + width());
  70. int snappedMaxY = lroundf(y() + height());
  71. return IntRect(snappedX, snappedY, snappedMaxX - snappedX, snappedMaxY - snappedY);
  72. }
  73. static void setHasTextDescendantsOnAncestors(InlineFlowBox* box)
  74. {
  75. while (box && !box->hasTextDescendants()) {
  76. box->setHasTextDescendants();
  77. box = box->parent();
  78. }
  79. }
  80. void InlineFlowBox::addToLine(InlineBox* child)
  81. {
  82. ASSERT(!child->parent());
  83. ASSERT(!child->nextOnLine());
  84. ASSERT(!child->prevOnLine());
  85. checkConsistency();
  86. child->setParent(this);
  87. if (!m_firstChild) {
  88. m_firstChild = child;
  89. m_lastChild = child;
  90. } else {
  91. m_lastChild->setNextOnLine(child);
  92. child->setPrevOnLine(m_lastChild);
  93. m_lastChild = child;
  94. }
  95. child->setFirstLineStyleBit(isFirstLineStyle());
  96. child->setIsHorizontal(isHorizontal());
  97. if (child->isText()) {
  98. if (child->renderer()->parent() == renderer())
  99. m_hasTextChildren = true;
  100. setHasTextDescendantsOnAncestors(this);
  101. } else if (child->isInlineFlowBox()) {
  102. if (toInlineFlowBox(child)->hasTextDescendants())
  103. setHasTextDescendantsOnAncestors(this);
  104. }
  105. if (descendantsHaveSameLineHeightAndBaseline() && !child->renderer()->isOutOfFlowPositioned()) {
  106. RenderStyle* parentStyle = renderer()->style(isFirstLineStyle());
  107. RenderStyle* childStyle = child->renderer()->style(isFirstLineStyle());
  108. bool shouldClearDescendantsHaveSameLineHeightAndBaseline = false;
  109. if (child->renderer()->isReplaced())
  110. shouldClearDescendantsHaveSameLineHeightAndBaseline = true;
  111. else if (child->isText()) {
  112. if (child->renderer()->isBR() || child->renderer()->parent() != renderer()) {
  113. if (!parentStyle->font().fontMetrics().hasIdenticalAscentDescentAndLineGap(childStyle->font().fontMetrics())
  114. || parentStyle->lineHeight() != childStyle->lineHeight()
  115. || (parentStyle->verticalAlign() != BASELINE && !isRootInlineBox()) || childStyle->verticalAlign() != BASELINE)
  116. shouldClearDescendantsHaveSameLineHeightAndBaseline = true;
  117. }
  118. if (childStyle->hasTextCombine() || childStyle->textEmphasisMark() != TextEmphasisMarkNone)
  119. shouldClearDescendantsHaveSameLineHeightAndBaseline = true;
  120. } else {
  121. if (child->renderer()->isBR()) {
  122. // FIXME: This is dumb. We only turn off because current layout test results expect the <br> to be 0-height on the baseline.
  123. // Other than making a zillion tests have to regenerate results, there's no reason to ditch the optimization here.
  124. shouldClearDescendantsHaveSameLineHeightAndBaseline = true;
  125. } else {
  126. ASSERT(isInlineFlowBox());
  127. InlineFlowBox* childFlowBox = toInlineFlowBox(child);
  128. // Check the child's bit, and then also check for differences in font, line-height, vertical-align
  129. if (!childFlowBox->descendantsHaveSameLineHeightAndBaseline()
  130. || !parentStyle->font().fontMetrics().hasIdenticalAscentDescentAndLineGap(childStyle->font().fontMetrics())
  131. || parentStyle->lineHeight() != childStyle->lineHeight()
  132. || (parentStyle->verticalAlign() != BASELINE && !isRootInlineBox()) || childStyle->verticalAlign() != BASELINE
  133. || childStyle->hasBorder() || childStyle->hasPadding() || childStyle->hasTextCombine())
  134. shouldClearDescendantsHaveSameLineHeightAndBaseline = true;
  135. }
  136. }
  137. if (shouldClearDescendantsHaveSameLineHeightAndBaseline)
  138. clearDescendantsHaveSameLineHeightAndBaseline();
  139. }
  140. if (!child->renderer()->isOutOfFlowPositioned()) {
  141. if (child->isText()) {
  142. RenderStyle* childStyle = child->renderer()->style(isFirstLineStyle());
  143. if (childStyle->letterSpacing() < 0 || childStyle->textShadow() || childStyle->textEmphasisMark() != TextEmphasisMarkNone || childStyle->textStrokeWidth())
  144. child->clearKnownToHaveNoOverflow();
  145. } else if (child->renderer()->isReplaced()) {
  146. RenderBox* box = toRenderBox(child->renderer());
  147. if (box->hasRenderOverflow() || box->hasSelfPaintingLayer())
  148. child->clearKnownToHaveNoOverflow();
  149. } else if (!child->renderer()->isBR() && (child->renderer()->style(isFirstLineStyle())->boxShadow() || child->boxModelObject()->hasSelfPaintingLayer()
  150. || (child->renderer()->isListMarker() && !toRenderListMarker(child->renderer())->isInside())
  151. || child->renderer()->style(isFirstLineStyle())->hasBorderImageOutsets()))
  152. child->clearKnownToHaveNoOverflow();
  153. if (knownToHaveNoOverflow() && child->isInlineFlowBox() && !toInlineFlowBox(child)->knownToHaveNoOverflow())
  154. clearKnownToHaveNoOverflow();
  155. }
  156. checkConsistency();
  157. }
  158. void InlineFlowBox::removeChild(InlineBox* child)
  159. {
  160. checkConsistency();
  161. if (!isDirty())
  162. dirtyLineBoxes();
  163. root()->childRemoved(child);
  164. if (child == m_firstChild)
  165. m_firstChild = child->nextOnLine();
  166. if (child == m_lastChild)
  167. m_lastChild = child->prevOnLine();
  168. if (child->nextOnLine())
  169. child->nextOnLine()->setPrevOnLine(child->prevOnLine());
  170. if (child->prevOnLine())
  171. child->prevOnLine()->setNextOnLine(child->nextOnLine());
  172. child->setParent(0);
  173. checkConsistency();
  174. }
  175. void InlineFlowBox::deleteLine(RenderArena* arena)
  176. {
  177. InlineBox* child = firstChild();
  178. InlineBox* next = 0;
  179. while (child) {
  180. ASSERT(this == child->parent());
  181. next = child->nextOnLine();
  182. #ifndef NDEBUG
  183. child->setParent(0);
  184. #endif
  185. child->deleteLine(arena);
  186. child = next;
  187. }
  188. #ifndef NDEBUG
  189. m_firstChild = 0;
  190. m_lastChild = 0;
  191. #endif
  192. removeLineBoxFromRenderObject();
  193. destroy(arena);
  194. }
  195. void InlineFlowBox::removeLineBoxFromRenderObject()
  196. {
  197. toRenderInline(renderer())->lineBoxes()->removeLineBox(this);
  198. }
  199. void InlineFlowBox::extractLine()
  200. {
  201. if (!extracted())
  202. extractLineBoxFromRenderObject();
  203. for (InlineBox* child = firstChild(); child; child = child->nextOnLine())
  204. child->extractLine();
  205. }
  206. void InlineFlowBox::extractLineBoxFromRenderObject()
  207. {
  208. toRenderInline(renderer())->lineBoxes()->extractLineBox(this);
  209. }
  210. void InlineFlowBox::attachLine()
  211. {
  212. if (extracted())
  213. attachLineBoxToRenderObject();
  214. for (InlineBox* child = firstChild(); child; child = child->nextOnLine())
  215. child->attachLine();
  216. }
  217. void InlineFlowBox::attachLineBoxToRenderObject()
  218. {
  219. toRenderInline(renderer())->lineBoxes()->attachLineBox(this);
  220. }
  221. void InlineFlowBox::adjustPosition(float dx, float dy)
  222. {
  223. InlineBox::adjustPosition(dx, dy);
  224. for (InlineBox* child = firstChild(); child; child = child->nextOnLine())
  225. child->adjustPosition(dx, dy);
  226. if (m_overflow)
  227. m_overflow->move(dx, dy); // FIXME: Rounding error here since overflow was pixel snapped, but nobody other than list markers passes non-integral values here.
  228. }
  229. RenderLineBoxList* InlineFlowBox::rendererLineBoxes() const
  230. {
  231. return toRenderInline(renderer())->lineBoxes();
  232. }
  233. static inline bool isLastChildForRenderer(RenderObject* ancestor, RenderObject* child)
  234. {
  235. if (!child)
  236. return false;
  237. if (child == ancestor)
  238. return true;
  239. RenderObject* curr = child;
  240. RenderObject* parent = curr->parent();
  241. while (parent && (!parent->isRenderBlock() || parent->isInline())) {
  242. if (parent->lastChild() != curr)
  243. return false;
  244. if (parent == ancestor)
  245. return true;
  246. curr = parent;
  247. parent = curr->parent();
  248. }
  249. return true;
  250. }
  251. static bool isAnsectorAndWithinBlock(RenderObject* ancestor, RenderObject* child)
  252. {
  253. RenderObject* object = child;
  254. while (object && (!object->isRenderBlock() || object->isInline())) {
  255. if (object == ancestor)
  256. return true;
  257. object = object->parent();
  258. }
  259. return false;
  260. }
  261. void InlineFlowBox::determineSpacingForFlowBoxes(bool lastLine, bool isLogicallyLastRunWrapped, RenderObject* logicallyLastRunRenderer)
  262. {
  263. // All boxes start off open. They will not apply any margins/border/padding on
  264. // any side.
  265. bool includeLeftEdge = false;
  266. bool includeRightEdge = false;
  267. // The root inline box never has borders/margins/padding.
  268. if (parent()) {
  269. bool ltr = renderer()->style()->isLeftToRightDirection();
  270. // Check to see if all initial lines are unconstructed. If so, then
  271. // we know the inline began on this line (unless we are a continuation).
  272. RenderLineBoxList* lineBoxList = rendererLineBoxes();
  273. if (!lineBoxList->firstLineBox()->isConstructed() && !renderer()->isInlineElementContinuation()) {
  274. #if ENABLE(CSS_BOX_DECORATION_BREAK)
  275. if (renderer()->style()->boxDecorationBreak() == DCLONE)
  276. includeLeftEdge = includeRightEdge = true;
  277. else
  278. #endif
  279. if (ltr && lineBoxList->firstLineBox() == this)
  280. includeLeftEdge = true;
  281. else if (!ltr && lineBoxList->lastLineBox() == this)
  282. includeRightEdge = true;
  283. }
  284. if (!lineBoxList->lastLineBox()->isConstructed()) {
  285. RenderInline* inlineFlow = toRenderInline(renderer());
  286. bool isLastObjectOnLine = !isAnsectorAndWithinBlock(renderer(), logicallyLastRunRenderer) || (isLastChildForRenderer(renderer(), logicallyLastRunRenderer) && !isLogicallyLastRunWrapped);
  287. // We include the border under these conditions:
  288. // (1) The next line was not created, or it is constructed. We check the previous line for rtl.
  289. // (2) The logicallyLastRun is not a descendant of this renderer.
  290. // (3) The logicallyLastRun is a descendant of this renderer, but it is the last child of this renderer and it does not wrap to the next line.
  291. #if ENABLE(CSS_BOX_DECORATION_BREAK)
  292. // (4) The decoration break is set to clone therefore there will be borders on every sides.
  293. if (renderer()->style()->boxDecorationBreak() == DCLONE)
  294. includeLeftEdge = includeRightEdge = true;
  295. else
  296. #endif
  297. if (ltr) {
  298. if (!nextLineBox()
  299. && ((lastLine || isLastObjectOnLine) && !inlineFlow->continuation()))
  300. includeRightEdge = true;
  301. } else {
  302. if ((!prevLineBox() || prevLineBox()->isConstructed())
  303. && ((lastLine || isLastObjectOnLine) && !inlineFlow->continuation()))
  304. includeLeftEdge = true;
  305. }
  306. }
  307. }
  308. setEdges(includeLeftEdge, includeRightEdge);
  309. // Recur into our children.
  310. for (InlineBox* currChild = firstChild(); currChild; currChild = currChild->nextOnLine()) {
  311. if (currChild->isInlineFlowBox()) {
  312. InlineFlowBox* currFlow = toInlineFlowBox(currChild);
  313. currFlow->determineSpacingForFlowBoxes(lastLine, isLogicallyLastRunWrapped, logicallyLastRunRenderer);
  314. }
  315. }
  316. }
  317. float InlineFlowBox::placeBoxesInInlineDirection(float logicalLeft, bool& needsWordSpacing, GlyphOverflowAndFallbackFontsMap& textBoxDataMap)
  318. {
  319. // Set our x position.
  320. beginPlacingBoxRangesInInlineDirection(logicalLeft);
  321. float startLogicalLeft = logicalLeft;
  322. logicalLeft += borderLogicalLeft() + paddingLogicalLeft();
  323. float minLogicalLeft = startLogicalLeft;
  324. float maxLogicalRight = logicalLeft;
  325. placeBoxRangeInInlineDirection(firstChild(), 0, logicalLeft, minLogicalLeft, maxLogicalRight, needsWordSpacing, textBoxDataMap);
  326. logicalLeft += borderLogicalRight() + paddingLogicalRight();
  327. endPlacingBoxRangesInInlineDirection(startLogicalLeft, logicalLeft, minLogicalLeft, maxLogicalRight);
  328. return logicalLeft;
  329. }
  330. float InlineFlowBox::placeBoxRangeInInlineDirection(InlineBox* firstChild, InlineBox* lastChild, float& logicalLeft, float& minLogicalLeft, float& maxLogicalRight, bool& needsWordSpacing, GlyphOverflowAndFallbackFontsMap& textBoxDataMap)
  331. {
  332. for (InlineBox* curr = firstChild; curr && curr != lastChild; curr = curr->nextOnLine()) {
  333. if (curr->renderer()->isText()) {
  334. InlineTextBox* text = toInlineTextBox(curr);
  335. RenderText* rt = toRenderText(text->renderer());
  336. if (rt->textLength()) {
  337. if (needsWordSpacing && isSpaceOrNewline(rt->characterAt(text->start())))
  338. logicalLeft += rt->style(isFirstLineStyle())->font().wordSpacing();
  339. needsWordSpacing = !isSpaceOrNewline(rt->characterAt(text->end()));
  340. }
  341. text->setLogicalLeft(logicalLeft);
  342. if (knownToHaveNoOverflow())
  343. minLogicalLeft = min(logicalLeft, minLogicalLeft);
  344. logicalLeft += text->logicalWidth();
  345. if (knownToHaveNoOverflow())
  346. maxLogicalRight = max(logicalLeft, maxLogicalRight);
  347. } else {
  348. if (curr->renderer()->isOutOfFlowPositioned()) {
  349. if (curr->renderer()->parent()->style()->isLeftToRightDirection())
  350. curr->setLogicalLeft(logicalLeft);
  351. else
  352. // Our offset that we cache needs to be from the edge of the right border box and
  353. // not the left border box. We have to subtract |x| from the width of the block
  354. // (which can be obtained from the root line box).
  355. curr->setLogicalLeft(root()->block()->logicalWidth() - logicalLeft);
  356. continue; // The positioned object has no effect on the width.
  357. }
  358. if (curr->renderer()->isRenderInline()) {
  359. InlineFlowBox* flow = toInlineFlowBox(curr);
  360. logicalLeft += flow->marginLogicalLeft();
  361. if (knownToHaveNoOverflow())
  362. minLogicalLeft = min(logicalLeft, minLogicalLeft);
  363. logicalLeft = flow->placeBoxesInInlineDirection(logicalLeft, needsWordSpacing, textBoxDataMap);
  364. if (knownToHaveNoOverflow())
  365. maxLogicalRight = max(logicalLeft, maxLogicalRight);
  366. logicalLeft += flow->marginLogicalRight();
  367. } else if (!curr->renderer()->isListMarker() || toRenderListMarker(curr->renderer())->isInside()) {
  368. // The box can have a different writing-mode than the overall line, so this is a bit complicated.
  369. // Just get all the physical margin and overflow values by hand based off |isVertical|.
  370. LayoutUnit logicalLeftMargin = isHorizontal() ? curr->boxModelObject()->marginLeft() : curr->boxModelObject()->marginTop();
  371. LayoutUnit logicalRightMargin = isHorizontal() ? curr->boxModelObject()->marginRight() : curr->boxModelObject()->marginBottom();
  372. logicalLeft += logicalLeftMargin;
  373. curr->setLogicalLeft(logicalLeft);
  374. if (knownToHaveNoOverflow())
  375. minLogicalLeft = min(logicalLeft, minLogicalLeft);
  376. logicalLeft += curr->logicalWidth();
  377. if (knownToHaveNoOverflow())
  378. maxLogicalRight = max(logicalLeft, maxLogicalRight);
  379. logicalLeft += logicalRightMargin;
  380. // If we encounter any space after this inline block then ensure it is treated as the space between two words.
  381. needsWordSpacing = true;
  382. }
  383. }
  384. }
  385. return logicalLeft;
  386. }
  387. bool InlineFlowBox::requiresIdeographicBaseline(const GlyphOverflowAndFallbackFontsMap& textBoxDataMap) const
  388. {
  389. if (isHorizontal())
  390. return false;
  391. if (renderer()->style(isFirstLineStyle())->fontDescription().nonCJKGlyphOrientation() == NonCJKGlyphOrientationUpright
  392. || renderer()->style(isFirstLineStyle())->font().primaryFont()->hasVerticalGlyphs())
  393. return true;
  394. for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) {
  395. if (curr->renderer()->isOutOfFlowPositioned())
  396. continue; // Positioned placeholders don't affect calculations.
  397. if (curr->isInlineFlowBox()) {
  398. if (toInlineFlowBox(curr)->requiresIdeographicBaseline(textBoxDataMap))
  399. return true;
  400. } else {
  401. if (curr->renderer()->style(isFirstLineStyle())->font().primaryFont()->hasVerticalGlyphs())
  402. return true;
  403. const Vector<const SimpleFontData*>* usedFonts = 0;
  404. if (curr->isInlineTextBox()) {
  405. GlyphOverflowAndFallbackFontsMap::const_iterator it = textBoxDataMap.find(toInlineTextBox(curr));
  406. usedFonts = it == textBoxDataMap.end() ? 0 : &it->value.first;
  407. }
  408. if (usedFonts) {
  409. for (size_t i = 0; i < usedFonts->size(); ++i) {
  410. if (usedFonts->at(i)->hasVerticalGlyphs())
  411. return true;
  412. }
  413. }
  414. }
  415. }
  416. return false;
  417. }
  418. static bool verticalAlignApplies(RenderObject* curr)
  419. {
  420. // http://www.w3.org/TR/CSS2/visudet.html#propdef-vertical-align - vertical-align
  421. // only applies to inline level and table-cell elements
  422. return !curr->isText() || curr->parent()->isInline() || curr->parent()->isTableCell();
  423. }
  424. void InlineFlowBox::adjustMaxAscentAndDescent(int& maxAscent, int& maxDescent, int maxPositionTop, int maxPositionBottom)
  425. {
  426. for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) {
  427. // The computed lineheight needs to be extended for the
  428. // positioned elements
  429. if (curr->renderer()->isOutOfFlowPositioned())
  430. continue; // Positioned placeholders don't affect calculations.
  431. if ((curr->verticalAlign() == TOP || curr->verticalAlign() == BOTTOM) && verticalAlignApplies(curr->renderer())) {
  432. int lineHeight = curr->lineHeight();
  433. if (curr->verticalAlign() == TOP) {
  434. if (maxAscent + maxDescent < lineHeight)
  435. maxDescent = lineHeight - maxAscent;
  436. }
  437. else {
  438. if (maxAscent + maxDescent < lineHeight)
  439. maxAscent = lineHeight - maxDescent;
  440. }
  441. if (maxAscent + maxDescent >= max(maxPositionTop, maxPositionBottom))
  442. break;
  443. }
  444. if (curr->isInlineFlowBox())
  445. toInlineFlowBox(curr)->adjustMaxAscentAndDescent(maxAscent, maxDescent, maxPositionTop, maxPositionBottom);
  446. }
  447. }
  448. void InlineFlowBox::computeLogicalBoxHeights(RootInlineBox* rootBox, LayoutUnit& maxPositionTop, LayoutUnit& maxPositionBottom,
  449. int& maxAscent, int& maxDescent, bool& setMaxAscent, bool& setMaxDescent,
  450. bool strictMode, GlyphOverflowAndFallbackFontsMap& textBoxDataMap,
  451. FontBaseline baselineType, VerticalPositionCache& verticalPositionCache)
  452. {
  453. // The primary purpose of this function is to compute the maximal ascent and descent values for
  454. // a line. These values are computed based off the block's line-box-contain property, which indicates
  455. // what parts of descendant boxes have to fit within the line.
  456. //
  457. // The maxAscent value represents the distance of the highest point of any box (typically including line-height) from
  458. // the root box's baseline. The maxDescent value represents the distance of the lowest point of any box
  459. // (also typically including line-height) from the root box baseline. These values can be negative.
  460. //
  461. // A secondary purpose of this function is to store the offset of every box's baseline from the root box's
  462. // baseline. This information is cached in the logicalTop() of every box. We're effectively just using
  463. // the logicalTop() as scratch space.
  464. //
  465. // Because a box can be positioned such that it ends up fully above or fully below the
  466. // root line box, we only consider it to affect the maxAscent and maxDescent values if some
  467. // part of the box (EXCLUDING leading) is above (for ascent) or below (for descent) the root box's baseline.
  468. bool affectsAscent = false;
  469. bool affectsDescent = false;
  470. bool checkChildren = !descendantsHaveSameLineHeightAndBaseline();
  471. if (isRootInlineBox()) {
  472. // Examine our root box.
  473. int ascent = 0;
  474. int descent = 0;
  475. rootBox->ascentAndDescentForBox(rootBox, textBoxDataMap, ascent, descent, affectsAscent, affectsDescent);
  476. if (strictMode || hasTextChildren() || (!checkChildren && hasTextDescendants())) {
  477. if (maxAscent < ascent || !setMaxAscent) {
  478. maxAscent = ascent;
  479. setMaxAscent = true;
  480. }
  481. if (maxDescent < descent || !setMaxDescent) {
  482. maxDescent = descent;
  483. setMaxDescent = true;
  484. }
  485. }
  486. }
  487. if (!checkChildren)
  488. return;
  489. for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) {
  490. if (curr->renderer()->isOutOfFlowPositioned())
  491. continue; // Positioned placeholders don't affect calculations.
  492. InlineFlowBox* inlineFlowBox = curr->isInlineFlowBox() ? toInlineFlowBox(curr) : 0;
  493. bool affectsAscent = false;
  494. bool affectsDescent = false;
  495. // The verticalPositionForBox function returns the distance between the child box's baseline
  496. // and the root box's baseline. The value is negative if the child box's baseline is above the
  497. // root box's baseline, and it is positive if the child box's baseline is below the root box's baseline.
  498. curr->setLogicalTop(rootBox->verticalPositionForBox(curr, verticalPositionCache));
  499. int ascent = 0;
  500. int descent = 0;
  501. rootBox->ascentAndDescentForBox(curr, textBoxDataMap, ascent, descent, affectsAscent, affectsDescent);
  502. LayoutUnit boxHeight = ascent + descent;
  503. if (curr->verticalAlign() == TOP && verticalAlignApplies(curr->renderer())) {
  504. if (maxPositionTop < boxHeight)
  505. maxPositionTop = boxHeight;
  506. } else if (curr->verticalAlign() == BOTTOM && verticalAlignApplies(curr->renderer())) {
  507. if (maxPositionBottom < boxHeight)
  508. maxPositionBottom = boxHeight;
  509. } else if (!inlineFlowBox || strictMode || inlineFlowBox->hasTextChildren() || (inlineFlowBox->descendantsHaveSameLineHeightAndBaseline() && inlineFlowBox->hasTextDescendants())
  510. || inlineFlowBox->boxModelObject()->hasInlineDirectionBordersOrPadding()) {
  511. // Note that these values can be negative. Even though we only affect the maxAscent and maxDescent values
  512. // if our box (excluding line-height) was above (for ascent) or below (for descent) the root baseline, once you factor in line-height
  513. // the final box can end up being fully above or fully below the root box's baseline! This is ok, but what it
  514. // means is that ascent and descent (including leading), can end up being negative. The setMaxAscent and
  515. // setMaxDescent booleans are used to ensure that we're willing to initially set maxAscent/Descent to negative
  516. // values.
  517. ascent -= curr->logicalTop();
  518. descent += curr->logicalTop();
  519. if (affectsAscent && (maxAscent < ascent || !setMaxAscent)) {
  520. maxAscent = ascent;
  521. setMaxAscent = true;
  522. }
  523. if (affectsDescent && (maxDescent < descent || !setMaxDescent)) {
  524. maxDescent = descent;
  525. setMaxDescent = true;
  526. }
  527. }
  528. if (inlineFlowBox)
  529. inlineFlowBox->computeLogicalBoxHeights(rootBox, maxPositionTop, maxPositionBottom, maxAscent, maxDescent,
  530. setMaxAscent, setMaxDescent, strictMode, textBoxDataMap,
  531. baselineType, verticalPositionCache);
  532. }
  533. }
  534. void InlineFlowBox::placeBoxesInBlockDirection(LayoutUnit top, LayoutUnit maxHeight, int maxAscent, bool strictMode, LayoutUnit& lineTop, LayoutUnit& lineBottom, bool& setLineTop,
  535. LayoutUnit& lineTopIncludingMargins, LayoutUnit& lineBottomIncludingMargins, bool& hasAnnotationsBefore, bool& hasAnnotationsAfter, FontBaseline baselineType)
  536. {
  537. bool isRootBox = isRootInlineBox();
  538. if (isRootBox) {
  539. const FontMetrics& fontMetrics = renderer()->style(isFirstLineStyle())->fontMetrics();
  540. // RootInlineBoxes are always placed on at pixel boundaries in their logical y direction. Not doing
  541. // so results in incorrect rendering of text decorations, most notably underlines.
  542. setLogicalTop(roundToInt(top + maxAscent - fontMetrics.ascent(baselineType)));
  543. }
  544. LayoutUnit adjustmentForChildrenWithSameLineHeightAndBaseline = 0;
  545. if (descendantsHaveSameLineHeightAndBaseline()) {
  546. adjustmentForChildrenWithSameLineHeightAndBaseline = logicalTop();
  547. if (parent())
  548. adjustmentForChildrenWithSameLineHeightAndBaseline += (boxModelObject()->borderAndPaddingBefore());
  549. }
  550. for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) {
  551. if (curr->renderer()->isOutOfFlowPositioned())
  552. continue; // Positioned placeholders don't affect calculations.
  553. if (descendantsHaveSameLineHeightAndBaseline()) {
  554. curr->adjustBlockDirectionPosition(adjustmentForChildrenWithSameLineHeightAndBaseline);
  555. continue;
  556. }
  557. InlineFlowBox* inlineFlowBox = curr->isInlineFlowBox() ? toInlineFlowBox(curr) : 0;
  558. bool childAffectsTopBottomPos = true;
  559. if (curr->verticalAlign() == TOP && verticalAlignApplies(curr->renderer()))
  560. curr->setLogicalTop(top);
  561. else if (curr->verticalAlign() == BOTTOM && verticalAlignApplies(curr->renderer()))
  562. curr->setLogicalTop(top + maxHeight - curr->lineHeight());
  563. else {
  564. if (!strictMode && inlineFlowBox && !inlineFlowBox->hasTextChildren() && !curr->boxModelObject()->hasInlineDirectionBordersOrPadding()
  565. && !(inlineFlowBox->descendantsHaveSameLineHeightAndBaseline() && inlineFlowBox->hasTextDescendants()))
  566. childAffectsTopBottomPos = false;
  567. LayoutUnit posAdjust = maxAscent - curr->baselinePosition(baselineType);
  568. curr->setLogicalTop(curr->logicalTop() + top + posAdjust);
  569. }
  570. LayoutUnit newLogicalTop = curr->logicalTop();
  571. LayoutUnit newLogicalTopIncludingMargins = newLogicalTop;
  572. LayoutUnit boxHeight = curr->logicalHeight();
  573. LayoutUnit boxHeightIncludingMargins = boxHeight;
  574. if (curr->isText() || curr->isInlineFlowBox()) {
  575. const FontMetrics& fontMetrics = curr->renderer()->style(isFirstLineStyle())->fontMetrics();
  576. newLogicalTop += curr->baselinePosition(baselineType) - fontMetrics.ascent(baselineType);
  577. if (curr->isInlineFlowBox()) {
  578. RenderBoxModelObject* boxObject = toRenderBoxModelObject(curr->renderer());
  579. newLogicalTop -= boxObject->style(isFirstLineStyle())->isHorizontalWritingMode() ? boxObject->borderTop() + boxObject->paddingTop() :
  580. boxObject->borderRight() + boxObject->paddingRight();
  581. }
  582. newLogicalTopIncludingMargins = newLogicalTop;
  583. } else if (!curr->renderer()->isBR()) {
  584. RenderBox* box = toRenderBox(curr->renderer());
  585. newLogicalTopIncludingMargins = newLogicalTop;
  586. LayoutUnit overSideMargin = curr->isHorizontal() ? box->marginTop() : box->marginRight();
  587. LayoutUnit underSideMargin = curr->isHorizontal() ? box->marginBottom() : box->marginLeft();
  588. newLogicalTop += overSideMargin;
  589. boxHeightIncludingMargins += overSideMargin + underSideMargin;
  590. }
  591. curr->setLogicalTop(newLogicalTop);
  592. if (childAffectsTopBottomPos) {
  593. if (curr->renderer()->isRubyRun()) {
  594. // Treat the leading on the first and last lines of ruby runs as not being part of the overall lineTop/lineBottom.
  595. // Really this is a workaround hack for the fact that ruby should have been done as line layout and not done using
  596. // inline-block.
  597. if (renderer()->style()->isFlippedLinesWritingMode() == (curr->renderer()->style()->rubyPosition() == RubyPositionAfter))
  598. hasAnnotationsBefore = true;
  599. else
  600. hasAnnotationsAfter = true;
  601. RenderRubyRun* rubyRun = toRenderRubyRun(curr->renderer());
  602. if (RenderRubyBase* rubyBase = rubyRun->rubyBase()) {
  603. LayoutUnit bottomRubyBaseLeading = (curr->logicalHeight() - rubyBase->logicalBottom()) + rubyBase->logicalHeight() - (rubyBase->lastRootBox() ? rubyBase->lastRootBox()->lineBottom() : LayoutUnit());
  604. LayoutUnit topRubyBaseLeading = rubyBase->logicalTop() + (rubyBase->firstRootBox() ? rubyBase->firstRootBox()->lineTop() : LayoutUnit());
  605. newLogicalTop += !renderer()->style()->isFlippedLinesWritingMode() ? topRubyBaseLeading : bottomRubyBaseLeading;
  606. boxHeight -= (topRubyBaseLeading + bottomRubyBaseLeading);
  607. }
  608. }
  609. if (curr->isInlineTextBox()) {
  610. TextEmphasisPosition emphasisMarkPosition;
  611. if (toInlineTextBox(curr)->getEmphasisMarkPosition(curr->renderer()->style(isFirstLineStyle()), emphasisMarkPosition)) {
  612. bool emphasisMarkIsOver = emphasisMarkPosition == TextEmphasisPositionOver;
  613. if (emphasisMarkIsOver != curr->renderer()->style(isFirstLineStyle())->isFlippedLinesWritingMode())
  614. hasAnnotationsBefore = true;
  615. else
  616. hasAnnotationsAfter = true;
  617. }
  618. }
  619. if (!setLineTop) {
  620. setLineTop = true;
  621. lineTop = newLogicalTop;
  622. lineTopIncludingMargins = min(lineTop, newLogicalTopIncludingMargins);
  623. } else {
  624. lineTop = min(lineTop, newLogicalTop);
  625. lineTopIncludingMargins = min(lineTop, min(lineTopIncludingMargins, newLogicalTopIncludingMargins));
  626. }
  627. lineBottom = max(lineBottom, newLogicalTop + boxHeight);
  628. lineBottomIncludingMargins = max(lineBottom, max(lineBottomIncludingMargins, newLogicalTopIncludingMargins + boxHeightIncludingMargins));
  629. }
  630. // Adjust boxes to use their real box y/height and not the logical height (as dictated by
  631. // line-height).
  632. if (inlineFlowBox)
  633. inlineFlowBox->placeBoxesInBlockDirection(top, maxHeight, maxAscent, strictMode, lineTop, lineBottom, setLineTop,
  634. lineTopIncludingMargins, lineBottomIncludingMargins, hasAnnotationsBefore, hasAnnotationsAfter, baselineType);
  635. }
  636. if (isRootBox) {
  637. if (strictMode || hasTextChildren() || (descendantsHaveSameLineHeightAndBaseline() && hasTextDescendants())) {
  638. if (!setLineTop) {
  639. setLineTop = true;
  640. lineTop = pixelSnappedLogicalTop();
  641. lineTopIncludingMargins = lineTop;
  642. } else {
  643. lineTop = min<LayoutUnit>(lineTop, pixelSnappedLogicalTop());
  644. lineTopIncludingMargins = min(lineTop, lineTopIncludingMargins);
  645. }
  646. lineBottom = max<LayoutUnit>(lineBottom, pixelSnappedLogicalBottom());
  647. lineBottomIncludingMargins = max(lineBottom, lineBottomIncludingMargins);
  648. }
  649. if (renderer()->style()->isFlippedLinesWritingMode())
  650. flipLinesInBlockDirection(lineTopIncludingMargins, lineBottomIncludingMargins);
  651. }
  652. }
  653. #if ENABLE(CSS3_TEXT)
  654. void InlineFlowBox::computeMaxLogicalTop(float& maxLogicalTop) const
  655. {
  656. for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) {
  657. if (curr->renderer()->isOutOfFlowPositioned())
  658. continue; // Positioned placeholders don't affect calculations.
  659. if (descendantsHaveSameLineHeightAndBaseline())
  660. continue;
  661. maxLogicalTop = max<float>(maxLogicalTop, curr->y());
  662. float localMaxLogicalTop = 0;
  663. if (curr->isInlineFlowBox())
  664. toInlineFlowBox(curr)->computeMaxLogicalTop(localMaxLogicalTop);
  665. maxLogicalTop = max<float>(maxLogicalTop, localMaxLogicalTop);
  666. }
  667. }
  668. #endif // CSS3_TEXT
  669. void InlineFlowBox::flipLinesInBlockDirection(LayoutUnit lineTop, LayoutUnit lineBottom)
  670. {
  671. // Flip the box on the line such that the top is now relative to the lineBottom instead of the lineTop.
  672. setLogicalTop(lineBottom - (logicalTop() - lineTop) - logicalHeight());
  673. for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) {
  674. if (curr->renderer()->isOutOfFlowPositioned())
  675. continue; // Positioned placeholders aren't affected here.
  676. if (curr->isInlineFlowBox())
  677. toInlineFlowBox(curr)->flipLinesInBlockDirection(lineTop, lineBottom);
  678. else
  679. curr->setLogicalTop(lineBottom - (curr->logicalTop() - lineTop) - curr->logicalHeight());
  680. }
  681. }
  682. inline void InlineFlowBox::addBoxShadowVisualOverflow(LayoutRect& logicalVisualOverflow)
  683. {
  684. // box-shadow on root line boxes is applying to the block and not to the lines.
  685. if (!parent())
  686. return;
  687. RenderStyle* style = renderer()->style(isFirstLineStyle());
  688. if (!style->boxShadow())
  689. return;
  690. LayoutUnit boxShadowLogicalTop;
  691. LayoutUnit boxShadowLogicalBottom;
  692. style->getBoxShadowBlockDirectionExtent(boxShadowLogicalTop, boxShadowLogicalBottom);
  693. // Similar to how glyph overflow works, if our lines are flipped, then it's actually the opposite shadow that applies, since
  694. // the line is "upside down" in terms of block coordinates.
  695. LayoutUnit shadowLogicalTop = style->isFlippedLinesWritingMode() ? -boxShadowLogicalBottom : boxShadowLogicalTop;
  696. LayoutUnit shadowLogicalBottom = style->isFlippedLinesWritingMode() ? -boxShadowLogicalTop : boxShadowLogicalBottom;
  697. LayoutUnit logicalTopVisualOverflow = min(pixelSnappedLogicalTop() + shadowLogicalTop, logicalVisualOverflow.y());
  698. LayoutUnit logicalBottomVisualOverflow = max(pixelSnappedLogicalBottom() + shadowLogicalBottom, logicalVisualOverflow.maxY());
  699. LayoutUnit boxShadowLogicalLeft;
  700. LayoutUnit boxShadowLogicalRight;
  701. style->getBoxShadowInlineDirectionExtent(boxShadowLogicalLeft, boxShadowLogicalRight);
  702. LayoutUnit logicalLeftVisualOverflow = min(pixelSnappedLogicalLeft() + boxShadowLogicalLeft, logicalVisualOverflow.x());
  703. LayoutUnit logicalRightVisualOverflow = max(pixelSnappedLogicalRight() + boxShadowLogicalRight, logicalVisualOverflow.maxX());
  704. logicalVisualOverflow = LayoutRect(logicalLeftVisualOverflow, logicalTopVisualOverflow,
  705. logicalRightVisualOverflow - logicalLeftVisualOverflow, logicalBottomVisualOverflow - logicalTopVisualOverflow);
  706. }
  707. inline void InlineFlowBox::addBorderOutsetVisualOverflow(LayoutRect& logicalVisualOverflow)
  708. {
  709. // border-image-outset on root line boxes is applying to the block and not to the lines.
  710. if (!parent())
  711. return;
  712. RenderStyle* style = renderer()->style(isFirstLineStyle());
  713. if (!style->hasBorderImageOutsets())
  714. return;
  715. LayoutBoxExtent borderOutsets = style->borderImageOutsets();
  716. LayoutUnit borderOutsetLogicalTop = borderOutsets.logicalTop(style->writingMode());
  717. LayoutUnit borderOutsetLogicalBottom = borderOutsets.logicalBottom(style->writingMode());
  718. LayoutUnit borderOutsetLogicalLeft = borderOutsets.logicalLeft(style->writingMode());
  719. LayoutUnit borderOutsetLogicalRight = borderOutsets.logicalRight(style->writingMode());
  720. // Similar to how glyph overflow works, if our lines are flipped, then it's actually the opposite border that applies, since
  721. // the line is "upside down" in terms of block coordinates. vertical-rl and horizontal-bt are the flipped line modes.
  722. LayoutUnit outsetLogicalTop = style->isFlippedLinesWritingMode() ? borderOutsetLogicalBottom : borderOutsetLogicalTop;
  723. LayoutUnit outsetLogicalBottom = style->isFlippedLinesWritingMode() ? borderOutsetLogicalTop : borderOutsetLogicalBottom;
  724. LayoutUnit logicalTopVisualOverflow = min(pixelSnappedLogicalTop() - outsetLogicalTop, logicalVisualOverflow.y());
  725. LayoutUnit logicalBottomVisualOverflow = max(pixelSnappedLogicalBottom() + outsetLogicalBottom, logicalVisualOverflow.maxY());
  726. LayoutUnit outsetLogicalLeft = includeLogicalLeftEdge() ? borderOutsetLogicalLeft : LayoutUnit();
  727. LayoutUnit outsetLogicalRight = includeLogicalRightEdge() ? borderOutsetLogicalRight : LayoutUnit();
  728. LayoutUnit logicalLeftVisualOverflow = min(pixelSnappedLogicalLeft() - outsetLogicalLeft, logicalVisualOverflow.x());
  729. LayoutUnit logicalRightVisualOverflow = max(pixelSnappedLogicalRight() + outsetLogicalRight, logicalVisualOverflow.maxX());
  730. logicalVisualOverflow = LayoutRect(logicalLeftVisualOverflow, logicalTopVisualOverflow,
  731. logicalRightVisualOverflow - logicalLeftVisualOverflow, logicalBottomVisualOverflow - logicalTopVisualOverflow);
  732. }
  733. inline void InlineFlowBox::addTextBoxVisualOverflow(InlineTextBox* textBox, GlyphOverflowAndFallbackFontsMap& textBoxDataMap, LayoutRect& logicalVisualOverflow)
  734. {
  735. if (textBox->knownToHaveNoOverflow())
  736. return;
  737. RenderStyle* style = textBox->renderer()->style(isFirstLineStyle());
  738. GlyphOverflowAndFallbackFontsMap::iterator it = textBoxDataMap.find(textBox);
  739. GlyphOverflow* glyphOverflow = it == textBoxDataMap.end() ? 0 : &it->value.second;
  740. bool isFlippedLine = style->isFlippedLinesWritingMode();
  741. int topGlyphEdge = glyphOverflow ? (isFlippedLine ? glyphOverflow->bottom : glyphOverflow->top) : 0;
  742. int bottomGlyphEdge = glyphOverflow ? (isFlippedLine ? glyphOverflow->top : glyphOverflow->bottom) : 0;
  743. int leftGlyphEdge = glyphOverflow ? glyphOverflow->left : 0;
  744. int rightGlyphEdge = glyphOverflow ? glyphOverflow->right : 0;
  745. int strokeOverflow = static_cast<int>(ceilf(style->textStrokeWidth() / 2.0f));
  746. int topGlyphOverflow = -strokeOverflow - topGlyphEdge;
  747. int bottomGlyphOverflow = strokeOverflow + bottomGlyphEdge;
  748. int leftGlyphOverflow = -strokeOverflow - leftGlyphEdge;
  749. int rightGlyphOverflow = strokeOverflow + rightGlyphEdge;
  750. TextEmphasisPosition emphasisMarkPosition;
  751. if (style->textEmphasisMark() != TextEmphasisMarkNone && textBox->getEmphasisMarkPosition(style, emphasisMarkPosition)) {
  752. int emphasisMarkHeight = style->font().emphasisMarkHeight(style->textEmphasisMarkString());
  753. if ((emphasisMarkPosition == TextEmphasisPositionOver) == (!style->isFlippedLinesWritingMode()))
  754. topGlyphOverflow = min(topGlyphOverflow, -emphasisMarkHeight);
  755. else
  756. bottomGlyphOverflow = max(bottomGlyphOverflow, emphasisMarkHeight);
  757. }
  758. // If letter-spacing is negative, we should factor that into right layout overflow. (Even in RTL, letter-spacing is
  759. // applied to the right, so this is not an issue with left overflow.
  760. rightGlyphOverflow -= min(0, (int)style->font().letterSpacing());
  761. LayoutUnit textShadowLogicalTop;
  762. LayoutUnit textShadowLogicalBottom;
  763. style->getTextShadowBlockDirectionExtent(textShadowLogicalTop, textShadowLogicalBottom);
  764. LayoutUnit childOverflowLogicalTop = min<LayoutUnit>(textShadowLogicalTop + topGlyphOverflow, topGlyphOverflow);
  765. LayoutUnit childOverflowLogicalBottom = max<LayoutUnit>(textShadowLogicalBottom + bottomGlyphOverflow, bottomGlyphOverflow);
  766. LayoutUnit textShadowLogicalLeft;
  767. LayoutUnit textShadowLogicalRight;
  768. style->getTextShadowInlineDirectionExtent(textShadowLogicalLeft, textShadowLogicalRight);
  769. LayoutUnit childOverflowLogicalLeft = min<LayoutUnit>(textShadowLogicalLeft + leftGlyphOverflow, leftGlyphOverflow);
  770. LayoutUnit childOverflowLogicalRight = max<LayoutUnit>(textShadowLogicalRight + rightGlyphOverflow, rightGlyphOverflow);
  771. LayoutUnit logicalTopVisualOverflow = min(textBox->pixelSnappedLogicalTop() + childOverflowLogicalTop, logicalVisualOverflow.y());
  772. LayoutUnit logicalBottomVisualOverflow = max(textBox->pixelSnappedLogicalBottom() + childOverflowLogicalBottom, logicalVisualOverflow.maxY());
  773. LayoutUnit logicalLeftVisualOverflow = min(textBox->pixelSnappedLogicalLeft() + childOverflowLogicalLeft, logicalVisualOverflow.x());
  774. LayoutUnit logicalRightVisualOverflow = max(textBox->pixelSnappedLogicalRight() + childOverflowLogicalRight, logicalVisualOverflow.maxX());
  775. logicalVisualOverflow = LayoutRect(logicalLeftVisualOverflow, logicalTopVisualOverflow,
  776. logicalRightVisualOverflow - logicalLeftVisualOverflow, logicalBottomVisualOverflow - logicalTopVisualOverflow);
  777. textBox->setLogicalOverflowRect(logicalVisualOverflow);
  778. }
  779. inline void InlineFlowBox::addReplacedChildOverflow(const InlineBox* inlineBox, LayoutRect& logicalLayoutOverflow, LayoutRect& logicalVisualOverflow)
  780. {
  781. RenderBox* box = toRenderBox(inlineBox->renderer());
  782. // Visual overflow only propagates if the box doesn't have a self-painting layer. This rectangle does not include
  783. // transforms or relative positioning (since those objects always have self-painting layers), but it does need to be adjusted
  784. // for writing-mode differences.
  785. if (!box->hasSelfPaintingLayer()) {
  786. LayoutRect childLogicalVisualOverflow = box->logicalVisualOverflowRectForPropagation(renderer()->style());
  787. childLogicalVisualOverflow.move(inlineBox->logicalLeft(), inlineBox->logicalTop());
  788. logicalVisualOverflow.unite(childLogicalVisualOverflow);
  789. }
  790. // Layout overflow internal to the child box only propagates if the child box doesn't have overflow clip set.
  791. // Otherwise the child border box propagates as layout overflow. This rectangle must include transforms and relative positioning
  792. // and be adjusted for writing-mode differences.
  793. LayoutRect childLogicalLayoutOverflow = box->logicalLayoutOverflowRectForPropagation(renderer()->style());
  794. childLogicalLayoutOverflow.move(inlineBox->logicalLeft(), inlineBox->logicalTop());
  795. logicalLayoutOverflow.unite(childLogicalLayoutOverflow);
  796. }
  797. void InlineFlowBox::computeOverflow(LayoutUnit lineTop, LayoutUnit lineBottom, GlyphOverflowAndFallbackFontsMap& textBoxDataMap)
  798. {
  799. // If we know we have no overflow, we can just bail.
  800. if (knownToHaveNoOverflow())
  801. return;
  802. // Visual overflow just includes overflow for stuff we need to repaint ourselves. Self-painting layers are ignored.
  803. // Layout overflow is used to determine scrolling extent, so it still includes child layers and also factors in
  804. // transforms, relative positioning, etc.
  805. LayoutRect logicalLayoutOverflow(enclosingLayoutRect(logicalFrameRectIncludingLineHeight(lineTop, lineBottom)));
  806. LayoutRect logicalVisualOverflow(logicalLayoutOverflow);
  807. addBoxShadowVisualOverflow(logicalVisualOverflow);
  808. addBorderOutsetVisualOverflow(logicalVisualOverflow);
  809. for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) {
  810. if (curr->renderer()->isOutOfFlowPositioned())
  811. continue; // Positioned placeholders don't affect calculations.
  812. if (curr->renderer()->isText()) {
  813. InlineTextBox* text = toInlineTextBox(curr);
  814. RenderText* rt = toRenderText(text->renderer());
  815. if (rt->isBR())
  816. continue;
  817. LayoutRect textBoxOverflow(enclosingLayoutRect(text->logicalFrameRect()));
  818. addTextBoxVisualOverflow(text, textBoxDataMap, textBoxOverflow);
  819. logicalVisualOverflow.unite(textBoxOverflow);
  820. } else if (curr->renderer()->isRenderInline()) {
  821. InlineFlowBox* flow = toInlineFlowBox(curr);
  822. flow->computeOverflow(lineTop, lineBottom, textBoxDataMap);
  823. if (!flow->boxModelObject()->hasSelfPaintingLayer())
  824. logicalVisualOverflow.unite(flow->logicalVisualOverflowRect(lineTop, lineBottom));
  825. LayoutRect childLayoutOverflow = flow->logicalLayoutOverflowRect(lineTop, lineBottom);
  826. childLayoutOverflow.move(flow->boxModelObject()->relativePositionLogicalOffset());
  827. logicalLayoutOverflow.unite(childLayoutOverflow);
  828. } else
  829. addReplacedChildOverflow(curr, logicalLayoutOverflow, logicalVisualOverflow);
  830. }
  831. setOverflowFromLogicalRects(logicalLayoutOverflow, logicalVisualOverflow, lineTop, lineBottom);
  832. }
  833. void InlineFlowBox::setLayoutOverflow(const LayoutRect& rect, LayoutUnit lineTop, LayoutUnit lineBottom)
  834. {
  835. LayoutRect frameBox = enclosingLayoutRect(frameRectIncludingLineHeight(lineTop, lineBottom));
  836. if (frameBox.contains(rect) || rect.isEmpty())
  837. return;
  838. if (!m_overflow)
  839. m_overflow = adoptPtr(new RenderOverflow(frameBox, frameBox));
  840. m_overflow->setLayoutOverflow(rect);
  841. }
  842. void InlineFlowBox::setVisualOverflow(const LayoutRect& rect, LayoutUnit lineTop, LayoutUnit lineBottom)
  843. {
  844. LayoutRect frameBox = enclosingLayoutRect(frameRectIncludingLineHeight(lineTop, lineBottom));
  845. if (frameBox.contains(rect) || rect.isEmpty())
  846. return;
  847. if (!m_overflow)
  848. m_overflow = adoptPtr(new RenderOverflow(frameBox, frameBox));
  849. m_overflow->setVisualOverflow(rect);
  850. }
  851. void InlineFlowBox::setOverflowFromLogicalRects(const LayoutRect& logicalLayoutOverflow, const LayoutRect& logicalVisualOverflow, LayoutUnit lineTop, LayoutUnit lineBottom)
  852. {
  853. LayoutRect layoutOverflow(isHorizontal() ? logicalLayoutOverflow : logicalLayoutOverflow.transposedRect());
  854. setLayoutOverflow(layoutOverflow, lineTop, lineBottom);
  855. LayoutRect visualOverflow(isHorizontal() ? logicalVisualOverflow : logicalVisualOverflow.transposedRect());
  856. setVisualOverflow(visualOverflow, lineTop, lineBottom);
  857. }
  858. bool InlineFlowBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit lineTop, LayoutUnit lineBottom)
  859. {
  860. LayoutRect overflowRect(visualOverflowRect(lineTop, lineBottom));
  861. flipForWritingMode(overflowRect);
  862. overflowRect.moveBy(accumulatedOffset);
  863. if (!locationInContainer.intersects(overflowRect))
  864. return false;
  865. // Check children first.
  866. // We need to account for culled inline parents of the hit-tested nodes, so that they may also get included in area-based hit-tests.
  867. RenderObject* culledParent = 0;
  868. for (InlineBox* curr = lastChild(); curr; curr = curr->prevOnLine()) {
  869. if (curr->renderer()->isText() || !curr->boxModelObject()->hasSelfPaintingLayer()) {
  870. RenderObject* newParent = 0;
  871. // Culled parents are only relevant for area-based hit-tests, so ignore it in point-based ones.
  872. if (locationInContainer.isRectBasedTest()) {
  873. newParent = curr->renderer()->parent();
  874. if (newParent == renderer())
  875. newParent = 0;
  876. }
  877. // Check the culled parent after all its children have been checked, to do this we wait until
  878. // we are about to test an element with a different parent.
  879. if (newParent != culledParent) {
  880. if (!newParent || !newParent->isDescendantOf(culledParent)) {
  881. while (culledParent && culledParent != renderer() && culledParent != newParent) {
  882. if (culledParent->isRenderInline() && toRenderInline(culledParent)->hitTestCulledInline(request, result, locationInContainer, accumulatedOffset))
  883. return true;
  884. culledParent = culledParent->parent();
  885. }
  886. }
  887. culledParent = newParent;
  888. }
  889. if (curr->nodeAtPoint(request, result, locationInContainer, accumulatedOffset, lineTop, lineBottom)) {
  890. renderer()->updateHitTestResult(result, locationInContainer.point() - toLayoutSize(accumulatedOffset));
  891. return true;
  892. }
  893. }
  894. }
  895. // Check any culled ancestor of the final children tested.
  896. while (culledParent && culledParent != renderer()) {
  897. if (culledParent->isRenderInline() && toRenderInline(culledParent)->hitTestCulledInline(request, result, locationInContainer, accumulatedOffset))
  898. return true;
  899. culledParent = culledParent->parent();
  900. }
  901. // Now check ourselves. Pixel snap hit testing.
  902. if (!visibleToHitTesting())
  903. return false;
  904. // Do not hittest content beyond the ellipsis box.
  905. if (isRootInlineBox() && hasEllipsisBox()) {
  906. const EllipsisBox* ellipsisBox = root()->ellipsisBox();
  907. LayoutRect boundsRect(roundedFrameRect());
  908. if (isHorizontal())
  909. renderer()->style()->isLeftToRightDirection() ? boundsRect.shiftXEdgeTo(ellipsisBox->right()) : boundsRect.setWidth(ellipsisBox->left() - left());
  910. else
  911. boundsRect.shiftYEdgeTo(ellipsisBox->right());
  912. flipForWritingMode(boundsRect);
  913. boundsRect.moveBy(accumulatedOffset);
  914. // We are beyond the ellipsis box.
  915. if (locationInContainer.intersects(boundsRect))
  916. return false;
  917. }
  918. LayoutRect frameRect = roundedFrameRect();
  919. LayoutUnit minX = frameRect.x();
  920. LayoutUnit minY = frameRect.y();
  921. LayoutUnit width = frameRect.width();
  922. LayoutUnit height = frameRect.height();
  923. // Constrain our hit testing to the line top and bottom if necessary.
  924. bool noQuirksMode = renderer()->document()->inNoQuirksMode();
  925. if (!noQuirksMode && !hasTextChildren() && !(descendantsHaveSameLineHeightAndBaseline() && hasTextDescendants())) {
  926. RootInlineBox* rootBox = root();
  927. LayoutUnit& top = isHorizontal() ? minY : minX;
  928. LayoutUnit& logicalHeight = isHorizontal() ? height : width;
  929. LayoutUnit bottom = min(rootBox->lineBottom(), top + logicalHeight);
  930. top = max(rootBox->lineTop(), top);
  931. logicalHeight = bottom - top;
  932. }
  933. // Move x/y to our coordinates.
  934. LayoutRect rect(minX, minY, width, height);
  935. flipForWritingMode(rect);
  936. rect.moveBy(accumulatedOffset);
  937. if (locationInContainer.intersects(rect)) {
  938. renderer()->updateHitTestResult(result, flipForWritingMode(locationInContainer.point() - toLayoutSize(accumulatedOffset))); // Don't add in m_x or m_y here, we want coords in the containing block's space.
  939. if (!result.addNodeToRectBasedTestResult(renderer()->node(), request, locationInContainer, rect))
  940. return true;
  941. }
  942. return false;
  943. }
  944. void InlineFlowBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset, LayoutUnit lineTop, LayoutUnit lineBottom)
  945. {
  946. LayoutRect overflowRect(visualOverflowRect(lineTop, lineBottom));
  947. overflowRect.inflate(renderer()->maximalOutlineSize(paintInfo.phase));
  948. flipForWritingMode(overflowRect);
  949. overflowRect.moveBy(paintOffset);
  950. if (!paintInfo.rect.intersects(pixelSnappedIntRect(overflowRect)))
  951. return;
  952. if (paintInfo.phase != PaintPhaseChildOutlines) {
  953. if (paintInfo.phase == PaintPhaseOutline || paintInfo.phase == PaintPhaseSelfOutline) {
  954. // Add ourselves to the paint info struct's list of inlines that need to paint their
  955. // outlines.
  956. if (renderer()->style()->visibility() == VISIBLE && renderer()->hasOutline() && !isRootInlineBox()) {
  957. RenderInline* inlineFlow = toRenderInline(renderer());
  958. RenderBlock* cb = 0;
  959. bool containingBlockPaintsContinuationOutline = inlineFlow->continuation() || inlineFlow->isInlineElementContinuation();
  960. if (containingBlockPaintsContinuationOutline) {
  961. // FIXME: See https://bugs.webkit.org/show_bug.cgi?id=54690. We currently don't reconnect inline continuations
  962. // after a child removal. As a result, those merged inlines do not get seperated and hence not get enclosed by
  963. // anonymous blocks. In this case, it is better to bail out and paint it ourself.
  964. RenderBlock* enclosingAnonymousBlock = renderer()->containingBlock();
  965. if (!enclosingAnonymousBlock->isAnonymousBlock())
  966. containingBlockPaintsContinuationOutline = false;
  967. else {
  968. cb = enclosingAnonymousBlock->containingBlock();
  969. for (RenderBoxModelObject* box = boxModelObject(); box != cb; box = box->parent()->enclosingBoxModelObject()) {
  970. if (box->hasSelfPaintingLayer()) {
  971. containingBlockPaintsContinuationOutline = false;
  972. break;
  973. }
  974. }
  975. }
  976. }
  977. if (containingBlockPaintsContinuationOutline) {
  978. // Add ourselves to the containing block of the entire continuation so that it can
  979. // paint us atomically.
  980. cb->addContinuationWithOutline(toRenderInline(renderer()->node()->renderer()));
  981. } else if (!inlineFlow->isInlineElementContinuation())
  982. paintInfo.outlineObjects->add(inlineFlow);
  983. }
  984. } else if (paintInfo.phase == PaintPhaseMask) {
  985. paintMask(paintInfo, paintOffset);
  986. return;
  987. } else {
  988. // Paint our background, border and box-shadow.
  989. paintBoxDecorations(paintInfo, paintOffset);
  990. }
  991. }
  992. if (paintInfo.phase == PaintPhaseMask)
  993. return;
  994. PaintPhase paintPhase = paintInfo.phase == PaintPhaseChildOutlines ? PaintPhaseOutline : paintInfo.phase;
  995. PaintInfo childInfo(paintInfo);
  996. childInfo.phase = paintPhase;
  997. childInfo.updateSubtreePaintRootForChildren(renderer());
  998. // Paint our children.
  999. if (paintPhase != PaintPhaseSelfOutline) {
  1000. for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) {
  1001. if (curr->renderer()->isText() || !curr->boxModelObject()->hasSelfPaintingLayer())
  1002. curr->paint(childInfo, paintOffset, lineTop, lineBottom);
  1003. }
  1004. }
  1005. }
  1006. void InlineFlowBox::paintFillLayers(const PaintInfo& paintInfo, const Color& c, const FillLayer* fillLayer, const LayoutRect& rect, CompositeOperator op)
  1007. {
  1008. if (!fillLayer)
  1009. return;
  1010. paintFillLayers(paintInfo, c, fillLayer->next(), rect, op);
  1011. paintFillLayer(paintInfo, c, fillLayer, rect, op);
  1012. }
  1013. bool InlineFlowBox::boxShadowCanBeAppliedToBackground(const FillLayer& lastBackgroundLayer) const
  1014. {
  1015. // The checks here match how paintFillLayer() decides whether to clip (if it does, the shadow
  1016. // would be clipped out, so it has to be drawn separately).
  1017. StyleImage* image = lastBackgroundLayer.image();
  1018. bool hasFillImage = image && image->canRender(renderer(), renderer()->style()->effectiveZoom());
  1019. return (!hasFillImage && !renderer()->style()->hasBorderRadius()) || (!prevLineBox() && !nextLineBox()) || !parent();
  1020. }
  1021. void InlineFlowBox::paintFillLayer(const PaintInfo& paintInfo, const Color& c, const FillLayer* fillLayer, const LayoutRect& rect, CompositeOperator op)
  1022. {
  1023. StyleImage* img = fillLayer->image();
  1024. bool hasFillImage = img && img->canRender(renderer(), renderer()->style()->effectiveZoom());
  1025. if ((!hasFillImage && !renderer()->style()->hasBorderRadius()) || (!prevLineBox() && !nextLineBox()) || !parent())
  1026. boxModelObject()->paintFillLayerExtended(paintInfo, c, fillLayer, rect, BackgroundBleedNone, this, rect.size(), op);
  1027. #if ENABLE(CSS_BOX_DECORATION_BREAK)
  1028. else if (renderer()->style()->boxDecorationBreak() == DCLONE) {
  1029. GraphicsContextStateSaver stateSaver(*paintInfo.context);
  1030. paintInfo.context->clip(LayoutRect(rect.x(), rect.y(), width(), height()));
  1031. boxModelObject()->paintFillLayerExtended(paintInfo, c, fillLayer, rect, BackgroundBleedNone, this, rect.size(), op);
  1032. }
  1033. #endif
  1034. else {
  1035. // We have a fill image that spans multiple lines.
  1036. // We need to adjust tx and ty by the width of all previous lines.
  1037. // Think of background painting on inlines as though you had one long line, a single continuous
  1038. // strip. Even though that strip has been broken up across multiple lines, you still paint it
  1039. // as though you had one single line. This means each line has to pick up the background where
  1040. // the previous line left off.
  1041. LayoutUnit logicalOffsetOnLine = 0;
  1042. LayoutUnit totalLogicalWidth;
  1043. if (renderer()->style()->direction() == LTR) {
  1044. for (InlineFlowBox* curr = prevLineBox(); curr; curr = curr->prevLineBox())
  1045. logicalOffsetOnLine += curr->logicalWidth();
  1046. totalLogicalWidth = logicalOffsetOnLine;
  1047. for (InlineFlowBox* curr = this; curr; curr = curr->nextLineBox())
  1048. totalLogicalWidth += curr->logicalWidth();
  1049. } else {
  1050. for (InlineFlowBox* curr = nextLineBox(); curr; curr = curr->nextLineBox())
  1051. logicalOffsetOnLine += curr->logicalWidth();
  1052. totalLogicalWidth = logicalOffsetOnLine;
  1053. for (InlineFlowBox* curr = this; curr; curr = curr->prevLineBox())
  1054. totalLogicalWidth += curr->logicalWidth();
  1055. }
  1056. LayoutUnit stripX = rect.x() - (isHorizontal() ? logicalOffsetOnLine : LayoutUnit());
  1057. LayoutUnit stripY = rect.y() - (isHorizontal() ? LayoutUnit() : logicalOffsetOnLine);
  1058. LayoutUnit stripWidth = isHorizontal() ? totalLogicalWidth : static_cast<LayoutUnit>(width());
  1059. LayoutUnit stripHeight = isHorizontal() ? static_cast<LayoutUnit>(height()) : totalLogicalWidth;
  1060. GraphicsContextStateSaver stateSaver(*paintInfo.context);
  1061. paintInfo.context->clip(LayoutRect(rect.x(), rect.y(), width(), height()));
  1062. boxModelObject()->paintFillLayerExtended(paintInfo, c, fillLayer, LayoutRect(stripX, stripY, stripWidth, stripHeight), BackgroundBleedNone, this, rect.size(), op);
  1063. }
  1064. }
  1065. void InlineFlowBox::paintBoxShadow(const PaintInfo& info, RenderStyle* s, ShadowStyle shadowStyle, const LayoutRect& paintRect)
  1066. {
  1067. if ((!prevLineBox() && !nextLineBox()) || !parent())
  1068. boxModelObject()->paintBoxShadow(info, paintRect, s, shadowStyle);
  1069. else {
  1070. // FIXME: We can do better here in the multi-line case. We want to push a clip so that the shadow doesn't
  1071. // protrude incorrectly at the edges, and we want to possibly include shadows cast from the previous/following lines
  1072. boxModelObject()->paintBoxShadow(info, paintRect, s, shadowStyle, includeLogicalLeftEdge(), includeLogicalRightEdge());
  1073. }
  1074. }
  1075. void InlineFlowBox::constrainToLineTopAndBottomIfNeeded(LayoutRect& rect) const
  1076. {
  1077. bool noQuirksMode = renderer()->document()->inNoQuirksMode();
  1078. if (!noQuirksMode && !hasTextChildren() && !(descendantsHaveSameLineHeightAndBaseline() && hasTextDescendants())) {
  1079. const RootInlineBox* rootBox = root();
  1080. LayoutUnit logicalTop = isHorizontal() ? rect.y() : rect.x();
  1081. LayoutUnit logicalHeight = isHorizontal() ? rect.height() : rect.width();
  1082. LayoutUnit bottom = min(rootBox->lineBottom(), logicalTop + logicalHeight);
  1083. logicalTop = max(rootBox->lineTop(), logicalTop);
  1084. logicalHeight = bottom - logicalTop;
  1085. if (isHorizontal()) {
  1086. rect.setY(logicalTop);
  1087. rect.setHeight(logicalHeight);
  1088. } else {
  1089. rect.setX(logicalTop);
  1090. rect.setWidth(logicalHeight);
  1091. }
  1092. }
  1093. }
  1094. static LayoutRect clipRectForNinePieceImageStrip(InlineFlowBox* box, const NinePieceImage& image, const LayoutRect& paintRect)
  1095. {
  1096. LayoutRect clipRect(paintRect);
  1097. RenderStyle* style = box->renderer()->style();
  1098. LayoutBoxExtent outsets = style->imageOutsets(image);
  1099. if (box->isHorizontal()) {
  1100. clipRect.setY(paintRect.y() - outsets.top());
  1101. clipRect.setHeight(paintRect.height() + outsets.top() + outsets.bottom());
  1102. if (box->includeLogicalLeftEdge()) {
  1103. clipRect.setX(paintRect.x() - outsets.left());
  1104. clipRect.setWidth(paintRect.width() + outsets.left());
  1105. }
  1106. if (box->includeLogicalRightEdge())
  1107. clipRect.setWidth(clipRect.width() + outsets.right());
  1108. } else {
  1109. clipRect.setX(paintRect.x() - outsets.left());
  1110. clipRect.setWidth(paintRect.width() + outsets.left() + outsets.right());
  1111. if (box->includeLogicalLeftEdge()) {
  1112. clipRect.setY(paintRect.y() - outsets.top());
  1113. clipRect.setHeight(paintRect.height() + outsets.top());
  1114. }
  1115. if (box->includeLogicalRightEdge())
  1116. clipRect.setHeight(clipRect.height() + outsets.bottom());
  1117. }
  1118. return clipRect;
  1119. }
  1120. void InlineFlowBox::paintBoxDecorations(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
  1121. {
  1122. if (!paintInfo.shouldPaintWithinRoot(renderer()) || renderer()->style()->visibility() != VISIBLE || paintInfo.phase != PaintPhaseForeground)
  1123. return;
  1124. // Pixel snap background/border painting.
  1125. LayoutRect frameRect = roundedFrameRect();
  1126. constrainToLineTopAndBottomIfNeeded(frameRect);
  1127. // Move x/y to our coordinates.
  1128. LayoutRect localRect(frameRect);
  1129. flipForWritingMode(localRect);
  1130. LayoutPoint adjustedPaintoffset = paintOffset + localRect.location();
  1131. GraphicsContext* context = paintInfo.context;
  1132. // You can use p::first-line to specify a background. If so, the root line boxes for
  1133. // a line may actually have to paint a background.
  1134. RenderStyle* styleToUse = renderer()->style(isFirstLineStyle());
  1135. if ((!parent() && isFirstLineStyle() && styleToUse != renderer()->style()) || (parent() && renderer()->hasBoxDecorations())) {
  1136. LayoutRect paintRect = LayoutRect(adjustedPaintoffset, frameRect.size());
  1137. // Shadow comes first and is behind the background and border.
  1138. if (!boxModelObject()->boxShadowShouldBeAppliedToBackground(BackgroundBleedNone, this))
  1139. paintBoxShadow(paintInfo, styleToUse, Normal, paintRect);
  1140. Color c = styleToUse->visitedDependentColor(CSSPropertyBackgroundColor);
  1141. paintFillLayers(paintInfo, c, styleToUse->backgroundLayers(), paintRect);
  1142. paintBoxShadow(paintInfo, styleToUse, Inset, paintRect);
  1143. // :first-line cannot be used to put borders on a line. Always paint borders with our
  1144. // non-first-line style.
  1145. if (parent() && renderer()->style()->hasBorder()) {
  1146. const NinePieceImage& borderImage = renderer()->style()->borderImage();
  1147. StyleImage* borderImageSource = borderImage.image();
  1148. bool hasBorderImage = borderImageSource && borderImageSource->canRender(renderer(), styleToUse->effectiveZoom());
  1149. if (hasBorderImage && !borderImageSource->isLoaded())
  1150. return; // Don't paint anything while we wait for the image to load.
  1151. // The simple case is where we either have no border image or we are the only box for this object. In those
  1152. // cases only a single call to draw is required.
  1153. if (!hasBorderImage || (!prevLineBox() && !nextLineBox()))
  1154. boxModelObject()->paintBorder(paintInfo, paintRect, renderer()->style(isFirstLineStyle()), BackgroundBleedNone, includeLogicalLeftEdge(), includeLogicalRightEdge());
  1155. else {
  1156. // We have a border image that spans multiple lines.
  1157. // We need to adjust tx and ty by the width of all previous lines.
  1158. // Think of border image painting on inlines as though you had one long line, a single continuous
  1159. // strip. Even though that strip has been broken up across multiple lines, you still paint it
  1160. // as though you had one single line. This means each line has to pick up the image where
  1161. // the previous line left off.
  1162. // FIXME: What the heck do we do with RTL here? The math we're using is obviously not right,
  1163. // but it isn't even clear how this should work at all.
  1164. LayoutUnit logicalOffsetOnLine = 0;
  1165. for (InlineFlowBox* curr = prevLineBox(); curr; curr = curr->prevLineBox())
  1166. logicalOffsetOnLine += curr->logicalWidth();
  1167. LayoutUnit totalLogicalWidth = logicalOffsetOnLine;
  1168. for (InlineFlowBox* curr = this; curr; curr = curr->nextLineBox())
  1169. totalLogicalWidth += curr->logicalWidth();
  1170. LayoutUnit stripX = adjustedPaintoffset.x() - (isHorizontal() ? logicalOffsetOnLine : LayoutUnit());
  1171. LayoutUnit stripY = adjustedPaintoffset.y() - (isHorizontal() ? LayoutUnit() : logicalOffsetOnLine);
  1172. LayoutUnit stripWidth = isHorizontal() ? totalLogicalWidth : frameRect.width();
  1173. LayoutUnit stripHeight = isHorizontal() ? frameRect.height() : totalLogicalWidth;
  1174. LayoutRect clipRect = clipRectForNinePieceImageStrip(this, borderImage, paintRect);
  1175. GraphicsContextStateSaver stateSaver(*context);
  1176. context->clip(clipRect);
  1177. boxModelObject()->paintBorder(paintInfo, LayoutRect(stripX, stripY, stripWidth, stripHeight), renderer()->style(isFirstLineStyle()));
  1178. }
  1179. }
  1180. }
  1181. }
  1182. void InlineFlowBox::paintMask(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
  1183. {
  1184. if (!paintInfo.shouldPaintWithinRoot(renderer()) || renderer()->style()->visibility() != VISIBLE || paintInfo.phase != PaintPhaseMask)
  1185. return;
  1186. // Pixel snap mask painting.
  1187. LayoutRect frameRect = roundedFrameRect();
  1188. constrainToLineTopAndBottomIfNeeded(frameRect);
  1189. // Move x/y to our coordinates.
  1190. LayoutRect localRect(frameRect);
  1191. flipForWritingMode(localRect);
  1192. LayoutPoint adjustedPaintOffset = paintOffset + localRect.location();
  1193. const NinePieceImage& maskNinePieceImage = renderer()->style()->maskBoxImage();
  1194. StyleImage* maskBoxImage = renderer()->style()->maskBoxImage().image();
  1195. // Figure out if we need to push a transparency layer to render our mask.
  1196. bool pushTransparencyLayer = false;
  1197. bool compositedMask = renderer()->hasLayer() && boxModelObject()->layer()->hasCompositedMask();
  1198. bool flattenCompositingLayers = renderer()->view()->frameView() && renderer()->view()->frameView()->paintBehavior() & PaintBehaviorFlattenCompositingLayers;
  1199. CompositeOperator compositeOp = CompositeSourceOver;
  1200. if (!compositedMask || flattenCompositingLayers) {
  1201. if ((maskBoxImage && renderer()->style()->maskLayers()->hasImage()) || renderer()->style()->maskLayers()->next())
  1202. pushTransparencyLayer = true;
  1203. compositeOp = CompositeDestinationIn;
  1204. if (pushTransparencyLayer) {
  1205. paintInfo.context->setCompositeOperation(CompositeDestinationIn);
  1206. paintInfo.context->beginTransparencyLayer(1.0f);
  1207. compositeOp = CompositeSourceOver;
  1208. }
  1209. }
  1210. LayoutRect paintRect = LayoutRect(adjustedPaintOffset, frameRect.size());
  1211. paintFillLayers(paintInfo, Color(), renderer()->style()->maskLayers(), paintRect, compositeOp);
  1212. bool hasBoxImage = maskBoxImage && maskBoxImage->canRender(renderer(), renderer()->style()->effectiveZoom());
  1213. if (!hasBoxImage || !maskBoxImage->isLoaded()) {
  1214. if (pushTransparencyLayer)
  1215. paintInfo.context->endTransparencyLayer();
  1216. return; // Don't paint anything while we wait for the image to load.
  1217. }
  1218. // The simple case is where we are the only box for this object. In those
  1219. // cases only a single call to draw is required.
  1220. if (!prevLineBox() && !nextLineBox()) {
  1221. boxModelObject()->paintNinePieceImage(paintInfo.context, LayoutRect(adjustedPaintOffset, frameRect.size()), renderer()->style(), maskNinePieceImage, compositeOp);
  1222. } else {
  1223. // We have a mask image that spans multiple lines.
  1224. // We need to adjust _tx and _ty by the width of all previous lines.
  1225. LayoutUnit logicalOffsetOnLine = 0;
  1226. for (InlineFlowBox* curr = prevLineBox(); curr; curr = curr->prevLineBox())
  1227. logicalOffsetOnLine += curr->logicalWidth();
  1228. LayoutUnit totalLogicalWidth = logicalOffsetOnLine;
  1229. for (InlineFlowBox* curr = this; curr; curr = curr->nextLineBox())
  1230. totalLogicalWidth += curr->logicalWidth();
  1231. LayoutUnit stripX = adjustedPaintOffset.x() - (isHorizontal() ? logicalOffsetOnLine : LayoutUnit());
  1232. LayoutUnit stripY = adjustedPaintOffset.y() - (isHorizontal() ? LayoutUnit() : logicalOffsetOnLine);
  1233. LayoutUnit stripWidth = isHorizontal() ? totalLogicalWidth : frameRect.width();
  1234. LayoutUnit stripHeight = isHorizontal() ? frameRect.height() : totalLogicalWidth;
  1235. LayoutRect clipRect = clipRectForNinePieceImageStrip(this, maskNinePieceImage, paintRect);
  1236. GraphicsContextStateSaver stateSaver(*paintInfo.context);
  1237. paintInfo.context->clip(clipRect);
  1238. boxModelObject()->paintNinePieceImage(paintInfo.context, LayoutRect(stripX, stripY, stripWidth, stripHeight), renderer()->style(), maskNinePieceImage, compositeOp);
  1239. }
  1240. if (pushTransparencyLayer)
  1241. paintInfo.context->endTransparencyLayer();
  1242. }
  1243. InlineBox* InlineFlowBox::firstLeafChild() const
  1244. {
  1245. InlineBox* leaf = 0;
  1246. for (InlineBox* child = firstChild(); child && !leaf; child = child->nextOnLine())
  1247. leaf = child->isLeaf() ? child : toInlineFlowBox(child)->firstLeafChild();
  1248. return leaf;
  1249. }
  1250. InlineBox* InlineFlowBox::lastLeafChild() const
  1251. {
  1252. InlineBox* leaf = 0;
  1253. for (InlineBox* child = lastChild(); child && !leaf; child = child->prevOnLine())
  1254. leaf = child->isLeaf() ? child : toInlineFlowBox(child)->lastLeafChild();
  1255. return leaf;
  1256. }
  1257. RenderObject::SelectionState InlineFlowBox::selectionState()
  1258. {
  1259. return RenderObject::SelectionNone;
  1260. }
  1261. bool InlineFlowBox::canAccommodateEllipsis(bool ltr, int blockEdge, int ellipsisWidth) const
  1262. {
  1263. for (InlineBox *box = firstChild(); box; box = box->nextOnLine()) {
  1264. if (!box->canAccommodateEllipsis(ltr, blockEdge, ellipsisWidth))
  1265. return false;
  1266. }
  1267. return true;
  1268. }
  1269. float InlineFlowBox::placeEllipsisBox(bool ltr, float blockLeftEdge, float blockRightEdge, float ellipsisWidth, float &truncatedWidth, bool& foundBox)
  1270. {
  1271. float result = -1;
  1272. // We iterate over all children, the foundBox variable tells us when we've found the
  1273. // box containing the ellipsis. All boxes after that one in the flow are hidden.
  1274. // If our flow is ltr then iterate over the boxes from left to right, otherwise iterate
  1275. // from right to left. Varying the order allows us to correctly hide the boxes following the ellipsis.
  1276. InlineBox* box = ltr ? firstChild() : lastChild();
  1277. // NOTE: these will cross after foundBox = true.
  1278. int visibleLeftEdge = blockLeftEdge;
  1279. int visibleRightEdge = blockRightEdge;
  1280. while (box) {
  1281. int currResult = box->placeEllipsisBox(ltr, visibleLeftEdge, visibleRightEdge, ellipsisWidth, truncatedWidth, foundBox);
  1282. if (currResult != -1 && result == -1)
  1283. result = currResult;
  1284. if (ltr) {
  1285. visibleLeftEdge += box->logicalWidth();
  1286. box = box->nextOnLine();
  1287. }
  1288. else {
  1289. visibleRightEdge -= box->logicalWidth();
  1290. box = box->prevOnLine();
  1291. }
  1292. }
  1293. return result;
  1294. }
  1295. void InlineFlowBox::clearTruncation()
  1296. {
  1297. for (InlineBox *box = firstChild(); box; box = box->nextOnLine())
  1298. box->clearTruncation();
  1299. }
  1300. LayoutUnit InlineFlowBox::computeOverAnnotationAdjustment(LayoutUnit allowedPosition) const
  1301. {
  1302. LayoutUnit result = 0;
  1303. for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) {
  1304. if (curr->renderer()->isOutOfFlowPositioned())
  1305. continue; // Positioned placeholders don't affect calculations.
  1306. if (curr->isInlineFlowBox())
  1307. result = max(result, toInlineFlowBox(curr)->computeOverAnnotationAdjustment(allowedPosition));
  1308. if (curr->renderer()->isReplaced() && curr->renderer()->isRubyRun() && curr->renderer()->style()->rubyPosition() == RubyPositionBefore) {
  1309. RenderRubyRun* rubyRun = toRenderRubyRun(curr->renderer());
  1310. RenderRubyText* rubyText = rubyRun->rubyText();
  1311. if (!rubyText)
  1312. continue;
  1313. if (!rubyRun->style()->isFlippedLinesWritingMode()) {
  1314. LayoutUnit topOfFirstRubyTextLine = rubyText->logicalTop() + (rubyText->firstRootBox() ? rubyText->firstRootBox()->lineTop() : LayoutUnit());
  1315. if (topOfFirstRubyTextLine >= 0)
  1316. continue;
  1317. topOfFirstRubyTextLine += curr->logicalTop();
  1318. result = max(result, allowedPosition - topOfFirstRubyTextLine);
  1319. } else {
  1320. LayoutUnit bottomOfLastRubyTextLine = rubyText->logicalTop() + (rubyText->lastRootBox() ? rubyText->lastRootBox()->lineBottom() : rubyText->logicalHeight());
  1321. if (bottomOfLastRubyTextLine <= curr->logicalHeight())
  1322. continue;
  1323. bottomOfLastRubyTextLine += curr->logicalTop();
  1324. result = max(result, bottomOfLastRubyTextLine - allowedPosition);
  1325. }
  1326. }
  1327. if (curr->isInlineTextBox()) {
  1328. RenderStyle* style = curr->renderer()->style(isFirstLineStyle());
  1329. TextEmphasisPosition emphasisMarkPosition;
  1330. if (style->textEmphasisMark() != TextEmphasisMarkNone && toInlineTextBox(curr)->getEmphasisMarkPosition(style, emphasisMarkPosition) && emphasisMarkPosition == TextEmphasisPositionOver) {
  1331. if (!style->isFlippedLinesWritingMode()) {
  1332. int topOfEmphasisMark = curr->logicalTop() - style->font().emphasisMarkHeight(style->textEmphasisMarkString());
  1333. result = max(result, allowedPosition - topOfEmphasisMark);
  1334. } else {
  1335. int bottomOfEmphasisMark = curr->logicalBottom() + style->font().emphasisMarkHeight(style->textEmphasisMarkString());
  1336. result = max(result, bottomOfEmphasisMark - allowedPosition);
  1337. }
  1338. }
  1339. }
  1340. }
  1341. return result;
  1342. }
  1343. LayoutUnit InlineFlowBox::computeUnderAnnotationAdjustment(LayoutUnit allowedPosition) const
  1344. {
  1345. LayoutUnit result = 0;
  1346. for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) {
  1347. if (curr->renderer()->isOutOfFlowPositioned())
  1348. continue; // Positioned placeholders don't affect calculations.
  1349. if (curr->isInlineFlowBox())
  1350. result = max(result, toInlineFlowBox(curr)->computeUnderAnnotationAdjustment(allowedPosition));
  1351. if (curr->renderer()->isReplaced() && curr->renderer()->isRubyRun() && curr->renderer()->style()->rubyPosition() == RubyPositionAfter) {
  1352. RenderRubyRun* rubyRun = toRenderRubyRun(curr->renderer());
  1353. RenderRubyText* rubyText = rubyRun->rubyText();
  1354. if (!rubyText)
  1355. continue;
  1356. if (rubyRun->style()->isFlippedLinesWritingMode()) {
  1357. LayoutUnit topOfFirstRubyTextLine = rubyText->logicalTop() + (rubyText->firstRootBox() ? rubyText->firstRootBox()->lineTop() : LayoutUnit());
  1358. if (topOfFirstRubyTextLine >= 0)
  1359. continue;
  1360. topOfFirstRubyTextLine += curr->logicalTop();
  1361. result = max(result, allowedPosition - topOfFirstRubyTextLine);
  1362. } else {
  1363. LayoutUnit bottomOfLastRubyTextLine = rubyText->logicalTop() + (rubyText->lastRootBox() ? rubyText->lastRootBox()->lineBottom() : rubyText->logicalHeight());
  1364. if (bottomOfLastRubyTextLine <= curr->logicalHeight())
  1365. continue;
  1366. bottomOfLastRubyTextLine += curr->logicalTop();
  1367. result = max(result, bottomOfLastRubyTextLine - allowedPosition);
  1368. }
  1369. }
  1370. if (curr->isInlineTextBox()) {
  1371. RenderStyle* style = curr->renderer()->style(isFirstLineStyle());
  1372. if (style->textEmphasisMark() != TextEmphasisMarkNone && style->textEmphasisPosition() == TextEmphasisPositionUnder) {
  1373. if (!style->isFlippedLinesWritingMode()) {
  1374. LayoutUnit bottomOfEmphasisMark = curr->logicalBottom() + style->font().emphasisMarkHeight(style->textEmphasisMarkString());
  1375. result = max(result, bottomOfEmphasisMark - allowedPosition);
  1376. } else {
  1377. LayoutUnit topOfEmphasisMark = curr->logicalTop() - style->font().emphasisMarkHeight(style->textEmphasisMarkString());
  1378. result = max(result, allowedPosition - topOfEmphasisMark);
  1379. }
  1380. }
  1381. }
  1382. }
  1383. return result;
  1384. }
  1385. void InlineFlowBox::collectLeafBoxesInLogicalOrder(Vector<InlineBox*>& leafBoxesInLogicalOrder, CustomInlineBoxRangeReverse customReverseImplementation, void* userData) const
  1386. {
  1387. InlineBox* leaf = firstLeafChild();
  1388. // FIXME: The reordering code is a copy of parts from BidiResolver::createBidiRunsForLine, operating directly on InlineBoxes, instead of BidiRuns.
  1389. // Investigate on how this code could possibly be shared.
  1390. unsigned char minLevel = 128;
  1391. unsigned char maxLevel = 0;
  1392. // First find highest and lowest levels, and initialize leafBoxesInLogicalOrder with the leaf boxes in visual order.
  1393. for (; leaf; leaf = leaf->nextLeafChild()) {
  1394. minLevel = min(minLevel, leaf->bidiLevel());
  1395. maxLevel = max(maxLevel, leaf->bidiLevel());
  1396. leafBoxesInLogicalOrder.append(leaf);
  1397. }
  1398. if (renderer()->style()->rtlOrdering() == VisualOrder)
  1399. return;
  1400. // Reverse of reordering of the line (L2 according to Bidi spec):
  1401. // L2. From the highest level found in the text to the lowest odd level on each line,
  1402. // reverse any contiguous sequence of characters that are at that level or higher.
  1403. // Reversing the reordering of the line is only done up to the lowest odd level.
  1404. if (!(minLevel % 2))
  1405. ++minLevel;
  1406. Vector<InlineBox*>::iterator end = leafBoxesInLogicalOrder.end();
  1407. while (minLevel <= maxLevel) {
  1408. Vector<InlineBox*>::iterator it = leafBoxesInLogicalOrder.begin();
  1409. while (it != end) {
  1410. while (it != end) {
  1411. if ((*it)->bidiLevel() >= minLevel)
  1412. break;
  1413. ++it;
  1414. }
  1415. Vector<InlineBox*>::iterator first = it;
  1416. while (it != end) {
  1417. if ((*it)->bidiLevel() < minLevel)
  1418. break;
  1419. ++it;
  1420. }
  1421. Vector<InlineBox*>::iterator last = it;
  1422. if (customReverseImplementation) {
  1423. ASSERT(userData);
  1424. (*customReverseImplementation)(userData, first, last);
  1425. } else
  1426. std::reverse(first, last);
  1427. }
  1428. ++minLevel;
  1429. }
  1430. }
  1431. #ifndef NDEBUG
  1432. const char* InlineFlowBox::boxName() const
  1433. {
  1434. return "InlineFlowBox";
  1435. }
  1436. void InlineFlowBox::showLineTreeAndMark(const InlineBox* markedBox1, const char* markedLabel1, const InlineBox* markedBox2, const char* markedLabel2, const RenderObject* obj, int depth) const
  1437. {
  1438. InlineBox::showLineTreeAndMark(markedBox1, markedLabel1, markedBox2, markedLabel2, obj, depth);
  1439. for (const InlineBox* box = firstChild(); box; box = box->nextOnLine())
  1440. box->showLineTreeAndMark(markedBox1, markedLabel1, markedBox2, markedLabel2, obj, depth + 1);
  1441. }
  1442. void InlineFlowBox::checkConsistency() const
  1443. {
  1444. #ifdef CHECK_CONSISTENCY
  1445. ASSERT(!m_hasBadChildList);
  1446. const InlineBox* prev = 0;
  1447. for (const InlineBox* child = m_firstChild; child; child = child->nextOnLine()) {
  1448. ASSERT(child->parent() == this);
  1449. ASSERT(child->prevOnLine() == prev);
  1450. prev = child;
  1451. }
  1452. ASSERT(prev == m_lastChild);
  1453. #endif
  1454. }
  1455. #endif
  1456. } // namespace WebCore