diff options
author | Caolán McNamara <caolanm@redhat.com> | 2020-09-07 19:53:02 +0100 |
---|---|---|
committer | Xisco Fauli <xiscofauli@libreoffice.org> | 2020-09-08 10:22:17 +0200 |
commit | ee18059ed6402eb0725048b3dd406852120a9faf (patch) | |
tree | 4cd998be7703475227b19508d2dfc0abc82f8a06 /canvas | |
parent | 72549d97c220d63d5fd5f6f38ae14f13c3e3d919 (diff) |
tdf#136545 revert cairo canvas uses cairo for text rendering already
This was the fallback path, so the problem must already exist in the uncommon
fallback case. I think I know the best approach to take, but for the 7-0 case
be conservative and restore the historic state.
this reverts 770892a387361067d23ab08ed38690c50b8b9395 and associated
code removal
Change-Id: I0e61d934e4dae03442ca5910f802199a1d3d53f4
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/102197
Tested-by: Jenkins
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
Diffstat (limited to 'canvas')
-rw-r--r-- | canvas/source/cairo/cairo_canvashelper_text.cxx | 4 | ||||
-rw-r--r-- | canvas/source/cairo/cairo_textlayout.cxx | 227 | ||||
-rw-r--r-- | canvas/source/cairo/cairo_textlayout.hxx | 5 |
3 files changed, 224 insertions, 12 deletions
diff --git a/canvas/source/cairo/cairo_canvashelper_text.cxx b/canvas/source/cairo/cairo_canvashelper_text.cxx index 830388775670..3b4d161417bd 100644 --- a/canvas/source/cairo/cairo_canvashelper_text.cxx +++ b/canvas/source/cairo/cairo_canvashelper_text.cxx @@ -254,7 +254,7 @@ namespace cairocanvas mpVirtualDevice->SetLayoutMode( nLayoutMode ); rtl::Reference pTextLayout( new TextLayout(text, textDirection, 0, CanvasFont::Reference(dynamic_cast< CanvasFont* >( xFont.get() )), mpSurfaceProvider) ); - pTextLayout->draw(*mpVirtualDevice, aOutpos, viewState, renderState); + pTextLayout->draw(mpCairo, *mpVirtualDevice, aOutpos, viewState, renderState); } return uno::Reference< rendering::XCachedPrimitive >(nullptr); @@ -289,7 +289,7 @@ namespace cairocanvas return uno::Reference< rendering::XCachedPrimitive >(nullptr); // no output necessary // TODO(F2): What about the offset scalings? - pTextLayout->draw(*mpVirtualDevice, aOutpos, viewState, renderState); + pTextLayout->draw(mpCairo, *mpVirtualDevice, aOutpos, viewState, renderState); } } else diff --git a/canvas/source/cairo/cairo_textlayout.cxx b/canvas/source/cairo/cairo_textlayout.cxx index d81a739b4956..32a62c5ea790 100644 --- a/canvas/source/cairo/cairo_textlayout.cxx +++ b/canvas/source/cairo/cairo_textlayout.cxx @@ -77,6 +77,11 @@ namespace cairocanvas // as required at the API spec rOutDev.SetLayoutMode( nLayoutMode | ComplexTextLayoutFlags::TextOriginLeft ); } + + bool compareFallbacks(const SystemGlyphData&rA, const SystemGlyphData &rB) + { + return rA.fallbacklevel < rB.fallbacklevel; + } } TextLayout::TextLayout( const rendering::StringContext& aText, @@ -257,6 +262,33 @@ namespace cairocanvas } /** + * TextLayout::isCairoRenderable + * + * Features currently not supported by Cairo (VCL rendering is used as fallback): + * - vertical glyphs + * + * @return true, if text/font can be rendered with cairo + **/ + bool TextLayout::isCairoRenderable(SystemFontData aSysFontData) const + { +#if defined CAIRO_HAS_FT_FONT + // is font usable? + if (!aSysFontData.nFontId) + return false; +#endif + + // vertical glyph rendering is not supported in cairo for now + if (aSysFontData.bVerticalCharacterType) + { + SAL_WARN("canvas.cairo", ":cairocanvas::TextLayout::isCairoRenderable(): Vertical Character Style not supported"); + return false; + } + + return true; + } + + + /** * TextLayout::draw * * Cairo-based text rendering. Draw text directly on the cairo surface with cairo fonts. @@ -265,30 +297,207 @@ namespace cairocanvas * Note: some text effects are not rendered due to lacking generic canvas or cairo canvas * implementation. See issues 92657, 92658, 92659, 92660, 97529 **/ - void TextLayout::draw( OutputDevice& rOutDev, + void TextLayout::draw( CairoSharedPtr const & pSCairo, + OutputDevice& rOutDev, const Point& rOutpos, const rendering::ViewState& viewState, const rendering::RenderState& renderState ) const { ::osl::MutexGuard aGuard( m_aMutex ); + SystemTextLayoutData aSysLayoutData; setupLayoutMode( rOutDev, mnTextDirection ); + // TODO(P2): cache that std::unique_ptr< long []> aOffsets(new long[maLogicalAdvancements.getLength()]); if( maLogicalAdvancements.hasElements() ) + { setupTextOffsets( aOffsets.get(), maLogicalAdvancements, viewState, renderState ); - if (maLogicalAdvancements.hasElements()) + // TODO(F3): ensure correct length and termination for DX + // array (last entry _must_ contain the overall width) + } + + aSysLayoutData = rOutDev.GetSysTextLayoutData(rOutpos, maText.Text, + ::canvas::tools::numeric_cast<sal_uInt16>(maText.StartPosition), + ::canvas::tools::numeric_cast<sal_uInt16>(maText.Length), + maLogicalAdvancements.hasElements() ? aOffsets.get() : nullptr); + + // Sort them so that all glyphs on the same glyph fallback level are consecutive + std::sort(aSysLayoutData.rGlyphData.begin(), aSysLayoutData.rGlyphData.end(), compareFallbacks); + bool bCairoRenderable = true; + + //Pull all the fonts we need to render the text + typedef std::pair<SystemFontData,int> FontLevel; + std::vector<FontLevel> aFontData; + for (auto const& glyph : aSysLayoutData.rGlyphData) { - rOutDev.DrawTextArray( rOutpos, maText.Text, aOffsets.get(), - ::canvas::tools::numeric_cast<sal_uInt16>(maText.StartPosition), - ::canvas::tools::numeric_cast<sal_uInt16>(maText.Length) ); + if( aFontData.empty() || glyph.fallbacklevel != aFontData.back().second ) + { + aFontData.emplace_back(rOutDev.GetSysFontData(glyph.fallbacklevel), + glyph.fallbacklevel); + if( !isCairoRenderable(aFontData.back().first) ) + { + bCairoRenderable = false; + SAL_INFO("canvas.cairo", ":cairocanvas::TextLayout::draw(S,O,p,v,r): VCL FALLBACK " << + (maLogicalAdvancements.hasElements() ? "ADV " : "") << + (aFontData.back().first.bAntialias ? "AA " : "") << + (aFontData.back().first.bFakeBold ? "FB " : "") << + (aFontData.back().first.bFakeItalic ? "FI " : "") << + " - " << + maText.Text.copy( maText.StartPosition, maText.Length)); + break; + } + } } - else + + // The ::GetSysTextLayoutData(), i.e. layouting of text to glyphs can change the font being used. + // The fallback checks need to be done after final font is known. + if (!bCairoRenderable) // VCL FALLBACKS { - rOutDev.DrawText( rOutpos, maText.Text, - ::canvas::tools::numeric_cast<sal_uInt16>(maText.StartPosition), - ::canvas::tools::numeric_cast<sal_uInt16>(maText.Length) ); + if (maLogicalAdvancements.hasElements()) // VCL FALLBACK - with glyph advances + { + rOutDev.DrawTextArray( rOutpos, maText.Text, aOffsets.get(), + ::canvas::tools::numeric_cast<sal_uInt16>(maText.StartPosition), + ::canvas::tools::numeric_cast<sal_uInt16>(maText.Length) ); + return; + } + else // VCL FALLBACK - without advances + { + rOutDev.DrawText( rOutpos, maText.Text, + ::canvas::tools::numeric_cast<sal_uInt16>(maText.StartPosition), + ::canvas::tools::numeric_cast<sal_uInt16>(maText.Length) ); + return; + } + } + + if (aSysLayoutData.rGlyphData.empty()) + return; //??? false? + + /** + * Setup platform independent glyph vector into cairo-based glyphs vector. + **/ + + // Loop through the fonts used and render the matching glyphs for each + for (auto const& elemFontData : aFontData) + { + const SystemFontData &rSysFontData = elemFontData.first; + + // setup glyphs + std::vector<cairo_glyph_t> cairo_glyphs; + cairo_glyphs.reserve( 256 ); + + for (auto const& systemGlyph : aSysLayoutData.rGlyphData) + { + if( systemGlyph.fallbacklevel != elemFontData.second ) + continue; + + cairo_glyph_t aGlyph; + aGlyph.index = systemGlyph.index; + aGlyph.x = systemGlyph.x; + aGlyph.y = systemGlyph.y; + cairo_glyphs.push_back(aGlyph); + } + + if (cairo_glyphs.empty()) + continue; + + const vcl::Font& aFont = rOutDev.GetFont(); + long nWidth = aFont.GetAverageFontWidth(); + long nHeight = aFont.GetFontHeight(); + if (nWidth == 0) + nWidth = nHeight; + if (nWidth == 0 || nHeight == 0) + continue; + + /** + * Setup font + **/ + cairo_font_face_t* font_face = nullptr; + +#if defined CAIRO_HAS_FT_FONT + font_face = cairo_ft_font_face_create_for_ft_face(static_cast<FT_Face>(rSysFontData.nFontId), + rSysFontData.nFontFlags); +#else +# error Native API needed. +#endif + + cairo_set_font_face( pSCairo.get(), font_face); + + // create default font options. cairo_get_font_options() does not retrieve the surface defaults, + // only what has been set before with cairo_set_font_options() + cairo_font_options_t* options = cairo_font_options_create(); + if (rSysFontData.bAntialias) + { + // CAIRO_ANTIALIAS_GRAY provides more similar result to VCL Canvas, + // so we're not using CAIRO_ANTIALIAS_SUBPIXEL + cairo_font_options_set_antialias(options, CAIRO_ANTIALIAS_GRAY); + } + cairo_set_font_options( pSCairo.get(), options); + + // Font color + Color aTextColor = rOutDev.GetTextColor(); + cairo_set_source_rgb(pSCairo.get(), + aTextColor.GetRed()/255.0, + aTextColor.GetGreen()/255.0, + aTextColor.GetBlue()/255.0); + + // Font rotation and scaling + cairo_matrix_t m; + + cairo_matrix_init_identity(&m); + + if (aSysLayoutData.orientation) + cairo_matrix_rotate(&m, (3600 - aSysLayoutData.orientation) * M_PI / 1800.0); + + cairo_matrix_scale(&m, nWidth, nHeight); + + //faux italics + if (rSysFontData.bFakeItalic) + m.xy = -m.xx * 0x6000 / 0x10000; + + cairo_set_font_matrix(pSCairo.get(), &m); + + SAL_INFO( + "canvas.cairo", + "Size:(" << aFont.GetAverageFontWidth() << "," << aFont.GetFontHeight() + << "), Pos (" << rOutpos.X() << "," << rOutpos.Y() + << "), G(" + << (!cairo_glyphs.empty() ? cairo_glyphs[0].index : -1) + << "," + << (cairo_glyphs.size() > 1 ? cairo_glyphs[1].index : -1) + << "," + << (cairo_glyphs.size() > 2 ? cairo_glyphs[2].index : -1) + << ") " << (maLogicalAdvancements.hasElements() ? "ADV " : "") + << (rSysFontData.bAntialias ? "AA " : "") + << (rSysFontData.bFakeBold ? "FB " : "") + << (rSysFontData.bFakeItalic ? "FI " : "") << " || Name:" + << aFont.GetFamilyName() << " - " + << maText.Text.copy(maText.StartPosition, maText.Length)); + + cairo_show_glyphs(pSCairo.get(), cairo_glyphs.data(), cairo_glyphs.size()); + + //faux bold + if (rSysFontData.bFakeBold) + { + double bold_dx = 0.5 * sqrt( 0.7 * aFont.GetFontHeight() ); + int total_steps = 1 * static_cast<int>(bold_dx + 0.5); + + // loop to draw the text for every half pixel of displacement + for (int nSteps = 0; nSteps < total_steps; nSteps++) + { + for(cairo_glyph_t & cairo_glyph : cairo_glyphs) + { + cairo_glyph.x += (bold_dx * nSteps / total_steps) / 4; + cairo_glyph.y -= (bold_dx * nSteps / total_steps) / 4; + } + cairo_show_glyphs(pSCairo.get(), cairo_glyphs.data(), cairo_glyphs.size()); + } + SAL_INFO("canvas.cairo",":cairocanvas::TextLayout::draw(S,O,p,v,r): FAKEBOLD - dx:" << static_cast<int>(bold_dx)); + } + + cairo_font_face_destroy(font_face); + cairo_font_options_destroy(options); } } diff --git a/canvas/source/cairo/cairo_textlayout.hxx b/canvas/source/cairo/cairo_textlayout.hxx index 6254108a50ad..b5ba2d84bb21 100644 --- a/canvas/source/cairo/cairo_textlayout.hxx +++ b/canvas/source/cairo/cairo_textlayout.hxx @@ -82,7 +82,8 @@ namespace cairocanvas virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; - void draw( OutputDevice& rOutDev, + void draw( ::cairo::CairoSharedPtr const & pSCairo, + OutputDevice& rOutDev, const Point& rOutpos, const css::rendering::ViewState& viewState, const css::rendering::RenderState& renderState ) const; @@ -101,6 +102,8 @@ namespace cairocanvas CanvasFont::Reference mpFont; SurfaceProviderRef mpRefDevice; sal_Int8 mnTextDirection; + + bool isCairoRenderable(SystemFontData aSysFontData) const; }; } |