From 97ac77f067910fa5e8206d75160fa63546a9358d Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 4 May 2024 07:03:24 +0200 Subject: Merging upstream version 4:24.2.3. Signed-off-by: Daniel Baumann --- vcl/inc/font/LogicalFontInstance.hxx | 3 +- vcl/inc/impfontcache.hxx | 8 +-- vcl/inc/impglyphitem.hxx | 6 +- vcl/qa/cppunit/graphicfilter/filters-webp-test.cxx | 12 ++-- vcl/qa/cppunit/logicalfontinstance.cxx | 68 +++++++++++++++++---- vcl/qa/cppunit/pdfexport/data/tdf142133.docx | Bin 0 -> 12078 bytes vcl/qa/cppunit/pdfexport/pdfexport.cxx | 35 +++++++++++ vcl/qa/cppunit/pdfexport/pdfexport2.cxx | 6 +- vcl/quartz/cgutils.mm | 10 +++ vcl/skia/gdiimpl.cxx | 20 ++++++ vcl/skia/osx/gdiimpl.cxx | 21 ++++--- vcl/source/app/salvtables.cxx | 2 + vcl/source/app/svmain.cxx | 2 +- vcl/source/bitmap/BitmapEx.cxx | 11 ++-- vcl/source/control/scrbar.cxx | 6 +- vcl/source/filter/webp/reader.cxx | 4 +- vcl/source/font/LogicalFontInstance.cxx | 53 ++++++++-------- vcl/source/font/fontcache.cxx | 4 +- vcl/source/gdi/CommonSalLayout.cxx | 6 +- vcl/source/gdi/pdfwriter_impl.cxx | 18 ++++-- vcl/source/gdi/sallayout.cxx | 44 ++++++++----- vcl/source/outdev/font.cxx | 4 +- vcl/source/treelist/iconviewimpl.cxx | 1 + vcl/source/window/accessibility.cxx | 2 +- vcl/source/window/legacyaccessibility.cxx | 2 +- vcl/source/window/printdlg.cxx | 2 +- vcl/unx/gtk3/gtkframe.cxx | 22 +++++-- vcl/unx/gtk3/gtkinst.cxx | 38 +++++++++++- vcl/win/window/salframe.cxx | 2 +- vcl/workben/listglyphs.cxx | 2 +- 30 files changed, 301 insertions(+), 113 deletions(-) create mode 100644 vcl/qa/cppunit/pdfexport/data/tdf142133.docx (limited to 'vcl') diff --git a/vcl/inc/font/LogicalFontInstance.hxx b/vcl/inc/font/LogicalFontInstance.hxx index 40d3c57c4e..73ba2e26a2 100644 --- a/vcl/inc/font/LogicalFontInstance.hxx +++ b/vcl/inc/font/LogicalFontInstance.hxx @@ -22,6 +22,7 @@ #include #include +#include #include #include #include @@ -100,7 +101,7 @@ public: // TODO: make data members private vcl::font::PhysicalFontFace* GetFontFace() { return m_pFontFace.get(); } const ImplFontCache* GetFontCache() const { return mpFontCache; } - bool GetGlyphBoundRect(sal_GlyphId, tools::Rectangle&, bool) const; + bool GetGlyphBoundRect(sal_GlyphId, basegfx::B2DRectangle&, bool) const; virtual bool GetGlyphOutline(sal_GlyphId, basegfx::B2DPolyPolygon&, bool) const = 0; basegfx::B2DPolyPolygon GetGlyphOutlineUntransformed(sal_GlyphId) const; diff --git a/vcl/inc/impfontcache.hxx b/vcl/inc/impfontcache.hxx index 5ea19b05d9..4d197003b2 100644 --- a/vcl/inc/impfontcache.hxx +++ b/vcl/inc/impfontcache.hxx @@ -21,10 +21,10 @@ #include +#include #include #include #include -#include #include "font/FontSelectPattern.hxx" #include "glyphid.hxx" @@ -59,7 +59,7 @@ struct GlyphBoundRectCacheHash } }; -typedef o3tl::lru_map GlyphBoundRectCache; class ImplFontCache @@ -86,8 +86,8 @@ public: LogicalFontInstance* pLogicalFont, int nFallbackLevel, OUString& rMissingCodes ); - bool GetCachedGlyphBoundRect(const LogicalFontInstance *, sal_GlyphId, tools::Rectangle &); - void CacheGlyphBoundRect(const LogicalFontInstance *, sal_GlyphId, tools::Rectangle &); + bool GetCachedGlyphBoundRect(const LogicalFontInstance*, sal_GlyphId, basegfx::B2DRectangle&); + void CacheGlyphBoundRect(const LogicalFontInstance*, sal_GlyphId, basegfx::B2DRectangle&); void Invalidate(); }; diff --git a/vcl/inc/impglyphitem.hxx b/vcl/inc/impglyphitem.hxx index 1fa8454e2e..bb08031f3a 100644 --- a/vcl/inc/impglyphitem.hxx +++ b/vcl/inc/impglyphitem.hxx @@ -20,8 +20,8 @@ #ifndef INCLUDED_VCL_IMPGLYPHITEM_HXX #define INCLUDED_VCL_IMPGLYPHITEM_HXX +#include #include -#include #include #include #include @@ -89,7 +89,7 @@ public: return bool(m_nFlags & GlyphItemFlags::IS_SAFE_TO_INSERT_KASHIDA); } - inline bool GetGlyphBoundRect(const LogicalFontInstance*, tools::Rectangle&) const; + inline bool GetGlyphBoundRect(const LogicalFontInstance*, basegfx::B2DRectangle&) const; inline bool GetGlyphOutline(const LogicalFontInstance*, basegfx::B2DPolyPolygon&) const; inline void dropGlyph(); @@ -121,7 +121,7 @@ public: }; bool GlyphItem::GetGlyphBoundRect(const LogicalFontInstance* pFontInstance, - tools::Rectangle& rRect) const + basegfx::B2DRectangle& rRect) const { return pFontInstance->GetGlyphBoundRect(m_aGlyphId, rRect, IsVertical()); } diff --git a/vcl/qa/cppunit/graphicfilter/filters-webp-test.cxx b/vcl/qa/cppunit/graphicfilter/filters-webp-test.cxx index d3c43f4819..cbc23315ca 100644 --- a/vcl/qa/cppunit/graphicfilter/filters-webp-test.cxx +++ b/vcl/qa/cppunit/graphicfilter/filters-webp-test.cxx @@ -141,10 +141,10 @@ void WebpFilterTest::testRoundtrip(bool lossy) } AlphaMask tmpAlpha = aResultBitmap.GetAlphaMask(); BitmapScopedReadAccess pAccessAlpha(tmpAlpha); - CPPUNIT_ASSERT_EQUAL(sal_uInt8(0), pAccessAlpha->GetPixelIndex(0, 0)); - CPPUNIT_ASSERT_EQUAL(sal_uInt8(0), pAccessAlpha->GetPixelIndex(0, 19)); - CPPUNIT_ASSERT_EQUAL(sal_uInt8(0), pAccessAlpha->GetPixelIndex(19, 0)); - CPPUNIT_ASSERT_EQUAL(sal_uInt8(64), pAccessAlpha->GetPixelIndex(19, 19)); + CPPUNIT_ASSERT_EQUAL(sal_uInt8(255), pAccessAlpha->GetPixelIndex(0, 0)); + CPPUNIT_ASSERT_EQUAL(sal_uInt8(255), pAccessAlpha->GetPixelIndex(0, 19)); + CPPUNIT_ASSERT_EQUAL(sal_uInt8(255), pAccessAlpha->GetPixelIndex(19, 0)); + CPPUNIT_ASSERT_EQUAL(sal_uInt8(191), pAccessAlpha->GetPixelIndex(19, 19)); } aStream.Seek(STREAM_SEEK_TO_BEGIN); @@ -192,8 +192,8 @@ void WebpFilterTest::testRead(std::u16string_view rName, bool lossy, bool alpha) { AlphaMask tmpAlpha = aResultBitmap.GetAlphaMask(); BitmapScopedReadAccess pAccessAlpha(tmpAlpha); - CPPUNIT_ASSERT_EQUAL(sal_uInt8(0), pAccessAlpha->GetPixelIndex(0, 0)); - CPPUNIT_ASSERT_EQUAL(sal_uInt8(255), pAccessAlpha->GetPixelIndex(0, 9)); + CPPUNIT_ASSERT_EQUAL(sal_uInt8(255), pAccessAlpha->GetPixelIndex(0, 0)); + CPPUNIT_ASSERT_EQUAL(sal_uInt8(0), pAccessAlpha->GetPixelIndex(0, 9)); } } } diff --git a/vcl/qa/cppunit/logicalfontinstance.cxx b/vcl/qa/cppunit/logicalfontinstance.cxx index 6d5bbc4daf..eb803ed403 100644 --- a/vcl/qa/cppunit/logicalfontinstance.cxx +++ b/vcl/qa/cppunit/logicalfontinstance.cxx @@ -39,25 +39,71 @@ void VclLogicalFontInstanceTest::testglyphboundrect() { ScopedVclPtr device = VclPtr::Create(DeviceFormat::WITHOUT_ALPHA); device->SetOutputSizePixel(Size(1000, 1000)); - device->SetFont(vcl::Font("Liberation Sans", Size(0, 110))); + vcl::Font font("Liberation Sans", Size(0, 110)); + device->SetFont(font); const LogicalFontInstance* pFontInstance = device->GetFontInstance(); - tools::Rectangle aBoundRect; + basegfx::B2DRectangle aBoundRect; const auto LATIN_SMALL_LETTER_B = 0x0062; + const auto SECTION_SIGN = 0x00A7; // UTR#50: Vertical_Orientation (vo) property value U pFontInstance->GetGlyphBoundRect(pFontInstance->GetGlyphIndex(LATIN_SMALL_LETTER_B), aBoundRect, false); - const tools::Long nExpectedX = 7; - const tools::Long nExpectedY = -80; - const tools::Long nExpectedWidth = 51; - const tools::Long nExpectedHeight = 83; + CPPUNIT_ASSERT_DOUBLES_EQUAL(7.1, aBoundRect.getMinX(), 0.05); + CPPUNIT_ASSERT_DOUBLES_EQUAL(-79.7, aBoundRect.getMinY(), 0.05); + CPPUNIT_ASSERT_DOUBLES_EQUAL(49.5, aBoundRect.getWidth(), 0.05); + CPPUNIT_ASSERT_DOUBLES_EQUAL(80.8, aBoundRect.getHeight(), 0.05); - CPPUNIT_ASSERT_EQUAL_MESSAGE("x of glyph is wrong", nExpectedX, aBoundRect.getX()); - CPPUNIT_ASSERT_EQUAL_MESSAGE("y of glyph is wrong", nExpectedY, aBoundRect.getY()); - CPPUNIT_ASSERT_EQUAL_MESSAGE("height of glyph of wrong", nExpectedWidth, aBoundRect.GetWidth()); - CPPUNIT_ASSERT_EQUAL_MESSAGE("width of glyph of wrong", nExpectedHeight, - aBoundRect.GetHeight()); + // tdf#160436: test vertically oriented glyphs + pFontInstance->GetGlyphBoundRect(pFontInstance->GetGlyphIndex(SECTION_SIGN), aBoundRect, true); + + CPPUNIT_ASSERT_DOUBLES_EQUAL(-79.7, aBoundRect.getMinX(), 0.05); + CPPUNIT_ASSERT_DOUBLES_EQUAL(-55.0, aBoundRect.getMinY(), 0.05); + CPPUNIT_ASSERT_DOUBLES_EQUAL(88.9, aBoundRect.getWidth(), 0.05); + CPPUNIT_ASSERT_DOUBLES_EQUAL(48.8, aBoundRect.getHeight(), 0.05); + + font.SetOrientation(900_deg10); + device->SetFont(font); + + pFontInstance = device->GetFontInstance(); + + pFontInstance->GetGlyphBoundRect(pFontInstance->GetGlyphIndex(LATIN_SMALL_LETTER_B), aBoundRect, + false); + + CPPUNIT_ASSERT_DOUBLES_EQUAL(-79.7, aBoundRect.getMinX(), 0.05); + CPPUNIT_ASSERT_DOUBLES_EQUAL(-56.6, aBoundRect.getMinY(), 0.05); + CPPUNIT_ASSERT_DOUBLES_EQUAL(80.8, aBoundRect.getWidth(), 0.05); + CPPUNIT_ASSERT_DOUBLES_EQUAL(49.5, aBoundRect.getHeight(), 0.05); + + // tdf#160436: test vertically oriented glyphs + pFontInstance->GetGlyphBoundRect(pFontInstance->GetGlyphIndex(SECTION_SIGN), aBoundRect, true); + + CPPUNIT_ASSERT_DOUBLES_EQUAL(-55.0, aBoundRect.getMinX(), 0.05); + CPPUNIT_ASSERT_DOUBLES_EQUAL(-9.2, aBoundRect.getMinY(), 0.05); + CPPUNIT_ASSERT_DOUBLES_EQUAL(48.8, aBoundRect.getWidth(), 0.05); + CPPUNIT_ASSERT_DOUBLES_EQUAL(88.9, aBoundRect.getHeight(), 0.05); + + font.SetOrientation(450_deg10); + device->SetFont(font); + + pFontInstance = device->GetFontInstance(); + + pFontInstance->GetGlyphBoundRect(pFontInstance->GetGlyphIndex(LATIN_SMALL_LETTER_B), aBoundRect, + false); + + CPPUNIT_ASSERT_DOUBLES_EQUAL(-51.3, aBoundRect.getMinX(), 0.05); + CPPUNIT_ASSERT_DOUBLES_EQUAL(-96.4, aBoundRect.getMinY(), 0.05); + CPPUNIT_ASSERT_DOUBLES_EQUAL(92.1, aBoundRect.getWidth(), 0.05); + CPPUNIT_ASSERT_DOUBLES_EQUAL(92.1, aBoundRect.getHeight(), 0.05); + + // tdf#160436: test vertically oriented glyphs + pFontInstance->GetGlyphBoundRect(pFontInstance->GetGlyphIndex(SECTION_SIGN), aBoundRect, true); + + CPPUNIT_ASSERT_DOUBLES_EQUAL(-95.3, aBoundRect.getMinX(), 0.05); + CPPUNIT_ASSERT_DOUBLES_EQUAL(-45.4, aBoundRect.getMinY(), 0.05); + CPPUNIT_ASSERT_DOUBLES_EQUAL(97.4, aBoundRect.getWidth(), 0.05); + CPPUNIT_ASSERT_DOUBLES_EQUAL(97.4, aBoundRect.getHeight(), 0.05); } CPPUNIT_TEST_SUITE_REGISTRATION(VclLogicalFontInstanceTest); diff --git a/vcl/qa/cppunit/pdfexport/data/tdf142133.docx b/vcl/qa/cppunit/pdfexport/data/tdf142133.docx new file mode 100644 index 0000000000..fa1e155b87 Binary files /dev/null and b/vcl/qa/cppunit/pdfexport/data/tdf142133.docx differ diff --git a/vcl/qa/cppunit/pdfexport/pdfexport.cxx b/vcl/qa/cppunit/pdfexport/pdfexport.cxx index d362a38553..e9a8530c3c 100644 --- a/vcl/qa/cppunit/pdfexport/pdfexport.cxx +++ b/vcl/qa/cppunit/pdfexport/pdfexport.cxx @@ -2740,6 +2740,41 @@ CPPUNIT_TEST_FIXTURE(PdfExportTest, testTdf157816Link) CPPUNIT_ASSERT_EQUAL(static_cast(4), pAnnots->GetElements().size()); } +CPPUNIT_TEST_FIXTURE(PdfExportTest, testTdf142133) +{ + vcl::filter::PDFDocument aDocument; + load(u"tdf142133.docx", aDocument); + + // The document has one page. + std::vector aPages = aDocument.GetPages(); + CPPUNIT_ASSERT_EQUAL(static_cast(1), aPages.size()); + + auto pAnnots = dynamic_cast(aPages[0]->Lookup("Annots"_ostr)); + CPPUNIT_ASSERT(pAnnots); + + // There should be one annotation + CPPUNIT_ASSERT_EQUAL(static_cast(1), pAnnots->GetElements().size()); + auto pAnnotReference + = dynamic_cast(pAnnots->GetElements()[0]); + CPPUNIT_ASSERT(pAnnotReference); + vcl::filter::PDFObjectElement* pAnnot = pAnnotReference->LookupObject(); + CPPUNIT_ASSERT(pAnnot); + // We're expecting something like /Type /Annot /A << /Type /Action /S /URI /URI (path) + CPPUNIT_ASSERT_EQUAL( + "Annot"_ostr, + static_cast(pAnnot->Lookup("Type"_ostr))->GetValue()); + CPPUNIT_ASSERT_EQUAL( + "Link"_ostr, + static_cast(pAnnot->Lookup("Subtype"_ostr))->GetValue()); + auto pAction = dynamic_cast(pAnnot->Lookup("A"_ostr)); + CPPUNIT_ASSERT(pAction); + auto pURIElem + = dynamic_cast(pAction->LookupElement("URI"_ostr)); + CPPUNIT_ASSERT(pURIElem); + // Check it matches + CPPUNIT_ASSERT_EQUAL("https://google.com/"_ostr, pURIElem->GetValue()); +} + CPPUNIT_TEST_FIXTURE(PdfExportTest, testTdf142806) { aMediaDescriptor["FilterName"] <<= OUString("writer_pdf_Export"); diff --git a/vcl/qa/cppunit/pdfexport/pdfexport2.cxx b/vcl/qa/cppunit/pdfexport/pdfexport2.cxx index 38e3629497..a464798076 100644 --- a/vcl/qa/cppunit/pdfexport/pdfexport2.cxx +++ b/vcl/qa/cppunit/pdfexport/pdfexport2.cxx @@ -40,6 +40,7 @@ #include #include +#include #include #include @@ -4580,7 +4581,10 @@ CPPUNIT_TEST_FIXTURE(PdfExportTest2, testRexportMediaBoxOrigin) = { // Rotation by $\theta$ $cos(\theta), sin(\theta), -sin(\theta), cos(\theta)$ 0, -1, 1, 0, // Translate x,y - -aOrigin[1] - aSize[1] / 2 + aSize[0] / 2, aOrigin[0] + aSize[0] / 2 + aSize[1] / 2 + -aOrigin[1] - aSize[1] / vcl::PDF_INSERT_MAGIC_SCALE_FACTOR / 2 + + aSize[0] / vcl::PDF_INSERT_MAGIC_SCALE_FACTOR / 2, + aOrigin[0] + aSize[0] / vcl::PDF_INSERT_MAGIC_SCALE_FACTOR / 2 + + aSize[1] / vcl::PDF_INSERT_MAGIC_SCALE_FACTOR / 2 }; for (sal_Int32 nIdx = 0; nIdx < 6; ++nIdx) diff --git a/vcl/quartz/cgutils.mm b/vcl/quartz/cgutils.mm index 0d611bec11..50b7fcd654 100644 --- a/vcl/quartz/cgutils.mm +++ b/vcl/quartz/cgutils.mm @@ -122,6 +122,16 @@ bool DefaultMTLDeviceIsSupported() bRet = false; } + if (bRet) + { + // tdf#160590 Disable Metal with Intel HD Graphics 6000 + // Releasing a Metal buffer resource hangs when fetching pixels from a + // Skia surface on this Intel MacBook Air built-in GPU. + static NSString* pIntelHDGraphics6000Prefix = @"Intel(R) Iris(TM) Graphics 6000"; + if ([pMetalDevice.name hasPrefix:pIntelHDGraphics6000Prefix]) + bRet = false; + } + [pMetalDevice release]; return bRet; } diff --git a/vcl/skia/gdiimpl.cxx b/vcl/skia/gdiimpl.cxx index d7028b9598..dce3175feb 100644 --- a/vcl/skia/gdiimpl.cxx +++ b/vcl/skia/gdiimpl.cxx @@ -1490,6 +1490,26 @@ void SkiaSalGraphicsImpl::invert(basegfx::B2DPolygon const& rPoly, SalInvert eFl aPaint.setShader( aBitmap.makeShader(SkTileMode::kRepeat, SkTileMode::kRepeat, SkSamplingOptions())); } + +#ifdef SK_METAL + // tdf#153306 prevent subpixel shifting of X coordinate + // HACK: for some unknown reason, if the X coordinate of the + // path's bounds is more than 1024, SkBlendMode::kExclusion will + // shift by about a half a pixel to the right with Skia/Metal on + // a Retina display. Weirdly, if the same polygon is repeatedly + // drawn, the total shift is cumulative so if the drawn polygon + // is more than a few pixels wide, the blinking cursor in Writer + // will exhibit this bug but only for one thin vertical slice at + // a time. Apparently, shifting drawing a very tiny amount to + // the left seems to be enough to quell this runaway cumulative + // X coordinate shift. + if (isGPU()) + { + SkMatrix aMatrix; + aMatrix.set(SkMatrix::kMTransX, -0.001); + getDrawCanvas()->concat(aMatrix); + } +#endif } getDrawCanvas()->drawPath(aPath, aPaint); postDraw(); diff --git a/vcl/skia/osx/gdiimpl.cxx b/vcl/skia/osx/gdiimpl.cxx index c4bd751842..9b511ad446 100644 --- a/vcl/skia/osx/gdiimpl.cxx +++ b/vcl/skia/osx/gdiimpl.cxx @@ -37,12 +37,6 @@ using namespace SkiaHelper; -static void releaseInstalledPixels(void* pAddr, void*) -{ - if (pAddr) - delete[] static_cast(pAddr); -} - AquaSkiaSalGraphicsImpl::AquaSkiaSalGraphicsImpl(AquaSalGraphics& rParent, AquaSharedAttributes& rShared) : SkiaSalGraphicsImpl(rParent, rShared.mpFrame) @@ -251,6 +245,7 @@ bool AquaSkiaSalGraphicsImpl::drawNativeControl(ControlType nType, ControlPart n if (!context) { SAL_WARN("vcl.skia", "drawNativeControl(): Failed to allocate bitmap context"); + delete[] data; return false; } // Setup context state for drawing (performDrawNativeControl() e.g. fills background in some cases). @@ -287,12 +282,9 @@ bool AquaSkiaSalGraphicsImpl::drawNativeControl(ControlType nType, ControlPart n if (!bitmap.installPixels(SkImageInfo::Make(width, height, mSurface->imageInfo().colorType(), kPremul_SkAlphaType), - data, width * 4, releaseInstalledPixels, nullptr)) + data, width * 4, nullptr, nullptr)) abort(); - // Make bitmap immutable to avoid making a copy in bitmap.asImage() - bitmap.setImmutable(); - preDraw(); SAL_INFO("vcl.skia.trace", "drawnativecontrol(" << this << "): " << rControlRegion << ":" << int(nType) << "/" << int(nPart)); @@ -312,6 +304,15 @@ bool AquaSkiaSalGraphicsImpl::drawNativeControl(ControlType nType, ControlPart n ++pendingOperationsToFlush; // tdf#136369 postDraw(); } + // Related: tdf#159529 eliminate possible memory leak + // Despite confirming that the release function passed to + // SkBitmap.bitmap.installPixels() does get called for every + // data array that has been allocated, Apple's Instruments + // indicates that the data is leaking. While it is likely a + // false positive, it makes leak analysis difficult so leave + // the bitmap mutable. That causes SkBitmap.asImage() to make + // a copy of the data and the data can be safely deleted here. + delete[] data; return bOK; } diff --git a/vcl/source/app/salvtables.cxx b/vcl/source/app/salvtables.cxx index 50ecd194bd..faf645fc79 100644 --- a/vcl/source/app/salvtables.cxx +++ b/vcl/source/app/salvtables.cxx @@ -2592,6 +2592,8 @@ public: else m_xScrollBar->set_width_request(nThickness); } + + virtual void set_scroll_swap_arrows(bool bSwap) override { m_xScrollBar->SetSwapArrows(bSwap); } }; } diff --git a/vcl/source/app/svmain.cxx b/vcl/source/app/svmain.cxx index 3aa2cecf4e..9eb99f09e3 100644 --- a/vcl/source/app/svmain.cxx +++ b/vcl/source/app/svmain.cxx @@ -194,7 +194,7 @@ int ImplSVMain() const bool bWasInitVCL = IsVCLInit(); -#if defined(LINUX) && !defined(SYSTEM_OPENSSL) +#if !defined(_WIN32) && !defined(SYSTEM_OPENSSL) if (!bWasInitVCL) { OUString constexpr name(u"SSL_CERT_FILE"_ustr); diff --git a/vcl/source/bitmap/BitmapEx.cxx b/vcl/source/bitmap/BitmapEx.cxx index 40feacbf66..07e25f1771 100644 --- a/vcl/source/bitmap/BitmapEx.cxx +++ b/vcl/source/bitmap/BitmapEx.cxx @@ -657,7 +657,7 @@ namespace const Bitmap& rSource, const Size& rDestinationSize, const basegfx::B2DHomMatrix& rTransform, - bool bSmooth) + bool bSmooth, bool bAlphaMask) { Bitmap aDestination(rDestinationSize, vcl::PixelFormat::N24_BPP); BitmapScopedWriteAccess xWrite(aDestination); @@ -673,7 +673,10 @@ namespace // tdf#157795 set color to black outside of bitmap bounds // Due to commit 81994cb2b8b32453a92bcb011830fcb884f22ff3, // transparent areas are now black instead of white. - const BitmapColor aOutside(0x0, 0x0, 0x0); + // tdf#160831 only set outside color to black for alpha masks + // The outside color still needs to be white for the content + // so only apply the fix for tdf#157795 to the alpha mask. + const BitmapColor aOutside = bAlphaMask ? BitmapColor(0x0, 0x0, 0x0) : BitmapColor(0xff, 0xff, 0xff); for(tools::Long y(0); y < aDestinationSizePixel.getHeight(); y++) { @@ -759,12 +762,12 @@ BitmapEx BitmapEx::TransformBitmapEx( // force destination to 24 bit, we want to smooth output const Size aDestinationSize(basegfx::fround(fWidth), basegfx::fround(fHeight)); bool bSmooth = implTransformNeedsSmooth(rTransformation); - const Bitmap aDestination(impTransformBitmap(GetBitmap(), aDestinationSize, rTransformation, bSmooth)); + const Bitmap aDestination(impTransformBitmap(GetBitmap(), aDestinationSize, rTransformation, bSmooth, false)); // create mask if(IsAlpha()) { - const Bitmap aAlpha(impTransformBitmap(GetAlphaMask().GetBitmap(), aDestinationSize, rTransformation, bSmooth)); + const Bitmap aAlpha(impTransformBitmap(GetAlphaMask().GetBitmap(), aDestinationSize, rTransformation, bSmooth, true)); return BitmapEx(aDestination, AlphaMask(aAlpha)); } diff --git a/vcl/source/control/scrbar.cxx b/vcl/source/control/scrbar.cxx index b652360139..7218b1485b 100644 --- a/vcl/source/control/scrbar.cxx +++ b/vcl/source/control/scrbar.cxx @@ -85,6 +85,7 @@ void ScrollBar::ImplInit( vcl::Window* pParent, WinBits nStyle ) meScrollType = ScrollType::DontKnow; mbCalcSize = true; mbFullDrag = false; + mbSwapArrows = false; ImplInitStyle( nStyle ); Control::ImplInit( pParent, nStyle, nullptr ); @@ -240,6 +241,7 @@ void ScrollBar::ImplCalc( bool bUpdate ) const tools::Rectangle aControlRegion( Point(0,0), aSize ); tools::Rectangle aBtn1Region, aBtn2Region, aTrackRegion, aBoundingRegion; + const bool bSwapArrows = mbSwapArrows || IsRTLEnabled(); // reset rectangles to empty *and* (0,0) position maThumbRect = tools::Rectangle(); @@ -248,9 +250,9 @@ void ScrollBar::ImplCalc( bool bUpdate ) if ( GetStyle() & WB_HORZ ) { - if ( GetNativeControlRegion( ControlType::Scrollbar, IsRTLEnabled()? ControlPart::ButtonRight: ControlPart::ButtonLeft, + if ( GetNativeControlRegion( ControlType::Scrollbar, bSwapArrows? ControlPart::ButtonRight: ControlPart::ButtonLeft, aControlRegion, ControlState::NONE, ImplControlValue(), aBoundingRegion, aBtn1Region ) && - GetNativeControlRegion( ControlType::Scrollbar, IsRTLEnabled()? ControlPart::ButtonLeft: ControlPart::ButtonRight, + GetNativeControlRegion( ControlType::Scrollbar, bSwapArrows? ControlPart::ButtonLeft: ControlPart::ButtonRight, aControlRegion, ControlState::NONE, ImplControlValue(), aBoundingRegion, aBtn2Region ) ) { maBtn1Rect = aBtn1Region; diff --git a/vcl/source/filter/webp/reader.cxx b/vcl/source/filter/webp/reader.cxx index 1d75ff79e8..2003312476 100644 --- a/vcl/source/filter/webp/reader.cxx +++ b/vcl/source/filter/webp/reader.cxx @@ -241,7 +241,7 @@ static bool readWebp(SvStream& stream, Graphic& graphic) for (tools::Long x = 0; x < access->Width(); ++x) { memcpy(dstB, src, 3); - *dstA = 255 - *(src + 3); + *dstA = *(src + 3); src += 4; dstB += 3; dstA += 1; @@ -273,7 +273,7 @@ static bool readWebp(SvStream& stream, Graphic& graphic) for (tools::Long x = 0; x < accessAlpha->Width(); ++x) { sal_uInt8 a = src[3]; - accessAlpha->SetPixelIndex(y, x, 255 - a); + accessAlpha->SetPixelIndex(y, x, a); src += 4; } } diff --git a/vcl/source/font/LogicalFontInstance.cxx b/vcl/source/font/LogicalFontInstance.cxx index 0c21cba475..3cf95cab8d 100644 --- a/vcl/source/font/LogicalFontInstance.cxx +++ b/vcl/source/font/LogicalFontInstance.cxx @@ -26,6 +26,8 @@ #include #include +#include + LogicalFontInstance::LogicalFontInstance(const vcl::font::PhysicalFontFace& rFontFace, const vcl::font::FontSelectPattern& rFontSelData) : mxFontMetric(new FontMetricData(rFontSelData)) @@ -166,47 +168,42 @@ void LogicalFontInstance::IgnoreFallbackForUnicode(sal_UCS4 cChar, FontWeight eW maUnicodeFallbackList.erase(it); } -bool LogicalFontInstance::GetGlyphBoundRect(sal_GlyphId nID, tools::Rectangle& rRect, +bool LogicalFontInstance::GetGlyphBoundRect(sal_GlyphId nID, basegfx::B2DRectangle& rRect, bool bVertical) const { + // TODO: find out if it's possible for the same glyph in the same font to be used both + // normally and vertically; if yes, then these two variants must be cached separately + if (mpFontCache && mpFontCache->GetCachedGlyphBoundRect(this, nID, rRect)) return true; auto* pHbFont = const_cast(this)->GetHbFont(); hb_glyph_extents_t aExtents; - bool res = hb_font_get_glyph_extents(pHbFont, nID, &aExtents); + if (!hb_font_get_glyph_extents(pHbFont, nID, &aExtents)) + return false; - if (res) - { - double nXScale = 0, nYScale = 0; - GetScale(&nXScale, &nYScale); + double nXScale = 0, nYScale = 0; + GetScale(&nXScale, &nYScale); - double fMinX = aExtents.x_bearing; - double fMinY = aExtents.y_bearing; - double fMaxX = aExtents.x_bearing + aExtents.width; - double fMaxY = aExtents.y_bearing + aExtents.height; + double fMinX = aExtents.x_bearing * nXScale; + double fMinY = -aExtents.y_bearing * nYScale; + double fMaxX = (aExtents.x_bearing + aExtents.width) * nXScale; + double fMaxY = -(aExtents.y_bearing + aExtents.height) * nYScale; + rRect = basegfx::B2DRectangle(fMinX, fMinY, fMaxX, fMaxY); - tools::Rectangle aRect(std::floor(fMinX * nXScale), -std::ceil(fMinY * nYScale), - std::ceil(fMaxX * nXScale), -std::floor(fMaxY * nYScale)); - if (mnOrientation && !bVertical) - { - // Apply font rotation. - const double fRad = toRadians(mnOrientation); - const double fCos = cos(fRad); - const double fSin = sin(fRad); - - rRect.SetLeft(fCos * aRect.Left() + fSin * aRect.Top()); - rRect.SetTop(-fSin * aRect.Left() - fCos * aRect.Top()); - rRect.SetRight(fCos * aRect.Right() + fSin * aRect.Bottom()); - rRect.SetBottom(-fSin * aRect.Right() - fCos * aRect.Bottom()); - } - else - rRect = aRect; + auto orientation = mnOrientation; + if (bVertical) + orientation += 900_deg10; + if (orientation) + { + // Apply font rotation. + rRect.transform(basegfx::utils::createRotateB2DHomMatrix(-toRadians(orientation))); } - if (mpFontCache && res) + if (mpFontCache) mpFontCache->CacheGlyphBoundRect(this, nID, rRect); - return res; + + return true; } sal_GlyphId LogicalFontInstance::GetGlyphIndex(uint32_t nUnicode, uint32_t nVariationSelector) const diff --git a/vcl/source/font/fontcache.cxx b/vcl/source/font/fontcache.cxx index c0dba15350..ce4ba6adf6 100644 --- a/vcl/source/font/fontcache.cxx +++ b/vcl/source/font/fontcache.cxx @@ -252,7 +252,7 @@ void ImplFontCache::Invalidate() m_aBoundRectCache.clear(); } -bool ImplFontCache::GetCachedGlyphBoundRect(const LogicalFontInstance *pFont, sal_GlyphId nID, tools::Rectangle &rRect) +bool ImplFontCache::GetCachedGlyphBoundRect(const LogicalFontInstance *pFont, sal_GlyphId nID, basegfx::B2DRectangle &rRect) { if (!pFont->GetFontCache()) return false; @@ -269,7 +269,7 @@ bool ImplFontCache::GetCachedGlyphBoundRect(const LogicalFontInstance *pFont, sa return false; } -void ImplFontCache::CacheGlyphBoundRect(const LogicalFontInstance *pFont, sal_GlyphId nID, tools::Rectangle &rRect) +void ImplFontCache::CacheGlyphBoundRect(const LogicalFontInstance *pFont, sal_GlyphId nID, basegfx::B2DRectangle &rRect) { if (!pFont->GetFontCache()) return; diff --git a/vcl/source/gdi/CommonSalLayout.cxx b/vcl/source/gdi/CommonSalLayout.cxx index bcf6f54639..455428e7f3 100644 --- a/vcl/source/gdi/CommonSalLayout.cxx +++ b/vcl/source/gdi/CommonSalLayout.cxx @@ -534,12 +534,12 @@ bool GenericSalLayout::LayoutText(vcl::text::ImplLayoutArgs& rArgs, const SalLay { // We need glyph's advance, top bearing, and height to // correct y offset. - tools::Rectangle aRect; + basegfx::B2DRectangle aRect; // Get cached bound rect value for the font, GetFont().GetGlyphBoundRect(nGlyphIndex, aRect, true); - nXOffset = -(aRect.Top() / nXScale + ( pHbPositions[i].y_advance - + ( aRect.GetHeight() / nXScale ) ) / 2.0 ); + nXOffset = -(aRect.getMinX() / nXScale + ( pHbPositions[i].y_advance + + ( aRect.getHeight() / nXScale ) ) / 2.0 ); } } diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx index a5365e681b..ff7383d7be 100644 --- a/vcl/source/gdi/pdfwriter_impl.cxx +++ b/vcl/source/gdi/pdfwriter_impl.cxx @@ -7091,7 +7091,7 @@ void PDFWriterImpl::drawLayout( SalLayout& rLayout, const OUString& rText, bool else if ( eAlign == ALIGN_TOP ) aOffset.AdjustY(GetFontInstance()->mxFontMetric->GetAscent() ); - tools::Rectangle aRectangle; + basegfx::B2DRectangle aRectangle; nIndex = 0; while (rLayout.GetNextGlyph(&pGlyph, aPos, nIndex, &pGlyphFont)) { @@ -7109,7 +7109,7 @@ void PDFWriterImpl::drawLayout( SalLayout& rLayout, const OUString& rText, bool else { aAdjOffset = basegfx::B2DPoint(aOffset.X(), aOffset.Y()); - aAdjOffset.adjustX(aRectangle.Left() + (aRectangle.GetWidth() - aEmphasisMark.GetWidth()) / 2 ); + aAdjOffset.adjustX(aRectangle.getMinX() + (aRectangle.getWidth() - aEmphasisMark.GetWidth()) / 2 ); } aAdjOffset = aRotScale.transform( aAdjOffset ); @@ -9125,9 +9125,15 @@ void PDFWriterImpl::writeReferenceXObject(const ReferenceXObjectEmit& rEmit) } double aOrigin[2] = { 0.0, 0.0 }; - if (auto* pArray = dynamic_cast(pPage->Lookup("MediaBox"_ostr))) + + // tdf#160714 use crop box for bounds of embedded PDF object + // If there is no crop box, fallback to the media box just to be safe. + auto* pBoundsArray = dynamic_cast(pPage->Lookup("CropBox"_ostr)); + if (!pBoundsArray) + pBoundsArray = dynamic_cast(pPage->Lookup("MediaBox"_ostr)); + if (pBoundsArray) { - const auto& rElements = pArray->GetElements(); + const auto& rElements = pBoundsArray->GetElements(); if (rElements.size() >= 4) { // get x1, y1 of the rectangle. @@ -9240,9 +9246,9 @@ void PDFWriterImpl::writeReferenceXObject(const ReferenceXObjectEmit& rEmit) // Now transform the object: rotate around the center and make sure that the rotation // doesn't affect the aspect ratio. basegfx::B2DHomMatrix aMat; - aMat.translate(-0.5 * aBBox.getWidth() - aOrigin[0], -0.5 * aBBox.getHeight() - aOrigin[1]); + aMat.translate((-0.5 * aBBox.getWidth() / fMagicScaleFactor) - aOrigin[0], (-0.5 * aBBox.getHeight() / fMagicScaleFactor) - aOrigin[1]); aMat.rotate(basegfx::deg2rad(nAngle)); - aMat.translate(0.5 * nWidth, 0.5 * nHeight); + aMat.translate(0.5 * nWidth / fMagicScaleFactor, 0.5 * nHeight / fMagicScaleFactor); aLine.append(" /Matrix [ "); aLine.append(aMat.a()); diff --git a/vcl/source/gdi/sallayout.cxx b/vcl/source/gdi/sallayout.cxx index af281127ba..28138c3f61 100644 --- a/vcl/source/gdi/sallayout.cxx +++ b/vcl/source/gdi/sallayout.cxx @@ -214,12 +214,18 @@ bool SalLayout::GetOutline(basegfx::B2DPolyPolygonVector& rVector) const return (bAllOk && bOneOk); } +// No need to expand to the next pixel, when the character only covers its tiny fraction +static double trimInsignificant(double n) +{ + return std::abs(n) >= 0x1p53 ? n : std::round(n * 1e5) / 1e5; +} + bool SalLayout::GetBoundRect(tools::Rectangle& rRect) const { bool bRet = false; - rRect.SetEmpty(); - tools::Rectangle aRectangle; + basegfx::B2DRectangle aUnion; + basegfx::B2DRectangle aRectangle; basegfx::B2DPoint aPos; const GlyphItem* pGlyph; @@ -230,22 +236,28 @@ bool SalLayout::GetBoundRect(tools::Rectangle& rRect) const // get bounding rectangle of individual glyph if (pGlyph->GetGlyphBoundRect(pGlyphFont, aRectangle)) { - if (!aRectangle.IsEmpty()) + if (!aRectangle.isEmpty()) { - aRectangle.AdjustLeft(std::floor(aPos.getX())); - aRectangle.AdjustRight(std::ceil(aPos.getX())); - aRectangle.AdjustTop(std::floor(aPos.getY())); - aRectangle.AdjustBottom(std::ceil(aPos.getY())); - + aRectangle.transform(basegfx::utils::createTranslateB2DHomMatrix(aPos)); // merge rectangle - if (rRect.IsEmpty()) - rRect = aRectangle; - else - rRect.Union(aRectangle); + aUnion.expand(aRectangle); } bRet = true; } } + if (aUnion.isEmpty()) + { + rRect = {}; + } + else + { + double l = rtl::math::approxFloor(trimInsignificant(aUnion.getMinX())), + t = rtl::math::approxFloor(trimInsignificant(aUnion.getMinY())), + r = rtl::math::approxCeil(trimInsignificant(aUnion.getMaxX())), + b = rtl::math::approxCeil(trimInsignificant(aUnion.getMaxY())); + assert(std::isfinite(l) && std::isfinite(t) && std::isfinite(r) && std::isfinite(b)); + rRect = tools::Rectangle(l, t, r, b); + } return bRet; } @@ -292,7 +304,7 @@ void GenericSalLayout::Justify(double nNewWidth) std::vector::iterator pGlyphIter; // count stretchable glyphs int nStretchable = 0; - double nMaxGlyphWidth = 0; + double nMaxGlyphWidth = 0.0; for(pGlyphIter = m_GlyphItems.begin(); pGlyphIter != pGlyphIterRight; ++pGlyphIter) { if( !pGlyphIter->IsInCluster() ) @@ -303,7 +315,7 @@ void GenericSalLayout::Justify(double nNewWidth) // move rightmost glyph to requested position nOldWidth -= pGlyphIterRight->origWidth(); - if( nOldWidth <= 0 ) + if( nOldWidth <= 0.0 ) return; if( nNewWidth < nMaxGlyphWidth) nNewWidth = nMaxGlyphWidth; @@ -312,10 +324,10 @@ void GenericSalLayout::Justify(double nNewWidth) // justify glyph widths and positions double nDiffWidth = nNewWidth - nOldWidth; - if( nDiffWidth >= 0) // expanded case + if( nDiffWidth >= 0.0 ) // expanded case { // expand width by distributing space between glyphs evenly - int nDeltaSum = 0; + double nDeltaSum = 0.0; for( pGlyphIter = m_GlyphItems.begin(); pGlyphIter != pGlyphIterRight; ++pGlyphIter ) { // move glyph to justified position diff --git a/vcl/source/outdev/font.cxx b/vcl/source/outdev/font.cxx index 2086db7f63..9c04373159 100644 --- a/vcl/source/outdev/font.cxx +++ b/vcl/source/outdev/font.cxx @@ -951,7 +951,7 @@ void OutputDevice::ImplDrawEmphasisMarks( SalLayout& rSalLayout ) aOffset += Point( nEmphasisWidth2, nEmphasisHeight2 ); basegfx::B2DPoint aOutPoint; - tools::Rectangle aRectangle; + basegfx::B2DRectangle aRectangle; const GlyphItem* pGlyph; const LogicalFontInstance* pGlyphFont; int nStart = 0; @@ -971,7 +971,7 @@ void OutputDevice::ImplDrawEmphasisMarks( SalLayout& rSalLayout ) else { aAdjPoint = aOffset; - aAdjPoint.AdjustX(aRectangle.Left() + (aRectangle.GetWidth() - aEmphasisMark.GetWidth()) / 2 ); + aAdjPoint.AdjustX(aRectangle.getMinX() + (aRectangle.getWidth() - aEmphasisMark.GetWidth()) / 2 ); } if ( mpFontInstance->mnOrientation ) diff --git a/vcl/source/treelist/iconviewimpl.cxx b/vcl/source/treelist/iconviewimpl.cxx index 048e193d4f..35025d1c81 100644 --- a/vcl/source/treelist/iconviewimpl.cxx +++ b/vcl/source/treelist/iconviewimpl.cxx @@ -467,6 +467,7 @@ void IconViewImpl::SyncVerThumb() void IconViewImpl::UpdateAll() { FindMostRight(); + AdjustScrollBars(m_aOutputSize); SyncVerThumb(); FillView(); ShowVerSBar(); diff --git a/vcl/source/window/accessibility.cxx b/vcl/source/window/accessibility.cxx index 3c6103ac31..295a5c3878 100644 --- a/vcl/source/window/accessibility.cxx +++ b/vcl/source/window/accessibility.cxx @@ -69,7 +69,7 @@ css::uno::Reference< css::accessibility::XAccessible > Window::GetAccessible( bo */ if ( !mpWindowImpl ) return css::uno::Reference< css::accessibility::XAccessible >(); - if ( !mpWindowImpl->mxAccessible.is() && bCreate ) + if (!mpWindowImpl->mxAccessible.is() && !mpWindowImpl->mbInDispose && bCreate) mpWindowImpl->mxAccessible = CreateAccessible(); return mpWindowImpl->mxAccessible; diff --git a/vcl/source/window/legacyaccessibility.cxx b/vcl/source/window/legacyaccessibility.cxx index 346e1fdc8f..a0f4aff339 100644 --- a/vcl/source/window/legacyaccessibility.cxx +++ b/vcl/source/window/legacyaccessibility.cxx @@ -109,7 +109,7 @@ Window* Window::getLegacyNonLayoutAccessibleRelationLabelFor() const static Window* ImplGetLabeledBy( Window* pFrameWindow, WindowType nMyType, Window* pLabeled ) { Window* pWindow = nullptr; - if ( (nMyType != WindowType::GROUPBOX) && (nMyType != WindowType::FIXEDLINE) ) + if (pFrameWindow && nMyType != WindowType::GROUPBOX && nMyType != WindowType::FIXEDLINE) { // search for a control that labels this window // a label is considered the last fixed text, fixed line or group box diff --git a/vcl/source/window/printdlg.cxx b/vcl/source/window/printdlg.cxx index 9c5f519f7c..c001b6e740 100644 --- a/vcl/source/window/printdlg.cxx +++ b/vcl/source/window/printdlg.cxx @@ -122,7 +122,7 @@ void PrintDialog::PrintPreviewWindow::Paint(vcl::RenderContext& rRenderContext, { rRenderContext.Push(); weld::SetPointFont(rRenderContext, rRenderContext.GetSettings().GetStyleSettings().GetLabelFont()); - + rRenderContext.SetTextColor(rRenderContext.GetSettings().GetStyleSettings().GetLabelTextColor()); rRenderContext.SetBackground(Wallpaper(Application::GetSettings().GetStyleSettings().GetDialogColor())); rRenderContext.Erase(); diff --git a/vcl/unx/gtk3/gtkframe.cxx b/vcl/unx/gtk3/gtkframe.cxx index f996b4359b..8c097c526c 100644 --- a/vcl/unx/gtk3/gtkframe.cxx +++ b/vcl/unx/gtk3/gtkframe.cxx @@ -3953,12 +3953,24 @@ void GtkSalFrame::signalRealize(GtkWidget*, gpointer frame) } AbsoluteScreenPixelRectangle aFloatRect = FloatingWindow::ImplConvertToAbsPos(pVclParent, pThis->m_aFloatRect); - if (gdk_window_get_window_type(widget_get_surface(pThis->m_pParent->m_pWindow)) != GDK_WINDOW_TOPLEVEL) + switch (gdk_window_get_window_type(widget_get_surface(pThis->m_pParent->m_pWindow))) { - // See tdf#152155 for an example - gtk_coord nX(0), nY(0.0); - gtk_widget_translate_coordinates(pThis->m_pParent->m_pWindow, widget_get_toplevel(pThis->m_pParent->m_pWindow), 0, 0, &nX, &nY); - aFloatRect.Move(nX, nY); + case GDK_WINDOW_TOPLEVEL: + break; + case GDK_WINDOW_CHILD: + { + // See tdf#152155 for an example + gtk_coord nX(0), nY(0.0); + gtk_widget_translate_coordinates(pThis->m_pParent->m_pWindow, widget_get_toplevel(pThis->m_pParent->m_pWindow), 0, 0, &nX, &nY); + aFloatRect.Move(nX, nY); + break; + } + default: + { + // See tdf#154072 for an example + aFloatRect.Move(-pThis->m_pParent->maGeometry.x(), -pThis->m_pParent->maGeometry.y()); + break; + } } GdkRectangle rect {static_cast(aFloatRect.Left()), static_cast(aFloatRect.Top()), diff --git a/vcl/unx/gtk3/gtkinst.cxx b/vcl/unx/gtk3/gtkinst.cxx index b8da4f7b7a..a899fc16c6 100644 --- a/vcl/unx/gtk3/gtkinst.cxx +++ b/vcl/unx/gtk3/gtkinst.cxx @@ -5505,8 +5505,9 @@ public: { GtkBox *pBox = GTK_BOX(gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6)); GtkWidget *pLabel = gtk_label_new_with_mnemonic(MapToGtkAccelerator(rStr).getStr()); + gtk_label_set_xalign(GTK_LABEL(pLabel), 0.0); pItem = eCheckRadioFalse != TRISTATE_INDET ? gtk_check_menu_item_new() : gtk_menu_item_new(); - gtk_box_pack_start(pBox, pImage, true, true, 0); + gtk_box_pack_start(pBox, pImage, false, true, 0); gtk_box_pack_start(pBox, pLabel, true, true, 0); gtk_container_add(GTK_CONTAINER(pItem), GTK_WIDGET(pBox)); gtk_widget_show_all(pItem); @@ -8745,6 +8746,11 @@ public: gtk_widget_set_size_request(GTK_WIDGET(m_pScrollbar), nThickness, -1); } + virtual void set_scroll_swap_arrows(bool /* bSwap */) override + { + // Related: tdf#93352 do nothing since GtkScrollbar has no arrows + } + virtual ~GtkInstanceScrollbar() override { g_signal_handler_disconnect(m_pAdjustment, m_nAdjustChangedSignalId); @@ -14834,6 +14840,32 @@ private: } #endif + static gboolean search_equal_func(GtkTreeModel *model, + int column, + const char *key, + GtkTreeIter *iter, + gpointer /*user_data*/) + { + GValue aValue = G_VALUE_INIT; + gtk_tree_model_get_value(model, iter, column, &aValue); + + GValue aStringValue = G_VALUE_INIT; + g_value_init(&aStringValue, G_TYPE_STRING); + const bool fail = !g_value_transform(&aValue, &aStringValue); + g_value_unset(&aValue); + if (fail) + return true; + + bool bNoMatch(true); + if (const char *str = g_value_get_string(&aStringValue)) + { + const vcl::I18nHelper& rI18nHelper = Application::GetSettings().GetLocaleI18nHelper(); + bNoMatch = !rI18nHelper.MatchString(OUString::fromUtf8(key), OUString::fromUtf8(str)); + } + g_value_unset(&aStringValue); + return bNoMatch; + } + public: GtkInstanceTreeView(GtkTreeView* pTreeView, GtkInstanceBuilder* pBuilder, bool bTakeOwnership) : GtkInstanceWidget(GTK_WIDGET(pTreeView), pBuilder, bTakeOwnership) @@ -14965,6 +14997,10 @@ public: m_nRowDeletedSignalId = g_signal_connect(m_pTreeModel, "row-deleted", G_CALLBACK(signalRowDeleted), this); m_nRowInsertedSignalId = g_signal_connect(m_pTreeModel, "row-inserted", G_CALLBACK(signalRowInserted), this); + + // tdf#160028 LibreOffice embeds RTL/LTR direction markers in currency strings, which defeats the + // default gtk search mechanism, so switch in our one here + gtk_tree_view_set_search_equal_func(m_pTreeView, search_equal_func, nullptr, nullptr); } virtual void connect_query_tooltip(const Link& rLink) override diff --git a/vcl/win/window/salframe.cxx b/vcl/win/window/salframe.cxx index 1eed596e6c..bd93ad6bf4 100644 --- a/vcl/win/window/salframe.cxx +++ b/vcl/win/window/salframe.cxx @@ -3589,7 +3589,7 @@ static bool HandleAltNumPadCode(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lPar if (!(keyFlags & KF_REPEAT)) state.clear(); state.started = true; - return true; + return false; // This must be processed further - e.g., to show accelerators } if (!state.started) diff --git a/vcl/workben/listglyphs.cxx b/vcl/workben/listglyphs.cxx index def2ff8181..341006d433 100644 --- a/vcl/workben/listglyphs.cxx +++ b/vcl/workben/listglyphs.cxx @@ -120,7 +120,7 @@ int ListGlyphs::Main() nChar = pCharMap->GetNextChar(nChar)) { auto nGlyphIndex = pFontInstance->GetGlyphIndex(nChar); - tools::Rectangle aGlyphBounds; + basegfx::B2DRectangle aGlyphBounds; pFontInstance->GetGlyphBoundRect(nGlyphIndex, aGlyphBounds, false); std::cout << "Codepoint: " << pFontFace->GetGlyphName(nGlyphIndex) << "; glyph bounds: " << aGlyphBounds << "\n"; -- cgit v1.2.3