void createLayout (TextLayout& layout, const AttributedString& text, IDWriteFactory& directWriteFactory, ID2D1Factory& direct2dFactory, IDWriteFontCollection& fontCollection) { // To add color to text, we need to create a D2D render target // Since we are not actually rendering to a D2D context we create a temporary GDI render target D2D1_RENDER_TARGET_PROPERTIES d2dRTProp = D2D1::RenderTargetProperties (D2D1_RENDER_TARGET_TYPE_SOFTWARE, D2D1::PixelFormat (DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_IGNORE), 0, 0, D2D1_RENDER_TARGET_USAGE_GDI_COMPATIBLE, D2D1_FEATURE_LEVEL_DEFAULT); ComSmartPtr<ID2D1DCRenderTarget> renderTarget; HRESULT hr = direct2dFactory.CreateDCRenderTarget (&d2dRTProp, renderTarget.resetAndGetPointerAddress()); ComSmartPtr<IDWriteTextLayout> dwTextLayout; if (! setupLayout (text, layout.getWidth(), layout.getHeight(), *renderTarget, directWriteFactory, fontCollection, dwTextLayout)) return; UINT32 actualLineCount = 0; hr = dwTextLayout->GetLineMetrics (nullptr, 0, &actualLineCount); layout.ensureStorageAllocated (actualLineCount); { ComSmartPtr<CustomDirectWriteTextRenderer> textRenderer (new CustomDirectWriteTextRenderer (fontCollection, text)); hr = dwTextLayout->Draw (&layout, textRenderer, 0, 0); } HeapBlock<DWRITE_LINE_METRICS> dwLineMetrics (actualLineCount); 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) { 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 createLayout (TextLayout& layout, const AttributedString& text, IDWriteFactory& directWriteFactory, IDWriteFontCollection& fontCollection, ID2D1DCRenderTarget& renderTarget) { ComSmartPtr<IDWriteTextLayout> dwTextLayout; if (! setupLayout (text, layout.getWidth(), layout.getHeight(), renderTarget, directWriteFactory, fontCollection, dwTextLayout)) return; UINT32 actualLineCount = 0; HRESULT hr = dwTextLayout->GetLineMetrics (nullptr, 0, &actualLineCount); layout.ensureStorageAllocated (actualLineCount); { ComSmartPtr<CustomDirectWriteTextRenderer> textRenderer (new CustomDirectWriteTextRenderer (fontCollection, text)); hr = dwTextLayout->Draw (&layout, textRenderer, 0, 0); } HeapBlock<DWRITE_LINE_METRICS> dwLineMetrics (actualLineCount); 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) { 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 createLayout (const AttributedString& text, TextLayout& layout) { tokens.ensureStorageAllocated (64); layout.ensureStorageAllocated (totalLines); addTextRuns (text); layoutRuns ((int) layout.getWidth()); int charPosition = 0; int lineStartPosition = 0; int runStartPosition = 0; TextLayout::Line* glyphLine = new TextLayout::Line(); TextLayout::Run* glyphRun = new TextLayout::Run(); for (int i = 0; i < tokens.size(); ++i) { const Token* const t = tokens.getUnchecked (i); const Point<float> tokenPos (t->area.getPosition().toFloat()); Array <int> newGlyphs; Array <float> xOffsets; t->font.getGlyphPositions (t->text.trimEnd(), newGlyphs, xOffsets); glyphRun->glyphs.ensureStorageAllocated (glyphRun->glyphs.size() + newGlyphs.size()); for (int j = 0; j < newGlyphs.size(); ++j) { if (charPosition == lineStartPosition) glyphLine->lineOrigin = tokenPos.translated (0, t->font.getAscent()); const float x = xOffsets.getUnchecked (j); glyphRun->glyphs.add (TextLayout::Glyph (newGlyphs.getUnchecked(j), Point<float> (tokenPos.getX() + x, 0), xOffsets.getUnchecked (j + 1) - x)); ++charPosition; } if (t->isWhitespace || t->isNewLine) ++charPosition; const Token* const nextToken = tokens [i + 1]; if (nextToken == nullptr) // this is the last token { addRun (glyphLine, glyphRun, t, runStartPosition, charPosition); glyphLine->stringRange = Range<int> (lineStartPosition, charPosition); layout.addLine (glyphLine); } else { if (t->font != nextToken->font || t->colour != nextToken->colour) { addRun (glyphLine, glyphRun, t, runStartPosition, charPosition); runStartPosition = charPosition; glyphRun = new TextLayout::Run(); } if (t->line != nextToken->line) { addRun (glyphLine, glyphRun, t, runStartPosition, charPosition); glyphLine->stringRange = Range<int> (lineStartPosition, charPosition); layout.addLine (glyphLine); runStartPosition = charPosition; lineStartPosition = charPosition; glyphLine = new TextLayout::Line(); glyphRun = new TextLayout::Run(); } } } if ((text.getJustification().getFlags() & (Justification::right | Justification::horizontallyCentred)) != 0) { const int totalW = (int) layout.getWidth(); for (int i = 0; i < totalLines; ++i) { const int lineW = getLineWidth (i); float dx = 0; if ((text.getJustification().getFlags() & Justification::right) != 0) dx = (float) (totalW - lineW); else dx = (totalW - lineW) / 2.0f; TextLayout::Line& glyphLine = layout.getLine (i); glyphLine.lineOrigin.x += dx; } } }
void createLayout (TextLayout& layout, const AttributedString& text, IDWriteFactory* const directWriteFactory, ID2D1Factory* const direct2dFactory, IDWriteFontCollection* const fontCollection) { // To add color to text, we need to create a D2D render target // Since we are not actually rendering to a D2D context we create a temporary GDI render target D2D1_RENDER_TARGET_PROPERTIES d2dRTProp = D2D1::RenderTargetProperties (D2D1_RENDER_TARGET_TYPE_SOFTWARE, D2D1::PixelFormat (DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_IGNORE), 0, 0, D2D1_RENDER_TARGET_USAGE_GDI_COMPATIBLE, D2D1_FEATURE_LEVEL_DEFAULT); ComSmartPtr<ID2D1DCRenderTarget> renderTarget; HRESULT hr = direct2dFactory->CreateDCRenderTarget (&d2dRTProp, renderTarget.resetAndGetPointerAddress()); Font defaultFont; BOOL fontFound = false; uint32 fontIndex; fontCollection->FindFamilyName (defaultFont.getTypefaceName().toWideCharPointer(), &fontIndex, &fontFound); if (! fontFound) fontIndex = 0; ComSmartPtr<IDWriteFontFamily> dwFontFamily; hr = fontCollection->GetFontFamily (fontIndex, dwFontFamily.resetAndGetPointerAddress()); ComSmartPtr<IDWriteFont> dwFont; hr = dwFontFamily->GetFirstMatchingFont (DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, dwFont.resetAndGetPointerAddress()); const float defaultFontHeightToEmSizeFactor = getFontHeightToEmSizeFactor (dwFont); jassert (directWriteFactory != nullptr); ComSmartPtr<IDWriteTextFormat> dwTextFormat; hr = directWriteFactory->CreateTextFormat (defaultFont.getTypefaceName().toWideCharPointer(), fontCollection, DWRITE_FONT_WEIGHT_REGULAR, DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, defaultFont.getHeight() * defaultFontHeightToEmSizeFactor, L"en-us", dwTextFormat.resetAndGetPointerAddress()); setTextFormatProperties (text, dwTextFormat); const int textLen = text.getText().length(); ComSmartPtr<IDWriteTextLayout> dwTextLayout; hr = directWriteFactory->CreateTextLayout (text.getText().toWideCharPointer(), textLen, dwTextFormat, layout.getWidth(), 1.0e7f, dwTextLayout.resetAndGetPointerAddress()); const int numAttributes = text.getNumAttributes(); for (int i = 0; i < numAttributes; ++i) addAttributedRange (*text.getAttribute (i), dwTextLayout, textLen, renderTarget, fontCollection); UINT32 actualLineCount = 0; hr = dwTextLayout->GetLineMetrics (nullptr, 0, &actualLineCount); layout.ensureStorageAllocated (actualLineCount); { ComSmartPtr<CustomDirectWriteTextRenderer> textRenderer (new CustomDirectWriteTextRenderer (fontCollection)); hr = dwTextLayout->Draw (&layout, textRenderer, 0, 0); } HeapBlock <DWRITE_LINE_METRICS> dwLineMetrics (actualLineCount); hr = dwTextLayout->GetLineMetrics (dwLineMetrics, actualLineCount, &actualLineCount); int lastLocation = 0; const int numLines = jmin ((int) actualLineCount, layout.getNumLines()); for (int i = 0; i < numLines; ++i) { lastLocation = dwLineMetrics[i].length; layout.getLine(i).stringRange = Range<int> (lastLocation, (int) lastLocation + dwLineMetrics[i].length); } }