diff --git a/modules/juce_graphics/native/juce_win32_Direct2DGraphicsContext.cpp b/modules/juce_graphics/native/juce_win32_Direct2DGraphicsContext.cpp index 1d121faada..fa23910d13 100644 --- a/modules/juce_graphics/native/juce_win32_Direct2DGraphicsContext.cpp +++ b/modules/juce_graphics/native/juce_win32_Direct2DGraphicsContext.cpp @@ -85,19 +85,17 @@ public: void setOrigin (int x, int y) { - currentState->origin.addXY (x, y); + addTransform (AffineTransform::translation ((float) x, (float) y)); } - void addTransform (const AffineTransform& /*transform*/) + void addTransform (const AffineTransform& transform) { - //xxx todo - jassertfalse; + currentState->transform = transform.followedBy (currentState->transform); } float getScaleFactor() { - //xxx - return 1.0f; + return currentState->transform.getScaleFactor(); } bool clipToRectangle (const Rectangle& r) @@ -119,24 +117,23 @@ public: void clipToPath (const Path& path, const AffineTransform& transform) { - currentState->clipToPath (pathToPathGeometry (path, transform, currentState->origin)); + currentState->clipToPath (pathToPathGeometry (path, transform)); } void clipToImageAlpha (const Image& sourceImage, const AffineTransform& transform) { - currentState->clipToImage (sourceImage,transform); + currentState->clipToImage (sourceImage, transform); } bool clipRegionIntersects (const Rectangle& r) { - const Rectangle r2 (r + currentState->origin); - return currentState->clipRect.intersects (r2); + return currentState->clipRect.intersects (r.toFloat().transformed (currentState->transform).getSmallestIntegerContainer()); } Rectangle getClipBounds() const { // xxx could this take into account complex clip regions? - return currentState->clipRect - currentState->origin; + return currentState->clipRect.toFloat().transformed (currentState->transform.inverted()).getSmallestIntegerContainer(); } bool isClipEmpty() const @@ -183,14 +180,16 @@ public: void fillRect (const Rectangle& r, bool /*replaceExistingContents*/) { + renderingTarget->SetTransform (transformToMatrix (currentState->transform)); currentState->createBrush(); - renderingTarget->FillRectangle (rectangleToRectF (r + currentState->origin), currentState->currentBrush); + renderingTarget->FillRectangle (rectangleToRectF (r), currentState->currentBrush); + renderingTarget->SetTransform (D2D1::IdentityMatrix()); } void fillPath (const Path& p, const AffineTransform& transform) { currentState->createBrush(); - ComSmartPtr geometry (pathToPathGeometry (p, transform, currentState->origin)); + ComSmartPtr geometry (pathToPathGeometry (p, transform.followedBy (currentState->transform))); if (renderingTarget != nullptr) renderingTarget->FillGeometry (geometry, currentState->currentBrush); @@ -198,10 +197,7 @@ public: void drawImage (const Image& image, const AffineTransform& transform) { - const int x = currentState->origin.getX(); - const int y = currentState->origin.getY(); - - renderingTarget->SetTransform (transformToMatrix (transform) * D2D1::Matrix3x2F::Translation ((FLOAT) x, (FLOAT) y)); + renderingTarget->SetTransform (transformToMatrix (transform.followedBy (currentState->transform))); D2D1_SIZE_U size; size.width = image.getWidth(); @@ -227,40 +223,37 @@ public: void drawLine (const Line & line) { // xxx doesn't seem to be correctly aligned, may need nudging by 0.5 to match the software renderer's behaviour - const Line l (line.getStart() + currentState->origin.toFloat(), - line.getEnd() + currentState->origin.toFloat()); - + renderingTarget->SetTransform (transformToMatrix (currentState->transform)); currentState->createBrush(); - renderingTarget->DrawLine (D2D1::Point2F (l.getStartX(), l.getStartY()), - D2D1::Point2F (l.getEndX(), l.getEndY()), + renderingTarget->DrawLine (D2D1::Point2F (line.getStartX(), line.getStartY()), + D2D1::Point2F (line.getEndX(), line.getEndY()), currentState->currentBrush); + renderingTarget->SetTransform (D2D1::IdentityMatrix()); } void drawVerticalLine (int x, float top, float bottom) { // xxx doesn't seem to be correctly aligned, may need nudging by 0.5 to match the software renderer's behaviour + renderingTarget->SetTransform (transformToMatrix (currentState->transform)); currentState->createBrush(); - x += currentState->origin.getX(); - const int y = currentState->origin.getY(); - - renderingTarget->DrawLine (D2D1::Point2F ((FLOAT) x, y + top), - D2D1::Point2F ((FLOAT) x, y + bottom), + renderingTarget->DrawLine (D2D1::Point2F ((FLOAT) x, top), + D2D1::Point2F ((FLOAT) x, bottom), currentState->currentBrush); + renderingTarget->SetTransform (D2D1::IdentityMatrix()); } void drawHorizontalLine (int y, float left, float right) { // xxx doesn't seem to be correctly aligned, may need nudging by 0.5 to match the software renderer's behaviour + renderingTarget->SetTransform (transformToMatrix (currentState->transform)); currentState->createBrush(); - y += currentState->origin.getY(); - const int x = currentState->origin.getX(); - - renderingTarget->DrawLine (D2D1::Point2F (x + left, (FLOAT) y), - D2D1::Point2F (x + right, (FLOAT) y), + renderingTarget->DrawLine (D2D1::Point2F (left, (FLOAT) y), + D2D1::Point2F (right, (FLOAT) y), currentState->currentBrush); + renderingTarget->SetTransform (D2D1::IdentityMatrix()); } void setFont (const Font& newFont) @@ -275,15 +268,14 @@ public: void drawGlyph (int glyphNumber, const AffineTransform& transform) { - const float x = (float) currentState->origin.getX(); - const float y = (float) currentState->origin.getY(); - currentState->createBrush(); currentState->createFont(); float hScale = currentState->font.getHorizontalScale(); - renderingTarget->SetTransform (D2D1::Matrix3x2F::Scale (hScale, 1) * transformToMatrix (transform) * D2D1::Matrix3x2F::Translation (x, y)); + renderingTarget->SetTransform (transformToMatrix (AffineTransform::scale (hScale, 1.0f) + .followedBy (transform) + .followedBy (currentState->transform))); const UINT16 glyphIndices = (UINT16) glyphNumber; const FLOAT glyphAdvances = 0; @@ -305,6 +297,18 @@ public: renderingTarget->SetTransform (D2D1::IdentityMatrix()); } + bool drawTextLayout (const AttributedString& text, const Rectangle& area) + { + renderingTarget->SetTransform (transformToMatrix (currentState->transform)); + + const Direct2DFactories& factories = Direct2DFactories::getInstance(); + DirectWriteTypeLayout::drawToD2DContext (text, area, renderingTarget, factories.directWriteFactory, + factories.d2dFactory, factories.systemFonts); + + renderingTarget->SetTransform (D2D1::IdentityMatrix()); + return true; + } + //============================================================================== class SavedState { @@ -323,8 +327,8 @@ public: // bottleneck.. Can the same internal objects be shared by multiple state objects, maybe using copy-on-write? setFill (owner.currentState->fillType); currentBrush = owner.currentState->currentBrush; - origin = owner.currentState->origin; clipRect = owner.currentState->clipRect; + transform = owner.currentState->transform; font = owner.currentState->font; currentFontFace = owner.currentState->currentFontFace; @@ -357,7 +361,7 @@ public: void clipToRectangle (const Rectangle& r) { clearClip(); - clipRect = r + origin; + clipRect = r.toFloat().transformed (transform).getSmallestIntegerContainer(); shouldClipRect = true; pushClips(); } @@ -569,9 +573,6 @@ public: { if (currentBrush == 0) { - const int x = origin.getX(); - const int y = origin.getY(); - if (fillType.isColour()) { D2D1_COLOR_F colour = colourToD2D (fillType.colour); @@ -610,7 +611,7 @@ public: D2D1_BRUSH_PROPERTIES brushProps; brushProps.opacity = fillType.getOpacity(); - brushProps.transform = transformToMatrix (fillType.transform); + brushProps.transform = transformToMatrix (fillType.transform.followedBy (transform)); const int numColors = fillType.gradient->getNumColours(); @@ -633,7 +634,7 @@ public: float r = p1.getDistanceFrom (p2); D2D1_RADIAL_GRADIENT_BRUSH_PROPERTIES props = - D2D1::RadialGradientBrushProperties (D2D1::Point2F (p1.getX() + x, p1.getY() + y), + D2D1::RadialGradientBrushProperties (D2D1::Point2F (p1.x, p1.y), D2D1::Point2F (0, 0), r, r); @@ -648,8 +649,8 @@ public: const Point& p2 = fillType.gradient->point2; D2D1_LINEAR_GRADIENT_BRUSH_PROPERTIES props = - D2D1::LinearGradientBrushProperties (D2D1::Point2F (p1.getX() + x, p1.getY() + y), - D2D1::Point2F (p2.getX() + x, p2.getY() + y)); + D2D1::LinearGradientBrushProperties (D2D1::Point2F (p1.x, p1.y), + D2D1::Point2F (p2.x, p2.y)); owner.renderingTarget->CreateLinearGradientBrush (props, brushProps, gradientStops, linearGradient.resetAndGetPointerAddress()); @@ -664,7 +665,7 @@ public: Direct2DLowLevelGraphicsContext& owner; - Point origin; + AffineTransform transform; Font font; float fontHeightToEmSizeFactor; @@ -722,12 +723,12 @@ private: return D2D1::RectF ((float) r.getX(), (float) r.getY(), (float) r.getRight(), (float) r.getBottom()); } - static const D2D1_COLOR_F colourToD2D (const Colour& c) + static D2D1_COLOR_F colourToD2D (const Colour& c) { return D2D1::ColorF::ColorF (c.getFloatRed(), c.getFloatGreen(), c.getFloatBlue(), c.getFloatAlpha()); } - static const D2D1_POINT_2F pointTransformed (int x, int y, const AffineTransform& transform = AffineTransform::identity) + static D2D1_POINT_2F pointTransformed (int x, int y, const AffineTransform& transform) { transform.transformPoint (x, y); return D2D1::Point2F ((FLOAT) x, (FLOAT) y); @@ -758,7 +759,7 @@ private: return p; } - static void pathToGeometrySink (const Path& path, ID2D1GeometrySink* sink, const AffineTransform& transform, int x, int y) + static void pathToGeometrySink (const Path& path, ID2D1GeometrySink* sink, const AffineTransform& transform) { Path::Iterator it (path); @@ -771,13 +772,13 @@ private: D2D1_BEZIER_SEGMENT seg; transform.transformPoint (it.x1, it.y1); - seg.point1 = D2D1::Point2F (it.x1 + x, it.y1 + y); + seg.point1 = D2D1::Point2F (it.x1, it.y1); transform.transformPoint (it.x2, it.y2); - seg.point2 = D2D1::Point2F (it.x2 + x, it.y2 + y); + seg.point2 = D2D1::Point2F (it.x2, it.y2); transform.transformPoint(it.x3, it.y3); - seg.point3 = D2D1::Point2F (it.x3 + x, it.y3 + y); + seg.point3 = D2D1::Point2F (it.x3, it.y3); sink->AddBezier (seg); break; @@ -786,7 +787,7 @@ private: case Path::Iterator::lineTo: { transform.transformPoint (it.x1, it.y1); - sink->AddLine (D2D1::Point2F (it.x1 + x, it.y1 + y)); + sink->AddLine (D2D1::Point2F (it.x1, it.y1)); break; } @@ -795,10 +796,10 @@ private: D2D1_QUADRATIC_BEZIER_SEGMENT seg; transform.transformPoint (it.x1, it.y1); - seg.point1 = D2D1::Point2F (it.x1 + x, it.y1 + y); + seg.point1 = D2D1::Point2F (it.x1, it.y1); transform.transformPoint (it.x2, it.y2); - seg.point2 = D2D1::Point2F (it.x2 + x, it.y2 + y); + seg.point2 = D2D1::Point2F (it.x2, it.y2); sink->AddQuadraticBezier (seg); break; @@ -813,14 +814,14 @@ private: case Path::Iterator::startNewSubPath: { transform.transformPoint (it.x1, it.y1); - sink->BeginFigure (D2D1::Point2F (it.x1 + x, it.y1 + y), D2D1_FIGURE_BEGIN_FILLED); + sink->BeginFigure (D2D1::Point2F (it.x1, it.y1), D2D1_FIGURE_BEGIN_FILLED); break; } } } } - static ID2D1PathGeometry* pathToPathGeometry (const Path& path, const AffineTransform& transform, const Point& point) + static ID2D1PathGeometry* pathToPathGeometry (const Path& path, const AffineTransform& transform) { ID2D1PathGeometry* p = nullptr; Direct2DFactories::getInstance().d2dFactory->CreatePathGeometry (&p); @@ -829,13 +830,13 @@ private: HRESULT hr = p->Open (sink.resetAndGetPointerAddress()); sink->SetFillMode (D2D1_FILL_MODE_WINDING); // xxx need to check Path::isUsingNonZeroWinding() - pathToGeometrySink (path, sink, transform, point.getX(), point.getY()); + pathToGeometrySink (path, sink, transform); hr = sink->Close(); return p; } - static const D2D1::Matrix3x2F transformToMatrix (const AffineTransform& transform) + static D2D1::Matrix3x2F transformToMatrix (const AffineTransform& transform) { D2D1::Matrix3x2F matrix; matrix._11 = transform.mat00;