RenderInline.cpp 69 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647
  1. /*
  2. * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
  3. * (C) 1999 Antti Koivisto (koivisto@kde.org)
  4. * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
  5. *
  6. * This library is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Library General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 2 of the License, or (at your option) any later version.
  10. *
  11. * This library is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Library General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Library General Public License
  17. * along with this library; see the file COPYING.LIB. If not, write to
  18. * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  19. * Boston, MA 02110-1301, USA.
  20. *
  21. */
  22. #include "config.h"
  23. #include "RenderInline.h"
  24. #include "Chrome.h"
  25. #include "FloatQuad.h"
  26. #include "GraphicsContext.h"
  27. #include "HitTestResult.h"
  28. #include "InlineTextBox.h"
  29. #include "Page.h"
  30. #include "RenderArena.h"
  31. #include "RenderBlock.h"
  32. #include "RenderFlowThread.h"
  33. #include "RenderFullScreen.h"
  34. #include "RenderGeometryMap.h"
  35. #include "RenderLayer.h"
  36. #include "RenderTheme.h"
  37. #include "RenderView.h"
  38. #include "StyleInheritedData.h"
  39. #include "TransformState.h"
  40. #include "VisiblePosition.h"
  41. #if ENABLE(DASHBOARD_SUPPORT) || ENABLE(DRAGGABLE_REGION)
  42. #include "Frame.h"
  43. #endif
  44. using namespace std;
  45. namespace WebCore {
  46. RenderInline::RenderInline(Element* element)
  47. : RenderBoxModelObject(element)
  48. , m_alwaysCreateLineBoxes(false)
  49. {
  50. setChildrenInline(true);
  51. }
  52. RenderInline* RenderInline::createAnonymous(Document* document)
  53. {
  54. RenderInline* renderer = new (document->renderArena()) RenderInline(0);
  55. renderer->setDocumentForAnonymous(document);
  56. return renderer;
  57. }
  58. void RenderInline::willBeDestroyed()
  59. {
  60. #if !ASSERT_DISABLED
  61. // Make sure we do not retain "this" in the continuation outline table map of our containing blocks.
  62. if (parent() && style()->visibility() == VISIBLE && hasOutline()) {
  63. bool containingBlockPaintsContinuationOutline = continuation() || isInlineElementContinuation();
  64. if (containingBlockPaintsContinuationOutline) {
  65. if (RenderBlock* cb = containingBlock()) {
  66. if (RenderBlock* cbCb = cb->containingBlock())
  67. ASSERT(!cbCb->paintsContinuationOutline(this));
  68. }
  69. }
  70. }
  71. #endif
  72. // Make sure to destroy anonymous children first while they are still connected to the rest of the tree, so that they will
  73. // properly dirty line boxes that they are removed from. Effects that do :before/:after only on hover could crash otherwise.
  74. children()->destroyLeftoverChildren();
  75. // Destroy our continuation before anything other than anonymous children.
  76. // The reason we don't destroy it before anonymous children is that they may
  77. // have continuations of their own that are anonymous children of our continuation.
  78. RenderBoxModelObject* continuation = this->continuation();
  79. if (continuation) {
  80. continuation->destroy();
  81. setContinuation(0);
  82. }
  83. if (!documentBeingDestroyed()) {
  84. if (firstLineBox()) {
  85. // We can't wait for RenderBoxModelObject::destroy to clear the selection,
  86. // because by then we will have nuked the line boxes.
  87. // FIXME: The FrameSelection should be responsible for this when it
  88. // is notified of DOM mutations.
  89. if (isSelectionBorder())
  90. view()->clearSelection();
  91. // If line boxes are contained inside a root, that means we're an inline.
  92. // In that case, we need to remove all the line boxes so that the parent
  93. // lines aren't pointing to deleted children. If the first line box does
  94. // not have a parent that means they are either already disconnected or
  95. // root lines that can just be destroyed without disconnecting.
  96. if (firstLineBox()->parent()) {
  97. for (InlineFlowBox* box = firstLineBox(); box; box = box->nextLineBox())
  98. box->remove();
  99. }
  100. } else if (parent())
  101. parent()->dirtyLinesFromChangedChild(this);
  102. }
  103. m_lineBoxes.deleteLineBoxes(renderArena());
  104. RenderBoxModelObject::willBeDestroyed();
  105. }
  106. RenderInline* RenderInline::inlineElementContinuation() const
  107. {
  108. RenderBoxModelObject* continuation = this->continuation();
  109. if (!continuation)
  110. return nullptr;
  111. if (continuation->isRenderInline())
  112. return toRenderInline(continuation);
  113. return continuation->isRenderBlock() ? toRenderBlock(continuation)->inlineElementContinuation() : nullptr;
  114. }
  115. void RenderInline::updateFromStyle()
  116. {
  117. RenderBoxModelObject::updateFromStyle();
  118. setInline(true); // Needed for run-ins, since run-in is considered a block display type.
  119. // FIXME: Support transforms and reflections on inline flows someday.
  120. setHasTransform(false);
  121. setHasReflection(false);
  122. }
  123. static RenderObject* inFlowPositionedInlineAncestor(RenderObject* p)
  124. {
  125. while (p && p->isRenderInline()) {
  126. if (p->isInFlowPositioned())
  127. return p;
  128. p = p->parent();
  129. }
  130. return 0;
  131. }
  132. static void updateStyleOfAnonymousBlockContinuations(RenderObject* box, const RenderStyle* newStyle, const RenderStyle* oldStyle)
  133. {
  134. for (;box && box->isAnonymousBlock(); box = box->nextSibling()) {
  135. if (box->style()->position() == newStyle->position())
  136. continue;
  137. if (!box->isRenderBlock())
  138. break; // We're done if we ever encounter something other than a RenderBlock.
  139. RenderBlock* block = toRenderBlock(box);
  140. if (!block->isAnonymousBlockContinuation())
  141. break; // We're done if we ever encounter something other than a continuation RenderBlock.
  142. // If we are no longer in-flow positioned but our descendant block(s) still have an in-flow positioned ancestor then
  143. // their containing anonymous block should keep its in-flow positioning.
  144. RenderInline* cont = toRenderBlock(box)->inlineElementContinuation();
  145. if (oldStyle->hasInFlowPosition() && inFlowPositionedInlineAncestor(cont))
  146. continue;
  147. RefPtr<RenderStyle> blockStyle = RenderStyle::createAnonymousStyleWithDisplay(block->style(), BLOCK);
  148. blockStyle->setPosition(newStyle->position());
  149. block->setStyle(blockStyle);
  150. }
  151. }
  152. void RenderInline::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
  153. {
  154. RenderBoxModelObject::styleDidChange(diff, oldStyle);
  155. // Ensure that all of the split inlines pick up the new style. We
  156. // only do this if we're an inline, since we don't want to propagate
  157. // a block's style to the other inlines.
  158. // e.g., <font>foo <h4>goo</h4> moo</font>. The <font> inlines before
  159. // and after the block share the same style, but the block doesn't
  160. // need to pass its style on to anyone else.
  161. RenderStyle* newStyle = style();
  162. RenderInline* continuation = inlineElementContinuation();
  163. for (RenderInline* currCont = continuation; currCont; currCont = currCont->inlineElementContinuation()) {
  164. RenderBoxModelObject* nextCont = currCont->continuation();
  165. currCont->setContinuation(0);
  166. currCont->setStyle(newStyle);
  167. currCont->setContinuation(nextCont);
  168. }
  169. // If an inline's in-flow positioning has changed then any descendant blocks will need to change their in-flow positioning accordingly.
  170. // Do this by updating the position of the descendant blocks' containing anonymous blocks - there may be more than one.
  171. if (continuation && oldStyle && newStyle->position() != oldStyle->position()
  172. && (newStyle->hasInFlowPosition() || oldStyle->hasInFlowPosition())) {
  173. // If any descendant blocks exist then they will be in the next anonymous block and its siblings.
  174. RenderObject* block = containingBlock()->nextSibling();
  175. ASSERT(block && block->isAnonymousBlock());
  176. updateStyleOfAnonymousBlockContinuations(block, newStyle, oldStyle);
  177. }
  178. if (!m_alwaysCreateLineBoxes) {
  179. bool alwaysCreateLineBoxes = hasSelfPaintingLayer() || hasBoxDecorations() || newStyle->hasPadding() || newStyle->hasMargin() || hasOutline();
  180. if (oldStyle && alwaysCreateLineBoxes) {
  181. dirtyLineBoxes(false);
  182. setNeedsLayout(true);
  183. }
  184. m_alwaysCreateLineBoxes = alwaysCreateLineBoxes;
  185. }
  186. }
  187. void RenderInline::updateAlwaysCreateLineBoxes(bool fullLayout)
  188. {
  189. // Once we have been tainted once, just assume it will happen again. This way effects like hover highlighting that change the
  190. // background color will only cause a layout on the first rollover.
  191. if (m_alwaysCreateLineBoxes)
  192. return;
  193. RenderStyle* parentStyle = parent()->style();
  194. RenderInline* parentRenderInline = parent()->isRenderInline() ? toRenderInline(parent()) : 0;
  195. bool checkFonts = document()->inNoQuirksMode();
  196. RenderFlowThread* flowThread = flowThreadContainingBlock();
  197. bool alwaysCreateLineBoxes = (parentRenderInline && parentRenderInline->alwaysCreateLineBoxes())
  198. || (parentRenderInline && parentStyle->verticalAlign() != BASELINE)
  199. || style()->verticalAlign() != BASELINE
  200. || style()->textEmphasisMark() != TextEmphasisMarkNone
  201. || (checkFonts && (!parentStyle->font().fontMetrics().hasIdenticalAscentDescentAndLineGap(style()->font().fontMetrics())
  202. || parentStyle->lineHeight() != style()->lineHeight()))
  203. || (flowThread && flowThread->hasRegionsWithStyling());
  204. if (!alwaysCreateLineBoxes && checkFonts && document()->styleSheetCollection()->usesFirstLineRules()) {
  205. // Have to check the first line style as well.
  206. parentStyle = parent()->style(true);
  207. RenderStyle* childStyle = style(true);
  208. alwaysCreateLineBoxes = !parentStyle->font().fontMetrics().hasIdenticalAscentDescentAndLineGap(childStyle->font().fontMetrics())
  209. || childStyle->verticalAlign() != BASELINE
  210. || parentStyle->lineHeight() != childStyle->lineHeight();
  211. }
  212. if (alwaysCreateLineBoxes) {
  213. if (!fullLayout)
  214. dirtyLineBoxes(false);
  215. m_alwaysCreateLineBoxes = true;
  216. }
  217. }
  218. LayoutRect RenderInline::localCaretRect(InlineBox* inlineBox, int, LayoutUnit* extraWidthToEndOfLine)
  219. {
  220. if (firstChild()) {
  221. // This condition is possible if the RenderInline is at an editing boundary,
  222. // i.e. the VisiblePosition is:
  223. // <RenderInline editingBoundary=true>|<RenderText> </RenderText></RenderInline>
  224. // FIXME: need to figure out how to make this return a valid rect, note that
  225. // there are no line boxes created in the above case.
  226. return LayoutRect();
  227. }
  228. ASSERT_UNUSED(inlineBox, !inlineBox);
  229. if (extraWidthToEndOfLine)
  230. *extraWidthToEndOfLine = 0;
  231. LayoutRect caretRect = localCaretRectForEmptyElement(borderAndPaddingWidth(), 0);
  232. if (InlineBox* firstBox = firstLineBox())
  233. caretRect.moveBy(roundedLayoutPoint(firstBox->topLeft()));
  234. return caretRect;
  235. }
  236. void RenderInline::addChild(RenderObject* newChild, RenderObject* beforeChild)
  237. {
  238. if (continuation())
  239. return addChildToContinuation(newChild, beforeChild);
  240. return addChildIgnoringContinuation(newChild, beforeChild);
  241. }
  242. static RenderBoxModelObject* nextContinuation(RenderObject* renderer)
  243. {
  244. if (renderer->isInline() && !renderer->isReplaced())
  245. return toRenderInline(renderer)->continuation();
  246. return toRenderBlock(renderer)->inlineElementContinuation();
  247. }
  248. RenderBoxModelObject* RenderInline::continuationBefore(RenderObject* beforeChild)
  249. {
  250. if (beforeChild && beforeChild->parent() == this)
  251. return this;
  252. RenderBoxModelObject* curr = nextContinuation(this);
  253. RenderBoxModelObject* nextToLast = this;
  254. RenderBoxModelObject* last = this;
  255. while (curr) {
  256. if (beforeChild && beforeChild->parent() == curr) {
  257. if (curr->firstChild() == beforeChild)
  258. return last;
  259. return curr;
  260. }
  261. nextToLast = last;
  262. last = curr;
  263. curr = nextContinuation(curr);
  264. }
  265. if (!beforeChild && !last->firstChild())
  266. return nextToLast;
  267. return last;
  268. }
  269. void RenderInline::addChildIgnoringContinuation(RenderObject* newChild, RenderObject* beforeChild)
  270. {
  271. // Make sure we don't append things after :after-generated content if we have it.
  272. if (!beforeChild && isAfterContent(lastChild()))
  273. beforeChild = lastChild();
  274. if (!newChild->isInline() && !newChild->isFloatingOrOutOfFlowPositioned()) {
  275. // We are placing a block inside an inline. We have to perform a split of this
  276. // inline into continuations. This involves creating an anonymous block box to hold
  277. // |newChild|. We then make that block box a continuation of this inline. We take all of
  278. // the children after |beforeChild| and put them in a clone of this object.
  279. RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyleWithDisplay(style(), BLOCK);
  280. // If inside an inline affected by in-flow positioning the block needs to be affected by it too.
  281. // Giving the block a layer like this allows it to collect the x/y offsets from inline parents later.
  282. if (RenderObject* positionedAncestor = inFlowPositionedInlineAncestor(this))
  283. newStyle->setPosition(positionedAncestor->style()->position());
  284. RenderBlock* newBox = RenderBlock::createAnonymous(document());
  285. newBox->setStyle(newStyle.release());
  286. RenderBoxModelObject* oldContinuation = continuation();
  287. setContinuation(newBox);
  288. splitFlow(beforeChild, newBox, newChild, oldContinuation);
  289. return;
  290. }
  291. RenderBoxModelObject::addChild(newChild, beforeChild);
  292. newChild->setNeedsLayoutAndPrefWidthsRecalc();
  293. }
  294. RenderInline* RenderInline::clone() const
  295. {
  296. RenderInline* cloneInline = new (renderArena()) RenderInline(node());
  297. cloneInline->setStyle(style());
  298. cloneInline->setFlowThreadState(flowThreadState());
  299. return cloneInline;
  300. }
  301. void RenderInline::splitInlines(RenderBlock* fromBlock, RenderBlock* toBlock,
  302. RenderBlock* middleBlock,
  303. RenderObject* beforeChild, RenderBoxModelObject* oldCont)
  304. {
  305. // Create a clone of this inline.
  306. RenderInline* cloneInline = clone();
  307. cloneInline->setContinuation(oldCont);
  308. #if ENABLE(FULLSCREEN_API)
  309. // If we're splitting the inline containing the fullscreened element,
  310. // |beforeChild| may be the renderer for the fullscreened element. However,
  311. // that renderer is wrapped in a RenderFullScreen, so |this| is not its
  312. // parent. Since the splitting logic expects |this| to be the parent, set
  313. // |beforeChild| to be the RenderFullScreen.
  314. const Element* fullScreenElement = document()->webkitCurrentFullScreenElement();
  315. if (fullScreenElement && beforeChild && beforeChild->node() == fullScreenElement)
  316. beforeChild = document()->fullScreenRenderer();
  317. #endif
  318. // Now take all of the children from beforeChild to the end and remove
  319. // them from |this| and place them in the clone.
  320. RenderObject* o = beforeChild;
  321. while (o) {
  322. RenderObject* tmp = o;
  323. o = tmp->nextSibling();
  324. cloneInline->addChildIgnoringContinuation(children()->removeChildNode(this, tmp), 0);
  325. tmp->setNeedsLayoutAndPrefWidthsRecalc();
  326. }
  327. // Hook |clone| up as the continuation of the middle block.
  328. middleBlock->setContinuation(cloneInline);
  329. // We have been reparented and are now under the fromBlock. We need
  330. // to walk up our inline parent chain until we hit the containing block.
  331. // Once we hit the containing block we're done.
  332. RenderBoxModelObject* curr = toRenderBoxModelObject(parent());
  333. RenderBoxModelObject* currChild = this;
  334. // FIXME: Because splitting is O(n^2) as tags nest pathologically, we cap the depth at which we're willing to clone.
  335. // There will eventually be a better approach to this problem that will let us nest to a much
  336. // greater depth (see bugzilla bug 13430) but for now we have a limit. This *will* result in
  337. // incorrect rendering, but the alternative is to hang forever.
  338. unsigned splitDepth = 1;
  339. const unsigned cMaxSplitDepth = 200;
  340. while (curr && curr != fromBlock) {
  341. ASSERT(curr->isRenderInline());
  342. if (splitDepth < cMaxSplitDepth) {
  343. // Create a new clone.
  344. RenderInline* cloneChild = cloneInline;
  345. cloneInline = toRenderInline(curr)->clone();
  346. // Insert our child clone as the first child.
  347. cloneInline->addChildIgnoringContinuation(cloneChild, 0);
  348. // Hook the clone up as a continuation of |curr|.
  349. RenderInline* inlineCurr = toRenderInline(curr);
  350. oldCont = inlineCurr->continuation();
  351. inlineCurr->setContinuation(cloneInline);
  352. cloneInline->setContinuation(oldCont);
  353. // Now we need to take all of the children starting from the first child
  354. // *after* currChild and append them all to the clone.
  355. o = currChild->nextSibling();
  356. while (o) {
  357. RenderObject* tmp = o;
  358. o = tmp->nextSibling();
  359. cloneInline->addChildIgnoringContinuation(inlineCurr->children()->removeChildNode(curr, tmp), 0);
  360. tmp->setNeedsLayoutAndPrefWidthsRecalc();
  361. }
  362. }
  363. // Keep walking up the chain.
  364. currChild = curr;
  365. curr = toRenderBoxModelObject(curr->parent());
  366. splitDepth++;
  367. }
  368. // Now we are at the block level. We need to put the clone into the toBlock.
  369. toBlock->children()->appendChildNode(toBlock, cloneInline);
  370. // Now take all the children after currChild and remove them from the fromBlock
  371. // and put them in the toBlock.
  372. o = currChild->nextSibling();
  373. while (o) {
  374. RenderObject* tmp = o;
  375. o = tmp->nextSibling();
  376. toBlock->children()->appendChildNode(toBlock, fromBlock->children()->removeChildNode(fromBlock, tmp));
  377. }
  378. }
  379. void RenderInline::splitFlow(RenderObject* beforeChild, RenderBlock* newBlockBox,
  380. RenderObject* newChild, RenderBoxModelObject* oldCont)
  381. {
  382. RenderBlock* pre = 0;
  383. RenderBlock* block = containingBlock();
  384. // Delete our line boxes before we do the inline split into continuations.
  385. block->deleteLineBoxTree();
  386. bool madeNewBeforeBlock = false;
  387. if (block->isAnonymousBlock() && (!block->parent() || !block->parent()->createsAnonymousWrapper())) {
  388. // We can reuse this block and make it the preBlock of the next continuation.
  389. pre = block;
  390. pre->removePositionedObjects(0);
  391. pre->removeFloatingObjects();
  392. block = block->containingBlock();
  393. } else {
  394. // No anonymous block available for use. Make one.
  395. pre = block->createAnonymousBlock();
  396. madeNewBeforeBlock = true;
  397. }
  398. RenderBlock* post = toRenderBlock(pre->createAnonymousBoxWithSameTypeAs(block));
  399. RenderObject* boxFirst = madeNewBeforeBlock ? block->firstChild() : pre->nextSibling();
  400. if (madeNewBeforeBlock)
  401. block->children()->insertChildNode(block, pre, boxFirst);
  402. block->children()->insertChildNode(block, newBlockBox, boxFirst);
  403. block->children()->insertChildNode(block, post, boxFirst);
  404. block->setChildrenInline(false);
  405. if (madeNewBeforeBlock) {
  406. RenderObject* o = boxFirst;
  407. while (o) {
  408. RenderObject* no = o;
  409. o = no->nextSibling();
  410. pre->children()->appendChildNode(pre, block->children()->removeChildNode(block, no));
  411. no->setNeedsLayoutAndPrefWidthsRecalc();
  412. }
  413. }
  414. splitInlines(pre, post, newBlockBox, beforeChild, oldCont);
  415. // We already know the newBlockBox isn't going to contain inline kids, so avoid wasting
  416. // time in makeChildrenNonInline by just setting this explicitly up front.
  417. newBlockBox->setChildrenInline(false);
  418. // We delayed adding the newChild until now so that the |newBlockBox| would be fully
  419. // connected, thus allowing newChild access to a renderArena should it need
  420. // to wrap itself in additional boxes (e.g., table construction).
  421. newBlockBox->addChild(newChild);
  422. // Always just do a full layout in order to ensure that line boxes (especially wrappers for images)
  423. // get deleted properly. Because objects moves from the pre block into the post block, we want to
  424. // make new line boxes instead of leaving the old line boxes around.
  425. pre->setNeedsLayoutAndPrefWidthsRecalc();
  426. block->setNeedsLayoutAndPrefWidthsRecalc();
  427. post->setNeedsLayoutAndPrefWidthsRecalc();
  428. }
  429. void RenderInline::addChildToContinuation(RenderObject* newChild, RenderObject* beforeChild)
  430. {
  431. RenderBoxModelObject* flow = continuationBefore(beforeChild);
  432. ASSERT(!beforeChild || beforeChild->parent()->isRenderBlock() || beforeChild->parent()->isRenderInline());
  433. RenderBoxModelObject* beforeChildParent = 0;
  434. if (beforeChild)
  435. beforeChildParent = toRenderBoxModelObject(beforeChild->parent());
  436. else {
  437. RenderBoxModelObject* cont = nextContinuation(flow);
  438. if (cont)
  439. beforeChildParent = cont;
  440. else
  441. beforeChildParent = flow;
  442. }
  443. if (newChild->isFloatingOrOutOfFlowPositioned())
  444. return beforeChildParent->addChildIgnoringContinuation(newChild, beforeChild);
  445. // A continuation always consists of two potential candidates: an inline or an anonymous
  446. // block box holding block children.
  447. bool childInline = newChild->isInline();
  448. bool bcpInline = beforeChildParent->isInline();
  449. bool flowInline = flow->isInline();
  450. if (flow == beforeChildParent)
  451. return flow->addChildIgnoringContinuation(newChild, beforeChild);
  452. else {
  453. // The goal here is to match up if we can, so that we can coalesce and create the
  454. // minimal # of continuations needed for the inline.
  455. if (childInline == bcpInline)
  456. return beforeChildParent->addChildIgnoringContinuation(newChild, beforeChild);
  457. else if (flowInline == childInline)
  458. return flow->addChildIgnoringContinuation(newChild, 0); // Just treat like an append.
  459. else
  460. return beforeChildParent->addChildIgnoringContinuation(newChild, beforeChild);
  461. }
  462. }
  463. void RenderInline::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
  464. {
  465. m_lineBoxes.paint(this, paintInfo, paintOffset);
  466. }
  467. template<typename GeneratorContext>
  468. void RenderInline::generateLineBoxRects(GeneratorContext& yield) const
  469. {
  470. if (!alwaysCreateLineBoxes())
  471. generateCulledLineBoxRects(yield, this);
  472. else if (InlineFlowBox* curr = firstLineBox()) {
  473. for (; curr; curr = curr->nextLineBox())
  474. yield(FloatRect(curr->topLeft(), curr->size()));
  475. } else
  476. yield(FloatRect());
  477. }
  478. template<typename GeneratorContext>
  479. void RenderInline::generateCulledLineBoxRects(GeneratorContext& yield, const RenderInline* container) const
  480. {
  481. if (!culledInlineFirstLineBox()) {
  482. yield(FloatRect());
  483. return;
  484. }
  485. bool isHorizontal = style()->isHorizontalWritingMode();
  486. for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
  487. if (curr->isFloatingOrOutOfFlowPositioned())
  488. continue;
  489. // We want to get the margin box in the inline direction, and then use our font ascent/descent in the block
  490. // direction (aligned to the root box's baseline).
  491. if (curr->isBox()) {
  492. RenderBox* currBox = toRenderBox(curr);
  493. if (currBox->inlineBoxWrapper()) {
  494. RootInlineBox* rootBox = currBox->inlineBoxWrapper()->root();
  495. int logicalTop = rootBox->logicalTop() + (rootBox->renderer()->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent() - container->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent());
  496. int logicalHeight = container->style(rootBox->isFirstLineStyle())->font().fontMetrics().height();
  497. if (isHorizontal)
  498. yield(FloatRect(currBox->inlineBoxWrapper()->x() - currBox->marginLeft(), logicalTop, currBox->width() + currBox->marginWidth(), logicalHeight));
  499. else
  500. yield(FloatRect(logicalTop, currBox->inlineBoxWrapper()->y() - currBox->marginTop(), logicalHeight, currBox->height() + currBox->marginHeight()));
  501. }
  502. } else if (curr->isRenderInline()) {
  503. // If the child doesn't need line boxes either, then we can recur.
  504. RenderInline* currInline = toRenderInline(curr);
  505. if (!currInline->alwaysCreateLineBoxes())
  506. currInline->generateCulledLineBoxRects(yield, container);
  507. else {
  508. for (InlineFlowBox* childLine = currInline->firstLineBox(); childLine; childLine = childLine->nextLineBox()) {
  509. RootInlineBox* rootBox = childLine->root();
  510. int logicalTop = rootBox->logicalTop() + (rootBox->renderer()->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent() - container->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent());
  511. int logicalHeight = container->style(rootBox->isFirstLineStyle())->font().fontMetrics().height();
  512. if (isHorizontal)
  513. yield(FloatRect(childLine->x() - childLine->marginLogicalLeft(),
  514. logicalTop,
  515. childLine->logicalWidth() + childLine->marginLogicalLeft() + childLine->marginLogicalRight(),
  516. logicalHeight));
  517. else
  518. yield(FloatRect(logicalTop,
  519. childLine->y() - childLine->marginLogicalLeft(),
  520. logicalHeight,
  521. childLine->logicalWidth() + childLine->marginLogicalLeft() + childLine->marginLogicalRight()));
  522. }
  523. }
  524. } else if (curr->isText()) {
  525. RenderText* currText = toRenderText(curr);
  526. for (InlineTextBox* childText = currText->firstTextBox(); childText; childText = childText->nextTextBox()) {
  527. RootInlineBox* rootBox = childText->root();
  528. int logicalTop = rootBox->logicalTop() + (rootBox->renderer()->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent() - container->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent());
  529. int logicalHeight = container->style(rootBox->isFirstLineStyle())->font().fontMetrics().height();
  530. if (isHorizontal)
  531. yield(FloatRect(childText->x(), logicalTop, childText->logicalWidth(), logicalHeight));
  532. else
  533. yield(FloatRect(logicalTop, childText->y(), logicalHeight, childText->logicalWidth()));
  534. }
  535. }
  536. }
  537. }
  538. namespace {
  539. class AbsoluteRectsGeneratorContext {
  540. public:
  541. AbsoluteRectsGeneratorContext(Vector<IntRect>& rects, const LayoutPoint& accumulatedOffset)
  542. : m_rects(rects)
  543. , m_accumulatedOffset(accumulatedOffset) { }
  544. void operator()(const FloatRect& rect)
  545. {
  546. IntRect intRect = enclosingIntRect(rect);
  547. intRect.move(m_accumulatedOffset.x(), m_accumulatedOffset.y());
  548. m_rects.append(intRect);
  549. }
  550. private:
  551. Vector<IntRect>& m_rects;
  552. const LayoutPoint& m_accumulatedOffset;
  553. };
  554. } // unnamed namespace
  555. void RenderInline::absoluteRects(Vector<IntRect>& rects, const LayoutPoint& accumulatedOffset) const
  556. {
  557. AbsoluteRectsGeneratorContext context(rects, accumulatedOffset);
  558. generateLineBoxRects(context);
  559. if (continuation()) {
  560. if (continuation()->isBox()) {
  561. RenderBox* box = toRenderBox(continuation());
  562. continuation()->absoluteRects(rects, toLayoutPoint(accumulatedOffset - containingBlock()->location() + box->locationOffset()));
  563. } else
  564. continuation()->absoluteRects(rects, toLayoutPoint(accumulatedOffset - containingBlock()->location()));
  565. }
  566. }
  567. namespace {
  568. class AbsoluteQuadsGeneratorContext {
  569. public:
  570. AbsoluteQuadsGeneratorContext(const RenderInline* renderer, Vector<FloatQuad>& quads)
  571. : m_quads(quads)
  572. , m_geometryMap()
  573. {
  574. m_geometryMap.pushMappingsToAncestor(renderer, 0);
  575. }
  576. void operator()(const FloatRect& rect)
  577. {
  578. m_quads.append(m_geometryMap.absoluteRect(rect));
  579. }
  580. private:
  581. Vector<FloatQuad>& m_quads;
  582. RenderGeometryMap m_geometryMap;
  583. };
  584. } // unnamed namespace
  585. void RenderInline::absoluteQuads(Vector<FloatQuad>& quads, bool* wasFixed) const
  586. {
  587. AbsoluteQuadsGeneratorContext context(this, quads);
  588. generateLineBoxRects(context);
  589. if (continuation())
  590. continuation()->absoluteQuads(quads, wasFixed);
  591. }
  592. LayoutUnit RenderInline::offsetLeft() const
  593. {
  594. LayoutPoint topLeft;
  595. if (InlineBox* firstBox = firstLineBoxIncludingCulling())
  596. topLeft = flooredLayoutPoint(firstBox->topLeft());
  597. return adjustedPositionRelativeToOffsetParent(topLeft).x();
  598. }
  599. LayoutUnit RenderInline::offsetTop() const
  600. {
  601. LayoutPoint topLeft;
  602. if (InlineBox* firstBox = firstLineBoxIncludingCulling())
  603. topLeft = flooredLayoutPoint(firstBox->topLeft());
  604. return adjustedPositionRelativeToOffsetParent(topLeft).y();
  605. }
  606. static LayoutUnit computeMargin(const RenderInline* renderer, const Length& margin)
  607. {
  608. if (margin.isAuto())
  609. return 0;
  610. if (margin.isFixed())
  611. return margin.value();
  612. if (margin.isPercent())
  613. return minimumValueForLength(margin, max<LayoutUnit>(0, renderer->containingBlock()->availableLogicalWidth()));
  614. if (margin.isViewportPercentage())
  615. return valueForLength(margin, 0, renderer->view());
  616. return 0;
  617. }
  618. LayoutUnit RenderInline::marginLeft() const
  619. {
  620. return computeMargin(this, style()->marginLeft());
  621. }
  622. LayoutUnit RenderInline::marginRight() const
  623. {
  624. return computeMargin(this, style()->marginRight());
  625. }
  626. LayoutUnit RenderInline::marginTop() const
  627. {
  628. return computeMargin(this, style()->marginTop());
  629. }
  630. LayoutUnit RenderInline::marginBottom() const
  631. {
  632. return computeMargin(this, style()->marginBottom());
  633. }
  634. LayoutUnit RenderInline::marginStart(const RenderStyle* otherStyle) const
  635. {
  636. return computeMargin(this, style()->marginStartUsing(otherStyle ? otherStyle : style()));
  637. }
  638. LayoutUnit RenderInline::marginEnd(const RenderStyle* otherStyle) const
  639. {
  640. return computeMargin(this, style()->marginEndUsing(otherStyle ? otherStyle : style()));
  641. }
  642. LayoutUnit RenderInline::marginBefore(const RenderStyle* otherStyle) const
  643. {
  644. return computeMargin(this, style()->marginBeforeUsing(otherStyle ? otherStyle : style()));
  645. }
  646. LayoutUnit RenderInline::marginAfter(const RenderStyle* otherStyle) const
  647. {
  648. return computeMargin(this, style()->marginAfterUsing(otherStyle ? otherStyle : style()));
  649. }
  650. const char* RenderInline::renderName() const
  651. {
  652. if (isRelPositioned())
  653. return "RenderInline (relative positioned)";
  654. if (isStickyPositioned())
  655. return "RenderInline (sticky positioned)";
  656. // FIXME: Temporary hack while the new generated content system is being implemented.
  657. if (isPseudoElement())
  658. return "RenderInline (generated)";
  659. if (isAnonymous())
  660. return "RenderInline (generated)";
  661. if (isRunIn())
  662. return "RenderInline (run-in)";
  663. return "RenderInline";
  664. }
  665. bool RenderInline::nodeAtPoint(const HitTestRequest& request, HitTestResult& result,
  666. const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction)
  667. {
  668. return m_lineBoxes.hitTest(this, request, result, locationInContainer, accumulatedOffset, hitTestAction);
  669. }
  670. namespace {
  671. class HitTestCulledInlinesGeneratorContext {
  672. public:
  673. HitTestCulledInlinesGeneratorContext(Region& region, const HitTestLocation& location) : m_intersected(false), m_region(region), m_location(location) { }
  674. void operator()(const FloatRect& rect)
  675. {
  676. m_intersected = m_intersected || m_location.intersects(rect);
  677. m_region.unite(enclosingIntRect(rect));
  678. }
  679. bool intersected() const { return m_intersected; }
  680. private:
  681. bool m_intersected;
  682. Region& m_region;
  683. const HitTestLocation& m_location;
  684. };
  685. } // unnamed namespace
  686. bool RenderInline::hitTestCulledInline(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset)
  687. {
  688. ASSERT(result.isRectBasedTest() && !alwaysCreateLineBoxes());
  689. if (!visibleToHitTesting())
  690. return false;
  691. HitTestLocation tmpLocation(locationInContainer, -toLayoutSize(accumulatedOffset));
  692. Region regionResult;
  693. HitTestCulledInlinesGeneratorContext context(regionResult, tmpLocation);
  694. generateCulledLineBoxRects(context, this);
  695. if (context.intersected()) {
  696. updateHitTestResult(result, tmpLocation.point());
  697. // We can not use addNodeToRectBasedTestResult to determine if we fully enclose the hit-test area
  698. // because it can only handle rectangular targets.
  699. result.addNodeToRectBasedTestResult(node(), request, locationInContainer);
  700. return regionResult.contains(tmpLocation.boundingBox());
  701. }
  702. return false;
  703. }
  704. VisiblePosition RenderInline::positionForPoint(const LayoutPoint& point)
  705. {
  706. // FIXME: Does not deal with relative or sticky positioned inlines (should it?)
  707. RenderBlock* cb = containingBlock();
  708. if (firstLineBox()) {
  709. // This inline actually has a line box. We must have clicked in the border/padding of one of these boxes. We
  710. // should try to find a result by asking our containing block.
  711. return cb->positionForPoint(point);
  712. }
  713. // Translate the coords from the pre-anonymous block to the post-anonymous block.
  714. LayoutPoint parentBlockPoint = cb->location() + point;
  715. RenderBoxModelObject* c = continuation();
  716. while (c) {
  717. RenderBox* contBlock = c->isInline() ? c->containingBlock() : toRenderBlock(c);
  718. if (c->isInline() || c->firstChild())
  719. return c->positionForPoint(parentBlockPoint - contBlock->locationOffset());
  720. c = toRenderBlock(c)->inlineElementContinuation();
  721. }
  722. return RenderBoxModelObject::positionForPoint(point);
  723. }
  724. namespace {
  725. class LinesBoundingBoxGeneratorContext {
  726. public:
  727. LinesBoundingBoxGeneratorContext(FloatRect& rect) : m_rect(rect) { }
  728. void operator()(const FloatRect& rect)
  729. {
  730. m_rect.uniteIfNonZero(rect);
  731. }
  732. private:
  733. FloatRect& m_rect;
  734. };
  735. } // unnamed namespace
  736. IntRect RenderInline::linesBoundingBox() const
  737. {
  738. if (!alwaysCreateLineBoxes()) {
  739. ASSERT(!firstLineBox());
  740. FloatRect floatResult;
  741. LinesBoundingBoxGeneratorContext context(floatResult);
  742. generateCulledLineBoxRects(context, this);
  743. return enclosingIntRect(floatResult);
  744. }
  745. IntRect result;
  746. // See <rdar://problem/5289721>, for an unknown reason the linked list here is sometimes inconsistent, first is non-zero and last is zero. We have been
  747. // unable to reproduce this at all (and consequently unable to figure ot why this is happening). The assert will hopefully catch the problem in debug
  748. // builds and help us someday figure out why. We also put in a redundant check of lastLineBox() to avoid the crash for now.
  749. ASSERT(!firstLineBox() == !lastLineBox()); // Either both are null or both exist.
  750. if (firstLineBox() && lastLineBox()) {
  751. // Return the width of the minimal left side and the maximal right side.
  752. float logicalLeftSide = 0;
  753. float logicalRightSide = 0;
  754. for (InlineFlowBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) {
  755. if (curr == firstLineBox() || curr->logicalLeft() < logicalLeftSide)
  756. logicalLeftSide = curr->logicalLeft();
  757. if (curr == firstLineBox() || curr->logicalRight() > logicalRightSide)
  758. logicalRightSide = curr->logicalRight();
  759. }
  760. bool isHorizontal = style()->isHorizontalWritingMode();
  761. float x = isHorizontal ? logicalLeftSide : firstLineBox()->x();
  762. float y = isHorizontal ? firstLineBox()->y() : logicalLeftSide;
  763. float width = isHorizontal ? logicalRightSide - logicalLeftSide : lastLineBox()->logicalBottom() - x;
  764. float height = isHorizontal ? lastLineBox()->logicalBottom() - y : logicalRightSide - logicalLeftSide;
  765. result = enclosingIntRect(FloatRect(x, y, width, height));
  766. }
  767. return result;
  768. }
  769. InlineBox* RenderInline::culledInlineFirstLineBox() const
  770. {
  771. for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
  772. if (curr->isFloatingOrOutOfFlowPositioned())
  773. continue;
  774. // We want to get the margin box in the inline direction, and then use our font ascent/descent in the block
  775. // direction (aligned to the root box's baseline).
  776. if (curr->isBox())
  777. return toRenderBox(curr)->inlineBoxWrapper();
  778. if (curr->isRenderInline()) {
  779. RenderInline* currInline = toRenderInline(curr);
  780. InlineBox* result = currInline->firstLineBoxIncludingCulling();
  781. if (result)
  782. return result;
  783. } else if (curr->isText()) {
  784. RenderText* currText = toRenderText(curr);
  785. if (currText->firstTextBox())
  786. return currText->firstTextBox();
  787. }
  788. }
  789. return 0;
  790. }
  791. InlineBox* RenderInline::culledInlineLastLineBox() const
  792. {
  793. for (RenderObject* curr = lastChild(); curr; curr = curr->previousSibling()) {
  794. if (curr->isFloatingOrOutOfFlowPositioned())
  795. continue;
  796. // We want to get the margin box in the inline direction, and then use our font ascent/descent in the block
  797. // direction (aligned to the root box's baseline).
  798. if (curr->isBox())
  799. return toRenderBox(curr)->inlineBoxWrapper();
  800. if (curr->isRenderInline()) {
  801. RenderInline* currInline = toRenderInline(curr);
  802. InlineBox* result = currInline->lastLineBoxIncludingCulling();
  803. if (result)
  804. return result;
  805. } else if (curr->isText()) {
  806. RenderText* currText = toRenderText(curr);
  807. if (currText->lastTextBox())
  808. return currText->lastTextBox();
  809. }
  810. }
  811. return 0;
  812. }
  813. LayoutRect RenderInline::culledInlineVisualOverflowBoundingBox() const
  814. {
  815. FloatRect floatResult;
  816. LinesBoundingBoxGeneratorContext context(floatResult);
  817. generateCulledLineBoxRects(context, this);
  818. LayoutRect result(enclosingLayoutRect(floatResult));
  819. bool isHorizontal = style()->isHorizontalWritingMode();
  820. for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
  821. if (curr->isFloatingOrOutOfFlowPositioned())
  822. continue;
  823. // For overflow we just have to propagate by hand and recompute it all.
  824. if (curr->isBox()) {
  825. RenderBox* currBox = toRenderBox(curr);
  826. if (!currBox->hasSelfPaintingLayer() && currBox->inlineBoxWrapper()) {
  827. LayoutRect logicalRect = currBox->logicalVisualOverflowRectForPropagation(style());
  828. if (isHorizontal) {
  829. logicalRect.moveBy(currBox->location());
  830. result.uniteIfNonZero(logicalRect);
  831. } else {
  832. logicalRect.moveBy(currBox->location());
  833. result.uniteIfNonZero(logicalRect.transposedRect());
  834. }
  835. }
  836. } else if (curr->isRenderInline()) {
  837. // If the child doesn't need line boxes either, then we can recur.
  838. RenderInline* currInline = toRenderInline(curr);
  839. if (!currInline->alwaysCreateLineBoxes())
  840. result.uniteIfNonZero(currInline->culledInlineVisualOverflowBoundingBox());
  841. else if (!currInline->hasSelfPaintingLayer())
  842. result.uniteIfNonZero(currInline->linesVisualOverflowBoundingBox());
  843. } else if (curr->isText()) {
  844. // FIXME; Overflow from text boxes is lost. We will need to cache this information in
  845. // InlineTextBoxes.
  846. RenderText* currText = toRenderText(curr);
  847. result.uniteIfNonZero(currText->linesVisualOverflowBoundingBox());
  848. }
  849. }
  850. return result;
  851. }
  852. LayoutRect RenderInline::linesVisualOverflowBoundingBox() const
  853. {
  854. if (!alwaysCreateLineBoxes())
  855. return culledInlineVisualOverflowBoundingBox();
  856. if (!firstLineBox() || !lastLineBox())
  857. return LayoutRect();
  858. // Return the width of the minimal left side and the maximal right side.
  859. LayoutUnit logicalLeftSide = LayoutUnit::max();
  860. LayoutUnit logicalRightSide = LayoutUnit::min();
  861. for (InlineFlowBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) {
  862. logicalLeftSide = min(logicalLeftSide, curr->logicalLeftVisualOverflow());
  863. logicalRightSide = max(logicalRightSide, curr->logicalRightVisualOverflow());
  864. }
  865. RootInlineBox* firstRootBox = firstLineBox()->root();
  866. RootInlineBox* lastRootBox = lastLineBox()->root();
  867. LayoutUnit logicalTop = firstLineBox()->logicalTopVisualOverflow(firstRootBox->lineTop());
  868. LayoutUnit logicalWidth = logicalRightSide - logicalLeftSide;
  869. LayoutUnit logicalHeight = lastLineBox()->logicalBottomVisualOverflow(lastRootBox->lineBottom()) - logicalTop;
  870. LayoutRect rect(logicalLeftSide, logicalTop, logicalWidth, logicalHeight);
  871. if (!style()->isHorizontalWritingMode())
  872. rect = rect.transposedRect();
  873. return rect;
  874. }
  875. LayoutRect RenderInline::clippedOverflowRectForRepaint(const RenderLayerModelObject* repaintContainer) const
  876. {
  877. // Only run-ins are allowed in here during layout.
  878. ASSERT(!view() || !view()->layoutStateEnabled() || isRunIn());
  879. if (!firstLineBoxIncludingCulling() && !continuation())
  880. return LayoutRect();
  881. LayoutRect repaintRect(linesVisualOverflowBoundingBox());
  882. bool hitRepaintContainer = false;
  883. // We need to add in the in-flow position offsets of any inlines (including us) up to our
  884. // containing block.
  885. RenderBlock* cb = containingBlock();
  886. for (const RenderObject* inlineFlow = this; inlineFlow && inlineFlow->isRenderInline() && inlineFlow != cb;
  887. inlineFlow = inlineFlow->parent()) {
  888. if (inlineFlow == repaintContainer) {
  889. hitRepaintContainer = true;
  890. break;
  891. }
  892. if (inlineFlow->style()->hasInFlowPosition() && inlineFlow->hasLayer())
  893. repaintRect.move(toRenderInline(inlineFlow)->layer()->paintOffset());
  894. }
  895. LayoutUnit outlineSize = style()->outlineSize();
  896. repaintRect.inflate(outlineSize);
  897. if (hitRepaintContainer || !cb)
  898. return repaintRect;
  899. if (cb->hasColumns())
  900. cb->adjustRectForColumns(repaintRect);
  901. if (cb->hasOverflowClip())
  902. cb->applyCachedClipAndScrollOffsetForRepaint(repaintRect);
  903. cb->computeRectForRepaint(repaintContainer, repaintRect);
  904. if (outlineSize) {
  905. for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
  906. if (!curr->isText())
  907. repaintRect.unite(curr->rectWithOutlineForRepaint(repaintContainer, outlineSize));
  908. }
  909. if (continuation() && !continuation()->isInline() && continuation()->parent())
  910. repaintRect.unite(continuation()->rectWithOutlineForRepaint(repaintContainer, outlineSize));
  911. }
  912. return repaintRect;
  913. }
  914. LayoutRect RenderInline::rectWithOutlineForRepaint(const RenderLayerModelObject* repaintContainer, LayoutUnit outlineWidth) const
  915. {
  916. LayoutRect r(RenderBoxModelObject::rectWithOutlineForRepaint(repaintContainer, outlineWidth));
  917. for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
  918. if (!curr->isText())
  919. r.unite(curr->rectWithOutlineForRepaint(repaintContainer, outlineWidth));
  920. }
  921. return r;
  922. }
  923. void RenderInline::computeRectForRepaint(const RenderLayerModelObject* repaintContainer, LayoutRect& rect, bool fixed) const
  924. {
  925. if (RenderView* v = view()) {
  926. // LayoutState is only valid for root-relative repainting
  927. if (v->layoutStateEnabled() && !repaintContainer) {
  928. LayoutState* layoutState = v->layoutState();
  929. if (style()->hasInFlowPosition() && layer())
  930. rect.move(layer()->paintOffset());
  931. rect.move(layoutState->m_paintOffset);
  932. if (layoutState->m_clipped)
  933. rect.intersect(layoutState->m_clipRect);
  934. return;
  935. }
  936. }
  937. if (repaintContainer == this)
  938. return;
  939. bool containerSkipped;
  940. RenderObject* o = container(repaintContainer, &containerSkipped);
  941. if (!o)
  942. return;
  943. LayoutPoint topLeft = rect.location();
  944. if (o->isBlockFlow() && !style()->hasOutOfFlowPosition()) {
  945. RenderBlock* cb = toRenderBlock(o);
  946. if (cb->hasColumns()) {
  947. LayoutRect repaintRect(topLeft, rect.size());
  948. cb->adjustRectForColumns(repaintRect);
  949. topLeft = repaintRect.location();
  950. rect = repaintRect;
  951. }
  952. }
  953. if (style()->hasInFlowPosition() && layer()) {
  954. // Apply the in-flow position offset when invalidating a rectangle. The layer
  955. // is translated, but the render box isn't, so we need to do this to get the
  956. // right dirty rect. Since this is called from RenderObject::setStyle, the relative or sticky position
  957. // flag on the RenderObject has been cleared, so use the one on the style().
  958. topLeft += layer()->paintOffset();
  959. }
  960. // FIXME: We ignore the lightweight clipping rect that controls use, since if |o| is in mid-layout,
  961. // its controlClipRect will be wrong. For overflow clip we use the values cached by the layer.
  962. rect.setLocation(topLeft);
  963. if (o->hasOverflowClip()) {
  964. RenderBox* containerBox = toRenderBox(o);
  965. containerBox->applyCachedClipAndScrollOffsetForRepaint(rect);
  966. if (rect.isEmpty())
  967. return;
  968. }
  969. if (containerSkipped) {
  970. // If the repaintContainer is below o, then we need to map the rect into repaintContainer's coordinates.
  971. LayoutSize containerOffset = repaintContainer->offsetFromAncestorContainer(o);
  972. rect.move(-containerOffset);
  973. return;
  974. }
  975. o->computeRectForRepaint(repaintContainer, rect, fixed);
  976. }
  977. LayoutSize RenderInline::offsetFromContainer(RenderObject* container, const LayoutPoint& point, bool* offsetDependsOnPoint) const
  978. {
  979. ASSERT(container == this->container());
  980. LayoutSize offset;
  981. if (isInFlowPositioned())
  982. offset += offsetForInFlowPosition();
  983. container->adjustForColumns(offset, point);
  984. if (container->hasOverflowClip())
  985. offset -= toRenderBox(container)->scrolledContentOffset();
  986. if (offsetDependsOnPoint)
  987. *offsetDependsOnPoint = container->hasColumns()
  988. || (container->isBox() && container->style()->isFlippedBlocksWritingMode())
  989. || container->isRenderFlowThread();
  990. return offset;
  991. }
  992. void RenderInline::mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState& transformState, MapCoordinatesFlags mode, bool* wasFixed) const
  993. {
  994. if (repaintContainer == this)
  995. return;
  996. if (RenderView *v = view()) {
  997. if (v->layoutStateEnabled() && !repaintContainer) {
  998. LayoutState* layoutState = v->layoutState();
  999. LayoutSize offset = layoutState->m_paintOffset;
  1000. if (style()->hasInFlowPosition() && layer())
  1001. offset += layer()->paintOffset();
  1002. transformState.move(offset);
  1003. return;
  1004. }
  1005. }
  1006. bool containerSkipped;
  1007. RenderObject* o = container(repaintContainer, &containerSkipped);
  1008. if (!o)
  1009. return;
  1010. if (mode & ApplyContainerFlip && o->isBox()) {
  1011. if (o->style()->isFlippedBlocksWritingMode()) {
  1012. IntPoint centerPoint = roundedIntPoint(transformState.mappedPoint());
  1013. transformState.move(toRenderBox(o)->flipForWritingModeIncludingColumns(centerPoint) - centerPoint);
  1014. }
  1015. mode &= ~ApplyContainerFlip;
  1016. }
  1017. LayoutSize containerOffset = offsetFromContainer(o, roundedLayoutPoint(transformState.mappedPoint()));
  1018. bool preserve3D = mode & UseTransforms && (o->style()->preserves3D() || style()->preserves3D());
  1019. if (mode & UseTransforms && shouldUseTransformFromContainer(o)) {
  1020. TransformationMatrix t;
  1021. getTransformFromContainer(o, containerOffset, t);
  1022. transformState.applyTransform(t, preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
  1023. } else
  1024. transformState.move(containerOffset.width(), containerOffset.height(), preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
  1025. if (containerSkipped) {
  1026. // There can't be a transform between repaintContainer and o, because transforms create containers, so it should be safe
  1027. // to just subtract the delta between the repaintContainer and o.
  1028. LayoutSize containerOffset = repaintContainer->offsetFromAncestorContainer(o);
  1029. transformState.move(-containerOffset.width(), -containerOffset.height(), preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
  1030. return;
  1031. }
  1032. o->mapLocalToContainer(repaintContainer, transformState, mode, wasFixed);
  1033. }
  1034. const RenderObject* RenderInline::pushMappingToContainer(const RenderLayerModelObject* ancestorToStopAt, RenderGeometryMap& geometryMap) const
  1035. {
  1036. ASSERT(ancestorToStopAt != this);
  1037. bool ancestorSkipped;
  1038. RenderObject* container = this->container(ancestorToStopAt, &ancestorSkipped);
  1039. if (!container)
  1040. return 0;
  1041. LayoutSize adjustmentForSkippedAncestor;
  1042. if (ancestorSkipped) {
  1043. // There can't be a transform between repaintContainer and o, because transforms create containers, so it should be safe
  1044. // to just subtract the delta between the ancestor and o.
  1045. adjustmentForSkippedAncestor = -ancestorToStopAt->offsetFromAncestorContainer(container);
  1046. }
  1047. bool offsetDependsOnPoint = false;
  1048. LayoutSize containerOffset = offsetFromContainer(container, LayoutPoint(), &offsetDependsOnPoint);
  1049. bool preserve3D = container->style()->preserves3D() || style()->preserves3D();
  1050. if (shouldUseTransformFromContainer(container)) {
  1051. TransformationMatrix t;
  1052. getTransformFromContainer(container, containerOffset, t);
  1053. t.translateRight(adjustmentForSkippedAncestor.width(), adjustmentForSkippedAncestor.height()); // FIXME: right?
  1054. geometryMap.push(this, t, preserve3D, offsetDependsOnPoint);
  1055. } else {
  1056. containerOffset += adjustmentForSkippedAncestor;
  1057. geometryMap.push(this, containerOffset, preserve3D, offsetDependsOnPoint);
  1058. }
  1059. return ancestorSkipped ? ancestorToStopAt : container;
  1060. }
  1061. void RenderInline::updateDragState(bool dragOn)
  1062. {
  1063. RenderBoxModelObject::updateDragState(dragOn);
  1064. if (continuation())
  1065. continuation()->updateDragState(dragOn);
  1066. }
  1067. void RenderInline::childBecameNonInline(RenderObject* child)
  1068. {
  1069. // We have to split the parent flow.
  1070. RenderBlock* newBox = containingBlock()->createAnonymousBlock();
  1071. RenderBoxModelObject* oldContinuation = continuation();
  1072. setContinuation(newBox);
  1073. RenderObject* beforeChild = child->nextSibling();
  1074. children()->removeChildNode(this, child);
  1075. splitFlow(beforeChild, newBox, child, oldContinuation);
  1076. }
  1077. void RenderInline::updateHitTestResult(HitTestResult& result, const LayoutPoint& point)
  1078. {
  1079. if (result.innerNode())
  1080. return;
  1081. Node* n = node();
  1082. LayoutPoint localPoint(point);
  1083. if (n) {
  1084. if (isInlineElementContinuation()) {
  1085. // We're in the continuation of a split inline. Adjust our local point to be in the coordinate space
  1086. // of the principal renderer's containing block. This will end up being the innerNonSharedNode.
  1087. RenderBlock* firstBlock = n->renderer()->containingBlock();
  1088. // Get our containing block.
  1089. RenderBox* block = containingBlock();
  1090. localPoint.moveBy(block->location() - firstBlock->locationOffset());
  1091. }
  1092. result.setInnerNode(n);
  1093. if (!result.innerNonSharedNode())
  1094. result.setInnerNonSharedNode(n);
  1095. result.setLocalPoint(localPoint);
  1096. }
  1097. }
  1098. void RenderInline::dirtyLineBoxes(bool fullLayout)
  1099. {
  1100. if (fullLayout) {
  1101. m_lineBoxes.deleteLineBoxes(renderArena());
  1102. return;
  1103. }
  1104. if (!alwaysCreateLineBoxes()) {
  1105. // We have to grovel into our children in order to dirty the appropriate lines.
  1106. for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
  1107. if (curr->isFloatingOrOutOfFlowPositioned())
  1108. continue;
  1109. if (curr->isBox() && !curr->needsLayout()) {
  1110. RenderBox* currBox = toRenderBox(curr);
  1111. if (currBox->inlineBoxWrapper())
  1112. currBox->inlineBoxWrapper()->root()->markDirty();
  1113. } else if (!curr->selfNeedsLayout()) {
  1114. if (curr->isRenderInline()) {
  1115. RenderInline* currInline = toRenderInline(curr);
  1116. for (InlineFlowBox* childLine = currInline->firstLineBox(); childLine; childLine = childLine->nextLineBox())
  1117. childLine->root()->markDirty();
  1118. } else if (curr->isText()) {
  1119. RenderText* currText = toRenderText(curr);
  1120. for (InlineTextBox* childText = currText->firstTextBox(); childText; childText = childText->nextTextBox())
  1121. childText->root()->markDirty();
  1122. }
  1123. }
  1124. }
  1125. } else
  1126. m_lineBoxes.dirtyLineBoxes();
  1127. }
  1128. void RenderInline::deleteLineBoxTree()
  1129. {
  1130. m_lineBoxes.deleteLineBoxTree(renderArena());
  1131. }
  1132. InlineFlowBox* RenderInline::createInlineFlowBox()
  1133. {
  1134. return new (renderArena()) InlineFlowBox(this);
  1135. }
  1136. InlineFlowBox* RenderInline::createAndAppendInlineFlowBox()
  1137. {
  1138. setAlwaysCreateLineBoxes();
  1139. InlineFlowBox* flowBox = createInlineFlowBox();
  1140. m_lineBoxes.appendLineBox(flowBox);
  1141. return flowBox;
  1142. }
  1143. LayoutUnit RenderInline::lineHeight(bool firstLine, LineDirectionMode /*direction*/, LinePositionMode /*linePositionMode*/) const
  1144. {
  1145. if (firstLine && document()->styleSheetCollection()->usesFirstLineRules()) {
  1146. RenderStyle* s = style(firstLine);
  1147. if (s != style())
  1148. return s->computedLineHeight(view());
  1149. }
  1150. return style()->computedLineHeight(view());
  1151. }
  1152. int RenderInline::baselinePosition(FontBaseline baselineType, bool firstLine, LineDirectionMode direction, LinePositionMode linePositionMode) const
  1153. {
  1154. const FontMetrics& fontMetrics = style(firstLine)->fontMetrics();
  1155. return fontMetrics.ascent(baselineType) + (lineHeight(firstLine, direction, linePositionMode) - fontMetrics.height()) / 2;
  1156. }
  1157. LayoutSize RenderInline::offsetForInFlowPositionedInline(const RenderBox* child) const
  1158. {
  1159. // FIXME: This function isn't right with mixed writing modes.
  1160. ASSERT(isInFlowPositioned());
  1161. if (!isInFlowPositioned())
  1162. return LayoutSize();
  1163. // When we have an enclosing relpositioned inline, we need to add in the offset of the first line
  1164. // box from the rest of the content, but only in the cases where we know we're positioned
  1165. // relative to the inline itself.
  1166. LayoutSize logicalOffset;
  1167. LayoutUnit inlinePosition;
  1168. LayoutUnit blockPosition;
  1169. if (firstLineBox()) {
  1170. inlinePosition = roundedLayoutUnit(firstLineBox()->logicalLeft());
  1171. blockPosition = firstLineBox()->logicalTop();
  1172. } else {
  1173. inlinePosition = layer()->staticInlinePosition();
  1174. blockPosition = layer()->staticBlockPosition();
  1175. }
  1176. if (!child->style()->hasStaticInlinePosition(style()->isHorizontalWritingMode()))
  1177. logicalOffset.setWidth(inlinePosition);
  1178. // This is not terribly intuitive, but we have to match other browsers. Despite being a block display type inside
  1179. // an inline, we still keep our x locked to the left of the relative positioned inline. Arguably the correct
  1180. // behavior would be to go flush left to the block that contains the inline, but that isn't what other browsers
  1181. // do.
  1182. else if (!child->style()->isOriginalDisplayInlineType())
  1183. // Avoid adding in the left border/padding of the containing block twice. Subtract it out.
  1184. logicalOffset.setWidth(inlinePosition - child->containingBlock()->borderAndPaddingLogicalLeft());
  1185. if (!child->style()->hasStaticBlockPosition(style()->isHorizontalWritingMode()))
  1186. logicalOffset.setHeight(blockPosition);
  1187. return style()->isHorizontalWritingMode() ? logicalOffset : logicalOffset.transposedSize();
  1188. }
  1189. void RenderInline::imageChanged(WrappedImagePtr, const IntRect*)
  1190. {
  1191. if (!parent())
  1192. return;
  1193. // FIXME: We can do better.
  1194. repaint();
  1195. }
  1196. void RenderInline::addFocusRingRects(Vector<IntRect>& rects, const LayoutPoint& additionalOffset)
  1197. {
  1198. AbsoluteRectsGeneratorContext context(rects, additionalOffset);
  1199. generateLineBoxRects(context);
  1200. for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
  1201. if (!curr->isText() && !curr->isListMarker()) {
  1202. FloatPoint pos(additionalOffset);
  1203. // FIXME: This doesn't work correctly with transforms.
  1204. if (curr->hasLayer())
  1205. pos = curr->localToAbsolute();
  1206. else if (curr->isBox())
  1207. pos.move(toRenderBox(curr)->locationOffset());
  1208. curr->addFocusRingRects(rects, flooredIntPoint(pos));
  1209. }
  1210. }
  1211. if (continuation()) {
  1212. if (continuation()->isInline())
  1213. continuation()->addFocusRingRects(rects, flooredLayoutPoint(additionalOffset + continuation()->containingBlock()->location() - containingBlock()->location()));
  1214. else
  1215. continuation()->addFocusRingRects(rects, flooredLayoutPoint(additionalOffset + toRenderBox(continuation())->location() - containingBlock()->location()));
  1216. }
  1217. }
  1218. void RenderInline::paintOutline(GraphicsContext* graphicsContext, const LayoutPoint& paintOffset)
  1219. {
  1220. if (!hasOutline())
  1221. return;
  1222. RenderStyle* styleToUse = style();
  1223. if (styleToUse->outlineStyleIsAuto() || hasOutlineAnnotation()) {
  1224. if (!theme()->supportsFocusRing(styleToUse)) {
  1225. // Only paint the focus ring by hand if the theme isn't able to draw the focus ring.
  1226. paintFocusRing(graphicsContext, paintOffset, styleToUse);
  1227. }
  1228. }
  1229. if (graphicsContext->paintingDisabled())
  1230. return;
  1231. if (styleToUse->outlineStyleIsAuto() || styleToUse->outlineStyle() == BNONE)
  1232. return;
  1233. Vector<LayoutRect> rects;
  1234. rects.append(LayoutRect());
  1235. for (InlineFlowBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) {
  1236. RootInlineBox* root = curr->root();
  1237. LayoutUnit top = max<LayoutUnit>(root->lineTop(), curr->logicalTop());
  1238. LayoutUnit bottom = min<LayoutUnit>(root->lineBottom(), curr->logicalBottom());
  1239. rects.append(LayoutRect(curr->x(), top, curr->logicalWidth(), bottom - top));
  1240. }
  1241. rects.append(LayoutRect());
  1242. Color outlineColor = styleToUse->visitedDependentColor(CSSPropertyOutlineColor);
  1243. bool useTransparencyLayer = outlineColor.hasAlpha();
  1244. if (useTransparencyLayer) {
  1245. graphicsContext->beginTransparencyLayer(static_cast<float>(outlineColor.alpha()) / 255);
  1246. outlineColor = Color(outlineColor.red(), outlineColor.green(), outlineColor.blue());
  1247. }
  1248. for (unsigned i = 1; i < rects.size() - 1; i++)
  1249. paintOutlineForLine(graphicsContext, paintOffset, rects.at(i - 1), rects.at(i), rects.at(i + 1), outlineColor);
  1250. if (useTransparencyLayer)
  1251. graphicsContext->endTransparencyLayer();
  1252. }
  1253. void RenderInline::paintOutlineForLine(GraphicsContext* graphicsContext, const LayoutPoint& paintOffset,
  1254. const LayoutRect& lastline, const LayoutRect& thisline, const LayoutRect& nextline,
  1255. const Color outlineColor)
  1256. {
  1257. RenderStyle* styleToUse = style();
  1258. int outlineWidth = styleToUse->outlineWidth();
  1259. EBorderStyle outlineStyle = styleToUse->outlineStyle();
  1260. bool antialias = shouldAntialiasLines(graphicsContext);
  1261. int offset = style()->outlineOffset();
  1262. LayoutRect box(LayoutPoint(paintOffset.x() + thisline.x() - offset, paintOffset.y() + thisline.y() - offset),
  1263. LayoutSize(thisline.width() + offset, thisline.height() + offset));
  1264. IntRect pixelSnappedBox = pixelSnappedIntRect(box);
  1265. IntRect pixelSnappedLastLine = pixelSnappedIntRect(paintOffset.x() + lastline.x(), 0, lastline.width(), 0);
  1266. IntRect pixelSnappedNextLine = pixelSnappedIntRect(paintOffset.x() + nextline.x(), 0, nextline.width(), 0);
  1267. // left edge
  1268. drawLineForBoxSide(graphicsContext,
  1269. pixelSnappedBox.x() - outlineWidth,
  1270. pixelSnappedBox.y() - (lastline.isEmpty() || thisline.x() < lastline.x() || (lastline.maxX() - 1) <= thisline.x() ? outlineWidth : 0),
  1271. pixelSnappedBox.x(),
  1272. pixelSnappedBox.maxY() + (nextline.isEmpty() || thisline.x() <= nextline.x() || (nextline.maxX() - 1) <= thisline.x() ? outlineWidth : 0),
  1273. BSLeft,
  1274. outlineColor, outlineStyle,
  1275. (lastline.isEmpty() || thisline.x() < lastline.x() || (lastline.maxX() - 1) <= thisline.x() ? outlineWidth : -outlineWidth),
  1276. (nextline.isEmpty() || thisline.x() <= nextline.x() || (nextline.maxX() - 1) <= thisline.x() ? outlineWidth : -outlineWidth),
  1277. antialias);
  1278. // right edge
  1279. drawLineForBoxSide(graphicsContext,
  1280. pixelSnappedBox.maxX(),
  1281. pixelSnappedBox.y() - (lastline.isEmpty() || lastline.maxX() < thisline.maxX() || (thisline.maxX() - 1) <= lastline.x() ? outlineWidth : 0),
  1282. pixelSnappedBox.maxX() + outlineWidth,
  1283. pixelSnappedBox.maxY() + (nextline.isEmpty() || nextline.maxX() <= thisline.maxX() || (thisline.maxX() - 1) <= nextline.x() ? outlineWidth : 0),
  1284. BSRight,
  1285. outlineColor, outlineStyle,
  1286. (lastline.isEmpty() || lastline.maxX() < thisline.maxX() || (thisline.maxX() - 1) <= lastline.x() ? outlineWidth : -outlineWidth),
  1287. (nextline.isEmpty() || nextline.maxX() <= thisline.maxX() || (thisline.maxX() - 1) <= nextline.x() ? outlineWidth : -outlineWidth),
  1288. antialias);
  1289. // upper edge
  1290. if (thisline.x() < lastline.x())
  1291. drawLineForBoxSide(graphicsContext,
  1292. pixelSnappedBox.x() - outlineWidth,
  1293. pixelSnappedBox.y() - outlineWidth,
  1294. min(pixelSnappedBox.maxX() + outlineWidth, (lastline.isEmpty() ? 1000000 : pixelSnappedLastLine.x())),
  1295. pixelSnappedBox.y(),
  1296. BSTop, outlineColor, outlineStyle,
  1297. outlineWidth,
  1298. (!lastline.isEmpty() && paintOffset.x() + lastline.x() + 1 < pixelSnappedBox.maxX() + outlineWidth) ? -outlineWidth : outlineWidth,
  1299. antialias);
  1300. if (lastline.maxX() < thisline.maxX())
  1301. drawLineForBoxSide(graphicsContext,
  1302. max(lastline.isEmpty() ? -1000000 : pixelSnappedLastLine.maxX(), pixelSnappedBox.x() - outlineWidth),
  1303. pixelSnappedBox.y() - outlineWidth,
  1304. pixelSnappedBox.maxX() + outlineWidth,
  1305. pixelSnappedBox.y(),
  1306. BSTop, outlineColor, outlineStyle,
  1307. (!lastline.isEmpty() && pixelSnappedBox.x() - outlineWidth < paintOffset.x() + lastline.maxX()) ? -outlineWidth : outlineWidth,
  1308. outlineWidth, antialias);
  1309. if (thisline.x() == thisline.maxX())
  1310. drawLineForBoxSide(graphicsContext,
  1311. pixelSnappedBox.x() - outlineWidth,
  1312. pixelSnappedBox.y() - outlineWidth,
  1313. pixelSnappedBox.maxX() + outlineWidth,
  1314. pixelSnappedBox.y(),
  1315. BSTop, outlineColor, outlineStyle,
  1316. outlineWidth,
  1317. outlineWidth,
  1318. antialias);
  1319. // lower edge
  1320. if (thisline.x() < nextline.x())
  1321. drawLineForBoxSide(graphicsContext,
  1322. pixelSnappedBox.x() - outlineWidth,
  1323. pixelSnappedBox.maxY(),
  1324. min(pixelSnappedBox.maxX() + outlineWidth, !nextline.isEmpty() ? pixelSnappedNextLine.x() + 1 : 1000000),
  1325. pixelSnappedBox.maxY() + outlineWidth,
  1326. BSBottom, outlineColor, outlineStyle,
  1327. outlineWidth,
  1328. (!nextline.isEmpty() && paintOffset.x() + nextline.x() + 1 < pixelSnappedBox.maxX() + outlineWidth) ? -outlineWidth : outlineWidth,
  1329. antialias);
  1330. if (nextline.maxX() < thisline.maxX())
  1331. drawLineForBoxSide(graphicsContext,
  1332. max(!nextline.isEmpty() ? pixelSnappedNextLine.maxX() : -1000000, pixelSnappedBox.x() - outlineWidth),
  1333. pixelSnappedBox.maxY(),
  1334. pixelSnappedBox.maxX() + outlineWidth,
  1335. pixelSnappedBox.maxY() + outlineWidth,
  1336. BSBottom, outlineColor, outlineStyle,
  1337. (!nextline.isEmpty() && pixelSnappedBox.x() - outlineWidth < paintOffset.x() + nextline.maxX()) ? -outlineWidth : outlineWidth,
  1338. outlineWidth, antialias);
  1339. if (thisline.x() == thisline.maxX())
  1340. drawLineForBoxSide(graphicsContext,
  1341. pixelSnappedBox.x() - outlineWidth,
  1342. pixelSnappedBox.maxY(),
  1343. pixelSnappedBox.maxX() + outlineWidth,
  1344. pixelSnappedBox.maxY() + outlineWidth,
  1345. BSBottom, outlineColor, outlineStyle,
  1346. outlineWidth,
  1347. outlineWidth,
  1348. antialias);
  1349. }
  1350. #if ENABLE(DASHBOARD_SUPPORT) || ENABLE(DRAGGABLE_REGION)
  1351. void RenderInline::addAnnotatedRegions(Vector<AnnotatedRegionValue>& regions)
  1352. {
  1353. // Convert the style regions to absolute coordinates.
  1354. if (style()->visibility() != VISIBLE)
  1355. return;
  1356. #if ENABLE(DASHBOARD_SUPPORT)
  1357. const Vector<StyleDashboardRegion>& styleRegions = style()->dashboardRegions();
  1358. unsigned i, count = styleRegions.size();
  1359. for (i = 0; i < count; i++) {
  1360. StyleDashboardRegion styleRegion = styleRegions[i];
  1361. LayoutRect linesBoundingBox = this->linesBoundingBox();
  1362. LayoutUnit w = linesBoundingBox.width();
  1363. LayoutUnit h = linesBoundingBox.height();
  1364. AnnotatedRegionValue region;
  1365. region.label = styleRegion.label;
  1366. region.bounds = LayoutRect(linesBoundingBox.x() + styleRegion.offset.left().value(),
  1367. linesBoundingBox.y() + styleRegion.offset.top().value(),
  1368. w - styleRegion.offset.left().value() - styleRegion.offset.right().value(),
  1369. h - styleRegion.offset.top().value() - styleRegion.offset.bottom().value());
  1370. region.type = styleRegion.type;
  1371. RenderObject* container = containingBlock();
  1372. if (!container)
  1373. container = this;
  1374. region.clip = region.bounds;
  1375. container->computeAbsoluteRepaintRect(region.clip);
  1376. if (region.clip.height() < 0) {
  1377. region.clip.setHeight(0);
  1378. region.clip.setWidth(0);
  1379. }
  1380. FloatPoint absPos = container->localToAbsolute();
  1381. region.bounds.setX(absPos.x() + region.bounds.x());
  1382. region.bounds.setY(absPos.y() + region.bounds.y());
  1383. regions.append(region);
  1384. }
  1385. #else // ENABLE(DRAGGABLE_REGION)
  1386. if (style()->getDraggableRegionMode() == DraggableRegionNone)
  1387. return;
  1388. AnnotatedRegionValue region;
  1389. region.draggable = style()->getDraggableRegionMode() == DraggableRegionDrag;
  1390. region.bounds = linesBoundingBox();
  1391. RenderObject* container = containingBlock();
  1392. if (!container)
  1393. container = this;
  1394. FloatPoint absPos = container->localToAbsolute();
  1395. region.bounds.setX(absPos.x() + region.bounds.x());
  1396. region.bounds.setY(absPos.y() + region.bounds.y());
  1397. regions.append(region);
  1398. #endif
  1399. }
  1400. #endif
  1401. } // namespace WebCore