officecfg/registry/data/org/openoffice/Office/UI/WriterCommands.xcu |    8 +
 sw/inc/cmdid.h                                                      |    1 
 sw/qa/extras/ooxmlexport/ooxmlexport17.cxx                          |   37 
++++++-
 sw/qa/uibase/wrtsh/wrtsh.cxx                                        |   22 ++++
 sw/sdi/_textsh.sdi                                                  |    6 +
 sw/sdi/swriter.sdi                                                  |   17 +++
 sw/source/filter/ww8/docxattributeoutput.cxx                        |    5 
 sw/source/uibase/dochdl/swdtflvr.cxx                                |   10 -
 sw/source/uibase/inc/wrtsh.hxx                                      |    2 
 sw/source/uibase/shells/basesh.cxx                                  |    2 
 sw/source/uibase/shells/textsh.cxx                                  |    5 
 sw/source/uibase/uiview/view.cxx                                    |    4 
 sw/source/uibase/uiview/view2.cxx                                   |    4 
 sw/source/uibase/wrtsh/wrtsh1.cxx                                   |   52 
+++++++++-
 sw/uiconfig/swriter/menubar/menubar.xml                             |    1 
 sw/uiconfig/swriter/menubar/mscompatibleformsmenu.xml               |    1 
 writerfilter/qa/cppunittests/dmapper/SdtHelper.cxx                  |   33 
++++++
 writerfilter/qa/cppunittests/dmapper/data/sdt-run-picture.docx      |binary
 writerfilter/source/dmapper/DomainMapper.cxx                        |   11 ++
 writerfilter/source/dmapper/DomainMapper_Impl.cxx                   |    5 
 writerfilter/source/dmapper/SdtHelper.hxx                           |    1 
 21 files changed, 211 insertions(+), 16 deletions(-)

New commits:
commit c18db3c86257974770cd9e7c5aea221222c78667
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Fri May 20 13:31:45 2022 +0200
Commit:     Miklos Vajna <vmik...@collabora.com>
CommitDate: Tue May 24 13:13:58 2022 +0200

    sw content controls, picture: add insert UI
    
    - handle the picture case in SwWrtShell::InsertContentControl(): insert
      a placeholder bitmap & create content control around the as-char image
    
    - expose this as a new .uno:InsertPictureContentControl command
    
    - add the new uno command to the default & MS-compatible menus
    
    - rename the SwWrtShell::Insert() overload taking a Graphic to make this
      a bit more readable
    
    (cherry picked from commit 73ed5e36047b6f46b3777bf6f36591ec4babb1f9)
    
    Change-Id: I289d6b6a9cd622c585b6cf0ec0c91d6b51ad81ac
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/134849
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com>
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>

diff --git 
a/officecfg/registry/data/org/openoffice/Office/UI/WriterCommands.xcu 
b/officecfg/registry/data/org/openoffice/Office/UI/WriterCommands.xcu
index a460cf46e5eb..ad244722288d 100644
--- a/officecfg/registry/data/org/openoffice/Office/UI/WriterCommands.xcu
+++ b/officecfg/registry/data/org/openoffice/Office/UI/WriterCommands.xcu
@@ -651,6 +651,14 @@
           <value>1</value>
         </prop>
       </node>
+      <node oor:name=".uno:InsertPictureContentControl" oor:op="replace">
+        <prop oor:name="Label" oor:type="xs:string">
+          <value xml:lang="en-US">Insert Picture Content Control</value>
+        </prop>
+        <prop oor:name="Properties" oor:type="xs:int">
+          <value>1</value>
+        </prop>
+      </node>
       <node oor:name=".uno:InsertObjectDialog" oor:op="replace">
         <prop oor:name="Label" oor:type="xs:string">
           <value xml:lang="en-US">Insert Other Objects</value>
diff --git a/sw/inc/cmdid.h b/sw/inc/cmdid.h
index e477ccd054aa..003c77e7efd0 100644
--- a/sw/inc/cmdid.h
+++ b/sw/inc/cmdid.h
@@ -216,6 +216,7 @@
 #define FN_INSERT_PAGEBREAK     (FN_INSERT + 23)    /* Page break*/
 #define FN_INSERT_DROPDOWN_CONTENT_CONTROL (FN_INSERT + 24)  /* Dropdown 
