Direct2D QPA: Refactor code to reduce code duplication
Refactor duplicate logic in painterPathToPathGeometry and vectorPathToID2D1PathGeometry into one utility class. At the same time make the naming of the two functions consistent with each other. Change-Id: I03c8fc183863473b7337223e51835cf080914a41 Reviewed-by: Friedemann Kleint <Friedemann.Kleint@digia.com>
This commit is contained in:
parent
7d0f4dde06
commit
0c95332f8f
@ -92,51 +92,124 @@ static inline ID2D1Factory1 *factory()
|
||||
return QWindowsDirect2DContext::instance()->d2dFactory();
|
||||
}
|
||||
|
||||
// XXX reduce code duplication between painterPathToPathGeometry and
|
||||
// vectorPathToID2D1PathGeometry, the two are quite similar
|
||||
|
||||
static ComPtr<ID2D1PathGeometry1> painterPathToPathGeometry(const QPainterPath &path)
|
||||
class Direct2DPathGeometryWriter
|
||||
{
|
||||
ComPtr<ID2D1PathGeometry1> geometry;
|
||||
ComPtr<ID2D1GeometrySink> sink;
|
||||
public:
|
||||
Direct2DPathGeometryWriter()
|
||||
: m_inFigure(false)
|
||||
, m_roundCoordinates(false)
|
||||
{
|
||||
|
||||
HRESULT hr = factory()->CreatePathGeometry(&geometry);
|
||||
if (FAILED(hr)) {
|
||||
qWarning("%s: Could not create path geometry: %#x", __FUNCTION__, hr);
|
||||
}
|
||||
|
||||
bool begin()
|
||||
{
|
||||
HRESULT hr = factory()->CreatePathGeometry(&m_geometry);
|
||||
if (FAILED(hr)) {
|
||||
qWarning("%s: Could not create path geometry: %#x", __FUNCTION__, hr);
|
||||
return false;
|
||||
}
|
||||
|
||||
hr = m_geometry->Open(&m_sink);
|
||||
if (FAILED(hr)) {
|
||||
qWarning("%s: Could not create geometry sink: %#x", __FUNCTION__, hr);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void setWindingFillEnabled(bool enable)
|
||||
{
|
||||
if (enable)
|
||||
m_sink->SetFillMode(D2D1_FILL_MODE_WINDING);
|
||||
else
|
||||
m_sink->SetFillMode(D2D1_FILL_MODE_ALTERNATE);
|
||||
}
|
||||
|
||||
void setAliasingEnabled(bool enable)
|
||||
{
|
||||
m_roundCoordinates = enable;
|
||||
}
|
||||
|
||||
bool isInFigure() const
|
||||
{
|
||||
return m_inFigure;
|
||||
}
|
||||
|
||||
void moveTo(const QPointF &point)
|
||||
{
|
||||
if (m_inFigure)
|
||||
m_sink->EndFigure(D2D1_FIGURE_END_OPEN);
|
||||
|
||||
m_sink->BeginFigure(adjusted(point), D2D1_FIGURE_BEGIN_FILLED);
|
||||
m_inFigure = true;
|
||||
}
|
||||
|
||||
void lineTo(const QPointF &point)
|
||||
{
|
||||
m_sink->AddLine(adjusted(point));
|
||||
}
|
||||
|
||||
void curveTo(const QPointF &p1, const QPointF &p2, const QPointF &p3)
|
||||
{
|
||||
D2D1_BEZIER_SEGMENT segment = {
|
||||
adjusted(p1),
|
||||
adjusted(p2),
|
||||
adjusted(p3)
|
||||
};
|
||||
|
||||
m_sink->AddBezier(segment);
|
||||
}
|
||||
|
||||
void close()
|
||||
{
|
||||
if (m_inFigure)
|
||||
m_sink->EndFigure(D2D1_FIGURE_END_OPEN);
|
||||
|
||||
m_sink->Close();
|
||||
}
|
||||
|
||||
ComPtr<ID2D1PathGeometry1> geometry() const
|
||||
{
|
||||
return m_geometry;
|
||||
}
|
||||
|
||||
private:
|
||||
D2D1_POINT_2F adjusted(const QPointF &point)
|
||||
{
|
||||
if (m_roundCoordinates)
|
||||
return to_d2d_point_2f(point.toPoint());
|
||||
else
|
||||
return to_d2d_point_2f(point);
|
||||
}
|
||||
|
||||
ComPtr<ID2D1PathGeometry1> m_geometry;
|
||||
ComPtr<ID2D1GeometrySink> m_sink;
|
||||
|
||||
bool m_inFigure;
|
||||
bool m_roundCoordinates;
|
||||
};
|
||||
|
||||
static ComPtr<ID2D1PathGeometry1> painterPathToID2D1PathGeometry(const QPainterPath &path, bool alias)
|
||||
{
|
||||
Direct2DPathGeometryWriter writer;
|
||||
if (!writer.begin())
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hr = geometry->Open(&sink);
|
||||
if (FAILED(hr)) {
|
||||
qWarning("%s: Could not create geometry sink: %#x", __FUNCTION__, hr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
switch (path.fillRule()) {
|
||||
case Qt::WindingFill:
|
||||
sink->SetFillMode(D2D1_FILL_MODE_WINDING);
|
||||
break;
|
||||
case Qt::OddEvenFill:
|
||||
sink->SetFillMode(D2D1_FILL_MODE_ALTERNATE);
|
||||
break;
|
||||
}
|
||||
|
||||
bool inFigure = false;
|
||||
writer.setWindingFillEnabled(path.fillRule() == Qt::WindingFill);
|
||||
writer.setAliasingEnabled(alias);
|
||||
|
||||
for (int i = 0; i < path.elementCount(); i++) {
|
||||
const QPainterPath::Element element = path.elementAt(i);
|
||||
|
||||
switch (element.type) {
|
||||
case QPainterPath::MoveToElement:
|
||||
if (inFigure)
|
||||
sink->EndFigure(D2D1_FIGURE_END_OPEN);
|
||||
|
||||
sink->BeginFigure(to_d2d_point_2f(element), D2D1_FIGURE_BEGIN_FILLED);
|
||||
inFigure = true;
|
||||
writer.moveTo(element);
|
||||
break;
|
||||
|
||||
case QPainterPath::LineToElement:
|
||||
sink->AddLine(to_d2d_point_2f(element));
|
||||
writer.lineTo(element);
|
||||
break;
|
||||
|
||||
case QPainterPath::CurveToElement:
|
||||
@ -149,13 +222,7 @@ static ComPtr<ID2D1PathGeometry1> painterPathToPathGeometry(const QPainterPath &
|
||||
Q_ASSERT(data1.type == QPainterPath::CurveToDataElement);
|
||||
Q_ASSERT(data2.type == QPainterPath::CurveToDataElement);
|
||||
|
||||
D2D1_BEZIER_SEGMENT segment;
|
||||
|
||||
segment.point1 = to_d2d_point_2f(element);
|
||||
segment.point2 = to_d2d_point_2f(data1);
|
||||
segment.point3 = to_d2d_point_2f(data2);
|
||||
|
||||
sink->AddBezier(segment);
|
||||
writer.curveTo(element, data1, data2);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -165,55 +232,22 @@ static ComPtr<ID2D1PathGeometry1> painterPathToPathGeometry(const QPainterPath &
|
||||
}
|
||||
}
|
||||
|
||||
if (inFigure)
|
||||
sink->EndFigure(D2D1_FIGURE_END_OPEN);
|
||||
|
||||
sink->Close();
|
||||
|
||||
return geometry;
|
||||
writer.close();
|
||||
return writer.geometry();
|
||||
}
|
||||
|
||||
static ComPtr<ID2D1PathGeometry1> vectorPathToID2D1PathGeometry(const QVectorPath &path, bool alias)
|
||||
{
|
||||
ComPtr<ID2D1PathGeometry1> pathGeometry;
|
||||
HRESULT hr = factory()->CreatePathGeometry(pathGeometry.GetAddressOf());
|
||||
if (FAILED(hr)) {
|
||||
qWarning("%s: Could not create path geometry: %#x", __FUNCTION__, hr);
|
||||
Direct2DPathGeometryWriter writer;
|
||||
if (!writer.begin())
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (path.isEmpty())
|
||||
return pathGeometry;
|
||||
|
||||
ComPtr<ID2D1GeometrySink> sink;
|
||||
hr = pathGeometry->Open(sink.GetAddressOf());
|
||||
if (FAILED(hr)) {
|
||||
qWarning("%s: Could not create geometry sink: %#x", __FUNCTION__, hr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sink->SetFillMode(path.hasWindingFill() ? D2D1_FILL_MODE_WINDING
|
||||
: D2D1_FILL_MODE_ALTERNATE);
|
||||
|
||||
bool inFigure = false;
|
||||
writer.setWindingFillEnabled(path.hasWindingFill());
|
||||
writer.setAliasingEnabled(alias);
|
||||
|
||||
const QPainterPath::ElementType *types = path.elements();
|
||||
const int count = path.elementCount();
|
||||
const qreal *points = 0;
|
||||
|
||||
QScopedArrayPointer<qreal> rounded_points;
|
||||
|
||||
if (alias) {
|
||||
// Aliased painting, round to whole numbers
|
||||
rounded_points.reset(new qreal[count * 2]);
|
||||
points = rounded_points.data();
|
||||
|
||||
for (int i = 0; i < (count * 2); i++)
|
||||
rounded_points[i] = qRound(path.points()[i]);
|
||||
} else {
|
||||
// Antialiased painting, keep original numbers
|
||||
points = path.points();
|
||||
}
|
||||
const qreal *points = path.points();
|
||||
|
||||
Q_ASSERT(points);
|
||||
|
||||
@ -226,15 +260,11 @@ static ComPtr<ID2D1PathGeometry1> vectorPathToID2D1PathGeometry(const QVectorPat
|
||||
|
||||
switch (types[i]) {
|
||||
case QPainterPath::MoveToElement:
|
||||
if (inFigure)
|
||||
sink->EndFigure(D2D1_FIGURE_END_OPEN);
|
||||
|
||||
sink->BeginFigure(D2D1::Point2F(x, y), D2D1_FIGURE_BEGIN_FILLED);
|
||||
inFigure = true;
|
||||
writer.moveTo(QPointF(x, y));
|
||||
break;
|
||||
|
||||
case QPainterPath::LineToElement:
|
||||
sink->AddLine(D2D1::Point2F(x, y));
|
||||
writer.lineTo(QPointF(x, y));
|
||||
break;
|
||||
|
||||
case QPainterPath::CurveToElement:
|
||||
@ -251,13 +281,7 @@ static ComPtr<ID2D1PathGeometry1> vectorPathToID2D1PathGeometry(const QVectorPat
|
||||
const qreal x3 = points[i * 2];
|
||||
const qreal y3 = points[i * 2 + 1];
|
||||
|
||||
D2D1_BEZIER_SEGMENT segment = {
|
||||
D2D1::Point2F(x, y),
|
||||
D2D1::Point2F(x2, y2),
|
||||
D2D1::Point2F(x3, y3)
|
||||
};
|
||||
|
||||
sink->AddBezier(segment);
|
||||
writer.curveTo(QPointF(x, y), QPointF(x2, y2), QPointF(x3, y3));
|
||||
}
|
||||
break;
|
||||
|
||||
@ -267,23 +291,17 @@ static ComPtr<ID2D1PathGeometry1> vectorPathToID2D1PathGeometry(const QVectorPat
|
||||
}
|
||||
}
|
||||
} else {
|
||||
sink->BeginFigure(D2D1::Point2F(points[0], points[1]), D2D1_FIGURE_BEGIN_FILLED);
|
||||
inFigure = true;
|
||||
|
||||
writer.moveTo(QPointF(points[0], points[1]));
|
||||
for (int i = 1; i < count; i++)
|
||||
sink->AddLine(D2D1::Point2F(points[i * 2], points[i * 2 + 1]));
|
||||
writer.lineTo(QPointF(points[i * 2], points[i * 2 + 1]));
|
||||
}
|
||||
|
||||
if (inFigure) {
|
||||
if (writer.isInFigure())
|
||||
if (path.hasImplicitClose())
|
||||
sink->AddLine(D2D1::Point2F(points[0], points[1]));
|
||||
writer.lineTo(QPointF(points[0], points[1]));
|
||||
|
||||
sink->EndFigure(D2D1_FIGURE_END_OPEN);
|
||||
}
|
||||
|
||||
sink->Close();
|
||||
|
||||
return pathGeometry;
|
||||
writer.close();
|
||||
return writer.geometry();
|
||||
}
|
||||
|
||||
class QWindowsDirect2DPaintEnginePrivate : public QPaintEngineExPrivate
|
||||
@ -375,7 +393,7 @@ public:
|
||||
{
|
||||
popClip();
|
||||
|
||||
ComPtr<ID2D1PathGeometry1> geometry = painterPathToPathGeometry(clipPath);
|
||||
ComPtr<ID2D1PathGeometry1> geometry = painterPathToID2D1PathGeometry(clipPath, antialiasMode() == D2D1_ANTIALIAS_MODE_ALIASED);
|
||||
if (!geometry)
|
||||
return;
|
||||
|
||||
@ -816,7 +834,7 @@ bool QWindowsDirect2DPaintEngine::begin(QPaintDevice * pdev)
|
||||
QPainterPath p;
|
||||
p.addRegion(systemClip());
|
||||
|
||||
ComPtr<ID2D1PathGeometry1> geometry = painterPathToPathGeometry(p);
|
||||
ComPtr<ID2D1PathGeometry1> geometry = painterPathToID2D1PathGeometry(p, d->antialiasMode() == D2D1_ANTIALIAS_MODE_ALIASED);
|
||||
if (!geometry)
|
||||
return false;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user