|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780 |
- /*
- ==============================================================================
-
- 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)
- {
- auto hr = pimpl->factories->d2dFactory->CreateHwndRenderTarget ({}, { hwnd, size }, pimpl->renderingTarget.resetAndGetPointerAddress());
- jassert (SUCCEEDED (hr)); ignoreUnused (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
|