configure.ac | 2 cui/source/tabpages/numfmt.cxx | 24 desktop/qa/desktop_lib/test_desktop_lib.cxx | 4 include/svl/zforlist.hxx | 6 include/svtools/scrolladaptor.hxx | 1 oox/source/ppt/slidepersist.cxx | 72 ++ sc/qa/uitest/calc_tests/formatCells.py | 8 sc/source/ui/inc/tabview.hxx | 1 sc/source/ui/miscdlgs/acredlin.cxx | 96 +-- sc/source/ui/view/tabview.cxx | 11 sd/qa/unit/data/pptx/tdf125573_FontWorkScaleX.pptx |binary sd/qa/unit/data/pptx/tdf153036_resizedConnectorL.pptx |binary sd/qa/unit/export-tests-ooxml3.cxx | 5 sd/qa/unit/import-tests.cxx | 16 svtools/source/control/scrolladaptor.cxx | 5 svx/source/dialog/fntctrl.cxx | 17 svx/source/dialog/svxruler.cxx | 6 sw/CppunitTest_sw_rtfimport.mk | 1 sw/inc/IDocumentSettingAccess.hxx | 1 sw/inc/doc.hxx | 3 sw/qa/extras/layout/data/Hyphenated-link.fodt | 254 ++++++++++ sw/qa/extras/layout/data/Hyphenated-link.rtf | 41 + sw/qa/extras/layout/data/hidden-para-separator.docx |binary sw/qa/extras/layout/layout2.cxx | 63 ++ sw/qa/extras/ooxmlexport/data/custom-styles-TOC-comma.docx |binary sw/qa/extras/ooxmlexport/data/custom-styles-TOC-semicolon.docx |binary sw/qa/extras/ooxmlexport/ooxmlexport17.cxx | 49 + sw/qa/extras/rtfimport/data/hidden-para-separator.rtf | 67 ++ sw/qa/extras/rtfimport/rtfimport.cxx | 37 + sw/qa/filter/html/html.cxx | 30 + sw/source/core/crsr/bookmark.cxx | 3 sw/source/core/doc/DocumentSettingManager.cxx | 9 sw/source/core/doc/doctxm.cxx | 5 sw/source/core/docnode/ndsect.cxx | 2 sw/source/core/inc/DocumentSettingManager.hxx | 1 sw/source/core/inc/UndoSection.hxx | 5 sw/source/core/inc/rootfrm.hxx | 9 sw/source/core/layout/newfrm.cxx | 3 sw/source/core/layout/wsfrm.cxx | 22 sw/source/core/text/guess.cxx | 30 + sw/source/core/text/redlnitr.cxx | 76 ++ sw/source/core/undo/unsect.cxx | 14 sw/source/core/view/viewsh.cxx | 8 sw/source/filter/html/css1atr.cxx | 11 sw/source/filter/html/htmltabw.cxx | 14 sw/source/filter/ww8/ww8atr.cxx | 27 - sw/source/filter/ww8/ww8par.cxx | 1 sw/source/filter/xml/xmlimp.cxx | 10 sw/source/uibase/docvw/HeaderFooterWin.cxx | 9 sw/source/uibase/uno/SwXDocumentSettings.cxx | 18 ucb/source/ucp/webdav-curl/CurlSession.cxx | 12 unoxml/inc/node.hxx | 3 unoxml/source/dom/attr.cxx | 2 unoxml/source/dom/attr.hxx | 3 unoxml/source/dom/document.cxx | 8 unoxml/source/dom/document.hxx | 3 unoxml/source/dom/documentfragment.cxx | 2 unoxml/source/dom/documentfragment.hxx | 3 unoxml/source/dom/element.cxx | 2 unoxml/source/dom/element.hxx | 3 unoxml/source/dom/entity.cxx | 2 unoxml/source/dom/entity.hxx | 3 unoxml/source/dom/entityreference.cxx | 2 unoxml/source/dom/entityreference.hxx | 3 unoxml/source/dom/node.cxx | 8 vcl/inc/osx/salframeview.h | 7 vcl/inc/osx/salinst.h | 1 vcl/inc/svdata.hxx | 1 vcl/osx/a11ytextattributeswrapper.mm | 6 vcl/osx/a11ywrapper.mm | 33 + vcl/osx/a11ywrapperbutton.mm | 4 vcl/osx/a11ywrappercheckbox.mm | 7 vcl/osx/a11ywrappercombobox.mm | 10 vcl/osx/a11ywrappergroup.mm | 4 vcl/osx/a11ywrapperlist.mm | 4 vcl/osx/a11ywrapperradiobutton.mm | 7 vcl/osx/a11ywrapperradiogroup.mm | 4 vcl/osx/a11ywrapperrow.mm | 4 vcl/osx/a11ywrapperscrollarea.mm | 4 vcl/osx/a11ywrapperscrollbar.mm | 4 vcl/osx/a11ywrappersplitter.mm | 4 vcl/osx/a11ywrapperstatictext.mm | 4 vcl/osx/a11ywrappertabgroup.mm | 4 vcl/osx/a11ywrappertextarea.mm | 4 vcl/osx/a11ywrappertoolbar.mm | 4 vcl/osx/salframeview.mm | 164 +++++- vcl/osx/salinst.cxx | 14 vcl/osx/saltimer.cxx | 4 vcl/skia/gdiimpl.cxx | 5 vcl/source/app/scheduler.cxx | 7 vcl/unx/gtk3/gtkinst.cxx | 157 ++++-- writerfilter/source/dmapper/DomainMapper_Impl.cxx | 11 writerfilter/source/dmapper/StyleSheetTable.cxx | 29 + writerfilter/source/filter/WriterFilter.cxx | 1 writerfilter/source/rtftok/rtfdispatchsymbol.cxx | 4 writerfilter/source/rtftok/rtfdocumentimpl.cxx | 17 writerfilter/source/rtftok/rtfdocumentimpl.hxx | 3 97 files changed, 1446 insertions(+), 246 deletions(-)
New commits: commit 339b90e9a1c89f8e67aeee94d06878b4e130ac36 Author: Rene Engelhard <r...@debian.org> AuthorDate: Sun Jan 22 11:58:41 2023 +0100 Commit: Andras Timar <andras.ti...@collabora.com> CommitDate: Mon Jan 23 09:41:35 2023 +0100 check for harfbuzz >= 2.6.8 because of hb_ot_layout_lookup_get_glyph_alternates() usage, see https://git.launchpad.net/~libreoffice/ubuntu/+source/libreoffice/commit/?h=wip/lunar-7.5&id=97d1a9d48f30394d86db0ce948c4fb8986afc701 and https://harfbuzz.github.io/harfbuzz-hb-ot-layout.html#hb-ot-layout-lookup-get-glyph-alternates: "Since: 2.6.8" Change-Id: I755c42745f3bdd647fcd7c101ea7e5fde24c5a6e Reviewed-on: https://gerrit.libreoffice.org/c/core/+/145965 Reviewed-by: خالد حسني <kha...@aliftype.com> Tested-by: René Engelhard <r...@debian.org> (cherry picked from commit a180a99e2d53a2ca04e8fe31a38f6994e42bf69b) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/145938 diff --git a/configure.ac b/configure.ac index 1cb0c9a63ab5..2cf3484ad4d8 100644 --- a/configure.ac +++ b/configure.ac @@ -10855,7 +10855,7 @@ libo_CHECK_SYSTEM_MODULE([graphite],[GRAPHITE],[graphite2 >= 0.9.3]) HARFBUZZ_CFLAGS_internal="-I${WORKDIR}/UnpackedTarball/harfbuzz/src" HARFBUZZ_LIBS_internal="-L${WORKDIR}/UnpackedTarball/harfbuzz/src/.libs -lharfbuzz" -libo_CHECK_SYSTEM_MODULE([harfbuzz],[HARFBUZZ],[harfbuzz-icu >= 2.6.0]) +libo_CHECK_SYSTEM_MODULE([harfbuzz],[HARFBUZZ],[harfbuzz-icu >= 2.6.8]) if test "$COM" = "MSC"; then # override the above GRAPHITE_LIBS="${WORKDIR}/LinkTarget/StaticLibrary/graphite.lib" commit f557c24c7cb1c54941401035d3ec4297c1109937 Author: Caolán McNamara <caol...@redhat.com> AuthorDate: Thu Jan 19 20:39:06 2023 +0000 Commit: Andras Timar <andras.ti...@collabora.com> CommitDate: Mon Jan 23 09:41:35 2023 +0100 change test to use Calibri instead of Cambria because of the Caladea problem There are sadly now two Caladea fonts with different metrics, see: https://bugzilla.redhat.com/show_bug.cgi?id=2162532 https://github.com/huertatipografica/Caladea/issues/4 Change-Id: I7080d16ec8aae2bbe60717aea85b980a33340e9b Reviewed-on: https://gerrit.libreoffice.org/c/core/+/145807 Tested-by: Jenkins Tested-by: René Engelhard <r...@debian.org> Reviewed-by: René Engelhard <r...@debian.org> diff --git a/sd/qa/unit/data/pptx/tdf125573_FontWorkScaleX.pptx b/sd/qa/unit/data/pptx/tdf125573_FontWorkScaleX.pptx index e8d1938a2308..28672eb4b7f3 100644 Binary files a/sd/qa/unit/data/pptx/tdf125573_FontWorkScaleX.pptx and b/sd/qa/unit/data/pptx/tdf125573_FontWorkScaleX.pptx differ diff --git a/sd/qa/unit/export-tests-ooxml3.cxx b/sd/qa/unit/export-tests-ooxml3.cxx index 309709317821..db023bef2592 100644 --- a/sd/qa/unit/export-tests-ooxml3.cxx +++ b/sd/qa/unit/export-tests-ooxml3.cxx @@ -748,14 +748,15 @@ void SdOOXMLExportTest3::testTdf125573_FontWorkScaleX() awt::Rectangle aBoundRectArch; xShapeArchProps->getPropertyValue(UNO_NAME_MISC_OBJ_BOUNDRECT) >>= aBoundRectArch; // BoundRect is DPI dependent, thus allow some range. - CPPUNIT_ASSERT_LESS(sal_Int32(50), std::abs(aBoundRectArch.Width - 13038)); + // (Without fix Expected less than: 85 Actual : 10432) + CPPUNIT_ASSERT_LESS(sal_Int32(85), std::abs(aBoundRectArch.Width - 13038)); // Error was, that text in shapes of category "Warp" was not scaled to the path. uno::Reference<beans::XPropertySet> xShapeWaveProps(getShapeFromPage(0, 1)); awt::Rectangle aBoundRectWave; xShapeWaveProps->getPropertyValue(UNO_NAME_MISC_OBJ_BOUNDRECT) >>= aBoundRectWave; // BoundRect is DPI dependent, thus allow some range. - CPPUNIT_ASSERT_LESS(sal_Int32(50), std::abs(aBoundRectWave.Width - 11576)); + CPPUNIT_ASSERT_LESS(sal_Int32(85), std::abs(aBoundRectWave.Width - 11576)); } void SdOOXMLExportTest3::testTdf99497_keepAppearanceOfCircleKind() commit 8bf89ad2f2ff8f54959958c350640c9d5d267ed7 Author: Patrick Luby <plub...@neooffice.org> AuthorDate: Fri Jan 20 18:57:02 2023 -0500 Commit: Andras Timar <andras.ti...@collabora.com> CommitDate: Mon Jan 23 09:41:35 2023 +0100 tdf#152703 Force relayout during live resizing of window Merge the following commits from the master branch: 3f7406bc4df3c7d6cc618312607bff1ec36a12f7 2d1a0d86d2d0c00fcfee61c39f2221e786e4245b fed429e4f6f437997aa6a88e2d071f58aa00ee34 24eabdbebcbc3b9189bbb9809205ead9f903a0cb d56d76a4204aad18f75463b0c9aa6130d558e0ef eefc323cd592c7958b13062e3f08e105d24055b1 9cc91e17172709c65742c092d3f312bce48ac6d9 Change-Id: Id0f001b3a1e09a6187bf5c08611e7eaa06385743 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/145918 Tested-by: Jenkins Reviewed-by: Patrick Luby <plub...@neooffice.org> diff --git a/vcl/inc/osx/salframeview.h b/vcl/inc/osx/salframeview.h index 2fcff0d1c1e5..6242f3d4146a 100644 --- a/vcl/inc/osx/salframeview.h +++ b/vcl/inc/osx/salframeview.h @@ -28,8 +28,13 @@ enum class SalEvent; { AquaSalFrame* mpFrame; id mDraggingDestinationHandler; + BOOL mbInLiveResize; + BOOL mbInWindowDidResize; + NSTimer* mpLiveResizeTimer; } -(id)initWithSalFrame: (AquaSalFrame*)pFrame; +-(void)clearLiveResizeTimer; +-(void)dealloc; -(BOOL)canBecomeKeyWindow; -(void)displayIfNeeded; -(void)windowDidBecomeKey: (NSNotification*)pNotification; @@ -62,6 +67,8 @@ enum class SalEvent; -(void)endExtTextInput; -(void)endExtTextInput:(EndExtTextInputFlags)nFlags; + +-(void)windowDidResizeWithTimer:(NSTimer *)pTimer; @end @interface SalFrameView : AquaA11yWrapper <NSTextInputClient> diff --git a/vcl/inc/osx/salinst.h b/vcl/inc/osx/salinst.h index 1e6fce7092fd..8811fa3c9c72 100644 --- a/vcl/inc/osx/salinst.h +++ b/vcl/inc/osx/salinst.h @@ -89,7 +89,6 @@ public: int mnActivePrintJobs; osl::Mutex maUserEventListMutex; osl::Condition maWaitingYieldCond; - bool mbIsLiveResize; bool mbNoYieldLock; bool mbTimerProcessed; diff --git a/vcl/inc/svdata.hxx b/vcl/inc/svdata.hxx index 3651eb3bce61..06d0aeb9b9af 100644 --- a/vcl/inc/svdata.hxx +++ b/vcl/inc/svdata.hxx @@ -269,6 +269,7 @@ struct ImplSVWinData StartAutoScrollFlags mnAutoScrollFlags = StartAutoScrollFlags::NONE; // auto scroll flags bool mbNoDeactivate = false; // true: do not execute Deactivate bool mbNoSaveFocus = false; // true: menus must not save/restore focus + bool mbIsLiveResize = false; // true: skip waiting for events and low priority timers }; typedef std::vector< std::pair< OUString, FieldUnit > > FieldUnitStringList; diff --git a/vcl/osx/salframeview.mm b/vcl/osx/salframeview.mm index 09643b5c307d..8445a6c40904 100644 --- a/vcl/osx/salframeview.mm +++ b/vcl/osx/salframeview.mm @@ -169,6 +169,9 @@ static AquaSalFrame* getMouseContainerFrame() -(id)initWithSalFrame: (AquaSalFrame*)pFrame { mDraggingDestinationHandler = nil; + mbInLiveResize = NO; + mbInWindowDidResize = NO; + mpLiveResizeTimer = nil; mpFrame = pFrame; NSRect aRect = { { static_cast<CGFloat>(pFrame->maGeometry.x()), static_cast<CGFloat>(pFrame->maGeometry.y()) }, { static_cast<CGFloat>(pFrame->maGeometry.width()), static_cast<CGFloat>(pFrame->maGeometry.height()) } }; @@ -209,6 +212,22 @@ static AquaSalFrame* getMouseContainerFrame() return static_cast<SalFrameWindow *>(pNSWindow); } +-(void)clearLiveResizeTimer +{ + if ( mpLiveResizeTimer ) + { + [mpLiveResizeTimer invalidate]; + [mpLiveResizeTimer release]; + mpLiveResizeTimer = nil; + } +} + +-(void)dealloc +{ + [self clearLiveResizeTimer]; + [super dealloc]; +} + -(AquaSalFrame*)getSalFrame { return mpFrame; @@ -219,21 +238,6 @@ static AquaSalFrame* getMouseContainerFrame() if( GetSalData() && GetSalData()->mpInstance ) { SolarMutexGuard aGuard; - -#if HAVE_FEATURE_SKIA - // Related: tdf#152703 Eliminate empty window with Skia/Metal while resizing - // The window will clear its background so when Skia/Metal is enabled, - // explicitly flush the Skia graphics to the window during live - // resizing or else nothing will be drawn until after live resizing - // has ended. - if ( [self inLiveResize] && SkiaHelper::isVCLSkiaEnabled() && mpFrame && AquaSalFrame::isAlive( mpFrame ) ) - { - AquaSalGraphics* pGraphics = mpFrame->mpGraphics; - if ( pGraphics ) - pGraphics->Flush(); - } -#endif - [super displayIfNeeded]; } } @@ -332,22 +336,100 @@ static AquaSalFrame* getMouseContainerFrame() (void)pNotification; SolarMutexGuard aGuard; + if ( mbInWindowDidResize ) + return; + + mbInWindowDidResize = YES; + if( mpFrame && AquaSalFrame::isAlive( mpFrame ) ) { mpFrame->UpdateFrameGeometry(); mpFrame->CallCallback( SalEvent::Resize, nullptr ); - // Related: tdf#152703 Stop flicker with Skia/Metal while resizing - // When Skia/Metal is enabled, rapidly resizing a window has a - // noticeable amount of flicker so don't send any paint events during - // live resizing. - // Also, it appears that most of the LibreOffice layouts do not change - // their layout much during live resizing so apply this change when - // Skia is not enabled to ensure consistent behavior whether Skia is - // enabled or not. - if ( ![self inLiveResize] ) + bool bInLiveResize = [self inLiveResize]; + ImplSVData* pSVData = ImplGetSVData(); + assert( pSVData ); + if ( pSVData ) + { + const bool bWasLiveResize = pSVData->mpWinData->mbIsLiveResize; + if ( bWasLiveResize != bInLiveResize ) + { + pSVData->mpWinData->mbIsLiveResize = bInLiveResize; + Scheduler::Wakeup(); + } + } + + if ( bInLiveResize || mbInLiveResize ) + { + mbInLiveResize = bInLiveResize; + +#if HAVE_FEATURE_SKIA + // Related: tdf#152703 Eliminate empty window with Skia/Metal while resizing + // The window will clear its background so when Skia/Metal is + // enabled, explicitly flush the Skia graphics to the window + // during live resizing or else nothing will be drawn until after + // live resizing has ended. + // Also, flushing during [self windowDidResize:] eliminates flicker + // by forcing this window's SkSurface to recreate its underlying + // CAMetalLayer with the new size. Flushing in + // [self displayIfNeeded] does not eliminate flicker so apparently + // [self windowDidResize:] is called earlier. + if ( SkiaHelper::isVCLSkiaEnabled() ) + { + AquaSalGraphics* pGraphics = mpFrame->mpGraphics; + if ( pGraphics ) + pGraphics->Flush(); + } +#endif + + // tdf#152703 Force relayout during live resizing of window + // During a live resize, macOS floods the application with + // windowDidResize: notifications so sending a paint event does + // not trigger redrawing with the new size. + // Instead, force relayout by dispatching all pending internal + // events and firing any pending timers. + // Also, Application::Reschedule() can potentially display a + // modal dialog which will cause a hang so temporarily disable + // live resize by clamping the window's minimum and maximum sizes + // to the current frame size which in Application::Reschedule(). + NSRect aFrame = [self frame]; + NSSize aMinSize = [self minSize]; + NSSize aMaxSize = [self maxSize]; + [self setMinSize:aFrame.size]; + [self setMaxSize:aFrame.size]; + Application::Reschedule( true ); + [self setMinSize:aMinSize]; + [self setMaxSize:aMaxSize]; + + if ( mbInLiveResize ) + { + // tdf#152703 Force repaint after live resizing ends + // Repost this notification so that this selector will be called + // at least once after live resizing ends + if ( !mpLiveResizeTimer ) + { + mpLiveResizeTimer = [NSTimer scheduledTimerWithTimeInterval:0.1f target:self selector:@selector(windowDidResizeWithTimer:) userInfo:pNotification repeats:YES]; + if ( mpLiveResizeTimer ) + { + [mpLiveResizeTimer retain]; + + // The timer won't fire without a call to + // Application::Reschedule() unless we copy the fix for + // #i84055# from vcl/osx/saltimer.cxx and add the timer + // to the NSEventTrackingRunLoopMode run loop mode + [[NSRunLoop currentRunLoop] addTimer:mpLiveResizeTimer forMode:NSEventTrackingRunLoopMode]; + } + } + } + } + else + { + [self clearLiveResizeTimer]; mpFrame->SendPaintEvent(); + } } + + mbInWindowDidResize = NO; } -(void)windowDidMiniaturize: (NSNotification*)pNotification @@ -486,6 +568,12 @@ static AquaSalFrame* getMouseContainerFrame() [pView endExtTextInput:nFlags]; } +-(void)windowDidResizeWithTimer:(NSTimer *)pTimer +{ + if ( pTimer ) + [self windowDidResize:[pTimer userInfo]]; +} + @end @implementation SalFrameView @@ -565,9 +653,9 @@ static AquaSalFrame* getMouseContainerFrame() -(void)drawRect: (NSRect)aRect { - AquaSalInstance *pInstance = GetSalData()->mpInstance; - assert(pInstance); - if (!pInstance) + ImplSVData* pSVData = ImplGetSVData(); + assert( pSVData ); + if ( !pSVData ) return; SolarMutexGuard aGuard; @@ -575,10 +663,10 @@ static AquaSalFrame* getMouseContainerFrame() return; const bool bIsLiveResize = [self inLiveResize]; - const bool bWasLiveResize = pInstance->mbIsLiveResize; + const bool bWasLiveResize = pSVData->mpWinData->mbIsLiveResize; if (bWasLiveResize != bIsLiveResize) { - pInstance->mbIsLiveResize = bIsLiveResize; + pSVData->mpWinData->mbIsLiveResize = bIsLiveResize; Scheduler::Wakeup(); } @@ -1705,7 +1793,7 @@ static AquaSalFrame* getMouseContainerFrame() else mSelectedRange = NSMakeRange( selRange.location, selRange.location + selRange.length > mMarkedRange.length ? mMarkedRange.length - selRange.location : selRange.length ); - // If we are going to post uncommitted text, cache the string paramater + // If we are going to post uncommitted text, cache the string parameter // as is needed in both [self endExtTextInput] and // [self attributedSubstringForProposedRange:actualRange:] mpLastMarkedText = [aString retain]; @@ -1851,7 +1939,7 @@ static AquaSalFrame* getMouseContainerFrame() // the returned position won't be anywhere near the text cursor. So, // dispatch an empty SalEvent::ExtTextInput event, fetch the position, // and then dispatch a SalEvent::EndExtTextInput event. - BOOL bNeedsExtTextInput = ( mbInKeyInput && !mpLastMarkedText && mpLastEvent && [mpLastEvent type] == NSEventTypeKeyDown && [mpLastEvent isARepeat] ); + bool bNeedsExtTextInput = ( mbInKeyInput && !mpLastMarkedText && mpLastEvent && [mpLastEvent type] == NSEventTypeKeyDown && [mpLastEvent isARepeat] ); if ( bNeedsExtTextInput ) { SalExtTextInputEvent aInputEvent; @@ -2018,7 +2106,7 @@ static AquaSalFrame* getMouseContainerFrame() mbInCommitMarkedText = YES; if (nFlags & EndExtTextInputFlags::Complete) { - // Retain the last marked text as it will be releasd in + // Retain the last marked text as it will be released in // [self insertText:replacementText:] NSAttributedString *pText = [mpLastMarkedText retain]; [self insertText:pText replacementRange:NSMakeRange(0, [mpLastMarkedText length])]; diff --git a/vcl/osx/salinst.cxx b/vcl/osx/salinst.cxx index e8a4a94efc08..ee5a1b245750 100644 --- a/vcl/osx/salinst.cxx +++ b/vcl/osx/salinst.cxx @@ -368,7 +368,6 @@ VCLPLUG_OSX_PUBLIC SalInstance* create_SalInstance() AquaSalInstance::AquaSalInstance() : SalInstance(std::make_unique<SalYieldMutex>()) , mnActivePrintJobs( 0 ) - , mbIsLiveResize( false ) , mbNoYieldLock( false ) , mbTimerProcessed( false ) { @@ -556,6 +555,13 @@ static bool isWakeupEvent( NSEvent *pEvent ) bool AquaSalInstance::DoYield(bool bWait, bool bHandleAllCurrentEvents) { + // Related: tdf#152703 Eliminate potential blocking during live resize + // Some events and timers call Application::Reschedule() or + // Application::Yield() so don't block and wait for events when a + // window is in live resize + if ( ImplGetSVData()->mpWinData->mbIsLiveResize ) + bWait = false; + // ensure that the per thread autorelease pool is top level and // will therefore not be destroyed by cocoa implicitly SalData::ensureThreadAutoreleasePool(); @@ -565,7 +571,11 @@ bool AquaSalInstance::DoYield(bool bWait, bool bHandleAllCurrentEvents) ReleasePoolHolder aReleasePool; // first, process current user events - bool bHadEvent = DispatchUserEvents( bHandleAllCurrentEvents ); + // Related: tdf#152703 Eliminate potential blocking during live resize + // Only native events and timers need to be dispatched to redraw + // the window so skip dispatching user events when a window is in + // live resize + bool bHadEvent = ( !ImplGetSVData()->mpWinData->mbIsLiveResize && DispatchUserEvents( bHandleAllCurrentEvents ) ); if ( !bHandleAllCurrentEvents && bHadEvent ) return true; diff --git a/vcl/osx/saltimer.cxx b/vcl/osx/saltimer.cxx index 4c33c321d729..8af7de217678 100644 --- a/vcl/osx/saltimer.cxx +++ b/vcl/osx/saltimer.cxx @@ -83,7 +83,7 @@ void AquaSalTimer::Start( sal_uInt64 nMS ) return; } - m_bDirectTimeout = (0 == nMS) && !pSalData->mpInstance->mbIsLiveResize; + m_bDirectTimeout = (0 == nMS) && !ImplGetSVData()->mpWinData->mbIsLiveResize; if ( m_bDirectTimeout ) Stop(); else @@ -142,7 +142,7 @@ void AquaSalTimer::callTimerCallback() void AquaSalTimer::handleTimerElapsed() { - if ( m_bDirectTimeout || GetSalData()->mpInstance->mbIsLiveResize ) + if ( m_bDirectTimeout || ImplGetSVData()->mpWinData->mbIsLiveResize ) { // Stop the timer, as it is just invalidated after the firing function Stop(); diff --git a/vcl/skia/gdiimpl.cxx b/vcl/skia/gdiimpl.cxx index 896849baefa3..c218d5d565e1 100644 --- a/vcl/skia/gdiimpl.cxx +++ b/vcl/skia/gdiimpl.cxx @@ -372,6 +372,11 @@ void SkiaSalGraphicsImpl::performFlush() { SkiaZone zone; flushDrawing(); + // Related: tdf#152703 Eliminate flickering during live resizing of a window + // When in live resize, the SkiaSalGraphicsImpl class does not detect that + // the window size has changed until after the flush has been called so + // call checkSurface() to recreate the SkSurface if needed before flushing. + checkSurface(); if (mSurface) { if (mDirtyRect.intersect(SkIRect::MakeWH(GetWidth(), GetHeight()))) diff --git a/vcl/source/app/scheduler.cxx b/vcl/source/app/scheduler.cxx index 251b972fe5ac..f83a4bb04d32 100644 --- a/vcl/source/app/scheduler.cxx +++ b/vcl/source/app/scheduler.cxx @@ -359,6 +359,13 @@ void Scheduler::CallbackTaskScheduling() for (; nTaskPriority < PRIO_COUNT; ++nTaskPriority) { + // Related: tdf#152703 Eliminate potential blocking during live resize + // Only higher priority tasks need to be fired to redraw the window + // so skip firing potentially long-running tasks, such as the Writer + // idle layout timer, when a window is in live resize + if ( ImplGetSVData()->mpWinData->mbIsLiveResize && nTaskPriority == static_cast<int>(TaskPriority::LOWEST) ) + continue; + pSchedulerData = rSchedCtx.mpFirstSchedulerData[nTaskPriority]; pPrevSchedulerData = nullptr; while (pSchedulerData) commit ee464203aef8673fda1c67821684d1e74511ff22 Author: Patrick Luby <plub...@neooffice.org> AuthorDate: Tue Jan 17 09:51:10 2023 -0500 Commit: Andras Timar <andras.ti...@collabora.com> CommitDate: Mon Jan 23 09:41:35 2023 +0100 tdf#148453 Fix crash by turning off optimization for Objective-C selector The default attributes sequence sometimes crashes when it is released but only when compiler optimization is enabled, so disable optimization for the +[AquaA11yTextAttributesWrapper createAttributedStringForElement] selector. Also, disabling optimization by itself is apparently not enough to stop the crashing. Acquiring the solar mutex during native accessibility calls is also needed. Native accessibility calls are called from native input sources in [NSApp nextEventMatchingMask:untilDate:inMode:dequeue:]. Since AquaSalInstance::DoYield() releases the solar mutex before calling [NSApp nextEventMatchingMask:untilDate:inMode:dequeue:], we need to always acquire the solar mutex during all NSAccessibility selectors (both the old informal protocol and the newer formal protocol) that we implement. Change-Id: I9b715e17e9c5a32b7ce28815e288b2af236c3cc6 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/145742 Tested-by: Jenkins Reviewed-by: Patrick Luby <plub...@neooffice.org> (cherry picked from commit de1d75a0cd25f239cdc751dec75c9019fbcabd8e) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/145812 diff --git a/vcl/osx/a11ytextattributeswrapper.mm b/vcl/osx/a11ytextattributeswrapper.mm index 84a9b27e54cc..9db1ba91307d 100644 --- a/vcl/osx/a11ytextattributeswrapper.mm +++ b/vcl/osx/a11ytextattributeswrapper.mm @@ -300,7 +300,11 @@ using namespace ::com::sun::star::uno; [AquaA11yTextAttributesWrapper addMarkup:markup withType:css::text::TextMarkupType::SPELLCHECK toString:string inRange:range]; } -+(NSMutableAttributedString *)createAttributedStringForElement:(AquaA11yWrapper *)wrapper inOrigRange:(id)origRange { +// tdf#148453 Fix crash by turning off optimization for Objective-C selector +// The default attributes sequence sometimes crashes when it is released but +// only when compiler optimization is enabled, so disable optimization for the +// +[AquaA11yTextAttributesWrapper createAttributedStringForElement] selector. ++(NSMutableAttributedString *)createAttributedStringForElement:(AquaA11yWrapper *)wrapper inOrigRange:(id)origRange __attribute__((optnone)) { static const Sequence < OUString > emptySequence; // vars NSMutableAttributedString * string = nil; diff --git a/vcl/osx/a11ywrapper.mm b/vcl/osx/a11ywrapper.mm index beb40f8851b3..73abb6050733 100644 --- a/vcl/osx/a11ywrapper.mm +++ b/vcl/osx/a11ywrapper.mm @@ -682,6 +682,9 @@ static std::ostream &operator<<(std::ostream &s, NSObject *obj) { #pragma mark Accessibility Protocol -(id)accessibilityAttributeValue:(NSString *)attribute { + // Related: tdf#148453 Acquire solar mutex during native accessibility calls + SolarMutexGuard aGuard; + SAL_INFO("vcl.a11y", "[" << self << " accessibilityAttributeValue:" << attribute << "]"); // #i90575# guard NSAccessibility protocol against unwanted access if ( isPopupMenuOpen ) { @@ -712,6 +715,9 @@ static std::ostream &operator<<(std::ostream &s, NSObject *obj) { } -(BOOL)accessibilityIsIgnored { + // Related: tdf#148453 Acquire solar mutex during native accessibility calls + SolarMutexGuard aGuard; + SAL_INFO("vcl.a11y", "[" << self << " accessibilityIsIgnored]"); // #i90575# guard NSAccessibility protocol against unwanted access if ( isPopupMenuOpen ) { @@ -736,6 +742,9 @@ static std::ostream &operator<<(std::ostream &s, NSObject *obj) { } -(NSArray *)accessibilityAttributeNames { + // Related: tdf#148453 Acquire solar mutex during native accessibility calls + SolarMutexGuard aGuard; + SAL_INFO("vcl.a11y", "[" << self << " accessibilityAttributeNames]"); // #i90575# guard NSAccessibility protocol against unwanted access if ( isPopupMenuOpen ) { @@ -817,6 +826,9 @@ static std::ostream &operator<<(std::ostream &s, NSObject *obj) { } -(BOOL)accessibilityIsAttributeSettable:(NSString *)attribute { + // Related: tdf#148453 Acquire solar mutex during native accessibility calls + SolarMutexGuard aGuard; + SAL_INFO("vcl.a11y", "[" << self << " accessibilityAttributeIsSettable:" << attribute << "]"); bool isSettable = false; if ( [ self accessibleText ] ) { @@ -835,6 +847,9 @@ static std::ostream &operator<<(std::ostream &s, NSObject *obj) { } -(NSArray *)accessibilityParameterizedAttributeNames { + // Related: tdf#148453 Acquire solar mutex during native accessibility calls + SolarMutexGuard aGuard; + SAL_INFO("vcl.a11y", "[" << self << " accessibilityParameterizedAttributeNames]"); NSMutableArray * attributeNames = [ [ NSMutableArray alloc ] init ]; // Special Attributes depending on interface @@ -845,6 +860,9 @@ static std::ostream &operator<<(std::ostream &s, NSObject *obj) { } -(id)accessibilityAttributeValue:(NSString *)attribute forParameter:(id)parameter { + // Related: tdf#148453 Acquire solar mutex during native accessibility calls + SolarMutexGuard aGuard; + SAL_INFO("vcl.a11y", "[" << self << " accessibilityAttributeValue:" << attribute << " forParameter:" << (static_cast<NSObject*>(parameter)) << "]"); SEL methodSelector = [ self selectorForAttribute: attribute asGetter: YES withGetterParameter: YES ]; if ( [ self respondsToSelector: methodSelector ] ) { @@ -860,6 +878,9 @@ static std::ostream &operator<<(std::ostream &s, NSObject *obj) { } -(void)accessibilitySetValue:(id)value forAttribute:(NSString *)attribute { + // Related: tdf#148453 Acquire solar mutex during native accessibility calls + SolarMutexGuard aGuard; + SAL_INFO("vcl.a11y", "[" << self << " accessibilitySetValue:" << (static_cast<NSObject*>(value)) << " forAttribute:" << attribute << "]"); SEL methodSelector = [ self selectorForAttribute: attribute asGetter: NO withGetterParameter: NO ]; if ( [ AquaA11yComponentWrapper respondsToSelector: methodSelector ] ) { @@ -877,6 +898,9 @@ static std::ostream &operator<<(std::ostream &s, NSObject *obj) { } -(id)accessibilityFocusedUIElement { + // Related: tdf#148453 Acquire solar mutex during native accessibility calls + SolarMutexGuard aGuard; + SAL_INFO("vcl.a11y", "[" << self << " accessibilityFocusedUIElement]"); // #i90575# guard NSAccessibility protocol against unwanted access if ( isPopupMenuOpen ) { @@ -937,6 +961,9 @@ static std::ostream &operator<<(std::ostream &s, NSObject *obj) { } -(void)accessibilityPerformAction:(NSString *)action { + // Related: tdf#148453 Acquire solar mutex during native accessibility calls + SolarMutexGuard aGuard; + SAL_INFO("vcl.a11y", "[" << self << " accessibilityPerformAction:" << action << "]"); AquaA11yWrapper * actionResponder = [ self actionResponder ]; if ( actionResponder ) { @@ -945,6 +972,9 @@ static std::ostream &operator<<(std::ostream &s, NSObject *obj) { } -(NSArray *)accessibilityActionNames { + // Related: tdf#148453 Acquire solar mutex during native accessibility calls + SolarMutexGuard aGuard; + SAL_INFO("vcl.a11y", "[" << self << " accessibilityActionNames]"); NSArray * actionNames = nil; AquaA11yWrapper * actionResponder = [ self actionResponder ]; @@ -1030,6 +1060,9 @@ static Reference < XAccessibleContext > hitTestRunner ( css::awt::Point point, } -(id)accessibilityHitTest:(NSPoint)point { + // Related: tdf#148453 Acquire solar mutex during native accessibility calls + SolarMutexGuard aGuard; + SAL_INFO("vcl.a11y", "[" << self << " accessibilityHitTest:" << point << "]"); static id wrapper = nil; if ( nil != wrapper ) { diff --git a/vcl/osx/a11ywrapperbutton.mm b/vcl/osx/a11ywrapperbutton.mm index ca5f16af3d42..a2c0d0398fe9 100644 --- a/vcl/osx/a11ywrapperbutton.mm +++ b/vcl/osx/a11ywrapperbutton.mm @@ -18,6 +18,7 @@ */ +#include <vcl/svapp.hxx> #include <osx/salinst.h> #include "a11ywrapperbutton.h" @@ -36,6 +37,9 @@ } -(NSArray *)accessibilityAttributeNames { + // Related: tdf#148453 Acquire solar mutex during native accessibility calls + SolarMutexGuard aGuard; + // Default Attributes NSMutableArray * attributeNames = [ NSMutableArray arrayWithArray: [ super accessibilityAttributeNames ] ]; // Special Attributes and removing unwanted attributes depending on role diff --git a/vcl/osx/a11ywrappercheckbox.mm b/vcl/osx/a11ywrappercheckbox.mm index d67c5b610ded..9e0f221985c9 100644 --- a/vcl/osx/a11ywrappercheckbox.mm +++ b/vcl/osx/a11ywrappercheckbox.mm @@ -18,6 +18,7 @@ */ +#include <vcl/svapp.hxx> #include <osx/salinst.h> #include "a11ywrappercheckbox.h" @@ -36,6 +37,9 @@ } -(BOOL)accessibilityIsAttributeSettable:(NSString *)attribute { + // Related: tdf#148453 Acquire solar mutex during native accessibility calls + SolarMutexGuard aGuard; + if ( [ attribute isEqualToString: NSAccessibilityValueAttribute ] ) { return NO; } @@ -43,6 +47,9 @@ } -(NSArray *)accessibilityAttributeNames { + // Related: tdf#148453 Acquire solar mutex during native accessibility calls + SolarMutexGuard aGuard; + // Default Attributes NSMutableArray * attributeNames = [ NSMutableArray arrayWithArray: [ super accessibilityAttributeNames ] ]; // Remove text-specific attributes diff --git a/vcl/osx/a11ywrappercombobox.mm b/vcl/osx/a11ywrappercombobox.mm index 962a66914863..bfcef7275e33 100644 --- a/vcl/osx/a11ywrappercombobox.mm +++ b/vcl/osx/a11ywrappercombobox.mm @@ -18,6 +18,7 @@ */ +#include <vcl/svapp.hxx> #include <osx/salinst.h> #include "a11ywrappercombobox.h" @@ -110,6 +111,9 @@ using namespace ::com::sun::star::uno; #pragma mark Accessibility Protocol -(BOOL)accessibilityIsAttributeSettable:(NSString *)attribute { + // Related: tdf#148453 Acquire solar mutex during native accessibility calls + SolarMutexGuard aGuard; + if ( [ self textArea ] != nil && ( [ attribute isEqualToString: NSAccessibilitySelectedTextAttribute ] || [ attribute isEqualToString: NSAccessibilitySelectedTextRangeAttribute ] @@ -120,6 +124,9 @@ using namespace ::com::sun::star::uno; } -(void)accessibilitySetValue:(id)value forAttribute:(NSString *)attribute { + // Related: tdf#148453 Acquire solar mutex during native accessibility calls + SolarMutexGuard aGuard; + if ( [ self textArea ] != nil && ( [ attribute isEqualToString: NSAccessibilitySelectedTextAttribute ] || [ attribute isEqualToString: NSAccessibilitySelectedTextRangeAttribute ] @@ -130,6 +137,9 @@ using namespace ::com::sun::star::uno; } -(NSArray *)accessibilityAttributeNames { + // Related: tdf#148453 Acquire solar mutex during native accessibility calls + SolarMutexGuard aGuard; + // Default Attributes NSMutableArray * attributeNames = [ NSMutableArray arrayWithArray: [ super accessibilityAttributeNames ] ]; // Special Attributes and removing unwanted attributes depending on role diff --git a/vcl/osx/a11ywrappergroup.mm b/vcl/osx/a11ywrappergroup.mm index 39cbd9adfcbc..7ed70d47baba 100644 --- a/vcl/osx/a11ywrappergroup.mm +++ b/vcl/osx/a11ywrappergroup.mm @@ -18,6 +18,7 @@ */ +#include <vcl/svapp.hxx> #include <osx/salinst.h> #include "a11ywrappergroup.h" @@ -30,6 +31,9 @@ } -(NSArray *)accessibilityAttributeNames { + // Related: tdf#148453 Acquire solar mutex during native accessibility calls + SolarMutexGuard aGuard; + // Default Attributes NSMutableArray * attributeNames = [ NSMutableArray arrayWithArray: [ super accessibilityAttributeNames ] ]; // Special Attributes and removing unwanted attributes depending on role diff --git a/vcl/osx/a11ywrapperlist.mm b/vcl/osx/a11ywrapperlist.mm index 9b0bac733bf9..25b3fa37ac62 100644 --- a/vcl/osx/a11ywrapperlist.mm +++ b/vcl/osx/a11ywrapperlist.mm @@ -18,6 +18,7 @@ */ +#include <vcl/svapp.hxx> #include <osx/salinst.h> #include "a11ywrapperlist.h" @@ -28,6 +29,9 @@ using namespace ::com::sun::star::accessibility; @implementation AquaA11yWrapperList : AquaA11yWrapper -(NSArray *)accessibilityAttributeNames { + // Related: tdf#148453 Acquire solar mutex during native accessibility calls + SolarMutexGuard aGuard; + // Default Attributes NSMutableArray * attributeNames = [ NSMutableArray arrayWithArray: [ super accessibilityAttributeNames ] ]; // Special Attributes and removing unwanted attributes depending on role diff --git a/vcl/osx/a11ywrapperradiobutton.mm b/vcl/osx/a11ywrapperradiobutton.mm index 21fd9529bb96..5022cc18c22b 100644 --- a/vcl/osx/a11ywrapperradiobutton.mm +++ b/vcl/osx/a11ywrapperradiobutton.mm @@ -18,6 +18,7 @@ */ +#include <vcl/svapp.hxx> #include <osx/salinst.h> #include "a11ywrapperradiobutton.h" #include "a11ytextwrapper.h" @@ -35,6 +36,9 @@ } -(BOOL)accessibilityIsAttributeSettable:(NSString *)attribute { + // Related: tdf#148453 Acquire solar mutex during native accessibility calls + SolarMutexGuard aGuard; + if ( [ attribute isEqualToString: NSAccessibilityValueAttribute ] ) { return NO; } @@ -42,6 +46,9 @@ } -(NSArray *)accessibilityAttributeNames { + // Related: tdf#148453 Acquire solar mutex during native accessibility calls + SolarMutexGuard aGuard; + // Default Attributes NSMutableArray * attributeNames = [ NSMutableArray arrayWithArray: [ super accessibilityAttributeNames ] ]; // Special Attributes and removing unwanted attributes depending on role diff --git a/vcl/osx/a11ywrapperradiogroup.mm b/vcl/osx/a11ywrapperradiogroup.mm index 557e0b1bca15..9768dbbb6988 100644 --- a/vcl/osx/a11ywrapperradiogroup.mm +++ b/vcl/osx/a11ywrapperradiogroup.mm @@ -18,6 +18,7 @@ */ +#include <vcl/svapp.hxx> #include <osx/salinst.h> #include "a11ywrapperradiogroup.h" #include "a11ytextwrapper.h" @@ -27,6 +28,9 @@ @implementation AquaA11yWrapperRadioGroup : AquaA11yWrapper -(NSArray *)accessibilityAttributeNames { + // Related: tdf#148453 Acquire solar mutex during native accessibility calls + SolarMutexGuard aGuard; + // Default Attributes NSMutableArray * attributeNames = [ NSMutableArray arrayWithArray: [ super accessibilityAttributeNames ] ]; // Special Attributes and removing unwanted attributes depending on role diff --git a/vcl/osx/a11ywrapperrow.mm b/vcl/osx/a11ywrapperrow.mm index 1b7ee56dd456..0c140c82c62c 100644 --- a/vcl/osx/a11ywrapperrow.mm +++ b/vcl/osx/a11ywrapperrow.mm @@ -18,6 +18,7 @@ */ +#include <vcl/svapp.hxx> #include <osx/salinst.h> #include "a11ywrapperrow.h" @@ -33,6 +34,9 @@ } -(NSArray *)accessibilityAttributeNames { + // Related: tdf#148453 Acquire solar mutex during native accessibility calls + SolarMutexGuard aGuard; + // Default Attributes NSMutableArray * attributeNames = [ NSMutableArray arrayWithArray: [ super accessibilityAttributeNames ] ]; // Special Attributes and removing unwanted attributes depending on role diff --git a/vcl/osx/a11ywrapperscrollarea.mm b/vcl/osx/a11ywrapperscrollarea.mm index b0b963a6b403..22037220d409 100644 --- a/vcl/osx/a11ywrapperscrollarea.mm +++ b/vcl/osx/a11ywrapperscrollarea.mm @@ -18,6 +18,7 @@ */ +#include <vcl/svapp.hxx> #include <osx/salinst.h> #include "a11ywrapperscrollarea.h" @@ -59,6 +60,9 @@ } -(NSArray *)accessibilityAttributeNames { + // Related: tdf#148453 Acquire solar mutex during native accessibility calls + SolarMutexGuard aGuard; + // Default Attributes NSMutableArray * attributeNames = [ NSMutableArray arrayWithArray: [ super accessibilityAttributeNames ] ]; // Special Attributes and removing unwanted attributes depending on role diff --git a/vcl/osx/a11ywrapperscrollbar.mm b/vcl/osx/a11ywrapperscrollbar.mm index a4b7a246b411..4a4612d3bbd0 100644 --- a/vcl/osx/a11ywrapperscrollbar.mm +++ b/vcl/osx/a11ywrapperscrollbar.mm @@ -18,6 +18,7 @@ */ +#include <vcl/svapp.hxx> #include <osx/salinst.h> #include "a11ywrapperscrollbar.h" @@ -31,6 +32,9 @@ using namespace ::com::sun::star::accessibility; @implementation AquaA11yWrapperScrollBar : AquaA11yWrapper -(NSArray *)accessibilityAttributeNames { + // Related: tdf#148453 Acquire solar mutex during native accessibility calls + SolarMutexGuard aGuard; + // Default Attributes NSMutableArray * attributeNames = [ NSMutableArray arrayWithArray: [ super accessibilityAttributeNames ] ]; // Special Attributes and removing unwanted attributes depending on role diff --git a/vcl/osx/a11ywrappersplitter.mm b/vcl/osx/a11ywrappersplitter.mm index b43928bd43cd..39ec496af2ac 100644 --- a/vcl/osx/a11ywrappersplitter.mm +++ b/vcl/osx/a11ywrappersplitter.mm @@ -18,6 +18,7 @@ */ +#include <vcl/svapp.hxx> #include <osx/salinst.h> #include "a11ywrappersplitter.h" @@ -28,6 +29,9 @@ using namespace ::com::sun::star::accessibility; @implementation AquaA11yWrapperSplitter : AquaA11yWrapper -(NSArray *)accessibilityAttributeNames { + // Related: tdf#148453 Acquire solar mutex during native accessibility calls + SolarMutexGuard aGuard; + // Default Attributes NSMutableArray * attributeNames = [ NSMutableArray arrayWithArray: [ super accessibilityAttributeNames ] ]; // Special Attributes and removing unwanted attributes depending on role diff --git a/vcl/osx/a11ywrapperstatictext.mm b/vcl/osx/a11ywrapperstatictext.mm index cd4728544c00..114c4179e8d6 100644 --- a/vcl/osx/a11ywrapperstatictext.mm +++ b/vcl/osx/a11ywrapperstatictext.mm @@ -18,6 +18,7 @@ */ +#include <vcl/svapp.hxx> #include <osx/salinst.h> #include "a11ywrapperstatictext.h" @@ -34,6 +35,9 @@ } -(NSArray *)accessibilityAttributeNames { + // Related: tdf#148453 Acquire solar mutex during native accessibility calls + SolarMutexGuard aGuard; + // Default Attributes NSMutableArray * attributeNames = [ NSMutableArray arrayWithArray: [ super accessibilityAttributeNames ] ]; // Special Attributes and removing unwanted attributes depending on role diff --git a/vcl/osx/a11ywrappertabgroup.mm b/vcl/osx/a11ywrappertabgroup.mm index ad5971865449..3d32ccc041f0 100644 --- a/vcl/osx/a11ywrappertabgroup.mm +++ b/vcl/osx/a11ywrappertabgroup.mm @@ -18,6 +18,7 @@ */ +#include <vcl/svapp.hxx> #include <osx/salinst.h> #include "a11ywrappertabgroup.h" @@ -26,6 +27,9 @@ @implementation AquaA11yWrapperTabGroup : AquaA11yWrapper -(NSArray *)accessibilityAttributeNames { + // Related: tdf#148453 Acquire solar mutex during native accessibility calls + SolarMutexGuard aGuard; + // Default Attributes NSMutableArray * attributeNames = [ NSMutableArray arrayWithArray: [ super accessibilityAttributeNames ] ]; // Special Attributes and removing unwanted attributes depending on role diff --git a/vcl/osx/a11ywrappertextarea.mm b/vcl/osx/a11ywrappertextarea.mm index 3f51f3541bd1..354030fb9aef 100644 --- a/vcl/osx/a11ywrappertextarea.mm +++ b/vcl/osx/a11ywrappertextarea.mm @@ -18,6 +18,7 @@ */ +#include <vcl/svapp.hxx> #include <osx/salinst.h> #include "a11ywrappertextarea.h" @@ -26,6 +27,9 @@ @implementation AquaA11yWrapperTextArea : AquaA11yWrapper -(NSArray *)accessibilityAttributeNames { + // Related: tdf#148453 Acquire solar mutex during native accessibility calls + SolarMutexGuard aGuard; + // Default Attributes NSMutableArray * attributeNames = [ NSMutableArray arrayWithArray: [ super accessibilityAttributeNames ] ]; // Special Attributes and removing unwanted attributes depending on role diff --git a/vcl/osx/a11ywrappertoolbar.mm b/vcl/osx/a11ywrappertoolbar.mm index 05e9b30e255e..28b5d01328f0 100644 --- a/vcl/osx/a11ywrappertoolbar.mm +++ b/vcl/osx/a11ywrappertoolbar.mm @@ -18,6 +18,7 @@ */ +#include <vcl/svapp.hxx> #include <osx/salinst.h> #include "a11ywrappertoolbar.h" @@ -26,6 +27,9 @@ @implementation AquaA11yWrapperToolbar : AquaA11yWrapper -(NSArray *)accessibilityAttributeNames { + // Related: tdf#148453 Acquire solar mutex during native accessibility calls + SolarMutexGuard aGuard; + // Default Attributes NSMutableArray * attributeNames = [ NSMutableArray arrayWithArray: [ super accessibilityAttributeNames ] ]; // Special Attributes and removing unwanted attributes depending on role commit 899c361dab1d527469f3f17bc3938a19cc3ff7f0 Author: Michael Stahl <michael.st...@allotropia.de> AuthorDate: Thu Jan 19 18:45:39 2023 +0100 Commit: Andras Timar <andras.ti...@collabora.com> CommitDate: Mon Jan 23 09:41:35 2023 +0100 sw: crashtesting forum-mso-en-12641.docx, fix assert in FindFieldSep The fieldmark may overlap a section; at the start was considered here, but at the end was not and so the assertion wrongly fired. Change-Id: I118bc36c2d9c4ca7028a583278d0f193537c4cb2 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/145826 Tested-by: Jenkins Reviewed-by: Michael Stahl <michael.st...@allotropia.de> (cherry picked from commit 959f64dbb85d1785dbea5a4d2a41519c98769a7c) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/145801 Reviewed-by: Miklos Vajna <vmik...@collabora.com> diff --git a/sw/source/core/crsr/bookmark.cxx b/sw/source/core/crsr/bookmark.cxx index feb7e77a3163..2520e6312b79 100644 --- a/sw/source/core/crsr/bookmark.cxx +++ b/sw/source/core/crsr/bookmark.cxx @@ -113,7 +113,8 @@ namespace sw::mark } else { - assert(pNode->IsNoTextNode() || pNode->IsSectionNode()); + assert(pNode->IsNoTextNode() || pNode->IsSectionNode() + || (pNode->IsEndNode() && pNode->StartOfSectionNode()->IsSectionNode())); } } assert(ret); // must have found it commit ec54b0c37fc4b76b9a54a4967da551f2ef6dbc0b Author: Michael Stahl <michael.st...@allotropia.de> AuthorDate: Thu Jan 19 12:28:57 2023 +0100 Commit: Andras Timar <andras.ti...@collabora.com> CommitDate: Mon Jan 23 09:41:35 2023 +0100 tdf#153039 ucb: webdav-curl: fix POST, which was actually doing PUT The problem is that first CURLOPT_POST was set and later CURLOPT_UPLOAD, which overrides the HTTP method to PUT. Move this out to the 4 functions that need it. Change-Id: Ibd555dcc00a03baa1bb300a9ab9905f383179c67 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/145786 Tested-by: Jenkins Reviewed-by: Michael Stahl <michael.st...@allotropia.de> (cherry picked from commit 261b1237532f431963358a7b4ac5fd1ad6e5d223) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/145796 Reviewed-by: Miklos Vajna <vmik...@collabora.com> diff --git a/ucb/source/ucp/webdav-curl/CurlSession.cxx b/ucb/source/ucp/webdav-curl/CurlSession.cxx index 25804dbacc4f..8e64608bfc8b 100644 --- a/ucb/source/ucp/webdav-curl/CurlSession.cxx +++ b/ucb/source/ucp/webdav-curl/CurlSession.cxx @@ -875,9 +875,6 @@ auto CurlProcessor::ProcessRequestImpl( oUploadSource.emplace(*pInData); rc = curl_easy_setopt(rSession.m_pCurl.get(), CURLOPT_READDATA, &*oUploadSource); assert(rc == CURLE_OK); - // libcurl won't upload without setting this - rc = curl_easy_setopt(rSession.m_pCurl.get(), CURLOPT_UPLOAD, 1L); - assert(rc == CURLE_OK); } rSession.m_ErrorBuffer[0] = '\0'; @@ -1638,6 +1635,7 @@ auto CurlProcessor::PropFind( curl_off_t const len(xSeqOutStream->getWrittenBytes().getLength()); ::std::vector<CurlOption> const options{ + { CURLOPT_UPLOAD, 1L, nullptr }, { CURLOPT_CUSTOMREQUEST, "PROPFIND", "CURLOPT_CUSTOMREQUEST" }, // note: Sharepoint cannot handle "Transfer-Encoding: chunked" { CURLOPT_INFILESIZE_LARGE, len, nullptr, CurlOption::Type::CurlOffT } @@ -1792,6 +1790,7 @@ auto CurlSession::PROPPATCH(OUString const& rURIReference, curl_off_t const len(xSeqOutStream->getWrittenBytes().getLength()); ::std::vector<CurlOption> const options{ + { CURLOPT_UPLOAD, 1L, nullptr }, { CURLOPT_CUSTOMREQUEST, "PROPPATCH", "CURLOPT_CUSTOMREQUEST" }, // note: Sharepoint cannot handle "Transfer-Encoding: chunked" { CURLOPT_INFILESIZE_LARGE, len, nullptr, CurlOption::Type::CurlOffT } @@ -1945,8 +1944,10 @@ auto CurlSession::PUT(OUString const& rURIReference, // lock m_Mutex after accessing global LockStore to avoid deadlock // note: Nextcloud 20 cannot handle "Transfer-Encoding: chunked" - ::std::vector<CurlOption> const options{ { CURLOPT_INFILESIZE_LARGE, len, nullptr, - CurlOption::Type::CurlOffT } }; + ::std::vector<CurlOption> const options{ + { CURLOPT_UPLOAD, 1L, nullptr }, // libcurl won't upload without setting this + { CURLOPT_INFILESIZE_LARGE, len, nullptr, CurlOption::Type::CurlOffT } + }; CurlProcessor::ProcessRequest(*this, uri, "PUT", options, &rEnv, ::std::move(pList), nullptr, &rxInStream, nullptr); @@ -2127,6 +2128,7 @@ auto CurlProcessor::Lock( } ::std::vector<CurlOption> const options{ + { CURLOPT_UPLOAD, 1L, nullptr }, { CURLOPT_CUSTOMREQUEST, "LOCK", "CURLOPT_CUSTOMREQUEST" }, // note: Sharepoint cannot handle "Transfer-Encoding: chunked" { CURLOPT_INFILESIZE_LARGE, len, nullptr, CurlOption::Type::CurlOffT } commit 44c8d3859c2fc54cc71ffbf606f512f652a263d6 Author: Miklos Vajna <vmik...@collabora.com> AuthorDate: Thu Jan 19 15:46:37 2023 +0100 Commit: Andras Timar <andras.ti...@collabora.com> CommitDate: Mon Jan 23 09:41:35 2023 +0100 sw XHTML export: use CSS instead of <center> for tables <center> is not valid XHTML, have to use CSS styling instead. HTML export uses <center> by default around tables where the alignment is center. Fix the problem by avoiding <center> in the XHTML case and set the left and right margin to auto, which means: If the values of margin-left and margin-right are both auto, the calculated space is evenly distributed. according to <https://developer.mozilla.org/en-US/docs/Web/CSS/margin-left>. The import will be adjusted to recognize the new markup in a follow-up change. Change-Id: I51e3507e9cde713f961b783378d66db59194a6ca Reviewed-on: https://gerrit.libreoffice.org/c/core/+/145814 Reviewed-by: Miklos Vajna <vmik...@collabora.com> Tested-by: Jenkins (cherry picked from commit 6ce374140f3bd1cede959ccc8da69fdacecff191) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/145803 Reviewed-by: Michael Stahl <michael.st...@allotropia.de> diff --git a/sw/qa/filter/html/html.cxx b/sw/qa/filter/html/html.cxx index 537b437c4bdb..65f67b7378d1 100644 --- a/sw/qa/filter/html/html.cxx +++ b/sw/qa/filter/html/html.cxx @@ -196,6 +196,36 @@ CPPUNIT_TEST_FIXTURE(Test, testTableRowSpanInAllCells) assertXPathNoAttribute(pHtmlDoc, "//tr[1]/td[1]", "rowspan"); assertXPath(pHtmlDoc, "//tr", 1); } + +CPPUNIT_TEST_FIXTURE(Test, testCenteredTableCSSExport) +{ + // Given a document with a centered table: + createSwDoc(); + SwDoc* pDoc = getSwDoc(); + SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell(); + SwInsertTableOptions aTableOptions(SwInsertTableFlags::NONE, 0); + pWrtShell->InsertTable(aTableOptions, 1, 1); + pWrtShell->MoveTable(GotoPrevTable, fnTableStart); + SfxItemSetFixed<RES_FRMATR_BEGIN, RES_FRMATR_END - 1> aSet(pWrtShell->GetAttrPool()); + SwFormatHoriOrient aHoriOrientItem(/*nX=*/0, text::HoriOrientation::CENTER); + aSet.Put(aHoriOrientItem); + pWrtShell->SetTableAttr(aSet); + + // When exporting to XHTML: + setFilterOptions("xhtmlns=reqif-xhtml"); + save("HTML (StarWriter)"); + + // Then make sure that CSS is used to horizontally position the table: + SvMemoryStream aStream; + WrapReqifFromTempFile(aStream); + xmlDocUniquePtr pXmlDoc = parseXmlStream(&aStream); + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 0 + // - Actual : 1 + // i.e <center> was used to position the table, not CSS. + assertXPath(pXmlDoc, "//reqif-xhtml:center", 0); + assertXPath(pXmlDoc, "//reqif-xhtml:table", "style", "margin-left: auto; margin-right: auto"); +} } CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/sw/source/filter/html/css1atr.cxx b/sw/source/filter/html/css1atr.cxx index 135494df00ca..28c5cc5dea8f 100644 --- a/sw/source/filter/html/css1atr.cxx +++ b/sw/source/filter/html/css1atr.cxx @@ -2064,6 +2064,17 @@ void SwHTMLWriter::OutCSS1_TableFrameFormatOptions( const SwFrameFormat& rFrameF if( SfxItemState::SET==rItemSet.GetItemState( RES_LAYOUT_SPLIT, false, &pItem ) ) OutCSS1_SwFormatLayoutSplit( *this, *pItem ); + if (mbXHTML) + { + sal_Int16 eTabHoriOri = rFrameFormat.GetHoriOrient().GetHoriOrient(); + if (eTabHoriOri == text::HoriOrientation::CENTER) + { + // Emit XHTML's center using inline CSS. + OutCSS1_Property(sCSS1_P_margin_left, "auto", nullptr, sw::Css1Background::Table); + OutCSS1_Property(sCSS1_P_margin_right, "auto", nullptr, sw::Css1Background::Table); + } + } + if( !m_bFirstCSS1Property ) Strm().WriteChar( '\"' ); } diff --git a/sw/source/filter/html/htmltabw.cxx b/sw/source/filter/html/htmltabw.cxx index ddb8c8eb5f10..a1dee0f75333 100644 --- a/sw/source/filter/html/htmltabw.cxx +++ b/sw/source/filter/html/htmltabw.cxx @@ -1113,7 +1113,13 @@ Writer& OutHTML_SwTableNode( Writer& rWrt, SwTableNode & rNode, if( rHTMLWrt.m_bLFPossible ) rHTMLWrt.OutNewLine(); // <CENTER> in new line if( text::HoriOrientation::CENTER==eDivHoriOri ) - HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), Concat2View(rHTMLWrt.GetNamespace() + OOO_STRING_SVTOOLS_HTML_center) ); + { + if (!rHTMLWrt.mbXHTML) + { + // Not XHTML's css center: start <center>. + HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), Concat2View(rHTMLWrt.GetNamespace() + OOO_STRING_SVTOOLS_HTML_center) ); + } + } else { OStringLiteral sOut = OOO_STRING_SVTOOLS_HTML_division @@ -1166,7 +1172,11 @@ Writer& OutHTML_SwTableNode( Writer& rWrt, SwTableNode & rNode, OString aTag = text::HoriOrientation::CENTER == eDivHoriOri ? OOO_STRING_SVTOOLS_HTML_center : OOO_STRING_SVTOOLS_HTML_division; - HTMLOutFuncs::Out_AsciiTag(rWrt.Strm(), Concat2View(rHTMLWrt.GetNamespace() + aTag), false); + if (!rHTMLWrt.mbXHTML || eDivHoriOri != text::HoriOrientation::CENTER) + { + // Not XHTML's css center: end <center>. + HTMLOutFuncs::Out_AsciiTag(rWrt.Strm(), Concat2View(rHTMLWrt.GetNamespace() + aTag), false); + } rHTMLWrt.m_bLFPossible = true; } commit 9b1ebd56c4b290a185a07e08a05852a59bdfc5d0 Author: Caolán McNamara <caol...@redhat.com> AuthorDate: Thu Jan 19 11:13:50 2023 +0000 Commit: Andras Timar <andras.ti...@collabora.com> CommitDate: Mon Jan 23 09:41:34 2023 +0100 tdf#149412 gtk3: show all selected rows in dnd icon otherwise it looks like only one row is getting moved Change-Id: Ie0b63a9c3cea377c3753785d9c6f7958cbc7ac1b Reviewed-on: https://gerrit.libreoffice.org/c/core/+/145820 Tested-by: Jenkins Reviewed-by: Adolfo Jayme Barrientos <fit...@ubuntu.com> diff --git a/vcl/unx/gtk3/gtkinst.cxx b/vcl/unx/gtk3/gtkinst.cxx index bd0da255a323..e369b587b9b4 100644 --- a/vcl/unx/gtk3/gtkinst.cxx +++ b/vcl/unx/gtk3/gtkinst.cxx @@ -2829,8 +2829,10 @@ private: #endif int m_nPressedButton; #if !GTK_CHECK_VERSION(4, 0, 0) +protected: int m_nPressStartX; int m_nPressStartY; +private: #endif ImplSVEvent* m_pDragCancelEvent; GtkCssProvider* m_pBgCssProvider; @@ -3010,6 +3012,14 @@ private: return true; } + /* Save press to possibly begin a drag */ + if (pEvent->type != GDK_BUTTON_RELEASE) + { + m_nPressedButton = pEvent->button; + m_nPressStartX = pEvent->x; + m_nPressStartY = pEvent->y; + } + if (!m_aMousePressHdl.IsSet() && !m_aMouseReleaseHdl.IsSet()) return false; @@ -3060,14 +3070,6 @@ private: return false; } - /* Save press to possibly begin a drag */ - if (pEvent->type != GDK_BUTTON_RELEASE) - { - m_nPressedButton = pEvent->button; - m_nPressStartX = pEvent->x; - m_nPressStartY = pEvent->y; - } - sal_uInt32 nModCode = GtkSalFrame::GetMouseModCode(pEvent->state); // strip out which buttons are involved from the nModCode and replace with m_nLastMouseButton sal_uInt16 nCode = m_nLastMouseButton | (nModCode & (KEY_SHIFT | KEY_MOD1 | KEY_MOD2)); @@ -3267,6 +3269,14 @@ private: return false; } +#if GTK_CHECK_VERSION(4, 0, 0) + virtual void drag_set_icon(GtkDragSource*) +#else + virtual void drag_set_icon(GdkDragContext*) +#endif + { + } + #if GTK_CHECK_VERSION(4, 0, 0) void signal_drag_begin(GtkDragSource* context) #else @@ -3278,19 +3288,22 @@ private: { #if !GTK_CHECK_VERSION(4, 0, 0) launch_drag_cancel(context); -#else - (void)context; #endif return; } -#if !GTK_CHECK_VERSION(4, 0, 0) if (bUnsetDragIcon) { +#if !GTK_CHECK_VERSION(4, 0, 0) cairo_surface_t *surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 0, 0); gtk_drag_set_icon_surface(context, surface); cairo_surface_destroy(surface); - } #endif + } + else + { + drag_set_icon(context); + } + if (!m_xDragSource) return; m_xDragSource->setActiveDragSource(); @@ -4902,11 +4915,11 @@ namespace { Size aSize(rDevice.GetOutputSizePixel()); cairo_surface_t* orig_surface = get_underlying_cairo_surface(rDevice); - double m_fXScale, m_fYScale; - dl_cairo_surface_get_device_scale(orig_surface, &m_fXScale, &m_fYScale); + double fXScale, fYScale; + dl_cairo_surface_get_device_scale(orig_surface, &fXScale, &fYScale); cairo_surface_t* surface; - if (m_fXScale != 1.0 || m_fYScale != -1) + if (fXScale != 1.0 || fYScale != -1) { surface = cairo_surface_create_similar_image(orig_surface, CAIRO_FORMAT_ARGB32, @@ -16441,6 +16454,77 @@ public: return false; } +#if GTK_CHECK_VERSION(4, 0, 0) + virtual void drag_set_icon(GtkDragSource*) override + { + } +#else + virtual void drag_set_icon(GdkDragContext* context) override + { + GtkTreeSelection *selection = gtk_tree_view_get_selection(m_pTreeView); + if (gtk_tree_selection_get_mode(selection) == GTK_SELECTION_MULTIPLE) + { + int nWidth = 0; + int nHeight = 0; + + GList* pList = gtk_tree_selection_get_selected_rows(gtk_tree_view_get_selection(m_pTreeView), nullptr); + std::vector<cairo_surface_t*> surfaces; + std::vector<int> heights; + for (GList* pItem = g_list_first(pList); pItem; pItem = g_list_next(pItem)) + { + GtkTreePath* pPath = static_cast<GtkTreePath*>(pItem->data); + + surfaces.push_back(gtk_tree_view_create_row_drag_icon(m_pTreeView, pPath)); + + double x1, x2, y1, y2; + cairo_t* cr = cairo_create(surfaces.back()); + cairo_clip_extents(cr, &x1, &y1, &x2, &y2); + cairo_destroy(cr); + + heights.push_back(y2 - y1); + + nWidth = std::max(nWidth, static_cast<int>(x2 - x1)); + nHeight += heights.back(); + } + g_list_free_full(pList, reinterpret_cast<GDestroyNotify>(gtk_tree_path_free)); + + // if its just one, then don't do anything and leave the default dnd icon as-is + if (surfaces.size() > 1) + { + cairo_surface_t* target = cairo_surface_create_similar(surfaces[0], + cairo_surface_get_content(surfaces[0]), + nWidth, + nHeight); + + cairo_t* cr = cairo_create(target); + + double y_pos = 0; + for (size_t i = 0; i < surfaces.size(); ++i) + { + cairo_set_source_surface(cr, surfaces[i], 2, y_pos + 2); + cairo_rectangle(cr, 0, y_pos, nWidth, heights[i]); + cairo_fill(cr); + y_pos += heights[i]; + } + + cairo_destroy(cr); + + double fXScale, fYScale; + dl_cairo_surface_get_device_scale(target, &fXScale, &fYScale); + cairo_surface_set_device_offset(target, + - m_nPressStartX * fXScale, + 0); + + gtk_drag_set_icon_surface(context, target); + cairo_surface_destroy(target); + } + + for (auto surface : surfaces) + cairo_surface_destroy(surface); + } + } +#endif + virtual void do_signal_drag_end() override { g_DragSource = nullptr; commit 584afec97fa97a4a5e68292ca0f66b0d3a2f664e Author: Caolán McNamara <caol...@redhat.com> AuthorDate: Thu Jan 19 10:28:47 2023 +0000 Commit: Andras Timar <andras.ti...@collabora.com> CommitDate: Mon Jan 23 09:41:34 2023 +0100 use cairo_surface_destroy after gtk_drag_set_icon_surface Change-Id: Iac543121a809eeabae630d4a426e72d5f9d47057 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/145783 Tested-by: Caolán McNamara <caol...@redhat.com> Reviewed-by: Caolán McNamara <caol...@redhat.com> (cherry picked from commit a7a842f4a437216cba8cd623306506aa30db7d8e) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/145819 Tested-by: Jenkins Reviewed-by: Adolfo Jayme Barrientos <fit...@ubuntu.com> diff --git a/vcl/unx/gtk3/gtkinst.cxx b/vcl/unx/gtk3/gtkinst.cxx index a072db8c5cc8..bd0da255a323 100644 --- a/vcl/unx/gtk3/gtkinst.cxx +++ b/vcl/unx/gtk3/gtkinst.cxx @@ -3135,6 +3135,7 @@ private: { cairo_surface_t *surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 0, 0); gtk_drag_set_icon_surface(pContext, surface); + cairo_surface_destroy(surface); } m_nPressedButton = -1; @@ -3287,6 +3288,7 @@ private: { cairo_surface_t *surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 0, 0); gtk_drag_set_icon_surface(context, surface); + cairo_surface_destroy(surface); } #endif if (!m_xDragSource) commit c343d12daba81d8be0f06d78c6af1ccb4941c443 Author: Caolán McNamara <caol...@redhat.com> AuthorDate: Thu Jan 19 16:31:03 2023 +0000 Commit: Andras Timar <andras.ti...@collabora.com> CommitDate: Mon Jan 23 09:41:34 2023 +0100 Resolves: tdf#153091 support text/plain without encoding from nedit Change-Id: I56dfc6dfec21b8c57b6f402c53b0229a2a2e7778 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/145798 Tested-by: Jenkins Reviewed-by: Adolfo Jayme Barrientos <fit...@ubuntu.com> diff --git a/vcl/unx/gtk3/gtkinst.cxx b/vcl/unx/gtk3/gtkinst.cxx index 9a5be553501f..a072db8c5cc8 100644 --- a/vcl/unx/gtk3/gtkinst.cxx +++ b/vcl/unx/gtk3/gtkinst.cxx @@ -825,16 +825,12 @@ public: virtual css::uno::Any SAL_CALL getTransferData(const css::datatransfer::DataFlavor& rFlavor) override { + css::uno::Any aRet; + css::datatransfer::DataFlavor aFlavor(rFlavor); if (aFlavor.MimeType == "text/plain;charset=utf-16") aFlavor.MimeType = "text/plain;charset=utf-8"; - auto it = m_aMimeTypeToGtkType.find(aFlavor.MimeType); - if (it == m_aMimeTypeToGtkType.end()) - return css::uno::Any(); - - css::uno::Any aRet; - GdkClipboard* clipboard = clipboard_get(m_eSelection); #if !GTK_CHECK_VERSION(4, 0, 0) @@ -846,21 +842,25 @@ public: aRet <<= aStr.replaceAll("\r\n", "\n"); return aRet; } - else +#endif + + auto it = m_aMimeTypeToGtkType.find(aFlavor.MimeType); + if (it == m_aMimeTypeToGtkType.end()) + return css::uno::Any(); + +#if !GTK_CHECK_VERSION(4, 0, 0) + GtkSelectionData* data = gtk_clipboard_wait_for_contents(clipboard, + it->second); + if (!data) { - GtkSelectionData* data = gtk_clipboard_wait_for_contents(clipboard, - it->second); - if (!data) - { - return css::uno::Any(); - } - gint length; - const guchar *rawdata = gtk_selection_data_get_data_with_length(data, - &length); - Sequence<sal_Int8> aSeq(reinterpret_cast<const sal_Int8*>(rawdata), length); - gtk_selection_data_free(data); - aRet <<= aSeq; + return css::uno::Any(); } + gint length; + const guchar *rawdata = gtk_selection_data_get_data_with_length(data, + &length); + Sequence<sal_Int8> aSeq(reinterpret_cast<const sal_Int8*>(rawdata), length); + gtk_selection_data_free(data); + aRet <<= aSeq; #else SalInstance* pInstance = GetSalInstance(); read_transfer_result aRes; commit f5272b0d66c270502c0ab3179aa521a931fb63e7 Author: Michael Stahl <michael.st...@allotropia.de> AuthorDate: Wed Jan 18 20:58:47 2023 +0100 Commit: Andras Timar <andras.ti...@collabora.com> CommitDate: Mon Jan 23 09:41:34 2023 +0100 tdf#153039 unoxml: replace root element of CDocument throws XForms replace doesn't work because: CDocument::IsChildTypeAllowed() tests that the document node does not already have an element child, because only one is allowed - but when called from CNode::replaceChild(), the existing child will be removed, so that needs to be allowed to proceed (check that removed child is also element). (regression from commit c5db3b93ee1058bd20ebcde2e757b52b9a67b74a) Change-Id: I167de3462f4d1934dbf8404ad395349897cfd981 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/145757 Tested-by: Jenkins Reviewed-by: Noel Grandin <noel.gran...@collabora.co.uk> (cherry picked from commit 9b9bc7461e0513e2bb493e7f00f800b2463751e1) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/145731 Reviewed-by: Caolán McNamara <caol...@redhat.com> diff --git a/unoxml/inc/node.hxx b/unoxml/inc/node.hxx index 852bcd1ae972..36301e10f22c 100644 --- a/unoxml/inc/node.hxx +++ b/unoxml/inc/node.hxx @@ -136,7 +136,8 @@ namespace DOM virtual void fastSaxify( Context& io_rContext ); // constrains child relationship between nodes based on type - virtual bool IsChildTypeAllowed(css::xml::dom::NodeType const nodeType); + virtual bool IsChildTypeAllowed(css::xml::dom::NodeType nodeType, + css::xml::dom::NodeType const* pReplacedNodeType); // ---- DOM interfaces diff --git a/unoxml/source/dom/attr.cxx b/unoxml/source/dom/attr.cxx index 1a993e152bd7..4988aa4211ec 100644 --- a/unoxml/source/dom/attr.cxx +++ b/unoxml/source/dom/attr.cxx @@ -70,7 +70,7 @@ namespace DOM return pNs; } - bool CAttr::IsChildTypeAllowed(NodeType const nodeType) + bool CAttr::IsChildTypeAllowed(NodeType const nodeType, NodeType const*const) { switch (nodeType) { case NodeType_TEXT_NODE: diff --git a/unoxml/source/dom/attr.hxx b/unoxml/source/dom/attr.hxx index 30c0aa25bb34..f30b25896158 100644 --- a/unoxml/source/dom/attr.hxx +++ b/unoxml/source/dom/attr.hxx @@ -52,7 +52,8 @@ namespace DOM /// return the libxml namespace corresponding to m_pNamespace on pNode xmlNsPtr GetNamespace(xmlNodePtr const pNode); - virtual bool IsChildTypeAllowed(css::xml::dom::NodeType const nodeType) override; + virtual bool IsChildTypeAllowed(css::xml::dom::NodeType const nodeType, + css::xml::dom::NodeType const*) override; /** Returns the name of this attribute. diff --git a/unoxml/source/dom/document.cxx b/unoxml/source/dom/document.cxx index 49c524b5ee99..413f764815e5 100644 --- a/unoxml/source/dom/document.cxx +++ b/unoxml/source/dom/document.cxx @@ -291,7 +291,7 @@ namespace DOM rContext.mxDocHandler->endDocument(); } - bool CDocument::IsChildTypeAllowed(NodeType const nodeType) + bool CDocument::IsChildTypeAllowed(NodeType const nodeType, NodeType const*const pReplacedNodeType) { switch (nodeType) { case NodeType_PROCESSING_INSTRUCTION_NODE: @@ -299,10 +299,12 @@ namespace DOM return true; case NodeType_ELEMENT_NODE: // there may be only one! - return nullptr == lcl_getDocumentRootPtr(m_aDocPtr); + return (pReplacedNodeType && *pReplacedNodeType == nodeType) + || nullptr == lcl_getDocumentRootPtr(m_aDocPtr); case NodeType_DOCUMENT_TYPE_NODE: // there may be only one! - return nullptr == lcl_getDocumentType(m_aDocPtr); + return (pReplacedNodeType && *pReplacedNodeType == nodeType) + || nullptr == lcl_getDocumentType(m_aDocPtr); default: return false; } diff --git a/unoxml/source/dom/document.hxx b/unoxml/source/dom/document.hxx index 291535ebf8e5..450b9200f86f 100644 --- a/unoxml/source/dom/document.hxx +++ b/unoxml/source/dom/document.hxx @@ -114,7 +114,8 @@ namespace DOM virtual void fastSaxify( Context& rContext ) override; - virtual bool IsChildTypeAllowed(css::xml::dom::NodeType const nodeType) override; + virtual bool IsChildTypeAllowed(css::xml::dom::NodeType const nodeType, + css::xml::dom::NodeType const* pReplacedNodeType) override; /** Creates an Attr of the given name. diff --git a/unoxml/source/dom/documentfragment.cxx b/unoxml/source/dom/documentfragment.cxx index 62c69b4db8e5..dd3ed3c18f54 100644 --- a/unoxml/source/dom/documentfragment.cxx +++ b/unoxml/source/dom/documentfragment.cxx @@ -32,7 +32,7 @@ namespace DOM { } - bool CDocumentFragment::IsChildTypeAllowed(NodeType const nodeType) + bool CDocumentFragment::IsChildTypeAllowed(NodeType const nodeType, NodeType const*const) { switch (nodeType) { case NodeType_ELEMENT_NODE: diff --git a/unoxml/source/dom/documentfragment.hxx b/unoxml/source/dom/documentfragment.hxx index 7bb3c187b236..c71edc86a78d 100644 --- a/unoxml/source/dom/documentfragment.hxx +++ b/unoxml/source/dom/documentfragment.hxx @@ -40,7 +40,8 @@ namespace DOM xmlNodePtr const pNode); public: - virtual bool IsChildTypeAllowed(css::xml::dom::NodeType const nodeType) override; + virtual bool IsChildTypeAllowed(css::xml::dom::NodeType const nodeType, + css::xml::dom::NodeType const*) override; // ---- resolve uno inheritance problems... // overrides for XNode base diff --git a/unoxml/source/dom/element.cxx b/unoxml/source/dom/element.cxx index 481b071e62e5..61109de6b85c 100644 --- a/unoxml/source/dom/element.cxx +++ b/unoxml/source/dom/element.cxx @@ -203,7 +203,7 @@ namespace DOM popContext(i_rContext); } - bool CElement::IsChildTypeAllowed(NodeType const nodeType) + bool CElement::IsChildTypeAllowed(NodeType const nodeType, NodeType const*const) { switch (nodeType) { case NodeType_ELEMENT_NODE: diff --git a/unoxml/source/dom/element.hxx b/unoxml/source/dom/element.hxx index efa048bfe2e1..3810e0935379 100644 --- a/unoxml/source/dom/element.hxx +++ b/unoxml/source/dom/element.hxx @@ -53,7 +53,8 @@ namespace DOM virtual void fastSaxify( Context& i_rContext ) override; - virtual bool IsChildTypeAllowed(css::xml::dom::NodeType const nodeType) override; + virtual bool IsChildTypeAllowed(css::xml::dom::NodeType const nodeType, + css::xml::dom::NodeType const*) override; /** Retrieves an attribute value by name. diff --git a/unoxml/source/dom/entity.cxx b/unoxml/source/dom/entity.cxx index 74b1faaf7e75..ccc8a0872499 100644 --- a/unoxml/source/dom/entity.cxx +++ b/unoxml/source/dom/entity.cxx @@ -37,7 +37,7 @@ namespace DOM { } - bool CEntity::IsChildTypeAllowed(NodeType const nodeType) + bool CEntity::IsChildTypeAllowed(NodeType const nodeType, NodeType const*const) { switch (nodeType) { case NodeType_ELEMENT_NODE: diff --git a/unoxml/source/dom/entity.hxx b/unoxml/source/dom/entity.hxx index 612c06502566..2668adb68701 100644 --- a/unoxml/source/dom/entity.hxx +++ b/unoxml/source/dom/entity.hxx @@ -45,7 +45,8 @@ namespace DOM xmlEntityPtr const pEntity); public: - virtual bool IsChildTypeAllowed(css::xml::dom::NodeType const nodeType) override; + virtual bool IsChildTypeAllowed(css::xml::dom::NodeType const nodeType, + css::xml::dom::NodeType const*) override; /** For unparsed entities, the name of the notation for the entity. diff --git a/unoxml/source/dom/entityreference.cxx b/unoxml/source/dom/entityreference.cxx index f94496d7b705..a3a06a238130 100644 --- a/unoxml/source/dom/entityreference.cxx +++ b/unoxml/source/dom/entityreference.cxx @@ -34,7 +34,7 @@ namespace DOM { } - bool CEntityReference::IsChildTypeAllowed(NodeType const nodeType) + bool CEntityReference::IsChildTypeAllowed(NodeType const nodeType, NodeType const*const) { switch (nodeType) { case NodeType_ELEMENT_NODE: diff --git a/unoxml/source/dom/entityreference.hxx b/unoxml/source/dom/entityreference.hxx index 05fd330af785..2ed9f568b7a8 100644 --- a/unoxml/source/dom/entityreference.hxx +++ b/unoxml/source/dom/entityreference.hxx @@ -43,7 +43,8 @@ namespace DOM xmlNodePtr const pNode); public: - virtual bool IsChildTypeAllowed(css::xml::dom::NodeType const nodeType) override; + virtual bool IsChildTypeAllowed(css::xml::dom::NodeType const nodeType, + css::xml::dom::NodeType const*) override; // ---- resolve uno inheritance problems... // overrides for XNode base diff --git a/unoxml/source/dom/node.cxx b/unoxml/source/dom/node.cxx index f5bd99aef475..88910e090f89 100644 --- a/unoxml/source/dom/node.cxx +++ b/unoxml/source/dom/node.cxx @@ -262,7 +262,7 @@ namespace DOM // default: do nothing } - bool CNode::IsChildTypeAllowed(NodeType const /*nodeType*/) + bool CNode::IsChildTypeAllowed(NodeType const /*nodeType*/, NodeType const*const) { // default: no children allowed return false; @@ -320,7 +320,7 @@ namespace DOM } checkNoParent(cur); - if (!IsChildTypeAllowed(pNewChild->m_aNodeType)) { + if (!IsChildTypeAllowed(pNewChild->m_aNodeType, nullptr)) { DOMException e; e.Code = DOMExceptionType_HIERARCHY_REQUEST_ERR; throw e; @@ -654,7 +654,7 @@ namespace DOM // already has parent checkNoParent(pNewChild); - if (!IsChildTypeAllowed(pNewNode->m_aNodeType)) { + if (!IsChildTypeAllowed(pNewNode->m_aNodeType, nullptr)) { DOMException e; e.Code = DOMExceptionType_HIERARCHY_REQUEST_ERR; throw e; @@ -825,7 +825,7 @@ namespace DOM // already has parent checkNoParent(pNew); - if (!IsChildTypeAllowed(pNewNode->m_aNodeType)) { + if (!IsChildTypeAllowed(pNewNode->m_aNodeType, &pOldNode->m_aNodeType)) { DOMException e; e.Code = DOMExceptionType_HIERARCHY_REQUEST_ERR; throw e; commit 96ae1486756fb4a8cc4da0af2ff45a848557964a Author: Michael Stahl <michael.st...@allotropia.de> AuthorDate: Wed Jan 18 11:56:30 2023 +0100 Commit: Andras Timar <andras.ti...@collabora.com> CommitDate: Mon Jan 23 09:41:34 2023 +0100 tdf#153082 writerfilter,sw: import/export locale-dependent TOC ... ... \t style name separators. OOXML says in 17.16.5.68 TOC: \t field-argument Uses paragraphs formatted with styles other than the built-in heading styles. text in this switch's field-argument specifies those styles as a set of comma-separated doublets, with each doublet being a comma-separated set of style name and table of content level. The reality is documented in Word online help: https://support.microsoft.com/en-us/office/field-codes-toc-table-of-contents-field-1f538bc4-60e6-4854-9f64-67754d78d05c?ui=en-US&rs=en-US&ad=US Note: Syntax shown here uses a comma (,) between the Style and Level parameters. A semicolon (;) is also valid, depending on which character is specified as the list separator in your operating system's regional and language settings. Because of language-specific dependencies, we recommend not using the \t switch in templates or documents that are intended for users across multiple language configurations. It's easy enough to recognize both ',' and ';' as separators on import, and unlikely that anybody would use these characters inside a style name; for export, both can't be written and a decision must be made. So do the same thing on export as Word does, assuming most document exchange is between users in the same locale; currently only for "de" locales but more can be added. Interestingly WW8 used to write ';' before 2009 when CWS hb32bugs01 changed it to ','. Change-Id: I2dcfdd009f448f6fae37cbd28929d0bbe504acf9 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/145744 Tested-by: Jenkins Reviewed-by: Michael Stahl <michael.st...@allotropia.de> (cherry picked from commit 7b62d09090e5172e26141694fb97bc27562a81ce) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/145722 Reviewed-by: Miklos Vajna <vmik...@collabora.com> diff --git a/sw/qa/extras/ooxmlexport/data/custom-styles-TOC-semicolon.docx b/sw/qa/extras/ooxmlexport/data/custom-styles-TOC-semicolon.docx new file mode 100644 index 000000000000..bef835c9bb46 Binary files /dev/null and b/sw/qa/extras/ooxmlexport/data/custom-styles-TOC-semicolon.docx differ diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport17.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport17.cxx index b216e14d22fe..0e000bff9641 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlexport17.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlexport17.cxx @@ -702,6 +702,30 @@ DECLARE_OOXMLEXPORT_TEST(testTdf148361, "tdf148361.docx") CPPUNIT_ASSERT_EQUAL(OUString("[Type text]"), aActual); } +DECLARE_OOXMLEXPORT_TEST(testTdf153082_semicolon, "custom-styles-TOC-semicolon.docx") +{ + uno::Reference<text::XDocumentIndexesSupplier> xIndexSupplier(mxComponent, uno::UNO_QUERY); + uno::Reference<container::XIndexAccess> xIndexes = xIndexSupplier->getDocumentIndexes(); + uno::Reference<text::XDocumentIndex> xTOC(xIndexes->getByIndex(0), uno::UNO_QUERY); + // check styles + uno::Reference<container::XIndexAccess> xParaStyles = + getProperty<uno::Reference<container::XIndexAccess>>(xTOC, "LevelParagraphStyles"); + uno::Sequence<OUString> styles; + xParaStyles->getByIndex(0) >>= styles; + CPPUNIT_ASSERT_EQUAL(uno::Sequence<OUString>{}, styles); + xParaStyles->getByIndex(1) >>= styles; + CPPUNIT_ASSERT_EQUAL(uno::Sequence<OUString>{}, styles); + xParaStyles->getByIndex(2) >>= styles; + // the first one is built-in Word style that was localised DE "Intensives Zitat" in the file + CPPUNIT_ASSERT_EQUAL((uno::Sequence<OUString>{"Intense Quote", "Custom1", "_MyStyle0"}), styles); + xTOC->update(); + OUString const tocContent(xTOC->getAnchor()->getString()); + CPPUNIT_ASSERT(tocContent.startsWith("Table of Contents")); + CPPUNIT_ASSERT(tocContent.indexOf("Lorem ipsum dolor sit amet, consectetuer adipiscing elit.") != -1); + CPPUNIT_ASSERT(tocContent.indexOf("Fusce posuere, magna sed pulvinar ultricies, purus lectus malesuada libero, sit amet commodo magna eros quis urna.") != -1); + CPPUNIT_ASSERT(tocContent.indexOf("Proin pharetra nonummy pede. Mauris et orci.") != -1); +} + DECLARE_OOXMLEXPORT_TEST(testTdf153082_comma, "custom-styles-TOC-comma.docx") { uno::Reference<text::XDocumentIndexesSupplier> xIndexSupplier(mxComponent, uno::UNO_QUERY); diff --git a/sw/source/filter/ww8/ww8atr.cxx b/sw/source/filter/ww8/ww8atr.cxx index 2e14a90dbfe7..862dbbe70e66 100644 --- a/sw/source/filter/ww8/ww8atr.cxx +++ b/sw/source/filter/ww8/ww8atr.cxx @@ -138,6 +138,7 @@ #include "ww8par.hxx" #include "ww8attributeoutput.hxx" #include "fields.hxx" +#include <i18nlangtag/mslangid.hxx> #include <i18nlangtag/languagetag.hxx> #include <unotools/fltrcfg.hxx> @@ -2252,6 +2253,21 @@ void AttributeOutputBase::GenerateBookmarksForSequenceField(const SwTextNode& rN } } +static auto GetSeparatorForLocale() -> OUString +{ + switch (sal_uInt16(MsLangId::getSystemLanguage())) + { + case sal_uInt16(LANGUAGE_GERMAN): + case sal_uInt16(LANGUAGE_GERMAN_AUSTRIAN): + case sal_uInt16(LANGUAGE_GERMAN_LIECHTENSTEIN): + case sal_uInt16(LANGUAGE_GERMAN_LUXEMBOURG): + case sal_uInt16(LANGUAGE_GERMAN_SWISS): + return ";"; + default: + return ","; + } +} + void AttributeOutputBase::StartTOX( const SwSection& rSect ) { if ( const SwTOXBase* pTOX = rSect.GetTOXBase() ) @@ -2361,6 +2377,9 @@ void AttributeOutputBase::StartTOX( const SwSection& rSect ) sStr = FieldString(eCode); OUString sTOption; + // tdf#153082 Word's separator interpretation in DOCX + // fields varies by system locale. + auto const tsep(GetSeparatorForLocale()); sal_uInt16 n, nTOXLvl = pTOX->GetLevel(); if( !nTOXLvl ) ++nTOXLvl; @@ -2462,8 +2481,8 @@ void AttributeOutputBase::StartTOX( const SwSection& rSect ) if (nTestLvl < nTOXLvl && nTestLvl >= nMaxMSAutoEvaluate) { if (!sTOption.isEmpty()) - sTOption += ","; - sTOption += pColl->GetName() + "," + OUString::number( nTestLvl + 1 ); + sTOption += tsep; + sTOption += pColl->GetName() + tsep + OUString::number(nTestLvl + 1); } } } @@ -2483,7 +2502,7 @@ void AttributeOutputBase::StartTOX( const SwSection& rSect ) if( !rStyles.isEmpty() ) { sal_Int32 nPos = 0; - const OUString sLvl{ "," + OUString::number( n + 1 ) }; + const OUString sLvl{tsep + OUString::number(n + 1)}; do { const OUString sStyle( rStyles.getToken( 0, TOX_STYLE_DELIMITER, nPos )); if( !sStyle.isEmpty() ) @@ -2494,7 +2513,7 @@ void AttributeOutputBase::StartTOX( const SwSection& rSect ) if (!pColl->IsAssignedToListLevelOfOutlineStyle() || pColl->GetAssignedOutlineStyleLevel() < nTOXLvl) { if( !sTOption.isEmpty() ) - sTOption += ","; + sTOption += tsep; sTOption += sStyle + sLvl; } } diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.cxx b/writerfilter/source/dmapper/DomainMapper_Impl.cxx index 87bc1b1728a1..be11e0499195 100644 --- a/writerfilter/source/dmapper/DomainMapper_Impl.cxx +++ b/writerfilter/source/dmapper/DomainMapper_Impl.cxx @@ -6255,13 +6255,14 @@ void DomainMapper_Impl::handleToc TOCStyleMap aMap; sal_Int32 nLevel; sal_Int32 nPosition = 0; + auto const tsep(sTemplate.indexOf(',') != -1 ? ',' : ';'); while( nPosition >= 0) { - OUString sStyleName = sTemplate.getToken( 0, ',', nPosition ); + OUString sStyleName = sTemplate.getToken(0, tsep, nPosition); //empty tokens should be skipped while( sStyleName.isEmpty() && nPosition > 0 ) - sStyleName = sTemplate.getToken( 0, ',', nPosition ); - nLevel = o3tl::toInt32(o3tl::getToken(sTemplate, 0, ',', nPosition )); + sStyleName = sTemplate.getToken(0, tsep, nPosition); + nLevel = o3tl::toInt32(o3tl::getToken(sTemplate, 0, tsep, nPosition )); if( !nLevel ) nLevel = 1; if( !sStyleName.isEmpty() ) commit 9f028707e78c85b99c587287328fc5fc000b42f4 Author: Michael Stahl <michael.st...@allotropia.de> AuthorDate: Fri Jan 6 19:07:35 2023 +0100 Commit: Andras Timar <andras.ti...@collabora.com> CommitDate: Mon Jan 23 09:41:34 2023 +0100 tdf#152872 sw: conditionally hide paragraph breaks Add a 3rd kind of hiding to SwRootFrame and CheckParaRedlineMerge(). This is quite simple as only consecutive paragraphs are merged. There is an existing similar feature described in http://www.openoffice.org/specs/writer/hidden_text/hidden_text.sxw which results in 0-height text frames if all text is hidden - but that is unconditional, while Word shows the paragraph when control chars are shown, and hides it otherwise *iff* its paragraph marker is hidden (and there's no page break on it). Reviewed-on: https://gerrit.libreoffice.org/c/core/+/145162 Tested-by: Jenkins Reviewed-by: Michael Stahl <michael.st...@allotropia.de> (cherry picked from commit 2bcfb7231b5ca74f02274cfb74ca8463f78905d6) tdf#152872 sw: fix crash on ooo27109-1.sxw Has a redline that ends on the body end node. (regression from commit 2bcfb7231b5ca74f02274cfb74ca8463f78905d6) (cherry picked from commit 29507e398d27bdfceb9155d24a20986ee997d70c) Change-Id: I8290962ea58278e17b8f84bf6b2ca4bb2325aa8f Reviewed-on: https://gerrit.libreoffice.org/c/core/+/145296 Tested-by: Jenkins Reviewed-by: Miklos Vajna <vmik...@collabora.com> diff --git a/sw/inc/doc.hxx b/sw/inc/doc.hxx index 80aa234cc6e3..4a399b839896 100644 --- a/sw/inc/doc.hxx +++ b/sw/inc/doc.hxx @@ -142,6 +142,7 @@ namespace sw::mark { class MarkManager; } namespace sw { enum class RedlineMode; enum class FieldmarkMode; + enum class ParagraphBreakMode; class MetaFieldManager; class UndoManager; class IShellCursorSupplier; @@ -1337,7 +1338,7 @@ public: // insert section (the ODF kind of section, not the nodesarray kind) SwSection * InsertSwSection(SwPaM const& rRange, SwSectionData &, - std::tuple<SwTOXBase const*, sw::RedlineMode, sw::FieldmarkMode> const* pTOXBase, + std::tuple<SwTOXBase const*, sw::RedlineMode, sw::FieldmarkMode, sw::ParagraphBreakMode> const* pTOXBase, SfxItemSet const*const pAttr, bool const bUpdate = true); static sal_uInt16 IsInsRegionAvailable( const SwPaM& rRange, const SwNode** ppSttNd = nullptr ); diff --git a/sw/qa/extras/layout/data/hidden-para-separator.docx b/sw/qa/extras/layout/data/hidden-para-separator.docx new file mode 100644 index 000000000000..1d5d26075f22 Binary files /dev/null and b/sw/qa/extras/layout/data/hidden-para-separator.docx differ diff --git a/sw/qa/extras/layout/layout2.cxx b/sw/qa/extras/layout/layout2.cxx index 0b528753aa9a..434bf6376ebc 100644 --- a/sw/qa/extras/layout/layout2.cxx +++ b/sw/qa/extras/layout/layout2.cxx @@ -636,6 +636,43 @@ CPPUNIT_TEST_FIXTURE(SwLayoutWriter2, testTdf149711_importDOCXMoveToParagraphMar assertXPath(pXmlDoc, "/root/page[1]/body/txt", 5); } +CPPUNIT_TEST_FIXTURE(SwLayoutWriter2, testTdf152872) +{ + createSwDoc("hidden-para-separator.docx"); + xmlDocUniquePtr pXmlDoc = parseLayoutDump(); + + assertXPath(pXmlDoc, "/root/page[1]/body/txt", 2); + assertXPath(pXmlDoc, "/root/page/body/txt[1]/SwParaPortion/SwLineLayout", "portion", "C DE"); + assertXPath(pXmlDoc, "/root/page/body/txt[2]/SwParaPortion", 0); // 5 is empty + assertXPath(pXmlDoc, "/root/page/body/txt[2]/infos/bounds", "height", "379"); + + dispatchCommand(mxComponent, ".uno:ControlCodes", {}); + + discardDumpedLayout(); + pXmlDoc = parseLayoutDump(); + + assertXPath(pXmlDoc, "/root/page[1]/body/txt", 5); + assertXPath(pXmlDoc, "/root/page/body/txt[1]/SwParaPortion/SwLineLayout", "portion", "C "); + assertXPath(pXmlDoc, "/root/page/body/txt[2]/SwParaPortion/SwLineLayout", "portion", "D"); + // 3 is an empty paragraph with RES_CHRATR_HIDDEN which results in 0-height + // frame; ideally it should only be hidden when control codes are hidden + // and be a full-height frame now, but that needs more work... + assertXPath(pXmlDoc, "/root/page/body/txt[3]/infos/bounds", "height", "0"); + assertXPath(pXmlDoc, "/root/page/body/txt[4]/SwParaPortion/SwLineLayout", "portion", "E"); + assertXPath(pXmlDoc, "/root/page/body/txt[5]/SwParaPortion", 0); // 5 is empty + assertXPath(pXmlDoc, "/root/page/body/txt[5]/infos/bounds", "height", "379"); + + dispatchCommand(mxComponent, ".uno:ControlCodes", {}); + + discardDumpedLayout(); + pXmlDoc = parseLayoutDump(); + + assertXPath(pXmlDoc, "/root/page[1]/body/txt", 2); + assertXPath(pXmlDoc, "/root/page/body/txt[1]/SwParaPortion/SwLineLayout", "portion", "C DE"); + assertXPath(pXmlDoc, "/root/page/body/txt[2]/SwParaPortion", 0); // 5 is empty + assertXPath(pXmlDoc, "/root/page/body/txt[2]/infos/bounds", "height", "379"); +} + CPPUNIT_TEST_FIXTURE(SwLayoutWriter2, testTdf151954) { createSwDoc("tdf151954.docx"); diff --git a/sw/source/core/doc/doctxm.cxx b/sw/source/core/doc/doctxm.cxx index 5578a503dcfd..5f54e5313f70 100644 --- a/sw/source/core/doc/doctxm.cxx +++ b/sw/source/core/doc/doctxm.cxx @@ -363,12 +363,13 @@ SwTOXBaseSection* SwDoc::InsertTableOf( const SwPaM& aPam, OUString sSectNm = GetUniqueTOXBaseName( *rTOX.GetTOXType(), rTOX.GetTOXName() ); SwSectionData aSectionData( SectionType::ToxContent, sSectNm ); - std::tuple<SwTOXBase const*, sw::RedlineMode, sw::FieldmarkMode> const tmp( + std::tuple<SwTOXBase const*, sw::RedlineMode, sw::FieldmarkMode, sw::ParagraphBreakMode> const tmp( &rTOX, pLayout && pLayout->IsHideRedlines() ? sw::RedlineMode::Hidden : sw::RedlineMode::Shown, - pLayout ? pLayout->GetFieldmarkMode() : sw::FieldmarkMode::ShowBoth); + pLayout ? pLayout->GetFieldmarkMode() : sw::FieldmarkMode::ShowBoth, + pLayout ? pLayout->GetParagraphBreakMode() : sw::ParagraphBreakMode::Shown); SwTOXBaseSection *const pNewSection = dynamic_cast<SwTOXBaseSection *>( InsertSwSection(aPam, aSectionData, & tmp, pSet, false)); if (pNewSection) diff --git a/sw/source/core/docnode/ndsect.cxx b/sw/source/core/docnode/ndsect.cxx index 8a53f83cd6ad..f4fe9b9a3ec4 100644 --- a/sw/source/core/docnode/ndsect.cxx +++ b/sw/source/core/docnode/ndsect.cxx @@ -152,7 +152,7 @@ static void lcl_CheckEmptyLayFrame( SwNodes const & rNds, SwSectionData& rSectio SwSection * SwDoc::InsertSwSection(SwPaM const& rRange, SwSectionData & rNewData, - std::tuple<SwTOXBase const*, sw::RedlineMode, sw::FieldmarkMode> const*const pTOXBaseAndMode, + std::tuple<SwTOXBase const*, sw::RedlineMode, sw::FieldmarkMode, sw::ParagraphBreakMode> const*const pTOXBaseAndMode, SfxItemSet const*const pAttr, bool const bUpdate) { const SwNode* pPrvNd = nullptr; diff --git a/sw/source/core/inc/UndoSection.hxx b/sw/source/core/inc/UndoSection.hxx index 85b15a8b7eb0..5be018a2e14d 100644 --- a/sw/source/core/inc/UndoSection.hxx +++ b/sw/source/core/inc/UndoSection.hxx @@ -35,13 +35,14 @@ class SwTOXBase; namespace sw { enum class RedlineMode; enum class FieldmarkMode; + enum class ParagraphBreakMode; }; class SwUndoInsSection final : public SwUndo, private SwUndRng { private: const std::unique_ptr<SwSectionData> m_pSectionData; - std::optional<std::tuple<std::unique_ptr<SwTOXBase>, sw::RedlineMode, sw::FieldmarkMode>> m_xTOXBase; /// set iff section is TOX + std::optional<std::tuple<std::unique_ptr<SwTOXBase>, sw::RedlineMode, sw::FieldmarkMode, sw::ParagraphBreakMode>> m_xTOXBase; /// set iff section is TOX const std::unique_ptr<SfxItemSet> m_pAttrSet; std::unique_ptr<SwHistory> m_pHistory; std::unique_ptr<SwRedlineData> m_pRedlData; @@ -56,7 +57,7 @@ private: public: SwUndoInsSection(SwPaM const&, SwSectionData const&, SfxItemSet const* pSet, - std::tuple<SwTOXBase const*, sw::RedlineMode, sw::FieldmarkMode> const* pTOXBase); + std::tuple<SwTOXBase const*, sw::RedlineMode, sw::FieldmarkMode, sw::ParagraphBreakMode> const* pTOXBase); virtual ~SwUndoInsSection() override; diff --git a/sw/source/core/inc/rootfrm.hxx b/sw/source/core/inc/rootfrm.hxx index 3d00fe1cc226..32344bf0d9c0 100644 --- a/sw/source/core/inc/rootfrm.hxx +++ b/sw/source/core/inc/rootfrm.hxx @@ -47,6 +47,7 @@ namespace sw { }; enum class FieldmarkMode { ShowCommand = 1, ShowResult = 2, ShowBoth = 3 }; + enum class ParagraphBreakMode { Shown, Hidden }; }; enum class SwInvalidateFlags @@ -121,6 +122,7 @@ class SW_DLLPUBLIC SwRootFrame final : public SwLayoutFrame bool mbLayoutFreezed; bool mbHideRedlines; sw::FieldmarkMode m_FieldmarkMode; + sw::ParagraphBreakMode m_ParagraphBreakMode; /** * For BrowseMode @@ -421,10 +423,9 @@ public: bool IsHideRedlines() const { return mbHideRedlines; } void SetHideRedlines(bool); sw::FieldmarkMode GetFieldmarkMode() const { return m_FieldmarkMode; } - void SetFieldmarkMode(sw::FieldmarkMode); - bool HasMergedParas() const { - return IsHideRedlines() || GetFieldmarkMode() != sw::FieldmarkMode::ShowBoth; - } + void SetFieldmarkMode(sw::FieldmarkMode, sw::ParagraphBreakMode); + sw::ParagraphBreakMode GetParagraphBreakMode() const { return m_ParagraphBreakMode; } + bool HasMergedParas() const; }; inline tools::Long SwRootFrame::GetBrowseWidth() const diff --git a/sw/source/core/layout/newfrm.cxx b/sw/source/core/layout/newfrm.cxx index c09c55779f46..5ca11e34138b 100644 --- a/sw/source/core/layout/newfrm.cxx +++ b/sw/source/core/layout/newfrm.cxx @@ -418,6 +418,9 @@ SwRootFrame::SwRootFrame( SwFrameFormat *pFormat, SwViewShell * pSh ) : m_FieldmarkMode(pSh->GetViewOptions()->IsFieldName() ? sw::FieldmarkMode::ShowCommand : sw::FieldmarkMode::ShowResult), + m_ParagraphBreakMode(pSh->GetViewOptions()->IsParagraph() + ? sw::ParagraphBreakMode::Shown + : sw::ParagraphBreakMode::Hidden), mnBrowseWidth(MIN_BROWSE_WIDTH), mpTurbo( nullptr ), mpLastPage( nullptr ), diff --git a/sw/source/core/layout/wsfrm.cxx b/sw/source/core/layout/wsfrm.cxx index 2d59a1c7ea73..f753a993aceb 100644 --- a/sw/source/core/layout/wsfrm.cxx +++ b/sw/source/core/layout/wsfrm.cxx @@ -4706,23 +4706,26 @@ void SwRootFrame::SetHideRedlines(bool const bHideRedlines) } // TODO: remove temporary ShowBoth sw::FieldmarkMode const eMode(m_FieldmarkMode); + sw::ParagraphBreakMode const ePBMode(m_ParagraphBreakMode); if (HasMergedParas()) { m_FieldmarkMode = sw::FieldmarkMode::ShowBoth; + m_ParagraphBreakMode = sw::ParagraphBreakMode::Shown; mbHideRedlines = false; UnHide(*this); } - if (bHideRedlines || eMode != m_FieldmarkMode) + if (bHideRedlines || eMode != m_FieldmarkMode || ePBMode != m_ParagraphBreakMode) { m_FieldmarkMode = eMode; + m_ParagraphBreakMode = ePBMode; mbHideRedlines = bHideRedlines; UnHide(*this); } } -void SwRootFrame::SetFieldmarkMode(sw::FieldmarkMode const eMode) +void SwRootFrame::SetFieldmarkMode(sw::FieldmarkMode const eFMMode, sw::ParagraphBreakMode const ePBMode) { - if (eMode == m_FieldmarkMode) + if (eFMMode == m_FieldmarkMode && ePBMode == m_ParagraphBreakMode) { return; } @@ -4732,14 +4735,23 @@ void SwRootFrame::SetFieldmarkMode(sw::FieldmarkMode const eMode) { mbHideRedlines = false; m_FieldmarkMode = sw::FieldmarkMode::ShowBoth; + m_ParagraphBreakMode = sw::ParagraphBreakMode::Shown; UnHide(*this); } - if (eMode != sw::FieldmarkMode::ShowBoth || isHideRedlines) + if (isHideRedlines || eFMMode != sw::FieldmarkMode::ShowBoth || ePBMode == sw::ParagraphBreakMode::Hidden) { mbHideRedlines = isHideRedlines; - m_FieldmarkMode = eMode; + m_FieldmarkMode = eFMMode; + m_ParagraphBreakMode = ePBMode; UnHide(*this); } } +bool SwRootFrame::HasMergedParas() const +{ + return IsHideRedlines() + || GetFieldmarkMode() != sw::FieldmarkMode::ShowBoth + || GetParagraphBreakMode() == sw::ParagraphBreakMode::Hidden; +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/text/redlnitr.cxx b/sw/source/core/text/redlnitr.cxx index 2b77d86aa350..c44b527536c1 100644 --- a/sw/source/core/text/redlnitr.cxx +++ b/sw/source/core/text/redlnitr.cxx @@ -47,8 +47,11 @@ #include <vcl/svapp.hxx> #include "redlnitr.hxx" #include <extinput.hxx> +#include <fmtpdsc.hxx> +#include <editeng/charhiddenitem.hxx> #include <editeng/colritem.hxx> #include <editeng/crossedoutitem.hxx> +#include <editeng/formatbreakitem.hxx> #include <editeng/udlnitem.hxx> using namespace ::com::sun::star; @@ -62,12 +65,15 @@ private: IDocumentMarkAccess const& m_rIDMA; bool const m_isHideRedlines; sw::FieldmarkMode const m_eFieldmarkMode; + bool const m_isHideParagraphBreaks; SwPosition const m_Start; /// next redline SwRedlineTable::size_type m_RedlineIndex; /// next fieldmark std::pair<sw::mark::IFieldmark const*, std::optional<SwPosition>> m_Fieldmark; std::optional<SwPosition> m_oNextFieldmarkHide; + /// previous paragraph break - because m_pStartPos/EndPos are non-owning + std::optional<std::pair<SwPosition, SwPosition>> m_oParagraphBreak; /// current start/end pair SwPosition const* m_pStartPos; SwPosition const* m_pEndPos; @@ -77,11 +83,13 @@ public: SwPosition const* GetEndPos() const { return m_pEndPos; } HideIterator(SwTextNode & rTextNode, - bool const isHideRedlines, sw::FieldmarkMode const eMode) + bool const isHideRedlines, sw::FieldmarkMode const eMode, + sw::ParagraphBreakMode const ePBMode) : m_rIDRA(rTextNode.getIDocumentRedlineAccess()) , m_rIDMA(*rTextNode.getIDocumentMarkAccess()) , m_isHideRedlines(isHideRedlines) , m_eFieldmarkMode(eMode) + , m_isHideParagraphBreaks(ePBMode == sw::ParagraphBreakMode::Hidden) , m_Start(rTextNode, 0) , m_RedlineIndex(isHideRedlines ? m_rIDRA.GetRedlinePos(rTextNode, RedlineType::Any) : SwRedlineTable::npos) , m_pStartPos(nullptr) @@ -188,12 +196,66 @@ public: m_pEndPos = &*m_Fieldmark.second; return true; } - else // nothing + else { assert(!pNextRedlineHide && !m_oNextFieldmarkHide); - m_pStartPos = nullptr; - m_pEndPos = nullptr; - return false; + auto const hasHiddenItem = [](auto const& rNode) { + auto const& rpSet(rNode.GetAttr(RES_PARATR_LIST_AUTOFMT).GetStyleHandle()); + return rpSet ? rpSet->Get(RES_CHRATR_HIDDEN).GetValue() : false; + }; + auto const hasBreakBefore = [](SwTextNode const& rNode) { + if (rNode.GetAttr(RES_PAGEDESC).GetPageDesc()) + { + return true; + } + switch (rNode.GetAttr(RES_BREAK).GetBreak()) + { + case SvxBreak::ColumnBefore: + case SvxBreak::ColumnBoth: + case SvxBreak::PageBefore: + case SvxBreak::PageBoth: + return true; + default: + break; + } + return false; + }; + auto const hasBreakAfter = [](SwTextNode const& rNode) { + switch (rNode.GetAttr(RES_BREAK).GetBreak()) + { + case SvxBreak::ColumnAfter: + case SvxBreak::ColumnBoth: + case SvxBreak::PageAfter: + case SvxBreak::PageBoth: + return true; + default: + break; + } + return false; + }; + if (m_isHideParagraphBreaks + && m_pEndPos->GetNode().IsTextNode() // ooo27109-1.sxw + // only merge if next node is also text node ... etc. - the rest is truncated