HTML5 <details> and <summary>: rendering
[WebKit-https.git] / Source / WebCore / rendering / RenderDetailsMarker.cpp
index 26e49d9..c366a78 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
+ * Copyright (C) 2010, 2011 Nokia Corporation and/or its subsidiary(-ies)
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
 #include "config.h"
 #include "RenderDetailsMarker.h"
 
+#include "GraphicsContext.h"
+#include "HTMLNames.h"
+#include "PaintInfo.h"
+#include "RenderDetails.h"
+#include "RenderSummary.h"
+
 namespace WebCore {
 
-RenderDetailsMarker::RenderDetailsMarker(Node* element)
-    : RenderBlock(element)
+using namespace HTMLNames;
+
+RenderDetailsMarker::RenderDetailsMarker(RenderDetails* item)
+    : RenderBox(item->document())
+    , m_details(item)
+{
+    setInline(true);
+    setReplaced(true);
+}
+
+void RenderDetailsMarker::destroy()
+{
+    if (m_details)
+        m_details->markerDestroyed();
+
+    RenderBox::destroy();
+}
+
+int RenderDetailsMarker::lineHeight(bool firstLine, LineDirectionMode direction, LinePositionMode) const
+{
+    return m_details->lineHeight(firstLine, direction, PositionOfInteriorLineBoxes);
+}
+
+int RenderDetailsMarker::baselinePosition(FontBaseline baselineType, bool firstLine, LineDirectionMode direction, LinePositionMode) const
+{
+    return m_details->baselinePosition(baselineType, firstLine, direction, PositionOfInteriorLineBoxes);
+}
+
+void RenderDetailsMarker::computePreferredLogicalWidths()
+{
+    ASSERT(preferredLogicalWidthsDirty());
+
+    m_minPreferredLogicalWidth = 2 * style()->fontMetrics().ascent() / 3;
+    m_maxPreferredLogicalWidth = m_minPreferredLogicalWidth;
+
+    setPreferredLogicalWidthsDirty(false);
+}
+
+void RenderDetailsMarker::layout()
+{
+    ASSERT(needsLayout());
+
+    setLogicalWidth(minPreferredLogicalWidth());
+    setLogicalHeight(style()->fontMetrics().height());
+
+    setMarginStart(0);
+    setMarginEnd(style()->fontMetrics().ascent() - minPreferredLogicalWidth() + 1);
+
+    setNeedsLayout(false);
+}
+
+IntRect RenderDetailsMarker::getRelativeMarkerRect() const
+{
+    IntRect relativeRect;
+
+    int bulletWidth = minPreferredLogicalWidth();
+    relativeRect = IntRect((logicalWidth() - bulletWidth) / 2, (logicalHeight() - bulletWidth) / 2, bulletWidth, bulletWidth);
+
+    if (!style()->isHorizontalWritingMode()) {
+        relativeRect = relativeRect.transposedRect();
+        relativeRect.setX(width() - relativeRect.x() - relativeRect.width());
+    }
+
+    return relativeRect;
+}
+
+bool RenderDetailsMarker::isOpen() const
 {
+    return m_details && m_details->isOpen();
+}
+
+static Path createPath(const FloatPoint* path)
+{
+    Path result;
+    result.moveTo(FloatPoint(path[0].x(), path[0].y()));
+    for (int i = 1; i < 4; ++i)
+        result.addLineTo(FloatPoint(path[i].x(), path[i].y()));
+    return result;
+}
+
+static Path createDownArrowPath()
+{
+    FloatPoint points[4] = { FloatPoint(0.0, 0.07), FloatPoint(0.5, 0.93), FloatPoint(1.0, 0.07), FloatPoint(0.0, 0.07) };
+    return createPath(points);
+}
+
+static Path createUpArrowPath()
+{
+    FloatPoint points[4] = { FloatPoint(0.0, 0.93), FloatPoint(0.5, 0.07), FloatPoint(1.0, 0.93), FloatPoint(0.0, 0.93) };
+    return createPath(points);
+}
+
+static Path createLeftArrowPath()
+{
+    FloatPoint points[4] = { FloatPoint(1.0, 0.0), FloatPoint(0.14, 0.5), FloatPoint(1.0, 1.0), FloatPoint(1.0, 0.0) };
+    return createPath(points);
+}
+
+static Path createRightArrowPath()
+{
+    FloatPoint points[4] = { FloatPoint(0.0, 0.0), FloatPoint(0.86, 0.5), FloatPoint(0.0, 1.0), FloatPoint(0.0, 0.0) };
+    return createPath(points);
+}
+
+RenderDetailsMarker::Orientation RenderDetailsMarker::orientation() const
+{
+    switch (style()->writingMode()) {
+    case TopToBottomWritingMode:
+        if (style()->isLeftToRightDirection())
+            return isOpen() ? Down : Right;
+        return isOpen() ? Down : Left;
+    case RightToLeftWritingMode:
+        if (style()->isLeftToRightDirection())
+            return isOpen() ? Left : Down;
+        return isOpen() ? Left : Up;
+    case LeftToRightWritingMode:
+        if (style()->isLeftToRightDirection())
+            return isOpen() ? Right : Down;
+        return isOpen() ? Right : Up;
+    case BottomToTopWritingMode:
+        if (style()->isLeftToRightDirection())
+            return isOpen() ? Up : Right;
+        return isOpen() ? Up : Left;
+    }
+    return Right;
+}
+
+Path RenderDetailsMarker::getCanonicalPath() const
+{
+    switch (orientation()) {
+    case Left: return createLeftArrowPath();
+    case Right: return createRightArrowPath();
+    case Up: return createUpArrowPath();
+    case Down: return createDownArrowPath();
+    }
+
+    return Path();
+}
+
+Path RenderDetailsMarker::getPath(const IntPoint& origin) const
+{
+    IntRect rect = getRelativeMarkerRect();
+    Path result = getCanonicalPath();
+    result.transform(AffineTransform().scale(rect.width()));
+    result.translate(FloatSize(origin.x() + rect.x(), origin.y() + rect.y()));
+    return result;
+}
+
+void RenderDetailsMarker::paint(PaintInfo& paintInfo, int tx, int ty)
+{
+    if (paintInfo.phase != PaintPhaseForeground || style()->visibility() != VISIBLE)
+        return;
+
+    IntPoint boxOrigin(tx + x(), ty + y());
+    IntRect overflowRect(visualOverflowRect());
+    overflowRect.move(boxOrigin.x(), boxOrigin.y());
+    overflowRect.inflate(maximalOutlineSize(paintInfo.phase));
+
+    if (!paintInfo.rect.intersects(overflowRect))
+        return;
+
+    const Color color(style()->visitedDependentColor(CSSPropertyColor));
+    paintInfo.context->setStrokeColor(color, style()->colorSpace());
+    paintInfo.context->setStrokeStyle(SolidStroke);
+    paintInfo.context->setStrokeThickness(1.0f);
+    paintInfo.context->setFillColor(color, style()->colorSpace());
+
+    paintInfo.context->fillPath(getPath(boxOrigin));
 }
 
 }