| 
							- /*
 -   ==============================================================================
 - 
 -    This file is part of the JUCE library.
 -    Copyright (c) 2022 - Raw Material Software Limited
 - 
 -    JUCE is an open source library subject to commercial or open-source
 -    licensing.
 - 
 -    By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 -    Agreement and JUCE Privacy Policy.
 - 
 -    End User License Agreement: www.juce.com/juce-7-licence
 -    Privacy Policy: www.juce.com/juce-privacy-policy
 - 
 -    Or: You may also use this code under the terms of the GPL v3 (see
 -    www.gnu.org/licenses).
 - 
 -    JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 -    EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 -    DISCLAIMED.
 - 
 -   ==============================================================================
 - */
 - 
 - namespace juce
 - {
 - 
 - template <typename Type>
 - D2D1_RECT_F rectangleToRectF (const Rectangle<Type>& r)
 - {
 -     return { (float) r.getX(), (float) r.getY(), (float) r.getRight(), (float) r.getBottom() };
 - }
 - 
 - static D2D1_COLOR_F colourToD2D (Colour c)
 - {
 -     return { c.getFloatRed(), c.getFloatGreen(), c.getFloatBlue(), c.getFloatAlpha() };
 - }
 - 
 - static void pathToGeometrySink (const Path& path, ID2D1GeometrySink* sink, const AffineTransform& transform)
 - {
 -     Path::Iterator it (path);
 - 
 -     while (it.next())
 -     {
 -         switch (it.elementType)
 -         {
 -         case Path::Iterator::cubicTo:
 -         {
 -             transform.transformPoint (it.x1, it.y1);
 -             transform.transformPoint (it.x2, it.y2);
 -             transform.transformPoint (it.x3, it.y3);
 - 
 -             sink->AddBezier ({ { it.x1, it.y1 }, { it.x2, it.y2 }, { it.x3, it.y3 } });
 -             break;
 -         }
 - 
 -         case Path::Iterator::lineTo:
 -         {
 -             transform.transformPoint (it.x1, it.y1);
 -             sink->AddLine ({ it.x1, it.y1 });
 -             break;
 -         }
 - 
 -         case Path::Iterator::quadraticTo:
 -         {
 -             transform.transformPoint (it.x1, it.y1);
 -             transform.transformPoint (it.x2, it.y2);
 -             sink->AddQuadraticBezier ({ { it.x1, it.y1 }, { it.x2, it.y2 } });
 -             break;
 -         }
 - 
 -         case Path::Iterator::closePath:
 -         {
 -             sink->EndFigure (D2D1_FIGURE_END_CLOSED);
 -             break;
 -         }
 - 
 -         case Path::Iterator::startNewSubPath:
 -         {
 -             transform.transformPoint (it.x1, it.y1);
 -             sink->BeginFigure ({ it.x1, it.y1 }, D2D1_FIGURE_BEGIN_FILLED);
 -             break;
 -         }
 -         }
 -     }
 - }
 - 
 - static D2D1::Matrix3x2F transformToMatrix (const AffineTransform& transform)
 - {
 -     return { transform.mat00, transform.mat10, transform.mat01, transform.mat11, transform.mat02, transform.mat12 };
 - }
 - 
 - static D2D1_POINT_2F pointTransformed (int x, int y, const AffineTransform& transform)
 - {
 -     transform.transformPoint (x, y);
 -     return { (FLOAT) x, (FLOAT) y };
 - }
 - 
 - static void rectToGeometrySink (const Rectangle<int>& rect, ID2D1GeometrySink* sink, const AffineTransform& transform)
 - {
 -     sink->BeginFigure (pointTransformed (rect.getX(),     rect.getY(),       transform), D2D1_FIGURE_BEGIN_FILLED);
 -     sink->AddLine     (pointTransformed (rect.getRight(), rect.getY(),       transform));
 -     sink->AddLine     (pointTransformed (rect.getRight(), rect.getBottom(),  transform));
 -     sink->AddLine     (pointTransformed (rect.getX(),     rect.getBottom(),  transform));
 -     sink->EndFigure (D2D1_FIGURE_END_CLOSED);
 - }
 - 
 - //==============================================================================
 - struct Direct2DLowLevelGraphicsContext::Pimpl
 - {
 -     ID2D1PathGeometry* rectListToPathGeometry (const RectangleList<int>& clipRegion)
 -     {
 -         ID2D1PathGeometry* p = nullptr;
 -         factories->d2dFactory->CreatePathGeometry (&p);
 - 
 -         ComSmartPtr<ID2D1GeometrySink> sink;
 -         auto hr = p->Open (sink.resetAndGetPointerAddress()); // xxx handle error
 -         sink->SetFillMode (D2D1_FILL_MODE_WINDING);
 - 
 -         for (int i = clipRegion.getNumRectangles(); --i >= 0;)
 -             rectToGeometrySink (clipRegion.getRectangle (i), sink, AffineTransform());
 - 
 -         hr = sink->Close();
 -         return p;
 -     }
 - 
 -     ID2D1PathGeometry* pathToPathGeometry (const Path& path, const AffineTransform& transform)
 -     {
 -         ID2D1PathGeometry* p = nullptr;
 -         factories->d2dFactory->CreatePathGeometry (&p);
 - 
 -         ComSmartPtr<ID2D1GeometrySink> sink;
 -         auto hr = p->Open (sink.resetAndGetPointerAddress());
 -         sink->SetFillMode (D2D1_FILL_MODE_WINDING); // xxx need to check Path::isUsingNonZeroWinding()
 - 
 -         pathToGeometrySink (path, sink, transform);
 - 
 -         hr = sink->Close();
 -         return p;
 -     }
 - 
 -     SharedResourcePointer<Direct2DFactories> factories;
 - 
 -     ComSmartPtr<ID2D1HwndRenderTarget> renderingTarget;
 -     ComSmartPtr<ID2D1SolidColorBrush> colourBrush;
 - };
 - 
 - //==============================================================================
 - struct Direct2DLowLevelGraphicsContext::SavedState
 - {
 - public:
 -     SavedState (Direct2DLowLevelGraphicsContext& owner_)
 -         : owner (owner_)
 -     {
 -         if (owner.currentState != nullptr)
 -         {
 -             // xxx seems like a very slow way to create one of these, and this is a performance
 -             // 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;
 -             clipRect = owner.currentState->clipRect;
 -             transform = owner.currentState->transform;
 - 
 -             font = owner.currentState->font;
 -             currentFontFace = owner.currentState->currentFontFace;
 -         }
 -         else
 -         {
 -             const auto size = owner.pimpl->renderingTarget->GetPixelSize();
 -             clipRect.setSize (size.width, size.height);
 -             setFill (FillType (Colours::black));
 -         }
 -     }
 - 
 -     ~SavedState()
 -     {
 -         clearClip();
 -         clearFont();
 -         clearFill();
 -         clearPathClip();
 -         clearImageClip();
 -         complexClipLayer = nullptr;
 -         bitmapMaskLayer = nullptr;
 -     }
 - 
 -     void clearClip()
 -     {
 -         popClips();
 -         shouldClipRect = false;
 -     }
 - 
 -     void clipToRectangle (const Rectangle<int>& r)
 -     {
 -         clearClip();
 -         clipRect = r.toFloat().transformedBy (transform).getSmallestIntegerContainer();
 -         shouldClipRect = true;
 -         pushClips();
 -     }
 - 
 -     void clearPathClip()
 -     {
 -         popClips();
 - 
 -         if (shouldClipComplex)
 -         {
 -             complexClipGeometry = nullptr;
 -             shouldClipComplex = false;
 -         }
 -     }
 - 
 -     void Direct2DLowLevelGraphicsContext::SavedState::clipToPath (ID2D1Geometry* geometry)
 -     {
 -         clearPathClip();
 - 
 -         if (complexClipLayer == nullptr)
 -             owner.pimpl->renderingTarget->CreateLayer (complexClipLayer.resetAndGetPointerAddress());
 - 
 -         complexClipGeometry = geometry;
 -         shouldClipComplex = true;
 -         pushClips();
 -     }
 - 
 -     void clearRectListClip()
 -     {
 -         popClips();
 - 
 -         if (shouldClipRectList)
 -         {
 -             rectListGeometry = nullptr;
 -             shouldClipRectList = false;
 -         }
 -     }
 - 
 -     void clipToRectList (ID2D1Geometry* geometry)
 -     {
 -         clearRectListClip();
 - 
 -         if (rectListLayer == nullptr)
 -             owner.pimpl->renderingTarget->CreateLayer (rectListLayer.resetAndGetPointerAddress());
 - 
 -         rectListGeometry = geometry;
 -         shouldClipRectList = true;
 -         pushClips();
 -     }
 - 
 -     void clearImageClip()
 -     {
 -         popClips();
 - 
 -         if (shouldClipBitmap)
 -         {
 -             maskBitmap = nullptr;
 -             bitmapMaskBrush = nullptr;
 -             shouldClipBitmap = false;
 -         }
 -     }
 - 
 -     void clipToImage (const Image& clipImage, const AffineTransform& clipTransform)
 -     {
 -         clearImageClip();
 - 
 -         if (bitmapMaskLayer == nullptr)
 -             owner.pimpl->renderingTarget->CreateLayer (bitmapMaskLayer.resetAndGetPointerAddress());
 - 
 -         D2D1_BRUSH_PROPERTIES brushProps = { 1, transformToMatrix (clipTransform) };
 -         auto bmProps = D2D1::BitmapBrushProperties (D2D1_EXTEND_MODE_WRAP, D2D1_EXTEND_MODE_WRAP);
 -         D2D1_SIZE_U size = { (UINT32) clipImage.getWidth(), (UINT32) clipImage.getHeight() };
 -         auto bp = D2D1::BitmapProperties();
 - 
 -         maskImage = clipImage.convertedToFormat (Image::ARGB);
 -         Image::BitmapData bd (maskImage, Image::BitmapData::readOnly); // xxx should be maskImage?
 -         bp.pixelFormat = owner.pimpl->renderingTarget->GetPixelFormat();
 -         bp.pixelFormat.alphaMode = D2D1_ALPHA_MODE_PREMULTIPLIED;
 - 
 -         auto hr = owner.pimpl->renderingTarget->CreateBitmap (size, bd.data, bd.lineStride, bp, maskBitmap.resetAndGetPointerAddress());
 -         hr = owner.pimpl->renderingTarget->CreateBitmapBrush (maskBitmap, bmProps, brushProps, bitmapMaskBrush.resetAndGetPointerAddress());
 - 
 -         imageMaskLayerParams = D2D1::LayerParameters();
 -         imageMaskLayerParams.opacityBrush = bitmapMaskBrush;
 - 
 -         shouldClipBitmap = true;
 -         pushClips();
 -     }
 - 
 -     void popClips()
 -     {
 -         if (clipsBitmap)
 -         {
 -             owner.pimpl->renderingTarget->PopLayer();
 -             clipsBitmap = false;
 -         }
 - 
 -         if (clipsComplex)
 -         {
 -             owner.pimpl->renderingTarget->PopLayer();
 -             clipsComplex = false;
 -         }
 - 
 -         if (clipsRectList)
 -         {
 -             owner.pimpl->renderingTarget->PopLayer();
 -             clipsRectList = false;
 -         }
 - 
 -         if (clipsRect)
 -         {
 -             owner.pimpl->renderingTarget->PopAxisAlignedClip();
 -             clipsRect = false;
 -         }
 -     }
 - 
 -     void pushClips()
 -     {
 -         if (shouldClipRect && !clipsRect)
 -         {
 -             owner.pimpl->renderingTarget->PushAxisAlignedClip (rectangleToRectF (clipRect), D2D1_ANTIALIAS_MODE_PER_PRIMITIVE);
 -             clipsRect = true;
 -         }
 - 
 -         if (shouldClipRectList && !clipsRectList)
 -         {
 -             auto layerParams = D2D1::LayerParameters();
 -             rectListGeometry->GetBounds (D2D1::IdentityMatrix(), &layerParams.contentBounds);
 -             layerParams.geometricMask = rectListGeometry;
 -             owner.pimpl->renderingTarget->PushLayer (layerParams, rectListLayer);
 -             clipsRectList = true;
 -         }
 - 
 -         if (shouldClipComplex && !clipsComplex)
 -         {
 -             auto layerParams = D2D1::LayerParameters();
 -             complexClipGeometry->GetBounds (D2D1::IdentityMatrix(), &layerParams.contentBounds);
 -             layerParams.geometricMask = complexClipGeometry;
 -             owner.pimpl->renderingTarget->PushLayer (layerParams, complexClipLayer);
 -             clipsComplex = true;
 -         }
 - 
 -         if (shouldClipBitmap && !clipsBitmap)
 -         {
 -             owner.pimpl->renderingTarget->PushLayer (imageMaskLayerParams, bitmapMaskLayer);
 -             clipsBitmap = true;
 -         }
 -     }
 - 
 -     void setFill (const FillType& newFillType)
 -     {
 -         if (fillType != newFillType)
 -         {
 -             fillType = newFillType;
 -             clearFill();
 -         }
 -     }
 - 
 -     void clearFont()
 -     {
 -         currentFontFace = localFontFace = nullptr;
 -     }
 - 
 -     void setFont (const Font& newFont)
 -     {
 -         if (font != newFont)
 -         {
 -             font = newFont;
 -             clearFont();
 -         }
 -     }
 - 
 -     void createFont()
 -     {
 -         if (currentFontFace == nullptr)
 -         {
 -             auto typefacePtr = font.getTypefacePtr();
 -             auto* typeface = dynamic_cast<WindowsDirectWriteTypeface*> (typefacePtr.get());
 -             currentFontFace = typeface->getIDWriteFontFace();
 -             fontHeightToEmSizeFactor = typeface->getUnitsToHeightScaleFactor();
 -         }
 -     }
 - 
 -     void setOpacity (float newOpacity)
 -     {
 -         fillType.setOpacity (newOpacity);
 - 
 -         if (currentBrush != nullptr)
 -             currentBrush->SetOpacity (newOpacity);
 -     }
 - 
 -     void clearFill()
 -     {
 -         gradientStops = nullptr;
 -         linearGradient = nullptr;
 -         radialGradient = nullptr;
 -         bitmap = nullptr;
 -         bitmapBrush = nullptr;
 -         currentBrush = nullptr;
 -     }
 - 
 -     void createBrush()
 -     {
 -         if (currentBrush == nullptr)
 -         {
 -             if (fillType.isColour())
 -             {
 -                 auto colour = colourToD2D (fillType.colour);
 -                 owner.pimpl->colourBrush->SetColor (colour);
 -                 currentBrush = owner.pimpl->colourBrush;
 -             }
 -             else if (fillType.isTiledImage())
 -             {
 -                 D2D1_BRUSH_PROPERTIES brushProps = { fillType.getOpacity(), transformToMatrix (fillType.transform) };
 -                 auto bmProps = D2D1::BitmapBrushProperties (D2D1_EXTEND_MODE_WRAP, D2D1_EXTEND_MODE_WRAP);
 - 
 -                 image = fillType.image;
 - 
 -                 D2D1_SIZE_U size = { (UINT32) image.getWidth(), (UINT32) image.getHeight() };
 -                 auto bp = D2D1::BitmapProperties();
 - 
 -                 this->image = image.convertedToFormat (Image::ARGB);
 -                 Image::BitmapData bd (this->image, Image::BitmapData::readOnly);
 -                 bp.pixelFormat = owner.pimpl->renderingTarget->GetPixelFormat();
 -                 bp.pixelFormat.alphaMode = D2D1_ALPHA_MODE_PREMULTIPLIED;
 - 
 -                 auto hr = owner.pimpl->renderingTarget->CreateBitmap (size, bd.data, bd.lineStride, bp, bitmap.resetAndGetPointerAddress());
 -                 hr = owner.pimpl->renderingTarget->CreateBitmapBrush (bitmap, bmProps, brushProps, bitmapBrush.resetAndGetPointerAddress());
 - 
 -                 currentBrush = bitmapBrush;
 -             }
 -             else if (fillType.isGradient())
 -             {
 -                 gradientStops = nullptr;
 - 
 -                 D2D1_BRUSH_PROPERTIES brushProps = { fillType.getOpacity(), transformToMatrix (fillType.transform.followedBy (transform)) };
 - 
 -                 const int numColors = fillType.gradient->getNumColours();
 - 
 -                 HeapBlock<D2D1_GRADIENT_STOP> stops (numColors);
 - 
 -                 for (int i = fillType.gradient->getNumColours(); --i >= 0;)
 -                 {
 -                     stops[i].color = colourToD2D (fillType.gradient->getColour (i));
 -                     stops[i].position = (FLOAT) fillType.gradient->getColourPosition (i);
 -                 }
 - 
 -                 owner.pimpl->renderingTarget->CreateGradientStopCollection (stops.getData(), numColors, gradientStops.resetAndGetPointerAddress());
 - 
 -                 if (fillType.gradient->isRadial)
 -                 {
 -                     radialGradient = nullptr;
 - 
 -                     const auto p1 = fillType.gradient->point1;
 -                     const auto p2 = fillType.gradient->point2;
 -                     const auto r = p1.getDistanceFrom (p2);
 -                     const auto props = D2D1::RadialGradientBrushProperties ({ p1.x, p1.y }, {}, r, r);
 - 
 -                     owner.pimpl->renderingTarget->CreateRadialGradientBrush (props, brushProps, gradientStops, radialGradient.resetAndGetPointerAddress());
 -                     currentBrush = radialGradient;
 -                 }
 -                 else
 -                 {
 -                     linearGradient = 0;
 - 
 -                     const auto p1 = fillType.gradient->point1;
 -                     const auto p2 = fillType.gradient->point2;
 -                     const auto props = D2D1::LinearGradientBrushProperties ({ p1.x, p1.y }, { p2.x, p2.y });
 - 
 -                     owner.pimpl->renderingTarget->CreateLinearGradientBrush (props, brushProps, gradientStops, linearGradient.resetAndGetPointerAddress());
 - 
 -                     currentBrush = linearGradient;
 -                 }
 -             }
 -         }
 -     }
 - 
 -     Direct2DLowLevelGraphicsContext& owner;
 - 
 -     AffineTransform transform;
 - 
 -     Font font;
 -     float fontHeightToEmSizeFactor = 1.0f;
 - 
 -     IDWriteFontFace* currentFontFace = nullptr;
 -     ComSmartPtr<IDWriteFontFace> localFontFace;
 - 
 -     Rectangle<int> clipRect;
 -     bool clipsRect = false, shouldClipRect = false;
 - 
 -     Image image;
 -     ComSmartPtr<ID2D1Bitmap> bitmap; // xxx needs a better name - what is this for??
 -     bool clipsBitmap = false, shouldClipBitmap = false;
 - 
 -     ComSmartPtr<ID2D1Geometry> complexClipGeometry;
 -     D2D1_LAYER_PARAMETERS complexClipLayerParams;
 -     ComSmartPtr<ID2D1Layer> complexClipLayer;
 -     bool clipsComplex = false, shouldClipComplex = false;
 - 
 -     ComSmartPtr<ID2D1Geometry> rectListGeometry;
 -     D2D1_LAYER_PARAMETERS rectListLayerParams;
 -     ComSmartPtr<ID2D1Layer> rectListLayer;
 -     bool clipsRectList = false, shouldClipRectList = false;
 - 
 -     Image maskImage;
 -     D2D1_LAYER_PARAMETERS imageMaskLayerParams;
 -     ComSmartPtr<ID2D1Layer> bitmapMaskLayer;
 -     ComSmartPtr<ID2D1Bitmap> maskBitmap;
 -     ComSmartPtr<ID2D1BitmapBrush> bitmapMaskBrush;
 - 
 -     ID2D1Brush* currentBrush = nullptr;
 -     ComSmartPtr<ID2D1BitmapBrush> bitmapBrush;
 -     ComSmartPtr<ID2D1LinearGradientBrush> linearGradient;
 -     ComSmartPtr<ID2D1RadialGradientBrush> radialGradient;
 -     ComSmartPtr<ID2D1GradientStopCollection> gradientStops;
 - 
 -     FillType fillType;
 - 
 -     JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SavedState)
 - };
 - 
 - //==============================================================================
 - Direct2DLowLevelGraphicsContext::Direct2DLowLevelGraphicsContext (HWND hwnd_)
 -     : hwnd (hwnd_),
 -       currentState (nullptr),
 -       pimpl (new Pimpl())
 - {
 -     RECT windowRect;
 -     GetClientRect (hwnd, &windowRect);
 -     D2D1_SIZE_U size = { (UINT32) (windowRect.right - windowRect.left), (UINT32) (windowRect.bottom - windowRect.top) };
 -     bounds.setSize (size.width, size.height);
 - 
 -     if (pimpl->factories->d2dFactory != nullptr)
 -     {
 -         [[maybe_unused]] auto hr = pimpl->factories->d2dFactory->CreateHwndRenderTarget ({}, { hwnd, size }, pimpl->renderingTarget.resetAndGetPointerAddress());
 -         jassert (SUCCEEDED (hr));
 -         hr = pimpl->renderingTarget->CreateSolidColorBrush (D2D1::ColorF::ColorF (0.0f, 0.0f, 0.0f, 1.0f), pimpl->colourBrush.resetAndGetPointerAddress());
 -     }
 - }
 - 
 - Direct2DLowLevelGraphicsContext::~Direct2DLowLevelGraphicsContext()
 - {
 -     states.clear();
 - }
 - 
 - void Direct2DLowLevelGraphicsContext::resized()
 - {
 -     RECT windowRect;
 -     GetClientRect (hwnd, &windowRect);
 -     D2D1_SIZE_U size = { (UINT32) (windowRect.right - windowRect.left), (UINT32) (windowRect.bottom - windowRect.top) };
 - 
 -     pimpl->renderingTarget->Resize (size);
 -     bounds.setSize (size.width, size.height);
 - }
 - 
 - void Direct2DLowLevelGraphicsContext::clear()
 - {
 -     pimpl->renderingTarget->Clear (D2D1::ColorF (D2D1::ColorF::White, 0.0f)); // xxx why white and not black?
 - }
 - 
 - void Direct2DLowLevelGraphicsContext::start()
 - {
 -     pimpl->renderingTarget->BeginDraw();
 -     saveState();
 - }
 - 
 - void Direct2DLowLevelGraphicsContext::end()
 - {
 -     states.clear();
 -     currentState = nullptr;
 -     pimpl->renderingTarget->EndDraw();
 -     pimpl->renderingTarget->CheckWindowState();
 - }
 - 
 - void Direct2DLowLevelGraphicsContext::setOrigin (Point<int> o)
 - {
 -     addTransform (AffineTransform::translation ((float) o.x, (float) o.y));
 - }
 - 
 - void Direct2DLowLevelGraphicsContext::addTransform (const AffineTransform& transform)
 - {
 -     currentState->transform = transform.followedBy (currentState->transform);
 - }
 - 
 - float Direct2DLowLevelGraphicsContext::getPhysicalPixelScaleFactor()
 - {
 -     return std::sqrt (std::abs (currentState->transform.getDeterminant()));
 - }
 - 
 - bool Direct2DLowLevelGraphicsContext::clipToRectangle (const Rectangle<int>& r)
 - {
 -     currentState->clipToRectangle (r);
 -     return ! isClipEmpty();
 - }
 - 
 - bool Direct2DLowLevelGraphicsContext::clipToRectangleList (const RectangleList<int>& clipRegion)
 - {
 -     currentState->clipToRectList (pimpl->rectListToPathGeometry (clipRegion));
 -     return ! isClipEmpty();
 - }
 - 
 - void Direct2DLowLevelGraphicsContext::excludeClipRectangle (const Rectangle<int>&)
 - {
 -     //xxx
 - }
 - 
 - void Direct2DLowLevelGraphicsContext::clipToPath (const Path& path, const AffineTransform& transform)
 - {
 -     currentState->clipToPath (pimpl->pathToPathGeometry (path, transform));
 - }
 - 
 - void Direct2DLowLevelGraphicsContext::clipToImageAlpha (const Image& sourceImage, const AffineTransform& transform)
 - {
 -     currentState->clipToImage (sourceImage, transform);
 - }
 - 
 - bool Direct2DLowLevelGraphicsContext::clipRegionIntersects (const Rectangle<int>& r)
 - {
 -     return currentState->clipRect.intersects (r.toFloat().transformedBy (currentState->transform).getSmallestIntegerContainer());
 - }
 - 
 - Rectangle<int> Direct2DLowLevelGraphicsContext::getClipBounds() const
 - {
 -     // xxx could this take into account complex clip regions?
 -     return currentState->clipRect.toFloat().transformedBy (currentState->transform.inverted()).getSmallestIntegerContainer();
 - }
 - 
 - bool Direct2DLowLevelGraphicsContext::isClipEmpty() const
 - {
 -     return currentState->clipRect.isEmpty();
 - }
 - 
 - void Direct2DLowLevelGraphicsContext::saveState()
 - {
 -     states.add (new SavedState (*this));
 -     currentState = states.getLast();
 - }
 - 
 - void Direct2DLowLevelGraphicsContext::restoreState()
 - {
 -     jassert (states.size() > 1); //you should never pop the last state!
 -     states.removeLast (1);
 -     currentState = states.getLast();
 - }
 - 
 - void Direct2DLowLevelGraphicsContext::beginTransparencyLayer (float /*opacity*/)
 - {
 -     jassertfalse; //xxx todo
 - }
 - 
 - void Direct2DLowLevelGraphicsContext::endTransparencyLayer()
 - {
 -     jassertfalse; //xxx todo
 - }
 - 
 - void Direct2DLowLevelGraphicsContext::setFill (const FillType& fillType)
 - {
 -     currentState->setFill (fillType);
 - }
 - 
 - void Direct2DLowLevelGraphicsContext::setOpacity (float newOpacity)
 - {
 -     currentState->setOpacity (newOpacity);
 - }
 - 
 - void Direct2DLowLevelGraphicsContext::setInterpolationQuality (Graphics::ResamplingQuality /*quality*/)
 - {
 - }
 - 
 - void Direct2DLowLevelGraphicsContext::fillRect (const Rectangle<int>& r, bool /*replaceExistingContents*/)
 - {
 -     fillRect (r.toFloat());
 - }
 - 
 - void Direct2DLowLevelGraphicsContext::fillRect (const Rectangle<float>& r)
 - {
 -     pimpl->renderingTarget->SetTransform (transformToMatrix (currentState->transform));
 -     currentState->createBrush();
 -     pimpl->renderingTarget->FillRectangle (rectangleToRectF (r), currentState->currentBrush);
 -     pimpl->renderingTarget->SetTransform (D2D1::IdentityMatrix());
 - }
 - 
 - void Direct2DLowLevelGraphicsContext::fillRectList (const RectangleList<float>& list)
 - {
 -     for (auto& r : list)
 -         fillRect (r);
 - }
 - 
 - void Direct2DLowLevelGraphicsContext::fillPath (const Path& p, const AffineTransform& transform)
 - {
 -     currentState->createBrush();
 -     ComSmartPtr<ID2D1Geometry> geometry (pimpl->pathToPathGeometry (p, transform.followedBy (currentState->transform)));
 - 
 -     if (pimpl->renderingTarget != nullptr)
 -         pimpl->renderingTarget->FillGeometry (geometry, currentState->currentBrush);
 - }
 - 
 - void Direct2DLowLevelGraphicsContext::drawImage (const Image& image, const AffineTransform& transform)
 - {
 -     pimpl->renderingTarget->SetTransform (transformToMatrix (transform.followedBy (currentState->transform)));
 - 
 -     D2D1_SIZE_U size = { (UINT32) image.getWidth(), (UINT32) image.getHeight() };
 -     auto bp = D2D1::BitmapProperties();
 - 
 -     Image img (image.convertedToFormat (Image::ARGB));
 -     Image::BitmapData bd (img, Image::BitmapData::readOnly);
 -     bp.pixelFormat = pimpl->renderingTarget->GetPixelFormat();
 -     bp.pixelFormat.alphaMode = D2D1_ALPHA_MODE_PREMULTIPLIED;
 - 
 -     {
 -         ComSmartPtr<ID2D1Bitmap> tempBitmap;
 -         pimpl->renderingTarget->CreateBitmap (size, bd.data, bd.lineStride, bp, tempBitmap.resetAndGetPointerAddress());
 -         if (tempBitmap != nullptr)
 -             pimpl->renderingTarget->DrawBitmap (tempBitmap);
 -     }
 - 
 -     pimpl->renderingTarget->SetTransform (D2D1::IdentityMatrix());
 - }
 - 
 - void Direct2DLowLevelGraphicsContext::drawLine (const Line<float>& line)
 - {
 -     // xxx doesn't seem to be correctly aligned, may need nudging by 0.5 to match the software renderer's behaviour
 -     pimpl->renderingTarget->SetTransform (transformToMatrix (currentState->transform));
 -     currentState->createBrush();
 - 
 -     pimpl->renderingTarget->DrawLine (D2D1::Point2F (line.getStartX(), line.getStartY()),
 -                                       D2D1::Point2F (line.getEndX(), line.getEndY()),
 -                                       currentState->currentBrush);
 -     pimpl->renderingTarget->SetTransform (D2D1::IdentityMatrix());
 - }
 - 
 - void Direct2DLowLevelGraphicsContext::setFont (const Font& newFont)
 - {
 -     currentState->setFont (newFont);
 - }
 - 
 - const Font& Direct2DLowLevelGraphicsContext::getFont()
 - {
 -     return currentState->font;
 - }
 - 
 - void Direct2DLowLevelGraphicsContext::drawGlyph (int glyphNumber, const AffineTransform& transform)
 - {
 -     currentState->createBrush();
 -     currentState->createFont();
 - 
 -     auto hScale = currentState->font.getHorizontalScale();
 - 
 -     pimpl->renderingTarget->SetTransform (transformToMatrix (AffineTransform::scale (hScale, 1.0f)
 -                                                                              .followedBy (transform)
 -                                                                              .followedBy (currentState->transform)));
 - 
 -     const auto glyphIndices = (UINT16) glyphNumber;
 -     const auto glyphAdvances = 0.0f;
 -     DWRITE_GLYPH_OFFSET offset = { 0.0f, 0.0f };
 - 
 -     DWRITE_GLYPH_RUN glyphRun;
 -     glyphRun.fontFace = currentState->currentFontFace;
 -     glyphRun.fontEmSize = (FLOAT) (currentState->font.getHeight() * currentState->fontHeightToEmSizeFactor);
 -     glyphRun.glyphCount = 1;
 -     glyphRun.glyphIndices = &glyphIndices;
 -     glyphRun.glyphAdvances = &glyphAdvances;
 -     glyphRun.glyphOffsets = &offset;
 -     glyphRun.isSideways = FALSE;
 -     glyphRun.bidiLevel = 0;
 - 
 -     pimpl->renderingTarget->DrawGlyphRun ({}, &glyphRun, currentState->currentBrush);
 -     pimpl->renderingTarget->SetTransform (D2D1::IdentityMatrix());
 - }
 - 
 - bool Direct2DLowLevelGraphicsContext::drawTextLayout (const AttributedString& text, const Rectangle<float>& area)
 - {
 -     pimpl->renderingTarget->SetTransform (transformToMatrix (currentState->transform));
 - 
 -     DirectWriteTypeLayout::drawToD2DContext (text, area,
 -                                              *(pimpl->renderingTarget),
 -                                              *(pimpl->factories->directWriteFactory),
 -                                              *(pimpl->factories->systemFonts));
 - 
 -     pimpl->renderingTarget->SetTransform (D2D1::IdentityMatrix());
 -     return true;
 - }
 - 
 - } // namespace juce
 
 
  |