Diff
Modified: trunk/LayoutTests/ChangeLog (129410 => 129411)
--- trunk/LayoutTests/ChangeLog 2012-09-24 21:13:31 UTC (rev 129410)
+++ trunk/LayoutTests/ChangeLog 2012-09-24 21:18:54 UTC (rev 129411)
@@ -1,3 +1,15 @@
+2012-09-24 Hans Muller <[email protected]>
+
+ [CSS Exclusions] ExclusionShape API should use logical coordinates for input/output
+ https://bugs.webkit.org/show_bug.cgi?id=96156
+
+ Reviewed by Dirk Schulze.
+
+ Verify that shape-inside respects the writing-mode, notably the vertical writing-modes.
+
+ * fast/exclusions/shape-inside/shape-inside-vertical-text-expected.html: Added.
+ * fast/exclusions/shape-inside/shape-inside-vertical-text.html: Added.
+
2012-09-24 Alec Flett <[email protected]>
Rebaseline for r129389
Added: trunk/LayoutTests/fast/exclusions/shape-inside/shape-inside-vertical-text-expected.html (0 => 129411)
--- trunk/LayoutTests/fast/exclusions/shape-inside/shape-inside-vertical-text-expected.html (rev 0)
+++ trunk/LayoutTests/fast/exclusions/shape-inside/shape-inside-vertical-text-expected.html 2012-09-24 21:18:54 UTC (rev 129411)
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<html>
+<head>
+<style>
+ #shape-inside-vertical-lr {
+ padding: 20px 35px 25px 15px;
+ width: 150px;
+ height: 175px;
+ -webkit-writing-mode: vertical-lr;
+ position: relative;
+ }
+ #shape-inside-vertical-rl {
+ padding: 20px 35px 25px 15px;
+ width: 150px;
+ height: 175px;
+ -webkit-writing-mode: vertical-rl;
+ position: relative;
+ }
+ #border {
+ position: absolute;
+ top: 13px;
+ left: 18px;
+ width: 150px;
+ height: 175px;
+ border: 2px solid blue;
+ }
+</style>
+</head>
+<body>
+ <div id="shape-inside-vertical-lr">
+ <div id="border"></div>
+ This text should be contained by the blue square.
+ </div>
+ <div id="shape-inside-vertical-rl">
+ <div id="border"></div>
+ This text should be contained by the blue square.
+ </div>
+</body>
+</html>
Added: trunk/LayoutTests/fast/exclusions/shape-inside/shape-inside-vertical-text.html (0 => 129411)
--- trunk/LayoutTests/fast/exclusions/shape-inside/shape-inside-vertical-text.html (rev 0)
+++ trunk/LayoutTests/fast/exclusions/shape-inside/shape-inside-vertical-text.html 2012-09-24 21:18:54 UTC (rev 129411)
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+ if (window.internals)
+ window.internals.settings.setCSSExclusionsEnabled(true);
+</script>
+<style>
+ #shape-inside-vertical-lr {
+ width: 200px;
+ height: 220px;
+ -webkit-shape-inside: rectangle(15px, 20px, 150px, 175px);
+ -webkit-writing-mode: vertical-lr;
+ position: relative;
+ }
+ #shape-inside-vertical-rl {
+ width: 200px;
+ height: 220px;
+ -webkit-shape-inside: rectangle(15px, 20px, 150px, 175px);
+ -webkit-writing-mode: vertical-rl;
+ position: relative;
+ }
+ #border {
+ position: absolute;
+ top: 13px;
+ left: 18px;
+ width: 150px;
+ height: 175px;
+ border: 2px solid blue;
+ }
+</style>
+</head>
+<body>
+ <div id="shape-inside-vertical-lr">
+ <div id="border"></div>
+ This text should be contained by the blue square.
+ </div>
+ <div id="shape-inside-vertical-rl">
+ <div id="border"></div>
+ This text should be contained by the blue square.
+ </div>
+</body>
+</html>
Modified: trunk/Source/WebCore/ChangeLog (129410 => 129411)
--- trunk/Source/WebCore/ChangeLog 2012-09-24 21:13:31 UTC (rev 129410)
+++ trunk/Source/WebCore/ChangeLog 2012-09-24 21:18:54 UTC (rev 129411)
@@ -1,3 +1,55 @@
+2012-09-24 Hans Muller <[email protected]>
+
+ [CSS Exclusions] ExclusionShape API should use logical coordinates for input/output
+ https://bugs.webkit.org/show_bug.cgi?id=96156
+
+ Reviewed by Dirk Schulze.
+
+ Correct how ExclusionShapes deal with logical coordinates and enable
+ shape-inside exclusion layout for vertical writing-modes.
+
+ BasicShape's are defined in physical cooordinates, incoming line and box
+ dimensions are logical coordinates, and the ExclusionShape internals assume
+ that lines are aligned with the Y axis. The createExclusionShape() method
+ is responsible for converting the BasicShape to the internal coordinate
+ system when the writing-mode is vertical. Similarly, the getInclude,ExcludedIntervals()
+ methods are responsible for converting their logical line parameters to Y
+ values in the internal coordinate system. The min,maxYForLogicalLine()
+ methods do the conversion, based on the WritingMode the ExclusionShape
+ was created with. The getInclude,ExcludedIntervals() methods return the
+ logical left and right edges of line segments. No transformation is needed for this.
+
+ The ExclusionShape's internal coordinate system is essentially the
+ "logical" one, except that top/bottom always map to Y, no matter what
+ the writing-mode is. This is just to simplify writing geometrical shape
+ algorithms, notably the complex ones for polygons. The bug report includes a
+ pair of diagrams that clarify how internal coordinates are related to logical
+ and physical coordinates.
+
+ Test: fast/exclusions/shape-inside/shape-inside-vertical-text.html
+
+ * rendering/ExclusionRectangle.cpp:
+ (WebCore::ExclusionRectangle::getExcludedIntervals): rename more accurately reflects return value
+ (WebCore::ExclusionRectangle::getIncludedIntervals): rename for consistency with "excluded" version
+ * rendering/ExclusionRectangle.h:
+ * rendering/ExclusionShape.cpp:
+ (WebCore):
+ (WebCore::ExclusionShape::createExclusionShape):
+ * rendering/ExclusionShape.h:
+ (LineSegment):
+ (WebCore::LineSegment::LineSegment): relocated from WrapShapeInfo.h
+ (WebCore):
+ (ExclusionShape):
+ (WebCore::ExclusionShape::minYForLogicalLine):
+ (WebCore::ExclusionShape::maxYForLogicalLine):
+ (WebCore::ExclusionShape::internalToLogicalBoundingBox):
+ * rendering/WrapShapeInfo.cpp:
+ (WebCore::WrapShapeInfo::isWrapShapeInfoEnabledForRenderBlock):
+ (WebCore::WrapShapeInfo::computeShapeSize): pass writingMode to createExclusionShape()
+ (WebCore::WrapShapeInfo::computeSegmentsForLine): removed short-circuit for vertical writing-modes
+ * rendering/WrapShapeInfo.h:
+ (WebCore):
+
2012-09-24 Tony Chang <[email protected]>
Replace RenderMeter::updateLogicalHeight to RenderMeter::computeLogicalHeight
Modified: trunk/Source/WebCore/rendering/ExclusionRectangle.cpp (129410 => 129411)
--- trunk/Source/WebCore/rendering/ExclusionRectangle.cpp 2012-09-24 21:13:31 UTC (rev 129410)
+++ trunk/Source/WebCore/rendering/ExclusionRectangle.cpp 2012-09-24 21:18:54 UTC (rev 129411)
@@ -40,10 +40,10 @@
return rx * sqrt(1 - (y*y) / (ry*ry));
}
-void ExclusionRectangle::getOutsideIntervals(float y1, float y2, Vector<ExclusionInterval>& rv) const
+void ExclusionRectangle::getExcludedIntervals(float logicalTop, float logicalBottom, SegmentList& result) const
{
- if (y1 > y2)
- std::swap(y1, y2);
+ float y1 = minYForLogicalLine(logicalTop, logicalBottom);
+ float y2 = maxYForLogicalLine(logicalTop, logicalBottom);
if (y2 < m_y || y1 >= m_y + m_height)
return;
@@ -65,15 +65,15 @@
}
}
- rv.append(ExclusionInterval(x1, x2));
+ result.append(LineSegment(x1, x2));
}
-void ExclusionRectangle::getInsideIntervals(float y1, float y2, Vector<ExclusionInterval>& rv) const
+void ExclusionRectangle::getIncludedIntervals(float logicalTop, float logicalBottom, SegmentList& result) const
{
- if (y1 > y2)
- std::swap(y1, y2);
+ float y1 = minYForLogicalLine(logicalTop, logicalBottom);
+ float y2 = maxYForLogicalLine(logicalTop, logicalBottom);
- if (y1 < m_y || y2 >= m_y + m_height)
+ if (y1 < m_y || y2 > m_y + m_height)
return;
float x1 = m_x;
@@ -106,7 +106,7 @@
}
}
- rv.append(ExclusionInterval(x1, x2));
+ result.append(LineSegment(x1, x2));
}
} // namespace WebCore
Modified: trunk/Source/WebCore/rendering/ExclusionRectangle.h (129410 => 129411)
--- trunk/Source/WebCore/rendering/ExclusionRectangle.h 2012-09-24 21:13:31 UTC (rev 129410)
+++ trunk/Source/WebCore/rendering/ExclusionRectangle.h 2012-09-24 21:18:54 UTC (rev 129411)
@@ -31,6 +31,7 @@
#define ExclusionRectangle_h
#include "ExclusionShape.h"
+#include "FloatSize.h"
#include <wtf/Assertions.h>
#include <wtf/Vector.h>
@@ -38,20 +39,20 @@
class ExclusionRectangle : public ExclusionShape {
public:
- ExclusionRectangle(float x, float y, float width, float height, float rx = 0, float ry = 0)
+ ExclusionRectangle(const FloatRect& bounds, const FloatSize& radii)
: ExclusionShape()
- , m_x(x)
- , m_y(y)
- , m_width(width)
- , m_height(height)
- , m_rx(rx)
- , m_ry(ry)
+ , m_x(bounds.x())
+ , m_y(bounds.y())
+ , m_width(bounds.width())
+ , m_height(bounds.height())
+ , m_rx(radii.width())
+ , m_ry(radii.height())
{
}
- virtual FloatRect shapeLogicalBoundingBox() const OVERRIDE { return FloatRect(m_x, m_y, m_width, m_height); }
- virtual void getOutsideIntervals(float y1, float y2, Vector<ExclusionInterval>&) const OVERRIDE;
- virtual void getInsideIntervals(float y1, float y2, Vector<ExclusionInterval>&) const OVERRIDE;
+ virtual FloatRect shapeLogicalBoundingBox() const OVERRIDE { return internalToLogicalBoundingBox(FloatRect(m_x, m_y, m_width, m_height)); }
+ virtual void getExcludedIntervals(float logicalTop, float logicalBottom, SegmentList&) const OVERRIDE;
+ virtual void getIncludedIntervals(float logicalTop, float logicalBottom, SegmentList&) const OVERRIDE;
private:
float m_x;
Modified: trunk/Source/WebCore/rendering/ExclusionShape.cpp (129410 => 129411)
--- trunk/Source/WebCore/rendering/ExclusionShape.cpp 2012-09-24 21:13:31 UTC (rev 129410)
+++ trunk/Source/WebCore/rendering/ExclusionShape.cpp 2012-09-24 21:18:54 UTC (rev 129411)
@@ -32,6 +32,7 @@
#include "BasicShapeFunctions.h"
#include "ExclusionRectangle.h"
+#include "FloatSize.h"
#include "LengthFunctions.h"
#include "NotImplemented.h"
#include "WindRule.h"
@@ -41,66 +42,93 @@
namespace WebCore {
-static PassOwnPtr<ExclusionShape> createExclusionRectangle(float x, float y, float width, float height, float rx, float ry)
+static PassOwnPtr<ExclusionShape> createExclusionRectangle(const FloatRect& bounds, const FloatSize& radii)
{
- ASSERT(width >= 0 && height >= 0 && rx >= 0 && ry >= 0);
- return adoptPtr(new ExclusionRectangle(x, y, width, height, rx, ry));
+ ASSERT(bounds.width() >= 0 && bounds.height() >= 0 && radii.width() >= 0 && radii.height() >= 0);
+ return adoptPtr(new ExclusionRectangle(bounds, radii));
}
-static PassOwnPtr<ExclusionShape> createExclusionCircle(float cx, float cy, float radius)
+static PassOwnPtr<ExclusionShape> createExclusionCircle(const FloatPoint& center, float radius)
{
ASSERT(radius >= 0);
- return adoptPtr(new ExclusionRectangle(cx - radius, cy - radius, cx + radius, cy + radius, radius, radius));
+ return adoptPtr(new ExclusionRectangle(FloatRect(center.x() - radius, center.y() - radius, radius*2, radius*2), FloatSize(radius, radius)));
}
-static PassOwnPtr<ExclusionShape> createExclusionEllipse(float cx, float cy, float rx, float ry)
+static PassOwnPtr<ExclusionShape> createExclusionEllipse(const FloatPoint& center, const FloatSize& radii)
{
- ASSERT(rx >= 0 && ry >= 0);
- return adoptPtr(new ExclusionRectangle(cx - rx, cy - ry, cx + rx, cy + ry, rx, ry));
+ ASSERT(radii.width() >= 0 && radii.height() >= 0);
+ return adoptPtr(new ExclusionRectangle(FloatRect(center.x() - radii.width(), center.y() - radii.height(), radii.width()*2, radii.height()*2), radii));
}
-PassOwnPtr<ExclusionShape> ExclusionShape::createExclusionShape(const BasicShape* wrapShape, float borderBoxLogicalWidth, float borderBoxLogicalHeight)
+// If the writingMode is vertical, then the BasicShape's (physical) x and y coordinates are swapped, so that
+// line segments are parallel to the internal coordinate system's X axis.
+
+PassOwnPtr<ExclusionShape> ExclusionShape::createExclusionShape(const BasicShape* basicShape, float logicalBoxWidth, float logicalBoxHeight, WritingMode writingMode)
{
- if (!wrapShape)
+ if (!basicShape)
return nullptr;
- switch (wrapShape->type()) {
+ bool horizontalWritingMode = isHorizontalWritingMode(writingMode);
+ float boxWidth = horizontalWritingMode ? logicalBoxWidth : logicalBoxHeight;
+ float boxHeight = horizontalWritingMode ? logicalBoxHeight : logicalBoxWidth;
+ OwnPtr<ExclusionShape> exclusionShape;
+
+ switch (basicShape->type()) {
+
case BasicShape::BASIC_SHAPE_RECTANGLE: {
- const BasicShapeRectangle* rectangle = static_cast<const BasicShapeRectangle*>(wrapShape);
- Length rx = rectangle->cornerRadiusX();
- Length ry = rectangle->cornerRadiusY();
- return createExclusionRectangle(
- floatValueForLength(rectangle->x(), borderBoxLogicalWidth),
- floatValueForLength(rectangle->y(), borderBoxLogicalHeight),
- floatValueForLength(rectangle->width(), borderBoxLogicalWidth),
- floatValueForLength(rectangle->height(), borderBoxLogicalHeight),
- rx.isUndefined() ? 0 : floatValueForLength(rx, borderBoxLogicalWidth),
- ry.isUndefined() ? 0 : floatValueForLength(ry, borderBoxLogicalHeight) );
+ const BasicShapeRectangle* rectangle = static_cast<const BasicShapeRectangle*>(basicShape);
+ float x = floatValueForLength(rectangle->x(), boxWidth);
+ float y = floatValueForLength(rectangle->y(), boxHeight);
+ float width = floatValueForLength(rectangle->width(), boxWidth);
+ float height = floatValueForLength(rectangle->height(), boxHeight);
+ Length radiusXLength = rectangle->cornerRadiusX();
+ Length radiusYLength = rectangle->cornerRadiusY();
+ float radiusX = radiusXLength.isUndefined() ? 0 : floatValueForLength(radiusXLength, boxWidth);
+ float radiusY = radiusYLength.isUndefined() ? 0 : floatValueForLength(radiusYLength, boxHeight);
+
+ exclusionShape = horizontalWritingMode
+ ? createExclusionRectangle(FloatRect(x, y, width, height), FloatSize(radiusX, radiusY))
+ : createExclusionRectangle(FloatRect(y, x, height, width), FloatSize(radiusY, radiusX));
+ break;
}
case BasicShape::BASIC_SHAPE_CIRCLE: {
- const BasicShapeCircle* circle = static_cast<const BasicShapeCircle*>(wrapShape);
- return createExclusionCircle(
- floatValueForLength(circle->centerX(), borderBoxLogicalWidth),
- floatValueForLength(circle->centerY(), borderBoxLogicalHeight),
- floatValueForLength(circle->radius(), std::max(borderBoxLogicalHeight, borderBoxLogicalWidth)) );
+ const BasicShapeCircle* circle = static_cast<const BasicShapeCircle*>(basicShape);
+ float centerX = floatValueForLength(circle->centerX(), boxWidth);
+ float centerY = floatValueForLength(circle->centerY(), boxHeight);
+ float radius = floatValueForLength(circle->radius(), std::max(boxHeight, boxWidth));
+
+ exclusionShape = horizontalWritingMode
+ ? createExclusionCircle(FloatPoint(centerX, centerY), radius)
+ : createExclusionCircle(FloatPoint(centerY, centerX), radius);
+ break;
}
case BasicShape::BASIC_SHAPE_ELLIPSE: {
- const BasicShapeEllipse* ellipse = static_cast<const BasicShapeEllipse*>(wrapShape);
- return createExclusionEllipse(
- floatValueForLength(ellipse->centerX(), borderBoxLogicalWidth),
- floatValueForLength(ellipse->centerY(), borderBoxLogicalHeight),
- floatValueForLength(ellipse->radiusX(), borderBoxLogicalWidth),
- floatValueForLength(ellipse->radiusY(), borderBoxLogicalHeight) );
+ const BasicShapeEllipse* ellipse = static_cast<const BasicShapeEllipse*>(basicShape);
+ float centerX = floatValueForLength(ellipse->centerX(), boxWidth);
+ float centerY = floatValueForLength(ellipse->centerY(), boxHeight);
+ float radiusX = floatValueForLength(ellipse->radiusX(), boxWidth);
+ float radiusY = floatValueForLength(ellipse->radiusY(), boxHeight);
+
+ exclusionShape = horizontalWritingMode
+ ? createExclusionEllipse(FloatPoint(centerX, centerY), FloatSize(radiusX, radiusY))
+ : createExclusionEllipse(FloatPoint(centerY, centerX), FloatSize(radiusY, radiusX));
+ break;
}
case BasicShape::BASIC_SHAPE_POLYGON:
notImplemented();
+
+ default:
+ ASSERT_NOT_REACHED();
}
- ASSERT_NOT_REACHED();
- return nullptr;
+ exclusionShape->m_logicalBoxWidth = logicalBoxWidth;
+ exclusionShape->m_logicalBoxHeight = logicalBoxHeight;
+ exclusionShape->m_writingMode = writingMode;
+
+ return exclusionShape.release();
}
} // namespace WebCore
Modified: trunk/Source/WebCore/rendering/ExclusionShape.h (129410 => 129411)
--- trunk/Source/WebCore/rendering/ExclusionShape.h 2012-09-24 21:13:31 UTC (rev 129410)
+++ trunk/Source/WebCore/rendering/ExclusionShape.h 2012-09-24 21:18:54 UTC (rev 129411)
@@ -31,22 +31,51 @@
#define ExclusionShape_h
#include "BasicShapes.h"
-#include "ExclusionInterval.h"
#include "FloatRect.h"
+#include "WritingMode.h"
#include <wtf/PassOwnPtr.h>
#include <wtf/Vector.h>
namespace WebCore {
+struct LineSegment {
+ float logicalLeft;
+ float logicalRight;
+
+ LineSegment(float logicalLeft, float logicalRight)
+ : logicalLeft(logicalLeft)
+ , logicalRight(logicalRight)
+ {
+ }
+};
+
+typedef Vector<LineSegment> SegmentList;
+
+
+// A representation of a BasicShape that enables layout code to determine how to break a line up into segments
+// that will fit within or around a shape. The line is defined by a pair of logical Y coordinates and the
+// computed segments are returned as pairs of logical X coordinates. The BasicShape itself is defined in
+// physical coordinates.
+
class ExclusionShape {
public:
- static PassOwnPtr<ExclusionShape> createExclusionShape(const BasicShape*, float borderBoxLogicalWidth, float borderBoxLogicalHeight);
+ static PassOwnPtr<ExclusionShape> createExclusionShape(const BasicShape*, float logicalBoxWidth, float logicalBoxHeight, WritingMode);
virtual ~ExclusionShape() { }
virtual FloatRect shapeLogicalBoundingBox() const = 0;
- virtual void getInsideIntervals(float logicalTop, float logicalBottom, Vector<ExclusionInterval>&) const = 0;
- virtual void getOutsideIntervals(float logicalTop, float logicalBottom, Vector<ExclusionInterval>&) const = 0;
+ virtual void getIncludedIntervals(float logicalTop, float logicalBottom, SegmentList&) const = 0;
+ virtual void getExcludedIntervals(float logicalTop, float logicalBottom, SegmentList&) const = 0;
+
+protected:
+ float minYForLogicalLine(float logicalTop, float logicalBottom) const { return (m_writingMode == RightToLeftWritingMode) ? m_logicalBoxHeight - logicalBottom : logicalTop; }
+ float maxYForLogicalLine(float logicalTop, float logicalBottom) const { return (m_writingMode == RightToLeftWritingMode) ? m_logicalBoxHeight - logicalTop : logicalBottom; }
+ FloatRect internalToLogicalBoundingBox(FloatRect r) const { return (m_writingMode == RightToLeftWritingMode) ? FloatRect(r.x(), m_logicalBoxHeight - r.maxY(), r.width(), r.height()) : r; }
+
+private:
+ WritingMode m_writingMode;
+ float m_logicalBoxWidth;
+ float m_logicalBoxHeight;
};
} // namespace WebCore
Modified: trunk/Source/WebCore/rendering/WrapShapeInfo.cpp (129410 => 129411)
--- trunk/Source/WebCore/rendering/WrapShapeInfo.cpp 2012-09-24 21:13:31 UTC (rev 129410)
+++ trunk/Source/WebCore/rendering/WrapShapeInfo.cpp 2012-09-24 21:18:54 UTC (rev 129411)
@@ -71,10 +71,6 @@
bool WrapShapeInfo::isWrapShapeInfoEnabledForRenderBlock(const RenderBlock* block)
{
- // FIXME: Bug 89705: Enable shape inside for vertical writing modes
- if (!block->isHorizontalWritingMode())
- return false;
-
// FIXME: Bug 89707: Enable shape inside for non-rectangular shapes
BasicShape* shape = block->style()->wrapShapeInside();
return (shape && shape->type() == BasicShape::BASIC_SHAPE_RECTANGLE);
@@ -107,7 +103,7 @@
BasicShape* shape = m_block->style()->wrapShapeInside();
ASSERT(shape);
- m_shape = ExclusionShape::createExclusionShape(shape, logicalWidth, logicalHeight);
+ m_shape = ExclusionShape::createExclusionShape(shape, logicalWidth, logicalHeight, m_block->style()->writingMode());
ASSERT(m_shape);
}
@@ -118,15 +114,7 @@
if (lineState() == LINE_INSIDE_SHAPE) {
ASSERT(m_shape);
-
- Vector<ExclusionInterval> intervals;
- m_shape->getInsideIntervals(lineTop, lineTop, intervals); // FIXME: Bug 95479, workaround for now
- for (size_t i = 0; i < intervals.size(); i++) {
- LineSegment segment;
- segment.logicalLeft = intervals[i].x1;
- segment.logicalRight = intervals[i].x2;
- m_segments.append(segment);
- }
+ m_shape->getIncludedIntervals(lineTop, lineTop, m_segments); // FIXME: Bug 95479, workaround for now
}
return m_segments.size();
}
Modified: trunk/Source/WebCore/rendering/WrapShapeInfo.h (129410 => 129411)
--- trunk/Source/WebCore/rendering/WrapShapeInfo.h 2012-09-24 21:13:31 UTC (rev 129410)
+++ trunk/Source/WebCore/rendering/WrapShapeInfo.h 2012-09-24 21:18:54 UTC (rev 129411)
@@ -42,15 +42,7 @@
namespace WebCore {
class RenderBlock;
-class WrapShapeInfo;
-struct LineSegment {
- LayoutUnit logicalLeft;
- LayoutUnit logicalRight;
-};
-
-typedef Vector<LineSegment> SegmentList;
-
class WrapShapeInfo {
WTF_MAKE_FAST_ALLOCATED;
public: