summaryrefslogtreecommitdiffstats
path: root/sc/source/filter/html/htmlexp.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'sc/source/filter/html/htmlexp.cxx')
-rw-r--r--sc/source/filter/html/htmlexp.cxx1378
1 files changed, 1378 insertions, 0 deletions
diff --git a/sc/source/filter/html/htmlexp.cxx b/sc/source/filter/html/htmlexp.cxx
new file mode 100644
index 000000000..9c9f8745f
--- /dev/null
+++ b/sc/source/filter/html/htmlexp.cxx
@@ -0,0 +1,1378 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#include <scitems.hxx>
+#include <editeng/eeitem.hxx>
+
+#include <vcl/svapp.hxx>
+#include <editeng/boxitem.hxx>
+#include <editeng/brushitem.hxx>
+#include <editeng/colritem.hxx>
+#include <editeng/crossedoutitem.hxx>
+#include <editeng/fhgtitem.hxx>
+#include <editeng/fontitem.hxx>
+#include <editeng/postitem.hxx>
+#include <editeng/udlnitem.hxx>
+#include <editeng/wghtitem.hxx>
+#include <editeng/justifyitem.hxx>
+#include <svx/xoutbmp.hxx>
+#include <editeng/editeng.hxx>
+#include <svtools/htmlcfg.hxx>
+#include <sfx2/docfile.hxx>
+#include <sfx2/frmhtmlw.hxx>
+#include <sfx2/objsh.hxx>
+#include <svl/urihelper.hxx>
+#include <svtools/htmlkywd.hxx>
+#include <svtools/htmlout.hxx>
+#include <svtools/parhtml.hxx>
+#include <vcl/outdev.hxx>
+#include <stdio.h>
+#include <osl/diagnose.h>
+#include <o3tl/unit_conversion.hxx>
+
+#include <htmlexp.hxx>
+#include <global.hxx>
+#include <postit.hxx>
+#include <document.hxx>
+#include <attrib.hxx>
+#include <patattr.hxx>
+#include <stlpool.hxx>
+#include <scresid.hxx>
+#include <formulacell.hxx>
+#include <cellform.hxx>
+#include <docoptio.hxx>
+#include <editutil.hxx>
+#include <ftools.hxx>
+#include <cellvalue.hxx>
+#include <mtvelements.hxx>
+
+#include <editeng/flditem.hxx>
+#include <editeng/borderline.hxx>
+
+// Without strings.hrc: error C2679: binary '=' : no operator defined which takes a
+// right-hand operand of type 'const class String (__stdcall *)(class ScResId)'
+// at
+// const String aStrTable( ScResId( SCSTR_TABLE ) ); aStrOut = aStrTable;
+// ?!???
+#include <strings.hrc>
+#include <globstr.hrc>
+
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/uno/Reference.h>
+#include <com/sun/star/document/XDocumentProperties.hpp>
+#include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
+#include <rtl/strbuf.hxx>
+#include <officecfg/Office/Common.hxx>
+
+using ::editeng::SvxBorderLine;
+using namespace ::com::sun::star;
+
+const char sMyBegComment[] = "<!-- ";
+const char sMyEndComment[] = " -->";
+const char sDisplay[] = "display:";
+const char sBorder[] = "border:";
+const char sBackground[] = "background:";
+
+const sal_uInt16 ScHTMLExport::nDefaultFontSize[SC_HTML_FONTSIZES] =
+{
+ HTMLFONTSZ1_DFLT, HTMLFONTSZ2_DFLT, HTMLFONTSZ3_DFLT, HTMLFONTSZ4_DFLT,
+ HTMLFONTSZ5_DFLT, HTMLFONTSZ6_DFLT, HTMLFONTSZ7_DFLT
+};
+
+sal_uInt16 ScHTMLExport::nFontSize[SC_HTML_FONTSIZES] = { 0 };
+
+const char* ScHTMLExport::pFontSizeCss[SC_HTML_FONTSIZES] =
+{
+ "xx-small", "x-small", "small", "medium", "large", "x-large", "xx-large"
+};
+
+const sal_uInt16 ScHTMLExport::nCellSpacing = 0;
+const char ScHTMLExport::sIndentSource[nIndentMax+1] =
+ "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
+
+// Macros for HTML export
+
+#define TAG_ON( tag ) HTMLOutFuncs::Out_AsciiTag( rStrm, tag )
+#define TAG_OFF( tag ) HTMLOutFuncs::Out_AsciiTag( rStrm, tag, false )
+#define OUT_STR( str ) HTMLOutFuncs::Out_String( rStrm, str, &aNonConvertibleChars )
+#define OUT_LF() rStrm.WriteCharPtr( SAL_NEWLINE_STRING ).WriteCharPtr( GetIndentStr() )
+#define TAG_ON_LF( tag ) (TAG_ON( tag ).WriteCharPtr( SAL_NEWLINE_STRING ).WriteCharPtr( GetIndentStr() ))
+#define TAG_OFF_LF( tag ) (TAG_OFF( tag ).WriteCharPtr( SAL_NEWLINE_STRING ).WriteCharPtr( GetIndentStr() ))
+#define OUT_HR() TAG_ON_LF( OOO_STRING_SVTOOLS_HTML_horzrule )
+#define OUT_COMMENT( comment ) (rStrm.WriteCharPtr( sMyBegComment ), OUT_STR( comment ) \
+ .WriteCharPtr( sMyEndComment ).WriteCharPtr( SAL_NEWLINE_STRING ) \
+ .WriteCharPtr( GetIndentStr() ))
+
+#define OUT_SP_CSTR_ASS( s ) rStrm.WriteChar( ' ').WriteCharPtr( s ).WriteChar( '=' )
+
+#define GLOBSTR(id) ScResId( id )
+
+void ScFormatFilterPluginImpl::ScExportHTML( SvStream& rStrm, const OUString& rBaseURL, ScDocument* pDoc,
+ const ScRange& rRange, const rtl_TextEncoding /*eNach*/, bool bAll,
+ const OUString& rStreamPath, OUString& rNonConvertibleChars, const OUString& rFilterOptions )
+{
+ ScHTMLExport aEx( rStrm, rBaseURL, pDoc, rRange, bAll, rStreamPath, rFilterOptions );
+ aEx.Write();
+ rNonConvertibleChars = aEx.GetNonConvertibleChars();
+}
+
+static OString lcl_getColGroupString(sal_Int32 nSpan, sal_Int32 nWidth)
+{
+ OStringBuffer aByteStr(OOO_STRING_SVTOOLS_HTML_colgroup);
+ aByteStr.append(' ');
+ if( nSpan > 1 )
+ {
+ aByteStr.append(OOO_STRING_SVTOOLS_HTML_O_span);
+ aByteStr.append("=\"");
+ aByteStr.append(nSpan);
+ aByteStr.append("\" ");
+ }
+ aByteStr.append(OOO_STRING_SVTOOLS_HTML_O_width);
+ aByteStr.append("=\"");
+ aByteStr.append(nWidth);
+ aByteStr.append('"');
+ return aByteStr.makeStringAndClear();
+}
+
+static void lcl_AddStamp( OUString& rStr, std::u16string_view rName,
+ const css::util::DateTime& rDateTime,
+ const LocaleDataWrapper& rLoc )
+{
+ Date aD(rDateTime.Day, rDateTime.Month, rDateTime.Year);
+ tools::Time aT(rDateTime.Hours, rDateTime.Minutes, rDateTime.Seconds,
+ rDateTime.NanoSeconds);
+ DateTime aDateTime(aD,aT);
+
+ OUString aStrDate = rLoc.getDate( aDateTime );
+ OUString aStrTime = rLoc.getTime( aDateTime );
+
+ rStr += GLOBSTR( STR_BY ) + " ";
+ if (!rName.empty())
+ rStr += rName;
+ else
+ rStr += "???";
+ rStr += " " + GLOBSTR( STR_ON ) + " ";
+ if (!aStrDate.isEmpty())
+ rStr += aStrDate;
+ else
+ rStr += "???";
+ rStr += ", ";
+ if (!aStrTime.isEmpty())
+ rStr += aStrTime;
+ else
+ rStr += "???";
+}
+
+static OString lcl_makeHTMLColorTriplet(const Color& rColor)
+{
+ char buf[24];
+
+ // <font COLOR="#00FF40">hello</font>
+ snprintf( buf, 24, "\"#%02X%02X%02X\"", rColor.GetRed(), rColor.GetGreen(), rColor.GetBlue() );
+
+ return OString(buf);
+}
+
+ScHTMLExport::ScHTMLExport( SvStream& rStrmP, const OUString& rBaseURL, ScDocument* pDocP,
+ const ScRange& rRangeP, bool bAllP,
+ const OUString& rStreamPathP, std::u16string_view rFilterOptions ) :
+ ScExportBase( rStrmP, pDocP, rRangeP ),
+ aBaseURL( rBaseURL ),
+ aStreamPath( rStreamPathP ),
+ pAppWin( Application::GetDefaultDevice() ),
+ nUsedTables( 0 ),
+ nIndent( 0 ),
+ bAll( bAllP ),
+ bTabHasGraphics( false ),
+ bTabAlignedLeft( false ),
+ bCalcAsShown( pDocP->GetDocOptions().IsCalcAsShown() ),
+ bTableDataHeight( true ),
+ mbSkipImages ( false ),
+ mbSkipHeaderFooter( false )
+{
+ strcpy( sIndent, sIndentSource );
+ sIndent[0] = 0;
+
+ // set HTML configuration
+ bCopyLocalFileToINet = officecfg::Office::Common::Filter::HTML::Export::LocalGraphic::get();
+
+ if (rFilterOptions == u"SkipImages")
+ {
+ mbSkipImages = true;
+ }
+ else if (rFilterOptions == u"SkipHeaderFooter")
+ {
+ mbSkipHeaderFooter = true;
+ }
+
+ for ( sal_uInt16 j=0; j < SC_HTML_FONTSIZES; j++ )
+ {
+ sal_uInt16 nSize = SvxHtmlOptions::GetFontSize( j );
+ // remember in Twips, like our SvxFontHeightItem
+ if ( nSize )
+ nFontSize[j] = nSize * 20;
+ else
+ nFontSize[j] = nDefaultFontSize[j] * 20;
+ }
+
+ const SCTAB nCount = pDoc->GetTableCount();
+ for ( SCTAB nTab = 0; nTab < nCount; nTab++ )
+ {
+ if ( !IsEmptyTable( nTab ) )
+ nUsedTables++;
+ }
+}
+
+ScHTMLExport::~ScHTMLExport()
+{
+ aGraphList.clear();
+}
+
+sal_uInt16 ScHTMLExport::GetFontSizeNumber( sal_uInt16 nHeight )
+{
+ sal_uInt16 nSize = 1;
+ for ( sal_uInt16 j=SC_HTML_FONTSIZES-1; j>0; j-- )
+ {
+ if( nHeight > (nFontSize[j] + nFontSize[j-1]) / 2 )
+ { // The one next to it
+ nSize = j+1;
+ break;
+ }
+ }
+ return nSize;
+}
+
+const char* ScHTMLExport::GetFontSizeCss( sal_uInt16 nHeight )
+{
+ sal_uInt16 nSize = GetFontSizeNumber( nHeight );
+ return pFontSizeCss[ nSize-1 ];
+}
+
+sal_uInt16 ScHTMLExport::ToPixel( sal_uInt16 nVal )
+{
+ if( nVal )
+ {
+ nVal = static_cast<sal_uInt16>(pAppWin->LogicToPixel(
+ Size( nVal, nVal ), MapMode( MapUnit::MapTwip ) ).Width());
+ if( !nVal ) // If there's a Twip there should also be a Pixel
+ nVal = 1;
+ }
+ return nVal;
+}
+
+Size ScHTMLExport::MMToPixel( const Size& rSize )
+{
+ Size aSize = pAppWin->LogicToPixel( rSize, MapMode( MapUnit::Map100thMM ) );
+ // If there's something there should also be a Pixel
+ if ( !aSize.Width() && rSize.Width() )
+ aSize.setWidth( 1 );
+ if ( !aSize.Height() && rSize.Height() )
+ aSize.setHeight( 1 );
+ return aSize;
+}
+
+void ScHTMLExport::Write()
+{
+ if (!mbSkipHeaderFooter)
+ {
+ rStrm.WriteChar( '<' ).WriteCharPtr( OOO_STRING_SVTOOLS_HTML_doctype ).WriteChar( ' ' ).WriteCharPtr( OOO_STRING_SVTOOLS_HTML_doctype5 ).WriteChar( '>' )
+ .WriteCharPtr( SAL_NEWLINE_STRING ).WriteCharPtr( SAL_NEWLINE_STRING );
+ TAG_ON_LF( OOO_STRING_SVTOOLS_HTML_html );
+ WriteHeader();
+ OUT_LF();
+ }
+ WriteBody();
+ OUT_LF();
+ if (!mbSkipHeaderFooter)
+ TAG_OFF_LF( OOO_STRING_SVTOOLS_HTML_html );
+}
+
+void ScHTMLExport::WriteHeader()
+{
+ IncIndent(1); TAG_ON_LF( OOO_STRING_SVTOOLS_HTML_head );
+
+ if ( pDoc->IsClipOrUndo() )
+ { // no real DocInfo available, but some META information like charset needed
+ SfxFrameHTMLWriter::Out_DocInfo( rStrm, aBaseURL, nullptr, sIndent, &aNonConvertibleChars );
+ }
+ else
+ {
+ uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
+ pDoc->GetDocumentShell()->GetModel(), uno::UNO_QUERY_THROW);
+ uno::Reference<document::XDocumentProperties> xDocProps
+ = xDPS->getDocumentProperties();
+ SfxFrameHTMLWriter::Out_DocInfo( rStrm, aBaseURL, xDocProps,
+ sIndent, &aNonConvertibleChars );
+ OUT_LF();
+
+ if (!xDocProps->getPrintedBy().isEmpty())
+ {
+ OUT_COMMENT( GLOBSTR( STR_DOC_INFO ) );
+ OUString aStrOut = GLOBSTR( STR_DOC_PRINTED ) + ": ";
+ lcl_AddStamp( aStrOut, xDocProps->getPrintedBy(),
+ xDocProps->getPrintDate(), ScGlobal::getLocaleData() );
+ OUT_COMMENT( aStrOut );
+ }
+
+ }
+ OUT_LF();
+
+ // CSS1 StyleSheet
+ PageDefaults( bAll ? 0 : aRange.aStart.Tab() );
+ IncIndent(1);
+ rStrm.WriteCharPtr( "<" ).WriteCharPtr( OOO_STRING_SVTOOLS_HTML_style ).WriteCharPtr( " " ).WriteCharPtr( OOO_STRING_SVTOOLS_HTML_O_type ).WriteCharPtr( "=\"text/css\">" );
+
+ OUT_LF();
+ rStrm.WriteCharPtr(OOO_STRING_SVTOOLS_HTML_body);
+ rStrm.WriteCharPtr(",");
+ rStrm.WriteCharPtr(OOO_STRING_SVTOOLS_HTML_division);
+ rStrm.WriteCharPtr(",");
+ rStrm.WriteCharPtr(OOO_STRING_SVTOOLS_HTML_table);
+ rStrm.WriteCharPtr(",");
+ rStrm.WriteCharPtr(OOO_STRING_SVTOOLS_HTML_thead);
+ rStrm.WriteCharPtr(",");
+ rStrm.WriteCharPtr(OOO_STRING_SVTOOLS_HTML_tbody);
+ rStrm.WriteCharPtr(",");
+ rStrm.WriteCharPtr(OOO_STRING_SVTOOLS_HTML_tfoot);
+ rStrm.WriteCharPtr(",");
+ rStrm.WriteCharPtr(OOO_STRING_SVTOOLS_HTML_tablerow);
+ rStrm.WriteCharPtr(",");
+ rStrm.WriteCharPtr(OOO_STRING_SVTOOLS_HTML_tableheader);
+ rStrm.WriteCharPtr(",");
+ rStrm.WriteCharPtr(OOO_STRING_SVTOOLS_HTML_tabledata);
+ rStrm.WriteCharPtr(",");
+ rStrm.WriteCharPtr(OOO_STRING_SVTOOLS_HTML_parabreak);
+ rStrm.WriteCharPtr(" { ");
+ rStrm.WriteCharPtr("font-family:");
+
+ if (!aHTMLStyle.aFontFamilyName.isEmpty())
+ {
+ const OUString& rList = aHTMLStyle.aFontFamilyName;
+ for(sal_Int32 nPos {0};;)
+ {
+ rStrm.WriteChar( '\"' );
+ OUT_STR( rList.getToken( 0, ';', nPos ) );
+ rStrm.WriteChar( '\"' );
+ if (nPos<0)
+ break;
+ rStrm.WriteCharPtr( ", " );
+ }
+ }
+ rStrm.WriteCharPtr("; ");
+ rStrm.WriteCharPtr("font-size:");
+ rStrm.WriteCharPtr(GetFontSizeCss(static_cast<sal_uInt16>(aHTMLStyle.nFontHeight)));
+ rStrm.WriteCharPtr(" }");
+
+ OUT_LF();
+
+ // write the style for the comments to make them stand out from normal cell content
+ // this is done through only showing the cell contents when the custom indicator is hovered
+ rStrm.WriteCharPtr(OOO_STRING_SVTOOLS_HTML_anchor);
+ rStrm.WriteCharPtr(".comment-indicator:hover");
+ rStrm.WriteCharPtr(" + ");
+ rStrm.WriteCharPtr(OOO_STRING_SVTOOLS_HTML_comment2);
+ rStrm.WriteCharPtr(" { ");
+ rStrm.WriteCharPtr(sBackground);
+ rStrm.WriteCharPtr("#ffd");
+ rStrm.WriteCharPtr("; ");
+ rStrm.WriteCharPtr("position:");
+ rStrm.WriteCharPtr("absolute");
+ rStrm.WriteCharPtr("; ");
+ rStrm.WriteCharPtr(sDisplay);
+ rStrm.WriteCharPtr("block");
+ rStrm.WriteCharPtr("; ");
+ rStrm.WriteCharPtr(sBorder);
+ rStrm.WriteCharPtr("1px solid black");
+ rStrm.WriteCharPtr("; ");
+ rStrm.WriteCharPtr("padding:");
+ rStrm.WriteCharPtr("0.5em");
+ rStrm.WriteCharPtr("; ");
+ rStrm.WriteCharPtr(" } ");
+
+ OUT_LF();
+
+ rStrm.WriteCharPtr(OOO_STRING_SVTOOLS_HTML_anchor);
+ rStrm.WriteCharPtr(".comment-indicator");
+ rStrm.WriteCharPtr(" { ");
+ rStrm.WriteCharPtr(sBackground);
+ rStrm.WriteCharPtr("red");
+ rStrm.WriteCharPtr("; ");
+ rStrm.WriteCharPtr(sDisplay);
+ rStrm.WriteCharPtr("inline-block");
+ rStrm.WriteCharPtr("; ");
+ rStrm.WriteCharPtr(sBorder);
+ rStrm.WriteCharPtr("1px solid black");
+ rStrm.WriteCharPtr("; ");
+ rStrm.WriteCharPtr("width:");
+ rStrm.WriteCharPtr("0.5em");
+ rStrm.WriteCharPtr("; ");
+ rStrm.WriteCharPtr("height:");
+ rStrm.WriteCharPtr("0.5em");
+ rStrm.WriteCharPtr("; ");
+ rStrm.WriteCharPtr(" } ");
+
+ OUT_LF();
+
+ rStrm.WriteCharPtr(OOO_STRING_SVTOOLS_HTML_comment2);
+ rStrm.WriteCharPtr(" { ");
+ rStrm.WriteCharPtr(sDisplay);
+ rStrm.WriteCharPtr("none");
+ rStrm.WriteCharPtr("; ");
+ rStrm.WriteCharPtr(" } ");
+
+
+ IncIndent(-1);
+ OUT_LF();
+ TAG_OFF_LF( OOO_STRING_SVTOOLS_HTML_style );
+
+ IncIndent(-1);
+ OUT_LF();
+ TAG_OFF_LF( OOO_STRING_SVTOOLS_HTML_head );
+}
+
+void ScHTMLExport::WriteOverview()
+{
+ if ( nUsedTables <= 1 )
+ return;
+
+ IncIndent(1);
+ OUT_HR();
+ IncIndent(1); TAG_ON( OOO_STRING_SVTOOLS_HTML_parabreak ); TAG_ON_LF( OOO_STRING_SVTOOLS_HTML_center );
+ TAG_ON( OOO_STRING_SVTOOLS_HTML_head1 );
+ OUT_STR( ScResId( STR_OVERVIEW ) );
+ TAG_OFF_LF( OOO_STRING_SVTOOLS_HTML_head1 );
+
+ OUString aStr;
+
+ const SCTAB nCount = pDoc->GetTableCount();
+ for ( SCTAB nTab = 0; nTab < nCount; nTab++ )
+ {
+ if ( !IsEmptyTable( nTab ) )
+ {
+ pDoc->GetName( nTab, aStr );
+ rStrm.WriteCharPtr( "<A HREF=\"#table" )
+ .WriteOString( OString::number(nTab) )
+ .WriteCharPtr( "\">" );
+ OUT_STR( aStr );
+ rStrm.WriteCharPtr( "</A>" );
+ TAG_ON_LF( OOO_STRING_SVTOOLS_HTML_linebreak );
+ }
+ }
+
+ IncIndent(-1); OUT_LF();
+ IncIndent(-1); TAG_OFF( OOO_STRING_SVTOOLS_HTML_center ); TAG_OFF_LF( OOO_STRING_SVTOOLS_HTML_parabreak );
+}
+
+const SfxItemSet& ScHTMLExport::PageDefaults( SCTAB nTab )
+{
+ SfxStyleSheetBasePool* pStylePool = pDoc->GetStyleSheetPool();
+ SfxStyleSheetBase* pStyleSheet = nullptr;
+ OSL_ENSURE( pStylePool, "StylePool not found! :-(" );
+
+ // remember defaults for compare in WriteCell
+ if ( !aHTMLStyle.bInitialized )
+ {
+ pStyleSheet = pStylePool->Find(
+ ScResId(STR_STYLENAME_STANDARD),
+ SfxStyleFamily::Para );
+ OSL_ENSURE( pStyleSheet, "ParaStyle not found! :-(" );
+ if (!pStyleSheet)
+ pStyleSheet = pStylePool->First(SfxStyleFamily::Para);
+ const SfxItemSet& rSetPara = pStyleSheet->GetItemSet();
+
+ aHTMLStyle.nDefaultScriptType = ScGlobal::GetDefaultScriptType();
+ aHTMLStyle.aFontFamilyName = static_cast<const SvxFontItem&>((rSetPara.Get(
+ ScGlobal::GetScriptedWhichID(
+ aHTMLStyle.nDefaultScriptType, ATTR_FONT
+ )))).GetFamilyName();
+ aHTMLStyle.nFontHeight = static_cast<const SvxFontHeightItem&>((rSetPara.Get(
+ ScGlobal::GetScriptedWhichID(
+ aHTMLStyle.nDefaultScriptType, ATTR_FONT_HEIGHT
+ )))).GetHeight();
+ aHTMLStyle.nFontSizeNumber = GetFontSizeNumber( static_cast< sal_uInt16 >( aHTMLStyle.nFontHeight ) );
+ }
+
+ // Page style sheet printer settings, e.g. for background graphics.
+ // There's only one background graphic in HTML!
+ pStyleSheet = pStylePool->Find( pDoc->GetPageStyle( nTab ), SfxStyleFamily::Page );
+ OSL_ENSURE( pStyleSheet, "PageStyle not found! :-(" );
+ if (!pStyleSheet)
+ pStyleSheet = pStylePool->First(SfxStyleFamily::Page);
+ const SfxItemSet& rSet = pStyleSheet->GetItemSet();
+ if ( !aHTMLStyle.bInitialized )
+ {
+ const SvxBrushItem* pBrushItem = &rSet.Get( ATTR_BACKGROUND );
+ aHTMLStyle.aBackgroundColor = pBrushItem->GetColor();
+ aHTMLStyle.bInitialized = true;
+ }
+ return rSet;
+}
+
+OString ScHTMLExport::BorderToStyle(const char* pBorderName,
+ const SvxBorderLine* pLine, bool& bInsertSemicolon)
+{
+ OStringBuffer aOut;
+
+ if ( pLine )
+ {
+ if ( bInsertSemicolon )
+ aOut.append("; ");
+
+ // which border
+ aOut.append(OString::Concat("border-") + pBorderName + ": ");
+
+ // thickness
+ int nWidth = pLine->GetWidth();
+ int nPxWidth = (nWidth > 0) ?
+ std::max(o3tl::convert(nWidth, o3tl::Length::twip, o3tl::Length::px), sal_Int64(1)) : 0;
+ aOut.append(OString::number(nPxWidth) + "px ");
+ switch (pLine->GetBorderLineStyle())
+ {
+ case SvxBorderLineStyle::SOLID:
+ aOut.append("solid");
+ break;
+ case SvxBorderLineStyle::DOTTED:
+ aOut.append("dotted");
+ break;
+ case SvxBorderLineStyle::DASHED:
+ case SvxBorderLineStyle::DASH_DOT:
+ case SvxBorderLineStyle::DASH_DOT_DOT:
+ aOut.append("dashed");
+ break;
+ case SvxBorderLineStyle::DOUBLE:
+ case SvxBorderLineStyle::DOUBLE_THIN:
+ case SvxBorderLineStyle::THINTHICK_SMALLGAP:
+ case SvxBorderLineStyle::THINTHICK_MEDIUMGAP:
+ case SvxBorderLineStyle::THINTHICK_LARGEGAP:
+ case SvxBorderLineStyle::THICKTHIN_SMALLGAP:
+ case SvxBorderLineStyle::THICKTHIN_MEDIUMGAP:
+ case SvxBorderLineStyle::THICKTHIN_LARGEGAP:
+ aOut.append("double");
+ break;
+ case SvxBorderLineStyle::EMBOSSED:
+ aOut.append("ridge");
+ break;
+ case SvxBorderLineStyle::ENGRAVED:
+ aOut.append("groove");
+ break;
+ case SvxBorderLineStyle::OUTSET:
+ aOut.append("outset");
+ break;
+ case SvxBorderLineStyle::INSET:
+ aOut.append("inset");
+ break;
+ default:
+ aOut.append("hidden");
+ }
+ aOut.append(" #");
+
+ // color
+ char hex[7];
+ snprintf( hex, 7, "%06" SAL_PRIxUINT32, static_cast<sal_uInt32>( pLine->GetColor().GetRGBColor() ) );
+ hex[6] = 0;
+
+ aOut.append(hex);
+
+ bInsertSemicolon = true;
+ }
+
+ return aOut.makeStringAndClear();
+}
+
+void ScHTMLExport::WriteBody()
+{
+ const SfxItemSet& rSet = PageDefaults( bAll ? 0 : aRange.aStart.Tab() );
+ const SvxBrushItem* pBrushItem = &rSet.Get( ATTR_BACKGROUND );
+
+ // default text color black
+ if (!mbSkipHeaderFooter)
+ {
+ rStrm.WriteChar( '<' ).WriteCharPtr( OOO_STRING_SVTOOLS_HTML_body );
+
+ if (!mbSkipImages)
+ {
+ if ( bAll && GPOS_NONE != pBrushItem->GetGraphicPos() )
+ {
+ OUString aLink = pBrushItem->GetGraphicLink();
+ OUString aGrfNm;
+
+ // Embedded graphic -> write using WriteGraphic
+ if( aLink.isEmpty() )
+ {
+ const Graphic* pGrf = pBrushItem->GetGraphic();
+ if( pGrf )
+ {
+ // Save graphic as (JPG) file
+ aGrfNm = aStreamPath;
+ ErrCode nErr = XOutBitmap::WriteGraphic( *pGrf, aGrfNm,
+ "JPG", XOutFlags::UseNativeIfPossible );
+ if( !nErr ) // Contains errors, as we have nothing to output
+ {
+ aGrfNm = URIHelper::SmartRel2Abs(
+ INetURLObject(aBaseURL),
+ aGrfNm, URIHelper::GetMaybeFileHdl());
+ aLink = aGrfNm;
+ }
+ }
+ }
+ else
+ {
+ aGrfNm = aLink;
+ if( bCopyLocalFileToINet )
+ {
+ CopyLocalFileToINet( aGrfNm, aStreamPath );
+ }
+ else
+ aGrfNm = URIHelper::SmartRel2Abs(
+ INetURLObject(aBaseURL),
+ aGrfNm, URIHelper::GetMaybeFileHdl());
+ aLink = aGrfNm;
+ }
+ if( !aLink.isEmpty() )
+ {
+ rStrm.WriteChar( ' ' ).WriteCharPtr( OOO_STRING_SVTOOLS_HTML_O_background ).WriteCharPtr( "=\"" );
+ OUT_STR( URIHelper::simpleNormalizedMakeRelative(
+ aBaseURL,
+ aLink ) ).WriteChar( '\"' );
+ }
+ }
+ }
+ if ( !aHTMLStyle.aBackgroundColor.IsTransparent() )
+ { // A transparent background color should always result in default
+ // background of the browser. Also, HTMLOutFuncs::Out_Color() writes
+ // black #000000 for COL_AUTO which is the same as white #ffffff with
+ // transparency set to 0xff, our default background.
+ OUT_SP_CSTR_ASS( OOO_STRING_SVTOOLS_HTML_O_bgcolor );
+ HTMLOutFuncs::Out_Color( rStrm, aHTMLStyle.aBackgroundColor );
+ }
+
+ rStrm.WriteChar( '>' ); OUT_LF();
+ }
+
+ if ( bAll )
+ WriteOverview();
+
+ WriteTables();
+
+ if (!mbSkipHeaderFooter)
+ TAG_OFF_LF( OOO_STRING_SVTOOLS_HTML_body );
+}
+
+void ScHTMLExport::WriteTables()
+{
+ const SCTAB nTabCount = pDoc->GetTableCount();
+ const OUString aStrTable( ScResId( SCSTR_TABLE ) );
+ OUString aStr;
+ OUString aStrOut;
+ SCCOL nStartCol;
+ SCROW nStartRow;
+ SCTAB nStartTab;
+ SCCOL nEndCol;
+ SCROW nEndRow;
+ SCTAB nEndTab;
+ SCCOL nStartColFix = 0;
+ SCROW nStartRowFix = 0;
+ SCCOL nEndColFix = 0;
+ SCROW nEndRowFix = 0;
+ ScDrawLayer* pDrawLayer = pDoc->GetDrawLayer();
+ if ( bAll )
+ {
+ nStartTab = 0;
+ nEndTab = nTabCount - 1;
+ }
+ else
+ {
+ nStartCol = nStartColFix = aRange.aStart.Col();
+ nStartRow = nStartRowFix = aRange.aStart.Row();
+ nStartTab = aRange.aStart.Tab();
+ nEndCol = nEndColFix = aRange.aEnd.Col();
+ nEndRow = nEndRowFix = aRange.aEnd.Row();
+ nEndTab = aRange.aEnd.Tab();
+ }
+ SCTAB nTableStrNum = 1;
+ for ( SCTAB nTab=nStartTab; nTab<=nEndTab; nTab++ )
+ {
+ if ( !pDoc->IsVisible( nTab ) )
+ continue; // for
+
+ if ( bAll )
+ {
+ if ( !GetDataArea( nTab, nStartCol, nStartRow, nEndCol, nEndRow ) )
+ continue; // for
+
+ if ( nUsedTables > 1 )
+ {
+ aStrOut = aStrTable + " " + OUString::number( nTableStrNum++ ) + ": ";
+
+ OUT_HR();
+
+ // Write anchor
+ rStrm.WriteCharPtr( "<A NAME=\"table" )
+ .WriteOString( OString::number(nTab) )
+ .WriteCharPtr( "\">" );
+ TAG_ON( OOO_STRING_SVTOOLS_HTML_head1 );
+ OUT_STR( aStrOut );
+ TAG_ON( OOO_STRING_SVTOOLS_HTML_emphasis );
+
+ pDoc->GetName( nTab, aStr );
+ OUT_STR( aStr );
+
+ TAG_OFF( OOO_STRING_SVTOOLS_HTML_emphasis );
+ TAG_OFF( OOO_STRING_SVTOOLS_HTML_head1 );
+ rStrm.WriteCharPtr( "</A>" ); OUT_LF();
+ }
+ }
+ else
+ {
+ nStartCol = nStartColFix;
+ nStartRow = nStartRowFix;
+ nEndCol = nEndColFix;
+ nEndRow = nEndRowFix;
+ if ( !TrimDataArea( nTab, nStartCol, nStartRow, nEndCol, nEndRow ) )
+ continue; // for
+ }
+
+ // <TABLE ...>
+ OStringBuffer aByteStrOut(OOO_STRING_SVTOOLS_HTML_table);
+
+ bTabHasGraphics = bTabAlignedLeft = false;
+ if ( bAll && pDrawLayer )
+ PrepareGraphics( pDrawLayer, nTab, nStartCol, nStartRow,
+ nEndCol, nEndRow );
+
+ // more <TABLE ...>
+ if ( bTabAlignedLeft )
+ {
+ aByteStrOut.append(" " OOO_STRING_SVTOOLS_HTML_O_align
+ "=\""
+ OOO_STRING_SVTOOLS_HTML_AL_left "\"");
+ }
+ // ALIGN=LEFT allow text and graphics to flow around
+ // CELLSPACING
+ aByteStrOut.append(" " OOO_STRING_SVTOOLS_HTML_O_cellspacing
+ "=\"" +
+ OString::number(nCellSpacing) + "\"");
+
+ // BORDER=0, we do the styling of the cells in <TD>
+ aByteStrOut.append(" " OOO_STRING_SVTOOLS_HTML_O_border "=\"0\"");
+ IncIndent(1); TAG_ON_LF( aByteStrOut.makeStringAndClear().getStr() );
+
+ // --- <COLGROUP> ----
+ {
+ SCCOL nCol = nStartCol;
+ sal_Int32 nWidth = 0;
+ sal_Int32 nSpan = 0;
+ while( nCol <= nEndCol )
+ {
+ if( pDoc->ColHidden(nCol, nTab) )
+ {
+ ++nCol;
+ continue;
+ }
+
+ if( nWidth != ToPixel( pDoc->GetColWidth( nCol, nTab ) ) )
+ {
+ if( nSpan != 0 )
+ {
+ TAG_ON(lcl_getColGroupString(nSpan, nWidth).getStr());
+ TAG_OFF_LF( OOO_STRING_SVTOOLS_HTML_colgroup );
+ }
+ nWidth = ToPixel( pDoc->GetColWidth( nCol, nTab ) );
+ nSpan = 1;
+ }
+ else
+ nSpan++;
+ nCol++;
+ }
+ if( nSpan )
+ {
+ TAG_ON(lcl_getColGroupString(nSpan, nWidth).getStr());
+ TAG_OFF_LF( OOO_STRING_SVTOOLS_HTML_colgroup );
+ }
+ }
+
+ // <TBODY> // Re-enable only when THEAD and TFOOT are exported
+ // IncIndent(1); TAG_ON_LF( OOO_STRING_SVTOOLS_HTML_tbody );
+ // At least old (3.x, 4.x?) Netscape doesn't follow <TABLE COLS=n> and
+ // <COL WIDTH=x> specified, but needs a width at every column.
+ bool bHasHiddenRows = pDoc->HasHiddenRows(nStartRow, nEndRow, nTab);
+ // We need to cache sc::ColumnBlockPosition per each column.
+ std::vector< sc::ColumnBlockPosition > blockPos( nEndCol - nStartCol + 1 );
+ for( SCCOL i = nStartCol; i <= nEndCol; ++i )
+ pDoc->InitColumnBlockPosition( blockPos[ i - nStartCol ], nTab, i );
+ for ( SCROW nRow=nStartRow; nRow<=nEndRow; nRow++ )
+ {
+ if ( bHasHiddenRows && pDoc->RowHidden(nRow, nTab) )
+ {
+ nRow = pDoc->FirstVisibleRow(nRow+1, nEndRow, nTab);
+ --nRow;
+ continue; // for
+ }
+
+ IncIndent(1); TAG_ON_LF( OOO_STRING_SVTOOLS_HTML_tablerow );
+ bTableDataHeight = true; // height at every first cell of each row
+ for ( SCCOL nCol2=nStartCol; nCol2<=nEndCol; nCol2++ )
+ {
+ if ( pDoc->ColHidden(nCol2, nTab) )
+ continue; // for
+
+ if ( nCol2 == nEndCol )
+ IncIndent(-1);
+ WriteCell( blockPos[ nCol2 - nStartCol ], nCol2, nRow, nTab );
+ bTableDataHeight = false;
+ }
+
+ if ( nRow == nEndRow )
+ IncIndent(-1);
+ TAG_OFF_LF( OOO_STRING_SVTOOLS_HTML_tablerow );
+ }
+ // TODO: Uncomment later
+ // IncIndent(-1); TAG_OFF_LF( OOO_STRING_SVTOOLS_HTML_tbody );
+
+ IncIndent(-1); TAG_OFF_LF( OOO_STRING_SVTOOLS_HTML_table );
+
+ if ( bTabHasGraphics && !mbSkipImages )
+ {
+ // the rest that is not in a cell
+ size_t ListSize = aGraphList.size();
+ for ( size_t i = 0; i < ListSize; ++i )
+ {
+ ScHTMLGraphEntry* pE = &aGraphList[ i ];
+ if ( !pE->bWritten )
+ WriteGraphEntry( pE );
+ }
+ aGraphList.clear();
+ if ( bTabAlignedLeft )
+ {
+ // clear <TABLE ALIGN=LEFT> with <BR CLEAR=LEFT>
+ aByteStrOut.append(OOO_STRING_SVTOOLS_HTML_linebreak);
+ aByteStrOut.append(' ').
+ append(OOO_STRING_SVTOOLS_HTML_O_clear).append('=').
+ append(OOO_STRING_SVTOOLS_HTML_AL_left);
+ TAG_ON_LF( aByteStrOut.makeStringAndClear().getStr() );
+ }
+ }
+
+ if ( bAll )
+ OUT_COMMENT( "**************************************************************************" );
+ }
+}
+
+void ScHTMLExport::WriteCell( sc::ColumnBlockPosition& rBlockPos, SCCOL nCol, SCROW nRow, SCTAB nTab )
+{
+ ScAddress aPos( nCol, nRow, nTab );
+ ScRefCellValue aCell(*pDoc, aPos, rBlockPos);
+ const ScPatternAttr* pAttr = pDoc->GetPattern( nCol, nRow, nTab );
+ const SfxItemSet* pCondItemSet = pDoc->GetCondResult( nCol, nRow, nTab, &aCell );
+
+ const ScMergeFlagAttr& rMergeFlagAttr = pAttr->GetItem( ATTR_MERGE_FLAG, pCondItemSet );
+ if ( rMergeFlagAttr.IsOverlapped() )
+ return ;
+
+ ScHTMLGraphEntry* pGraphEntry = nullptr;
+ if ( bTabHasGraphics && !mbSkipImages )
+ {
+ size_t ListSize = aGraphList.size();
+ for ( size_t i = 0; i < ListSize; ++i )
+ {
+ ScHTMLGraphEntry* pE = &aGraphList[ i ];
+ if ( pE->bInCell && pE->aRange.Contains( aPos ) )
+ {
+ if ( pE->aRange.aStart == aPos )
+ {
+ pGraphEntry = pE;
+ break; // for
+ }
+ else
+ return ; // Is a Col/RowSpan, Overlapped
+ }
+ }
+ }
+
+ sal_uInt32 nFormat = pAttr->GetNumberFormat( pFormatter );
+ bool bValueData = aCell.hasNumeric();
+ SvtScriptType nScriptType = SvtScriptType::NONE;
+ if (!aCell.isEmpty())
+ nScriptType = pDoc->GetScriptType(nCol, nRow, nTab, &aCell);
+
+ if ( nScriptType == SvtScriptType::NONE )
+ nScriptType = aHTMLStyle.nDefaultScriptType;
+
+ OStringBuffer aStrTD(OOO_STRING_SVTOOLS_HTML_tabledata);
+
+ // border of the cells
+ const SvxBoxItem* pBorder = pDoc->GetAttr( nCol, nRow, nTab, ATTR_BORDER );
+ if ( pBorder && (pBorder->GetTop() || pBorder->GetBottom() || pBorder->GetLeft() || pBorder->GetRight()) )
+ {
+ aStrTD.append(" " OOO_STRING_SVTOOLS_HTML_style "=\"");
+
+ bool bInsertSemicolon = false;
+ aStrTD.append(BorderToStyle("top", pBorder->GetTop(),
+ bInsertSemicolon));
+ aStrTD.append(BorderToStyle("bottom", pBorder->GetBottom(),
+ bInsertSemicolon));
+ aStrTD.append(BorderToStyle("left", pBorder->GetLeft(),
+ bInsertSemicolon));
+ aStrTD.append(BorderToStyle("right", pBorder->GetRight(),
+ bInsertSemicolon));
+
+ aStrTD.append('"');
+ }
+
+ const char* pChar;
+ sal_uInt16 nHeightPixel;
+
+ const ScMergeAttr& rMergeAttr = pAttr->GetItem( ATTR_MERGE, pCondItemSet );
+ if ( pGraphEntry || rMergeAttr.IsMerged() )
+ {
+ SCCOL nC, jC;
+ SCROW nR;
+ tools::Long v;
+ if ( pGraphEntry )
+ nC = std::max( SCCOL(pGraphEntry->aRange.aEnd.Col() - nCol + 1),
+ rMergeAttr.GetColMerge() );
+ else
+ nC = rMergeAttr.GetColMerge();
+ if ( nC > 1 )
+ {
+ aStrTD.append(' ').append(OOO_STRING_SVTOOLS_HTML_O_colspan).
+ append('=').append(static_cast<sal_Int32>(nC));
+ nC = nC + nCol;
+ for ( jC=nCol, v=0; jC<nC; jC++ )
+ v += pDoc->GetColWidth( jC, nTab );
+ }
+
+ if ( pGraphEntry )
+ nR = std::max( SCROW(pGraphEntry->aRange.aEnd.Row() - nRow + 1),
+ rMergeAttr.GetRowMerge() );
+ else
+ nR = rMergeAttr.GetRowMerge();
+ if ( nR > 1 )
+ {
+ aStrTD.append(' ').append(OOO_STRING_SVTOOLS_HTML_O_rowspan).
+ append('=').append(static_cast<sal_Int32>(nR));
+ nR += nRow;
+ v = pDoc->GetRowHeight( nRow, nR-1, nTab );
+ nHeightPixel = ToPixel( static_cast< sal_uInt16 >( v ) );
+ }
+ else
+ nHeightPixel = ToPixel( pDoc->GetRowHeight( nRow, nTab ) );
+ }
+ else
+ nHeightPixel = ToPixel( pDoc->GetRowHeight( nRow, nTab ) );
+
+ if ( bTableDataHeight )
+ {
+ aStrTD.append(" " OOO_STRING_SVTOOLS_HTML_O_height "=\"" +
+ OString::number(nHeightPixel) + "\"");
+ }
+
+ const SvxFontItem& rFontItem = static_cast<const SvxFontItem&>( pAttr->GetItem(
+ ScGlobal::GetScriptedWhichID( nScriptType, ATTR_FONT),
+ pCondItemSet) );
+
+ const SvxFontHeightItem& rFontHeightItem = static_cast<const SvxFontHeightItem&>(
+ pAttr->GetItem( ScGlobal::GetScriptedWhichID( nScriptType,
+ ATTR_FONT_HEIGHT), pCondItemSet) );
+
+ const SvxWeightItem& rWeightItem = static_cast<const SvxWeightItem&>( pAttr->GetItem(
+ ScGlobal::GetScriptedWhichID( nScriptType, ATTR_FONT_WEIGHT),
+ pCondItemSet) );
+
+ const SvxPostureItem& rPostureItem = static_cast<const SvxPostureItem&>(
+ pAttr->GetItem( ScGlobal::GetScriptedWhichID( nScriptType,
+ ATTR_FONT_POSTURE), pCondItemSet) );
+
+ const SvxUnderlineItem& rUnderlineItem =
+ pAttr->GetItem( ATTR_FONT_UNDERLINE, pCondItemSet );
+
+ const SvxCrossedOutItem& rCrossedOutItem =
+ pAttr->GetItem( ATTR_FONT_CROSSEDOUT, pCondItemSet );
+
+ const SvxColorItem& rColorItem = pAttr->GetItem(
+ ATTR_FONT_COLOR, pCondItemSet );
+
+ const SvxHorJustifyItem& rHorJustifyItem =
+ pAttr->GetItem( ATTR_HOR_JUSTIFY, pCondItemSet );
+
+ const SvxVerJustifyItem& rVerJustifyItem =
+ pAttr->GetItem( ATTR_VER_JUSTIFY, pCondItemSet );
+
+ const SvxBrushItem& rBrushItem = pAttr->GetItem(
+ ATTR_BACKGROUND, pCondItemSet );
+
+ Color aBgColor;
+ if ( rBrushItem.GetColor().GetAlpha() == 0 )
+ aBgColor = aHTMLStyle.aBackgroundColor; // No unwanted background color
+ else
+ aBgColor = rBrushItem.GetColor();
+
+ bool bBold = ( WEIGHT_BOLD <= rWeightItem.GetWeight() );
+ bool bItalic = ( ITALIC_NONE != rPostureItem.GetPosture() );
+ bool bUnderline = ( LINESTYLE_NONE != rUnderlineItem.GetLineStyle() );
+ bool bCrossedOut = ( STRIKEOUT_SINGLE <= rCrossedOutItem.GetStrikeout() );
+ bool bSetFontColor = ( COL_AUTO != rColorItem.GetValue() ); // default is AUTO now
+ bool bSetFontName = ( aHTMLStyle.aFontFamilyName != rFontItem.GetFamilyName() );
+ sal_uInt16 nSetFontSizeNumber = 0;
+ sal_uInt32 nFontHeight = rFontHeightItem.GetHeight();
+ if ( nFontHeight != aHTMLStyle.nFontHeight )
+ {
+ nSetFontSizeNumber = GetFontSizeNumber( static_cast<sal_uInt16>(nFontHeight) );
+ if ( nSetFontSizeNumber == aHTMLStyle.nFontSizeNumber )
+ nSetFontSizeNumber = 0; // no difference, don't set
+ }
+
+ bool bSetFont = (bSetFontColor || bSetFontName || nSetFontSizeNumber);
+
+ //! TODO: we could entirely use CSS1 here instead, but that would exclude
+ //! Netscape 3.0 and Netscape 4.x without JavaScript enabled.
+ //! Do we want that?
+
+ switch( rHorJustifyItem.GetValue() )
+ {
+ case SvxCellHorJustify::Standard:
+ pChar = (bValueData ? OOO_STRING_SVTOOLS_HTML_AL_right : OOO_STRING_SVTOOLS_HTML_AL_left);
+ break;
+ case SvxCellHorJustify::Center: pChar = OOO_STRING_SVTOOLS_HTML_AL_center; break;
+ case SvxCellHorJustify::Block: pChar = OOO_STRING_SVTOOLS_HTML_AL_justify; break;
+ case SvxCellHorJustify::Right: pChar = OOO_STRING_SVTOOLS_HTML_AL_right; break;
+ case SvxCellHorJustify::Left:
+ case SvxCellHorJustify::Repeat:
+ default: pChar = OOO_STRING_SVTOOLS_HTML_AL_left; break;
+ }
+
+ aStrTD.append(" " OOO_STRING_SVTOOLS_HTML_O_align "=\"" +
+ OString::Concat(pChar) + "\"");
+
+ switch( rVerJustifyItem.GetValue() )
+ {
+ case SvxCellVerJustify::Top: pChar = OOO_STRING_SVTOOLS_HTML_VA_top; break;
+ case SvxCellVerJustify::Center: pChar = OOO_STRING_SVTOOLS_HTML_VA_middle; break;
+ case SvxCellVerJustify::Bottom: pChar = OOO_STRING_SVTOOLS_HTML_VA_bottom; break;
+ case SvxCellVerJustify::Standard:
+ default: pChar = nullptr;
+ }
+ if ( pChar )
+ {
+ aStrTD.append(' ').append(OOO_STRING_SVTOOLS_HTML_O_valign).
+ append('=').append(pChar);
+ }
+
+ if ( aHTMLStyle.aBackgroundColor != aBgColor )
+ {
+ aStrTD.append(' ').append(OOO_STRING_SVTOOLS_HTML_O_bgcolor).
+ append('=');
+ aStrTD.append(lcl_makeHTMLColorTriplet(aBgColor));
+ }
+
+ double fVal = 0.0;
+ if ( bValueData )
+ {
+ switch (aCell.meType)
+ {
+ case CELLTYPE_VALUE:
+ fVal = aCell.mfValue;
+ if ( bCalcAsShown && fVal != 0.0 )
+ fVal = pDoc->RoundValueAsShown( fVal, nFormat );
+ break;
+ case CELLTYPE_FORMULA:
+ fVal = aCell.mpFormula->GetValue();
+ break;
+ default:
+ OSL_FAIL( "value data with unsupported cell type" );
+ }
+ }
+
+ aStrTD.append(HTMLOutFuncs::CreateTableDataOptionsValNum(bValueData, fVal,
+ nFormat, *pFormatter, &aNonConvertibleChars));
+
+ TAG_ON(aStrTD.makeStringAndClear().getStr());
+
+ //write the note for this as the first thing in the tag
+ ScPostIt* pNote = pDoc->HasNote(aPos) ? pDoc->GetNote(aPos) : nullptr;
+ if (pNote)
+ {
+ //create the comment indicator
+ OString aStr = OOO_STRING_SVTOOLS_HTML_anchor " "
+ OOO_STRING_SVTOOLS_HTML_O_class "=\"comment-indicator\"";
+ TAG_ON(aStr.getStr());
+ TAG_OFF(OOO_STRING_SVTOOLS_HTML_anchor);
+ OUT_LF();
+
+ //create the element holding the contents
+ //this is a bit naive, since it doesn't separate
+ //lines into html breaklines yet
+ TAG_ON(OOO_STRING_SVTOOLS_HTML_comment2);
+ OUT_STR( pNote->GetText() );
+ TAG_OFF(OOO_STRING_SVTOOLS_HTML_comment2);
+ OUT_LF();
+ }
+
+ if ( bBold ) TAG_ON( OOO_STRING_SVTOOLS_HTML_bold );
+ if ( bItalic ) TAG_ON( OOO_STRING_SVTOOLS_HTML_italic );
+ if ( bUnderline ) TAG_ON( OOO_STRING_SVTOOLS_HTML_underline );
+ if ( bCrossedOut ) TAG_ON( OOO_STRING_SVTOOLS_HTML_strikethrough );
+
+ if ( bSetFont )
+ {
+ OStringBuffer aStr(OOO_STRING_SVTOOLS_HTML_font);
+ if ( bSetFontName )
+ {
+ aStr.append(" " OOO_STRING_SVTOOLS_HTML_O_face "=\"");
+
+ if (!rFontItem.GetFamilyName().isEmpty())
+ {
+ const OUString& rList = rFontItem.GetFamilyName();
+ for (sal_Int32 nPos {0};;)
+ {
+ OString aTmpStr = HTMLOutFuncs::ConvertStringToHTML(
+ rList.getToken( 0, ';', nPos ),
+ &aNonConvertibleChars);
+ aStr.append(aTmpStr);
+ if (nPos<0)
+ break;
+ aStr.append(',');
+ }
+ }
+
+ aStr.append('\"');
+ }
+ if ( nSetFontSizeNumber )
+ {
+ aStr.append(' ').append(OOO_STRING_SVTOOLS_HTML_O_size).
+ append('=').append(static_cast<sal_Int32>(nSetFontSizeNumber));
+ }
+ if ( bSetFontColor )
+ {
+ Color aColor = rColorItem.GetValue();
+
+ // always export automatic text color as black
+ if ( aColor == COL_AUTO )
+ aColor = COL_BLACK;
+
+ aStr.append(' ').append(OOO_STRING_SVTOOLS_HTML_O_color).
+ append('=').append(lcl_makeHTMLColorTriplet(aColor));
+ }
+ TAG_ON(aStr.makeStringAndClear().getStr());
+ }
+
+ OUString aURL;
+ bool bWriteHyperLink(false);
+ if (aCell.meType == CELLTYPE_FORMULA)
+ {
+ ScFormulaCell* pFCell = aCell.mpFormula;
+ if (pFCell->IsHyperLinkCell())
+ {
+ OUString aCellText;
+ pFCell->GetURLResult(aURL, aCellText);
+ bWriteHyperLink = true;
+ }
+ }
+
+ if (bWriteHyperLink)
+ {
+ OString aURLStr = HTMLOutFuncs::ConvertStringToHTML(aURL, &aNonConvertibleChars);
+ OString aStr = OOO_STRING_SVTOOLS_HTML_anchor " " OOO_STRING_SVTOOLS_HTML_O_href "=\"" + aURLStr + "\"";
+ TAG_ON(aStr.getStr());
+ }
+
+ OUString aStrOut;
+ bool bFieldText = false;
+
+ const Color* pColor;
+ switch (aCell.meType)
+ {
+ case CELLTYPE_EDIT :
+ bFieldText = WriteFieldText(aCell.mpEditText);
+ if ( bFieldText )
+ break;
+ [[fallthrough]];
+ default:
+ aStrOut = ScCellFormat::GetString(aCell, nFormat, &pColor, *pFormatter, *pDoc);
+ }
+
+ if ( !bFieldText )
+ {
+ if ( aStrOut.isEmpty() )
+ {
+ TAG_ON( OOO_STRING_SVTOOLS_HTML_linebreak ); // No completely empty line
+ }
+ else
+ {
+ sal_Int32 nPos = aStrOut.indexOf( '\n' );
+ if ( nPos == -1 )
+ {
+ OUT_STR( aStrOut );
+ }
+ else
+ {
+ sal_Int32 nStartPos = 0;
+ do
+ {
+ OUString aSingleLine = aStrOut.copy( nStartPos, nPos - nStartPos );
+ OUT_STR( aSingleLine );
+ TAG_ON( OOO_STRING_SVTOOLS_HTML_linebreak );
+ nStartPos = nPos + 1;
+ }
+ while( ( nPos = aStrOut.indexOf( '\n', nStartPos ) ) != -1 );
+ OUString aSingleLine = aStrOut.copy( nStartPos );
+ OUT_STR( aSingleLine );
+ }
+ }
+ }
+ if ( pGraphEntry )
+ WriteGraphEntry( pGraphEntry );
+
+ if (bWriteHyperLink) { TAG_OFF(OOO_STRING_SVTOOLS_HTML_anchor); }
+
+ if ( bSetFont ) TAG_OFF( OOO_STRING_SVTOOLS_HTML_font );
+ if ( bCrossedOut ) TAG_OFF( OOO_STRING_SVTOOLS_HTML_strikethrough );
+ if ( bUnderline ) TAG_OFF( OOO_STRING_SVTOOLS_HTML_underline );
+ if ( bItalic ) TAG_OFF( OOO_STRING_SVTOOLS_HTML_italic );
+ if ( bBold ) TAG_OFF( OOO_STRING_SVTOOLS_HTML_bold );
+
+ TAG_OFF_LF( OOO_STRING_SVTOOLS_HTML_tabledata );
+}
+
+bool ScHTMLExport::WriteFieldText( const EditTextObject* pData )
+{
+ bool bFields = false;
+ // text and anchor of URL fields, Doc-Engine is a ScFieldEditEngine
+ EditEngine& rEngine = pDoc->GetEditEngine();
+ rEngine.SetText( *pData );
+ sal_Int32 nParas = rEngine.GetParagraphCount();
+ if ( nParas )
+ {
+ ESelection aSel( 0, 0, nParas-1, rEngine.GetTextLen( nParas-1 ) );
+ SfxItemSet aSet( rEngine.GetAttribs( aSel ) );
+ SfxItemState eFieldState = aSet.GetItemState( EE_FEATURE_FIELD, false );
+ if ( eFieldState == SfxItemState::DONTCARE || eFieldState == SfxItemState::SET )
+ bFields = true;
+ }
+ if ( bFields )
+ {
+ bool bOldUpdateMode = rEngine.SetUpdateLayout( true ); // no portions if not formatted
+ for ( sal_Int32 nPar=0; nPar < nParas; nPar++ )
+ {
+ if ( nPar > 0 )
+ TAG_ON( OOO_STRING_SVTOOLS_HTML_linebreak );
+ std::vector<sal_Int32> aPortions;
+ rEngine.GetPortions( nPar, aPortions );
+ sal_Int32 nStart = 0;
+ for ( const sal_Int32 nEnd : aPortions )
+ {
+ ESelection aSel( nPar, nStart, nPar, nEnd );
+ bool bUrl = false;
+ // fields are single characters
+ if ( nEnd == nStart+1 )
+ {
+ SfxItemSet aSet = rEngine.GetAttribs( aSel );
+ if ( const SvxFieldItem* pFieldItem = aSet.GetItemIfSet( EE_FEATURE_FIELD, false ) )
+ {
+ const SvxFieldData* pField = pFieldItem->GetField();
+ if (const SvxURLField* pURLField = dynamic_cast<const SvxURLField*>(pField))
+ {
+ bUrl = true;
+ rStrm.WriteChar( '<' ).WriteCharPtr( OOO_STRING_SVTOOLS_HTML_anchor ).WriteChar( ' ' ).WriteCharPtr( OOO_STRING_SVTOOLS_HTML_O_href ).WriteCharPtr( "=\"" );
+ OUT_STR( pURLField->GetURL() );
+ rStrm.WriteCharPtr( "\">" );
+ OUT_STR( pURLField->GetRepresentation() );
+ rStrm.WriteCharPtr( "</" ).WriteCharPtr( OOO_STRING_SVTOOLS_HTML_anchor ).WriteChar( '>' );
+ }
+ }
+ }
+ if ( !bUrl )
+ OUT_STR( rEngine.GetText( aSel ) );
+ nStart = nEnd;
+ }
+ }
+ rEngine.SetUpdateLayout( bOldUpdateMode );
+ }
+ return bFields;
+}
+
+void ScHTMLExport::CopyLocalFileToINet( OUString& rFileNm,
+ std::u16string_view rTargetNm )
+{
+ INetURLObject aFileUrl, aTargetUrl;
+ aFileUrl.SetSmartURL( rFileNm );
+ aTargetUrl.SetSmartURL( rTargetNm );
+ if( !(INetProtocol::File == aFileUrl.GetProtocol() &&
+ ( INetProtocol::File != aTargetUrl.GetProtocol() &&
+ INetProtocol::Ftp <= aTargetUrl.GetProtocol() &&
+ INetProtocol::Javascript >= aTargetUrl.GetProtocol())) )
+ return;
+
+ if( pFileNameMap )
+ {
+ // Did we already move the file?
+ std::map<OUString, OUString>::iterator it = pFileNameMap->find( rFileNm );
+ if( it != pFileNameMap->end() )
+ {
+ rFileNm = it->second;
+ return;
+ }
+ }
+ else
+ {
+ pFileNameMap.reset( new std::map<OUString, OUString> );
+ }
+
+ bool bRet = false;
+ SvFileStream aTmp( aFileUrl.PathToFileName(), StreamMode::READ );
+
+ OUString aSrc = rFileNm;
+ OUString aDest = aTargetUrl.GetPartBeforeLastName() + aFileUrl.GetLastName();
+
+ SfxMedium aMedium( aDest, StreamMode::WRITE | StreamMode::SHARE_DENYNONE );
+
+ {
+ SvFileStream aCpy( aMedium.GetPhysicalName(), StreamMode::WRITE );
+ aCpy.WriteStream( aTmp );
+ }
+
+ // Take over
+ aMedium.Close();
+ aMedium.Commit();
+
+ bRet = ERRCODE_NONE == aMedium.GetError();
+
+ if( bRet )
+ {
+ pFileNameMap->insert( std::make_pair( aSrc, aDest ) );
+ rFileNm = aDest;
+ }
+}
+
+void ScHTMLExport::IncIndent( short nVal )
+{
+ sIndent[nIndent] = '\t';
+ nIndent = nIndent + nVal;
+ if ( nIndent < 0 )
+ nIndent = 0;
+ else if ( nIndent > nIndentMax )
+ nIndent = nIndentMax;
+ sIndent[nIndent] = 0;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */