/* -*- 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/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
// Whether to use GetSkImage() that checks for delayed scaling or whether to access // the stored image directly without checks. enum DirectImage
{
Yes,
No
};
// Sets SkBlender that will do an invert operation. void setBlenderInvert(SkPaint* paint); // Sets SkBlender that will do a xor operation. void setBlenderXor(SkPaint* paint);
// Must be called in any VCL backend before any Skia functionality is used. // If not set, Skia will be disabled.
VCL_DLLPUBLIC void
prepareSkia(std::unique_ptr<skwindow::WindowContext> (*createGpuWindowContext)(bool));
// Get checksum of the image content, only for raster images. Is cached, // but may still be somewhat expensive.
uint32_t getSkImageChecksum(sk_sp<SkImage> image);
// SkSurfaceProps to be used by all Skia surfaces.
VCL_DLLPUBLIC const SkSurfaceProps* surfaceProps(); // Set pixel geometry to be used by SkSurfaceProps.
VCL_DLLPUBLIC void setPixelGeometry(SkPixelGeometry pixelGeometry);
inlinebool isUnitTestRunning(constchar* name = nullptr)
{ if (name == nullptr)
{ if (o3tl::IsRunningUnitTest()) returntrue; return !vcl::test::activeGraphicsRenderTest().isEmpty();
} constchar* const testname = getenv("LO_TESTNAME"); if (testname != nullptr && std::string_view(name) == testname) returntrue; return vcl::test::activeGraphicsRenderTest().equalsAscii(name);
}
// Scaling done on the GPU is fast, but bicubic done in raster mode can be slow // if done too much, and it generally shouldn't be needed for to-screen drawing. // In that case use only BmpScaleFlag::Default, which is bilinear+mipmap, // which should be good enough (and that's what the "super" bitmap scaling // algorithm done by VCL does as well). inline BmpScaleFlag goodScalingQuality(bool isGPU, bool isUpscale = false)
{ #ifdef MACOSX // tdf#161480 use BmpScaleFlag::NearestNeighbor when upscaling on macOS // On macOS, due to Retina window scaling, it is very common to // have Skia surfaces that are 2 times the size of their respective // output device sizes so upscaling is often the default state. // But when upscaling bitmaps on macOS with either Skia/Metal or // Skia/Raster, some distortion to color and/or alpha values is // introduced and only BmpScaleFlag::NearestNeighbor will upscale // the bitmap correctly. if (isUpscale) return BmpScaleFlag::NearestNeighbor; #else
(void)isUpscale; #endif
// Normal scaling algorithms have a poor quality when downscaling a lot. // https://bugs.chromium.org/p/skia/issues/detail?id=11810 suggests to use mipmaps // in such a case, which is annoying to do explicitly instead of Skia deciding which // algorithm would be the best, but now with Skia removing SkFilterQuality and requiring // explicitly being told what algorithm to use this appears to be the best we can do. // Anything scaled down at least this ratio will use linear+mipmaps.
constexpr int downscaleRatioThreshold = 4;
inline SkSamplingOptions makeSamplingOptions(BmpScaleFlag scalingType, SkMatrix matrix, int scalingFactor)
{ switch (scalingType)
{ case BmpScaleFlag::BestQuality: if (scalingFactor != 1)
matrix.postScale(scalingFactor, scalingFactor); if (matrix.getScaleX() <= 1.0 / downscaleRatioThreshold
|| matrix.getScaleY() <= 1.0 / downscaleRatioThreshold) return SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kLinear); return SkSamplingOptions(SkCubicResampler::Mitchell()); case BmpScaleFlag::Default: // Use SkMipmapMode::kNearest for better quality when downscaling. SkMipmapMode::kLinear // would be even better, but it is not specially optimized in raster mode. return SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kNearest); case BmpScaleFlag::Fast: case BmpScaleFlag::NearestNeighbor: return SkSamplingOptions(SkFilterMode::kNearest, SkMipmapMode::kNone); default:
assert(false); return SkSamplingOptions();
}
}
inline SkSamplingOptions makeSamplingOptions(BmpScaleFlag scalingType, const Size& srcSize,
Size destSize, int scalingFactor)
{ switch (scalingType)
{ case BmpScaleFlag::BestQuality: if (scalingFactor != 1)
destSize *= scalingFactor; if (srcSize.Width() / destSize.Width() >= downscaleRatioThreshold
|| srcSize.Height() / destSize.Height() >= downscaleRatioThreshold) return SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kLinear); return SkSamplingOptions(SkCubicResampler::Mitchell()); case BmpScaleFlag::Default: // As in the first overload, use kNearest. return SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kNearest); case BmpScaleFlag::Fast: case BmpScaleFlag::NearestNeighbor: return SkSamplingOptions(SkFilterMode::kNearest, SkMipmapMode::kNone); default:
assert(false); return SkSamplingOptions();
}
}
inline SkSamplingOptions makeSamplingOptions(const SalTwoRect& rPosAry, int scalingFactor, int srcScalingFactor, bool isGPU)
{ // If there will be scaling, make it smooth, but not in unittests, as those often // require exact color values and would be confused by this. if (isUnitTestRunning()) return SkSamplingOptions(); // none
Size srcSize(rPosAry.mnSrcWidth, rPosAry.mnSrcHeight);
Size destSize(rPosAry.mnDestWidth, rPosAry.mnDestHeight); if (scalingFactor != 1)
destSize *= scalingFactor; if (srcScalingFactor != 1)
srcSize *= srcScalingFactor; if (srcSize != destSize)
{ bool isUpscale
= (srcSize.Width() < destSize.Width() || srcSize.Height() < destSize.Height());
BmpScaleFlag scalingType = goodScalingQuality(isGPU, isUpscale); return makeSamplingOptions(scalingType, srcSize, destSize, 1);
} return SkSamplingOptions(); // none
}
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.