/src/3rdparty/webkit/Source/WebCore/rendering/InlineBox.cpp

https://bitbucket.org/ultra_iter/qt-vtl · C++ · 382 lines · 295 code · 59 blank · 28 comment · 65 complexity · 4bfda5e4f97b947f900e0b6778b0ddbb MD5 · raw file

  1. /*
  2. * Copyright (C) 2003, 2004, 2005, 2006, 2007 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 "InlineBox.h"
  21. #include "HitTestResult.h"
  22. #include "InlineFlowBox.h"
  23. #include "PaintInfo.h"
  24. #include "RenderArena.h"
  25. #include "RenderBlock.h"
  26. #include "RootInlineBox.h"
  27. using namespace std;
  28. namespace WebCore {
  29. #ifndef NDEBUG
  30. static bool inInlineBoxDetach;
  31. #endif
  32. #ifndef NDEBUG
  33. InlineBox::~InlineBox()
  34. {
  35. if (!m_hasBadParent && m_parent)
  36. m_parent->setHasBadChildList();
  37. }
  38. #endif
  39. void InlineBox::remove()
  40. {
  41. if (parent())
  42. parent()->removeChild(this);
  43. }
  44. void InlineBox::destroy(RenderArena* renderArena)
  45. {
  46. #ifndef NDEBUG
  47. inInlineBoxDetach = true;
  48. #endif
  49. delete this;
  50. #ifndef NDEBUG
  51. inInlineBoxDetach = false;
  52. #endif
  53. // Recover the size left there for us by operator delete and free the memory.
  54. renderArena->free(*(size_t *)this, this);
  55. }
  56. void* InlineBox::operator new(size_t sz, RenderArena* renderArena) throw()
  57. {
  58. return renderArena->allocate(sz);
  59. }
  60. void InlineBox::operator delete(void* ptr, size_t sz)
  61. {
  62. ASSERT(inInlineBoxDetach);
  63. // Stash size where destroy can find it.
  64. *(size_t *)ptr = sz;
  65. }
  66. #ifndef NDEBUG
  67. const char* InlineBox::boxName() const
  68. {
  69. return "InlineBox";
  70. }
  71. void InlineBox::showTreeForThis() const
  72. {
  73. if (m_renderer)
  74. m_renderer->showTreeForThis();
  75. }
  76. void InlineBox::showLineTreeForThis() const
  77. {
  78. if (m_renderer)
  79. m_renderer->containingBlock()->showLineTreeAndMark(this, "*");
  80. }
  81. void InlineBox::showLineTreeAndMark(const InlineBox* markedBox1, const char* markedLabel1, const InlineBox* markedBox2, const char* markedLabel2, const RenderObject* obj, int depth) const
  82. {
  83. int printedCharacters = 0;
  84. if (this == markedBox1)
  85. printedCharacters += fprintf(stderr, "%s", markedLabel1);
  86. if (this == markedBox2)
  87. printedCharacters += fprintf(stderr, "%s", markedLabel2);
  88. if (renderer() == obj)
  89. printedCharacters += fprintf(stderr, "*");
  90. for (; printedCharacters < depth * 2; printedCharacters++)
  91. fputc(' ', stderr);
  92. showBox(printedCharacters);
  93. }
  94. void InlineBox::showBox(int printedCharacters) const
  95. {
  96. printedCharacters += fprintf(stderr, "%s\t%p", boxName(), this);
  97. for (; printedCharacters < showTreeCharacterOffset; printedCharacters++)
  98. fputc(' ', stderr);
  99. fprintf(stderr, "\t%s %p\n", renderer() ? renderer()->renderName() : "No Renderer", renderer());
  100. }
  101. #endif
  102. int InlineBox::logicalHeight() const
  103. {
  104. #if ENABLE(SVG)
  105. if (hasVirtualLogicalHeight())
  106. return virtualLogicalHeight();
  107. #endif
  108. if (renderer()->isText())
  109. return m_isText ? renderer()->style(m_firstLine)->fontMetrics().height() : 0;
  110. if (renderer()->isBox() && parent())
  111. return isHorizontal() ? toRenderBox(m_renderer)->height() : toRenderBox(m_renderer)->width();
  112. ASSERT(isInlineFlowBox());
  113. RenderBoxModelObject* flowObject = boxModelObject();
  114. const FontMetrics& fontMetrics = renderer()->style(m_firstLine)->fontMetrics();
  115. int result = fontMetrics.height();
  116. if (parent())
  117. result += flowObject->borderAndPaddingLogicalHeight();
  118. return result;
  119. }
  120. int InlineBox::caretMinOffset() const
  121. {
  122. return m_renderer->caretMinOffset();
  123. }
  124. int InlineBox::caretMaxOffset() const
  125. {
  126. return m_renderer->caretMaxOffset();
  127. }
  128. unsigned InlineBox::caretMaxRenderedOffset() const
  129. {
  130. return 1;
  131. }
  132. void InlineBox::dirtyLineBoxes()
  133. {
  134. markDirty();
  135. for (InlineFlowBox* curr = parent(); curr && !curr->isDirty(); curr = curr->parent())
  136. curr->markDirty();
  137. }
  138. void InlineBox::deleteLine(RenderArena* arena)
  139. {
  140. if (!m_extracted && m_renderer->isBox())
  141. toRenderBox(m_renderer)->setInlineBoxWrapper(0);
  142. destroy(arena);
  143. }
  144. void InlineBox::extractLine()
  145. {
  146. m_extracted = true;
  147. if (m_renderer->isBox())
  148. toRenderBox(m_renderer)->setInlineBoxWrapper(0);
  149. }
  150. void InlineBox::attachLine()
  151. {
  152. m_extracted = false;
  153. if (m_renderer->isBox())
  154. toRenderBox(m_renderer)->setInlineBoxWrapper(this);
  155. }
  156. void InlineBox::adjustPosition(float dx, float dy)
  157. {
  158. m_x += dx;
  159. m_y += dy;
  160. if (m_renderer->isReplaced())
  161. toRenderBox(m_renderer)->move(dx, dy);
  162. }
  163. void InlineBox::paint(PaintInfo& paintInfo, int tx, int ty, int /* lineTop */, int /*lineBottom*/)
  164. {
  165. if (!paintInfo.shouldPaintWithinRoot(renderer()) || (paintInfo.phase != PaintPhaseForeground && paintInfo.phase != PaintPhaseSelection))
  166. return;
  167. IntPoint childPoint = IntPoint(tx, ty);
  168. if (parent()->renderer()->style()->isFlippedBlocksWritingMode()) // Faster than calling containingBlock().
  169. childPoint = renderer()->containingBlock()->flipForWritingMode(toRenderBox(renderer()), childPoint, RenderBox::ParentToChildFlippingAdjustment);
  170. // Paint all phases of replaced elements atomically, as though the replaced element established its
  171. // own stacking context. (See Appendix E.2, section 6.4 on inline block/table elements in the CSS2.1
  172. // specification.)
  173. bool preservePhase = paintInfo.phase == PaintPhaseSelection || paintInfo.phase == PaintPhaseTextClip;
  174. PaintInfo info(paintInfo);
  175. info.phase = preservePhase ? paintInfo.phase : PaintPhaseBlockBackground;
  176. renderer()->paint(info, childPoint.x(), childPoint.y());
  177. if (!preservePhase) {
  178. info.phase = PaintPhaseChildBlockBackgrounds;
  179. renderer()->paint(info, childPoint.x(), childPoint.y());
  180. info.phase = PaintPhaseFloat;
  181. renderer()->paint(info, childPoint.x(), childPoint.y());
  182. info.phase = PaintPhaseForeground;
  183. renderer()->paint(info, childPoint.x(), childPoint.y());
  184. info.phase = PaintPhaseOutline;
  185. renderer()->paint(info, childPoint.x(), childPoint.y());
  186. }
  187. }
  188. bool InlineBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty, int /* lineTop */, int /*lineBottom*/)
  189. {
  190. // Hit test all phases of replaced elements atomically, as though the replaced element established its
  191. // own stacking context. (See Appendix E.2, section 6.4 on inline block/table elements in the CSS2.1
  192. // specification.)
  193. return renderer()->hitTest(request, result, IntPoint(x, y), tx, ty);
  194. }
  195. const RootInlineBox* InlineBox::root() const
  196. {
  197. if (m_parent)
  198. return m_parent->root();
  199. ASSERT(isRootInlineBox());
  200. return static_cast<const RootInlineBox*>(this);
  201. }
  202. RootInlineBox* InlineBox::root()
  203. {
  204. if (m_parent)
  205. return m_parent->root();
  206. ASSERT(isRootInlineBox());
  207. return static_cast<RootInlineBox*>(this);
  208. }
  209. bool InlineBox::nextOnLineExists() const
  210. {
  211. if (!m_determinedIfNextOnLineExists) {
  212. m_determinedIfNextOnLineExists = true;
  213. if (!parent())
  214. m_nextOnLineExists = false;
  215. else if (nextOnLine())
  216. m_nextOnLineExists = true;
  217. else
  218. m_nextOnLineExists = parent()->nextOnLineExists();
  219. }
  220. return m_nextOnLineExists;
  221. }
  222. bool InlineBox::prevOnLineExists() const
  223. {
  224. if (!m_determinedIfPrevOnLineExists) {
  225. m_determinedIfPrevOnLineExists = true;
  226. if (!parent())
  227. m_prevOnLineExists = false;
  228. else if (prevOnLine())
  229. m_prevOnLineExists = true;
  230. else
  231. m_prevOnLineExists = parent()->prevOnLineExists();
  232. }
  233. return m_prevOnLineExists;
  234. }
  235. InlineBox* InlineBox::nextLeafChild() const
  236. {
  237. InlineBox* leaf = 0;
  238. for (InlineBox* box = nextOnLine(); box && !leaf; box = box->nextOnLine())
  239. leaf = box->isLeaf() ? box : static_cast<InlineFlowBox*>(box)->firstLeafChild();
  240. if (!leaf && parent())
  241. leaf = parent()->nextLeafChild();
  242. return leaf;
  243. }
  244. InlineBox* InlineBox::prevLeafChild() const
  245. {
  246. InlineBox* leaf = 0;
  247. for (InlineBox* box = prevOnLine(); box && !leaf; box = box->prevOnLine())
  248. leaf = box->isLeaf() ? box : static_cast<InlineFlowBox*>(box)->lastLeafChild();
  249. if (!leaf && parent())
  250. leaf = parent()->prevLeafChild();
  251. return leaf;
  252. }
  253. RenderObject::SelectionState InlineBox::selectionState()
  254. {
  255. return renderer()->selectionState();
  256. }
  257. bool InlineBox::canAccommodateEllipsis(bool ltr, int blockEdge, int ellipsisWidth)
  258. {
  259. // Non-replaced elements can always accommodate an ellipsis.
  260. if (!m_renderer || !m_renderer->isReplaced())
  261. return true;
  262. IntRect boxRect(m_x, 0, m_logicalWidth, 10);
  263. IntRect ellipsisRect(ltr ? blockEdge - ellipsisWidth : blockEdge, 0, ellipsisWidth, 10);
  264. return !(boxRect.intersects(ellipsisRect));
  265. }
  266. float InlineBox::placeEllipsisBox(bool, float, float, float, bool&)
  267. {
  268. // Use -1 to mean "we didn't set the position."
  269. return -1;
  270. }
  271. void InlineBox::clearKnownToHaveNoOverflow()
  272. {
  273. m_knownToHaveNoOverflow = false;
  274. if (parent() && parent()->knownToHaveNoOverflow())
  275. parent()->clearKnownToHaveNoOverflow();
  276. }
  277. FloatPoint InlineBox::locationIncludingFlipping()
  278. {
  279. if (!renderer()->style()->isFlippedBlocksWritingMode())
  280. return FloatPoint(x(), y());
  281. RenderBlock* block = root()->block();
  282. if (block->style()->isHorizontalWritingMode())
  283. return FloatPoint(x(), block->height() - height() - y());
  284. else
  285. return FloatPoint(block->width() - width() - x(), y());
  286. }
  287. void InlineBox::flipForWritingMode(FloatRect& rect)
  288. {
  289. if (!renderer()->style()->isFlippedBlocksWritingMode())
  290. return;
  291. root()->block()->flipForWritingMode(rect);
  292. }
  293. FloatPoint InlineBox::flipForWritingMode(const FloatPoint& point)
  294. {
  295. if (!renderer()->style()->isFlippedBlocksWritingMode())
  296. return point;
  297. return root()->block()->flipForWritingMode(point);
  298. }
  299. void InlineBox::flipForWritingMode(IntRect& rect)
  300. {
  301. if (!renderer()->style()->isFlippedBlocksWritingMode())
  302. return;
  303. root()->block()->flipForWritingMode(rect);
  304. }
  305. IntPoint InlineBox::flipForWritingMode(const IntPoint& point)
  306. {
  307. if (!renderer()->style()->isFlippedBlocksWritingMode())
  308. return point;
  309. return root()->block()->flipForWritingMode(point);
  310. }
  311. } // namespace WebCore
  312. #ifndef NDEBUG
  313. void showTree(const WebCore::InlineBox* b)
  314. {
  315. if (b)
  316. b->showTreeForThis();
  317. }
  318. void showLineTree(const WebCore::InlineBox* b)
  319. {
  320. if (b)
  321. b->showLineTreeForThis();
  322. }
  323. #endif