[Libreoffice-commits] core.git: 8 commits - include/svtools include/vcl sfx2/source svtools/qa svtools/source sw/qa sw/source vcl/source

Tomaž Vajngerl tomaz.vajngerl at collabora.com
Sun Sep 21 15:31:59 PDT 2014


 include/svtools/HtmlWriter.hxx             |   31 +
 include/svtools/htmlout.hxx                |    1 
 include/vcl/gdimtf.hxx                     |    6 
 include/vcl/graphicfilter.hxx              |    2 
 sfx2/source/doc/graphhelp.cxx              |   38 +-
 svtools/qa/unit/testHtmlWriter.cxx         |  124 +++++++
 svtools/source/svhtml/HtmlWriter.cxx       |   49 ++
 svtools/source/svhtml/htmlout.cxx          |   25 +
 sw/qa/extras/htmlexport/data/HTMLImage.odt |binary
 sw/qa/extras/htmlexport/htmlexport.cxx     |   30 +
 sw/source/filter/html/htmlatr.cxx          |    3 
 sw/source/filter/html/htmlflywriter.cxx    |  505 +++++++++++++++++++++--------
 sw/source/filter/html/wrthtml.cxx          |   62 +--
 sw/source/filter/html/wrthtml.hxx          |    7 
 vcl/source/filter/graphicfilter.cxx        |   12 
 vcl/source/gdi/gdimtf.cxx                  |   21 -
 16 files changed, 712 insertions(+), 204 deletions(-)

New commits:
commit 935e8fc98c033680029e4531747a2f680f50d5ca
Author: Tomaž Vajngerl <tomaz.vajngerl at collabora.com>
Date:   Mon Sep 22 00:09:22 2014 +0200

    werror: ‘nDirection’ shadows a member of 'this'
    
    Change-Id: Idb56ef8327164f22379b732f9507e0b255b0998c

diff --git a/sw/source/filter/html/wrthtml.cxx b/sw/source/filter/html/wrthtml.cxx
index b64f9aa..5cc182f 100644
--- a/sw/source/filter/html/wrthtml.cxx
+++ b/sw/source/filter/html/wrthtml.cxx
@@ -1307,10 +1307,10 @@ void SwHTMLWriter::OutDirection( sal_uInt16 nDir )
     }
 }
 
-OString SwHTMLWriter::convertDirection(sal_uInt16 nDirection)
+OString SwHTMLWriter::convertDirection(sal_uInt16 nDir)
 {
     OString sConverted;
-    switch (nDirection)
+    switch (nDir)
     {
     case FRMDIR_HORI_LEFT_TOP:
     case FRMDIR_VERT_TOP_LEFT:
commit 2113c50b455ae67874eb61ff0dcd75c766b17002
Author: Tomaž Vajngerl <tomaz.vajngerl at collabora.com>
Date:   Sun Sep 21 21:34:01 2014 +0200

    fdo#62104 Optimize thumbnail size by using PNG8 and other tricks
    
    Change-Id: I54ece4a1977fe93c0e7bbb11774bd8657912c6bb

diff --git a/include/vcl/gdimtf.hxx b/include/vcl/gdimtf.hxx
index 4d863aa..414f430 100644
--- a/include/vcl/gdimtf.hxx
+++ b/include/vcl/gdimtf.hxx
@@ -24,6 +24,7 @@
 #include <tools/gen.hxx>
 #include <tools/link.hxx>
 #include <vcl/mapmod.hxx>
+#include <vcl/bitmap.hxx>
 #include <vector>
 
 class OutputDevice;
@@ -214,7 +215,10 @@ public:
     friend VCL_DLLPUBLIC SvStream& WriteGDIMetaFile( SvStream& rOStm, const GDIMetaFile& rGDIMetaFile );
 
     /// Creates an antialiased thumbnail, with maximum width or height of nMaximumExtent.
-    bool        CreateThumbnail(BitmapEx& rBmpEx, sal_uInt32 nMaximumSize = 256) const;
+    bool        CreateThumbnail(BitmapEx& rBitmapEx,
+                                sal_uInt32 nMaximumExtent = 256,
+                                BmpConversion nColorConversion = BMP_CONVERSION_24BIT,
+                                long nScaleFlag = BMP_SCALE_BESTQUALITY) const;
 
     void            UseCanvas( bool _bUseCanvas );
     bool        GetUseCanvas() const { return bUseCanvas; }
diff --git a/sfx2/source/doc/graphhelp.cxx b/sfx2/source/doc/graphhelp.cxx
index f1d0bc5..2741131 100644
--- a/sfx2/source/doc/graphhelp.cxx
+++ b/sfx2/source/doc/graphhelp.cxx
@@ -39,6 +39,7 @@
 #include <vcl/outdev.hxx>
 #include <vcl/virdev.hxx>
 #include <vcl/bitmapex.hxx>
+#include <vcl/graphicfilter.hxx>
 
 #include <tools/stream.hxx>
 #include <tools/helpers.hxx>
@@ -52,7 +53,7 @@
 #include "graphhelp.hxx"
 #include "doc.hrc"
 
-using namespace ::com::sun::star;
+using namespace css;
 
 SvMemoryStream* GraphicHelper::getFormatStrFromGDI_Impl( const GDIMetaFile* pGDIMeta, sal_uInt32 nFormat )
 {
@@ -192,30 +193,33 @@ bool GraphicHelper::supportsMetaFileHandle_Impl()
 
 
 // static
-bool GraphicHelper::getThumbnailFormatFromGDI_Impl( GDIMetaFile* pMetaFile,
-                                                        const uno::Reference< io::XStream >& xStream )
+bool GraphicHelper::getThumbnailFormatFromGDI_Impl(GDIMetaFile* pMetaFile, const uno::Reference<io::XStream>& xStream)
 {
     bool bResult = false;
-    SvStream* pStream = NULL;
 
-    if ( xStream.is() )
-        pStream = ::utl::UcbStreamHelper::CreateStream( xStream );
+    if (!pMetaFile || !xStream.is())
+        return false;
 
-    if ( pMetaFile && pStream && !pStream->GetError() )
-    {
-        BitmapEx aResultBitmap;
+    boost::scoped_ptr<SvStream> pStream(utl::UcbStreamHelper::CreateStream(xStream));
 
-        bResult = pMetaFile->CreateThumbnail(aResultBitmap);
+    if (pStream->GetError())
+        return false;
 
-        if ( bResult )
-            bResult = ( !aResultBitmap.IsEmpty()
-                        && GraphicConverter::Export( *pStream, aResultBitmap, CVT_PNG ) == 0
-                        && ( pStream->Flush(), !pStream->GetError() ) );
+    BitmapEx aResultBitmap;
 
-        delete pStream;
-    }
+    bResult = pMetaFile->CreateThumbnail(aResultBitmap, 256, BMP_CONVERSION_8BIT_COLORS, BMP_SCALE_DEFAULT);
 
-    return bResult;
+    if (!bResult || aResultBitmap.IsEmpty())
+        return false;
+
+    GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter();
+
+    if (rFilter.compressAsPNG(aResultBitmap, *pStream.get(), 9) != GRFILTER_OK)
+        return false;
+
+    pStream->Flush();
+
+    return !pStream->GetError();
 }
 
 // static
diff --git a/vcl/source/gdi/gdimtf.cxx b/vcl/source/gdi/gdimtf.cxx
index 3bd6eb2..3b0d9d0 100644
--- a/vcl/source/gdi/gdimtf.cxx
+++ b/vcl/source/gdi/gdimtf.cxx
@@ -2879,7 +2879,7 @@ SvStream& GDIMetaFile::Write( SvStream& rOStm )
     return rOStm;
 }
 
-bool GDIMetaFile::CreateThumbnail(BitmapEx& rBmpEx, sal_uInt32 nMaximumExtent) const
+bool GDIMetaFile::CreateThumbnail(BitmapEx& rBitmapEx, sal_uInt32 nMaximumExtent, BmpConversion eColorConversion, long nScaleFlag) const
 {
     // initialization seems to be complicated but is used to avoid rounding errors
     VirtualDevice   aVDev;
@@ -2889,8 +2889,8 @@ bool GDIMetaFile::CreateThumbnail(BitmapEx& rBmpEx, sal_uInt32 nMaximumExtent) c
     Size            aDrawSize( aVDev.LogicToPixel( GetPrefSize(), GetPrefMapMode() ) );
     Size            aSizePix( labs( aBRPix.X() - aTLPix.X() ) + 1, labs( aBRPix.Y() - aTLPix.Y() ) + 1 );
 
-    if ( !rBmpEx.IsEmpty() )
-        rBmpEx.SetEmpty();
+    if (!rBitmapEx.IsEmpty())
+        rBitmapEx.SetEmpty();
 
     // determine size that has the same aspect ratio as image size and
     // fits into the rectangle determined by nMaximumExtent
@@ -2932,19 +2932,18 @@ bool GDIMetaFile::CreateThumbnail(BitmapEx& rBmpEx, sal_uInt32 nMaximumExtent) c
         const_cast<GDIMetaFile *>(this)->Play(&aVDev, aBackPosPix, aAntialias);
 
         // get paint bitmap
-        Bitmap aBmp( aVDev.GetBitmap( aNullPt, aVDev.GetOutputSizePixel() ) );
+        Bitmap aBitmap( aVDev.GetBitmap( aNullPt, aVDev.GetOutputSizePixel() ) );
 
-        // assure that we have a true color image
-        if ( aBmp.GetBitCount() != 24 )
-            aBmp.Convert( BMP_CONVERSION_24BIT );
+        // scale down the image to the desired size - use the input scaler for the scaling operation
+        aBitmap.Scale(aDrawSize, nScaleFlag);
 
-        // downsize, to get the antialiased picture
-        aBmp.Scale(aDrawSize, BMP_SCALE_BESTQUALITY);
+        // convert to desired bitmap color format
+        aBitmap.Convert(eColorConversion);
 
-        rBmpEx = BitmapEx(aBmp);
+        rBitmapEx = BitmapEx(aBitmap);
     }
 
-    return !rBmpEx.IsEmpty();
+    return !rBitmapEx.IsEmpty();
 }
 
 void GDIMetaFile::UseCanvas( bool _bUseCanvas )
commit 3a7e54f5d2020ea1f6f2b27a51f5ca065844837f
Author: Tomaž Vajngerl <tomaz.vajngerl at collabora.com>
Date:   Sun Sep 21 21:29:19 2014 +0200

    Convenient function to compress a Graphic to PNG image
    
    Change-Id: I3d30dd4337b6bd3b5b0c7cdf97a8787c4bc37fa3

diff --git a/include/vcl/graphicfilter.hxx b/include/vcl/graphicfilter.hxx
index 1579845..313ee02 100644
--- a/include/vcl/graphicfilter.hxx
+++ b/include/vcl/graphicfilter.hxx
@@ -320,6 +320,8 @@ public:
                      Graphic& rGraphic,
                      GraphicFilter* pFilter = NULL,
                      sal_uInt16* pDeterminedFormat = NULL );
