RenderRubyRun.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  1. /*
  2. * Copyright (C) 2009 Google Inc. All rights reserved.
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions are
  6. * met:
  7. *
  8. * * Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * * Redistributions in binary form must reproduce the above
  11. * copyright notice, this list of conditions and the following disclaimer
  12. * in the documentation and/or other materials provided with the
  13. * distribution.
  14. * * Neither the name of Google Inc. nor the names of its
  15. * contributors may be used to endorse or promote products derived from
  16. * this software without specific prior written permission.
  17. *
  18. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  19. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  20. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  21. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  22. * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  23. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  24. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  25. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  26. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  27. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  28. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  29. */
  30. #include "config.h"
  31. #include "RenderRubyRun.h"
  32. #include "RenderRubyBase.h"
  33. #include "RenderRubyText.h"
  34. #include "RenderText.h"
  35. #include "RenderView.h"
  36. #include "StyleInheritedData.h"
  37. #include <wtf/StackStats.h>
  38. using namespace std;
  39. namespace WebCore {
  40. RenderRubyRun::RenderRubyRun()
  41. : RenderBlock(0)
  42. {
  43. setReplaced(true);
  44. setInline(true);
  45. }
  46. RenderRubyRun::~RenderRubyRun()
  47. {
  48. }
  49. bool RenderRubyRun::hasRubyText() const
  50. {
  51. // The only place where a ruby text can be is in the first position
  52. // Note: As anonymous blocks, ruby runs do not have ':before' or ':after' content themselves.
  53. return firstChild() && firstChild()->isRubyText();
  54. }
  55. bool RenderRubyRun::hasRubyBase() const
  56. {
  57. // The only place where a ruby base can be is in the last position
  58. // Note: As anonymous blocks, ruby runs do not have ':before' or ':after' content themselves.
  59. return lastChild() && lastChild()->isRubyBase();
  60. }
  61. bool RenderRubyRun::isEmpty() const
  62. {
  63. return !hasRubyText() && !hasRubyBase();
  64. }
  65. RenderRubyText* RenderRubyRun::rubyText() const
  66. {
  67. RenderObject* child = firstChild();
  68. // If in future it becomes necessary to support floating or positioned ruby text,
  69. // layout will have to be changed to handle them properly.
  70. ASSERT(!child || !child->isRubyText() || !child->isFloatingOrOutOfFlowPositioned());
  71. return child && child->isRubyText() ? static_cast<RenderRubyText*>(child) : 0;
  72. }
  73. RenderRubyBase* RenderRubyRun::rubyBase() const
  74. {
  75. RenderObject* child = lastChild();
  76. return child && child->isRubyBase() ? static_cast<RenderRubyBase*>(child) : 0;
  77. }
  78. RenderRubyBase* RenderRubyRun::rubyBaseSafe()
  79. {
  80. RenderRubyBase* base = rubyBase();
  81. if (!base) {
  82. base = createRubyBase();
  83. RenderBlock::addChild(base);
  84. }
  85. return base;
  86. }
  87. RenderBlock* RenderRubyRun::firstLineBlock() const
  88. {
  89. return 0;
  90. }
  91. void RenderRubyRun::updateFirstLetter()
  92. {
  93. }
  94. bool RenderRubyRun::isChildAllowed(RenderObject* child, RenderStyle*) const
  95. {
  96. return child->isRubyText() || child->isInline();
  97. }
  98. void RenderRubyRun::addChild(RenderObject* child, RenderObject* beforeChild)
  99. {
  100. ASSERT(child);
  101. if (child->isRubyText()) {
  102. if (!beforeChild) {
  103. // RenderRuby has already ascertained that we can add the child here.
  104. ASSERT(!hasRubyText());
  105. // prepend ruby texts as first child
  106. RenderBlock::addChild(child, firstChild());
  107. } else if (beforeChild->isRubyText()) {
  108. // New text is inserted just before another.
  109. // In this case the new text takes the place of the old one, and
  110. // the old text goes into a new run that is inserted as next sibling.
  111. ASSERT(beforeChild->parent() == this);
  112. RenderObject* ruby = parent();
  113. ASSERT(ruby->isRuby());
  114. RenderBlock* newRun = staticCreateRubyRun(ruby);
  115. ruby->addChild(newRun, nextSibling());
  116. // Add the new ruby text and move the old one to the new run
  117. // Note: Doing it in this order and not using RenderRubyRun's methods,
  118. // in order to avoid automatic removal of the ruby run in case there is no
  119. // other child besides the old ruby text.
  120. RenderBlock::addChild(child, beforeChild);
  121. RenderBlock::removeChild(beforeChild);
  122. newRun->addChild(beforeChild);
  123. } else if (hasRubyBase()) {
  124. // Insertion before a ruby base object.
  125. // In this case we need insert a new run before the current one and split the base.
  126. RenderObject* ruby = parent();
  127. RenderRubyRun* newRun = staticCreateRubyRun(ruby);
  128. ruby->addChild(newRun, this);
  129. newRun->addChild(child);
  130. rubyBaseSafe()->moveChildren(newRun->rubyBaseSafe(), beforeChild);
  131. }
  132. } else {
  133. // child is not a text -> insert it into the base
  134. // (append it instead if beforeChild is the ruby text)
  135. if (beforeChild && beforeChild->isRubyText())
  136. beforeChild = 0;
  137. rubyBaseSafe()->addChild(child, beforeChild);
  138. }
  139. }
  140. void RenderRubyRun::removeChild(RenderObject* child)
  141. {
  142. // If the child is a ruby text, then merge the ruby base with the base of
  143. // the right sibling run, if possible.
  144. if (!beingDestroyed() && !documentBeingDestroyed() && child->isRubyText()) {
  145. RenderRubyBase* base = rubyBase();
  146. RenderObject* rightNeighbour = nextSibling();
  147. if (base && rightNeighbour && rightNeighbour->isRubyRun()) {
  148. // Ruby run without a base can happen only at the first run.
  149. RenderRubyRun* rightRun = toRenderRubyRun(rightNeighbour);
  150. if (rightRun->hasRubyBase()) {
  151. RenderRubyBase* rightBase = rightRun->rubyBaseSafe();
  152. // Collect all children in a single base, then swap the bases.
  153. rightBase->moveChildren(base);
  154. moveChildTo(rightRun, base);
  155. rightRun->moveChildTo(this, rightBase);
  156. // The now empty ruby base will be removed below.
  157. ASSERT(!rubyBase()->firstChild());
  158. }
  159. }
  160. }
  161. RenderBlock::removeChild(child);
  162. if (!beingDestroyed() && !documentBeingDestroyed()) {
  163. // Check if our base (if any) is now empty. If so, destroy it.
  164. RenderBlock* base = rubyBase();
  165. if (base && !base->firstChild()) {
  166. RenderBlock::removeChild(base);
  167. base->deleteLineBoxTree();
  168. base->destroy();
  169. }
  170. // If any of the above leaves the run empty, destroy it as well.
  171. if (isEmpty()) {
  172. parent()->removeChild(this);
  173. deleteLineBoxTree();
  174. destroy();
  175. }
  176. }
  177. }
  178. RenderRubyBase* RenderRubyRun::createRubyBase() const
  179. {
  180. RenderRubyBase* renderer = RenderRubyBase::createAnonymous(document());
  181. RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyleWithDisplay(style(), BLOCK);
  182. newStyle->setTextAlign(CENTER); // FIXME: use WEBKIT_CENTER?
  183. renderer->setStyle(newStyle.release());
  184. return renderer;
  185. }
  186. RenderRubyRun* RenderRubyRun::staticCreateRubyRun(const RenderObject* parentRuby)
  187. {
  188. ASSERT(parentRuby && parentRuby->isRuby());
  189. RenderRubyRun* rr = new (parentRuby->renderArena()) RenderRubyRun();
  190. rr->setDocumentForAnonymous(parentRuby->document());
  191. RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyleWithDisplay(parentRuby->style(), INLINE_BLOCK);
  192. rr->setStyle(newStyle.release());
  193. return rr;
  194. }
  195. RenderObject* RenderRubyRun::layoutSpecialExcludedChild(bool relayoutChildren)
  196. {
  197. StackStats::LayoutCheckPoint layoutCheckPoint;
  198. // Don't bother positioning the RenderRubyRun yet.
  199. RenderRubyText* rt = rubyText();
  200. if (!rt)
  201. return 0;
  202. if (relayoutChildren)
  203. rt->setChildNeedsLayout(true, MarkOnlyThis);
  204. rt->layoutIfNeeded();
  205. return rt;
  206. }
  207. void RenderRubyRun::layout()
  208. {
  209. RenderBlock::layout();
  210. RenderRubyText* rt = rubyText();
  211. if (!rt)
  212. return;
  213. rt->setLogicalLeft(0);
  214. // Place the RenderRubyText such that its bottom is flush with the lineTop of the first line of the RenderRubyBase.
  215. LayoutUnit lastLineRubyTextBottom = rt->logicalHeight();
  216. LayoutUnit firstLineRubyTextTop = 0;
  217. RootInlineBox* rootBox = rt->lastRootBox();
  218. if (rootBox) {
  219. // In order to align, we have to ignore negative leading.
  220. firstLineRubyTextTop = rt->firstRootBox()->logicalTopLayoutOverflow();
  221. lastLineRubyTextBottom = rootBox->logicalBottomLayoutOverflow();
  222. }
  223. if (style()->isFlippedLinesWritingMode() == (style()->rubyPosition() == RubyPositionAfter)) {
  224. LayoutUnit firstLineTop = 0;
  225. if (RenderRubyBase* rb = rubyBase()) {
  226. RootInlineBox* rootBox = rb->firstRootBox();
  227. if (rootBox)
  228. firstLineTop = rootBox->logicalTopLayoutOverflow();
  229. firstLineTop += rb->logicalTop();
  230. }
  231. rt->setLogicalTop(-lastLineRubyTextBottom + firstLineTop);
  232. } else {
  233. LayoutUnit lastLineBottom = logicalHeight();
  234. if (RenderRubyBase* rb = rubyBase()) {
  235. RootInlineBox* rootBox = rb->lastRootBox();
  236. if (rootBox)
  237. lastLineBottom = rootBox->logicalBottomLayoutOverflow();
  238. lastLineBottom += rb->logicalTop();
  239. }
  240. rt->setLogicalTop(-firstLineRubyTextTop + lastLineBottom);
  241. }
  242. // Update our overflow to account for the new RenderRubyText position.
  243. computeOverflow(clientLogicalBottom());
  244. }
  245. void RenderRubyRun::getOverhang(bool firstLine, RenderObject* startRenderer, RenderObject* endRenderer, int& startOverhang, int& endOverhang) const
  246. {
  247. ASSERT(!needsLayout());
  248. startOverhang = 0;
  249. endOverhang = 0;
  250. RenderRubyBase* rubyBase = this->rubyBase();
  251. RenderRubyText* rubyText = this->rubyText();
  252. if (!rubyBase || !rubyText)
  253. return;
  254. if (!rubyBase->firstRootBox())
  255. return;
  256. int logicalWidth = this->logicalWidth();
  257. int logicalLeftOverhang = numeric_limits<int>::max();
  258. int logicalRightOverhang = numeric_limits<int>::max();
  259. for (RootInlineBox* rootInlineBox = rubyBase->firstRootBox(); rootInlineBox; rootInlineBox = rootInlineBox->nextRootBox()) {
  260. logicalLeftOverhang = min<int>(logicalLeftOverhang, rootInlineBox->logicalLeft());
  261. logicalRightOverhang = min<int>(logicalRightOverhang, logicalWidth - rootInlineBox->logicalRight());
  262. }
  263. startOverhang = style()->isLeftToRightDirection() ? logicalLeftOverhang : logicalRightOverhang;
  264. endOverhang = style()->isLeftToRightDirection() ? logicalRightOverhang : logicalLeftOverhang;
  265. if (!startRenderer || !startRenderer->isText() || startRenderer->style(firstLine)->fontSize() > rubyBase->style(firstLine)->fontSize())
  266. startOverhang = 0;
  267. if (!endRenderer || !endRenderer->isText() || endRenderer->style(firstLine)->fontSize() > rubyBase->style(firstLine)->fontSize())
  268. endOverhang = 0;
  269. // We overhang a ruby only if the neighboring render object is a text.
  270. // We can overhang the ruby by no more than half the width of the neighboring text
  271. // and no more than half the font size.
  272. int halfWidthOfFontSize = rubyText->style(firstLine)->fontSize() / 2;
  273. if (startOverhang)
  274. startOverhang = min<int>(startOverhang, min<int>(toRenderText(startRenderer)->minLogicalWidth(), halfWidthOfFontSize));
  275. if (endOverhang)
  276. endOverhang = min<int>(endOverhang, min<int>(toRenderText(endRenderer)->minLogicalWidth(), halfWidthOfFontSize));
  277. }
  278. } // namespace WebCore