content control */
 #define FN_CONTENT_CONTROL_PROPERTIES (FN_INSERT + 25)  /* Content control 
properties */
+#define FN_INSERT_PICTURE_CONTENT_CONTROL (FN_INSERT + 26) /* Picture content 
control */
 #define FN_POSTIT               (FN_INSERT + 29)    /* Insert/edit PostIt */
 #define FN_INSERT_TABLE         (FN_INSERT + 30)    /* Insert Table */
 #define FN_INSERT_STRING        (FN_INSERT+31)
diff --git a/sw/qa/uibase/wrtsh/wrtsh.cxx b/sw/qa/uibase/wrtsh/wrtsh.cxx
index 9aa3efbaf214..ecb7754f53ca 100644
--- a/sw/qa/uibase/wrtsh/wrtsh.cxx
+++ b/sw/qa/uibase/wrtsh/wrtsh.cxx
@@ -285,6 +285,28 @@ CPPUNIT_TEST_FIXTURE(Test, 
testReplacePictureContentControl)
     // killed the image selection.
     CPPUNIT_ASSERT(pWrtShell->IsFrameSelected());
 }
+
+CPPUNIT_TEST_FIXTURE(Test, testInsertPictureContentControl)
+{
+    // Given an empty document:
+    SwDoc* pDoc = createSwDoc();
+
+    // When inserting a content control:
+    SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
+    pWrtShell->InsertContentControl(SwContentControlType::PICTURE);
+
+    // Then make sure that the matching text attribute is added to the 
document model:
+    SwTextNode* pTextNode = pWrtShell->GetCursor()->GetNode().GetTextNode();
+    SwTextAttr* pAttr = pTextNode->GetTextAttrForCharAt(0, 
RES_TXTATR_CONTENTCONTROL);
+    auto pTextContentControl = 
static_txtattr_cast<SwTextContentControl*>(pAttr);
+    auto& rFormatContentControl
+        = static_cast<SwFormatContentControl&>(pTextContentControl->GetAttr());
+    std::shared_ptr<SwContentControl> pContentControl = 
rFormatContentControl.GetContentControl();
+    // Without the accompanying fix in place, this test would have failed, 
there was no special
+    // handling for picture content control, no placeholder fly content was 
inserted.
+    CPPUNIT_ASSERT(pContentControl->GetPicture());
+    CPPUNIT_ASSERT(pTextNode->GetTextAttrForCharAt(1, RES_TXTATR_FLYCNT));
+}
 }
 
 CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/sw/sdi/_textsh.sdi b/sw/sdi/_textsh.sdi
index 816439cee140..16cd41e339ce 100644
--- a/sw/sdi/_textsh.sdi
+++ b/sw/sdi/_textsh.sdi
@@ -290,6 +290,12 @@ interface BaseText
         StateMethod = NoState ;
         DisableFlags="SfxDisableFlags::SwOnProtectedCursor";
     ]
+    FN_INSERT_PICTURE_CONTENT_CONTROL  // status(final|play)
+    [
+        ExecMethod = ExecInsert ;
+        StateMethod = NoState ;
+        DisableFlags="SfxDisableFlags::SwOnProtectedCursor";
+    ]
     FN_CONTENT_CONTROL_PROPERTIES  // status(final|play)
     [
         ExecMethod = ExecInsert ;
diff --git a/sw/sdi/swriter.sdi b/sw/sdi/swriter.sdi
index 7663d3f2c6b1..3361825974b2 100644
--- a/sw/sdi/swriter.sdi
+++ b/sw/sdi/swriter.sdi
@@ -3083,6 +3083,23 @@ SfxVoidItem InsertDropdownContentControl 
FN_INSERT_DROPDOWN_CONTENT_CONTROL
     GroupId = SfxGroupId::Insert;
 ]
 
