RenderFieldset.cpp 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. /*
  2. * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
  3. * (C) 1999 Antti Koivisto (koivisto@kde.org)
  4. * (C) 2000 Dirk Mueller (mueller@kde.org)
  5. * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc.
  6. *
  7. * This library is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU Library General Public
  9. * License as published by the Free Software Foundation; either
  10. * version 2 of the License, or (at your option) any later version.
  11. *
  12. * This library is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * Library General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Library General Public License
  18. * along with this library; see the file COPYING.LIB. If not, write to
  19. * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  20. * Boston, MA 02110-1301, USA.
  21. *
  22. */
  23. #include "config.h"
  24. #include "RenderFieldset.h"
  25. #include "CSSPropertyNames.h"
  26. #include "GraphicsContext.h"
  27. #include "HTMLNames.h"
  28. #include "PaintInfo.h"
  29. using std::min;
  30. using std::max;
  31. namespace WebCore {
  32. using namespace HTMLNames;
  33. RenderFieldset::RenderFieldset(Element* element)
  34. : RenderBlock(element)
  35. {
  36. }
  37. void RenderFieldset::computePreferredLogicalWidths()
  38. {
  39. RenderBlock::computePreferredLogicalWidths();
  40. if (RenderBox* legend = findLegend()) {
  41. int legendMinWidth = legend->minPreferredLogicalWidth();
  42. Length legendMarginLeft = legend->style()->marginLeft();
  43. Length legendMarginRight = legend->style()->marginLeft();
  44. if (legendMarginLeft.isFixed())
  45. legendMinWidth += legendMarginLeft.value();
  46. if (legendMarginRight.isFixed())
  47. legendMinWidth += legendMarginRight.value();
  48. m_minPreferredLogicalWidth = max(m_minPreferredLogicalWidth, legendMinWidth + borderAndPaddingWidth());
  49. }
  50. }
  51. RenderObject* RenderFieldset::layoutSpecialExcludedChild(bool relayoutChildren)
  52. {
  53. RenderBox* legend = findLegend();
  54. if (legend) {
  55. if (relayoutChildren)
  56. legend->setNeedsLayout(true);
  57. legend->layoutIfNeeded();
  58. LayoutUnit logicalLeft;
  59. if (style()->isLeftToRightDirection()) {
  60. switch (legend->style()->textAlign()) {
  61. case CENTER:
  62. logicalLeft = (logicalWidth() - logicalWidthForChild(legend)) / 2;
  63. break;
  64. case RIGHT:
  65. logicalLeft = logicalWidth() - borderEnd() - paddingEnd() - logicalWidthForChild(legend);
  66. break;
  67. default:
  68. logicalLeft = borderStart() + paddingStart() + marginStartForChild(legend);
  69. break;
  70. }
  71. } else {
  72. switch (legend->style()->textAlign()) {
  73. case LEFT:
  74. logicalLeft = borderStart() + paddingStart();
  75. break;
  76. case CENTER: {
  77. // Make sure that the extra pixel goes to the end side in RTL (since it went to the end side
  78. // in LTR).
  79. LayoutUnit centeredWidth = logicalWidth() - logicalWidthForChild(legend);
  80. logicalLeft = centeredWidth - centeredWidth / 2;
  81. break;
  82. }
  83. default:
  84. logicalLeft = logicalWidth() - borderStart() - paddingStart() - marginStartForChild(legend) - logicalWidthForChild(legend);
  85. break;
  86. }
  87. }
  88. setLogicalLeftForChild(legend, logicalLeft);
  89. LayoutUnit fieldsetBorderBefore = borderBefore();
  90. LayoutUnit legendLogicalHeight = logicalHeightForChild(legend);
  91. LayoutUnit legendLogicalTop;
  92. LayoutUnit collapsedLegendExtent;
  93. // FIXME: We need to account for the legend's margin before too.
  94. if (fieldsetBorderBefore > legendLogicalHeight) {
  95. // The <legend> is smaller than the associated fieldset before border
  96. // so the latter determines positioning of the <legend>. The sizing depends
  97. // on the legend's margins as we want to still follow the author's cues.
  98. // Firefox completely ignores the margins in this case which seems wrong.
  99. legendLogicalTop = (fieldsetBorderBefore - legendLogicalHeight) / 2;
  100. collapsedLegendExtent = max<LayoutUnit>(fieldsetBorderBefore, legendLogicalTop + legendLogicalHeight + marginAfterForChild(legend));
  101. } else
  102. collapsedLegendExtent = legendLogicalHeight + marginAfterForChild(legend);
  103. setLogicalTopForChild(legend, legendLogicalTop);
  104. setLogicalHeight(paddingBefore() + collapsedLegendExtent);
  105. }
  106. return legend;
  107. }
  108. RenderBox* RenderFieldset::findLegend(FindLegendOption option) const
  109. {
  110. for (RenderObject* legend = firstChild(); legend; legend = legend->nextSibling()) {
  111. if (option == IgnoreFloatingOrOutOfFlow && legend->isFloatingOrOutOfFlowPositioned())
  112. continue;
  113. if (legend->node() && (legend->node()->hasTagName(legendTag)))
  114. return toRenderBox(legend);
  115. }
  116. return 0;
  117. }
  118. void RenderFieldset::paintBoxDecorations(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
  119. {
  120. if (!paintInfo.shouldPaintWithinRoot(this))
  121. return;
  122. LayoutRect paintRect(paintOffset, size());
  123. RenderBox* legend = findLegend();
  124. if (!legend)
  125. return RenderBlock::paintBoxDecorations(paintInfo, paintOffset);
  126. // FIXME: We need to work with "rl" and "bt" block flow directions. In those
  127. // cases the legend is embedded in the right and bottom borders respectively.
  128. // https://bugs.webkit.org/show_bug.cgi?id=47236
  129. if (style()->isHorizontalWritingMode()) {
  130. LayoutUnit yOff = (legend->y() > 0) ? LayoutUnit() : (legend->height() - borderTop()) / 2;
  131. paintRect.setHeight(paintRect.height() - yOff);
  132. paintRect.setY(paintRect.y() + yOff);
  133. } else {
  134. LayoutUnit xOff = (legend->x() > 0) ? LayoutUnit() : (legend->width() - borderLeft()) / 2;
  135. paintRect.setWidth(paintRect.width() - xOff);
  136. paintRect.setX(paintRect.x() + xOff);
  137. }
  138. if (!boxShadowShouldBeAppliedToBackground(determineBackgroundBleedAvoidance(paintInfo.context)))
  139. paintBoxShadow(paintInfo, paintRect, style(), Normal);
  140. paintFillLayers(paintInfo, style()->visitedDependentColor(CSSPropertyBackgroundColor), style()->backgroundLayers(), paintRect);
  141. paintBoxShadow(paintInfo, paintRect, style(), Inset);
  142. if (!style()->hasBorder())
  143. return;
  144. // Create a clipping region around the legend and paint the border as normal
  145. GraphicsContext* graphicsContext = paintInfo.context;
  146. GraphicsContextStateSaver stateSaver(*graphicsContext);
  147. // FIXME: We need to work with "rl" and "bt" block flow directions. In those
  148. // cases the legend is embedded in the right and bottom borders respectively.
  149. // https://bugs.webkit.org/show_bug.cgi?id=47236
  150. if (style()->isHorizontalWritingMode()) {
  151. LayoutUnit clipTop = paintRect.y();
  152. LayoutUnit clipHeight = max(static_cast<LayoutUnit>(style()->borderTopWidth()), legend->height() - ((legend->height() - borderTop()) / 2));
  153. graphicsContext->clipOut(pixelSnappedIntRect(paintRect.x() + legend->x(), clipTop, legend->width(), clipHeight));
  154. } else {
  155. LayoutUnit clipLeft = paintRect.x();
  156. LayoutUnit clipWidth = max(static_cast<LayoutUnit>(style()->borderLeftWidth()), legend->width());
  157. graphicsContext->clipOut(pixelSnappedIntRect(clipLeft, paintRect.y() + legend->y(), clipWidth, legend->height()));
  158. }
  159. paintBorder(paintInfo, paintRect, style());
  160. }
  161. void RenderFieldset::paintMask(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
  162. {
  163. if (style()->visibility() != VISIBLE || paintInfo.phase != PaintPhaseMask)
  164. return;
  165. LayoutRect paintRect = LayoutRect(paintOffset, size());
  166. RenderBox* legend = findLegend();
  167. if (!legend)
  168. return RenderBlock::paintMask(paintInfo, paintOffset);
  169. // FIXME: We need to work with "rl" and "bt" block flow directions. In those
  170. // cases the legend is embedded in the right and bottom borders respectively.
  171. // https://bugs.webkit.org/show_bug.cgi?id=47236
  172. if (style()->isHorizontalWritingMode()) {
  173. LayoutUnit yOff = (legend->y() > 0) ? LayoutUnit() : (legend->height() - borderTop()) / 2;
  174. paintRect.expand(0, -yOff);
  175. paintRect.move(0, yOff);
  176. } else {
  177. LayoutUnit xOff = (legend->x() > 0) ? LayoutUnit() : (legend->width() - borderLeft()) / 2;
  178. paintRect.expand(-xOff, 0);
  179. paintRect.move(xOff, 0);
  180. }
  181. paintMaskImages(paintInfo, paintRect);
  182. }
  183. } // namespace WebCore