/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
// For each font within the font file, get a font face reference and add to the builder. for (UINT32 fontIndex = 0; fontIndex < numberOfFonts; ++fontIndex)
{
sal::systools::COMReference<IDWriteFontFaceReference> fontFaceReference; if (FAILED(dwriteFactory3->CreateFontFaceReference(
fontFile, fontIndex, DWRITE_FONT_SIMULATIONS_NONE, &fontFaceReference))) continue;
// Leave it to DirectWrite to read properties directly out of the font files
dwriteFontSetBuilder->AddFontFaceReference(fontFaceReference);
}
bool WinSkiaSalGraphicsImpl::TryRenderCachedNativeControl(ControlCacheKey const& rControlCacheKey, int nX, int nY)
{ staticbool gbCacheEnabled = !getenv("SAL_WITHOUT_WIDGET_CACHE"); if (!gbCacheEnabled) returnfalse;
if (!aControlCacheKey.canCacheControl()) returntrue;
SkiaControlCachePair pair(aControlCacheKey, std::move(image));
SkiaControlsCache::get().insert(std::move(pair)); returntrue;
}
sk_sp<SkTypeface>
WinSkiaSalGraphicsImpl::createDirectWriteTypeface(const WinFontInstance* pWinFont) try
{ using sal::systools::ThrowIfFailed;
IDWriteFactory* dwriteFactory = WinSalGraphics::getDWriteFactory(); if (!dwriteDone)
{
dwriteFontMgr = SkFontMgr_New_DirectWrite(dwriteFactory);
dwriteDone = true;
} if (!dwriteFontMgr) return nullptr;
IDWriteFontFace* fontFace = pWinFont->GetDWFontFace(); if (!fontFace) return nullptr;
sal::systools::COMReference<IDWriteFontCollection> collection;
ThrowIfFailed(dwriteFactory->GetSystemFontCollection(&collection), SAL_WHERE);
sal::systools::COMReference<IDWriteFont> font; // As said above, this fails for our fonts. if (FAILED(collection->GetFontFromFontFace(fontFace, &font)))
{ // If not found in system collection, try our private font collection. // If that's not possible we'll fall back to Skia's GDI-based font rendering. if (!dwritePrivateCollection
|| FAILED(dwritePrivateCollection->GetFontFromFontFace(fontFace, &font)))
{ // Our private fonts are installed using AddFontResourceExW( FR_PRIVATE ) // and that does not make them available to the DWrite system font // collection. For such cases attempt to update a collection of // private fonts with this newly used font.
bool WinSkiaSalGraphicsImpl::DrawTextLayout(const GenericSalLayout& rLayout)
{
assert(dynamic_cast<SkiaWinFontInstance*>(&rLayout.GetFont()));
SkiaWinFontInstance& rWinFont = static_cast<SkiaWinFontInstance&>(rLayout.GetFont()); const vcl::font::FontSelectPattern& rFSD = rWinFont.GetFontSelectPattern(); if (rFSD.mnHeight == 0) returnfalse; const HFONT hLayoutFont = rWinFont.GetHFONT();
LOGFONTW logFont; if (GetObjectW(hLayoutFont, sizeof(logFont), &logFont) == 0)
{
assert(false); returnfalse;
}
sk_sp<SkTypeface> typeface = rWinFont.GetSkiaTypeface(); if (!typeface)
{
typeface = createDirectWriteTypeface(&rWinFont); bool dwrite = true; if (!typeface) // fall back to GDI text rendering
{ // If lfWidth is kept, then with hScale != 1 characters get too wide, presumably // because the horizontal scaling gets applied twice if GDI is used for drawing (tdf#141715). // Using lfWidth /= hScale gives slightly incorrect sizes, for a reason I don't understand. // LOGFONT docs say that 0 means GDI will find out the right value on its own somehow, // and it apparently works.
logFont.lfWidth = 0; // Reset LOGFONT orientation, the proper orientation is applied by drawGenericLayout(), // and keeping this would make it get applied once more when doing the actual GDI drawing. // Resetting it here does not seem to cause any problem.
logFont.lfOrientation = 0;
logFont.lfEscapement = 0;
typeface = SkCreateTypefaceFromLOGFONT(logFont);
dwrite = false; if (!typeface) returnfalse;
} // Cache the typeface.
rWinFont.SetSkiaTypeface(typeface, dwrite);
}
SkFont font(typeface);
bool bSubpixelPositioning = rLayout.GetSubpixelPositioning();
SkFont::Edging ePreferredAliasing
= bSubpixelPositioning ? SkFont::Edging::kSubpixelAntiAlias : fontEdging; if (bSubpixelPositioning)
{ // note that SkFont defaults to a BaselineSnap of true, so I think really only // subpixel in text direction
font.setSubpixel(true);
}
font.setEdging(logFont.lfQuality == NONANTIALIASED_QUALITY ? SkFont::Edging::kAlias
: ePreferredAliasing);
void WinSkiaSalGraphicsImpl::initFontInfo()
{ // Skia needs to be explicitly told what kind of antialiasing should be used, // get it from system settings. This does not actually matter for the text // rendering itself, since Skia has been patched to simply use the setting // from the LOGFONT, which gets set by VCL's ImplGetLogFontFromFontSelect() // and that one normally uses DEFAULT_QUALITY, so Windows will select // the appropriate AA setting. But Skia internally chooses the format to which // the glyphs will be rendered based on this setting (subpixel AA requires colors, // others do not).
fontEdging = SkFont::Edging::kAlias;
SkPixelGeometry pixelGeometry = kUnknown_SkPixelGeometry; BOOL set; if (SystemParametersInfo(SPI_GETFONTSMOOTHING, 0, &set, 0) && set)
{
UINT set2; if (SystemParametersInfo(SPI_GETFONTSMOOTHINGTYPE, 0, &set2, 0)
&& set2 == FE_FONTSMOOTHINGCLEARTYPE)
{
fontEdging = SkFont::Edging::kSubpixelAntiAlias; if (SystemParametersInfo(SPI_GETFONTSMOOTHINGORIENTATION, 0, &set2, 0)
&& set2 == FE_FONTSMOOTHINGORIENTATIONBGR) // No idea how to tell if it's horizontal or vertical.
pixelGeometry = kBGR_H_SkPixelGeometry; else
pixelGeometry = kRGB_H_SkPixelGeometry; // default
} else
fontEdging = SkFont::Edging::kAntiAlias;
}
setPixelGeometry(pixelGeometry);
}
void WinSkiaSalGraphicsImpl::ClearDevFontCache()
{
dwriteFontMgr.reset();
dwritePrivateCollection.clear();
dwriteDone = false;
initFontInfo(); // get font info again, just in case
}
SkiaCompatibleDC::SkiaCompatibleDC(WinSalGraphics& rGraphics, int x, int y, int width, int height)
: maRects(0, 0, width, height, x, y, width, height)
{
mpImpl = rGraphics.getWinSalGraphicsImplBase();
mhCompatibleDC = CreateCompatibleDC(rGraphics.getHDC());
// move the origin so that we always paint at 0,0 - to keep the bitmap small
OffsetViewportOrgEx(mhCompatibleDC, -x, -y, nullptr);
void SkiaCompatibleDC::fill(sal_uInt32 color)
{ if (!mpData) return;
sal_uInt32* p = mpData; for (int i = maRects.mnSrcWidth * maRects.mnSrcHeight; i > 0; --i)
*p++ = color;
}
sk_sp<SkImage> SkiaCompatibleDC::getAsImageDiff(const SkiaCompatibleDC& white) const
{
SkiaZone zone;
assert(maRects.mnSrcWidth == white.maRects.mnSrcWidth
|| maRects.mnSrcHeight == white.maRects.mnSrcHeight);
SkBitmap tmpBitmap; if (!tmpBitmap.tryAllocPixels(SkImageInfo::Make(maRects.mnSrcWidth, maRects.mnSrcHeight,
kBGRA_8888_SkColorType, kPremul_SkAlphaType),
maRects.mnSrcWidth * 4))
abort(); // Native widgets are drawn twice on black/white background to synthetize alpha // (commit c6b66646870cb2bffaa73565affcf80bf74e0b5c). The problem is that // most widgets when drawn on transparent background are drawn properly (and the result // is in premultiplied alpha format), some such as "Edit" (used by ControlType::Editbox) // keep the alpha channel as transparent. Therefore the alpha is actually computed // from the difference in the premultiplied red channels when drawn one black and on white. // Alpha is computed as "alpha = 1.0 - abs(black.red - white.red)". // I doubt this can be done using Skia, so do it manually here. Fortunately // the bitmaps should be fairly small and are cached.
uint32_t* dest = tmpBitmap.getAddr32(0, 0);
assert(dest == tmpBitmap.getPixels()); const sal_uInt32* src = mpData; const sal_uInt32* whiteSrc = white.mpData;
uint32_t* end = dest + tmpBitmap.width() * tmpBitmap.height(); while (dest < end)
{
uint32_t alpha = 255 - abs(int(*src & 0xff) - int(*whiteSrc & 0xff));
*dest = (*src & 0x00ffffff) | (alpha << 24);
++dest;
++src;
++whiteSrc;
}
tmpBitmap.notifyPixelsChanged();
tmpBitmap.setImmutable();
sk_sp<SkSurface> surface = createSkSurface(tmpBitmap.width(), tmpBitmap.height());
SkPaint paint;
paint.setBlendMode(SkBlendMode::kSrc); // set as is, including alpha
SkCanvas* canvas = surface->getCanvas();
canvas->save(); // The data we got is upside-down.
SkMatrix matrix;
matrix.preTranslate(0, tmpBitmap.height());
matrix.setConcat(matrix, SkMatrix::Scale(1, -1));
canvas->concat(matrix);
canvas->drawImage(tmpBitmap.asImage(), 0, 0, SkSamplingOptions(), &paint);
canvas->restore(); return makeCheckedImageSnapshot(surface);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.