+SfxVoidItem InsertPictureContentControl FN_INSERT_PICTURE_CONTENT_CONTROL
+()
+[
+    AutoUpdate = FALSE,
+    FastCall = FALSE,
+    ReadOnlyDoc = FALSE,
+    Toggle = FALSE,
+    Container = FALSE,
+    RecordAbsolute = FALSE,
+    RecordPerSet;
+
+    AccelConfig = TRUE,
+    MenuConfig = TRUE,
+    ToolBoxConfig = TRUE,
+    GroupId = SfxGroupId::Insert;
+]
+
 SfxVoidItem ContentControlProperties FN_CONTENT_CONTROL_PROPERTIES
 ()
 [
diff --git a/sw/source/uibase/dochdl/swdtflvr.cxx 
b/sw/source/uibase/dochdl/swdtflvr.cxx
index 45b74a55773b..542101829162 100644
--- a/sw/source/uibase/dochdl/swdtflvr.cxx
+++ b/sw/source/uibase/dochdl/swdtflvr.cxx
@@ -2506,7 +2506,7 @@ bool SwTransferable::PasteTargetURL( const 
TransferableDataHelper& rData,
                 {
                 case SwPasteSdr::Insert:
                     SwTransferable::SetSelInShell( rSh, false, pPt );
-                    rSh.Insert(sURL, OUString(), aGraphic);
+                    rSh.InsertGraphic(sURL, OUString(), aGraphic);
                     break;
 
                 case SwPasteSdr::Replace:
@@ -2528,7 +2528,7 @@ bool SwTransferable::PasteTargetURL( const 
TransferableDataHelper& rData,
                     else
                     {
                         SwTransferable::SetSelInShell( rSh, false, pPt );
-                        rSh.Insert(sURL, OUString(), aGraphic);
+                        rSh.InsertGraphic(sURL, OUString(), aGraphic);
                     }
                     break;
                 default:
@@ -2634,7 +2634,7 @@ bool SwTransferable::PasteDDE( const 
TransferableDataHelper& rData,
             if ( bReReadGrf )
                 rWrtShell.ReRead( aCmd, sLnkTyp, &aGrf );
             else
-                rWrtShell.Insert( aCmd, sLnkTyp, aGrf );
+                rWrtShell.InsertGraphic( aCmd, sLnkTyp, aGrf );
         }
         return bRet;
     }
@@ -2927,7 +2927,7 @@ bool SwTransferable::PasteGrf( const 
TransferableDataHelper& rData, SwWrtShell&
             case SwPasteSdr::Insert:
             {
                 SwTransferable::SetSelInShell( rSh, false, pPt );
-                rSh.Insert(sURL, OUString(), aGraphic, nullptr, nAnchorType);
+                rSh.InsertGraphic(sURL, OUString(), aGraphic, nullptr, 
nAnchorType);
                 break;
             }
 
@@ -2981,7 +2981,7 @@ bool SwTransferable::PasteGrf( const 
TransferableDataHelper& rData, SwWrtShell&
                 else
                 {
                     SwTransferable::SetSelInShell( rSh, false, pPt );
-                    rSh.Insert(aBkmk.GetURL(), OUString(), aGraphic);
+                    rSh.InsertGraphic(aBkmk.GetURL(), OUString(), aGraphic);
                 }
                 break;
             }
diff --git a/sw/source/uibase/inc/wrtsh.hxx b/sw/source/uibase/inc/wrtsh.hxx
index a80f42c8315a..91cb72146fc0 100644
--- a/sw/source/uibase/inc/wrtsh.hxx
+++ b/sw/source/uibase/inc/wrtsh.hxx
@@ -309,7 +309,7 @@ typedef bool (SwWrtShell::*FNSimpleMove)();
     bool    InsertField2(SwField const &, SwPaM* pAnnotationRange = nullptr);
     void    Insert(const OUString &);
     // graphic
-    void    Insert( const OUString &rPath, const OUString &rFilter,
+    void    InsertGraphic( const OUString &rPath, const OUString &rFilter,
                     const Graphic &, SwFlyFrameAttrMgr * = nullptr,
                     RndStdIds nAnchorType = RndStdIds::FLY_AT_PARA);
 
diff --git a/sw/source/uibase/shells/basesh.cxx 
b/sw/source/uibase/shells/basesh.cxx
index 810f26b873fb..a5ea0e6b1012 100644
--- a/sw/source/uibase/shells/basesh.cxx
+++ b/sw/source/uibase/shells/basesh.cxx
@@ -916,7 +916,7 @@ void SwBaseShell::Execute(SfxRequest &rReq)
                 if ( nSelType & SelectionType::Graphic )
                     rSh.ReRead( aGrfName, aFltName, &aGrf );
                 else
-                    rSh.Insert( aGrfName, aFltName, aGrf );
+                    rSh.InsertGraphic( aGrfName, aFltName, aGrf );
 
                 GetView().GetEditWin().GrabFocus();
             }
diff --git a/sw/source/uibase/shells/textsh.cxx 
b/sw/source/uibase/shells/textsh.cxx
index a8326e40200e..94b0a50e211a 100644
--- a/sw/source/uibase/shells/textsh.cxx
+++ b/sw/source/uibase/shells/textsh.cxx
@@ -234,6 +234,11 @@ void SwTextShell::ExecInsert(SfxRequest &rReq)
         rReq.Done();
         break;
 
+    case FN_INSERT_PICTURE_CONTENT_CONTROL:
+        rSh.InsertContentControl(SwContentControlType::PICTURE);
+        rReq.Done();
+        break;
+
     case FN_CONTENT_CONTROL_PROPERTIES:
     {
         SwWrtShell& rWrtSh = GetShell();
diff --git a/sw/source/uibase/uiview/view.cxx b/sw/source/uibase/uiview/view.cxx
index d26759e3ea4c..1400e25dcd0e 100644
--- a/sw/source/uibase/uiview/view.cxx
+++ b/sw/source/uibase/uiview/view.cxx
@@ -595,7 +595,7 @@ void SwView::CheckReadonlyState()
             FN_INSERT_HARDHYPHEN,       FN_INSERT_HARD_SPACE,       
FN_INSERT_NNBSP,
             FN_INSERT_BREAK,            FN_INSERT_LINEBREAK,        
FN_INSERT_COLUMN_BREAK,
             FN_INSERT_BREAK_DLG,        FN_INSERT_CONTENT_CONTROL,  
FN_INSERT_CHECKBOX_CONTENT_CONTROL,
-            FN_INSERT_DROPDOWN_CONTENT_CONTROL,
+            FN_INSERT_DROPDOWN_CONTENT_CONTROL, 
FN_INSERT_PICTURE_CONTENT_CONTROL,
             FN_DELETE_SENT,             FN_DELETE_BACK_SENT,        
FN_DELETE_WORD,
             FN_DELETE_BACK_WORD,        FN_DELETE_LINE,             
FN_DELETE_BACK_LINE,
             FN_DELETE_PARA,             FN_DELETE_BACK_PARA,        
FN_DELETE_WHOLE_LINE,
@@ -1777,7 +1777,7 @@ void SwView::ScannerEventHdl()
                 if( !aScanBmp.IsEmpty() )
                 {
                     Graphic aGrf(aScanBmp);
-                    m_pWrtShell->Insert( OUString(), OUString(), aGrf );
+                    m_pWrtShell->InsertGraphic( OUString(), OUString(), aGrf );
                 }
             }
         }
diff --git a/sw/source/uibase/uiview/view2.cxx 
b/sw/source/uibase/uiview/view2.cxx
index f83173640f17..60c2395293b6 100644
--- a/sw/source/uibase/uiview/view2.cxx
+++ b/sw/source/uibase/uiview/view2.cxx
@@ -281,11 +281,11 @@ ErrCode SwView::InsertGraphic( const OUString &rPath, 
const OUString &rFilter,
                 OUString sURL = URIHelper::SmartRel2Abs(
                     aTemp, rPath, URIHelper::GetMaybeFileHdl() );
                 aGraphic.setOriginURL(sURL);
-                rShell.Insert( sURL, rFilter, aGraphic, &aFrameManager );
+                rShell.InsertGraphic( sURL, rFilter, aGraphic, &aFrameManager 
);
             }
             else
             {
-                rShell.Insert( OUString(), OUString(), aGraphic, 
&aFrameManager );
+                rShell.InsertGraphic( OUString(), OUString(), aGraphic, 
&aFrameManager );
             }
 
             // it is too late after "EndAction" because the Shell can already 
be destroyed.
diff --git a/sw/source/uibase/wrtsh/wrtsh1.cxx 
b/sw/source/uibase/wrtsh/wrtsh1.cxx
index 51a602fec6e4..07147f9f3a37 100644
--- a/sw/source/uibase/wrtsh/wrtsh1.cxx
+++ b/sw/source/uibase/wrtsh/wrtsh1.cxx
@@ -102,6 +102,7 @@
 #include <svx/postattr.hxx>
 #include <comphelper/lok.hxx>
 #include <comphelper/propertyvalue.hxx>
+#include <svtools/optionsdrawinglayer.hxx>
 #include <memory>
 
 #include <frmtool.hxx>
@@ -266,9 +267,9 @@ void SwWrtShell::Insert( const OUString &rStr )
 // Maximum height limit not possible, because the maximum height
 // of the current frame can not be obtained.
 
-void SwWrtShell::Insert( const OUString &rPath, const OUString &rFilter,
-                         const Graphic &rGrf, SwFlyFrameAttrMgr *pFrameMgr,
-                         RndStdIds nAnchorType )
+void SwWrtShell::InsertGraphic( const OUString &rPath, const OUString &rFilter,
+                                const Graphic &rGrf, SwFlyFrameAttrMgr 
*pFrameMgr,
+                                RndStdIds nAnchorType )
 {
     ResetCursorStack();
     if ( !CanInsert() )
@@ -1025,7 +1026,6 @@ void 
SwWrtShell::InsertContentControl(SwContentControlType eType)
     switch (eType)
     {
         case SwContentControlType::RICH_TEXT:
-        case SwContentControlType::PICTURE:
         {
             pContentControl->SetShowingPlaceHolder(true);
             if (!HasSelection())
@@ -1056,6 +1056,50 @@ void 
SwWrtShell::InsertContentControl(SwContentControlType eType)
             pContentControl->SetListItems({ aListItem });
             break;
         }
+        case SwContentControlType::PICTURE:
+        {
+            // Set up the picture content control.
+            pContentControl->SetShowingPlaceHolder(true);
+            pContentControl->SetPicture(true);
+
+            // Create the placeholder bitmap.
+            BitmapEx aBitmap(Size(1, 1), vcl::PixelFormat::N24_BPP);
+            Color aColor = SvtOptionsDrawinglayer::getHilightColor();
+            aColor.IncreaseLuminance(255 * 0.75);
+            aBitmap.Erase(aColor);
+            SwRewriter aRewriter;
+            aRewriter.AddRule(UndoArg1, SwResId(STR_GRAPHIC_DEFNAME));
+            StartUndo(SwUndoId::INSERT, &aRewriter);
+            LockPaint();
+            StartAction();
+            InsertGraphic(OUString(), OUString(), aBitmap, nullptr, 
RndStdIds::FLY_AS_CHAR);
+
+            // Set properties on the bitmap.
+            SfxItemSetFixed<RES_FRM_SIZE, RES_FRM_SIZE> 
aSet(GetDoc()->GetAttrPool());
+            GetFlyFrameAttr(aSet);
+            SwFormatFrameSize aSize(SwFrameSize::Fixed, 3000, 3000);
+            aSet.Put(aSize);
+            SetFlyFrameAttr(aSet);
+            SwFrameFormat* pFrameFormat = GetFlyFrameFormat();
+            EndAction();
+            UnlockPaint();
+            EndUndo();
+
+            // Go after the anchor position.
+            UnSelectFrame();
+            LeaveSelFrameMode();
+            {
+                SwCursor* pCursor = getShellCursor(true);
+                pCursor->DeleteMark();
+                const SwPosition* pAnchor = 
pFrameFormat->GetAnchor().GetContentAnchor();
+                pCursor->GetPoint()->nContent = pAnchor->nContent;
+                ++pCursor->GetPoint()->nContent;
+            }
+
+            // Select before the anchor position.
+            Left(CRSR_SKIP_CHARS, /*bSelect=*/true, 1, /*bBasicCall=*/false);
+            break;
+        }
     }
     if (aPlaceholder.getLength())
     {
diff --git a/sw/uiconfig/swriter/menubar/menubar.xml 
b/sw/uiconfig/swriter/menubar/menubar.xml
index 50be3dde2bba..c755f9cc88da 100644
--- a/sw/uiconfig/swriter/menubar/menubar.xml
+++ b/sw/uiconfig/swriter/menubar/menubar.xml
@@ -713,6 +713,7 @@
       <menu:menu menu:id=".uno:ContentControlsMenu">
         <menu:menupopup>
           <menu:menuitem menu:id=".uno:InsertContentControl"/>
+          <menu:menuitem menu:id=".uno:InsertPictureContentControl"/>
           <menu:menuitem menu:id=".uno:InsertCheckboxContentControl"/>
           <menu:menuitem menu:id=".uno:InsertDropdownContentControl"/>
           <menu:menuitem menu:id=".uno:ContentControlProperties"/>
diff --git a/sw/uiconfig/swriter/menubar/mscompatibleformsmenu.xml 
b/sw/uiconfig/swriter/menubar/mscompatibleformsmenu.xml
index 147b4dd03d6e..cc4483cda320 100644
--- a/sw/uiconfig/swriter/menubar/mscompatibleformsmenu.xml
+++ b/sw/uiconfig/swriter/menubar/mscompatibleformsmenu.xml
@@ -16,6 +16,7 @@
       <menu:menu menu:id=".uno:MSCompatContentControls">
         <menu:menupopup>
           <menu:menuitem menu:id=".uno:InsertContentControl"/>
+          <menu:menuitem menu:id=".uno:InsertPictureContentControl"/>
           <menu:menuitem menu:id=".uno:InsertCheckboxContentControl"/>
           <menu:menuitem menu:id=".uno:InsertDropdownContentControl"/>
           <menu:menuitem menu:id=".uno:DatePickerFormField"/>
commit 2e6b891afacd59c70f5ff164a4144c24ee7988b2
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Fri May 20 08:54:28 2022 +0200
Commit:     Miklos Vajna <vmik...@collabora.com>
CommitDate: Tue May 24 13:13:46 2022 +0200

    sw content controls, picture: add DOCX filter
    
    Map Picture UNO property on content controls to:
    
        <w:sdt>
          <w:sdtPr>
            <w:picture/>
        ...
    
    And do the opposite on import.
    
    (cherry picked from commit 22d7cbc0f0c50c59abca7ab5f7db46e4d0e5f86a)
    
    Conflicts:
            sw/qa/extras/ooxmlexport/ooxmlexport17.cxx
    
    Change-Id: I5b164f796f194f5fc4bb30d7a30e053e577ed92d
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/134848
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com>
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>

diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport17.cxx 
b/sw/qa/extras/ooxmlexport/ooxmlexport17.cxx
index 1c4c99597c21..58b7a4845aec 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport17.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport17.cxx
@@ -185,7 +185,7 @@ CPPUNIT_TEST_FIXTURE(Test, testCheckboxContentControlExport)
 
 CPPUNIT_TEST_FIXTURE(Test, testDropdownContentControlExport)
 {
-    // Given a document with a checkbox content control around a text portion:
+    // Given a document with a dropdown content control around a text portion:
     mxComponent = loadFromDesktop("private:factory/swriter");
     uno::Reference<lang::XMultiServiceFactory> xMSF(mxComponent, 
uno::UNO_QUERY);
     uno::Reference<text::XTextDocument> xTextDocument(mxComponent, 
uno::UNO_QUERY);
@@ -235,6 +235,41 @@ CPPUNIT_TEST_FIXTURE(Test, 
testDropdownContentControlExport)
     assertXPath(pXmlDoc, "//w:sdt/w:sdtPr/w:dropDownList/w:listItem[3]", 
"value", "B");
 }
 
+CPPUNIT_TEST_FIXTURE(Test, testPictureContentControlExport)
+{
+    // Given a document with a picture content control around a text portion:
+    mxComponent = loadFromDesktop("private:factory/swriter");
+    uno::Reference<lang::XMultiServiceFactory> xMSF(mxComponent, 
uno::UNO_QUERY);
+    uno::Reference<text::XTextDocument> xTextDocument(mxComponent, 
uno::UNO_QUERY);
+    uno::Reference<text::XText> xText = xTextDocument->getText();
+    uno::Reference<text::XTextCursor> xCursor = xText->createTextCursor();
+    uno::Reference<beans::XPropertySet> xTextGraphic(
+        xMSF->createInstance("com.sun.star.text.TextGraphicObject"), 
uno::UNO_QUERY);
+    xTextGraphic->setPropertyValue("AnchorType",
+                                   
uno::Any(text::TextContentAnchorType_AS_CHARACTER));
+    uno::Reference<text::XTextContent> xTextContent(xTextGraphic, 
uno::UNO_QUERY);
+    xText->insertTextContent(xCursor, xTextContent, false);
+    xCursor->gotoStart(/*bExpand=*/false);
+    xCursor->gotoEnd(/*bExpand=*/true);
+    uno::Reference<text::XTextContent> xContentControl(
+        xMSF->createInstance("com.sun.star.text.ContentControl"), 
uno::UNO_QUERY);
+    uno::Reference<beans::XPropertySet> xContentControlProps(xContentControl, 
uno::UNO_QUERY);
+    xContentControlProps->setPropertyValue("Picture", uno::Any(true));
+    xText->insertTextContent(xCursor, xContentControl, /*bAbsorb=*/true);
+
+    // When exporting to DOCX:
+    save("Office Open XML Text", maTempFile);
+    mbExported = true;
+
+    // Then make sure the expected markup is used:
+    xmlDocUniquePtr pXmlDoc = parseExport("word/document.xml");
+    // Without the fix in place, this test would have failed with:
+    // - Expected: 1
+    // - Actual  : 0
+    // i.e. <w:picture> was lost on export.
+    assertXPath(pXmlDoc, "//w:sdt/w:sdtPr/w:picture", 1);
+}
+
 DECLARE_OOXMLEXPORT_TEST(testTdf137466, "tdf137466.docx")
 {
     xmlDocUniquePtr pXmlDoc = parseExport("word/document.xml");
diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx 
b/sw/source/filter/ww8/docxattributeoutput.cxx
index 939f3cffbbf2..322c8e896658 100644
--- a/sw/source/filter/ww8/docxattributeoutput.cxx
+++ b/sw/source/filter/ww8/docxattributeoutput.cxx
@@ -2343,6 +2343,11 @@ void DocxAttributeOutput::WriteContentControlStart()
         m_pSerializer->singleElementNS(XML_w, XML_showingPlcHdr);
     }
 
+    if (m_pContentControl->GetPicture())
+    {
+        m_pSerializer->singleElementNS(XML_w, XML_picture);
+    }
+
     if (m_pContentControl->GetCheckbox())
     {
         m_pSerializer->startElementNS(XML_w14, XML_checkbox);
diff --git a/writerfilter/qa/cppunittests/dmapper/SdtHelper.cxx 
b/writerfilter/qa/cppunittests/dmapper/SdtHelper.cxx
index 633355c79a5f..b2e7f1058f88 100644
--- a/writerfilter/qa/cppunittests/dmapper/SdtHelper.cxx
+++ b/writerfilter/qa/cppunittests/dmapper/SdtHelper.cxx
@@ -181,6 +181,39 @@ CPPUNIT_TEST_FIXTURE(Test, testSdtRunDropdown)
     uno::Reference<text::XTextRange> xContent(xContentEnum->nextElement(), 
uno::UNO_QUERY);
     CPPUNIT_ASSERT_EQUAL(OUString("choose a color"), xContent->getString());
 }
+
+CPPUNIT_TEST_FIXTURE(Test, testSdtRunPicture)
+{
+    // Given a document with a dropdown inline/run SDT:
+    OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + 
"sdt-run-picture.docx";
+
+    // When loading the document:
+    getComponent() = loadFromDesktop(aURL);
+
+    // Then make sure that the doc model has a clickable picture content 
control:
+    uno::Reference<text::XTextDocument> xTextDocument(getComponent(), 
uno::UNO_QUERY);
+    uno::Reference<container::XEnumerationAccess> 
xParagraphsAccess(xTextDocument->getText(),
+                                                                    
uno::UNO_QUERY);
+    uno::Reference<container::XEnumeration> xParagraphs = 
xParagraphsAccess->createEnumeration();
+    uno::Reference<container::XEnumerationAccess> 
xParagraph(xParagraphs->nextElement(),
+                                                             uno::UNO_QUERY);
+    uno::Reference<container::XEnumeration> xPortions = 
xParagraph->createEnumeration();
+    uno::Reference<beans::XPropertySet> xTextPortion(xPortions->nextElement(), 
uno::UNO_QUERY);
+    OUString aPortionType;
+    xTextPortion->getPropertyValue("TextPortionType") >>= aPortionType;
+    // Without the accompanying fix in place, this failed with:
+    // - Expected: ContentControl
+    // - Actual  : Frame
+    // i.e. the SDT was imported as a plain image, not as a clickable 
placeholder in a content
+    // control.
+    CPPUNIT_ASSERT_EQUAL(OUString("ContentControl"), aPortionType);
+    uno::Reference<text::XTextContent> xContentControl;
+    xTextPortion->getPropertyValue("ContentControl") >>= xContentControl;
+    uno::Reference<beans::XPropertySet> xContentControlProps(xContentControl, 
uno::UNO_QUERY);
+    bool bPicture{};
+    xContentControlProps->getPropertyValue("Picture") >>= bPicture;
+    CPPUNIT_ASSERT(bPicture);
+}
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/qa/cppunittests/dmapper/data/sdt-run-picture.docx 
b/writerfilter/qa/cppunittests/dmapper/data/sdt-run-picture.docx
new file mode 100644
index 000000000000..25fcc7f6f8f9
Binary files /dev/null and 
b/writerfilter/qa/cppunittests/dmapper/data/sdt-run-picture.docx differ
diff --git a/writerfilter/source/dmapper/DomainMapper.cxx 
b/writerfilter/source/dmapper/DomainMapper.cxx
index 817bd1125ce1..0f9139e80890 100644
--- a/writerfilter/source/dmapper/DomainMapper.cxx
+++ b/writerfilter/source/dmapper/DomainMapper.cxx
@@ -1098,6 +1098,7 @@ void DomainMapper::lcl_attribute(Id nName, Value & val)
                     case SdtControlType::richText:
                     case SdtControlType::checkBox:
                     case SdtControlType::dropDown:
+                    case SdtControlType::picture:
                         m_pImpl->PopSdt();
                         break;
                     default:
@@ -2787,6 +2788,16 @@ void DomainMapper::sprmWithProps( Sprm& rSprm, const 
PropertyMapPtr& rContext )
                 }
                 break;
             }
+            else if (nSprmId == NS_ooxml::LN_CT_SdtPr_picture)
+            {
+                m_pImpl->m_pSdtHelper->setControlType(SdtControlType::picture);
+                writerfilter::Reference<Properties>::Pointer_t pProperties = 
rSprm.getProps();
+                if (pProperties)
+                {
+                    pProperties->resolve(*this);
+                }
+                break;
+            }
         }
 
         // this is an unsupported SDT property, create a grab bag for it
diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.cxx 
b/writerfilter/source/dmapper/DomainMapper_Impl.cxx
index 813f9943a005..e0eac791f26f 100644
--- a/writerfilter/source/dmapper/DomainMapper_Impl.cxx
+++ b/writerfilter/source/dmapper/DomainMapper_Impl.cxx
@@ -920,6 +920,11 @@ void DomainMapper_Impl::PopSdt()
         }
     }
 
+    if (m_pSdtHelper->getControlType() == SdtControlType::picture)
+    {
+        xContentControlProps->setPropertyValue("Picture", uno::Any(true));
+    }
+
     xText->insertTextContent(xCursor, xContentControl, /*bAbsorb=*/true);
 
     m_pSdtHelper->clear();
diff --git a/writerfilter/source/dmapper/SdtHelper.hxx 
b/writerfilter/source/dmapper/SdtHelper.hxx
index a1aecd2aa704..cdf3bafbb9b0 100644
--- a/writerfilter/source/dmapper/SdtHelper.hxx
+++ b/writerfilter/source/dmapper/SdtHelper.hxx
@@ -44,6 +44,7 @@ enum class SdtControlType
     plainText,
     richText,
     checkBox,
+    picture,
     unsupported, // Sdt block is defined, but we still do not support such 
type of field
     unknown
 };

Reply via email to