+
+    sal_uInt16 compressAsPNG(const Graphic& rGraphic, SvStream& rOutputStream, sal_uInt32 nCompression = 5);
 };
 
 #endif // INCLUDED_VCL_GRAPHICFILTER_HXX
diff --git a/vcl/source/filter/graphicfilter.cxx b/vcl/source/filter/graphicfilter.cxx
index 9c69d98..2f38fbf 100644
--- a/vcl/source/filter/graphicfilter.cxx
+++ b/vcl/source/filter/graphicfilter.cxx
@@ -2302,4 +2302,16 @@ int GraphicFilter::LoadGraphic( const OUString &rPath, const OUString &rFilterNa
     return nRes;
 }
 
+sal_uInt16 GraphicFilter::compressAsPNG(const Graphic& rGraphic, SvStream& rOutputStream, sal_uInt32 nCompression)
+{
+    nCompression = MinMax(nCompression, 0, 100);
+
+    uno::Sequence<beans::PropertyValue> aFilterData(1);
+    aFilterData[0].Name = "Compression";
+    aFilterData[0].Value <<= nCompression;
+
+    sal_uInt16 nFilterFormat = GetExportFormatNumberForShortName("PNG");
+    return ExportGraphic(rGraphic, OUString(), rOutputStream, nFilterFormat, &aFilterData);
+}
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
commit 6b894d17ef1ca50b5326290d691635fbfbbdd864
Author: Tomaž Vajngerl <tomaz.vajngerl at collabora.com>
Date:   Sat Sep 20 15:44:40 2014 +0200

    Test HTML export of images & image properties.
    
    Change-Id: Ib0bffab0e653dc9ad0cc5367fdbc6bdee02181d2

diff --git a/sw/qa/extras/htmlexport/data/HTMLImage.odt b/sw/qa/extras/htmlexport/data/HTMLImage.odt
new file mode 100644
index 0000000..c938c3f
Binary files /dev/null and b/sw/qa/extras/htmlexport/data/HTMLImage.odt differ
diff --git a/sw/qa/extras/htmlexport/htmlexport.cxx b/sw/qa/extras/htmlexport/htmlexport.cxx
index f59b09b..5c655bf 100644
--- a/sw/qa/extras/htmlexport/htmlexport.cxx
+++ b/sw/qa/extras/htmlexport/htmlexport.cxx
@@ -162,6 +162,36 @@ DECLARE_HTMLEXPORT_TEST(testSkipImageEmbeddedDocument, "skipimage-embedded-docum
     assertXPathContent(pDoc, "/html/body/p/span/p/span", "Inner.");
 }
 
+DECLARE_HTMLEXPORT_TEST(testExportImageProperties, "HTMLImage.odt")
+{
+    htmlDocPtr pDoc = parseHtml(maTempFile);
+    CPPUNIT_ASSERT(pDoc);
+
+    assertXPath(pDoc, "/html/body", 1);
+
+    assertXPath(pDoc, "/html/body/p/map/area", "shape", "poly");
+    assertXPath(pDoc, "/html/body/p/map/area", "href", "http://www.microsoft.com/");
+    assertXPath(pDoc, "/html/body/p/map/area", "target", "_self");
+    assertXPath(pDoc, "/html/body/p/map/area", "alt", "microsoft");
+
+    assertXPath(pDoc, "/html/body/p/a", 1);
+    assertXPath(pDoc, "/html/body/p/a", "href", "http://www.google.com/");
+
+    assertXPath(pDoc, "/html/body/p/a/font", 1);
+    assertXPath(pDoc, "/html/body/p/a/font", "color", "#ff0000");
+
+    assertXPath(pDoc, "/html/body/p/a/font/img", 1);
+    assertXPath(pDoc, "/html/body/p/a/font/img", "name", "Text");
+    assertXPath(pDoc, "/html/body/p/a/font/img", "alt", "Four colors");
+    assertXPath(pDoc, "/html/body/p/a/font/img", "align", "middle");
+    assertXPath(pDoc, "/html/body/p/a/font/img", "hspace", "38");
+    assertXPath(pDoc, "/html/body/p/a/font/img", "vspace", "19");
+    assertXPath(pDoc, "/html/body/p/a/font/img", "width", "222");
+    assertXPath(pDoc, "/html/body/p/a/font/img", "height", "222");
+    assertXPath(pDoc, "/html/body/p/a/font/img", "border", "3");
+    assertXPath(pDoc, "/html/body/p/a/font/img", "usemap", "#map1");
+}
+
 CPPUNIT_PLUGIN_IMPLEMENT();
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
commit 03fe839d6e76ed8b1dfb65093ab59a8904852ff6
Author: Tomaž Vajngerl <tomaz.vajngerl at collabora.com>
Date:   Sat Sep 20 15:41:13 2014 +0200

    html export: rework image output to use HTML writer
    
    Change-Id: Iead3f0f49b93453bd45f07f047978cb92d279d21

diff --git a/sw/source/filter/html/htmlflywriter.cxx b/sw/source/filter/html/htmlflywriter.cxx
index 725ba97..a96b261 100644
--- a/sw/source/filter/html/htmlflywriter.cxx
+++ b/sw/source/filter/html/htmlflywriter.cxx
@@ -803,115 +803,360 @@ OString SwHTMLWriter::OutFrmFmtOptions( const SwFrmFmt &rFrmFmt,
     return sRetEndTags;
 }
 
