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

Generated by: LCOV version 1.10