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;
        }
    }
Ejemplo n.º 3
0
        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);
        }
    }