mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-11 23:54:18 +00:00
TextLayout: added support for using the AttributedString::getLineSpacing value in DirectWrite
This commit is contained in:
parent
6fcde1eccc
commit
d833ab5e33
2 changed files with 56 additions and 51 deletions
|
|
@ -198,7 +198,7 @@ public:
|
|||
void fillPath (const Path& p, const AffineTransform& transform)
|
||||
{
|
||||
currentState->createBrush();
|
||||
ComSmartPtr <ID2D1Geometry> geometry (pathToPathGeometry (p, transform.followedBy (currentState->transform)));
|
||||
ComSmartPtr<ID2D1Geometry> geometry (pathToPathGeometry (p, transform.followedBy (currentState->transform)));
|
||||
|
||||
if (renderingTarget != nullptr)
|
||||
renderingTarget->FillGeometry (geometry, currentState->currentBrush);
|
||||
|
|
@ -220,7 +220,7 @@ public:
|
|||
bp.pixelFormat.alphaMode = D2D1_ALPHA_MODE_PREMULTIPLIED;
|
||||
|
||||
{
|
||||
ComSmartPtr <ID2D1Bitmap> tempBitmap;
|
||||
ComSmartPtr<ID2D1Bitmap> tempBitmap;
|
||||
renderingTarget->CreateBitmap (size, bd.data, bd.lineStride, bp, tempBitmap.resetAndGetPointerAddress());
|
||||
if (tempBitmap != nullptr)
|
||||
renderingTarget->DrawBitmap (tempBitmap);
|
||||
|
|
@ -286,7 +286,7 @@ public:
|
|||
{
|
||||
renderingTarget->SetTransform (transformToMatrix (currentState->transform));
|
||||
|
||||
DirectWriteTypeLayout::drawToD2DContext (text, area, renderingTarget, factories->directWriteFactory,
|
||||
DirectWriteTypeLayout::drawToD2DContext (text, area, *renderingTarget, factories->directWriteFactory,
|
||||
factories->d2dFactory, factories->systemFonts);
|
||||
|
||||
renderingTarget->SetTransform (D2D1::IdentityMatrix());
|
||||
|
|
@ -654,38 +654,38 @@ public:
|
|||
Font font;
|
||||
float fontHeightToEmSizeFactor;
|
||||
IDWriteFontFace* currentFontFace;
|
||||
ComSmartPtr <IDWriteFontFace> localFontFace;
|
||||
ComSmartPtr<IDWriteFontFace> localFontFace;
|
||||
|
||||
FillType fillType;
|
||||
|
||||
Image image;
|
||||
ComSmartPtr <ID2D1Bitmap> bitmap; // xxx needs a better name - what is this for??
|
||||
ComSmartPtr<ID2D1Bitmap> bitmap; // xxx needs a better name - what is this for??
|
||||
|
||||
Rectangle<int> clipRect;
|
||||
bool clipsRect, shouldClipRect;
|
||||
|
||||
ComSmartPtr <ID2D1Geometry> complexClipGeometry;
|
||||
ComSmartPtr<ID2D1Geometry> complexClipGeometry;
|
||||
D2D1_LAYER_PARAMETERS complexClipLayerParams;
|
||||
ComSmartPtr <ID2D1Layer> complexClipLayer;
|
||||
ComSmartPtr<ID2D1Layer> complexClipLayer;
|
||||
bool clipsComplex, shouldClipComplex;
|
||||
|
||||
ComSmartPtr <ID2D1Geometry> rectListGeometry;
|
||||
ComSmartPtr<ID2D1Geometry> rectListGeometry;
|
||||
D2D1_LAYER_PARAMETERS rectListLayerParams;
|
||||
ComSmartPtr <ID2D1Layer> rectListLayer;
|
||||
ComSmartPtr<ID2D1Layer> rectListLayer;
|
||||
bool clipsRectList, shouldClipRectList;
|
||||
|
||||
Image maskImage;
|
||||
D2D1_LAYER_PARAMETERS imageMaskLayerParams;
|
||||
ComSmartPtr <ID2D1Layer> bitmapMaskLayer;
|
||||
ComSmartPtr <ID2D1Bitmap> maskBitmap;
|
||||
ComSmartPtr <ID2D1BitmapBrush> bitmapMaskBrush;
|
||||
ComSmartPtr<ID2D1Layer> bitmapMaskLayer;
|
||||
ComSmartPtr<ID2D1Bitmap> maskBitmap;
|
||||
ComSmartPtr<ID2D1BitmapBrush> bitmapMaskBrush;
|
||||
bool clipsBitmap, shouldClipBitmap;
|
||||
|
||||
ID2D1Brush* currentBrush;
|
||||
ComSmartPtr <ID2D1BitmapBrush> bitmapBrush;
|
||||
ComSmartPtr <ID2D1LinearGradientBrush> linearGradient;
|
||||
ComSmartPtr <ID2D1RadialGradientBrush> radialGradient;
|
||||
ComSmartPtr <ID2D1GradientStopCollection> gradientStops;
|
||||
ComSmartPtr<ID2D1BitmapBrush> bitmapBrush;
|
||||
ComSmartPtr<ID2D1LinearGradientBrush> linearGradient;
|
||||
ComSmartPtr<ID2D1RadialGradientBrush> radialGradient;
|
||||
ComSmartPtr<ID2D1GradientStopCollection> gradientStops;
|
||||
|
||||
private:
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SavedState)
|
||||
|
|
@ -695,8 +695,8 @@ public:
|
|||
private:
|
||||
SharedResourcePointer<Direct2DFactories> factories;
|
||||
HWND hwnd;
|
||||
ComSmartPtr <ID2D1HwndRenderTarget> renderingTarget;
|
||||
ComSmartPtr <ID2D1SolidColorBrush> colourBrush;
|
||||
ComSmartPtr<ID2D1HwndRenderTarget> renderingTarget;
|
||||
ComSmartPtr<ID2D1SolidColorBrush> colourBrush;
|
||||
Rectangle<int> bounds;
|
||||
|
||||
SavedState* currentState;
|
||||
|
|
@ -734,7 +734,7 @@ private:
|
|||
ID2D1PathGeometry* p = nullptr;
|
||||
factories->d2dFactory->CreatePathGeometry (&p);
|
||||
|
||||
ComSmartPtr <ID2D1GeometrySink> sink;
|
||||
ComSmartPtr<ID2D1GeometrySink> sink;
|
||||
HRESULT hr = p->Open (sink.resetAndGetPointerAddress()); // xxx handle error
|
||||
sink->SetFillMode (D2D1_FILL_MODE_WINDING);
|
||||
|
||||
|
|
@ -812,7 +812,7 @@ private:
|
|||
ID2D1PathGeometry* p = nullptr;
|
||||
factories->d2dFactory->CreatePathGeometry (&p);
|
||||
|
||||
ComSmartPtr <ID2D1GeometrySink> sink;
|
||||
ComSmartPtr<ID2D1GeometrySink> sink;
|
||||
HRESULT hr = p->Open (sink.resetAndGetPointerAddress());
|
||||
sink->SetFillMode (D2D1_FILL_MODE_WINDING); // xxx need to check Path::isUsingNonZeroWinding()
|
||||
|
||||
|
|
|
|||
|
|
@ -125,7 +125,7 @@ namespace DirectWriteTypeLayout
|
|||
const float totalHeight = std::abs ((float) dwFontMetrics.ascent) + std::abs ((float) dwFontMetrics.descent);
|
||||
const float fontHeightToEmSizeFactor = (float) dwFontMetrics.designUnitsPerEm / totalHeight;
|
||||
|
||||
glyphRunLayout->font = getFontForRun (glyphRun, glyphRun->fontEmSize / fontHeightToEmSizeFactor);
|
||||
glyphRunLayout->font = getFontForRun (*glyphRun, glyphRun->fontEmSize / fontHeightToEmSizeFactor);
|
||||
glyphRunLayout->colour = getColourOf (static_cast<ID2D1SolidColorBrush*> (clientDrawingEffect));
|
||||
|
||||
const Point<float> lineOrigin (layout->getLine (currentLine).lineOrigin);
|
||||
|
|
@ -169,16 +169,16 @@ namespace DirectWriteTypeLayout
|
|||
return Colour::fromFloatRGBA (colour.r, colour.g, colour.b, colour.a);
|
||||
}
|
||||
|
||||
Font getFontForRun (DWRITE_GLYPH_RUN const* glyphRun, float fontHeight)
|
||||
Font getFontForRun (const DWRITE_GLYPH_RUN& glyphRun, float fontHeight)
|
||||
{
|
||||
for (int i = 0; i < attributedString.getNumAttributes(); ++i)
|
||||
if (const Font* font = attributedString.getAttribute(i)->getFont())
|
||||
if (WindowsDirectWriteTypeface* wt = dynamic_cast<WindowsDirectWriteTypeface*> (font->getTypeface()))
|
||||
if (wt->getIDWriteFontFace() == glyphRun->fontFace)
|
||||
if (wt->getIDWriteFontFace() == glyphRun.fontFace)
|
||||
return font->withHeight (fontHeight);
|
||||
|
||||
ComSmartPtr<IDWriteFont> dwFont;
|
||||
HRESULT hr = fontCollection.GetFontFromFontFace (glyphRun->fontFace, dwFont.resetAndGetPointerAddress());
|
||||
HRESULT hr = fontCollection.GetFontFromFontFace (glyphRun.fontFace, dwFont.resetAndGetPointerAddress());
|
||||
jassert (dwFont != nullptr);
|
||||
|
||||
ComSmartPtr<IDWriteFontFamily> dwFontFamily;
|
||||
|
|
@ -206,7 +206,7 @@ namespace DirectWriteTypeLayout
|
|||
return dwFontMetrics.designUnitsPerEm / totalHeight;
|
||||
}
|
||||
|
||||
void setTextFormatProperties (const AttributedString& text, IDWriteTextFormat* const format)
|
||||
void setTextFormatProperties (const AttributedString& text, IDWriteTextFormat& format)
|
||||
{
|
||||
DWRITE_TEXT_ALIGNMENT alignment = DWRITE_TEXT_ALIGNMENT_LEADING;
|
||||
DWRITE_WORD_WRAPPING wrapType = DWRITE_WORD_WRAPPING_WRAP;
|
||||
|
|
@ -232,7 +232,7 @@ namespace DirectWriteTypeLayout
|
|||
// This must be set correctly and manually when using RTL Scripts (Hebrew, Arabic)
|
||||
if (text.getReadingDirection() == AttributedString::rightToLeft)
|
||||
{
|
||||
format->SetReadingDirection (DWRITE_READING_DIRECTION_RIGHT_TO_LEFT);
|
||||
format.SetReadingDirection (DWRITE_READING_DIRECTION_RIGHT_TO_LEFT);
|
||||
|
||||
switch (text.getJustification().getOnlyHorizontalFlags())
|
||||
{
|
||||
|
|
@ -242,12 +242,12 @@ namespace DirectWriteTypeLayout
|
|||
}
|
||||
}
|
||||
|
||||
format->SetTextAlignment (alignment);
|
||||
format->SetWordWrapping (wrapType);
|
||||
format.SetTextAlignment (alignment);
|
||||
format.SetWordWrapping (wrapType);
|
||||
}
|
||||
|
||||
void addAttributedRange (const AttributedString::Attribute& attr, IDWriteTextLayout* textLayout,
|
||||
const int textLen, ID2D1RenderTarget* const renderTarget, IDWriteFontCollection& fontCollection)
|
||||
void addAttributedRange (const AttributedString::Attribute& attr, IDWriteTextLayout& textLayout,
|
||||
const int textLen, ID2D1RenderTarget& renderTarget, IDWriteFontCollection& fontCollection)
|
||||
{
|
||||
DWRITE_TEXT_RANGE range;
|
||||
range.startPosition = attr.range.getStart();
|
||||
|
|
@ -279,31 +279,31 @@ namespace DirectWriteTypeLayout
|
|||
break;
|
||||
}
|
||||
|
||||
textLayout->SetFontFamilyName (familyName.toWideCharPointer(), range);
|
||||
textLayout->SetFontWeight (dwFont->GetWeight(), range);
|
||||
textLayout->SetFontStretch (dwFont->GetStretch(), range);
|
||||
textLayout->SetFontStyle (dwFont->GetStyle(), range);
|
||||
textLayout.SetFontFamilyName (familyName.toWideCharPointer(), range);
|
||||
textLayout.SetFontWeight (dwFont->GetWeight(), range);
|
||||
textLayout.SetFontStretch (dwFont->GetStretch(), range);
|
||||
textLayout.SetFontStyle (dwFont->GetStyle(), range);
|
||||
|
||||
const float fontHeightToEmSizeFactor = getFontHeightToEmSizeFactor (*dwFont);
|
||||
textLayout->SetFontSize (font->getHeight() * fontHeightToEmSizeFactor, range);
|
||||
textLayout.SetFontSize (font->getHeight() * fontHeightToEmSizeFactor, range);
|
||||
}
|
||||
|
||||
if (const Colour* const colour = attr.getColour())
|
||||
{
|
||||
ComSmartPtr<ID2D1SolidColorBrush> d2dBrush;
|
||||
renderTarget->CreateSolidColorBrush (D2D1::ColorF (D2D1::ColorF (colour->getFloatRed(),
|
||||
colour->getFloatGreen(),
|
||||
colour->getFloatBlue(),
|
||||
colour->getFloatAlpha())),
|
||||
d2dBrush.resetAndGetPointerAddress());
|
||||
renderTarget.CreateSolidColorBrush (D2D1::ColorF (colour->getFloatRed(),
|
||||
colour->getFloatGreen(),
|
||||
colour->getFloatBlue(),
|
||||
colour->getFloatAlpha()),
|
||||
d2dBrush.resetAndGetPointerAddress());
|
||||
|
||||
// We need to call SetDrawingEffect with a legimate brush to get DirectWrite to break text based on colours
|
||||
textLayout->SetDrawingEffect (d2dBrush, range);
|
||||
textLayout.SetDrawingEffect (d2dBrush, range);
|
||||
}
|
||||
}
|
||||
|
||||
bool setupLayout (const AttributedString& text, const float maxWidth, const float maxHeight,
|
||||
ID2D1RenderTarget* const renderTarget, IDWriteFactory& directWriteFactory,
|
||||
ID2D1RenderTarget& renderTarget, IDWriteFactory& directWriteFactory,
|
||||
IDWriteFontCollection& fontCollection, ComSmartPtr<IDWriteTextLayout>& textLayout)
|
||||
{
|
||||
// To add color to text, we need to create a D2D render target
|
||||
|
|
@ -333,7 +333,7 @@ namespace DirectWriteTypeLayout
|
|||
defaultFont.getHeight() * defaultFontHeightToEmSizeFactor,
|
||||
L"en-us", dwTextFormat.resetAndGetPointerAddress());
|
||||
|
||||
setTextFormatProperties (text, dwTextFormat);
|
||||
setTextFormatProperties (text, *dwTextFormat);
|
||||
|
||||
{
|
||||
DWRITE_TRIMMING trimming = { DWRITE_TRIMMING_GRANULARITY_CHARACTER, 0, 0 };
|
||||
|
|
@ -353,7 +353,7 @@ namespace DirectWriteTypeLayout
|
|||
const int numAttributes = text.getNumAttributes();
|
||||
|
||||
for (int i = 0; i < numAttributes; ++i)
|
||||
addAttributedRange (*text.getAttribute (i), textLayout, textLen, renderTarget, fontCollection);
|
||||
addAttributedRange (*text.getAttribute (i), *textLayout, textLen, renderTarget, fontCollection);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -375,7 +375,7 @@ namespace DirectWriteTypeLayout
|
|||
|
||||
ComSmartPtr<IDWriteTextLayout> dwTextLayout;
|
||||
|
||||
if (! setupLayout (text, layout.getWidth(), layout.getHeight(), renderTarget,
|
||||
if (! setupLayout (text, layout.getWidth(), layout.getHeight(), *renderTarget,
|
||||
directWriteFactory, fontCollection, dwTextLayout))
|
||||
return;
|
||||
|
||||
|
|
@ -393,15 +393,20 @@ namespace DirectWriteTypeLayout
|
|||
hr = dwTextLayout->GetLineMetrics (dwLineMetrics, actualLineCount, &actualLineCount);
|
||||
int lastLocation = 0;
|
||||
const int numLines = jmin ((int) actualLineCount, layout.getNumLines());
|
||||
float yAdjustment = 0;
|
||||
const float extraLineSpacing = text.getLineSpacing();
|
||||
|
||||
for (int i = 0; i < numLines; ++i)
|
||||
{
|
||||
layout.getLine(i).stringRange = Range<int> (lastLocation, (int) lastLocation + dwLineMetrics[i].length);
|
||||
TextLayout::Line& line = layout.getLine (i);
|
||||
line.stringRange = Range<int> (lastLocation, (int) lastLocation + dwLineMetrics[i].length);
|
||||
line.lineOrigin.y += yAdjustment;
|
||||
yAdjustment += extraLineSpacing;
|
||||
lastLocation += dwLineMetrics[i].length;
|
||||
}
|
||||
}
|
||||
|
||||
void drawToD2DContext (const AttributedString& text, const Rectangle<float>& area, ID2D1RenderTarget* const renderTarget,
|
||||
void drawToD2DContext (const AttributedString& text, const Rectangle<float>& area, ID2D1RenderTarget& renderTarget,
|
||||
IDWriteFactory& directWriteFactory, IDWriteFontCollection& fontCollection)
|
||||
{
|
||||
ComSmartPtr<IDWriteTextLayout> dwTextLayout;
|
||||
|
|
@ -410,11 +415,11 @@ namespace DirectWriteTypeLayout
|
|||
directWriteFactory, fontCollection, dwTextLayout))
|
||||
{
|
||||
ComSmartPtr<ID2D1SolidColorBrush> d2dBrush;
|
||||
renderTarget->CreateSolidColorBrush (D2D1::ColorF (D2D1::ColorF (0.0f, 0.0f, 0.0f, 1.0f)),
|
||||
d2dBrush.resetAndGetPointerAddress());
|
||||
renderTarget.CreateSolidColorBrush (D2D1::ColorF (0.0f, 0.0f, 0.0f, 1.0f),
|
||||
d2dBrush.resetAndGetPointerAddress());
|
||||
|
||||
renderTarget->DrawTextLayout (D2D1::Point2F ((float) area.getX(), (float) area.getY()),
|
||||
dwTextLayout, d2dBrush, D2D1_DRAW_TEXT_OPTIONS_CLIP);
|
||||
renderTarget.DrawTextLayout (D2D1::Point2F ((float) area.getX(), (float) area.getY()),
|
||||
dwTextLayout, d2dBrush, D2D1_DRAW_TEXT_OPTIONS_CLIP);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue