LCOV - code coverage report
Current view: top level - sc/source/filter/html - htmlpars.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 446 1680 26.5 %
Date: 2015-06-13 12:38:46 Functions: 85 170 50.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      11             :  *   Licensed to the Apache Software Foundation (ASF) under one or more
      12             :  *   contributor license agreements. See the NOTICE file distributed
      13             :  *   with this work for additional information regarding copyright
      14             :  *   ownership. The ASF licenses this file to you under the Apache
      15             :  *   License, Version 2.0 (the "License"); you may not use this file
      16             :  *   except in compliance with the License. You may obtain a copy of
      17             :  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
      18             :  */
      19             : 
      20             : #include <sal/config.h>
      21             : 
      22             : #include <utility>
      23             : 
      24             : #include <boost/shared_ptr.hpp>
      25             : #include <comphelper/string.hxx>
      26             : #include <o3tl/ptr_container.hxx>
      27             : 
      28             : #include "scitems.hxx"
      29             : #include <editeng/eeitem.hxx>
      30             : 
      31             : #include <svtools/htmlcfg.hxx>
      32             : #include <svx/algitem.hxx>
      33             : #include <editeng/colritem.hxx>
      34             : #include <editeng/brushitem.hxx>
      35             : #include <editeng/editeng.hxx>
      36             : #include <editeng/fhgtitem.hxx>
      37             : #include <editeng/fontitem.hxx>
      38             : #include <editeng/postitem.hxx>
      39             : #include <editeng/udlnitem.hxx>
      40             : #include <editeng/wghtitem.hxx>
      41             : #include <editeng/boxitem.hxx>
      42             : #include <editeng/justifyitem.hxx>
      43             : #include <sfx2/objsh.hxx>
      44             : #include <svl/eitem.hxx>
      45             : #include <svl/intitem.hxx>
      46             : #include <vcl/graphicfilter.hxx>
      47             : #include <svtools/parhtml.hxx>
      48             : #include <svtools/htmlkywd.hxx>
      49             : #include <svtools/htmltokn.h>
      50             : #include <sfx2/docfile.hxx>
      51             : 
      52             : #include <vcl/svapp.hxx>
      53             : #include <tools/urlobj.hxx>
      54             : #include <tools/tenccvt.hxx>
      55             : 
      56             : #include <rtl/tencinfo.h>
      57             : 
      58             : #include "htmlpars.hxx"
      59             : #include "global.hxx"
      60             : #include "document.hxx"
      61             : #include "rangelst.hxx"
      62             : 
      63             : #include <config_orcus.h>
      64             : 
      65             : #if ENABLE_ORCUS
      66             : #include <orcus/css_parser.hpp>
      67             : #endif
      68             : 
      69             : #include <com/sun/star/document/XDocumentProperties.hpp>
      70             : #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
      71             : #include <boost/scoped_array.hpp>
      72             : 
      73             : using ::editeng::SvxBorderLine;
      74             : using namespace ::com::sun::star;
      75             : 
      76           1 : ScHTMLStyles::ScHTMLStyles() : maEmpty() {}
      77             : 
      78           0 : void ScHTMLStyles::add(const char* pElemName, size_t nElemName, const char* pClassName, size_t nClassName,
      79             :                        const OUString& aProp, const OUString& aValue)
      80             : {
      81           0 :     if (pElemName)
      82             :     {
      83           0 :         OUString aElem(pElemName, nElemName, RTL_TEXTENCODING_UTF8);
      84           0 :         aElem = aElem.toAsciiLowerCase();
      85           0 :         if (pClassName)
      86             :         {
      87             :             // Both element and class names given.
      88           0 :             ElemsType::iterator itrElem = maElemProps.find(aElem);
      89           0 :             if (itrElem == maElemProps.end())
      90             :             {
      91             :                 // new element
      92           0 :                 std::unique_ptr<NamePropsType> p(new NamePropsType);
      93           0 :                 std::pair<ElemsType::iterator, bool> r = o3tl::ptr_container::insert(maElemProps, aElem, std::move(p));
      94           0 :                 if (!r.second)
      95             :                     // insertion failed.
      96           0 :                     return;
      97           0 :                 itrElem = r.first;
      98             :             }
      99             : 
     100           0 :             NamePropsType* pClsProps = itrElem->second;
     101           0 :             OUString aClass(pClassName, nClassName, RTL_TEXTENCODING_UTF8);
     102           0 :             aClass = aClass.toAsciiLowerCase();
     103           0 :             insertProp(*pClsProps, aClass, aProp, aValue);
     104             :         }
     105             :         else
     106             :         {
     107             :             // Element name only. Add it to the element global.
     108           0 :             insertProp(maElemGlobalProps, aElem, aProp, aValue);
     109           0 :         }
     110             :     }
     111             :     else
     112             :     {
     113           0 :         if (pClassName)
     114             :         {
     115             :             // Class name only. Add it to the global.
     116           0 :             OUString aClass(pClassName, nClassName, RTL_TEXTENCODING_UTF8);
     117           0 :             aClass = aClass.toAsciiLowerCase();
     118           0 :             insertProp(maGlobalProps, aClass, aProp, aValue);
     119             :         }
     120             :     }
     121             : }
     122             : 
     123           0 : const OUString& ScHTMLStyles::getPropertyValue(
     124             :     const OUString& rElem, const OUString& rClass, const OUString& rPropName) const
     125             : {
     126             :     // First, look into the element-class storage.
     127             :     {
     128           0 :         ElemsType::const_iterator itr = maElemProps.find(rElem);
     129           0 :         if (itr != maElemProps.end())
     130             :         {
     131           0 :             const NamePropsType* pClasses = itr->second;
     132           0 :             NamePropsType::const_iterator itr2 = pClasses->find(rClass);
     133           0 :             if (itr2 != pClasses->end())
     134             :             {
     135           0 :                 const PropsType* pProps = itr2->second;
     136           0 :                 PropsType::const_iterator itr3 = pProps->find(rPropName);
     137           0 :                 if (itr3 != pProps->end())
     138           0 :                     return itr3->second;
     139             :             }
     140             :         }
     141             :     }
     142             :     // Next, look into the class global storage.
     143             :     {
     144           0 :         NamePropsType::const_iterator itr = maGlobalProps.find(rClass);
     145           0 :         if (itr != maGlobalProps.end())
     146             :         {
     147           0 :             const PropsType* pProps = itr->second;
     148           0 :             PropsType::const_iterator itr2 = pProps->find(rPropName);
     149           0 :             if (itr2 != pProps->end())
     150           0 :                 return itr2->second;
     151             :         }
     152             :     }
     153             :     // As the last resort, look into the element global storage.
     154             :     {
     155           0 :         NamePropsType::const_iterator itr = maElemGlobalProps.find(rClass);
     156           0 :         if (itr != maElemGlobalProps.end())
     157             :         {
     158           0 :             const PropsType* pProps = itr->second;
     159           0 :             PropsType::const_iterator itr2 = pProps->find(rPropName);
     160           0 :             if (itr2 != pProps->end())
     161           0 :                 return itr2->second;
     162             :         }
     163             :     }
     164             : 
     165           0 :     return maEmpty; // nothing found.
     166             : }
     167             : 
     168           0 : void ScHTMLStyles::insertProp(
     169             :     NamePropsType& rStore, const OUString& aName,
     170             :     const OUString& aProp, const OUString& aValue)
     171             : {
     172           0 :     NamePropsType::iterator itr = rStore.find(aName);
     173           0 :     if (itr == rStore.end())
     174             :     {
     175             :         // new element
     176           0 :         std::unique_ptr<PropsType> p(new PropsType);
     177           0 :         std::pair<NamePropsType::iterator, bool> r = o3tl::ptr_container::insert(rStore, aName, std::move(p));
     178           0 :         if (!r.second)
     179             :             // insertion failed.
     180           0 :             return;
     181             : 
     182           0 :         itr = r.first;
     183             :     }
     184             : 
     185           0 :     PropsType* pProps = itr->second;
     186           0 :     pProps->insert(PropsType::value_type(aProp, aValue));
     187             : }
     188             : 
     189             : // BASE class for HTML parser classes
     190             : 
     191           1 : ScHTMLParser::ScHTMLParser( EditEngine* pEditEngine, ScDocument* pDoc ) :
     192             :     ScEEParser( pEditEngine ),
     193           1 :     mpDoc( pDoc )
     194             : {
     195           1 :     SvxHtmlOptions& rHtmlOptions = SvxHtmlOptions::Get();
     196           8 :     for( sal_uInt16 nIndex = 0; nIndex < SC_HTML_FONTSIZES; ++nIndex )
     197           7 :         maFontHeights[ nIndex ] = rHtmlOptions.GetFontSize( nIndex ) * 20;
     198           1 : }
     199             : 
     200           1 : ScHTMLParser::~ScHTMLParser()
     201             : {
     202           1 : }
     203             : 
     204           0 : ScHTMLLayoutParser::ScHTMLLayoutParser(
     205             :     EditEngine* pEditP, const OUString& rBaseURL, const Size& aPageSizeP,
     206             :     ScDocument* pDocP ) :
     207             :         ScHTMLParser( pEditP, pDocP ),
     208             :         aPageSize( aPageSizeP ),
     209             :         aBaseURL( rBaseURL ),
     210           0 :         xLockedList( new ScRangeList ),
     211             :         pTables( NULL ),
     212           0 :         pColOffset( new ScHTMLColOffset ),
     213           0 :         pLocalColOffset( new ScHTMLColOffset ),
     214             :         nFirstTableCell(0),
     215             :         nTableLevel(0),
     216             :         nTable(0),
     217             :         nMaxTable(0),
     218             :         nColCntStart(0),
     219             :         nMaxCol(0),
     220             :         nTableWidth(0),
     221             :         nColOffset(0),
     222             :         nColOffsetStart(0),
     223             :         nOffsetTolerance( SC_HTML_OFFSET_TOLERANCE_SMALL ),
     224             :         bTabInTabCell( false ),
     225             :         bFirstRow( true ),
     226             :         bInCell( false ),
     227           0 :         bInTitle( false )
     228             : {
     229           0 :     MakeColNoRef( pLocalColOffset, 0, 0, 0, 0 );
     230           0 :     MakeColNoRef( pColOffset, 0, 0, 0, 0 );
     231           0 : }
     232             : 
     233           0 : ScHTMLLayoutParser::~ScHTMLLayoutParser()
     234             : {
     235           0 :     while ( !aTableStack.empty() )
     236             :     {
     237           0 :         ScHTMLTableStackEntry* pS = aTableStack.top();
     238           0 :         aTableStack.pop();
     239             : 
     240           0 :         bool found = false;
     241           0 :         for ( size_t i = 0, nListSize = maList.size(); i < nListSize; ++i )
     242             :         {
     243           0 :             if ( pS->pCellEntry == maList[ i ] )
     244             :             {
     245           0 :                 found = true;
     246           0 :                 break;
     247             :             }
     248             :         }
     249           0 :         if ( !found )
     250           0 :             delete pS->pCellEntry;
     251           0 :         if ( pS->pLocalColOffset != pLocalColOffset )
     252           0 :             delete pS->pLocalColOffset;
     253           0 :         delete pS;
     254             :     }
     255           0 :     delete pLocalColOffset;
     256           0 :     delete pColOffset;
     257           0 :     if ( pTables )
     258             :     {
     259           0 :         for( OuterMap::const_iterator it = pTables->begin(); it != pTables->end(); ++it)
     260           0 :             delete it->second;
     261           0 :         delete pTables;
     262             :     }
     263           0 : }
     264             : 
     265           0 : sal_uLong ScHTMLLayoutParser::Read( SvStream& rStream, const OUString& rBaseURL )
     266             : {
     267           0 :     Link<> aOldLink = pEdit->GetImportHdl();
     268           0 :     pEdit->SetImportHdl( LINK( this, ScHTMLLayoutParser, HTMLImportHdl ) );
     269             : 
     270           0 :     SfxObjectShell* pObjSh = mpDoc->GetDocumentShell();
     271           0 :     bool bLoading = pObjSh && pObjSh->IsLoading();
     272             : 
     273           0 :     SvKeyValueIteratorRef xValues;
     274           0 :     SvKeyValueIterator* pAttributes = NULL;
     275           0 :     if ( bLoading )
     276           0 :         pAttributes = pObjSh->GetHeaderAttributes();
     277             :     else
     278             :     {
     279             :         // When not loading, set up fake http headers to force the SfxHTMLParser to use UTF8
     280             :         // (used when pasting from clipboard)
     281           0 :         const sal_Char* pCharSet = rtl_getBestMimeCharsetFromTextEncoding( RTL_TEXTENCODING_UTF8 );
     282           0 :         if( pCharSet )
     283             :         {
     284           0 :             OUString aContentType = "text/html; charset=";
     285           0 :             aContentType += OUString::createFromAscii( pCharSet );
     286             : 
     287           0 :             xValues = new SvKeyValueIterator;
     288           0 :             xValues->Append( SvKeyValue( OUString( OOO_STRING_SVTOOLS_HTML_META_content_type ), aContentType ) );
     289           0 :             pAttributes = xValues;
     290             :         }
     291             :     }
     292             : 
     293           0 :     sal_uLong nErr = pEdit->Read( rStream, rBaseURL, EE_FORMAT_HTML, pAttributes );
     294             : 
     295           0 :     pEdit->SetImportHdl( aOldLink );
     296             :     // Create column width
     297           0 :     Adjust();
     298           0 :     OutputDevice* pDefaultDev = Application::GetDefaultDevice();
     299           0 :     sal_uInt16 nCount = pColOffset->size();
     300           0 :     sal_uLong nOff = (*pColOffset)[0];
     301           0 :     Size aSize;
     302           0 :     for ( sal_uInt16 j = 1; j < nCount; j++ )
     303             :     {
     304           0 :         aSize.Width() = (*pColOffset)[j] - nOff;
     305           0 :         aSize = pDefaultDev->PixelToLogic( aSize, MapMode( MAP_TWIP ) );
     306           0 :         maColWidths[ j-1 ] = aSize.Width();
     307           0 :         nOff = (*pColOffset)[j];
     308             :     }
     309           0 :     return nErr;
     310             : }
     311             : 
     312           0 : const ScHTMLTable* ScHTMLLayoutParser::GetGlobalTable() const
     313             : {
     314           0 :     return 0;
     315             : }
     316             : 
     317           0 : void ScHTMLLayoutParser::NewActEntry( ScEEParseEntry* pE )
     318             : {
     319           0 :     ScEEParser::NewActEntry( pE );
     320           0 :     if ( pE )
     321             :     {
     322           0 :         if ( !pE->aSel.HasRange() )
     323             :         {   // Completely empty, following text ends up in the same paragraph!
     324           0 :             pActEntry->aSel.nStartPara = pE->aSel.nEndPara;
     325           0 :             pActEntry->aSel.nStartPos = pE->aSel.nEndPos;
     326             :         }
     327             :     }
     328           0 :     pActEntry->aSel.nEndPara = pActEntry->aSel.nStartPara;
     329           0 :     pActEntry->aSel.nEndPos = pActEntry->aSel.nStartPos;
     330           0 : }
     331             : 
     332           0 : void ScHTMLLayoutParser::EntryEnd( ScEEParseEntry* pE, const ESelection& rSel )
     333             : {
     334           0 :     if ( rSel.nEndPara >= pE->aSel.nStartPara )
     335             :     {
     336           0 :         pE->aSel.nEndPara = rSel.nEndPara;
     337           0 :         pE->aSel.nEndPos = rSel.nEndPos;
     338             :     }
     339           0 :     else if ( rSel.nStartPara == pE->aSel.nStartPara - 1 && !pE->aSel.HasRange() )
     340             :     {   // Did not attach a paragraph, but empty, do nothing
     341             :     }
     342             :     else
     343             :     {
     344             :         OSL_FAIL( "EntryEnd: EditEngine ESelection End < Start" );
     345             :     }
     346           0 : }
     347             : 
     348           0 : void ScHTMLLayoutParser::NextRow( ImportInfo* pInfo )
     349             : {
     350           0 :     if ( bInCell )
     351           0 :         CloseEntry( pInfo );
     352           0 :     if ( nRowMax < ++nRowCnt )
     353           0 :         nRowMax = nRowCnt;
     354           0 :     nColCnt = nColCntStart;
     355           0 :     nColOffset = nColOffsetStart;
     356           0 :     bFirstRow = false;
     357           0 : }
     358             : 
     359           0 : bool ScHTMLLayoutParser::SeekOffset( ScHTMLColOffset* pOffset, sal_uInt16 nOffset,
     360             :         SCCOL* pCol, sal_uInt16 nOffsetTol )
     361             : {
     362             :     OSL_ENSURE( pOffset, "ScHTMLLayoutParser::SeekOffset - illegal call" );
     363           0 :     ScHTMLColOffset::const_iterator it = pOffset->find( nOffset );
     364           0 :     bool bFound = it != pOffset->end();
     365           0 :     sal_uInt16 nPos = it - pOffset->begin();
     366           0 :     *pCol = static_cast<SCCOL>(nPos);
     367           0 :     if ( bFound )
     368           0 :         return true;
     369           0 :     sal_uInt16 nCount = pOffset->size();
     370           0 :     if ( !nCount )
     371           0 :         return false;
     372             :     // nPos is the position of insertion, that's where the next higher one is (or isn't)
     373           0 :     if ( nPos < nCount && (((*pOffset)[nPos] - nOffsetTol) <= nOffset) )
     374           0 :         return true;
     375             :     // Not smaller than everything else? Then compare with the next lower one
     376           0 :     else if ( nPos && (((*pOffset)[nPos-1] + nOffsetTol) >= nOffset) )
     377             :     {
     378           0 :         (*pCol)--;
     379           0 :         return true;
     380             :     }
     381           0 :     return false;
     382             : }
     383             : 
     384           0 : void ScHTMLLayoutParser::MakeCol( ScHTMLColOffset* pOffset, sal_uInt16& nOffset,
     385             :         sal_uInt16& nWidth, sal_uInt16 nOffsetTol, sal_uInt16 nWidthTol )
     386             : {
     387             :     OSL_ENSURE( pOffset, "ScHTMLLayoutParser::MakeCol - illegal call" );
     388             :     SCCOL nPos;
     389           0 :     if ( SeekOffset( pOffset, nOffset, &nPos, nOffsetTol ) )
     390           0 :         nOffset = (sal_uInt16)(*pOffset)[nPos];
     391             :     else
     392           0 :         pOffset->insert( nOffset );
     393           0 :     if ( nWidth )
     394             :     {
     395           0 :         if ( SeekOffset( pOffset, nOffset + nWidth, &nPos, nWidthTol ) )
     396           0 :             nWidth = (sal_uInt16)(*pOffset)[nPos] - nOffset;
     397             :         else
     398           0 :             pOffset->insert( nOffset + nWidth );
     399             :     }
     400           0 : }
     401             : 
     402           0 : void ScHTMLLayoutParser::MakeColNoRef( ScHTMLColOffset* pOffset, sal_uInt16 nOffset,
     403             :         sal_uInt16 nWidth, sal_uInt16 nOffsetTol, sal_uInt16 nWidthTol )
     404             : {
     405             :     OSL_ENSURE( pOffset, "ScHTMLLayoutParser::MakeColNoRef - illegal call" );
     406             :     SCCOL nPos;
     407           0 :     if ( SeekOffset( pOffset, nOffset, &nPos, nOffsetTol ) )
     408           0 :         nOffset = (sal_uInt16)(*pOffset)[nPos];
     409             :     else
     410           0 :         pOffset->insert( nOffset );
     411           0 :     if ( nWidth )
     412             :     {
     413           0 :         if ( !SeekOffset( pOffset, nOffset + nWidth, &nPos, nWidthTol ) )
     414           0 :             pOffset->insert( nOffset + nWidth );
     415             :     }
     416           0 : }
     417             : 
     418           0 : void ScHTMLLayoutParser::ModifyOffset( ScHTMLColOffset* pOffset, sal_uInt16& nOldOffset,
     419             :             sal_uInt16& nNewOffset, sal_uInt16 nOffsetTol )
     420             : {
     421             :     OSL_ENSURE( pOffset, "ScHTMLLayoutParser::ModifyOffset - illegal call" );
     422             :     SCCOL nPos;
     423           0 :     if ( !SeekOffset( pOffset, nOldOffset, &nPos, nOffsetTol ) )
     424             :     {
     425           0 :         if ( SeekOffset( pOffset, nNewOffset, &nPos, nOffsetTol ) )
     426           0 :             nNewOffset = (sal_uInt16)(*pOffset)[nPos];
     427             :         else
     428           0 :             pOffset->insert( nNewOffset );
     429           0 :         return ;
     430             :     }
     431           0 :     nOldOffset = (sal_uInt16)(*pOffset)[nPos];
     432             :     SCCOL nPos2;
     433           0 :     if ( SeekOffset( pOffset, nNewOffset, &nPos2, nOffsetTol ) )
     434             :     {
     435           0 :         nNewOffset = (sal_uInt16)(*pOffset)[nPos2];
     436           0 :         return ;
     437             :     }
     438           0 :     long nDiff = nNewOffset - nOldOffset;
     439           0 :     if ( nDiff < 0 )
     440             :     {
     441           0 :         do
     442             :         {
     443           0 :             const_cast<sal_uLong&>((*pOffset)[nPos]) += nDiff;
     444             :         } while ( nPos-- );
     445             :     }
     446             :     else
     447             :     {
     448           0 :         do
     449             :         {
     450           0 :             const_cast<sal_uLong&>((*pOffset)[nPos]) += nDiff;
     451           0 :         } while ( ++nPos < (sal_uInt16)pOffset->size() );
     452             :     }
     453             : }
     454             : 
     455           0 : void ScHTMLLayoutParser::SkipLocked( ScEEParseEntry* pE, bool bJoin )
     456             : {
     457           0 :     if ( ValidCol(pE->nCol) )
     458             :     {   // Or else this would create a wrong value at ScAddress (chance for an infinite loop)!
     459           0 :         bool bBadCol = false;
     460             :         bool bAgain;
     461             :         ScRange aRange( pE->nCol, pE->nRow, 0,
     462           0 :             pE->nCol + pE->nColOverlap - 1, pE->nRow + pE->nRowOverlap - 1, 0 );
     463           0 :         do
     464             :         {
     465           0 :             bAgain = false;
     466           0 :             for ( size_t i =  0, nRanges = xLockedList->size(); i < nRanges; ++i )
     467             :             {
     468           0 :                 ScRange* pR = (*xLockedList)[i];
     469           0 :                 if ( pR->Intersects( aRange ) )
     470             :                 {
     471           0 :                     pE->nCol = pR->aEnd.Col() + 1;
     472           0 :                     SCCOL nTmp = pE->nCol + pE->nColOverlap - 1;
     473           0 :                     if ( pE->nCol > MAXCOL || nTmp > MAXCOL )
     474           0 :                         bBadCol = true;
     475             :                     else
     476             :                     {
     477           0 :                         bAgain = true;
     478           0 :                         aRange.aStart.SetCol( pE->nCol );
     479           0 :                         aRange.aEnd.SetCol( nTmp );
     480             :                     }
     481           0 :                     break;
     482             :                 }
     483             :             }
     484             :         } while ( bAgain );
     485           0 :         if ( bJoin && !bBadCol )
     486           0 :             xLockedList->Join( aRange );
     487             :     }
     488           0 : }
     489             : 
     490           0 : void ScHTMLLayoutParser::Adjust()
     491             : {
     492           0 :     xLockedList->RemoveAll();
     493             : 
     494           0 :     ScHTMLAdjustStack aStack;
     495           0 :     ScHTMLAdjustStackEntry* pS = NULL;
     496           0 :     sal_uInt16 nTab = 0;
     497           0 :     SCCOL nLastCol = SCCOL_MAX;
     498           0 :     SCROW nNextRow = 0;
     499           0 :     SCROW nCurRow = 0;
     500           0 :     sal_uInt16 nPageWidth = (sal_uInt16) aPageSize.Width();
     501           0 :     InnerMap* pTab = NULL;
     502           0 :     for ( size_t i = 0, nListSize = maList.size(); i < nListSize; ++i )
     503             :     {
     504           0 :         ScEEParseEntry* pE = maList[ i ];
     505           0 :         if ( pE->nTab < nTab )
     506             :         {   // Table finished
     507           0 :             if ( !aStack.empty() )
     508             :             {
     509           0 :                 pS = aStack.top();
     510           0 :                 aStack.pop();
     511             : 
     512           0 :                 nLastCol = pS->nLastCol;
     513           0 :                 nNextRow = pS->nNextRow;
     514           0 :                 nCurRow = pS->nCurRow;
     515             :             }
     516           0 :             delete pS;
     517           0 :             pS = NULL;
     518           0 :             nTab = pE->nTab;
     519           0 :             if (pTables)
     520             :             {
     521           0 :                 OuterMap::const_iterator it = pTables->find( nTab );
     522           0 :                 if ( it != pTables->end() )
     523           0 :                     pTab = it->second;
     524             :             }
     525             : 
     526             :         }
     527           0 :         SCROW nRow = pE->nRow;
     528           0 :         if ( pE->nCol <= nLastCol )
     529             :         {   // Next row
     530           0 :             if ( pE->nRow < nNextRow )
     531           0 :                 pE->nRow = nCurRow = nNextRow;
     532             :             else
     533           0 :                 nCurRow = nNextRow = pE->nRow;
     534           0 :             SCROW nR = 0;
     535           0 :             if ( pTab )
     536             :             {
     537           0 :                 InnerMap::const_iterator it = pTab->find( nCurRow );
     538           0 :                 if ( it != pTab->end() )
     539           0 :                     nR = it->second;
     540             :             }
     541           0 :             if ( nR )
     542           0 :                 nNextRow += nR;
     543             :             else
     544           0 :                 nNextRow++;
     545             :         }
     546             :         else
     547           0 :             pE->nRow = nCurRow;
     548           0 :         nLastCol = pE->nCol; // Read column
     549           0 :         if ( pE->nTab > nTab )
     550             :         {   // New table
     551             :             aStack.push( new ScHTMLAdjustStackEntry(
     552           0 :                 nLastCol, nNextRow, nCurRow ) );
     553           0 :             nTab = pE->nTab;
     554           0 :             if ( pTables )
     555             :             {
     556           0 :                 OuterMap::const_iterator it = pTables->find( nTab );
     557           0 :                 if ( it != pTables->end() )
     558           0 :                     pTab = it->second;
     559             :             }
     560             :             // New line spacing
     561           0 :             SCROW nR = 0;
     562           0 :             if ( pTab )
     563             :             {
     564           0 :                 InnerMap::const_iterator it = pTab->find( nCurRow );
     565           0 :                 if ( it != pTab->end() )
     566           0 :                     nR = it->second;
     567             :             }
     568           0 :             if ( nR )
     569           0 :                 nNextRow = nCurRow + nR;
     570             :             else
     571           0 :                 nNextRow = nCurRow + 1;
     572             :         }
     573           0 :         if ( nTab == 0 )
     574           0 :             pE->nWidth = nPageWidth;
     575             :         else
     576             :         {   // Real table, no paragraphs on the field
     577           0 :             if ( pTab )
     578             :             {
     579           0 :                 SCROW nRowSpan = pE->nRowOverlap;
     580           0 :                 for ( SCROW j=0; j < nRowSpan; j++ )
     581             :                 {   // RowSpan resulting from merged rows
     582           0 :                     SCROW nRows = 0;
     583           0 :                     InnerMap::const_iterator it = pTab->find( nRow+j );
     584           0 :                     if ( it != pTab->end() )
     585           0 :                         nRows = it->second;
     586           0 :                     if ( nRows > 1 )
     587             :                     {
     588           0 :                         pE->nRowOverlap += nRows - 1;
     589           0 :                         if ( j == 0 )
     590             :                         {   // Merged rows move the next row
     591           0 :                             SCROW nTmp = nCurRow + nRows;
     592           0 :                             if ( nNextRow < nTmp )
     593           0 :                                 nNextRow = nTmp;
     594             :                         }
     595             :                     }
     596             :                 }
     597             :             }
     598             :         }
     599             :         // Real column
     600           0 :         (void)SeekOffset( pColOffset, pE->nOffset, &pE->nCol, nOffsetTolerance );
     601           0 :         SCCOL nColBeforeSkip = pE->nCol;
     602           0 :         SkipLocked( pE, false );
     603           0 :         if ( pE->nCol != nColBeforeSkip )
     604             :         {
     605           0 :             SCCOL nCount = (SCCOL)pColOffset->size();
     606           0 :             if ( nCount <= pE->nCol )
     607             :             {
     608           0 :                 pE->nOffset = (sal_uInt16) (*pColOffset)[nCount-1];
     609           0 :                 MakeCol( pColOffset, pE->nOffset, pE->nWidth, nOffsetTolerance, nOffsetTolerance );
     610             :             }
     611             :             else
     612             :             {
     613           0 :                 pE->nOffset = (sal_uInt16) (*pColOffset)[pE->nCol];
     614             :             }
     615             :         }
     616             :         SCCOL nPos;
     617           0 :         if ( pE->nWidth && SeekOffset( pColOffset, pE->nOffset + pE->nWidth, &nPos, nOffsetTolerance ) )
     618           0 :             pE->nColOverlap = (nPos > pE->nCol ? nPos - pE->nCol : 1);
     619             :         else
     620             :         {
     621             :         //FIXME: This may not be correct, but works anyway ...
     622           0 :             pE->nColOverlap = 1;
     623             :         }
     624             :         xLockedList->Join( ScRange( pE->nCol, pE->nRow, 0,
     625           0 :             pE->nCol + pE->nColOverlap - 1, pE->nRow + pE->nRowOverlap - 1, 0 ) );
     626             :         // Take over MaxDimensions
     627           0 :         SCCOL nColTmp = pE->nCol + pE->nColOverlap;
     628           0 :         if ( nColMax < nColTmp )
     629           0 :             nColMax = nColTmp;
     630           0 :         SCROW nRowTmp = pE->nRow + pE->nRowOverlap;
     631           0 :         if ( nRowMax < nRowTmp )
     632           0 :             nRowMax = nRowTmp;
     633             :     }
     634           0 :     while ( !aStack.empty() )
     635             :     {
     636           0 :         delete aStack.top();
     637           0 :         aStack.pop();
     638           0 :     }
     639           0 : }
     640             : 
     641           0 : sal_uInt16 ScHTMLLayoutParser::GetWidth( ScEEParseEntry* pE )
     642             : {
     643           0 :     if ( pE->nWidth )
     644           0 :         return pE->nWidth;
     645           0 :     sal_Int32 nTmp = ::std::min( static_cast<sal_Int32>( pE->nCol -
     646           0 :                 nColCntStart + pE->nColOverlap),
     647           0 :             static_cast<sal_Int32>( pLocalColOffset->size() - 1));
     648           0 :     SCCOL nPos = (nTmp < 0 ? 0 : static_cast<SCCOL>(nTmp));
     649           0 :     sal_uInt16 nOff2 = (sal_uInt16) (*pLocalColOffset)[nPos];
     650           0 :     if ( pE->nOffset < nOff2 )
     651           0 :         return nOff2 - pE->nOffset;
     652           0 :     return 0;
     653             : }
     654             : 
     655           0 : void ScHTMLLayoutParser::SetWidths()
     656             : {
     657             :     ScEEParseEntry* pE;
     658             :     SCCOL nCol;
     659           0 :     if ( !nTableWidth )
     660           0 :         nTableWidth = (sal_uInt16) aPageSize.Width();
     661           0 :     SCCOL nColsPerRow = nMaxCol - nColCntStart;
     662           0 :     if ( nColsPerRow <= 0 )
     663           0 :         nColsPerRow = 1;
     664           0 :     if ( pLocalColOffset->size() <= 2 )
     665             :     {   // Only PageSize, there was no width setting
     666           0 :         sal_uInt16 nWidth = nTableWidth / static_cast<sal_uInt16>(nColsPerRow);
     667           0 :         sal_uInt16 nOff = nColOffsetStart;
     668           0 :         pLocalColOffset->clear();
     669           0 :         for ( nCol = 0; nCol <= nColsPerRow; ++nCol, nOff = nOff + nWidth )
     670             :         {
     671           0 :             MakeColNoRef( pLocalColOffset, nOff, 0, 0, 0 );
     672             :         }
     673           0 :         nTableWidth = (sal_uInt16)(pLocalColOffset->back() - pLocalColOffset->front());
     674           0 :         for ( size_t i = nFirstTableCell, nListSize = maList.size(); i < nListSize; ++i )
     675             :         {
     676           0 :             pE = maList[ i ];
     677           0 :             if ( pE->nTab == nTable )
     678             :             {
     679           0 :                 pE->nOffset = (sal_uInt16) (*pLocalColOffset)[pE->nCol - nColCntStart];
     680           0 :                 pE->nWidth = 0; // to be recalculated later
     681             :             }
     682             :         }
     683             :     }
     684             :     else
     685             :     {   // Some without width
     686             :         // Why actually no pE?
     687           0 :         if ( nFirstTableCell < maList.size() )
     688             :         {
     689           0 :             boost::scoped_array<sal_uInt16> pOffsets(new sal_uInt16[ nColsPerRow+1 ]);
     690           0 :             memset( pOffsets.get(), 0, (nColsPerRow+1) * sizeof(sal_uInt16) );
     691           0 :             boost::scoped_array<sal_uInt16> pWidths(new sal_uInt16[ nColsPerRow ]);
     692           0 :             memset( pWidths.get(), 0, nColsPerRow * sizeof(sal_uInt16) );
     693           0 :             pOffsets[0] = nColOffsetStart;
     694           0 :             for ( size_t i = nFirstTableCell, nListSize = maList.size(); i < nListSize; ++i )
     695             :             {
     696           0 :                 pE = maList[ i ];
     697           0 :                 if ( pE->nTab == nTable && pE->nWidth )
     698             :                 {
     699           0 :                     nCol = pE->nCol - nColCntStart;
     700           0 :                     if ( nCol < nColsPerRow )
     701             :                     {
     702           0 :                         if ( pE->nColOverlap == 1 )
     703             :                         {
     704           0 :                             if ( pWidths[nCol] < pE->nWidth )
     705           0 :                                 pWidths[nCol] = pE->nWidth;
     706             :                         }
     707             :                         else
     708             :                         {   // try to find a single undefined width
     709           0 :                             sal_uInt16 nTotal = 0;
     710           0 :                             bool bFound = false;
     711           0 :                             SCCOL nHere = 0;
     712           0 :                             SCCOL nStop = std::min( static_cast<SCCOL>(nCol + pE->nColOverlap), nColsPerRow );
     713           0 :                             for ( ; nCol < nStop; nCol++ )
     714             :                             {
     715           0 :                                 if ( pWidths[nCol] )
     716           0 :                                     nTotal = nTotal + pWidths[nCol];
     717             :                                 else
     718             :                                 {
     719           0 :                                     if ( bFound )
     720             :                                     {
     721           0 :                                         bFound = false;
     722           0 :                                         break;  // for
     723             :                                     }
     724           0 :                                     bFound = true;
     725           0 :                                     nHere = nCol;
     726             :                                 }
     727             :                             }
     728           0 :                             if ( bFound && pE->nWidth > nTotal )
     729           0 :                                 pWidths[nHere] = pE->nWidth - nTotal;
     730             :                         }
     731             :                     }
     732             :                 }
     733             :             }
     734           0 :             sal_uInt16 nWidths = 0;
     735           0 :             sal_uInt16 nUnknown = 0;
     736           0 :             for ( nCol = 0; nCol < nColsPerRow; nCol++ )
     737             :             {
     738           0 :                 if ( pWidths[nCol] )
     739           0 :                     nWidths = nWidths + pWidths[nCol];
     740             :                 else
     741           0 :                     nUnknown++;
     742             :             }
     743           0 :             if ( nUnknown )
     744             :             {
     745           0 :                 sal_uInt16 nW = ((nWidths < nTableWidth) ?
     746           0 :                     ((nTableWidth - nWidths) / nUnknown) :
     747           0 :                     (nTableWidth / nUnknown));
     748           0 :                 for ( nCol = 0; nCol < nColsPerRow; nCol++ )
     749             :                 {
     750           0 :                     if ( !pWidths[nCol] )
     751           0 :                         pWidths[nCol] = nW;
     752             :                 }
     753             :             }
     754           0 :             for ( nCol = 1; nCol <= nColsPerRow; nCol++ )
     755             :             {
     756           0 :                 pOffsets[nCol] = pOffsets[nCol-1] + pWidths[nCol-1];
     757             :             }
     758           0 :             pLocalColOffset->clear();
     759           0 :             for ( nCol = 0; nCol <= nColsPerRow; nCol++ )
     760             :             {
     761           0 :                 MakeColNoRef( pLocalColOffset, pOffsets[nCol], 0, 0, 0 );
     762             :             }
     763           0 :             nTableWidth = pOffsets[nColsPerRow] - pOffsets[0];
     764             : 
     765           0 :             for ( size_t i = nFirstTableCell, nListSize = maList.size(); i < nListSize; ++i )
     766             :             {
     767           0 :                 pE = maList[ i ];
     768           0 :                 if ( pE->nTab == nTable )
     769             :                 {
     770           0 :                     nCol = pE->nCol - nColCntStart;
     771             :                     OSL_ENSURE( nCol < nColsPerRow, "ScHTMLLayoutParser::SetWidths: column overflow" );
     772           0 :                     if ( nCol < nColsPerRow )
     773             :                     {
     774           0 :                         pE->nOffset = pOffsets[nCol];
     775           0 :                         nCol = nCol + pE->nColOverlap;
     776           0 :                         if ( nCol > nColsPerRow )
     777           0 :                             nCol = nColsPerRow;
     778           0 :                         pE->nWidth = pOffsets[nCol] - pE->nOffset;
     779             :                     }
     780             :                 }
     781           0 :             }
     782             :         }
     783             :     }
     784           0 :     if ( !pLocalColOffset->empty() )
     785             :     {
     786           0 :         sal_uInt16 nMax = (sal_uInt16) pLocalColOffset->back();
     787           0 :         if ( aPageSize.Width() < nMax )
     788           0 :             aPageSize.Width() = nMax;
     789             :     }
     790           0 :     for ( size_t i = nFirstTableCell, nListSize = maList.size(); i < nListSize; ++i )
     791             :     {
     792           0 :         pE = maList[ i ];
     793           0 :         if ( pE->nTab == nTable )
     794             :         {
     795           0 :             if ( !pE->nWidth )
     796             :             {
     797           0 :                 pE->nWidth = GetWidth( pE );
     798             :                 OSL_ENSURE( pE->nWidth, "SetWidths: pE->nWidth == 0" );
     799             :             }
     800           0 :             MakeCol( pColOffset, pE->nOffset, pE->nWidth, nOffsetTolerance, nOffsetTolerance );
     801             :         }
     802             :     }
     803           0 : }
     804             : 
     805           0 : void ScHTMLLayoutParser::Colonize( ScEEParseEntry* pE )
     806             : {
     807           0 :     if ( pE->nCol == SCCOL_MAX )
     808           0 :         pE->nCol = nColCnt;
     809           0 :     if ( pE->nRow == SCROW_MAX )
     810           0 :         pE->nRow = nRowCnt;
     811           0 :     SCCOL nCol = pE->nCol;
     812           0 :     SkipLocked( pE ); // Change of columns to the right
     813             : 
     814           0 :     if ( nCol < pE->nCol )
     815             :     {   // Replaced
     816           0 :         nCol = pE->nCol - nColCntStart;
     817           0 :         SCCOL nCount = static_cast<SCCOL>(pLocalColOffset->size());
     818           0 :         if ( nCol < nCount )
     819           0 :             nColOffset = (sal_uInt16) (*pLocalColOffset)[nCol];
     820             :         else
     821           0 :             nColOffset = (sal_uInt16) (*pLocalColOffset)[nCount - 1];
     822             :     }
     823           0 :     pE->nOffset = nColOffset;
     824           0 :     sal_uInt16 nWidth = GetWidth( pE );
     825           0 :     MakeCol( pLocalColOffset, pE->nOffset, nWidth, nOffsetTolerance, nOffsetTolerance );
     826           0 :     if ( pE->nWidth )
     827           0 :         pE->nWidth = nWidth;
     828           0 :     nColOffset = pE->nOffset + nWidth;
     829           0 :     if ( nTableWidth < nColOffset - nColOffsetStart )
     830           0 :         nTableWidth = nColOffset - nColOffsetStart;
     831           0 : }
     832             : 
     833           0 : void ScHTMLLayoutParser::CloseEntry( ImportInfo* pInfo )
     834             : {
     835           0 :     bInCell = false;
     836           0 :     if ( bTabInTabCell )
     837             :     {   // From the stack in TableOff
     838           0 :         bTabInTabCell = false;
     839           0 :         bool found = false;
     840           0 :         for ( size_t i = 0, nListSize = maList.size(); i < nListSize; ++i )
     841             :         {
     842           0 :             if ( pActEntry == maList[ i ] )
     843             :             {
     844           0 :                 found = true;
     845           0 :                 break;
     846             :             }
     847             :         }
     848           0 :         if ( !found )
     849           0 :             delete pActEntry;
     850           0 :         NewActEntry( maList.back() ); // New free flying pActEntry
     851           0 :         return ;
     852             :     }
     853           0 :     if ( pActEntry->nTab == 0 )
     854           0 :         pActEntry->nWidth = (sal_uInt16) aPageSize.Width();
     855           0 :     Colonize( pActEntry );
     856           0 :     nColCnt = pActEntry->nCol + pActEntry->nColOverlap;
     857           0 :     if ( nMaxCol < nColCnt )
     858           0 :         nMaxCol = nColCnt;      // TableStack MaxCol
     859           0 :     if ( nColMax < nColCnt )
     860           0 :         nColMax = nColCnt;      // Global MaxCol for ScEEParser GetDimensions!
     861           0 :     EntryEnd( pActEntry, pInfo->aSelection );
     862           0 :     ESelection& rSel = pActEntry->aSel;
     863           0 :     while ( rSel.nStartPara < rSel.nEndPara
     864           0 :             && pEdit->GetTextLen( rSel.nStartPara ) == 0 )
     865             :     {   // Strip preceding empty paragraphs
     866           0 :         rSel.nStartPara++;
     867             :     }
     868           0 :     while ( rSel.nEndPos == 0 && rSel.nEndPara > rSel.nStartPara )
     869             :     {   // Strip successive empty paragraphs
     870           0 :         rSel.nEndPara--;
     871           0 :         rSel.nEndPos = pEdit->GetTextLen( rSel.nEndPara );
     872             :     }
     873           0 :     if ( rSel.nStartPara > rSel.nEndPara )
     874             :     {   // Gives GPF in CreateTextObject
     875             :         OSL_FAIL( "CloseEntry: EditEngine ESelection Start > End" );
     876           0 :         rSel.nEndPara = rSel.nStartPara;
     877             :     }
     878           0 :     if ( rSel.HasRange() )
     879           0 :         pActEntry->aItemSet.Put( SfxBoolItem( ATTR_LINEBREAK, true ) );
     880           0 :     maList.push_back( pActEntry );
     881           0 :     NewActEntry( pActEntry ); // New free flying pActEntry
     882             : }
     883             : 
     884           0 : IMPL_LINK( ScHTMLLayoutParser, HTMLImportHdl, ImportInfo*, pInfo )
     885             : {
     886           0 :     switch ( pInfo->eState )
     887             :     {
     888             :         case HTMLIMP_NEXTTOKEN:
     889           0 :             ProcToken( pInfo );
     890           0 :             break;
     891             :         case HTMLIMP_UNKNOWNATTR:
     892           0 :             ProcToken( pInfo );
     893           0 :             break;
     894             :         case HTMLIMP_START:
     895           0 :             break;
     896             :         case HTMLIMP_END:
     897           0 :             if ( pInfo->aSelection.nEndPos )
     898             :             {
     899             :                 // If text remains: create paragraph, without calling CloseEntry().
     900           0 :                 if( bInCell )   // ...but only in opened table cells.
     901             :                 {
     902           0 :                     bInCell = false;
     903           0 :                     NextRow( pInfo );
     904           0 :                     bInCell = true;
     905             :                 }
     906           0 :                 CloseEntry( pInfo );
     907             :             }
     908           0 :             while ( nTableLevel > 0 )
     909           0 :                 TableOff( pInfo );      // close tables, if </TABLE> missing
     910           0 :             break;
     911             :         case HTMLIMP_SETATTR:
     912           0 :             break;
     913             :         case HTMLIMP_INSERTTEXT:
     914           0 :             break;
     915             :         case HTMLIMP_INSERTPARA:
     916           0 :             if ( nTableLevel < 1 )
     917             :             {
     918           0 :                 CloseEntry( pInfo );
     919           0 :                 NextRow( pInfo );
     920             :             }
     921           0 :             break;
     922             :         case HTMLIMP_INSERTFIELD:
     923           0 :             break;
     924             :         default:
     925             :             OSL_FAIL("HTMLImportHdl: unknown ImportInfo.eState");
     926             :     }
     927           0 :     return 0;
     928             : }
     929             : 
     930             : // Greatest common divisor (Euclid)
     931             : // Special case: 0 and something gives 1
     932           0 : static SCROW lcl_GGT( SCROW a, SCROW b )
     933             : {
     934           0 :     if ( !a || !b )
     935           0 :         return 1;
     936           0 :     do
     937             :     {
     938           0 :         if ( a > b )
     939           0 :             a -= SCROW(a / b) * b;
     940             :         else
     941           0 :             b -= SCROW(b / a) * a;
     942           0 :     } while ( a && b );
     943           0 :     return ((a != 0) ? a : b);
     944             : }
     945             : 
     946             : // Lowest common multiple: a * b / GCD(a,b)
     947           0 : static SCROW lcl_KGV( SCROW a, SCROW b )
     948             : {
     949           0 :     if ( a > b )    // Make overflow even less likely
     950           0 :         return (a / lcl_GGT(a,b)) * b;
     951             :     else
     952           0 :         return (b / lcl_GGT(a,b)) * a;
     953             : }
     954             : 
     955           0 : void ScHTMLLayoutParser::TableDataOn( ImportInfo* pInfo )
     956             : {
     957           0 :     if ( bInCell )
     958           0 :         CloseEntry( pInfo );
     959           0 :     if ( !nTableLevel )
     960             :     {
     961             :         OSL_FAIL( "dumbo doc! <TH> or <TD> without previous <TABLE>" );
     962           0 :         TableOn( pInfo );
     963             :     }
     964           0 :     bInCell = true;
     965           0 :     bool bHorJustifyCenterTH = (pInfo->nToken == HTML_TABLEHEADER_ON);
     966           0 :     const HTMLOptions& rOptions = static_cast<HTMLParser*>(pInfo->pParser)->GetOptions();
     967           0 :     for (size_t i = 0, n = rOptions.size(); i < n; ++i)
     968             :     {
     969           0 :         const HTMLOption& rOption = rOptions[i];
     970           0 :         switch( rOption.GetToken() )
     971             :         {
     972             :             case HTML_O_COLSPAN:
     973             :             {
     974           0 :                 pActEntry->nColOverlap = ( SCCOL ) rOption.GetString().toInt32();
     975             :             }
     976           0 :             break;
     977             :             case HTML_O_ROWSPAN:
     978             :             {
     979           0 :                 pActEntry->nRowOverlap = ( SCROW ) rOption.GetString().toInt32();
     980             :             }
     981           0 :             break;
     982             :             case HTML_O_ALIGN:
     983             :             {
     984           0 :                 bHorJustifyCenterTH = false;
     985             :                 SvxCellHorJustify eVal;
     986           0 :                 const OUString& rOptVal = rOption.GetString();
     987           0 :                 if ( rOptVal.equalsIgnoreAsciiCase( OOO_STRING_SVTOOLS_HTML_AL_right )  )
     988           0 :                     eVal = SVX_HOR_JUSTIFY_RIGHT;
     989           0 :                 else if ( rOptVal.equalsIgnoreAsciiCase( OOO_STRING_SVTOOLS_HTML_AL_center ) )
     990           0 :                     eVal = SVX_HOR_JUSTIFY_CENTER;
     991           0 :                 else if ( rOptVal.equalsIgnoreAsciiCase( OOO_STRING_SVTOOLS_HTML_AL_left ) )
     992           0 :                     eVal = SVX_HOR_JUSTIFY_LEFT;
     993             :                 else
     994           0 :                     eVal = SVX_HOR_JUSTIFY_STANDARD;
     995           0 :                 if ( eVal != SVX_HOR_JUSTIFY_STANDARD )
     996           0 :                     pActEntry->aItemSet.Put( SvxHorJustifyItem( eVal, ATTR_HOR_JUSTIFY) );
     997             :             }
     998           0 :             break;
     999             :             case HTML_O_VALIGN:
    1000             :             {
    1001             :                 SvxCellVerJustify eVal;
    1002           0 :                 const OUString& rOptVal = rOption.GetString();
    1003           0 :                 if ( rOptVal.equalsIgnoreAsciiCase( OOO_STRING_SVTOOLS_HTML_VA_top ) )
    1004           0 :                     eVal = SVX_VER_JUSTIFY_TOP;
    1005           0 :                 else if ( rOptVal.equalsIgnoreAsciiCase( OOO_STRING_SVTOOLS_HTML_VA_middle ) )
    1006           0 :                     eVal = SVX_VER_JUSTIFY_CENTER;
    1007           0 :                 else if ( rOptVal.equalsIgnoreAsciiCase( OOO_STRING_SVTOOLS_HTML_VA_bottom ) )
    1008           0 :                     eVal = SVX_VER_JUSTIFY_BOTTOM;
    1009             :                 else
    1010           0 :                     eVal = SVX_VER_JUSTIFY_STANDARD;
    1011           0 :                 pActEntry->aItemSet.Put( SvxVerJustifyItem( eVal, ATTR_VER_JUSTIFY) );
    1012             :             }
    1013           0 :             break;
    1014             :             case HTML_O_WIDTH:
    1015             :             {
    1016           0 :                 pActEntry->nWidth = GetWidthPixel( rOption );
    1017             :             }
    1018           0 :             break;
    1019             :             case HTML_O_BGCOLOR:
    1020             :             {
    1021           0 :                 Color aColor;
    1022           0 :                 rOption.GetColor( aColor );
    1023             :                 pActEntry->aItemSet.Put(
    1024           0 :                     SvxBrushItem( aColor, ATTR_BACKGROUND ) );
    1025             :             }
    1026           0 :             break;
    1027             :             case HTML_O_SDVAL:
    1028             :             {
    1029           0 :                 pActEntry->pValStr = new OUString( rOption.GetString() );
    1030             :             }
    1031           0 :             break;
    1032             :             case HTML_O_SDNUM:
    1033             :             {
    1034           0 :                 pActEntry->pNumStr = new OUString( rOption.GetString() );
    1035             :             }
    1036           0 :             break;
    1037             :         }
    1038             :     }
    1039           0 :     pActEntry->nCol = nColCnt;
    1040           0 :     pActEntry->nRow = nRowCnt;
    1041           0 :     pActEntry->nTab = nTable;
    1042             : 
    1043           0 :     if ( bHorJustifyCenterTH )
    1044             :         pActEntry->aItemSet.Put(
    1045           0 :             SvxHorJustifyItem( SVX_HOR_JUSTIFY_CENTER, ATTR_HOR_JUSTIFY) );
    1046           0 : }
    1047             : 
    1048           0 : void ScHTMLLayoutParser::TableRowOn( ImportInfo* pInfo )
    1049             : {
    1050           0 :     if ( nColCnt > nColCntStart )
    1051           0 :         NextRow( pInfo ); // The optional TableRowOff wasn't there
    1052           0 :     nColOffset = nColOffsetStart;
    1053           0 : }
    1054             : 
    1055           0 : void ScHTMLLayoutParser::TableRowOff( ImportInfo* pInfo )
    1056             : {
    1057           0 :     NextRow( pInfo );
    1058           0 : }
    1059             : 
    1060           0 : void ScHTMLLayoutParser::TableDataOff( ImportInfo* pInfo )
    1061             : {
    1062           0 :     if ( bInCell )
    1063           0 :         CloseEntry( pInfo ); // Only if it really was one
    1064           0 : }
    1065             : 
    1066           0 : void ScHTMLLayoutParser::TableOn( ImportInfo* pInfo )
    1067             : {
    1068           0 :     OUString aTabName;
    1069             : 
    1070           0 :     if ( ++nTableLevel > 1 )
    1071             :     {   // Table in Table
    1072           0 :         sal_uInt16 nTmpColOffset = nColOffset; // Will be changed in Colonize()
    1073           0 :         Colonize( pActEntry );
    1074             :         aTableStack.push( new ScHTMLTableStackEntry(
    1075             :             pActEntry, xLockedList, pLocalColOffset, nFirstTableCell,
    1076             :             nColCnt, nRowCnt, nColCntStart, nMaxCol, nTable,
    1077             :             nTableWidth, nColOffset, nColOffsetStart,
    1078           0 :             bFirstRow ) );
    1079           0 :         sal_uInt16 nLastWidth = nTableWidth;
    1080           0 :         nTableWidth = GetWidth( pActEntry );
    1081           0 :         if ( nTableWidth == nLastWidth && nMaxCol - nColCntStart > 1 )
    1082             :         {   // There must be more than one, so this one cannot be enough
    1083           0 :             nTableWidth = nLastWidth / static_cast<sal_uInt16>((nMaxCol - nColCntStart));
    1084             :         }
    1085           0 :         nLastWidth = nTableWidth;
    1086           0 :         if ( pInfo->nToken == HTML_TABLE_ON )
    1087             :         {   // It can still be TD or TH, if we didn't have a TABLE earlier
    1088           0 :             const HTMLOptions& rOptions = static_cast<HTMLParser*>(pInfo->pParser)->GetOptions();
    1089           0 :             for (size_t i = 0, n = rOptions.size(); i < n; ++i)
    1090             :             {
    1091           0 :                 const HTMLOption& rOption = rOptions[i];
    1092           0 :                 switch( rOption.GetToken() )
    1093             :                 {
    1094             :                     case HTML_O_WIDTH:
    1095             :                     {   // Percent: of document width or outer cell
    1096           0 :                         nTableWidth = GetWidthPixel( rOption );
    1097             :                     }
    1098           0 :                     break;
    1099             :                     case HTML_O_BORDER:
    1100             :                         // Border is: ((pOption->GetString().Len() == 0) || (pOption->GetNumber() != 0));
    1101           0 :                     break;
    1102             :                     case HTML_O_ID:
    1103           0 :                         aTabName = rOption.GetString();
    1104           0 :                     break;
    1105             :                 }
    1106             :             }
    1107             :         }
    1108           0 :         bInCell = false;
    1109           0 :         if ( bTabInTabCell && !(nTableWidth < nLastWidth) )
    1110             :         {   // Multiple tables in one cell, underneath each other
    1111           0 :             bTabInTabCell = false;
    1112           0 :             NextRow( pInfo );
    1113             :         }
    1114             :         else
    1115             :         {   // It start's in this cell or next to each other
    1116           0 :             bTabInTabCell = false;
    1117           0 :             nColCntStart = nColCnt;
    1118           0 :             nColOffset = nTmpColOffset;
    1119           0 :             nColOffsetStart = nColOffset;
    1120             :         }
    1121             : 
    1122           0 :         ScEEParseEntry* pE = NULL;
    1123           0 :         if (maList.size())
    1124           0 :             pE = maList.back();
    1125           0 :         NewActEntry( pE ); // New free flying pActEntry
    1126           0 :         xLockedList = new ScRangeList;
    1127             :     }
    1128             :     else
    1129             :     {   // Simple table at the document level
    1130           0 :         EntryEnd( pActEntry, pInfo->aSelection );
    1131           0 :         if ( pActEntry->aSel.HasRange() )
    1132             :         {   // Flying text left
    1133           0 :             CloseEntry( pInfo );
    1134           0 :             NextRow( pInfo );
    1135             :         }
    1136             :         aTableStack.push( new ScHTMLTableStackEntry(
    1137             :             pActEntry, xLockedList, pLocalColOffset, nFirstTableCell,
    1138             :             nColCnt, nRowCnt, nColCntStart, nMaxCol, nTable,
    1139             :             nTableWidth, nColOffset, nColOffsetStart,
    1140           0 :             bFirstRow ) );
    1141             :         // As soon as we have multiple tables we need to be tolerant with the offsets.
    1142           0 :         if (nMaxTable > 0)
    1143           0 :             nOffsetTolerance = SC_HTML_OFFSET_TOLERANCE_LARGE;
    1144           0 :         nTableWidth = 0;
    1145           0 :         if ( pInfo->nToken == HTML_TABLE_ON )
    1146             :         {
    1147             :             // It can still be TD or TH, if we didn't have a TABLE earlier
    1148           0 :             const HTMLOptions& rOptions = static_cast<HTMLParser*>(pInfo->pParser)->GetOptions();
    1149           0 :             for (size_t i = 0, n = rOptions.size(); i < n; ++i)
    1150             :             {
    1151           0 :                 const HTMLOption& rOption = rOptions[i];
    1152           0 :                 switch( rOption.GetToken() )
    1153             :                 {
    1154             :                     case HTML_O_WIDTH:
    1155             :                     {   // Percent: of document width or outer cell
    1156           0 :                         nTableWidth = GetWidthPixel( rOption );
    1157             :                     }
    1158           0 :                     break;
    1159             :                     case HTML_O_BORDER:
    1160             :                         //BorderOn is: ((pOption->GetString().Len() == 0) || (pOption->GetNumber() != 0));
    1161           0 :                     break;
    1162             :                     case HTML_O_ID:
    1163           0 :                         aTabName = rOption.GetString();
    1164           0 :                     break;
    1165             :                 }
    1166             :             }
    1167             :         }
    1168             :     }
    1169           0 :     nTable = ++nMaxTable;
    1170           0 :     bFirstRow = true;
    1171           0 :     nFirstTableCell = maList.size();
    1172             : 
    1173           0 :     pLocalColOffset = new ScHTMLColOffset;
    1174           0 :     MakeColNoRef( pLocalColOffset, nColOffsetStart, 0, 0, 0 );
    1175           0 : }
    1176             : 
    1177           0 : void ScHTMLLayoutParser::TableOff( ImportInfo* pInfo )
    1178             : {
    1179           0 :     if ( bInCell )
    1180           0 :         CloseEntry( pInfo );
    1181           0 :     if ( nColCnt > nColCntStart )
    1182           0 :         TableRowOff( pInfo ); // The optional TableRowOff wasn't
    1183           0 :     if ( !nTableLevel )
    1184             :     {
    1185             :         OSL_FAIL( "dumbo doc! </TABLE> without opening <TABLE>" );
    1186           0 :         return ;
    1187             :     }
    1188           0 :     if ( --nTableLevel > 0 )
    1189             :     {   // Table in Table done
    1190           0 :         if ( !aTableStack.empty() )
    1191             :         {
    1192           0 :             ScHTMLTableStackEntry* pS = aTableStack.top();
    1193           0 :             aTableStack.pop();
    1194             : 
    1195           0 :             ScEEParseEntry* pE = pS->pCellEntry;
    1196           0 :             SCROW nRows = nRowCnt - pS->nRowCnt;
    1197           0 :             if ( nRows > 1 )
    1198             :             {   // Insert size of table at this position
    1199           0 :                 SCROW nRow = pS->nRowCnt;
    1200           0 :                 sal_uInt16 nTab = pS->nTable;
    1201           0 :                 if ( !pTables )
    1202           0 :                     pTables = new OuterMap;
    1203             :                 // Height of outer table
    1204           0 :                 OuterMap::const_iterator it = pTables->find( nTab );
    1205             :                 InnerMap* pTab1;
    1206           0 :                 if ( it == pTables->end() )
    1207             :                 {
    1208           0 :                     pTab1 = new InnerMap;
    1209           0 :                     (*pTables)[ nTab ] = pTab1;
    1210             :                 }
    1211             :                 else
    1212           0 :                     pTab1 = it->second;
    1213           0 :                 SCROW nRowSpan = pE->nRowOverlap;
    1214             :                 SCROW nRowKGV;
    1215             :                 SCROW nRowsPerRow1; // Outer table
    1216             :                 SCROW nRowsPerRow2; // Inner table
    1217           0 :                 if ( nRowSpan > 1 )
    1218             :                 {   // LCM to which we can map the inner and outer rows
    1219           0 :                     nRowKGV = lcl_KGV( nRowSpan, nRows );
    1220           0 :                     nRowsPerRow1 = nRowKGV / nRowSpan;
    1221           0 :                     nRowsPerRow2 = nRowKGV / nRows;
    1222             :                 }
    1223             :                 else
    1224             :                 {
    1225           0 :                     nRowKGV = nRowsPerRow1 = nRows;
    1226           0 :                     nRowsPerRow2 = 1;
    1227             :                 }
    1228           0 :                 InnerMap* pTab2 = NULL;
    1229           0 :                 if ( nRowsPerRow2 > 1 )
    1230             :                 {   // Height of the inner table
    1231           0 :                     pTab2 = new InnerMap;
    1232           0 :                     (*pTables)[ nTable ] = pTab2;
    1233             :                 }
    1234             :                 // Abuse void* Data entry of the Table class for height mapping
    1235           0 :                 if ( nRowKGV > 1 )
    1236             :                 {
    1237           0 :                     if ( nRowsPerRow1 > 1 )
    1238             :                     {   // Outer
    1239           0 :                         for ( SCROW j=0; j < nRowSpan; j++ )
    1240             :                         {
    1241           0 :                             sal_uLong nRowKey = nRow + j;
    1242           0 :                             SCROW nR = (*pTab1)[ nRowKey ];
    1243           0 :                             if ( !nR )
    1244           0 :                                 (*pTab1)[ nRowKey ] = nRowsPerRow1;
    1245           0 :                             else if ( nRowsPerRow1 > nR )
    1246           0 :                                 (*pTab1)[ nRowKey ] = nRowsPerRow1;
    1247             :                             //TODO: How can we improve on this?
    1248           0 :                             else if ( nRowsPerRow1 < nR && nRowSpan == 1
    1249           0 :                               && nTable == nMaxTable )
    1250             :                             {   // Still some space left, merge in a better way (if possible)
    1251           0 :                                 SCROW nAdd = nRowsPerRow1 - (nR % nRowsPerRow1);
    1252           0 :                                 nR += nAdd;
    1253           0 :                                 if ( (nR % nRows) == 0 )
    1254             :                                 {   // Only if representable
    1255           0 :                                     SCROW nR2 = (*pTab1)[ nRowKey+1 ];
    1256           0 :                                     if ( nR2 > nAdd )
    1257             :                                     {   // Only if we really have enough space
    1258           0 :                                         (*pTab1)[ nRowKey ] = nR;
    1259           0 :                                         (*pTab1)[ nRowKey+1 ] = nR2 - nAdd;
    1260           0 :                                         nRowsPerRow2 = nR / nRows;
    1261             :                                     }
    1262             :                                 }
    1263             :                             }
    1264             :                         }
    1265             :                     }
    1266           0 :                     if ( nRowsPerRow2 > 1 )
    1267             :                     {   // Inner
    1268           0 :                         if ( !pTab2 )
    1269             :                         {   // nRowsPerRow2 could be've been incremented
    1270           0 :                             pTab2 = new InnerMap;
    1271           0 :                             (*pTables)[ nTable ] = pTab2;
    1272             :                         }
    1273           0 :                         for ( SCROW j=0; j < nRows; j++ )
    1274             :                         {
    1275           0 :                             sal_uLong nRowKey = nRow + j;
    1276           0 :                             (*pTab2)[ nRowKey ] = nRowsPerRow2;
    1277             :                         }
    1278             :                     }
    1279             :                 }
    1280             :             }
    1281             : 
    1282           0 :             SetWidths();
    1283             : 
    1284           0 :             if ( !pE->nWidth )
    1285           0 :                 pE->nWidth = nTableWidth;
    1286           0 :             else if ( pE->nWidth < nTableWidth )
    1287             :             {
    1288           0 :                 sal_uInt16 nOldOffset = pE->nOffset + pE->nWidth;
    1289           0 :                 sal_uInt16 nNewOffset = pE->nOffset + nTableWidth;
    1290           0 :                 ModifyOffset( pS->pLocalColOffset, nOldOffset, nNewOffset, nOffsetTolerance );
    1291           0 :                 sal_uInt16 nTmp = nNewOffset - pE->nOffset - pE->nWidth;
    1292           0 :                 pE->nWidth = nNewOffset - pE->nOffset;
    1293           0 :                 pS->nTableWidth = pS->nTableWidth + nTmp;
    1294           0 :                 if ( pS->nColOffset >= nOldOffset )
    1295           0 :                     pS->nColOffset = pS->nColOffset + nTmp;
    1296             :             }
    1297             : 
    1298           0 :             nColCnt = pE->nCol + pE->nColOverlap;
    1299           0 :             nRowCnt = pS->nRowCnt;
    1300           0 :             nColCntStart = pS->nColCntStart;
    1301           0 :             nMaxCol = pS->nMaxCol;
    1302           0 :             nTable = pS->nTable;
    1303           0 :             nTableWidth = pS->nTableWidth;
    1304           0 :             nFirstTableCell = pS->nFirstTableCell;
    1305           0 :             nColOffset = pS->nColOffset;
    1306           0 :             nColOffsetStart = pS->nColOffsetStart;
    1307           0 :             bFirstRow = pS->bFirstRow;
    1308           0 :             xLockedList = pS->xLockedList;
    1309           0 :             delete pLocalColOffset;
    1310           0 :             pLocalColOffset = pS->pLocalColOffset;
    1311           0 :             delete pActEntry;
    1312             :             // pActEntry is kept around if a table is started in the same row
    1313             :             // (anything's possible in HTML); will be deleted by CloseEntry
    1314           0 :             pActEntry = pE;
    1315           0 :             delete pS;
    1316             :         }
    1317           0 :         bTabInTabCell = true;
    1318           0 :         bInCell = true;
    1319             :     }
    1320             :     else
    1321             :     {   // Simple table finished
    1322           0 :         SetWidths();
    1323           0 :         nMaxCol = 0;
    1324           0 :         nTable = 0;
    1325           0 :         if ( !aTableStack.empty() )
    1326             :         {
    1327           0 :             ScHTMLTableStackEntry* pS = aTableStack.top();
    1328           0 :             aTableStack.pop();
    1329           0 :             delete pLocalColOffset;
    1330           0 :             pLocalColOffset = pS->pLocalColOffset;
    1331           0 :             delete pS;
    1332             :         }
    1333             :     }
    1334             : }
    1335             : 
    1336           0 : void ScHTMLLayoutParser::Image( ImportInfo* pInfo )
    1337             : {
    1338           0 :     ScHTMLImage* pImage = new ScHTMLImage;
    1339           0 :     pActEntry->maImageList.push_back( pImage );
    1340           0 :     const HTMLOptions& rOptions = static_cast<HTMLParser*>(pInfo->pParser)->GetOptions();
    1341           0 :     for (size_t i = 0, n = rOptions.size(); i < n; ++i)
    1342             :     {
    1343           0 :         const HTMLOption& rOption = rOptions[i];
    1344           0 :         switch( rOption.GetToken() )
    1345             :         {
    1346             :             case HTML_O_SRC:
    1347             :             {
    1348           0 :                 pImage->aURL = INetURLObject::GetAbsURL( aBaseURL, rOption.GetString() );
    1349             :             }
    1350           0 :             break;
    1351             :             case HTML_O_ALT:
    1352             :             {
    1353           0 :                 if ( !pActEntry->bHasGraphic )
    1354             :                 {   // ALT text only if not any image loaded
    1355           0 :                     if (!pActEntry->aAltText.isEmpty())
    1356           0 :                         pActEntry->aAltText += "; ";
    1357             : 
    1358           0 :                     pActEntry->aAltText += rOption.GetString();
    1359             :                 }
    1360             :             }
    1361           0 :             break;
    1362             :             case HTML_O_WIDTH:
    1363             :             {
    1364           0 :                 pImage->aSize.Width() = (long)rOption.GetNumber();
    1365             :             }
    1366           0 :             break;
    1367             :             case HTML_O_HEIGHT:
    1368             :             {
    1369           0 :                 pImage->aSize.Height() = (long)rOption.GetNumber();
    1370             :             }
    1371           0 :             break;
    1372             :             case HTML_O_HSPACE:
    1373             :             {
    1374           0 :                 pImage->aSpace.X() = (long)rOption.GetNumber();
    1375             :             }
    1376           0 :             break;
    1377             :             case HTML_O_VSPACE:
    1378             :             {
    1379           0 :                 pImage->aSpace.Y() = (long)rOption.GetNumber();
    1380             :             }
    1381           0 :             break;
    1382             :         }
    1383             :     }
    1384           0 :     if (pImage->aURL.isEmpty())
    1385             :     {
    1386             :         OSL_FAIL( "Image: graphic without URL ?!?" );
    1387           0 :         return ;
    1388             :     }
    1389             : 
    1390             :     sal_uInt16 nFormat;
    1391           0 :     Graphic* pGraphic = new Graphic;
    1392           0 :     GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter();
    1393           0 :     if ( GRFILTER_OK != GraphicFilter::LoadGraphic( pImage->aURL, pImage->aFilterName,
    1394           0 :             *pGraphic, &rFilter, &nFormat ) )
    1395             :     {
    1396           0 :         delete pGraphic;
    1397           0 :         return ; // Bad luck
    1398             :     }
    1399           0 :     if ( !pActEntry->bHasGraphic )
    1400             :     {   // discard any ALT text in this cell if we have any image
    1401           0 :         pActEntry->bHasGraphic = true;
    1402           0 :         (pActEntry->aAltText).clear();
    1403             :     }
    1404           0 :     pImage->aFilterName = rFilter.GetImportFormatName( nFormat );
    1405           0 :     pImage->pGraphic = pGraphic;
    1406           0 :     if ( !(pImage->aSize.Width() && pImage->aSize.Height()) )
    1407             :     {
    1408           0 :         OutputDevice* pDefaultDev = Application::GetDefaultDevice();
    1409             :         pImage->aSize = pDefaultDev->LogicToPixel( pGraphic->GetPrefSize(),
    1410           0 :             pGraphic->GetPrefMapMode() );
    1411             :     }
    1412           0 :     if ( pActEntry->maImageList.size() > 0 )
    1413             :     {
    1414           0 :         long nWidth = 0;
    1415           0 :         for ( size_t i=0; i < pActEntry->maImageList.size(); ++i )
    1416             :         {
    1417           0 :             ScHTMLImage* pI = &pActEntry->maImageList[ i ];
    1418           0 :             if ( pI->nDir & nHorizontal )
    1419           0 :                 nWidth += pI->aSize.Width() + 2 * pI->aSpace.X();
    1420             :             else
    1421           0 :                 nWidth = 0;
    1422             :         }
    1423           0 :         if ( pActEntry->nWidth
    1424           0 :           && (nWidth + pImage->aSize.Width() + 2 * pImage->aSpace.X()
    1425           0 :                 >= pActEntry->nWidth) )
    1426           0 :             pActEntry->maImageList.back().nDir = nVertical;
    1427             :     }
    1428             : }
    1429             : 
    1430           0 : void ScHTMLLayoutParser::ColOn( ImportInfo* pInfo )
    1431             : {
    1432           0 :     const HTMLOptions& rOptions = static_cast<HTMLParser*>(pInfo->pParser)->GetOptions();
    1433           0 :     for (size_t i = 0, n = rOptions.size(); i < n; ++i)
    1434             :     {
    1435           0 :         const HTMLOption& rOption = rOptions[i];
    1436           0 :         switch( rOption.GetToken() )
    1437             :         {
    1438             :             case HTML_O_WIDTH:
    1439             :             {
    1440           0 :                 sal_uInt16 nVal = GetWidthPixel( rOption );
    1441           0 :                 MakeCol( pLocalColOffset, nColOffset, nVal, 0, 0 );
    1442           0 :                 nColOffset = nColOffset + nVal;
    1443             :             }
    1444           0 :             break;
    1445             :         }
    1446             :     }
    1447           0 : }
    1448             : 
    1449           0 : sal_uInt16 ScHTMLLayoutParser::GetWidthPixel( const HTMLOption& rOption )
    1450             : {
    1451           0 :     const OUString& rOptVal = rOption.GetString();
    1452           0 :     if ( rOptVal.indexOf('%') != -1 )
    1453             :     {   // Percent
    1454           0 :         sal_uInt16 nW = (nTableWidth ? nTableWidth : (sal_uInt16) aPageSize.Width());
    1455           0 :         return (sal_uInt16)((rOption.GetNumber() * nW) / 100);
    1456             :     }
    1457             :     else
    1458             :     {
    1459           0 :         if ( rOptVal.indexOf('*') != -1 )
    1460             :         {   // Relative to what?
    1461             :             // TODO: Collect all relative values in ColArray and then MakeCol
    1462           0 :             return 0;
    1463             :         }
    1464             :         else
    1465           0 :             return (sal_uInt16)rOption.GetNumber(); // Pixel
    1466             :     }
    1467             : }
    1468             : 
    1469           0 : void ScHTMLLayoutParser::AnchorOn( ImportInfo* pInfo )
    1470             : {
    1471           0 :     const HTMLOptions& rOptions = static_cast<HTMLParser*>(pInfo->pParser)->GetOptions();
    1472           0 :     for (size_t i = 0, n = rOptions.size(); i < n; ++i)
    1473             :     {
    1474           0 :         const HTMLOption& rOption = rOptions[i];
    1475           0 :         switch( rOption.GetToken() )
    1476             :         {
    1477             :             case HTML_O_NAME:
    1478             :             {
    1479           0 :                 pActEntry->pName = new OUString(rOption.GetString());
    1480             :             }
    1481           0 :             break;
    1482             :         }
    1483             :     }
    1484           0 : }
    1485             : 
    1486           0 : bool ScHTMLLayoutParser::IsAtBeginningOfText( ImportInfo* pInfo )
    1487             : {
    1488           0 :     ESelection& rSel = pActEntry->aSel;
    1489           0 :     return rSel.nStartPara == rSel.nEndPara &&
    1490           0 :         rSel.nStartPara <= pInfo->aSelection.nEndPara &&
    1491           0 :         pEdit->GetTextLen( rSel.nStartPara ) == 0;
    1492             : }
    1493             : 
    1494           0 : void ScHTMLLayoutParser::FontOn( ImportInfo* pInfo )
    1495             : {
    1496           0 :     if ( IsAtBeginningOfText( pInfo ) )
    1497             :     {   // Only at the start of the text; applies to whole line
    1498           0 :         const HTMLOptions& rOptions = static_cast<HTMLParser*>(pInfo->pParser)->GetOptions();
    1499           0 :         for (size_t i = 0, n = rOptions.size(); i < n; ++i)
    1500             :         {
    1501           0 :             const HTMLOption& rOption = rOptions[i];
    1502           0 :             switch( rOption.GetToken() )
    1503             :             {
    1504             :                 case HTML_O_FACE :
    1505             :                 {
    1506           0 :                     const OUString& rFace = rOption.GetString();
    1507           0 :                     OUString aFontName;
    1508           0 :                     sal_Int32 nPos = 0;
    1509           0 :                     while( nPos != -1 )
    1510             :                     {
    1511             :                         // Font list, VCL uses the semicolon as separator
    1512             :                         // HTML uses the comma
    1513           0 :                         OUString aFName = rFace.getToken( 0, ',', nPos );
    1514           0 :                         aFName = comphelper::string::strip(aFName, ' ');
    1515           0 :                         if( !aFontName.isEmpty() )
    1516           0 :                             aFontName += ";";
    1517           0 :                         aFontName += aFName;
    1518           0 :                     }
    1519           0 :                     if ( !aFontName.isEmpty() )
    1520             :                         pActEntry->aItemSet.Put( SvxFontItem( FAMILY_DONTKNOW,
    1521           0 :                             aFontName, EMPTY_OUSTRING, PITCH_DONTKNOW,
    1522           0 :                             RTL_TEXTENCODING_DONTKNOW, ATTR_FONT ) );
    1523             :                 }
    1524           0 :                 break;
    1525             :                 case HTML_O_SIZE :
    1526             :                 {
    1527           0 :                     sal_uInt16 nSize = (sal_uInt16) rOption.GetNumber();
    1528           0 :                     if ( nSize == 0 )
    1529           0 :                         nSize = 1;
    1530           0 :                     else if ( nSize > SC_HTML_FONTSIZES )
    1531           0 :                         nSize = SC_HTML_FONTSIZES;
    1532             :                     pActEntry->aItemSet.Put( SvxFontHeightItem(
    1533           0 :                         maFontHeights[nSize-1], 100, ATTR_FONT_HEIGHT ) );
    1534             :                 }
    1535           0 :                 break;
    1536             :                 case HTML_O_COLOR :
    1537             :                 {
    1538           0 :                     Color aColor;
    1539           0 :                     rOption.GetColor( aColor );
    1540           0 :                     pActEntry->aItemSet.Put( SvxColorItem( aColor, ATTR_FONT_COLOR ) );
    1541             :                 }
    1542           0 :                 break;
    1543             :             }
    1544             :         }
    1545             :     }
    1546           0 : }
    1547             : 
    1548           0 : void ScHTMLLayoutParser::ProcToken( ImportInfo* pInfo )
    1549             : {
    1550           0 :     bool bSetLastToken = true;
    1551           0 :     switch ( pInfo->nToken )
    1552             :     {
    1553             :         case HTML_META:
    1554             :         {
    1555           0 :             HTMLParser* pParser = static_cast<HTMLParser*>(pInfo->pParser);
    1556             :             uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
    1557           0 :                 mpDoc->GetDocumentShell()->GetModel(), uno::UNO_QUERY_THROW);
    1558             :             pParser->ParseMetaOptions(
    1559           0 :                 xDPS->getDocumentProperties(),
    1560           0 :                 mpDoc->GetDocumentShell()->GetHeaderAttributes() );
    1561             :         }
    1562           0 :         break;
    1563             :         case HTML_TITLE_ON:
    1564             :         {
    1565           0 :             bInTitle = true;
    1566           0 :             aString.clear();
    1567             :         }
    1568           0 :         break;
    1569             :         case HTML_TITLE_OFF:
    1570             :         {
    1571           0 :             if ( bInTitle && !aString.isEmpty() )
    1572             :             {
    1573             :                 // Remove blanks from line brakes
    1574           0 :                 aString = aString.trim();
    1575             :                 uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
    1576             :                     mpDoc->GetDocumentShell()->GetModel(),
    1577           0 :                     uno::UNO_QUERY_THROW);
    1578           0 :                 xDPS->getDocumentProperties()->setTitle(aString);
    1579             :             }
    1580           0 :             bInTitle = false;
    1581             :         }
    1582           0 :         break;
    1583             :         case HTML_TABLE_ON:
    1584             :         {
    1585           0 :             TableOn( pInfo );
    1586             :         }
    1587           0 :         break;
    1588             :         case HTML_COL_ON:
    1589             :         {
    1590           0 :             ColOn( pInfo );
    1591             :         }
    1592           0 :         break;
    1593             :         case HTML_TABLEHEADER_ON:       // Opens row
    1594             :         {
    1595           0 :             if ( bInCell )
    1596           0 :                 CloseEntry( pInfo );
    1597             :             // Do not set bInCell to true, TableDataOn does that
    1598             :             pActEntry->aItemSet.Put(
    1599           0 :                 SvxWeightItem( WEIGHT_BOLD, ATTR_FONT_WEIGHT) );
    1600             :         }   // fall through
    1601             :         case HTML_TABLEDATA_ON:         // Opens cell
    1602             :         {
    1603           0 :             TableDataOn( pInfo );
    1604             :         }
    1605           0 :         break;
    1606             :         case HTML_TABLEHEADER_OFF:
    1607             :         case HTML_TABLEDATA_OFF:        // Closes cell
    1608             :         {
    1609           0 :             TableDataOff( pInfo );
    1610             :         }
    1611           0 :         break;
    1612             :         case HTML_TABLEROW_ON:          // Before first cell in row
    1613             :         {
    1614           0 :             TableRowOn( pInfo );
    1615             :         }
    1616           0 :         break;
    1617             :         case HTML_TABLEROW_OFF:         // After last cell in row
    1618             :         {
    1619           0 :             TableRowOff( pInfo );
    1620             :         }
    1621           0 :         break;
    1622             :         case HTML_TABLE_OFF:
    1623             :         {
    1624           0 :             TableOff( pInfo );
    1625             :         }
    1626           0 :         break;
    1627             :         case HTML_IMAGE:
    1628             :         {
    1629           0 :             Image( pInfo );
    1630             :         }
    1631           0 :         break;
    1632             :         case HTML_PARABREAK_OFF:
    1633             :         {   // We continue vertically after an image
    1634           0 :             if ( pActEntry->maImageList.size() > 0 )
    1635           0 :                 pActEntry->maImageList.back().nDir = nVertical;
    1636             :         }
    1637           0 :         break;
    1638             :         case HTML_ANCHOR_ON:
    1639             :         {
    1640           0 :             AnchorOn( pInfo );
    1641             :         }
    1642           0 :         break;
    1643             :         case HTML_FONT_ON :
    1644             :         {
    1645           0 :             FontOn( pInfo );
    1646             :         }
    1647           0 :         break;
    1648             :         case HTML_BIGPRINT_ON :
    1649             :         {
    1650             :             // TODO: Remember current font size and increase by 1
    1651           0 :             if ( IsAtBeginningOfText( pInfo ) )
    1652             :                 pActEntry->aItemSet.Put( SvxFontHeightItem(
    1653           0 :                     maFontHeights[3], 100, ATTR_FONT_HEIGHT ) );
    1654             :         }
    1655           0 :         break;
    1656             :         case HTML_SMALLPRINT_ON :
    1657             :         {
    1658             :             // TODO: Remember current font size and decrease by 1
    1659           0 :             if ( IsAtBeginningOfText( pInfo ) )
    1660             :                 pActEntry->aItemSet.Put( SvxFontHeightItem(
    1661           0 :                     maFontHeights[0], 100, ATTR_FONT_HEIGHT ) );
    1662             :         }
    1663           0 :         break;
    1664             :         case HTML_BOLD_ON :
    1665             :         case HTML_STRONG_ON :
    1666             :         {
    1667           0 :             if ( IsAtBeginningOfText( pInfo ) )
    1668             :                 pActEntry->aItemSet.Put( SvxWeightItem( WEIGHT_BOLD,
    1669           0 :                     ATTR_FONT_WEIGHT ) );
    1670             :         }
    1671           0 :         break;
    1672             :         case HTML_ITALIC_ON :
    1673             :         case HTML_EMPHASIS_ON :
    1674             :         case HTML_ADDRESS_ON :
    1675             :         case HTML_BLOCKQUOTE_ON :
    1676             :         case HTML_BLOCKQUOTE30_ON :
    1677             :         case HTML_CITIATION_ON :
    1678             :         case HTML_VARIABLE_ON :
    1679             :         {
    1680           0 :             if ( IsAtBeginningOfText( pInfo ) )
    1681             :                 pActEntry->aItemSet.Put( SvxPostureItem( ITALIC_NORMAL,
    1682           0 :                     ATTR_FONT_POSTURE ) );
    1683             :         }
    1684           0 :         break;
    1685             :         case HTML_DEFINSTANCE_ON :
    1686             :         {
    1687           0 :             if ( IsAtBeginningOfText( pInfo ) )
    1688             :             {
    1689             :                 pActEntry->aItemSet.Put( SvxWeightItem( WEIGHT_BOLD,
    1690           0 :                     ATTR_FONT_WEIGHT ) );
    1691             :                 pActEntry->aItemSet.Put( SvxPostureItem( ITALIC_NORMAL,
    1692           0 :                     ATTR_FONT_POSTURE ) );
    1693             :             }
    1694             :         }
    1695           0 :         break;
    1696             :         case HTML_UNDERLINE_ON :
    1697             :         {
    1698           0 :             if ( IsAtBeginningOfText( pInfo ) )
    1699             :                 pActEntry->aItemSet.Put( SvxUnderlineItem( UNDERLINE_SINGLE,
    1700           0 :                     ATTR_FONT_UNDERLINE ) );
    1701             :         }
    1702           0 :         break;
    1703             :         case HTML_TEXTTOKEN:
    1704             :         {
    1705           0 :             if ( bInTitle )
    1706           0 :                 aString += pInfo->aText;
    1707             :         }
    1708           0 :         break;
    1709             :         default:
    1710             :         {   // Don't set nLastToken!
    1711           0 :             bSetLastToken = false;
    1712             :         }
    1713             :     }
    1714           0 :     if ( bSetLastToken )
    1715           0 :         nLastToken = pInfo->nToken;
    1716           0 : }
    1717             : 
    1718             : // HTML DATA QUERY PARSER
    1719             : 
    1720             : template< typename Type >
    1721           0 : inline Type getLimitedValue( const Type& rValue, const Type& rMin, const Type& rMax )
    1722           0 : { return ::std::max( ::std::min( rValue, rMax ), rMin ); }
    1723             : 
    1724          28 : ScHTMLEntry::ScHTMLEntry( const SfxItemSet& rItemSet, ScHTMLTableId nTableId ) :
    1725             :     ScEEParseEntry( rItemSet ),
    1726          28 :     mbImportAlways( false )
    1727             : {
    1728          28 :     nTab = nTableId;
    1729          28 :     bEntirePara = false;
    1730          28 : }
    1731             : 
    1732          40 : bool ScHTMLEntry::HasContents() const
    1733             : {
    1734          40 :      return mbImportAlways || aSel.HasRange() || !aAltText.isEmpty() || IsTable();
    1735             : }
    1736             : 
    1737           7 : void ScHTMLEntry::AdjustStart( const ImportInfo& rInfo )
    1738             : {
    1739             :     // set start position
    1740           7 :     aSel.nStartPara = rInfo.aSelection.nStartPara;
    1741           7 :     aSel.nStartPos = rInfo.aSelection.nStartPos;
    1742             :     // adjust end position
    1743           7 :     if( (aSel.nEndPara < aSel.nStartPara) || ((aSel.nEndPara == aSel.nStartPara) && (aSel.nEndPos < aSel.nStartPos)) )
    1744             :     {
    1745           0 :         aSel.nEndPara = aSel.nStartPara;
    1746           0 :         aSel.nEndPos = aSel.nStartPos;
    1747             :     }
    1748           7 : }
    1749             : 
    1750          32 : void ScHTMLEntry::AdjustEnd( const ImportInfo& rInfo )
    1751             : {
    1752             :     OSL_ENSURE( (aSel.nEndPara < rInfo.aSelection.nEndPara) ||
    1753             :                 ((aSel.nEndPara == rInfo.aSelection.nEndPara) && (aSel.nEndPos <= rInfo.aSelection.nEndPos)),
    1754             :                 "ScHTMLQueryParser::AdjustEntryEnd - invalid end position" );
    1755             :     // set end position
    1756          32 :     aSel.nEndPara = rInfo.aSelection.nEndPara;
    1757          32 :     aSel.nEndPos = rInfo.aSelection.nEndPos;
    1758          32 : }
    1759             : 
    1760          26 : void ScHTMLEntry::Strip( const EditEngine& rEditEngine )
    1761             : {
    1762             :     // strip leading empty paragraphs
    1763          58 :     while( (aSel.nStartPara < aSel.nEndPara) && (rEditEngine.GetTextLen( aSel.nStartPara ) <= aSel.nStartPos) )
    1764             :     {
    1765           6 :         ++aSel.nStartPara;
    1766           6 :         aSel.nStartPos = 0;
    1767             :     }
    1768             :     // strip trailing empty paragraphs
    1769          52 :     while( (aSel.nStartPara < aSel.nEndPara) && (aSel.nEndPos == 0) )
    1770             :     {
    1771           0 :         --aSel.nEndPara;
    1772           0 :         aSel.nEndPos = rEditEngine.GetTextLen( aSel.nEndPara );
    1773             :     }
    1774          26 : }
    1775             : 
    1776             : /** A map of ScHTMLTable objects.
    1777             : 
    1778             :     Organizes the tables with a unique table key. Stores nested tables inside
    1779             :     the parent table and forms in this way a tree structure of tables. An
    1780             :     instance of this class ownes the contained table objects and deletes them
    1781             :     on destruction.
    1782             :  */
    1783             : class ScHTMLTableMap
    1784             : {
    1785             : private:
    1786             :     typedef ::boost::shared_ptr< ScHTMLTable >          ScHTMLTablePtr;
    1787             :     typedef ::std::map< ScHTMLTableId, ScHTMLTablePtr > ScHTMLTableStdMap;
    1788             : 
    1789             : public:
    1790             :     typedef ScHTMLTableStdMap::iterator             iterator;
    1791             :     typedef ScHTMLTableStdMap::const_iterator       const_iterator;
    1792             : 
    1793             : private:
    1794             :     ScHTMLTable&        mrParentTable;      /// Reference to parent table.
    1795             :     ScHTMLTableStdMap   maTables;           /// Container for all table objects.
    1796             :     mutable ScHTMLTable* mpCurrTable;       /// Current table, used for fast search.
    1797             : 
    1798             : public:
    1799             :     explicit            ScHTMLTableMap( ScHTMLTable& rParentTable );
    1800             :     virtual             ~ScHTMLTableMap();
    1801             : 
    1802           4 :     inline const_iterator begin() const { return maTables.begin(); }
    1803           4 :     inline const_iterator end() const { return maTables.end(); }
    1804             : 
    1805             :     /** Returns the specified table.
    1806             :         @param nTableId  Unique identifier of the table.
    1807             :         @param bDeep  true = searches deep in all nested table; false = only in this container. */
    1808             :     ScHTMLTable*        FindTable( ScHTMLTableId nTableId, bool bDeep = true ) const;
    1809             : 
    1810             :     /** Inserts a new table into the container. This container owns the created table.
    1811             :         @param bPreFormText  true = New table is based on preformatted text (<pre> tag). */
    1812             :     ScHTMLTable*        CreateTable( const ImportInfo& rInfo, bool bPreFormText );
    1813             : 
    1814             : private:
    1815             :     /** Sets a working table with its index for search optimization. */
    1816           5 :     inline void         SetCurrTable( ScHTMLTable* pTable ) const
    1817           5 :                             { if( pTable ) mpCurrTable = pTable; }
    1818             : };
    1819             : 
    1820           1 : ScHTMLTableMap::ScHTMLTableMap( ScHTMLTable& rParentTable ) :
    1821             :     mrParentTable(rParentTable),
    1822           1 :     mpCurrTable(NULL)
    1823             : {
    1824           1 : }
    1825             : 
    1826           2 : ScHTMLTableMap::~ScHTMLTableMap()
    1827             : {
    1828           2 : }
    1829             : 
    1830           4 : ScHTMLTable* ScHTMLTableMap::FindTable( ScHTMLTableId nTableId, bool bDeep ) const
    1831             : {
    1832           4 :     ScHTMLTable* pResult = 0;
    1833           4 :     if( mpCurrTable && (nTableId == mpCurrTable->GetTableId()) )
    1834           3 :         pResult = mpCurrTable;              // cached table
    1835             :     else
    1836             :     {
    1837           1 :         const_iterator aFind = maTables.find( nTableId );
    1838           1 :         if( aFind != maTables.end() )
    1839           0 :             pResult = aFind->second.get();  // table from this container
    1840             :     }
    1841             : 
    1842             :     // not found -> search deep in nested tables
    1843           4 :     if( !pResult && bDeep )
    1844           2 :         for( const_iterator aIter = begin(), aEnd = end(); !pResult && (aIter != aEnd); ++aIter )
    1845           1 :             pResult = aIter->second->FindNestedTable( nTableId );
    1846             : 
    1847           4 :     SetCurrTable( pResult );
    1848           4 :     return pResult;
    1849             : }
    1850             : 
    1851           1 : ScHTMLTable* ScHTMLTableMap::CreateTable( const ImportInfo& rInfo, bool bPreFormText )
    1852             : {
    1853           1 :     ScHTMLTable* pTable = new ScHTMLTable( mrParentTable, rInfo, bPreFormText );
    1854           1 :     maTables[ pTable->GetTableId() ].reset( pTable );
    1855           1 :     SetCurrTable( pTable );
    1856           1 :     return pTable;
    1857             : }
    1858             : 
    1859             : /** Simplified forward iterator for convenience.
    1860             : 
    1861             :     Before the iterator can be dereferenced, it must be tested with the is()
    1862             :     method. The iterator may be invalid directly after construction (e.g. empty
    1863             :     container).
    1864             :  */
    1865             : class ScHTMLTableIterator
    1866             : {
    1867             : public:
    1868             :     /** Constructs the iterator for the passed table map.
    1869             :         @param pTableMap  Pointer to the table map (is allowed to be NULL). */
    1870             :     explicit            ScHTMLTableIterator( const ScHTMLTableMap* pTableMap );
    1871             : 
    1872           9 :     inline bool         is() const { return mpTableMap && maIter != maEnd; }
    1873           3 :     inline ScHTMLTable* operator->() { return maIter->second.get(); }
    1874           3 :     inline ScHTMLTableIterator& operator++() { ++maIter; return *this; }
    1875             : 
    1876             : private:
    1877             :     ScHTMLTableMap::const_iterator maIter;
    1878             :     ScHTMLTableMap::const_iterator maEnd;
    1879             :     const ScHTMLTableMap* mpTableMap;
    1880             : };
    1881             : 
    1882           6 : ScHTMLTableIterator::ScHTMLTableIterator( const ScHTMLTableMap* pTableMap ) :
    1883           6 :     mpTableMap(pTableMap)
    1884             : {
    1885           6 :     if( pTableMap )
    1886             :     {
    1887           3 :         maIter = pTableMap->begin();
    1888           3 :         maEnd = pTableMap->end();
    1889             :     }
    1890           6 : }
    1891             : 
    1892           2 : ScHTMLTableAutoId::ScHTMLTableAutoId( ScHTMLTableId& rnUnusedId ) :
    1893             :     mnTableId( rnUnusedId ),
    1894           2 :     mrnUnusedId( rnUnusedId )
    1895             : {
    1896           2 :     ++mrnUnusedId;
    1897           2 : }
    1898             : 
    1899           1 : ScHTMLTable::ScHTMLTable( ScHTMLTable& rParentTable, const ImportInfo& rInfo, bool bPreFormText ) :
    1900             :     mpParentTable( &rParentTable ),
    1901             :     maTableId( rParentTable.maTableId.mrnUnusedId ),
    1902           1 :     maTableItemSet( rParentTable.GetCurrItemSet() ),
    1903             :     mrEditEngine( rParentTable.mrEditEngine ),
    1904             :     mrEEParseList( rParentTable.mrEEParseList ),
    1905             :     mpCurrEntryList( 0 ),
    1906             :     maSize( 1, 1 ),
    1907             :     mpParser(rParentTable.mpParser),
    1908             :     mbBorderOn( false ),
    1909             :     mbPreFormText( bPreFormText ),
    1910             :     mbRowOn( false ),
    1911             :     mbDataOn( false ),
    1912           2 :     mbPushEmptyLine( false )
    1913             : {
    1914           1 :     if( mbPreFormText )
    1915             :     {
    1916           0 :         ImplRowOn();
    1917           0 :         ImplDataOn( ScHTMLSize( 1, 1 ) );
    1918             :     }
    1919             :     else
    1920             :     {
    1921           1 :         ProcessFormatOptions( maTableItemSet, rInfo );
    1922           1 :         const HTMLOptions& rOptions = static_cast<HTMLParser*>(rInfo.pParser)->GetOptions();
    1923           1 :         HTMLOptions::const_iterator itr = rOptions.begin(), itrEnd = rOptions.end();
    1924           1 :         for (; itr != itrEnd; ++itr)
    1925             :         {
    1926           0 :             switch( itr->GetToken() )
    1927             :             {
    1928             :                 case HTML_O_BORDER:
    1929           0 :                     mbBorderOn = itr->GetString().isEmpty() || (itr->GetNumber() != 0);
    1930           0 :                 break;
    1931             :                 case HTML_O_ID:
    1932           0 :                     maTableName = itr->GetString();
    1933           0 :                 break;
    1934             :             }
    1935             :         }
    1936             :     }
    1937             : 
    1938           1 :     CreateNewEntry( rInfo );
    1939           1 : }
    1940             : 
    1941           1 : ScHTMLTable::ScHTMLTable(
    1942             :     SfxItemPool& rPool,
    1943             :     EditEngine& rEditEngine,
    1944             :     ::std::vector< ScEEParseEntry* >& rEEParseList,
    1945             :     ScHTMLTableId& rnUnusedId, ScHTMLParser* pParser
    1946             : ) :
    1947             :     mpParentTable( 0 ),
    1948             :     maTableId( rnUnusedId ),
    1949             :     maTableItemSet( rPool ),
    1950             :     mrEditEngine( rEditEngine ),
    1951             :     mrEEParseList( rEEParseList ),
    1952             :     mpCurrEntryList( 0 ),
    1953             :     maSize( 1, 1 ),
    1954             :     mpParser(pParser),
    1955             :     mbBorderOn( false ),
    1956             :     mbPreFormText( false ),
    1957             :     mbRowOn( false ),
    1958             :     mbDataOn( false ),
    1959           1 :     mbPushEmptyLine( false )
    1960             : {
    1961             :     // open the first "cell" of the document
    1962           1 :     ImplRowOn();
    1963           1 :     ImplDataOn( ScHTMLSize( 1, 1 ) );
    1964           1 :     mxCurrEntry = CreateEntry();
    1965           1 : }
    1966             : 
    1967           3 : ScHTMLTable::~ScHTMLTable()
    1968             : {
    1969           3 : }
    1970             : 
    1971          28 : const SfxItemSet& ScHTMLTable::GetCurrItemSet() const
    1972             : {
    1973             :     // first try cell item set, then row item set, then table item set
    1974          28 :     return mxDataItemSet.get() ? *mxDataItemSet : (mxRowItemSet.get() ? *mxRowItemSet : maTableItemSet);
    1975             : }
    1976             : 
    1977          21 : ScHTMLSize ScHTMLTable::GetSpan( const ScHTMLPos& rCellPos ) const
    1978             : {
    1979          21 :     ScHTMLSize aSpan( 1, 1 );
    1980          21 :     const ScRange* pRange = NULL;
    1981          84 :     if(  ( (pRange = maVMergedCells.Find( rCellPos.MakeAddr() ) ) != 0)
    1982          84 :       || ( (pRange = maHMergedCells.Find( rCellPos.MakeAddr() ) ) != 0)
    1983             :       )
    1984           0 :         aSpan.Set( pRange->aEnd.Col() - pRange->aStart.Col() + 1, pRange->aEnd.Row() - pRange->aStart.Row() + 1 );
    1985          21 :     return aSpan;
    1986             : }
    1987             : 
    1988           3 : ScHTMLTable* ScHTMLTable::FindNestedTable( ScHTMLTableId nTableId ) const
    1989             : {
    1990           3 :     return mxNestedTables.get() ? mxNestedTables->FindTable( nTableId, true ) : 0;
    1991             : }
    1992             : 
    1993           0 : void ScHTMLTable::PutItem( const SfxPoolItem& rItem )
    1994             : {
    1995             :     OSL_ENSURE( mxCurrEntry.get(), "ScHTMLTable::PutItem - no current entry" );
    1996           0 :     if( mxCurrEntry.get() && mxCurrEntry->IsEmpty() )
    1997           0 :         mxCurrEntry->GetItemSet().Put( rItem );
    1998           0 : }
    1999             : 
    2000          13 : void ScHTMLTable::PutText( const ImportInfo& rInfo )
    2001             : {
    2002             :     OSL_ENSURE( mxCurrEntry.get(), "ScHTMLTable::PutText - no current entry" );
    2003          13 :     if( mxCurrEntry.get() )
    2004             :     {
    2005          13 :         if( !mxCurrEntry->HasContents() && IsSpaceCharInfo( rInfo ) )
    2006           7 :             mxCurrEntry->AdjustStart( rInfo );
    2007             :         else
    2008           6 :             mxCurrEntry->AdjustEnd( rInfo );
    2009             :     }
    2010          13 : }
    2011             : 
    2012           6 : void ScHTMLTable::InsertPara( const ImportInfo& rInfo )
    2013             : {
    2014           6 :     if( mxCurrEntry.get() && mbDataOn && !IsEmptyCell() )
    2015           0 :         mxCurrEntry->SetImportAlways();
    2016           6 :     PushEntry( rInfo );
    2017           6 :     CreateNewEntry( rInfo );
    2018           6 :     InsertLeadingEmptyLine();
    2019           6 : }
    2020             : 
    2021           0 : void ScHTMLTable::BreakOn()
    2022             : {
    2023             :     // empty line, if <br> is at start of cell
    2024           0 :     mbPushEmptyLine = !mbPreFormText && mbDataOn && IsEmptyCell();
    2025           0 : }
    2026             : 
    2027           0 : void ScHTMLTable::HeadingOn()
    2028             : {
    2029             :     // call directly, InsertPara() has not been called before
    2030           0 :     InsertLeadingEmptyLine();
    2031           0 : }
    2032             : 
    2033           6 : void ScHTMLTable::InsertLeadingEmptyLine()
    2034             : {
    2035             :     // empty line, if <p>, </p>, <h?>, or </h*> are not at start of cell
    2036           6 :     mbPushEmptyLine = !mbPreFormText && mbDataOn && !IsEmptyCell();
    2037           6 : }
    2038             : 
    2039           0 : void ScHTMLTable::AnchorOn()
    2040             : {
    2041             :     OSL_ENSURE( mxCurrEntry.get(), "ScHTMLTable::AnchorOn - no current entry" );
    2042             :     // don't skip entries with single hyperlinks
    2043           0 :     if( mxCurrEntry.get() )
    2044           0 :         mxCurrEntry->SetImportAlways();
    2045           0 : }
    2046             : 
    2047           1 : ScHTMLTable* ScHTMLTable::TableOn( const ImportInfo& rInfo )
    2048             : {
    2049           1 :     PushEntry( rInfo );
    2050           1 :     return InsertNestedTable( rInfo, false );
    2051             : }
    2052             : 
    2053           1 : ScHTMLTable* ScHTMLTable::TableOff( const ImportInfo& rInfo )
    2054             : {
    2055           1 :     return mbPreFormText ? this : CloseTable( rInfo );
    2056             : }
    2057             : 
    2058           0 : ScHTMLTable* ScHTMLTable::PreOn( const ImportInfo& rInfo )
    2059             : {
    2060           0 :     PushEntry( rInfo );
    2061           0 :     return InsertNestedTable( rInfo, true );
    2062             : }
    2063             : 
    2064           0 : ScHTMLTable* ScHTMLTable::PreOff( const ImportInfo& rInfo )
    2065             : {
    2066           0 :     return mbPreFormText ? CloseTable( rInfo ) : this;
    2067             : }
    2068             : 
    2069           2 : void ScHTMLTable::RowOn( const ImportInfo& rInfo )
    2070             : {
    2071           2 :     PushEntry( rInfo, true );
    2072           2 :     if( mpParentTable && !mbPreFormText )   // no rows allowed in global and preformatted tables
    2073             :     {
    2074           2 :         ImplRowOn();
    2075           2 :         ProcessFormatOptions( *mxRowItemSet, rInfo );
    2076             :     }
    2077           2 :     CreateNewEntry( rInfo );
    2078           2 : }
    2079             : 
    2080           2 : void ScHTMLTable::RowOff( const ImportInfo& rInfo )
    2081             : {
    2082           2 :     PushEntry( rInfo, true );
    2083           2 :     if( mpParentTable && !mbPreFormText )   // no rows allowed in global and preformatted tables
    2084           2 :         ImplRowOff();
    2085           2 :     CreateNewEntry( rInfo );
    2086           2 : }
    2087             : 
    2088             : namespace {
    2089             : 
    2090             : /**
    2091             :  * Decode a numbert format string stored in Excel-generated HTML's CSS
    2092             :  * region.
    2093             :  */
    2094           0 : OUString decodeNumberFormat(const OUString& rFmt)
    2095             : {
    2096           0 :     OUStringBuffer aBuf;
    2097           0 :     const sal_Unicode* p = rFmt.getStr();
    2098           0 :     sal_Int32 n = rFmt.getLength();
    2099           0 :     for (sal_Int32 i = 0; i < n; ++i, ++p)
    2100             :     {
    2101           0 :         if (*p == '\\')
    2102             :         {
    2103             :             // Skip '\'.
    2104           0 :             ++i;
    2105           0 :             ++p;
    2106             : 
    2107             :             // Parse all subsequent digits until first non-digit is found.
    2108           0 :             sal_Int32 nDigitCount = 0;
    2109           0 :             const sal_Unicode* p1 = p;
    2110           0 :             for (; i < n; ++i, ++p, ++nDigitCount)
    2111             :             {
    2112           0 :                 if (*p < '0' || '9' < *p)
    2113             :                 {
    2114           0 :                     --i;
    2115           0 :                     --p;
    2116           0 :                     break;
    2117             :                 }
    2118             : 
    2119             :             }
    2120           0 :             if (nDigitCount)
    2121             :             {
    2122             :                 // Hex-encoded character found. Decode it back into its
    2123             :                 // original character. An example of number format with
    2124             :                 // hex-encoded chars: "\0022$\0022\#\,\#\#0\.00"
    2125           0 :                 sal_uInt32 nVal = OUString(p1, nDigitCount).toUInt32(16);
    2126           0 :                 aBuf.append(static_cast<sal_Unicode>(nVal));
    2127             :             }
    2128             :         }
    2129             :         else
    2130           0 :             aBuf.append(*p);
    2131             :     }
    2132           0 :     return aBuf.makeStringAndClear();
    2133             : }
    2134             : 
    2135             : }
    2136             : 
    2137           6 : void ScHTMLTable::DataOn( const ImportInfo& rInfo )
    2138             : {
    2139           6 :     PushEntry( rInfo, true );
    2140           6 :     if( mpParentTable && !mbPreFormText )   // no cells allowed in global and preformatted tables
    2141             :     {
    2142             :         // read needed options from the <td> tag
    2143           6 :         ScHTMLSize aSpanSize( 1, 1 );
    2144          12 :         ::std::unique_ptr<OUString> pValStr, pNumStr;
    2145           6 :         const HTMLOptions& rOptions = static_cast<HTMLParser*>(rInfo.pParser)->GetOptions();
    2146           6 :         HTMLOptions::const_iterator itr = rOptions.begin(), itrEnd = rOptions.end();
    2147           6 :         sal_uInt32 nNumberFormat = NUMBERFORMAT_ENTRY_NOT_FOUND;
    2148           6 :         for (; itr != itrEnd; ++itr)
    2149             :         {
    2150           0 :             switch (itr->GetToken())
    2151             :             {
    2152             :                 case HTML_O_COLSPAN:
    2153           0 :                     aSpanSize.mnCols = static_cast<SCCOL>( getLimitedValue<sal_Int32>( itr->GetString().toInt32(), 1, 256 ) );
    2154           0 :                 break;
    2155             :                 case HTML_O_ROWSPAN:
    2156           0 :                     aSpanSize.mnRows = static_cast<SCROW>( getLimitedValue<sal_Int32>( itr->GetString().toInt32(), 1, 256 ) );
    2157           0 :                 break;
    2158             :                 case HTML_O_SDVAL:
    2159           0 :                     pValStr.reset(new OUString(itr->GetString()));
    2160           0 :                 break;
    2161             :                 case HTML_O_SDNUM:
    2162           0 :                     pNumStr.reset(new OUString(itr->GetString()));
    2163           0 :                 break;
    2164             :                 case HTML_O_CLASS:
    2165             :                 {
    2166             :                     // Pick up the number format associated with this class (if
    2167             :                     // any).
    2168           0 :                     OUString aElem("td");
    2169           0 :                     OUString aClass = itr->GetString();
    2170           0 :                     OUString aProp("mso-number-format");
    2171           0 :                     const ScHTMLStyles& rStyles = mpParser->GetStyles();
    2172           0 :                     const OUString& rVal = rStyles.getPropertyValue(aElem, aClass, aProp);
    2173           0 :                     if (!rVal.isEmpty())
    2174             :                     {
    2175           0 :                         OUString aNumFmt = decodeNumberFormat(rVal);
    2176             : 
    2177           0 :                         nNumberFormat = GetFormatTable()->GetEntryKey(aNumFmt);
    2178           0 :                         if (nNumberFormat == NUMBERFORMAT_ENTRY_NOT_FOUND)
    2179             :                         {
    2180           0 :                             sal_Int32 nErrPos  = 0;
    2181             :                             short nDummy;
    2182           0 :                             bool bValidFmt = GetFormatTable()->PutEntry(aNumFmt, nErrPos, nDummy, nNumberFormat);
    2183           0 :                             if (!bValidFmt)
    2184           0 :                                 nNumberFormat = NUMBERFORMAT_ENTRY_NOT_FOUND;
    2185           0 :                         }
    2186           0 :                     }
    2187             :                 }
    2188           0 :                 break;
    2189             :             }
    2190             :         }
    2191             : 
    2192           6 :         ImplDataOn( aSpanSize );
    2193             : 
    2194           6 :         if (nNumberFormat != NUMBERFORMAT_ENTRY_NOT_FOUND)
    2195           0 :             mxDataItemSet->Put( SfxUInt32Item(ATTR_VALUE_FORMAT, nNumberFormat) );
    2196             : 
    2197           6 :         ProcessFormatOptions( *mxDataItemSet, rInfo );
    2198           6 :         CreateNewEntry( rInfo );
    2199           6 :         mxCurrEntry->pValStr = pValStr.release();
    2200          12 :         mxCurrEntry->pNumStr = pNumStr.release();
    2201             :     }
    2202             :     else
    2203           0 :         CreateNewEntry( rInfo );
    2204           6 : }
    2205             : 
    2206           6 : void ScHTMLTable::DataOff( const ImportInfo& rInfo )
    2207             : {
    2208           6 :     PushEntry( rInfo, true );
    2209           6 :     if( mpParentTable && !mbPreFormText )   // no cells allowed in global and preformatted tables
    2210           6 :         ImplDataOff();
    2211           6 :     CreateNewEntry( rInfo );
    2212           6 : }
    2213             : 
    2214           1 : void ScHTMLTable::BodyOn( const ImportInfo& rInfo )
    2215             : {
    2216           1 :     bool bPushed = PushEntry( rInfo );
    2217           1 :     if( !mpParentTable )
    2218             :     {
    2219             :         // do not start new row, if nothing (no title) precedes the body.
    2220           1 :         if( bPushed || !mbRowOn )
    2221           0 :             ImplRowOn();
    2222           1 :         if( bPushed || !mbDataOn )
    2223           0 :             ImplDataOn( ScHTMLSize( 1, 1 ) );
    2224           1 :         ProcessFormatOptions( *mxDataItemSet, rInfo );
    2225             :     }
    2226           1 :     CreateNewEntry( rInfo );
    2227           1 : }
    2228             : 
    2229           1 : void ScHTMLTable::BodyOff( const ImportInfo& rInfo )
    2230             : {
    2231           1 :     PushEntry( rInfo );
    2232           1 :     if( !mpParentTable )
    2233             :     {
    2234           1 :         ImplDataOff();
    2235           1 :         ImplRowOff();
    2236             :     }
    2237           1 :     CreateNewEntry( rInfo );
    2238           1 : }
    2239             : 
    2240           1 : ScHTMLTable* ScHTMLTable::CloseTable( const ImportInfo& rInfo )
    2241             : {
    2242           1 :     if( mpParentTable )     // not allowed to close global table
    2243             :     {
    2244           1 :         PushEntry( rInfo, mbDataOn );
    2245           1 :         ImplDataOff();
    2246           1 :         ImplRowOff();
    2247           1 :         mpParentTable->PushTableEntry( GetTableId() );
    2248           1 :         mpParentTable->CreateNewEntry( rInfo );
    2249           1 :         if( mbPreFormText ) // enclose preformatted table with empty lines in parent table
    2250           0 :             mpParentTable->InsertLeadingEmptyLine();
    2251           1 :         return mpParentTable;
    2252             :     }
    2253           0 :     return this;
    2254             : }
    2255             : 
    2256           0 : SCCOLROW ScHTMLTable::GetDocSize( ScHTMLOrient eOrient, SCCOLROW nCellPos ) const
    2257             : {
    2258           0 :     const ScSizeVec& rSizes = maCumSizes[ eOrient ];
    2259           0 :     size_t nIndex = static_cast< size_t >( nCellPos );
    2260           0 :     if( nIndex >= rSizes.size() ) return 0;
    2261           0 :     return (nIndex == 0) ? rSizes.front() : (rSizes[ nIndex ] - rSizes[ nIndex - 1 ]);
    2262             : }
    2263             : 
    2264          28 : SCCOLROW ScHTMLTable::GetDocSize( ScHTMLOrient eOrient, SCCOLROW nCellBegin, SCCOLROW nCellEnd ) const
    2265             : {
    2266          28 :     const ScSizeVec& rSizes = maCumSizes[ eOrient ];
    2267          28 :     size_t nBeginIdx = static_cast< size_t >( ::std::max< SCCOLROW >( nCellBegin, 0 ) );
    2268          28 :     size_t nEndIdx = static_cast< size_t >( ::std::min< SCCOLROW >( nCellEnd, static_cast< SCCOLROW >( rSizes.size() ) ) );
    2269          28 :     if (nBeginIdx >= nEndIdx ) return 0;
    2270          21 :     return rSizes[ nEndIdx - 1 ] - ((nBeginIdx == 0) ? 0 : rSizes[ nBeginIdx - 1 ]);
    2271             : }
    2272             : 
    2273           9 : SCCOLROW ScHTMLTable::GetDocSize( ScHTMLOrient eOrient ) const
    2274             : {
    2275           9 :     const ScSizeVec& rSizes = maCumSizes[ eOrient ];
    2276           9 :     return rSizes.empty() ? 0 : rSizes.back();
    2277             : }
    2278             : 
    2279           7 : ScHTMLSize ScHTMLTable::GetDocSize( const ScHTMLPos& rCellPos ) const
    2280             : {
    2281           7 :     ScHTMLSize aCellSpan = GetSpan( rCellPos );
    2282             :     return ScHTMLSize(
    2283           7 :         static_cast< SCCOL >( GetDocSize( tdCol, rCellPos.mnCol, rCellPos.mnCol + aCellSpan.mnCols ) ),
    2284          14 :         static_cast< SCROW >( GetDocSize( tdRow, rCellPos.mnRow, rCellPos.mnRow + aCellSpan.mnRows ) ) );
    2285             : }
    2286             : 
    2287          14 : SCCOLROW ScHTMLTable::GetDocPos( ScHTMLOrient eOrient, SCCOLROW nCellPos ) const
    2288             : {
    2289          14 :     return maDocBasePos.Get( eOrient ) + GetDocSize( eOrient, 0, nCellPos );
    2290             : }
    2291             : 
    2292           7 : ScHTMLPos ScHTMLTable::GetDocPos( const ScHTMLPos& rCellPos ) const
    2293             : {
    2294             :     return ScHTMLPos(
    2295           7 :         static_cast< SCCOL >( GetDocPos( tdCol, rCellPos.mnCol ) ),
    2296          14 :         static_cast< SCROW >( GetDocPos( tdRow, rCellPos.mnRow ) ) );
    2297             : }
    2298             : 
    2299           1 : void ScHTMLTable::GetDocRange( ScRange& rRange ) const
    2300             : {
    2301           1 :     rRange.aStart = rRange.aEnd = maDocBasePos.MakeAddr();
    2302           1 :     rRange.aEnd.Move( static_cast< SCsCOL >( GetDocSize( tdCol ) ) - 1, static_cast< SCsROW >( GetDocSize( tdRow ) ) - 1, 0 );
    2303           1 : }
    2304             : 
    2305           2 : void ScHTMLTable::ApplyCellBorders( ScDocument* pDoc, const ScAddress& rFirstPos ) const
    2306             : {
    2307             :     OSL_ENSURE( pDoc, "ScHTMLTable::ApplyCellBorders - no document" );
    2308           2 :     if( pDoc && mbBorderOn )
    2309             :     {
    2310           0 :         const SCCOL nLastCol = maSize.mnCols - 1;
    2311           0 :         const SCROW nLastRow = maSize.mnRows - 1;
    2312           0 :         const long nOuterLine = DEF_LINE_WIDTH_2;
    2313           0 :         const long nInnerLine = DEF_LINE_WIDTH_0;
    2314           0 :         SvxBorderLine aOuterLine(0, nOuterLine, table::BorderLineStyle::SOLID);
    2315           0 :         SvxBorderLine aInnerLine(0, nInnerLine, table::BorderLineStyle::SOLID);
    2316           0 :         SvxBoxItem aBorderItem( ATTR_BORDER );
    2317             : 
    2318           0 :         for( SCCOL nCol = 0; nCol <= nLastCol; ++nCol )
    2319             :         {
    2320           0 :             SvxBorderLine* pLeftLine = (nCol == 0) ? &aOuterLine : &aInnerLine;
    2321           0 :             SvxBorderLine* pRightLine = (nCol == nLastCol) ? &aOuterLine : &aInnerLine;
    2322           0 :             SCCOL nCellCol1 = static_cast< SCCOL >( GetDocPos( tdCol, nCol ) ) + rFirstPos.Col();
    2323           0 :             SCCOL nCellCol2 = nCellCol1 + static_cast< SCCOL >( GetDocSize( tdCol, nCol ) ) - 1;
    2324           0 :             for( SCROW nRow = 0; nRow <= nLastRow; ++nRow )
    2325             :             {
    2326           0 :                 SvxBorderLine* pTopLine = (nRow == 0) ? &aOuterLine : &aInnerLine;
    2327           0 :                 SvxBorderLine* pBottomLine = (nRow == nLastRow) ? &aOuterLine : &aInnerLine;
    2328           0 :                 SCROW nCellRow1 = GetDocPos( tdRow, nRow ) + rFirstPos.Row();
    2329           0 :                 SCROW nCellRow2 = nCellRow1 + GetDocSize( tdRow, nRow ) - 1;
    2330           0 :                 for( SCCOL nCellCol = nCellCol1; nCellCol <= nCellCol2; ++nCellCol )
    2331             :                 {
    2332           0 :                     aBorderItem.SetLine( (nCellCol == nCellCol1) ? pLeftLine : 0, SvxBoxItemLine::LEFT );
    2333           0 :                     aBorderItem.SetLine( (nCellCol == nCellCol2) ? pRightLine : 0, SvxBoxItemLine::RIGHT );
    2334           0 :                     for( SCROW nCellRow = nCellRow1; nCellRow <= nCellRow2; ++nCellRow )
    2335             :                     {
    2336           0 :                         aBorderItem.SetLine( (nCellRow == nCellRow1) ? pTopLine : 0, SvxBoxItemLine::TOP );
    2337           0 :                         aBorderItem.SetLine( (nCellRow == nCellRow2) ? pBottomLine : 0, SvxBoxItemLine::BOTTOM );
    2338           0 :                         pDoc->ApplyAttr( nCellCol, nCellRow, rFirstPos.Tab(), aBorderItem );
    2339             :                     }
    2340             :                 }
    2341             :             }
    2342           0 :         }
    2343             :     }
    2344             : 
    2345           3 :     for( ScHTMLTableIterator aIter( mxNestedTables.get() ); aIter.is(); ++aIter )
    2346           1 :         aIter->ApplyCellBorders( pDoc, rFirstPos );
    2347           2 : }
    2348             : 
    2349           0 : SvNumberFormatter* ScHTMLTable::GetFormatTable()
    2350             : {
    2351           0 :     return mpParser->GetDoc().GetFormatTable();
    2352             : }
    2353             : 
    2354          28 : bool ScHTMLTable::IsEmptyCell() const
    2355             : {
    2356          28 :     return mpCurrEntryList && mpCurrEntryList->empty();
    2357             : }
    2358             : 
    2359          13 : bool ScHTMLTable::IsSpaceCharInfo( const ImportInfo& rInfo )
    2360             : {
    2361          13 :     return (rInfo.nToken == HTML_TEXTTOKEN) && (rInfo.aText.getLength() == 1) && (rInfo.aText[ 0 ] == ' ');
    2362             : }
    2363             : 
    2364          27 : ScHTMLTable::ScHTMLEntryPtr ScHTMLTable::CreateEntry() const
    2365             : {
    2366          27 :     return ScHTMLEntryPtr( new ScHTMLEntry( GetCurrItemSet() ) );
    2367             : }
    2368             : 
    2369          26 : void ScHTMLTable::CreateNewEntry( const ImportInfo& rInfo )
    2370             : {
    2371             :     OSL_ENSURE( !mxCurrEntry.get(), "ScHTMLTable::CreateNewEntry - old entry still present" );
    2372          26 :     mxCurrEntry = CreateEntry();
    2373          26 :     mxCurrEntry->aSel = rInfo.aSelection;
    2374          26 : }
    2375             : 
    2376           7 : void ScHTMLTable::ImplPushEntryToList( ScHTMLEntryList& rEntryList, ScHTMLEntryPtr& rxEntry )
    2377             : {
    2378             :     // HTML entry list does not own the entries
    2379           7 :     rEntryList.push_back( rxEntry.get() );
    2380             :     // mrEEParseList (reference to member of ScEEParser) owns the entries
    2381           7 :     mrEEParseList.push_back( rxEntry.release() );
    2382           7 : }
    2383             : 
    2384          27 : bool ScHTMLTable::PushEntry( ScHTMLEntryPtr& rxEntry )
    2385             : {
    2386          27 :     bool bPushed = false;
    2387          27 :     if( rxEntry.get() && rxEntry->HasContents() )
    2388             :     {
    2389           7 :         if( mpCurrEntryList )
    2390             :         {
    2391           7 :             if( mbPushEmptyLine )
    2392             :             {
    2393           0 :                 ScHTMLEntryPtr xEmptyEntry = CreateEntry();
    2394           0 :                 ImplPushEntryToList( *mpCurrEntryList, xEmptyEntry );
    2395           0 :                 mbPushEmptyLine = false;
    2396             :             }
    2397           7 :             ImplPushEntryToList( *mpCurrEntryList, rxEntry );
    2398           7 :             bPushed = true;
    2399             :         }
    2400           0 :         else if( mpParentTable )
    2401             :         {
    2402           0 :             bPushed = mpParentTable->PushEntry( rxEntry );
    2403             :         }
    2404             :         else
    2405             :         {
    2406             :             OSL_FAIL( "ScHTMLTable::PushEntry - cannot push entry, no parent found" );
    2407             :         }
    2408             :     }
    2409          27 :     return bPushed;
    2410             : }
    2411             : 
    2412          26 : bool ScHTMLTable::PushEntry( const ImportInfo& rInfo, bool bLastInCell )
    2413             : {
    2414             :     OSL_ENSURE( mxCurrEntry.get(), "ScHTMLTable::PushEntry - no current entry" );
    2415          26 :     bool bPushed = false;
    2416          26 :     if( mxCurrEntry.get() )
    2417             :     {
    2418          26 :         mxCurrEntry->AdjustEnd( rInfo );
    2419          26 :         mxCurrEntry->Strip( mrEditEngine );
    2420             : 
    2421             :         // import entry always, if it is the last in cell, and cell is still empty
    2422          26 :         if( bLastInCell && IsEmptyCell() )
    2423             :         {
    2424           0 :             mxCurrEntry->SetImportAlways();
    2425             :             // don't insert empty lines before single empty entries
    2426           0 :             if( mxCurrEntry->IsEmpty() )
    2427           0 :                 mbPushEmptyLine = false;
    2428             :         }
    2429             : 
    2430          26 :         bPushed = PushEntry( mxCurrEntry );
    2431          26 :         mxCurrEntry.reset();
    2432             :     }
    2433          26 :     return bPushed;
    2434             : }
    2435             : 
    2436           1 : bool ScHTMLTable::PushTableEntry( ScHTMLTableId nTableId )
    2437             : {
    2438             :     OSL_ENSURE( nTableId != SC_HTML_GLOBAL_TABLE, "ScHTMLTable::PushTableEntry - cannot push global table" );
    2439           1 :     bool bPushed = false;
    2440           1 :     if( nTableId != SC_HTML_GLOBAL_TABLE )
    2441             :     {
    2442           1 :         ScHTMLEntryPtr xEntry( new ScHTMLEntry( maTableItemSet, nTableId ) );
    2443           1 :         bPushed = PushEntry( xEntry );
    2444             :     }
    2445           1 :     return bPushed;
    2446             : }
    2447             : 
    2448          14 : ScHTMLTable* ScHTMLTable::GetExistingTable( ScHTMLTableId nTableId ) const
    2449             : {
    2450           2 :     ScHTMLTable* pTable = ((nTableId != SC_HTML_GLOBAL_TABLE) && mxNestedTables.get()) ?
    2451          16 :         mxNestedTables->FindTable( nTableId, false ) : 0;
    2452             :     OSL_ENSURE( pTable || (nTableId == SC_HTML_GLOBAL_TABLE), "ScHTMLTable::GetExistingTable - table not found" );
    2453          14 :     return pTable;
    2454             : }
    2455             : 
    2456           1 : ScHTMLTable* ScHTMLTable::InsertNestedTable( const ImportInfo& rInfo, bool bPreFormText )
    2457             : {
    2458           1 :     if( !mxNestedTables.get() )
    2459           1 :         mxNestedTables.reset( new ScHTMLTableMap( *this ) );
    2460           1 :     if( bPreFormText )      // enclose new preformatted table with empty lines
    2461           0 :         InsertLeadingEmptyLine();
    2462           1 :     return mxNestedTables->CreateTable( rInfo, bPreFormText );
    2463             : }
    2464             : 
    2465           7 : void ScHTMLTable::InsertNewCell( const ScHTMLSize& rSpanSize )
    2466             : {
    2467             :     ScRange* pRange;
    2468             : 
    2469             :     /*  Find an unused cell by skipping all merged ranges that cover the
    2470             :         current cell position stored in maCurrCell. */
    2471          14 :     while( ((pRange = maVMergedCells.Find( maCurrCell.MakeAddr() )) != 0) || ((pRange = maHMergedCells.Find( maCurrCell.MakeAddr() )) != 0) )
    2472           0 :         maCurrCell.mnCol = pRange->aEnd.Col() + 1;
    2473           7 :     mpCurrEntryList = &maEntryMap[ maCurrCell ];
    2474             : 
    2475             :     /*  If the new cell is merged horizontally, try to find collisions with
    2476             :         other vertically merged ranges. In this case, shrink existing
    2477             :         vertically merged ranges (do not shrink the new cell). */
    2478           7 :     SCCOL nColEnd = maCurrCell.mnCol + rSpanSize.mnCols;
    2479          14 :     for( ScAddress aAddr( maCurrCell.MakeAddr() ); aAddr.Col() < nColEnd; aAddr.IncCol() )
    2480           7 :         if( (pRange = maVMergedCells.Find( aAddr )) != 0 )
    2481           0 :             pRange->aEnd.SetRow( maCurrCell.mnRow - 1 );
    2482             : 
    2483             :     // insert the new range into the cell lists
    2484           7 :     ScRange aNewRange( maCurrCell.MakeAddr() );
    2485           7 :     aNewRange.aEnd.Move( rSpanSize.mnCols - 1, rSpanSize.mnRows - 1, 0 );
    2486           7 :     if( rSpanSize.mnRows > 1 )
    2487             :     {
    2488           0 :         maVMergedCells.Append( aNewRange );
    2489             :         /*  Do not insert vertically merged ranges into maUsedCells yet,
    2490             :             because they may be shrunken (see above). The final vertically
    2491             :             merged ranges are inserted in FillEmptyCells(). */
    2492             :     }
    2493             :     else
    2494             :     {
    2495           7 :         if( rSpanSize.mnCols > 1 )
    2496           0 :             maHMergedCells.Append( aNewRange );
    2497             :         /*  Insert horizontally merged ranges and single cells into
    2498             :             maUsedCells, they will not be changed anymore. */
    2499           7 :         maUsedCells.Join( aNewRange );
    2500             :     }
    2501             : 
    2502             :     // adjust table size
    2503           7 :     maSize.mnCols = ::std::max< SCCOL >( maSize.mnCols, aNewRange.aEnd.Col() + 1 );
    2504           7 :     maSize.mnRows = ::std::max< SCROW >( maSize.mnRows, aNewRange.aEnd.Row() + 1 );
    2505           7 : }
    2506             : 
    2507           3 : void ScHTMLTable::ImplRowOn()
    2508             : {
    2509           3 :     if( mbRowOn )
    2510           0 :         ImplRowOff();
    2511           3 :     mxRowItemSet.reset( new SfxItemSet( maTableItemSet ) );
    2512           3 :     maCurrCell.mnCol = 0;
    2513           3 :     mbRowOn = true;
    2514           3 :     mbDataOn = false;
    2515           3 : }
    2516             : 
    2517           4 : void ScHTMLTable::ImplRowOff()
    2518             : {
    2519           4 :     if( mbDataOn )
    2520           0 :         ImplDataOff();
    2521           4 :     if( mbRowOn )
    2522             :     {
    2523           3 :         mxRowItemSet.reset();
    2524           3 :         ++maCurrCell.mnRow;
    2525           3 :         mbRowOn = mbDataOn = false;
    2526             :     }
    2527           4 : }
    2528             : 
    2529           7 : void ScHTMLTable::ImplDataOn( const ScHTMLSize& rSpanSize )
    2530             : {
    2531           7 :     if( mbDataOn )
    2532           0 :         ImplDataOff();
    2533           7 :     if( !mbRowOn )
    2534           0 :         ImplRowOn();
    2535           7 :     mxDataItemSet.reset( new SfxItemSet( *mxRowItemSet ) );
    2536           7 :     InsertNewCell( rSpanSize );
    2537           7 :     mbDataOn = true;
    2538           7 :     mbPushEmptyLine = false;
    2539           7 : }
    2540             : 
    2541           8 : void ScHTMLTable::ImplDataOff()
    2542             : {
    2543           8 :     if( mbDataOn )
    2544             :     {
    2545           7 :         mxDataItemSet.reset();
    2546           7 :         ++maCurrCell.mnCol;
    2547           7 :         mpCurrEntryList = 0;
    2548           7 :         mbDataOn = false;
    2549             :     }
    2550           8 : }
    2551             : 
    2552          10 : void ScHTMLTable::ProcessFormatOptions( SfxItemSet& rItemSet, const ImportInfo& rInfo )
    2553             : {
    2554             :     // special handling for table header cells
    2555          10 :     if( rInfo.nToken == HTML_TABLEHEADER_ON )
    2556             :     {
    2557           0 :         rItemSet.Put( SvxWeightItem( WEIGHT_BOLD, ATTR_FONT_WEIGHT ) );
    2558           0 :         rItemSet.Put( SvxHorJustifyItem( SVX_HOR_JUSTIFY_CENTER, ATTR_HOR_JUSTIFY ) );
    2559             :     }
    2560             : 
    2561          10 :     const HTMLOptions& rOptions = static_cast<HTMLParser*>(rInfo.pParser)->GetOptions();
    2562          10 :     HTMLOptions::const_iterator itr = rOptions.begin(), itrEnd = rOptions.end();
    2563          10 :     for (; itr != itrEnd; ++itr)
    2564             :     {
    2565           0 :         switch( itr->GetToken() )
    2566             :         {
    2567             :             case HTML_O_ALIGN:
    2568             :             {
    2569           0 :                 SvxCellHorJustify eVal = SVX_HOR_JUSTIFY_STANDARD;
    2570           0 :                 const OUString& rOptVal = itr->GetString();
    2571           0 :                 if( rOptVal.equalsIgnoreAsciiCase( OOO_STRING_SVTOOLS_HTML_AL_right ) )
    2572           0 :                     eVal = SVX_HOR_JUSTIFY_RIGHT;
    2573           0 :                 else if( rOptVal.equalsIgnoreAsciiCase( OOO_STRING_SVTOOLS_HTML_AL_center ) )
    2574           0 :                     eVal = SVX_HOR_JUSTIFY_CENTER;
    2575           0 :                 else if( rOptVal.equalsIgnoreAsciiCase( OOO_STRING_SVTOOLS_HTML_AL_left ) )
    2576           0 :                     eVal = SVX_HOR_JUSTIFY_LEFT;
    2577           0 :                 if( eVal != SVX_HOR_JUSTIFY_STANDARD )
    2578           0 :                     rItemSet.Put( SvxHorJustifyItem( eVal, ATTR_HOR_JUSTIFY ) );
    2579             :             }
    2580           0 :             break;
    2581             : 
    2582             :             case HTML_O_VALIGN:
    2583             :             {
    2584           0 :                 SvxCellVerJustify eVal = SVX_VER_JUSTIFY_STANDARD;
    2585           0 :                 const OUString& rOptVal = itr->GetString();
    2586           0 :                 if( rOptVal.equalsIgnoreAsciiCase( OOO_STRING_SVTOOLS_HTML_VA_top ) )
    2587           0 :                     eVal = SVX_VER_JUSTIFY_TOP;
    2588           0 :                 else if( rOptVal.equalsIgnoreAsciiCase( OOO_STRING_SVTOOLS_HTML_VA_middle ) )
    2589           0 :                     eVal = SVX_VER_JUSTIFY_CENTER;
    2590           0 :                 else if( rOptVal.equalsIgnoreAsciiCase( OOO_STRING_SVTOOLS_HTML_VA_bottom ) )
    2591           0 :                     eVal = SVX_VER_JUSTIFY_BOTTOM;
    2592           0 :                 if( eVal != SVX_VER_JUSTIFY_STANDARD )
    2593           0 :                     rItemSet.Put( SvxVerJustifyItem( eVal, ATTR_VER_JUSTIFY ) );
    2594             :             }
    2595           0 :             break;
    2596             : 
    2597             :             case HTML_O_BGCOLOR:
    2598             :             {
    2599           0 :                 Color aColor;
    2600           0 :                 itr->GetColor( aColor );
    2601           0 :                 rItemSet.Put( SvxBrushItem( aColor, ATTR_BACKGROUND ) );
    2602             :             }
    2603           0 :             break;
    2604             :         }
    2605             :     }
    2606          10 : }
    2607             : 
    2608          14 : void ScHTMLTable::SetDocSize( ScHTMLOrient eOrient, SCCOLROW nCellPos, SCCOLROW nSize )
    2609             : {
    2610             :     OSL_ENSURE( nCellPos >= 0, "ScHTMLTable::SetDocSize - unexpected negative position" );
    2611          14 :     ScSizeVec& rSizes = maCumSizes[ eOrient ];
    2612          14 :     size_t nIndex = static_cast< size_t >( nCellPos );
    2613             :     // expand with height/width == 1
    2614          35 :     while( nIndex >= rSizes.size() )
    2615           7 :         rSizes.push_back( rSizes.empty() ? 1 : (rSizes.back() + 1) );
    2616             :     // update size of passed position and all following
    2617             :     // #i109987# only grow, don't shrink - use the largest needed size
    2618          14 :     SCsCOLROW nDiff = nSize - ((nIndex == 0) ? rSizes.front() : (rSizes[ nIndex ] - rSizes[ nIndex - 1 ]));
    2619          14 :     if( nDiff > 0 )
    2620           4 :         for( ScSizeVec::iterator aIt = rSizes.begin() + nIndex, aEnd = rSizes.end(); aIt != aEnd; ++aIt )
    2621           2 :             *aIt += nDiff;
    2622          14 : }
    2623             : 
    2624          14 : void ScHTMLTable::CalcNeededDocSize(
    2625             :         ScHTMLOrient eOrient, SCCOLROW nCellPos, SCCOLROW nCellSpan, SCCOLROW nRealDocSize )
    2626             : {
    2627          14 :     SCCOLROW nDiffSize = 0;
    2628             :     // in merged columns/rows: reduce needed size by size of leading columns
    2629          28 :     while( nCellSpan > 1 )
    2630             :     {
    2631           0 :         nDiffSize += GetDocSize( eOrient, nCellPos );
    2632           0 :         --nCellSpan;
    2633           0 :         ++nCellPos;
    2634             :     }
    2635             :     // set remaining needed size to last column/row
    2636          14 :     nRealDocSize -= ::std::min< SCCOLROW >( nRealDocSize - 1, nDiffSize );
    2637          14 :     SetDocSize( eOrient, nCellPos, nRealDocSize );
    2638          14 : }
    2639             : 
    2640           2 : void ScHTMLTable::FillEmptyCells()
    2641             : {
    2642           3 :     for( ScHTMLTableIterator aIter( mxNestedTables.get() ); aIter.is(); ++aIter )
    2643           1 :         aIter->FillEmptyCells();
    2644             : 
    2645             :     // insert the final vertically merged ranges into maUsedCells
    2646           2 :     for ( size_t i = 0, nRanges = maVMergedCells.size(); i < nRanges; ++i )
    2647             :     {
    2648           0 :         ScRange* pRange = maVMergedCells[ i ];
    2649           0 :         maUsedCells.Join( *pRange );
    2650             :     }
    2651             : 
    2652           5 :     for( ScAddress aAddr; aAddr.Row() < maSize.mnRows; aAddr.IncRow() )
    2653             :     {
    2654          10 :         for( aAddr.SetCol( 0 ); aAddr.Col() < maSize.mnCols; aAddr.IncCol() )
    2655             :         {
    2656           7 :             if( !maUsedCells.Find( aAddr ) )
    2657             :             {
    2658             :                 // create a range for the lock list (used to calc. cell span)
    2659           0 :                 ScRange aRange( aAddr );
    2660           0 :                 do
    2661             :                 {
    2662           0 :                     aRange.aEnd.IncCol();
    2663             :                 }
    2664           0 :                 while( (aRange.aEnd.Col() < maSize.mnCols) && !maUsedCells.Find( aRange.aEnd ) );
    2665           0 :                 aRange.aEnd.IncCol( -1 );
    2666           0 :                 maUsedCells.Join( aRange );
    2667             : 
    2668             :                 // insert a dummy entry
    2669           0 :                 ScHTMLEntryPtr xEntry = CreateEntry();
    2670           0 :                 ImplPushEntryToList( maEntryMap[ ScHTMLPos( aAddr ) ], xEntry );
    2671             :             }
    2672             :         }
    2673             :     }
    2674           2 : }
    2675             : 
    2676           2 : void ScHTMLTable::RecalcDocSize()
    2677             : {
    2678             :     // recalc table sizes recursively from inner to outer
    2679           3 :     for( ScHTMLTableIterator aIter( mxNestedTables.get() ); aIter.is(); ++aIter )
    2680           1 :         aIter->RecalcDocSize();
    2681             : 
    2682             :     /*  Two passes: first calculates the sizes of single columns/rows, then
    2683             :         the sizes of spanned columns/rows. This allows to fill nested tables
    2684             :         into merged cells optimally. */
    2685             :     static const sal_uInt16 PASS_SINGLE = 0;
    2686             :     static const sal_uInt16 PASS_SPANNED = 1;
    2687           6 :     for( sal_uInt16 nPass = PASS_SINGLE; nPass <= PASS_SPANNED; ++nPass )
    2688             :     {
    2689             :         // iterate through every table cell
    2690           4 :         ScHTMLEntryMap::const_iterator aMapIterEnd = maEntryMap.end();
    2691          18 :         for( ScHTMLEntryMap::const_iterator aMapIter = maEntryMap.begin(); aMapIter != aMapIterEnd; ++aMapIter )
    2692             :         {
    2693          14 :             const ScHTMLPos& rCellPos = aMapIter->first;
    2694          14 :             ScHTMLSize aCellSpan = GetSpan( rCellPos );
    2695             : 
    2696          14 :             const ScHTMLEntryList& rEntryList = aMapIter->second;
    2697          14 :             ScHTMLEntryList::const_iterator aListIter;
    2698          14 :             ScHTMLEntryList::const_iterator aListIterEnd = rEntryList.end();
    2699             : 
    2700             :             // process the dimension of the current cell in this pass?
    2701             :             // (pass is single and span is 1) or (pass is not single and span is not 1)
    2702          14 :             bool bProcessColWidth = ((nPass == PASS_SINGLE) == (aCellSpan.mnCols == 1));
    2703          14 :             bool bProcessRowHeight = ((nPass == PASS_SINGLE) == (aCellSpan.mnRows == 1));
    2704          14 :             if( bProcessColWidth || bProcessRowHeight )
    2705             :             {
    2706           7 :                 ScHTMLSize aDocSize( 1, 0 );    // resulting size of the cell in document
    2707             : 
    2708             :                 // expand the cell size for each cell parse entry
    2709          14 :                 for( aListIter = rEntryList.begin(); aListIter != aListIterEnd; ++aListIter )
    2710             :                 {
    2711           7 :                     ScHTMLTable* pTable = GetExistingTable( (*aListIter)->GetTableId() );
    2712             :                     // find entry with maximum width
    2713           7 :                     if( bProcessColWidth && pTable )
    2714           1 :                         aDocSize.mnCols = ::std::max( aDocSize.mnCols, static_cast< SCCOL >( pTable->GetDocSize( tdCol ) ) );
    2715             :                     // add up height of each entry
    2716           7 :                     if( bProcessRowHeight )
    2717           7 :                         aDocSize.mnRows += pTable ? pTable->GetDocSize( tdRow ) : 1;
    2718             :                 }
    2719           7 :                 if( !aDocSize.mnRows )
    2720           0 :                     aDocSize.mnRows = 1;
    2721             : 
    2722           7 :                 if( bProcessColWidth )
    2723           7 :                     CalcNeededDocSize( tdCol, rCellPos.mnCol, aCellSpan.mnCols, aDocSize.mnCols );
    2724           7 :                 if( bProcessRowHeight )
    2725           7 :                     CalcNeededDocSize( tdRow, rCellPos.mnRow, aCellSpan.mnRows, aDocSize.mnRows );
    2726             :             }
    2727             :         }
    2728             :     }
    2729           2 : }
    2730             : 
    2731           2 : void ScHTMLTable::RecalcDocPos( const ScHTMLPos& rBasePos )
    2732             : {
    2733           2 :     maDocBasePos = rBasePos;
    2734             :     // after the previous assignment it is allowed to call GetDocPos() methods
    2735             : 
    2736             :     // iterate through every table cell
    2737           2 :     ScHTMLEntryMap::iterator aMapIterEnd = maEntryMap.end();
    2738           9 :     for( ScHTMLEntryMap::iterator aMapIter = maEntryMap.begin(); aMapIter != aMapIterEnd; ++aMapIter )
    2739             :     {
    2740             :         // fixed doc position of the entire cell (first entry)
    2741           7 :         const ScHTMLPos aCellDocPos( GetDocPos( aMapIter->first ) );
    2742             :         // fixed doc size of the entire cell
    2743           7 :         const ScHTMLSize aCellDocSize( GetDocSize( aMapIter->first ) );
    2744             : 
    2745             :         // running doc position for single entries
    2746           7 :         ScHTMLPos aEntryDocPos( aCellDocPos );
    2747             : 
    2748           7 :         ScHTMLEntryList& rEntryList = aMapIter->second;
    2749           7 :         ScHTMLEntry* pEntry = 0;
    2750           7 :         ScHTMLEntryList::iterator aListIterEnd = rEntryList.end();
    2751          14 :         for( ScHTMLEntryList::iterator aListIter = rEntryList.begin(); aListIter != aListIterEnd; ++aListIter )
    2752             :         {
    2753           7 :             pEntry = *aListIter;
    2754           7 :             if( ScHTMLTable* pTable = GetExistingTable( pEntry->GetTableId() ) )
    2755             :             {
    2756           1 :                 pTable->RecalcDocPos( aEntryDocPos );   // recalc nested table
    2757           1 :                 pEntry->nCol = SCCOL_MAX;
    2758           1 :                 pEntry->nRow = SCROW_MAX;
    2759           1 :                 SCROW nTableRows = static_cast< SCROW >( pTable->GetDocSize( tdRow ) );
    2760             : 
    2761             :                 // use this entry to pad empty space right of table
    2762           1 :                 if( mpParentTable )     // ... but not in global table
    2763             :                 {
    2764           0 :                     SCCOL nStartCol = aEntryDocPos.mnCol + static_cast< SCCOL >( pTable->GetDocSize( tdCol ) );
    2765           0 :                     SCCOL nNextCol = aEntryDocPos.mnCol + aCellDocSize.mnCols;
    2766           0 :                     if( nStartCol < nNextCol )
    2767             :                     {
    2768           0 :                         pEntry->nCol = nStartCol;
    2769           0 :                         pEntry->nRow = aEntryDocPos.mnRow;
    2770           0 :                         pEntry->nColOverlap = nNextCol - nStartCol;
    2771           0 :                         pEntry->nRowOverlap = nTableRows;
    2772             :                     }
    2773             :                 }
    2774           1 :                 aEntryDocPos.mnRow += nTableRows;
    2775             :             }
    2776             :             else
    2777             :             {
    2778           6 :                 pEntry->nCol = aEntryDocPos.mnCol;
    2779           6 :                 pEntry->nRow = aEntryDocPos.mnRow;
    2780           6 :                 if( mpParentTable )    // do not merge in global table
    2781           6 :                     pEntry->nColOverlap = aCellDocSize.mnCols;
    2782           6 :                 ++aEntryDocPos.mnRow;
    2783             :             }
    2784             :         }
    2785             : 
    2786             :         // pEntry points now to last entry.
    2787           7 :         if( pEntry )
    2788             :         {
    2789           7 :             if( (pEntry == rEntryList.front()) && (pEntry->GetTableId() == SC_HTML_NO_TABLE) )
    2790             :             {
    2791             :                 // pEntry is the only entry in this cell - merge rows of cell with single non-table entry.
    2792           6 :                 pEntry->nRowOverlap = aCellDocSize.mnRows;
    2793             :             }
    2794             :             else
    2795             :             {
    2796             :                 // fill up incomplete entry lists
    2797           1 :                 SCROW nFirstUnusedRow = aCellDocPos.mnRow + aCellDocSize.mnRows;
    2798           2 :                 while( aEntryDocPos.mnRow < nFirstUnusedRow )
    2799             :                 {
    2800           0 :                     ScHTMLEntryPtr xDummyEntry( new ScHTMLEntry( pEntry->GetItemSet() ) );
    2801           0 :                     xDummyEntry->nCol = aEntryDocPos.mnCol;
    2802           0 :                     xDummyEntry->nRow = aEntryDocPos.mnRow;
    2803           0 :                     xDummyEntry->nColOverlap = aCellDocSize.mnCols;
    2804           0 :                     ImplPushEntryToList( rEntryList, xDummyEntry );
    2805           0 :                     ++aEntryDocPos.mnRow;
    2806           0 :                 }
    2807             :             }
    2808             :         }
    2809             :     }
    2810           2 : }
    2811             : 
    2812           1 : ScHTMLGlobalTable::ScHTMLGlobalTable(
    2813             :     SfxItemPool& rPool,
    2814             :     EditEngine& rEditEngine,
    2815             :     ::std::vector< ScEEParseEntry* >& rEEParseList,
    2816             :     ScHTMLTableId& rnUnusedId,
    2817             :     ScHTMLParser* pParser
    2818             : ) :
    2819           1 :     ScHTMLTable( rPool, rEditEngine, rEEParseList, rnUnusedId, pParser )
    2820             : {
    2821           1 : }
    2822             : 
    2823           2 : ScHTMLGlobalTable::~ScHTMLGlobalTable()
    2824             : {
    2825           2 : }
    2826             : 
    2827           1 : void ScHTMLGlobalTable::Recalc()
    2828             : {
    2829             :     // Fills up empty cells with a dummy entry. */
    2830           1 :     FillEmptyCells();
    2831             :     // recalc table sizes of all nested tables and this table
    2832           1 :     RecalcDocSize();
    2833             :     // recalc document positions of all entries in this table and in nested tables
    2834           1 :     RecalcDocPos( GetDocPos() );
    2835           1 : }
    2836             : 
    2837           1 : ScHTMLQueryParser::ScHTMLQueryParser( EditEngine* pEditEngine, ScDocument* pDoc ) :
    2838             :     ScHTMLParser( pEditEngine, pDoc ),
    2839             :     mnUnusedId( SC_HTML_GLOBAL_TABLE ),
    2840           1 :     mbTitleOn( false )
    2841             : {
    2842             :     mxGlobTable.reset(
    2843           1 :         new ScHTMLGlobalTable(*pPool, *pEdit, maList, mnUnusedId, this));
    2844           1 :     mpCurrTable = mxGlobTable.get();
    2845           1 : }
    2846             : 
    2847           2 : ScHTMLQueryParser::~ScHTMLQueryParser()
    2848             : {
    2849           2 : }
    2850             : 
    2851           1 : sal_uLong ScHTMLQueryParser::Read( SvStream& rStrm, const OUString& rBaseURL  )
    2852             : {
    2853           1 :     SvKeyValueIteratorRef xValues;
    2854           1 :     SvKeyValueIterator* pAttributes = 0;
    2855             : 
    2856           1 :     SfxObjectShell* pObjSh = mpDoc->GetDocumentShell();
    2857           1 :     if( pObjSh && pObjSh->IsLoading() )
    2858             :     {
    2859           1 :         pAttributes = pObjSh->GetHeaderAttributes();
    2860             :     }
    2861             :     else
    2862             :     {
    2863             :         /*  When not loading, set up fake HTTP headers to force the SfxHTMLParser
    2864             :             to use UTF8 (used when pasting from clipboard) */
    2865           0 :         const sal_Char* pCharSet = rtl_getBestMimeCharsetFromTextEncoding( RTL_TEXTENCODING_UTF8 );
    2866           0 :         if( pCharSet )
    2867             :         {
    2868           0 :             OUString aContentType = "text/html; charset=";
    2869           0 :             aContentType += OUString::createFromAscii( pCharSet );
    2870             : 
    2871           0 :             xValues = new SvKeyValueIterator;
    2872           0 :             xValues->Append( SvKeyValue( OUString( OOO_STRING_SVTOOLS_HTML_META_content_type ), aContentType ) );
    2873           0 :             pAttributes = xValues;
    2874             :         }
    2875             :     }
    2876             : 
    2877           1 :     Link<> aOldLink = pEdit->GetImportHdl();
    2878           1 :     pEdit->SetImportHdl( LINK( this, ScHTMLQueryParser, HTMLImportHdl ) );
    2879           1 :     sal_uLong nErr = pEdit->Read( rStrm, rBaseURL, EE_FORMAT_HTML, pAttributes );
    2880           1 :     pEdit->SetImportHdl( aOldLink );
    2881             : 
    2882           1 :     mxGlobTable->Recalc();
    2883           1 :     nColMax = static_cast< SCCOL >( mxGlobTable->GetDocSize( tdCol ) - 1 );
    2884           1 :     nRowMax = static_cast< SCROW >( mxGlobTable->GetDocSize( tdRow ) - 1 );
    2885             : 
    2886           1 :     return nErr;
    2887             : }
    2888             : 
    2889           1 : const ScHTMLTable* ScHTMLQueryParser::GetGlobalTable() const
    2890             : {
    2891           1 :     return mxGlobTable.get();
    2892             : }
    2893             : 
    2894          34 : void ScHTMLQueryParser::ProcessToken( const ImportInfo& rInfo )
    2895             : {
    2896          34 :     switch( rInfo.nToken )
    2897             :     {
    2898             : // --- meta data ---
    2899           0 :         case HTML_META:             MetaOn( rInfo );                break;  // <meta>
    2900             : 
    2901             : // --- title handling ---
    2902           0 :         case HTML_TITLE_ON:         TitleOn( rInfo );               break;  // <title>
    2903           0 :         case HTML_TITLE_OFF:        TitleOff( rInfo );              break;  // </title>
    2904             : 
    2905           0 :         case HTML_STYLE_ON:                                         break;
    2906           0 :         case HTML_STYLE_OFF:        ParseStyle(rInfo.aText);        break;
    2907             : 
    2908             : // --- body handling ---
    2909           1 :         case HTML_BODY_ON:          mpCurrTable->BodyOn( rInfo );   break;  // <body>
    2910           1 :         case HTML_BODY_OFF:         mpCurrTable->BodyOff( rInfo );  break;  // </body>
    2911             : 
    2912             : // --- insert text ---
    2913          13 :         case HTML_TEXTTOKEN:        InsertText( rInfo );            break;  // any text
    2914           0 :         case HTML_LINEBREAK:        mpCurrTable->BreakOn();         break;  // <br>
    2915             :         case HTML_HEAD1_ON:                                                 // <h1>
    2916             :         case HTML_HEAD2_ON:                                                 // <h2>
    2917             :         case HTML_HEAD3_ON:                                                 // <h3>
    2918             :         case HTML_HEAD4_ON:                                                 // <h4>
    2919             :         case HTML_HEAD5_ON:                                                 // <h5>
    2920             :         case HTML_HEAD6_ON:                                                 // <h6>
    2921           0 :         case HTML_PARABREAK_ON:     mpCurrTable->HeadingOn();       break;  // <p>
    2922             : 
    2923             : // --- misc. contents ---
    2924           0 :         case HTML_ANCHOR_ON:        mpCurrTable->AnchorOn();        break;  // <a>
    2925             : 
    2926             : // --- table handling ---
    2927           1 :         case HTML_TABLE_ON:         TableOn( rInfo );               break;  // <table>
    2928           1 :         case HTML_TABLE_OFF:        TableOff( rInfo );              break;  // </table>
    2929           2 :         case HTML_TABLEROW_ON:      mpCurrTable->RowOn( rInfo );    break;  // <tr>
    2930           2 :         case HTML_TABLEROW_OFF:     mpCurrTable->RowOff( rInfo );   break;  // </tr>
    2931             :         case HTML_TABLEHEADER_ON:                                           // <th>
    2932           6 :         case HTML_TABLEDATA_ON:     mpCurrTable->DataOn( rInfo );   break;  // <td>
    2933             :         case HTML_TABLEHEADER_OFF:                                          // </th>
    2934           6 :         case HTML_TABLEDATA_OFF:    mpCurrTable->DataOff( rInfo );  break;  // </td>
    2935           0 :         case HTML_PREFORMTXT_ON:    PreOn( rInfo );                 break;  // <pre>
    2936           0 :         case HTML_PREFORMTXT_OFF:   PreOff( rInfo );                break;  // </pre>
    2937             : 
    2938             : // --- formatting ---
    2939           0 :         case HTML_FONT_ON:          FontOn( rInfo );                break;  // <font>
    2940             : 
    2941             :         case HTML_BIGPRINT_ON:      // <big>
    2942             :             //! TODO: store current font size, use following size
    2943           0 :             mpCurrTable->PutItem( SvxFontHeightItem( maFontHeights[ 3 ], 100, ATTR_FONT_HEIGHT ) );
    2944           0 :         break;
    2945             :         case HTML_SMALLPRINT_ON:    // <small>
    2946             :             //! TODO: store current font size, use preceding size
    2947           0 :             mpCurrTable->PutItem( SvxFontHeightItem( maFontHeights[ 0 ], 100, ATTR_FONT_HEIGHT ) );
    2948           0 :         break;
    2949             : 
    2950             :         case HTML_BOLD_ON:          // <b>
    2951             :         case HTML_STRONG_ON:        // <strong>
    2952           0 :             mpCurrTable->PutItem( SvxWeightItem( WEIGHT_BOLD, ATTR_FONT_WEIGHT ) );
    2953           0 :         break;
    2954             : 
    2955             :         case HTML_ITALIC_ON:        // <i>
    2956             :         case HTML_EMPHASIS_ON:      // <em>
    2957             :         case HTML_ADDRESS_ON:       // <address>
    2958             :         case HTML_BLOCKQUOTE_ON:    // <blockquote>
    2959             :         case HTML_BLOCKQUOTE30_ON:  // <bq>
    2960             :         case HTML_CITIATION_ON:     // <cite>
    2961             :         case HTML_VARIABLE_ON:      // <var>
    2962           0 :             mpCurrTable->PutItem( SvxPostureItem( ITALIC_NORMAL, ATTR_FONT_POSTURE ) );
    2963           0 :         break;
    2964             : 
    2965             :         case HTML_DEFINSTANCE_ON:   // <dfn>
    2966           0 :             mpCurrTable->PutItem( SvxWeightItem( WEIGHT_BOLD, ATTR_FONT_WEIGHT ) );
    2967           0 :             mpCurrTable->PutItem( SvxPostureItem( ITALIC_NORMAL, ATTR_FONT_POSTURE ) );
    2968           0 :         break;
    2969             : 
    2970             :         case HTML_UNDERLINE_ON:     // <u>
    2971           0 :             mpCurrTable->PutItem( SvxUnderlineItem( UNDERLINE_SINGLE, ATTR_FONT_UNDERLINE ) );
    2972           0 :         break;
    2973             :     }
    2974          34 : }
    2975             : 
    2976          13 : void ScHTMLQueryParser::InsertText( const ImportInfo& rInfo )
    2977             : {
    2978          13 :     mpCurrTable->PutText( rInfo );
    2979          13 :     if( mbTitleOn )
    2980           0 :         maTitle.append(rInfo.aText);
    2981          13 : }
    2982             : 
    2983           0 : void ScHTMLQueryParser::FontOn( const ImportInfo& rInfo )
    2984             : {
    2985           0 :     const HTMLOptions& rOptions = static_cast<HTMLParser*>(rInfo.pParser)->GetOptions();
    2986           0 :     HTMLOptions::const_iterator itr = rOptions.begin(), itrEnd = rOptions.end();
    2987           0 :     for (; itr != itrEnd; ++itr)
    2988             :     {
    2989           0 :         switch( itr->GetToken() )
    2990             :         {
    2991             :             case HTML_O_FACE :
    2992             :             {
    2993           0 :                 const OUString& rFace = itr->GetString();
    2994           0 :                 OUString aFontName;
    2995           0 :                 sal_Int32 nPos = 0;
    2996           0 :                 while( nPos != -1 )
    2997             :                 {
    2998             :                     // font list separator: VCL = ';' HTML = ','
    2999           0 :                     OUString aFName = comphelper::string::strip(rFace.getToken(0, ',', nPos), ' ');
    3000           0 :                     aFontName = ScGlobal::addToken(aFontName, aFName, ';');
    3001           0 :                 }
    3002           0 :                 if ( !aFontName.isEmpty() )
    3003             :                     mpCurrTable->PutItem( SvxFontItem( FAMILY_DONTKNOW,
    3004           0 :                         aFontName, EMPTY_OUSTRING, PITCH_DONTKNOW,
    3005           0 :                         RTL_TEXTENCODING_DONTKNOW, ATTR_FONT ) );
    3006             :             }
    3007           0 :             break;
    3008             :             case HTML_O_SIZE :
    3009             :             {
    3010           0 :                 sal_uInt32 nSize = getLimitedValue< sal_uInt32 >( itr->GetNumber(), 1, SC_HTML_FONTSIZES );
    3011           0 :                 mpCurrTable->PutItem( SvxFontHeightItem( maFontHeights[ nSize - 1 ], 100, ATTR_FONT_HEIGHT ) );
    3012             :             }
    3013           0 :             break;
    3014             :             case HTML_O_COLOR :
    3015             :             {
    3016           0 :                 Color aColor;
    3017           0 :                 itr->GetColor( aColor );
    3018           0 :                 mpCurrTable->PutItem( SvxColorItem( aColor, ATTR_FONT_COLOR ) );
    3019             :             }
    3020           0 :             break;
    3021             :         }
    3022             :     }
    3023           0 : }
    3024             : 
    3025           0 : void ScHTMLQueryParser::MetaOn( const ImportInfo& rInfo )
    3026             : {
    3027           0 :     if( mpDoc->GetDocumentShell() )
    3028             :     {
    3029           0 :         HTMLParser* pParser = static_cast< HTMLParser* >( rInfo.pParser );
    3030             : 
    3031             :         uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
    3032           0 :             mpDoc->GetDocumentShell()->GetModel(), uno::UNO_QUERY_THROW);
    3033             :         pParser->ParseMetaOptions(
    3034           0 :             xDPS->getDocumentProperties(),
    3035           0 :             mpDoc->GetDocumentShell()->GetHeaderAttributes() );
    3036             :     }
    3037           0 : }
    3038             : 
    3039           0 : void ScHTMLQueryParser::TitleOn( const ImportInfo& /*rInfo*/ )
    3040             : {
    3041           0 :     mbTitleOn = true;
    3042           0 :     maTitle.makeStringAndClear();
    3043           0 : }
    3044             : 
    3045           0 : void ScHTMLQueryParser::TitleOff( const ImportInfo& rInfo )
    3046             : {
    3047           0 :     if( mbTitleOn )
    3048             :     {
    3049           0 :         OUString aTitle = maTitle.makeStringAndClear().trim();
    3050           0 :         if (!aTitle.isEmpty() && mpDoc->GetDocumentShell())
    3051             :         {
    3052             :             uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
    3053           0 :                 mpDoc->GetDocumentShell()->GetModel(), uno::UNO_QUERY_THROW);
    3054             : 
    3055           0 :             xDPS->getDocumentProperties()->setTitle(aTitle);
    3056             :         }
    3057           0 :         InsertText( rInfo );
    3058           0 :         mbTitleOn = false;
    3059             :     }
    3060           0 : }
    3061             : 
    3062           1 : void ScHTMLQueryParser::TableOn( const ImportInfo& rInfo )
    3063             : {
    3064           1 :     mpCurrTable = mpCurrTable->TableOn( rInfo );
    3065           1 : }
    3066             : 
    3067           1 : void ScHTMLQueryParser::TableOff( const ImportInfo& rInfo )
    3068             : {
    3069           1 :     mpCurrTable = mpCurrTable->TableOff( rInfo );
    3070           1 : }
    3071             : 
    3072           0 : void ScHTMLQueryParser::PreOn( const ImportInfo& rInfo )
    3073             : {
    3074           0 :     mpCurrTable = mpCurrTable->PreOn( rInfo );
    3075           0 : }
    3076             : 
    3077           0 : void ScHTMLQueryParser::PreOff( const ImportInfo& rInfo )
    3078             : {
    3079           0 :     mpCurrTable = mpCurrTable->PreOff( rInfo );
    3080           0 : }
    3081             : 
    3082           0 : void ScHTMLQueryParser::CloseTable( const ImportInfo& rInfo )
    3083             : {
    3084           0 :     mpCurrTable = mpCurrTable->CloseTable( rInfo );
    3085           0 : }
    3086             : 
    3087             : #if ENABLE_ORCUS
    3088             : 
    3089             : namespace {
    3090             : 
    3091             : /**
    3092             :  * Handler class for the CSS parser.
    3093             :  */
    3094           0 : class CSSHandler
    3095             : {
    3096             :     struct MemStr
    3097             :     {
    3098             :         const char* mp;
    3099             :         size_t      mn;
    3100             : 
    3101           0 :         MemStr() : mp(NULL), mn(0) {}
    3102           0 :         MemStr(const char* p, size_t n) : mp(p), mn(n) {}
    3103           0 :         MemStr& operator=(const MemStr& r)
    3104             :         {
    3105           0 :             mp = r.mp;
    3106           0 :             mn = r.mn;
    3107           0 :             return *this;
    3108             :         }
    3109             :     };
    3110             : 
    3111             :     typedef std::pair<MemStr, MemStr> SelectorName; // element : class
    3112             :     typedef std::vector<SelectorName> SelectorNames;
    3113             :     SelectorNames maSelectorNames; /// current selector names.
    3114             :     MemStr maPropName;  /// current property name.
    3115             :     MemStr maPropValue; /// current property value.
    3116             : 
    3117             :     ScHTMLStyles& mrStyles;
    3118             : public:
    3119           0 :     CSSHandler(ScHTMLStyles& rStyles) : mrStyles(rStyles) {}
    3120             : 
    3121           0 :     static void at_rule_name(const char* /*p*/, size_t /*n*/)
    3122             :     {
    3123             :         // TODO: For now, we ignore at-rule properties.
    3124           0 :     }
    3125             : 
    3126           0 :     void property_name(const char* p, size_t n)
    3127             :     {
    3128           0 :         maPropName = MemStr(p, n);
    3129           0 :     }
    3130             : 
    3131           0 :     void value(const char* p, size_t n)
    3132             :     {
    3133           0 :         maPropValue = MemStr(p, n);
    3134           0 :     }
    3135             : 
    3136           0 :     static void begin_parse() {}
    3137             : 
    3138           0 :     static void end_parse() {}
    3139             : 
    3140           0 :     static void begin_block() {}
    3141             : 
    3142           0 :     void end_block()
    3143             :     {
    3144           0 :         maSelectorNames.clear();
    3145           0 :     }
    3146             : 
    3147           0 :     static void begin_property() {}
    3148             : 
    3149           0 :     void end_property()
    3150             :     {
    3151           0 :         SelectorNames::const_iterator itr = maSelectorNames.begin(), itrEnd = maSelectorNames.end();
    3152           0 :         for (; itr != itrEnd; ++itr)
    3153             :         {
    3154             :             // Add this property to the collection for each selector.
    3155           0 :             const SelectorName& rSelName = *itr;
    3156           0 :             const MemStr& rElem = rSelName.first;
    3157           0 :             const MemStr& rClass = rSelName.second;
    3158           0 :             OUString aName(maPropName.mp, maPropName.mn, RTL_TEXTENCODING_UTF8);
    3159           0 :             OUString aValue(maPropValue.mp, maPropValue.mn, RTL_TEXTENCODING_UTF8);
    3160           0 :             mrStyles.add(rElem.mp, rElem.mn, rClass.mp, rClass.mn, aName, aValue);
    3161           0 :         }
    3162           0 :         maPropName = MemStr();
    3163           0 :         maPropValue = MemStr();
    3164           0 :     }
    3165             : 
    3166             :     // new members
    3167           0 :     static void simple_selector_type(const char* /*p*/, size_t /*n*/) {}
    3168             : 
    3169           0 :     static void simple_selector_class(const char* /*p*/, size_t /*n*/) {}
    3170             : 
    3171           0 :     static void simple_selector_pseudo_element(orcus::css::pseudo_element_t /*pe*/) {}
    3172             : 
    3173           0 :     static void simple_selector_pseudo_class(orcus::css::pseudo_class_t /*pc*/) {}
    3174             : 
    3175           0 :     static void simple_selector_id(const char* /*p*/, size_t /*n*/) {}
    3176             : 
    3177           0 :     static void end_simple_selector() {}
    3178             : 
    3179           0 :     static void end_selector() {}
    3180             : 
    3181           0 :     static void combinator(orcus::css::combinator_t /*combinator*/) {}
    3182             : 
    3183           0 :     static void rgb(uint8_t /*red*/ , uint8_t /*green*/ , uint8_t /*blue*/ ) {}
    3184             : 
    3185           0 :     static void rgba(uint8_t /*red*/ , uint8_t /*green*/ , uint8_t /*blue*/ , double /*alpha*/ ) {}
    3186             : 
    3187           0 :     static void hsl(uint8_t /*hue*/ , uint8_t /*sat*/ , uint8_t /*light*/ ) {}
    3188             : 
    3189           0 :     static void hsla(uint8_t /*hue*/ , uint8_t /*sat*/ , uint8_t /*light*/ , double /*alpha*/ ) {}
    3190             : 
    3191           0 :     static void url(const char* /*p*/, size_t /*n*/) {}
    3192             : 
    3193             : };
    3194             : 
    3195             : }
    3196             : 
    3197           0 : void ScHTMLQueryParser::ParseStyle(const OUString& rStrm)
    3198             : {
    3199           0 :     OString aStr = OUStringToOString(rStrm, RTL_TEXTENCODING_UTF8);
    3200           0 :     CSSHandler aHdl(GetStyles());
    3201           0 :     orcus::css_parser<CSSHandler> aParser(aStr.getStr(), aStr.getLength(), aHdl);
    3202             :     try
    3203             :     {
    3204           0 :         aParser.parse();
    3205             :     }
    3206           0 :     catch (const orcus::css::parse_error&)
    3207             :     {
    3208             :         // TODO: Parsing of CSS failed.  Do nothing for now.
    3209           0 :     }
    3210           0 : }
    3211             : 
    3212             : #else
    3213             : 
    3214             : void ScHTMLQueryParser::ParseStyle(const OUString&) {}
    3215             : 
    3216             : #endif
    3217             : 
    3218         110 : IMPL_LINK( ScHTMLQueryParser, HTMLImportHdl, const ImportInfo*, pInfo )
    3219             : {
    3220          55 :     switch( pInfo->eState )
    3221             :     {
    3222             :         case HTMLIMP_START:
    3223           1 :         break;
    3224             : 
    3225             :         case HTMLIMP_NEXTTOKEN:
    3226             :         case HTMLIMP_UNKNOWNATTR:
    3227          34 :             ProcessToken( *pInfo );
    3228          34 :         break;
    3229             : 
    3230             :         case HTMLIMP_INSERTPARA:
    3231           6 :             mpCurrTable->InsertPara( *pInfo );
    3232           6 :         break;
    3233             : 
    3234             :         case HTMLIMP_SETATTR:
    3235             :         case HTMLIMP_INSERTTEXT:
    3236             :         case HTMLIMP_INSERTFIELD:
    3237          13 :         break;
    3238             : 
    3239             :         case HTMLIMP_END:
    3240           2 :             while( mpCurrTable->GetTableId() != SC_HTML_GLOBAL_TABLE )
    3241           0 :                 CloseTable( *pInfo );
    3242           1 :         break;
    3243             : 
    3244             :         default:
    3245             :             OSL_FAIL( "ScHTMLQueryParser::HTMLImportHdl - unknown ImportInfo::eState" );
    3246             :     }
    3247          55 :     return 0;
    3248          30 : }
    3249             : 
    3250             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.11