diff options
-rw-r--r-- | include/vcl/imaprect.hxx | 2 | ||||
-rw-r--r-- | svtools/source/svhtml/htmlout.cxx | 4 | ||||
-rw-r--r-- | sw/qa/extras/htmlexport/data/tdf160867_image_with_link.fodt | 25 | ||||
-rw-r--r-- | sw/qa/extras/htmlexport/htmlexport.cxx | 21 | ||||
-rw-r--r-- | sw/source/core/inc/noteurl.hxx | 34 | ||||
-rw-r--r-- | sw/source/core/inc/swfont.hxx | 3 | ||||
-rw-r--r-- | sw/source/core/layout/paintfrm.cxx | 1 | ||||
-rw-r--r-- | sw/source/core/text/atrhndl.hxx | 2 | ||||
-rw-r--r-- | sw/source/core/text/atrstck.cxx | 15 | ||||
-rw-r--r-- | sw/source/core/text/inftxt.cxx | 21 | ||||
-rw-r--r-- | sw/source/core/text/inftxt.hxx | 7 | ||||
-rw-r--r-- | sw/source/core/text/itrform2.cxx | 2 | ||||
-rw-r--r-- | sw/source/core/text/itrpaint.cxx | 3 | ||||
-rw-r--r-- | sw/source/core/text/noteurl.cxx | 35 | ||||
-rw-r--r-- | sw/source/core/text/pormulti.cxx | 3 | ||||
-rw-r--r-- | sw/source/core/txtnode/swfont.cxx | 2 |
16 files changed, 176 insertions, 4 deletions
diff --git a/include/vcl/imaprect.hxx b/include/vcl/imaprect.hxx index 89cb52d80bbe..8abe1ed39960 100644 --- a/include/vcl/imaprect.hxx +++ b/include/vcl/imaprect.hxx @@ -25,7 +25,7 @@ class Fraction; -class UNLESS_MERGELIBS(VCL_DLLPUBLIC) IMapRectangleObject final : public IMapObject +class VCL_DLLPUBLIC IMapRectangleObject final : public IMapObject { tools::Rectangle aRect; diff --git a/svtools/source/svhtml/htmlout.cxx b/svtools/source/svhtml/htmlout.cxx index 956546269708..d165a8922f02 100644 --- a/svtools/source/svhtml/htmlout.cxx +++ b/svtools/source/svhtml/htmlout.cxx @@ -702,7 +702,7 @@ SvStream& HTMLOutFuncs::Out_ImageMap( SvStream& rStream, sOut.append(OString::Concat("<") + OOO_STRING_SVTOOLS_HTML_area " " OOO_STRING_SVTOOLS_HTML_O_shape - "=" + pShape + " " + "=\"" + pShape + "\" " OOO_STRING_SVTOOLS_HTML_O_coords "=\"" + aCoords + "\" "); rStream.WriteOString( sOut ); @@ -756,7 +756,7 @@ SvStream& HTMLOutFuncs::Out_ImageMap( SvStream& rStream, Out_Events( rStream, rMacroTab, pEventTable, bOutStarBasic ); - rStream.WriteChar( '>' ); + rStream.WriteOString("/>"); } } diff --git a/sw/qa/extras/htmlexport/data/tdf160867_image_with_link.fodt b/sw/qa/extras/htmlexport/data/tdf160867_image_with_link.fodt new file mode 100644 index 000000000000..43c35cdff13e --- /dev/null +++ b/sw/qa/extras/htmlexport/data/tdf160867_image_with_link.fodt @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<office:document xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0" office:version="1.3" office:mimetype="application/vnd.oasis.opendocument.text"> + <office:styles> + <style:style style:name="Frame" style:family="graphic"> + <style:graphic-properties text:anchor-type="as-char" svg:x="0" svg:y="0" style:number-wrapped-paragraphs="no-limit" style:wrap-contour="false" fo:background-color="transparent" draw:fill="none" fo:margin-left="0" fo:margin-right="0" fo:margin-top="0" fo:margin-bottom="0" style:wrap="none" style:vertical-pos="middle" style:vertical-rel="baseline" style:horizontal-pos="from-left" style:horizontal-rel="paragraph" fo:padding="0" fo:border="none" loext:rel-width-rel="paragraph"/> + </style:style> + </office:styles> + <office:body> + <office:text> + <text:p><draw:a xlink:type="simple" xlink:href="foo/bar"><draw:frame draw:style-name="Frame" draw:name="image1" svg:width="17cm" svg:height="25mm" style:rel-height="scale"><draw:image draw:mime-type="image/png"> + <office:binary-data>iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsIAAA7CARUoSoAAAAAMSURBVBhXY/jPwAAAAwEBAGMkVdMAAAAASUVORK5C</office:binary-data> + </draw:image> + </draw:frame></draw:a>image1 with a hyperlink, and this text with <text:a xlink:type="simple" xlink:href="baz" text:style-name="Internet_20_link" text:visited-style-name="Visited_20_Internet_20_Link">another hyperlink</text:a></text:p> + <text:p><draw:frame draw:style-name="Frame" draw:name="frame" svg:width="17cm"> + <draw:text-box fo:min-height="1pt"> + <text:p><draw:a xlink:type="simple" xlink:href="foo/bar"><draw:frame draw:style-name="Frame" draw:name="image2" svg:width="17cm" svg:height="25mm"><draw:image draw:mime-type="image/png"> + <office:binary-data>iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsIAAA7CARUoSoAAAAAMSURBVBhXY/jPwAAAAwEBAGMkVdMAAAAASUVORK5C</office:binary-data> + </draw:image> + </draw:frame></draw:a>image2 with a hyperlink, and this text with <text:a xlink:type="simple" xlink:href="baz" text:style-name="Internet_20_link" text:visited-style-name="Visited_20_Internet_20_Link">another hyperlink</text:a>, in a frame</text:p> + </draw:text-box> + </draw:frame></text:p> + </office:text> + </office:body> +</office:document>
\ No newline at end of file diff --git a/sw/qa/extras/htmlexport/htmlexport.cxx b/sw/qa/extras/htmlexport/htmlexport.cxx index 6a23599184a5..329be9231bb9 100644 --- a/sw/qa/extras/htmlexport/htmlexport.cxx +++ b/sw/qa/extras/htmlexport/htmlexport.cxx @@ -3082,6 +3082,27 @@ CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testHTML_Tdf160390) ExportToHTML(); } +CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testHTML_160867) +{ + // Given a document with an image with hyperlink, and text with hyperlink, both in a frame: + createSwDoc("tdf160867_image_with_link.fodt"); + // When exporting to HTML: + ExportToHTML(); + // Parse it as XML (strict!) + xmlDocUniquePtr pDoc = parseXml(maTempFile); + CPPUNIT_ASSERT(pDoc); + assertXPath(pDoc, "/html/body/p"_ostr, 2); + + // Test export of text hyperlink in the image map. TODO: implement export of image hyperlink. + // Without the fix, the test would fail with + // - Expected: 1 + // - Actual : 0 + // - In <>, XPath '/html/body/p[2]/map' number of nodes is incorrect + const OUString mapName = getXPath(pDoc, "/html/body/p[2]/map"_ostr, "name"_ostr); + assertXPath(pDoc, "/html/body/p[2]/map/area"_ostr, "shape"_ostr, u"rect"_ustr); + assertXPath(pDoc, "/html/body/p[2]/img"_ostr, "usemap"_ostr, "#" + mapName); +} + } // end of anonymous namespace CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/sw/source/core/inc/noteurl.hxx b/sw/source/core/inc/noteurl.hxx index 1e5775d3c099..eeae15642a43 100644 --- a/sw/source/core/inc/noteurl.hxx +++ b/sw/source/core/inc/noteurl.hxx @@ -20,8 +20,42 @@ #ifndef INCLUDED_SW_SOURCE_CORE_INC_NOTEURL_HXX #define INCLUDED_SW_SOURCE_CORE_INC_NOTEURL_HXX +#include <swrect.hxx> + +#include <rtl/ustring.hxx> + +#include <vector> + +class ImageMap; +class MapMode; + +class SwURLNote +{ + OUString aURL; + OUString aTarget; + SwRect aRect; + +public: + SwURLNote(const OUString& rURL, const OUString& rTarget, const SwRect& rRect) + : aURL(rURL) + , aTarget(rTarget) + , aRect(rRect) + { + } + const OUString& GetURL() const { return aURL; } + const OUString& GetTarget() const { return aTarget; } + const SwRect& GetRect() const { return aRect; } +}; + class SwNoteURL { +private: + std::vector<SwURLNote> m_List; + +public: + SwNoteURL() {} + void InsertURLNote(const OUString& rURL, const OUString& rTarget, const SwRect& rRect); + void FillImageMap(ImageMap* pMap, const Point& rPos, const MapMode& rMap); }; // globale Variable, in NoteURL.Cxx angelegt diff --git a/sw/source/core/inc/swfont.hxx b/sw/source/core/inc/swfont.hxx index a8c3320d1cb8..25453744bd3f 100644 --- a/sw/source/core/inc/swfont.hxx +++ b/sw/source/core/inc/swfont.hxx @@ -174,6 +174,7 @@ class SwFont bool m_bFontChg :1; bool m_bOrgChg :1; // nOrgHeight/Ascent are invalid bool m_bGreyWave :1; // for the extended TextInput: gray waveline + bool m_bURL : 1 = false; public: SwFont( const SwAttrSet* pSet, const IDocumentSettingAccess* pIDocumentSettingAccess ); @@ -264,6 +265,8 @@ public: inline void SetGreyWave( const bool bNew ); bool IsGreyWave() const { return m_bGreyWave; } bool IsPaintBlank() const { return m_bPaintBlank; } + void SetURL(const bool bURL) { m_bURL = bURL; } + bool IsURL() const { return m_bURL; } // setting of the base class font for SwTextCharFormat void SetDiffFnt( const SfxItemSet* pSet, diff --git a/sw/source/core/layout/paintfrm.cxx b/sw/source/core/layout/paintfrm.cxx index 8aa4c3738934..1e8600d83094 100644 --- a/sw/source/core/layout/paintfrm.cxx +++ b/sw/source/core/layout/paintfrm.cxx @@ -8136,6 +8136,7 @@ Graphic SwFlyFrameFormat::MakeGraphic( ImageMap* pMap, const sal_uInt32 /*nMaxim if( bNoteURL ) { OSL_ENSURE( pNoteURL, "MakeGraphic: Good Bye, NoteURL." ); + pNoteURL->FillImageMap(pMap, pFly->getFrameArea().Pos(), aMap); delete pNoteURL; pNoteURL = nullptr; } diff --git a/sw/source/core/text/atrhndl.hxx b/sw/source/core/text/atrhndl.hxx index 851615325a06..efe1ae954958 100644 --- a/sw/source/core/text/atrhndl.hxx +++ b/sw/source/core/text/atrhndl.hxx @@ -46,6 +46,8 @@ private: // a template, if we have to restart the attribute evaluation std::optional<SwFont> m_oFnt; + int m_nINETFMT = 0; // for font's SetURL + bool m_bVertLayout; bool m_bVertLayoutLRBT; diff --git a/sw/source/core/text/atrstck.cxx b/sw/source/core/text/atrstck.cxx index 0eb8d74e89c6..82a3da7fbf17 100644 --- a/sw/source/core/text/atrstck.cxx +++ b/sw/source/core/text/atrstck.cxx @@ -367,6 +367,13 @@ void SwAttrHandler::PushAndChg( const SwTextAttr& rAttr, SwFont& rFnt ) } } } + + if (rAttr.Which() == RES_TXTATR_INETFMT) + { + if (m_nINETFMT == 0) + rFnt.SetURL(true); + ++m_nINETFMT; + } } // this is the usual case, we have a basic attribute, push it onto the // stack and change the font @@ -433,6 +440,14 @@ void SwAttrHandler::PopAndChg( const SwTextAttr& rAttr, SwFont& rFnt ) const SfxItemSet* pSet = CharFormat::GetItemSet( rAttr.GetAttr() ); if ( !pSet ) return; + if (rAttr.Which() == RES_TXTATR_INETFMT) + { + assert(m_nINETFMT > 0); + --m_nINETFMT; + if (m_nINETFMT == 0) + rFnt.SetURL(false); + } + for ( sal_uInt16 i = RES_CHRATR_BEGIN; i < RES_CHRATR_END; i++) { const SfxPoolItem* pItem; diff --git a/sw/source/core/text/inftxt.cxx b/sw/source/core/text/inftxt.cxx index b293f18f824a..a1a3bb89a87b 100644 --- a/sw/source/core/text/inftxt.cxx +++ b/sw/source/core/text/inftxt.cxx @@ -21,7 +21,9 @@ #include <unotools/linguprops.hxx> #include <unotools/lingucfg.hxx> +#include <fmtinfmt.hxx> #include <hintids.hxx> +#include <txatbase.hxx> #include <svl/ctloptions.hxx> #include <sfx2/infobar.hxx> #include <sfx2/printer.hxx> @@ -1461,6 +1463,25 @@ void SwTextPaintInfo::DrawViewOpt( const SwLinePortion &rPor, DrawBackground( rPor, pColor ); } +void SwTextPaintInfo::NotifyURL_(const SwLinePortion& rPor) const +{ + assert(pNoteURL); + + SwRect aIntersect; + CalcRect(rPor, nullptr, &aIntersect); + + if (aIntersect.HasArea()) + { + SwTextNode* pNd = const_cast<SwTextNode*>(GetTextFrame()->GetTextNodeFirst()); + SwTextAttr* const pAttr = pNd->GetTextAttrAt(sal_Int32(GetIdx()), RES_TXTATR_INETFMT); + if (pAttr) + { + const SwFormatINetFormat& rFormat = pAttr->GetINetFormat(); + pNoteURL->InsertURLNote(rFormat.GetValue(), rFormat.GetTargetFrame(), aIntersect); + } + } +} + static void lcl_InitHyphValues( PropertyValues &rVals, sal_Int16 nMinLeading, sal_Int16 nMinTrailing, bool bNoCapsHyphenation, bool bNoLastWordHyphenation, diff --git a/sw/source/core/text/inftxt.hxx b/sw/source/core/text/inftxt.hxx index cb11d02b1e8d..9c4126a7a6e9 100644 --- a/sw/source/core/text/inftxt.hxx +++ b/sw/source/core/text/inftxt.hxx @@ -358,6 +358,7 @@ class SwTextPaintInfo : public SwTextSizeInfo const bool bGrammarCheck = false ); SwTextPaintInfo &operator=(const SwTextPaintInfo&) = delete; + void NotifyURL_(const SwLinePortion& rPor) const; protected: SwTextPaintInfo() @@ -418,6 +419,12 @@ public: void DrawCSDFHighlighting(const SwLinePortion &rPor) const; + void NotifyURL(const SwLinePortion& rPor) const + { + if (URLNotify()) + NotifyURL_(rPor); + } + /** * Calculate the rectangular area where the portion takes place. * @param[in] rPor portion for which the method specify the painting area diff --git a/sw/source/core/text/itrform2.cxx b/sw/source/core/text/itrform2.cxx index 2d24e103957a..046aa6bde1ea 100644 --- a/sw/source/core/text/itrform2.cxx +++ b/sw/source/core/text/itrform2.cxx @@ -1318,7 +1318,7 @@ SwTextPortion *SwTextFormatter::WhichTextPor( SwTextFormatInfo &rInf ) const } if( !pPor ) { - if( !rInf.X() && !m_pCurr->GetNextPortion() && !m_pCurr->GetLen() ) + if( !rInf.X() && !m_pCurr->GetNextPortion() && !m_pCurr->GetLen() && !GetFnt()->IsURL() ) pPor = m_pCurr; else pPor = new SwTextPortion; diff --git a/sw/source/core/text/itrpaint.cxx b/sw/source/core/text/itrpaint.cxx index 5b6bb1288d57..8fa9ca45f5fd 100644 --- a/sw/source/core/text/itrpaint.cxx +++ b/sw/source/core/text/itrpaint.cxx @@ -459,6 +459,9 @@ void SwTextPainter::DrawTextLine( const SwRect &rPaint, SwSaveClip &rClip, // reset (for special vertical alignment) GetInfo().Y( nOldY ); + if (GetFnt()->IsURL() && pPor->InTextGrp()) + GetInfo().NotifyURL(*pPor); + bFirst &= !pPor->GetLen(); if( pNext || !pPor->IsMarginPortion() ) pPor->Move( GetInfo() ); diff --git a/sw/source/core/text/noteurl.cxx b/sw/source/core/text/noteurl.cxx index fa91ea252d5f..ae52e1c29a91 100644 --- a/sw/source/core/text/noteurl.cxx +++ b/sw/source/core/text/noteurl.cxx @@ -19,7 +19,42 @@ #include <noteurl.hxx> +#include <vcl/imap.hxx> +#include <vcl/imaprect.hxx> +#include <vcl/mapmod.hxx> +#include <vcl/outdev.hxx> + // Global variable SwNoteURL* pNoteURL = nullptr; +void SwNoteURL::InsertURLNote(const OUString& rURL, const OUString& rTarget, const SwRect& rRect) +{ + const size_t nCount = m_List.size(); + for (size_t i = 0; i < nCount; ++i) + if (rRect == m_List[i].GetRect()) + return; + + m_List.emplace_back(rURL, rTarget, rRect); +} + +void SwNoteURL::FillImageMap(ImageMap* pMap, const Point& rPos, const MapMode& rMap) +{ + assert(pMap && "FillImageMap: No ImageMap, no cookies!"); + const size_t nCount = m_List.size(); + if (nCount) + { + MapMode aMap(MapUnit::Map100thMM); + for (size_t i = 0; i < nCount; ++i) + { + const SwURLNote& rNote = m_List[i]; + SwRect aSwRect(rNote.GetRect()); + aSwRect -= rPos; + tools::Rectangle aRect(OutputDevice::LogicToLogic(aSwRect.SVRect(), rMap, aMap)); + IMapRectangleObject aObj(aRect, rNote.GetURL(), OUString(), OUString(), + rNote.GetTarget(), OUString(), true, false); + pMap->InsertIMapObject(aObj); + } + } +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/text/pormulti.cxx b/sw/source/core/text/pormulti.cxx index 9fb6011f0db5..aaf8339b37ef 100644 --- a/sw/source/core/text/pormulti.cxx +++ b/sw/source/core/text/pormulti.cxx @@ -1783,6 +1783,9 @@ void SwTextPainter::PaintMultiPortion( const SwRect &rPaint, pPor->Paint( GetInfo() ); } + if (GetFnt()->IsURL() && pPor->InTextGrp()) + GetInfo().NotifyURL(*pPor); + bFirst &= !pPor->GetLen(); if( pNext || !pPor->IsMarginPortion() ) pPor->Move( GetInfo() ); diff --git a/sw/source/core/txtnode/swfont.cxx b/sw/source/core/txtnode/swfont.cxx index 98fec0f153e2..20b3062267f7 100644 --- a/sw/source/core/txtnode/swfont.cxx +++ b/sw/source/core/txtnode/swfont.cxx @@ -684,6 +684,7 @@ SwFont::SwFont( const SwFont &rFont ) m_bOrgChg = rFont.m_bOrgChg; m_bPaintBlank = rFont.m_bPaintBlank; m_bGreyWave = rFont.m_bGreyWave; + m_bURL = rFont.m_bURL; } SwFont::SwFont( const SwAttrSet* pAttrSet, @@ -873,6 +874,7 @@ SwFont& SwFont::operator=( const SwFont &rFont ) m_bOrgChg = rFont.m_bOrgChg; m_bPaintBlank = rFont.m_bPaintBlank; m_bGreyWave = rFont.m_bGreyWave; + m_bURL = rFont.m_bURL; } return *this; } |