summaryrefslogtreecommitdiff
path: root/canvas
diff options
context:
space:
mode:
authorCaolán McNamara <caolanm@redhat.com>2020-09-07 19:53:02 +0100
committerXisco Fauli <xiscofauli@libreoffice.org>2020-09-08 10:22:17 +0200
commitee18059ed6402eb0725048b3dd406852120a9faf (patch)
tree4cd998be7703475227b19508d2dfc0abc82f8a06 /canvas
parent72549d97c220d63d5fd5f6f38ae14f13c3e3d919 (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.cxx4
-rw-r--r--canvas/source/cairo/cairo_textlayout.cxx227
-rw-r--r--canvas/source/cairo/cairo_textlayout.hxx5
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;
};
}