-Writer& OutHTML_Image( Writer& rWrt, const SwFrmFmt &rFrmFmt,
-                       Graphic& rGraphic, const OUString& rAlternateTxt,
-                       const Size &rRealSize, sal_uInt32 nFrmOpts,
-                       const sal_Char *pMarkType,
-                       const ImageMap *pAltImgMap )
+void SwHTMLWriter::writeFrameFormatOptions(HtmlWriter& aHtml, const SwFrmFmt& rFrmFmt, const OUString& rAlternateText, sal_uInt32 nFrameOptions)
 {
-    SwHTMLWriter &rHTMLWrt = static_cast<SwHTMLWriter&>(rWrt);
+    OStringBuffer sOut;
 
-    if (rHTMLWrt.mbSkipImages)
-        return rHTMLWrt;
+    const SfxPoolItem* pItem;
+    const SfxItemSet& rItemSet = rFrmFmt.GetAttrSet();
 
-    // ggf. ein noch offenes Attribut voruebergehend beenden
-    if( !rHTMLWrt.aINetFmts.empty() )
+    // Name
+    if( (nFrameOptions & (HTML_FRMOPT_ID|HTML_FRMOPT_NAME)) &&
+        !rFrmFmt.GetName().isEmpty() )
     {
-        SwFmtINetFmt *pINetFmt = rHTMLWrt.aINetFmts.back();
-        OutHTML_INetFmt( rWrt, *pINetFmt, false );
+        const sal_Char* pAttributeName = (nFrameOptions & HTML_FRMOPT_ID) ? OOO_STRING_SVTOOLS_HTML_O_id : OOO_STRING_SVTOOLS_HTML_O_name;
+        aHtml.attribute(pAttributeName, rFrmFmt.GetName());
     }
 
-    const SfxPoolItem* pItem;
-    const SfxItemSet& rItemSet = rFrmFmt.GetAttrSet();
+    // Name
+    if (nFrameOptions & HTML_FRMOPT_DIR)
+    {
+        sal_uInt16 nCurrentDirection = GetHTMLDirection(rItemSet);
+        OString sDirection = convertDirection(nCurrentDirection);
+        aHtml.attribute(OOO_STRING_SVTOOLS_HTML_O_dir, sDirection);
+    }
+
+    // alt
+    if( (nFrameOptions & HTML_FRMOPT_ALT) && !rAlternateText.isEmpty() )
+    {
+        aHtml.attribute(OOO_STRING_SVTOOLS_HTML_O_alt, rAlternateText);
+    }
+
+    // align
+    const sal_Char* pAlignString = 0;
+    RndStdIds eAnchorId = rFrmFmt.GetAnchor().GetAnchorId();
+    if( (nFrameOptions & HTML_FRMOPT_ALIGN) &&
+        ((FLY_AT_PARA == eAnchorId) || (FLY_AT_CHAR == eAnchorId)) )
+    {
+        const SwFmtHoriOrient& rHoriOri = rFrmFmt.GetHoriOrient();
+        if( !(nFrameOptions & HTML_FRMOPT_S_ALIGN) ||
+            text::RelOrientation::FRAME == rHoriOri.GetRelationOrient() ||
+            text::RelOrientation::PRINT_AREA == rHoriOri.GetRelationOrient() )
+        {
+            pAlignString = text::HoriOrientation::RIGHT == rHoriOri.GetHoriOrient()
+                        ? OOO_STRING_SVTOOLS_HTML_AL_right
+                        : OOO_STRING_SVTOOLS_HTML_AL_left;
+        }
+    }
+    if( (nFrameOptions & HTML_FRMOPT_ALIGN) && !pAlignString &&
+        ( (nFrameOptions & HTML_FRMOPT_S_ALIGN) == 0 ||
+          (FLY_AS_CHAR == eAnchorId) ) &&
+        SfxItemState::SET == rItemSet.GetItemState( RES_VERT_ORIENT, true, &pItem ))
+    {
+        switch( ((SwFmtVertOrient*)pItem)->GetVertOrient() )
+        {
+        case text::VertOrientation::LINE_TOP:     pAlignString = OOO_STRING_SVTOOLS_HTML_VA_top;        break;
+        case text::VertOrientation::CHAR_TOP:
+        case text::VertOrientation::BOTTOM:       pAlignString = OOO_STRING_SVTOOLS_HTML_VA_texttop;    break;
+        case text::VertOrientation::LINE_CENTER:
+        case text::VertOrientation::CHAR_CENTER:  pAlignString = OOO_STRING_SVTOOLS_HTML_VA_absmiddle;  break;
+        case text::VertOrientation::CENTER:       pAlignString = OOO_STRING_SVTOOLS_HTML_VA_middle;     break;
+        case text::VertOrientation::LINE_BOTTOM:
+        case text::VertOrientation::CHAR_BOTTOM:  pAlignString = OOO_STRING_SVTOOLS_HTML_VA_absbottom;  break;
+        case text::VertOrientation::TOP:          pAlignString = OOO_STRING_SVTOOLS_HTML_VA_bottom;     break;
+        case text::VertOrientation::NONE:     break;
+        }
+    }
+    if (pAlignString)
+    {
+        aHtml.attribute(OOO_STRING_SVTOOLS_HTML_O_align, pAlignString);
+    }
+
+    // hspace und vspace
+    Size aTwipSpc( 0, 0 );
+    if( (nFrameOptions & (HTML_FRMOPT_SPACE | HTML_FRMOPT_MARGINSIZE)) &&
+        SfxItemState::SET == rItemSet.GetItemState( RES_LR_SPACE, true, &pItem ))
+    {
+        aTwipSpc.Width() =
+            ( ((SvxLRSpaceItem*)pItem)->GetLeft() +
+                ((SvxLRSpaceItem*)pItem)->GetRight() ) / 2;
+        nDfltLeftMargin = nDfltRightMargin = aTwipSpc.Width();
+    }
+    if( (nFrameOptions & (HTML_FRMOPT_SPACE|HTML_FRMOPT_MARGINSIZE)) &&
+        SfxItemState::SET == rItemSet.GetItemState( RES_UL_SPACE, true, &pItem ))
+    {
+        aTwipSpc.Height()  =
+            ( ((SvxULSpaceItem*)pItem)->GetUpper() +
+                ((SvxULSpaceItem*)pItem)->GetLower() ) / 2;
+        nDfltTopMargin = nDfltBottomMargin = (sal_uInt16)aTwipSpc.Height();
+    }
+
+    if( (nFrameOptions & HTML_FRMOPT_SPACE) &&
+        (aTwipSpc.Width() || aTwipSpc.Height()) &&
+        Application::GetDefaultDevice() )
+    {
+        Size aPixelSpc =
+            Application::GetDefaultDevice()->LogicToPixel( aTwipSpc,
+                                                MapMode(MAP_TWIP) );
+        if( !aPixelSpc.Width() && aTwipSpc.Width() )
+            aPixelSpc.Width() = 1;
+        if( !aPixelSpc.Height() && aTwipSpc.Height() )
+            aPixelSpc.Height() = 1;
+
+        if (aPixelSpc.Width())
+        {
+            aHtml.attribute(OOO_STRING_SVTOOLS_HTML_O_hspace, static_cast<sal_Int32>(aPixelSpc.Width()));
+        }
+
+        if (aPixelSpc.Height())
+        {
+            aHtml.attribute(OOO_STRING_SVTOOLS_HTML_O_vspace, static_cast<sal_Int32>(aPixelSpc.Height()));
+        }
+    }
+
+    // Der Abstand muss bei der Groesse beruecksichtigt, wenn das entsprechende
+    // Flag gesetzt ist.
+    if( (nFrameOptions & HTML_FRMOPT_MARGINSIZE) )
+    {
+        aTwipSpc.Width() *= -2;
+        aTwipSpc.Height() *= -2;
+    }
+    else
+    {
+        aTwipSpc.Width() = 0;
+        aTwipSpc.Height() = 0;
+    }
+
+    if( !(nFrameOptions & HTML_FRMOPT_ABSSIZE) &&
+        SfxItemState::SET == rItemSet.GetItemState( RES_BOX, true, &pItem ))
+    {
+        const SvxBoxItem* pBoxItem = (const SvxBoxItem*)pItem;
+
+        aTwipSpc.Width() += pBoxItem->CalcLineSpace( BOX_LINE_LEFT );
+        aTwipSpc.Width() += pBoxItem->CalcLineSpace( BOX_LINE_RIGHT );
+        aTwipSpc.Height() += pBoxItem->CalcLineSpace( BOX_LINE_TOP );
+        aTwipSpc.Height() += pBoxItem->CalcLineSpace( BOX_LINE_BOTTOM );
+    }
+
+    // "width" and/or "height"
+    // ATT_VAR_SIZE/ATT_MIN_SIZE nur ausgeben, wenn ANYSIZE gesezut ist
+    if( (nFrameOptions & HTML_FRMOPT_SIZE) &&
+        SfxItemState::SET == rItemSet.GetItemState( RES_FRM_SIZE, true, &pItem ) &&
+        ( (nFrameOptions & HTML_FRMOPT_ANYSIZE) ||
+          ATT_FIX_SIZE == ((const SwFmtFrmSize *)pItem)->GetHeightSizeType()) )
+    {
+        const SwFmtFrmSize *pFSItem = (const SwFmtFrmSize *)pItem;
+        sal_uInt8 nPrcWidth = pFSItem->GetWidthPercent();
+        sal_uInt8 nPrcHeight = pFSItem->GetHeightPercent();
+
+        // Groesse des Objekts Twips ohne Raender
+        Size aTwipSz( (nPrcWidth ? 0
+                                 : pFSItem->GetWidth()-aTwipSpc.Width()),
+                      (nPrcHeight ? 0
+                                  : pFSItem->GetHeight()-aTwipSpc.Height()) );
+
+        OSL_ENSURE( aTwipSz.Width() >= 0 && aTwipSz.Height() >= 0,
+                "Rahmengroesse minus Abstand < 0!!!???" );
+        if( aTwipSz.Width() < 0 )
+            aTwipSz.Width() = 0;
+        if( aTwipSz.Height() < 0 )
+            aTwipSz.Height() = 0;
+
+        Size aPixelSz( 0, 0 );
+        if( (aTwipSz.Width() || aTwipSz.Height()) &&
+            Application::GetDefaultDevice() )
+        {
+            aPixelSz =
+                Application::GetDefaultDevice()->LogicToPixel( aTwipSz,
+                                                    MapMode(MAP_TWIP) );
+            if( !aPixelSz.Width() && aTwipSz.Width() )
+                aPixelSz.Width() = 1;
+            if( !aPixelSz.Height() && aTwipSz.Height() )
+                aPixelSz.Height() = 1;
+        }
 
-    const SwFmtURL *pURLItem = 0;
+        if( (nFrameOptions & HTML_FRMOPT_WIDTH) &&
+            ((nPrcWidth && nPrcWidth!=255) || aPixelSz.Width()) )
+        {
+            OString sWidth;
+            if (nPrcWidth)
+                sWidth = OString::number(static_cast<sal_Int32>(nPrcWidth)) + "%";
+            else
+                sWidth = OString::number(static_cast<sal_Int32>(aPixelSz.Width()));
+            aHtml.attribute(OOO_STRING_SVTOOLS_HTML_O_width, sWidth);
+        }
+
+        if( (nFrameOptions & HTML_FRMOPT_HEIGHT) &&
+            ((nPrcHeight && nPrcHeight!=255) || aPixelSz.Height()) )
+        {
+            OString sHeight;
+            if (nPrcWidth)
+                sHeight = OString::number(static_cast<sal_Int32>(nPrcHeight)) + "%";
+            else
+                sHeight = OString::number(static_cast<sal_Int32>(aPixelSz.Height()));
+            aHtml.attribute(OOO_STRING_SVTOOLS_HTML_O_height, sHeight);
+        }
+    }
+
+    // Umlauf fuer absatzgeb. Grafiken als <BR CLEAR=...> in den String
+    // schreiben
+
+    const sal_Char* pSurroundString = 0;
+    if( (nFrameOptions & HTML_FRMOPT_BRCLEAR) &&
+        ((FLY_AT_PARA == rFrmFmt.GetAnchor().GetAnchorId()) ||
+         (FLY_AT_CHAR == rFrmFmt.GetAnchor().GetAnchorId())) &&
+        SfxItemState::SET == rItemSet.GetItemState( RES_SURROUND, true, &pItem ))
+    {
+        const SwFmtSurround* pSurround = (const SwFmtSurround*)pItem;
+        sal_Int16 eHoriOri = rFrmFmt.GetHoriOrient().GetHoriOrient();
+        SwSurround eSurround = pSurround->GetSurround();
+        bool bAnchorOnly = pSurround->IsAnchorOnly();
+        switch( eHoriOri )
+        {
+            case text::HoriOrientation::RIGHT:
+            {
+                switch( eSurround )
+                {
+                case SURROUND_NONE:
+                case SURROUND_RIGHT:
+                    pSurroundString = OOO_STRING_SVTOOLS_HTML_AL_right;
+                    break;
+                case SURROUND_LEFT:
+                case SURROUND_PARALLEL:
+                    if( bAnchorOnly )
+                        bClearRight = true;
+                    break;
+                default:
+                    ;
+                }
+            }
+            break;
+
+            default:
+            // If a frame is centered, it gets left aligned. This
+            // should be taken into account here, too.
+            {
+                switch( eSurround )
+                {
+                case SURROUND_NONE:
+                case SURROUND_LEFT:
+                    pSurroundString = OOO_STRING_SVTOOLS_HTML_AL_left;
+                    break;
+                case SURROUND_RIGHT:
+                case SURROUND_PARALLEL:
+                    if( bAnchorOnly )
+                        bClearLeft = true;
+                    break;
+                default:
+                    break;
+                }
+            }
+            break;
+        }
+
+        if (pSurroundString)
+        {
+            aHtml.start(OOO_STRING_SVTOOLS_HTML_linebreak);
+            aHtml.attribute(OOO_STRING_SVTOOLS_HTML_O_clear, pSurroundString);
+            aHtml.end();
+        }
+    }
+}
+
+namespace
+{
+
+OUString lclWriteOutImap(SwHTMLWriter& rHTMLWrt, const SfxItemSet& rItemSet, const SwFrmFmt& rFrmFmt,
+                         const Size& rRealSize, const ImageMap* pAltImgMap, SwFmtURL*& pURLItem)
+{
+    OUString aIMapName;
+
+    const SfxPoolItem* pItem;
 
     // das URL-Attribut nur beruecksichtigen, wenn keine Image-Map
     // uebergeben wurde
-    if( !pAltImgMap &&
-        SfxItemState::SET == rItemSet.GetItemState( RES_URL, true, &pItem ))
+    if (!pAltImgMap && SfxItemState::SET == rItemSet.GetItemState( RES_URL, true, &pItem))
     {
-        pURLItem = (const SwFmtURL *)pItem;
+        pURLItem = (SwFmtURL*) pItem;
     }
 
     // Image-Map rausschreiben
-    const ImageMap *pIMap = pAltImgMap;
+    const ImageMap* pIMap = pAltImgMap;
     if( !pIMap && pURLItem )
     {
         pIMap = pURLItem->GetMap();
     }
 
-    OUString aIMapName;
-    if( pIMap )
+    if (pIMap)
     {
         // den Namen eindeutig machen
         aIMapName = pIMap->GetName();
         OUString aNameBase;
-        if( !aIMapName.isEmpty() )
+        if (!aIMapName.isEmpty())
             aNameBase = aIMapName;
         else
             aNameBase = OOO_STRING_SVTOOLS_HTML_map;
-        if( aIMapName.isEmpty() )
-            aIMapName = aNameBase + OUString::number( rHTMLWrt.nImgMapCnt );
+
+        if (aIMapName.isEmpty())
+            aIMapName = aNameBase + OUString::number(rHTMLWrt.nImgMapCnt);
 
         bool bFound;
         do
         {
             bFound = false;
-            for(size_t i = 0; i < rHTMLWrt.aImgMapNames.size(); ++i)
+            for (size_t i = 0; i < rHTMLWrt.aImgMapNames.size(); ++i)
             {
                 // TODO: Unicode: Comparison is case insensitive for ASCII
                 // characters only now!
-                if( aIMapName.equalsIgnoreAsciiCase( rHTMLWrt.aImgMapNames[i] ) )
+                if (aIMapName.equalsIgnoreAsciiCase(rHTMLWrt.aImgMapNames[i]))
                 {
                     bFound = true;
                     break;
                 }
             }
-            if( bFound )
+            if (bFound)
             {
                 rHTMLWrt.nImgMapCnt++;
                 aIMapName = aNameBase + OUString::number( rHTMLWrt.nImgMapCnt );
             }
-
-        } while( bFound );
+        } while (bFound);
 
         bool bScale = false;
-        Fraction aScaleX( 1, 1 );
-        Fraction aScaleY( 1, 1 );
+        Fraction aScaleX(1, 1);
+        Fraction aScaleY(1, 1);
 
         const SwFmtFrmSize& rFrmSize = rFrmFmt.GetFrmSize();
         const SvxBoxItem& rBox = rFrmFmt.GetBox();
 
-        if( !rFrmSize.GetWidthPercent() && rRealSize.Width() )
+        if (!rFrmSize.GetWidthPercent() && rRealSize.Width())
         {
             SwTwips nWidth = rFrmSize.GetWidth();
-            nWidth -= ( rBox.CalcLineSpace(BOX_LINE_LEFT) +
-                        rBox.CalcLineSpace(BOX_LINE_RIGHT) );
+            nWidth -= rBox.CalcLineSpace(BOX_LINE_LEFT) + rBox.CalcLineSpace(BOX_LINE_RIGHT);
 
-            OSL_ENSURE( nWidth>0, "Gibt es 0 twip breite Grafiken!?" );
-            if( nWidth<=0 ) // sollte nicht passieren
+            OSL_ENSURE( nWidth > 0, "Gibt es 0 twip breite Grafiken!?" );
+            if (nWidth <= 0) // sollte nicht passieren
                 nWidth = 1;
 
-            if( rRealSize.Width() != nWidth )
+            if (rRealSize.Width() != nWidth)
             {
-                aScaleX = Fraction( nWidth, rRealSize.Width() );
+                aScaleX = Fraction(nWidth, rRealSize.Width());
                 bScale = true;
             }
         }
-        if( !rFrmSize.GetHeightPercent() && rRealSize.Height() )
+
+        if (!rFrmSize.GetHeightPercent() && rRealSize.Height())
         {
             SwTwips nHeight = rFrmSize.GetHeight();
-            nHeight -= ( rBox.CalcLineSpace(BOX_LINE_TOP) +
-                         rBox.CalcLineSpace(BOX_LINE_BOTTOM) );
 
-            OSL_ENSURE( nHeight>0, "Gibt es 0 twip hohe Grafiken!?" );
-            if( nHeight<=0 )
+            nHeight -= rBox.CalcLineSpace(BOX_LINE_TOP) + rBox.CalcLineSpace(BOX_LINE_BOTTOM);
+
+            OSL_ENSURE( nHeight > 0, "Gibt es 0 twip hohe Grafiken!?" );
+            if (nHeight <= 0)
                 nHeight = 1;
 
-            if( rRealSize.Height() != nHeight )
+            if (rRealSize.Height() != nHeight)
             {
-                aScaleY = Fraction( nHeight, rRealSize.Height() );
+                aScaleY = Fraction(nHeight, rRealSize.Height());
                 bScale = true;
             }
         }
@@ -921,7 +1166,7 @@ Writer& OutHTML_Image( Writer& rWrt, const SwFrmFmt &rFrmFmt,
         OString aIndMap, aIndArea;
         const sal_Char *pIndArea = 0, *pIndMap = 0;
 
-        if( rHTMLWrt.bLFPossible )
+        if (rHTMLWrt.bLFPossible)
         {
             rHTMLWrt.OutNewLine( true );
             aIndMap = rHTMLWrt.GetIndentString();
@@ -930,11 +1175,11 @@ Writer& OutHTML_Image( Writer& rWrt, const SwFrmFmt &rFrmFmt,
             pIndMap = aIndMap.getStr();
         }
 
-        if( bScale )
+        if (bScale)
         {
-            ImageMap aScaledIMap( *pIMap );
-            aScaledIMap.Scale( aScaleX, aScaleY );
-            HTMLOutFuncs::Out_ImageMap( rWrt.Strm(), rWrt.GetBaseURL(), aScaledIMap, aIMapName,
+            ImageMap aScaledIMap(*pIMap);
+            aScaledIMap.Scale(aScaleX, aScaleY);
+            HTMLOutFuncs::Out_ImageMap( rHTMLWrt.Strm(), rHTMLWrt.GetBaseURL(), aScaledIMap, aIMapName,
                                         aIMapEventTable,
                                         rHTMLWrt.bCfgStarBasic,
                                         SAL_NEWLINE_STRING, pIndArea, pIndMap,
@@ -943,7 +1188,7 @@ Writer& OutHTML_Image( Writer& rWrt, const SwFrmFmt &rFrmFmt,
         }
         else
         {
-            HTMLOutFuncs::Out_ImageMap( rWrt.Strm(), rWrt.GetBaseURL(), *pIMap, aIMapName,
+            HTMLOutFuncs::Out_ImageMap( rHTMLWrt.Strm(), rHTMLWrt.GetBaseURL(), *pIMap, aIMapName,
                                         aIMapEventTable,
                                         rHTMLWrt.bCfgStarBasic,
                                         SAL_NEWLINE_STRING, pIndArea, pIndMap,
@@ -951,94 +1196,101 @@ Writer& OutHTML_Image( Writer& rWrt, const SwFrmFmt &rFrmFmt,
                                         &rHTMLWrt.aNonConvertableCharacters );
         }
     }
+    return aIMapName;
+}
 
-    // wenn meoglich vor der Grafik einen Zeilen-Umbruch ausgeben
+}
+
+Writer& OutHTML_Image( Writer& rWrt, const SwFrmFmt &rFrmFmt,
+                       Graphic& rGraphic, const OUString& rAlternateTxt,
+                       const Size &rRealSize, sal_uInt32 nFrmOpts,
+                       const sal_Char *pMarkType,
+                       const ImageMap *pAltImgMap )
+{
+    SwHTMLWriter& rHTMLWrt = static_cast<SwHTMLWriter&>(rWrt);
+
+    if (rHTMLWrt.mbSkipImages)
+        return rHTMLWrt;
+
+    // ggf. ein noch offenes Attribut voruebergehend beenden
+    if( !rHTMLWrt.aINetFmts.empty() )
+    {
+        SwFmtINetFmt* pINetFmt = rHTMLWrt.aINetFmts.back();
+        OutHTML_INetFmt( rWrt, *pINetFmt, false );
+    }
+
+    const SfxPoolItem* pItem;
+    const SfxItemSet& rItemSet = rFrmFmt.GetAttrSet();
+
+    SwFmtURL* pURLItem = 0;
+    OUString aIMapName = lclWriteOutImap(rHTMLWrt, rItemSet, rFrmFmt, rRealSize, pAltImgMap, pURLItem);
+
+    // put img into new line
     if( rHTMLWrt.bLFPossible )
         rHTMLWrt.OutNewLine( true );
 
-    // Attribute die ausserhelb der Grafik geschreiben werden muessen sammeln
-    OStringBuffer sOut;
-    OString aEndTags;
+    HtmlWriter aHtml(rWrt.Strm());
 
-    // implizite Sprungmarke -> <A NAME=...></A>...<IMG ...>
+    // <a name=...></a>...<img ...>
     if( pMarkType && !rFrmFmt.GetName().isEmpty() )
+    {
         rHTMLWrt.OutImplicitMark( rFrmFmt.GetName(), pMarkType );
+    }
 
-    // URL -> <A>...<IMG ... >...</A>
+    // URL -> <a>...<img ... >...</a>
     const SvxMacroItem *pMacItem = 0;
-    if( SfxItemState::SET == rItemSet.GetItemState( RES_FRMMACRO, true, &pItem ))
+    if (SfxItemState::SET == rItemSet.GetItemState(RES_FRMMACRO, true, &pItem))
+    {
         pMacItem = (const SvxMacroItem *)pItem;
+    }
 
-    if( pURLItem || pMacItem )
+    if (pURLItem || pMacItem)
     {
         OUString aMapURL;
         OUString aName;
         OUString aTarget;
-        if( pURLItem )
+
+        if(pURLItem)
         {
             aMapURL = pURLItem->GetURL();
             aName = pURLItem->GetName();
             aTarget = pURLItem->GetTargetFrameName();
         }
+
         bool bEvents = pMacItem && !pMacItem->GetMacroTable().empty();
 
         if( !aMapURL.isEmpty() || !aName.isEmpty() || !aTarget.isEmpty() || bEvents )
         {
-            sOut.append('<').append(OOO_STRING_SVTOOLS_HTML_anchor);
+            aHtml.start(OOO_STRING_SVTOOLS_HTML_anchor);
 
-            // Ein HREF nur Ausgaben, wenn es einen Link oder Makros gibt
+            // Output "href" element if a link or macro exists
             if( !aMapURL.isEmpty() || bEvents )
             {
-                sOut.append(' ').append(OOO_STRING_SVTOOLS_HTML_O_href).
-                    append("=\"");
-                rWrt.Strm().WriteCharPtr( sOut.makeStringAndClear().getStr() );
-                rHTMLWrt.OutHyperlinkHRefValue( aMapURL );
-                sOut.append('\"');
+                aHtml.attribute(OOO_STRING_SVTOOLS_HTML_O_href, OUStringToOString(rHTMLWrt.convertHyperlinkHRefValue(aMapURL), RTL_TEXTENCODING_UTF8));
             }
 
             if( !aName.isEmpty() )
             {
-                sOut.append(' ').append(OOO_STRING_SVTOOLS_HTML_O_name).
-                    append("=\"");
-                rWrt.Strm().WriteCharPtr( sOut.makeStringAndClear().getStr() );
-                HTMLOutFuncs::Out_String( rWrt.Strm(), aName,
-                                          rHTMLWrt.eDestEnc, &rHTMLWrt.aNonConvertableCharacters );
-                sOut.append('\"');
+                aHtml.attribute(OOO_STRING_SVTOOLS_HTML_O_name, OUStringToOString(aName, RTL_TEXTENCODING_UTF8));
             }
 
             if( !aTarget.isEmpty() )
             {
-                sOut.append(' ').append(OOO_STRING_SVTOOLS_HTML_O_target).
-                    append("=\"");
-                rWrt.Strm().WriteCharPtr( sOut.makeStringAndClear().getStr() );
-                HTMLOutFuncs::Out_String( rWrt.Strm(), aTarget,
-                                          rHTMLWrt.eDestEnc, &rHTMLWrt.aNonConvertableCharacters );
-                sOut.append('\"');
+                aHtml.attribute(OOO_STRING_SVTOOLS_HTML_O_target, OUStringToOString(aTarget, RTL_TEXTENCODING_UTF8));
             }
 
-            if (!sOut.isEmpty())
-                rWrt.Strm().WriteCharPtr( sOut.makeStringAndClear().getStr() );
-
             if( pMacItem )
             {
                 const SvxMacroTableDtor& rMacTable = pMacItem->GetMacroTable();
-                if( !rMacTable.empty() )
-                    HTMLOutFuncs::Out_Events( rWrt.Strm(), rMacTable,
-                                              aAnchorEventTable,
-                                              rHTMLWrt.bCfgStarBasic,
-                                                 rHTMLWrt.eDestEnc,
-                                        &rHTMLWrt.aNonConvertableCharacters );
+                if (!rMacTable.empty())
+                {
+                    HtmlWriterHelper::applyEvents(aHtml, rMacTable, aAnchorEventTable, rHTMLWrt.bCfgStarBasic);
+                }
             }
-
-            rWrt.Strm().WriteCharPtr( ">" );
-            aEndTags = OStringBuffer().append("</").
-                append(OOO_STRING_SVTOOLS_HTML_anchor).
-                append(">").append(aEndTags).
-                makeStringAndClear();
         }
     }
 
-    // Umrandung -> <FONT COLOR = ...>...<IMG ... >...</FONT>
+    // <font color = ...>...<img ... >...</font>
     sal_uInt16 nBorderWidth = 0;
     if( (nFrmOpts & HTML_FRMOPT_BORDER) &&
         SfxItemState::SET == rItemSet.GetItemState( RES_BOX, true, &pItem ))
@@ -1098,74 +1350,57 @@ Writer& OutHTML_Image( Writer& rWrt, const SwFrmFmt &rFrmFmt,
 
         if( pColBorderLine )
         {
-            sOut.append('<');
-            sOut.append(OOO_STRING_SVTOOLS_HTML_font).append(' ').
-                append(OOO_STRING_SVTOOLS_HTML_O_color).append("=");
-            rWrt.Strm().WriteCharPtr( sOut.makeStringAndClear().getStr() );
-            HTMLOutFuncs::Out_Color( rWrt.Strm(),
-                                     pColBorderLine->GetColor(), rHTMLWrt.eDestEnc ).WriteChar( '>' );
-
-            aEndTags = OStringBuffer().
-                append("</").
-                append(OOO_STRING_SVTOOLS_HTML_font).
-                append('>').append(aEndTags).makeStringAndClear();
+            aHtml.start(OOO_STRING_SVTOOLS_HTML_font);
+            HtmlWriterHelper::applyColor(aHtml, OOO_STRING_SVTOOLS_HTML_O_color, pColBorderLine->GetColor());
         }
     }
 
-    sOut.append('<');
-    sOut.append(OOO_STRING_SVTOOLS_HTML_image).append(' ').
-        append(OOO_STRING_SVTOOLS_HTML_O_src).
-        append("=\"").append(OOO_STRING_SVTOOLS_HTML_O_data).append(":");
-    rWrt.Strm().WriteCharPtr( sOut.makeStringAndClear().getStr() );
+    aHtml.start(OOO_STRING_SVTOOLS_HTML_image);
 
     OUString aGraphicInBase64;
     sal_uLong nErr = XOutBitmap::GraphicToBase64(rGraphic, aGraphicInBase64);
-    if( nErr )
+    if (nErr)
     {
         rHTMLWrt.nWarn = WARN_SWG_POOR_LOAD | WARN_SW_WRITE_BASE;
     }
-    HTMLOutFuncs::Out_String( rWrt.Strm(), aGraphicInBase64, rHTMLWrt.eDestEnc, &rHTMLWrt.aNonConvertableCharacters ).WriteChar( '\"' );
+
+    OStringBuffer sBuffer;
+    sBuffer.append(OOO_STRING_SVTOOLS_HTML_O_data);
+    sBuffer.append(":");
+    sBuffer.append(OUStringToOString(aGraphicInBase64, RTL_TEXTENCODING_UTF8));
+    aHtml.attribute(OOO_STRING_SVTOOLS_HTML_O_src, sBuffer.makeStringAndClear().getStr());
 
     // Events
-    if( SfxItemState::SET == rItemSet.GetItemState( RES_FRMMACRO, true, &pItem ))
+    if (SfxItemState::SET == rItemSet.GetItemState(RES_FRMMACRO, true, &pItem))
     {
-        const SvxMacroTableDtor& rMacTable =
-            ((const SvxMacroItem *)pItem)->GetMacroTable();
-        if( !rMacTable.empty() )
-            HTMLOutFuncs::Out_Events( rWrt.Strm(), rMacTable, aImageEventTable,
-                                      rHTMLWrt.bCfgStarBasic, rHTMLWrt.eDestEnc,
-                                        &rHTMLWrt.aNonConvertableCharacters );
+        const SvxMacroTableDtor& rMacTable = ((const SvxMacroItem *)pItem)->GetMacroTable();
+        if (!rMacTable.empty())
+        {
+            HtmlWriterHelper::applyEvents(aHtml, rMacTable, aImageEventTable, rHTMLWrt.bCfgStarBasic);
+        }
     }
 
-    // ALT, ALIGN, WIDTH, HEIGHT, HSPACE, VSPACE
-    aEndTags = rHTMLWrt.OutFrmFmtOptions( rFrmFmt, rAlternateTxt, nFrmOpts, aEndTags );
+    // alt, align, width, height, hspace, vspace
+    rHTMLWrt.writeFrameFormatOptions(aHtml, rFrmFmt, rAlternateTxt, nFrmOpts);
     if( rHTMLWrt.IsHTMLMode( HTMLMODE_ABS_POS_FLY ) )
         rHTMLWrt.OutCSS1_FrmFmtOptions( rFrmFmt, nFrmOpts );
 
     if( nFrmOpts & HTML_FRMOPT_BORDER )
     {
-        sOut.append(' ').append(OOO_STRING_SVTOOLS_HTML_O_border).
-            append("=\"").append(static_cast<sal_Int32>(nBorderWidth)).append("\"");
-        rWrt.Strm().WriteCharPtr( sOut.makeStringAndClear().getStr() );
+        aHtml.attribute(OOO_STRING_SVTOOLS_HTML_O_border, nBorderWidth);
     }
 
     if( pURLItem && pURLItem->IsServerMap() )
     {
-        sOut.append(' ').append(OOO_STRING_SVTOOLS_HTML_O_ismap);
-        rWrt.Strm().WriteCharPtr( sOut.makeStringAndClear().getStr() );
+        aHtml.attribute(OOO_STRING_SVTOOLS_HTML_O_ismap);
     }
+
     if( !aIMapName.isEmpty() )
     {
-        sOut.append(' ').append(OOO_STRING_SVTOOLS_HTML_O_usemap).
-            append("=\"#");
-        rWrt.Strm().WriteCharPtr( sOut.makeStringAndClear().getStr() );
-        HTMLOutFuncs::Out_String( rWrt.Strm(), aIMapName, rHTMLWrt.eDestEnc, &rHTMLWrt.aNonConvertableCharacters ).WriteChar( '\"' );
+        aHtml.attribute(OOO_STRING_SVTOOLS_HTML_O_usemap, "#" + aIMapName);
     }
 
-    rHTMLWrt.Strm().WriteChar( '>' );
-
-    if( !aEndTags.isEmpty() )
-        rWrt.Strm().WriteCharPtr( aEndTags.getStr() );
+    aHtml.flushStack();
 
     if( !rHTMLWrt.aINetFmts.empty() )
     {
diff --git a/sw/source/filter/html/wrthtml.cxx b/sw/source/filter/html/wrthtml.cxx
index a6f138b..b64f9aa 100644
--- a/sw/source/filter/html/wrthtml.cxx
+++ b/sw/source/filter/html/wrthtml.cxx
@@ -1171,32 +1171,32 @@ void SwHTMLWriter::OutImplicitMark( const OUString& rMark,
     }
 }
 
-void SwHTMLWriter::OutHyperlinkHRefValue( const OUString& rURL )
+OUString SwHTMLWriter::convertHyperlinkHRefValue(const OUString& rURL)
 {
-    OUString sURL( rURL );
-    sal_Int32 nPos = sURL.lastIndexOf( cMarkSeparator );
-    if( nPos != -1 )
+    OUString sURL(rURL);
+    sal_Int32 nPos = sURL.lastIndexOf(cMarkSeparator);
+    if (nPos != -1)
     {
-        OUString sCmp(comphelper::string::remove(sURL.copy(nPos+1), ' '));
-        if( !sCmp.isEmpty() )
+        OUString sCompare(comphelper::string::remove(sURL.copy(nPos + 1), ' '));
+        if (!sCompare.isEmpty())
         {
-            sCmp = sCmp.toAsciiLowerCase();
-            if( sCmp == "region" ||
-                sCmp == "frame" ||
-                sCmp == "graphic" ||
-                sCmp == "ole" ||
-                sCmp == "table" ||
-                sCmp == "outline" ||
-                sCmp == "text" )
+            sCompare = sCompare.toAsciiLowerCase();
+            if( sCompare == "region"  || sCompare == "frame"   ||
+                sCompare == "graphic" || sCompare == "ole"     ||
+                sCompare == "table"   || sCompare == "outline" ||
+                sCompare == "text" )
             {
                 sURL = sURL.replace( '?', '_' );   // '?' causes problems in IE/Netscape 5
             }
         }
     }
+    return URIHelper::simpleNormalizedMakeRelative(GetBaseURL(), sURL);
+}
 
-    sURL = URIHelper::simpleNormalizedMakeRelative( GetBaseURL(), sURL);
-    HTMLOutFuncs::Out_String( Strm(), sURL, eDestEnc,
-                              &aNonConvertableCharacters );
+void SwHTMLWriter::OutHyperlinkHRefValue( const OUString& rURL )
+{
+    OUString sURL = convertHyperlinkHRefValue(rURL);
+    HTMLOutFuncs::Out_String( Strm(), sURL, eDestEnc, &aNonConvertableCharacters );
 }
 
 void SwHTMLWriter::OutBackground( const SvxBrushItem *pBrushItem, bool bGraphic )
@@ -1297,25 +1297,31 @@ sal_uInt16 SwHTMLWriter::GetHTMLDirection( sal_uInt16 nDir ) const
 
 void SwHTMLWriter::OutDirection( sal_uInt16 nDir )
 {
-    const sal_Char *pValue = 0;
-    switch( nDir )
+    OString sConverted = convertDirection(nDir);
+    if (!sConverted.isEmpty())
+    {
+        OStringBuffer sOut;
+        sOut.append(' ').append(OOO_STRING_SVTOOLS_HTML_O_dir)
+            .append("=\"").append(sConverted).append('\"');
+        Strm().WriteCharPtr( sOut.makeStringAndClear().getStr() );
+    }
+}
+
+OString SwHTMLWriter::convertDirection(sal_uInt16 nDirection)
+{
+    OString sConverted;
+    switch (nDirection)
     {
     case FRMDIR_HORI_LEFT_TOP:
     case FRMDIR_VERT_TOP_LEFT:
-        pValue = "ltr";
+        sConverted = "ltr";
         break;
     case FRMDIR_HORI_RIGHT_TOP:
     case FRMDIR_VERT_TOP_RIGHT:
-        pValue = "rtl";
+        sConverted = "rtl";
         break;
     }
-    if( pValue != 0 )
-    {
-        OStringBuffer sOut;
-        sOut.append(' ').append(OOO_STRING_SVTOOLS_HTML_O_dir)
-            .append("=\"").append(pValue).append('\"');
-        Strm().WriteCharPtr( sOut.makeStringAndClear().getStr() );
-    }
+    return sConverted;
 }
 
 OString SwHTMLWriter::GetIndentString(sal_uInt16 nIncLvl)
diff --git a/sw/source/filter/html/wrthtml.hxx b/sw/source/filter/html/wrthtml.hxx
index a62cae3..7cef620 100644
--- a/sw/source/filter/html/wrthtml.hxx
+++ b/sw/source/filter/html/wrthtml.hxx
@@ -414,6 +414,9 @@ public:
     void OutBookmarks();
     void OutPointFieldmarks( const SwPosition& rPos );
     void OutImplicitMark( const OUString& rMark, const sal_Char *pMarkType );
+
+    OUString convertHyperlinkHRefValue(const OUString& rURL);
+
     void OutHyperlinkHRefValue( const OUString& rURL );
 
     // gebe die evt. an der akt. Position stehenden FlyFrame aus.
@@ -465,12 +468,16 @@ public:
     sal_uInt16 GetHTMLDirection( sal_uInt16 nDir ) const;
     sal_uInt16 GetHTMLDirection( const SfxItemSet& rItemSet ) const;
     void OutDirection( sal_uInt16 nDir );
+    OString convertDirection(sal_uInt16 nDirection);
 
     // ALT/ALIGN/WIDTH/HEIGHT/HSPACE/VSPACE-Optionen des aktuellen
     // Frame-Formats ausgeben und ggf. ein <BR CLEAR=...> vorne an
     // rEndTags anhaengen
     OString OutFrmFmtOptions( const SwFrmFmt& rFrmFmt, const OUString& rAltTxt,
         sal_uInt32 nFrmOpts, const OString& rEndTags = OString() );
+
+    void writeFrameFormatOptions(HtmlWriter& aHtml, const SwFrmFmt& rFrmFmt, const OUString& rAltTxt, sal_uInt32 nFrmOpts);
+
     void OutCSS1_TableFrmFmtOptions( const SwFrmFmt& rFrmFmt );
     void OutCSS1_TableCellBorderHack(const SwFrmFmt& rFrmFmt);
     void OutCSS1_SectionFmtOptions( const SwFrmFmt& rFrmFmt, const SwFmtCol *pCol );
commit 3aa99295a72d6129b72ce22805f03da3edb64432
Author: Tomaž Vajngerl <tomaz.vajngerl at collabora.com>
Date:   Sat Sep 20 15:40:11 2014 +0200

    html: add applyEvents to HTML output
    
    Change-Id: I8cc2d752673254c0f23f63030a8fa7d4d288c0a9

diff --git a/include/svtools/htmlout.hxx b/include/svtools/htmlout.hxx
index f904a05..5612207 100644
--- a/include/svtools/htmlout.hxx
+++ b/include/svtools/htmlout.hxx
@@ -109,6 +109,7 @@ struct HTMLOutFuncs
 struct HtmlWriterHelper
 {
     SVT_DLLPUBLIC static void applyColor( HtmlWriter& rHtmlWriter, const OString &aAttributeName, const Color& rColor);
+    SVT_DLLPUBLIC static void applyEvents(HtmlWriter& rHtmlWriter, const SvxMacroTableDtor& rMacroTable, const HTMLOutEvent* pEventTable, bool bOutStarBasic);
 };
 
 #endif
diff --git a/svtools/source/svhtml/htmlout.cxx b/svtools/source/svhtml/htmlout.cxx
index da58dc3..003889d 100644
--- a/svtools/source/svhtml/htmlout.cxx
+++ b/svtools/source/svhtml/htmlout.cxx
@@ -1001,4 +1001,29 @@ void HtmlWriterHelper::applyColor(HtmlWriter& rHtmlWriter, const OString &aAttri
     rHtmlWriter.attribute(aAttributeName, sBuffer.makeStringAndClear());
 }
 
+
+void HtmlWriterHelper::applyEvents(HtmlWriter& rHtmlWriter, const SvxMacroTableDtor& rMacroTable, const HTMLOutEvent* pEventTable, bool bOutStarBasic)
+{
+    sal_uInt16 i = 0;
+    while (pEventTable[i].pBasicName || pEventTable[i].pJavaName)
+    {
+        const SvxMacro* pMacro = rMacroTable.Get(pEventTable[i].nEvent);
+
+        if (pMacro && pMacro->HasMacro() && (JAVASCRIPT == pMacro->GetScriptType() || bOutStarBasic))
+        {
+            const sal_Char* pAttributeName = NULL;
+            if (STARBASIC == pMacro->GetScriptType())
+                pAttributeName = pEventTable[i].pBasicName;
+            else
+                pAttributeName = pEventTable[i].pJavaName;
+
+            if (pAttributeName)
+            {
+                rHtmlWriter.attribute(pAttributeName, OUStringToOString(pMacro->GetMacName(), RTL_TEXTENCODING_UTF8));
+            }
+        }
+        i++;
+    }
+}
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
commit 4bc2d7c39c1c5c1cff05665c07330ce9f9395010
Author: Tomaž Vajngerl <tomaz.vajngerl at collabora.com>
Date:   Sat Sep 20 14:53:39 2014 +0200

    html: line break <br/> - use XML style single element declaration
    
    Change-Id: I2e2b7fb85bd272a45d973c29f792c54aa7be0a82

diff --git a/sw/source/filter/html/htmlatr.cxx b/sw/source/filter/html/htmlatr.cxx
index a6f507a..826c7cc 100644
--- a/sw/source/filter/html/htmlatr.cxx
+++ b/sw/source/filter/html/htmlatr.cxx
@@ -2524,7 +2524,8 @@ Writer& OutHTML_SwTxtNode( Writer& rWrt, const SwCntntNode& rNode )
                     if( 0x0a == c )
                     {
                         HTMLOutFuncs::FlushToAscii( rWrt.Strm(), aContext );
-                        HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), OOO_STRING_SVTOOLS_HTML_linebreak );
+                        HtmlWriter aHtml(rWrt.Strm());
+                        aHtml.single(OOO_STRING_SVTOOLS_HTML_linebreak);
                     }
                     // #i120442#: if c is outside the unicode base plane output it as "&#******;"
                     else if( c > 0xffff)
commit d42813db533b0a4930528ba1ccd34f33498ffe36
Author: Tomaž Vajngerl <tomaz.vajngerl at collabora.com>
Date:   Sat Sep 20 14:50:46 2014 +0200

    Extend HTMLWriter: flush the stack, more values for attribute(..)
    
    Change-Id: I733426ba5f82ee25751387f88942dbc66689821d

diff --git a/include/svtools/HtmlWriter.hxx b/include/svtools/HtmlWriter.hxx
index fc2c5c5..3c065ff 100644
--- a/include/svtools/HtmlWriter.hxx
+++ b/include/svtools/HtmlWriter.hxx
@@ -12,6 +12,7 @@
 #define INCLUDED_SVTOOLS_HTMLWRITER_HXX
 
 #include <rtl/string.hxx>
+#include <rtl/ustring.hxx>
 #include <tools/stream.hxx>
 #include <vector>
 #include <svtools/svtdllapi.h>
@@ -20,11 +21,13 @@ class SVT_DLLPUBLIC HtmlWriter
 {
 private:
     std::vector<OString> maElementStack;
-    SvStream&            mrStream;
 
-    bool                 mbElementOpen;
-    bool                 mbContentWritten;
-    bool                 mbPrettyPrint;
+    SvStream& mrStream;
+
+    bool mbElementOpen;
+    bool mbContentWritten;
+    bool mbPrettyPrint;
+    rtl_TextEncoding maEncoding;
 
 public:
     HtmlWriter(SvStream& rStream);
@@ -32,11 +35,23 @@ public:
 
     void prettyPrint(bool bChoice);
 
-    void start(const OString &aElement);
+    void start(const OString& aElement);
+
     void end();
-    void write(const OString &aContent);
-    void attribute(const OString &aAttribute, const OString &aValue);
-    void single(const OString &aContent);
+
+    void flushStack();
+    void flushStack(const OString& aElement);
+
+    void write(const OString& aContent);
+
+    void attribute(const OString& aAttribute, const char* aValue);
+    void attribute(const OString& aAttribute, sal_Int32 aValue);
+    void attribute(const OString& aAttribute, const OString& aValue);
+    void attribute(const OString& aAttribute, const OUString& aValue);
+    // boolean attribute e.g. <img ismap>
+    void attribute(const OString& aAttribute);
+
+    void single(const OString& aContent);
     void endAttribute();
 };
 
diff --git a/svtools/qa/unit/testHtmlWriter.cxx b/svtools/qa/unit/testHtmlWriter.cxx
index 59cdb24..7c9d38f 100644
--- a/svtools/qa/unit/testHtmlWriter.cxx
+++ b/svtools/qa/unit/testHtmlWriter.cxx
@@ -40,6 +40,8 @@ public:
     void testSingleElementWithContent();
     void testSingleElementWithContentAndAttributes();
     void testNested();
+    void testAttributeValues();
+    void testFlushStack();
 
     CPPUNIT_TEST_SUITE(Test);
     CPPUNIT_TEST(testSingleElement);
@@ -47,6 +49,8 @@ public:
     CPPUNIT_TEST(testSingleElementWithContent);
     CPPUNIT_TEST(testSingleElementWithContentAndAttributes);
     CPPUNIT_TEST(testNested);
+    CPPUNIT_TEST(testAttributeValues);
+    CPPUNIT_TEST(testFlushStack);
 
     CPPUNIT_TEST_SUITE_END();
 };
@@ -162,6 +166,126 @@ void Test::testNested()
     CPPUNIT_ASSERT_EQUAL(OString("<abc><xyz>xxx</xyz></abc>"), aString);
 }
 
+void Test::testAttributeValues()
+{
+    SvMemoryStream aStream;
+
+    HtmlWriter aHtml(aStream);
+    aHtml.prettyPrint(false);
+    aHtml.start("abc");
+    aHtml.attribute("one", OString("one"));
+    aHtml.attribute("two", OUString("two"));
+    aHtml.attribute("three", sal_Int32(12));
+    aHtml.end();
+
+    OString aString = extractFromStream(aStream);
+
+    CPPUNIT_ASSERT_EQUAL(OString("<abc one=\"one\" two=\"two\" three=\"12\"/>"), aString);
+}
+
+void Test::testFlushStack()
+{
+    {
+        SvMemoryStream aStream;
+
+        HtmlWriter aHtml(aStream);
+        aHtml.prettyPrint(false);
+        aHtml.start("a");
+        aHtml.flushStack("a"); // simple ,end element "a" = like end()
+
+        OString aString = extractFromStream(aStream);
+
+        CPPUNIT_ASSERT_EQUAL(OString("<a/>"), aString);
+    }
+
+    {
+        SvMemoryStream aStream;
+
+        HtmlWriter aHtml(aStream);
+        aHtml.prettyPrint(false);
+        aHtml.start("a");
+        aHtml.start("b");
+        aHtml.flushStack("b"); // end at first element "b", don't output "a" yet
+
+        OString aString = extractFromStream(aStream);
+
+        CPPUNIT_ASSERT_EQUAL(OString("<a><b/>"), aString);
+    }
+
+    {
+        SvMemoryStream aStream;
+
+        HtmlWriter aHtml(aStream);
+        aHtml.prettyPrint(false);
+        aHtml.start("a");
+        aHtml.start("b");
+        aHtml.flushStack("a"); // end at first element "a"
+
+        OString aString = extractFromStream(aStream);
+
+        CPPUNIT_ASSERT_EQUAL(OString("<a><b/></a>"), aString);
+    }
+
+    {
+        SvMemoryStream aStream;
+
+        HtmlWriter aHtml(aStream);
+        aHtml.prettyPrint(false);
+        aHtml.start("a");
+        aHtml.start("b");
+        aHtml.start("c");
+        aHtml.flushStack("a"); // end at first element "a"
+
+        OString aString = extractFromStream(aStream);
+
+        CPPUNIT_ASSERT_EQUAL(OString("<a><b><c/></b></a>"), aString);
+    }
+
+    {
+        SvMemoryStream aStream;
+
+        HtmlWriter aHtml(aStream);
+        aHtml.prettyPrint(false);
+        aHtml.start("a");
+        aHtml.start("b");
+        aHtml.start("c");
+        aHtml.flushStack("b"); // end at first element "b"
+
+        OString aString = extractFromStream(aStream);
+
+        CPPUNIT_ASSERT_EQUAL(OString("<a><b><c/></b>"), aString);
+    }
+
+    {
+        SvMemoryStream aStream;
+
+        HtmlWriter aHtml(aStream);
+        aHtml.prettyPrint(false);
+        aHtml.start("a");
+        aHtml.start("b");
+        aHtml.start("c");
+        aHtml.flushStack("x"); // no known element - ends when stack is empty
+
+        OString aString = extractFromStream(aStream);
+
+        CPPUNIT_ASSERT_EQUAL(OString("<a><b><c/></b></a>"), aString);
+    }
+
+    {
+        SvMemoryStream aStream;
+
+        HtmlWriter aHtml(aStream);
+        aHtml.prettyPrint(false);
+        aHtml.start("a");
+        aHtml.start("b");
+        aHtml.start("c");
+        aHtml.flushStack(); // flush the whole stack
+
+        OString aString = extractFromStream(aStream);
+
+        CPPUNIT_ASSERT_EQUAL(OString("<a><b><c/></b></a>"), aString);
+    }
+}
 
 CPPUNIT_TEST_SUITE_REGISTRATION(Test);
 CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/svtools/source/svhtml/HtmlWriter.cxx b/svtools/source/svhtml/HtmlWriter.cxx
index 5accc5d..f075d40 100644
--- a/svtools/source/svhtml/HtmlWriter.cxx
+++ b/svtools/source/svhtml/HtmlWriter.cxx
@@ -14,7 +14,8 @@ HtmlWriter::HtmlWriter(SvStream& rStream) :
     mrStream(rStream),
     mbElementOpen(false),
     mbContentWritten(false),
-    mbPrettyPrint(true)
+    mbPrettyPrint(true),
+    maEncoding(RTL_TEXTENCODING_UTF8)
 {}
 
 HtmlWriter::~HtmlWriter()
@@ -25,7 +26,7 @@ void HtmlWriter::prettyPrint(bool bChoice)
     mbPrettyPrint = bChoice;
 }
 
-void HtmlWriter::start(const OString &aElement)
+void HtmlWriter::start(const OString& aElement)
 {
     if (mbElementOpen)
     {
@@ -66,6 +67,24 @@ void HtmlWriter::endAttribute()
     }
 }
 
+void HtmlWriter::flushStack()
+{
+    while (!maElementStack.empty())
+    {
+        end();
+    }
+}
+
+void HtmlWriter::flushStack(const OString& aElement)
+{
+    OString sCurrentElement;
+    do
+    {
+        sCurrentElement = maElementStack.back();
+        end();
+    } while (!maElementStack.empty() && aElement != sCurrentElement);
+}
+
 void HtmlWriter::end()
 {
     if (mbElementOpen)
@@ -105,7 +124,7 @@ void HtmlWriter::write(const OString &aContent)
     mrStream.WriteOString(aContent);
 }
 
-void HtmlWriter::attribute(const OString &aAttribute, const OString &aValue)
+void HtmlWriter::attribute(const OString &aAttribute, const OString& aValue)
 {
     if (mbElementOpen && !aAttribute.isEmpty() && !aValue.isEmpty())
     {
@@ -118,5 +137,29 @@ void HtmlWriter::attribute(const OString &aAttribute, const OString &aValue)
     }
 }
 
+void HtmlWriter::attribute(const OString& aAttribute, const sal_Int32 aValue)
+{
+    attribute(aAttribute, OString::number(aValue));
+}
+
+void HtmlWriter::attribute(const OString& aAttribute, const char* pValue)
+{
+    attribute(aAttribute, OString(pValue));
+}
+
+void HtmlWriter::attribute(const OString& aAttribute, const OUString& aValue)
+{
+    attribute(aAttribute, OUStringToOString(aValue, maEncoding));
+}
+
+void HtmlWriter::attribute(const OString& aAttribute)
+{
+    if (mbElementOpen && !aAttribute.isEmpty())
+    {
+        mrStream.WriteChar(' ');
+        mrStream.WriteOString(aAttribute);
+    }
+}
+
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */


More information about the Libreoffice-commits mailing list