LCOV - code coverage report
Current view: top level - sc/source/filter/rtf - rtfparse.cxx (source / functions) Hit Total Coverage
Test: commit 10e77ab3ff6f4314137acd6e2702a6e5c1ce1fae Lines: 1 193 0.5 %
Date: 2014-11-03 Functions: 2 14 14.3 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      11             :  *   Licensed to the Apache Software Foundation (ASF) under one or more
      12             :  *   contributor license agreements. See the NOTICE file distributed
      13             :  *   with this work for additional information regarding copyright
      14             :  *   ownership. The ASF licenses this file to you under the Apache
      15             :  *   License, Version 2.0 (the "License"); you may not use this file
      16             :  *   except in compliance with the License. You may obtain a copy of
      17             :  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
      18             :  */
      19             : 
      20             : #include "scitems.hxx"
      21             : #include <editeng/eeitem.hxx>
      22             : #include <editeng/editeng.hxx>
      23             : #include <editeng/fhgtitem.hxx>
      24             : #include <editeng/svxrtf.hxx>
      25             : #include <vcl/outdev.hxx>
      26             : #include <svtools/rtftoken.h>
      27             : 
      28             : #include "rtfparse.hxx"
      29             : #include "global.hxx"
      30             : #include "document.hxx"
      31             : #include "docpool.hxx"
      32             : 
      33             : #define SC_RTFTWIPTOL 10        // 10 Twips tolerance when determining columns
      34             : 
      35           0 : ScRTFParser::ScRTFParser( EditEngine* pEditP ) :
      36             :         ScEEParser( pEditP ),
      37             :         mnCurPos(0),
      38           0 :         pColTwips( new ScRTFColTwips ),
      39             :         pActDefault( NULL ),
      40             :         pDefMerge( NULL ),
      41             :         nStartAdjust( (sal_uLong)~0 ),
      42             :         nLastWidth(0),
      43           0 :         bNewDef( false )
      44             : {
      45             :     // RTF default FontSize 12Pt
      46           0 :     long nMM = OutputDevice::LogicToLogic( 12, MAP_POINT, MAP_100TH_MM );
      47           0 :     pPool->SetPoolDefaultItem( SvxFontHeightItem( nMM, 100, EE_CHAR_FONTHEIGHT ) );
      48             :     // Free-flying pInsDefault
      49           0 :     pInsDefault = new ScRTFCellDefault( pPool );
      50           0 : }
      51             : 
      52           0 : ScRTFParser::~ScRTFParser()
      53             : {
      54           0 :     delete pInsDefault;
      55           0 :     delete pColTwips;
      56           0 :     maDefaultList.clear();
      57           0 : }
      58             : 
      59           0 : sal_uLong ScRTFParser::Read( SvStream& rStream, const OUString& rBaseURL )
      60             : {
      61           0 :     Link aOldLink = pEdit->GetImportHdl();
      62           0 :     pEdit->SetImportHdl( LINK( this, ScRTFParser, RTFImportHdl ) );
      63           0 :     sal_uLong nErr = pEdit->Read( rStream, rBaseURL, EE_FORMAT_RTF );
      64           0 :     if ( nLastToken == RTF_PAR )
      65             :     {
      66           0 :         if ( !maList.empty() )
      67             :         {
      68           0 :             ScEEParseEntry* pE = maList.back();
      69           0 :             if (    // Completely empty
      70           0 :                 (  (  pE->aSel.nStartPara == pE->aSel.nEndPara
      71           0 :                    && pE->aSel.nStartPos  == pE->aSel.nEndPos
      72             :                    )
      73           0 :                 ||  // Empty paragraph
      74           0 :                    (  pE->aSel.nStartPara + 1 == pE->aSel.nEndPara
      75           0 :                    && pE->aSel.nStartPos      == pEdit->GetTextLen( pE->aSel.nStartPara )
      76           0 :                    && pE->aSel.nEndPos        == 0
      77             :                    )
      78             :                 )
      79             :                )
      80             :             {   // Don't take over the last paragraph
      81           0 :                 maList.pop_back();
      82             :             }
      83             :         }
      84             :     }
      85           0 :     ColAdjust();
      86           0 :     pEdit->SetImportHdl( aOldLink );
      87           0 :     return nErr;
      88             : }
      89             : 
      90           0 : void ScRTFParser::EntryEnd( ScEEParseEntry* pE, const ESelection& aSel )
      91             : {
      92             :     // Paragraph -2 strips the attached empty paragraph
      93           0 :     pE->aSel.nEndPara = aSel.nEndPara - 2;
      94             :     // Although it's called nEndPos, the last one is position + 1
      95           0 :     pE->aSel.nEndPos = pEdit->GetTextLen( aSel.nEndPara - 1 );
      96           0 : }
      97             : 
      98           0 : inline void ScRTFParser::NextRow()
      99             : {
     100           0 :     if ( nRowMax < ++nRowCnt )
     101           0 :         nRowMax = nRowCnt;
     102           0 : }
     103             : 
     104           0 : bool ScRTFParser::SeekTwips( sal_uInt16 nTwips, SCCOL* pCol )
     105             : {
     106           0 :     ScRTFColTwips::const_iterator it = pColTwips->find( nTwips );
     107           0 :     bool bFound = it != pColTwips->end();
     108           0 :     sal_uInt16 nPos = it - pColTwips->begin();
     109           0 :     *pCol = static_cast<SCCOL>(nPos);
     110           0 :     if ( bFound )
     111           0 :         return true;
     112           0 :     sal_uInt16 nCount = pColTwips->size();
     113           0 :     if ( !nCount )
     114           0 :         return false;
     115           0 :     SCCOL nCol = *pCol;
     116             :     // nCol is insertion position; the next one higher up is there (or not)
     117           0 :     if ( nCol < static_cast<SCCOL>(nCount) && (((*pColTwips)[nCol] - SC_RTFTWIPTOL) <= nTwips) )
     118           0 :         return true;
     119             :     // Not smaller than everything else? Then compare with the next lower one
     120           0 :     else if ( nCol != 0 && (((*pColTwips)[nCol-1] + SC_RTFTWIPTOL) >= nTwips) )
     121             :     {
     122           0 :         (*pCol)--;
     123           0 :         return true;
     124             :     }
     125           0 :     return false;
     126             : }
     127             : 
     128           0 : void ScRTFParser::ColAdjust()
     129             : {
     130           0 :     if ( nStartAdjust != (sal_uLong)~0 )
     131             :     {
     132           0 :         SCCOL nCol = 0;
     133             :         ScEEParseEntry* pE;
     134           0 :         for ( size_t i = nStartAdjust, nListSize = maList.size(); i < nListSize; ++ i )
     135             :         {
     136           0 :             pE = maList[ i ];
     137           0 :             if ( pE->nCol == 0 )
     138           0 :                 nCol = 0;
     139           0 :             pE->nCol = nCol;
     140           0 :             if ( pE->nColOverlap > 1 )
     141           0 :                 nCol = nCol + pE->nColOverlap; // Merged cells with \clmrg
     142             :             else
     143             :             {
     144           0 :                 SeekTwips( pE->nTwips, &nCol );
     145           0 :                 if ( ++nCol <= pE->nCol )
     146           0 :                     nCol = pE->nCol + 1; // Moved cell X
     147           0 :                 pE->nColOverlap = nCol - pE->nCol; // Merged cells without \clmrg
     148             :             }
     149           0 :             if ( nCol > nColMax )
     150           0 :                 nColMax = nCol;
     151             :         }
     152           0 :         nStartAdjust = (sal_uLong)~0;
     153           0 :         pColTwips->clear();
     154             :     }
     155           0 : }
     156             : 
     157           0 : IMPL_LINK( ScRTFParser, RTFImportHdl, ImportInfo*, pInfo )
     158             : {
     159           0 :     switch ( pInfo->eState )
     160             :     {
     161             :         case RTFIMP_NEXTTOKEN:
     162           0 :             ProcToken( pInfo );
     163           0 :             break;
     164             :         case RTFIMP_UNKNOWNATTR:
     165           0 :             ProcToken( pInfo );
     166           0 :             break;
     167             :         case RTFIMP_START:
     168             :         {
     169           0 :             SvxRTFParser* pParser = static_cast<SvxRTFParser*>(pInfo->pParser);
     170           0 :             pParser->SetAttrPool( pPool );
     171           0 :             RTFPardAttrMapIds& rMap = pParser->GetPardMap();
     172           0 :             rMap.nBrush = ATTR_BACKGROUND;
     173           0 :             rMap.nBox = ATTR_BORDER;
     174           0 :             rMap.nShadow = ATTR_SHADOW;
     175             :         }
     176           0 :             break;
     177             :         case RTFIMP_END:
     178           0 :             if ( pInfo->aSelection.nEndPos )
     179             :             {   // If still text: create last paragraph
     180           0 :                 pActDefault = NULL;
     181           0 :                 pInfo->nToken = RTF_PAR;
     182             :                 // EditEngine did not attach an empty paragraph anymore
     183             :                 // which EntryEnd could strip
     184           0 :                 pInfo->aSelection.nEndPara++;
     185           0 :                 ProcToken( pInfo );
     186             :             }
     187           0 :             break;
     188             :         case RTFIMP_SETATTR:
     189           0 :             break;
     190             :         case RTFIMP_INSERTTEXT:
     191           0 :             break;
     192             :         case RTFIMP_INSERTPARA:
     193           0 :             break;
     194             :         default:
     195             :             OSL_FAIL("unknown ImportInfo.eState");
     196             :     }
     197           0 :     return 0;
     198             : }
     199             : 
     200             : // Bad behavior:
     201             : // For RTF_INTBL or respectively at the start of the first RTF_CELL
     202             : // after RTF_CELLX if there was no RTF_INTBL
     203           0 : void ScRTFParser::NewCellRow( ImportInfo* /*pInfo*/ )
     204             : {
     205           0 :     if ( bNewDef )
     206             :     {
     207           0 :         bNewDef = false;
     208             :         // Not flush on the right? => new table
     209           0 :         if ( nLastWidth && !maDefaultList.empty() )
     210             :         {
     211           0 :             const ScRTFCellDefault& rD = maDefaultList.back();
     212           0 :             if (rD.nTwips != nLastWidth)
     213             :             {
     214             :                 SCCOL n1, n2;
     215           0 :                 if ( !(  SeekTwips( nLastWidth, &n1 )
     216           0 :                       && SeekTwips( rD.nTwips, &n2 )
     217           0 :                       && n1 == n2
     218           0 :                       )
     219             :                 )
     220             :                 {
     221           0 :                     ColAdjust();
     222             :                 }
     223             :             }
     224             :         }
     225             :         // Build up TwipCols only after nLastWidth comparison!
     226           0 :         for ( size_t i = 0, n = maDefaultList.size(); i < n; ++i )
     227             :         {
     228           0 :             const ScRTFCellDefault& rD = maDefaultList[i];
     229             :             SCCOL nCol;
     230           0 :             if ( !SeekTwips(rD.nTwips, &nCol) )
     231           0 :                 pColTwips->insert( rD.nTwips );
     232             :         }
     233             :     }
     234           0 :     pDefMerge = NULL;
     235           0 :     pActDefault = maDefaultList.empty() ? NULL : &maDefaultList[0];
     236           0 :     mnCurPos = 0;
     237             :     OSL_ENSURE( pActDefault, "NewCellRow: pActDefault==0" );
     238           0 : }
     239             : 
     240             : /*
     241             :     SW:
     242             :     ~~~
     243             :     [\par]
     244             :     \trowd \cellx \cellx ...
     245             :     \intbl \cell \cell ...
     246             :     \row
     247             :     [\par]
     248             :     [\trowd \cellx \cellx ...]
     249             :     \intbl \cell \cell ...
     250             :     \row
     251             :     [\par]
     252             : 
     253             :     M$-Word:
     254             :     ~~~~~~~~
     255             :     [\par]
     256             :     \trowd \cellx \cellx ...
     257             :     \intbl \cell \cell ...
     258             :     \intbl \row
     259             :     [\par]
     260             :     [\trowd \cellx \cellx ...]
     261             :     \intbl \cell \cell ...
     262             :     \intbl \row
     263             :     [\par]
     264             : 
     265             :  */
     266             : 
     267           0 : void ScRTFParser::ProcToken( ImportInfo* pInfo )
     268             : {
     269             :     ScEEParseEntry* pE;
     270           0 :     switch ( pInfo->nToken )
     271             :     {
     272             :         case RTF_TROWD:         // denotes table row defauls, before RTF_CELLX
     273             :         {
     274           0 :             if (!maDefaultList.empty())
     275           0 :                 nLastWidth = maDefaultList.back().nTwips;
     276             : 
     277           0 :             nColCnt = 0;
     278           0 :             maDefaultList.clear();
     279           0 :             pDefMerge = NULL;
     280           0 :             nLastToken = pInfo->nToken;
     281           0 :             mnCurPos = 0;
     282             :         }
     283           0 :         break;
     284             :         case RTF_CLMGF:         // The first cell of cells to be merged
     285             :         {
     286           0 :             pDefMerge = pInsDefault;
     287           0 :             nLastToken = pInfo->nToken;
     288             :         }
     289           0 :         break;
     290             :         case RTF_CLMRG:         // A cell to be merged with the preceding cell
     291             :         {
     292           0 :             if (!pDefMerge && !maDefaultList.empty())
     293             :             {
     294           0 :                 pDefMerge = &maDefaultList.back();
     295           0 :                 mnCurPos = maDefaultList.size() - 1;
     296             :             }
     297             :             OSL_ENSURE( pDefMerge, "RTF_CLMRG: pDefMerge==0" );
     298           0 :             if ( pDefMerge ) // Else broken RTF
     299           0 :                 pDefMerge->nColOverlap++;   // multiple successive ones possible
     300           0 :             pInsDefault->nColOverlap = 0;   // Flag: ignore these
     301           0 :             nLastToken = pInfo->nToken;
     302             :         }
     303           0 :         break;
     304             :         case RTF_CELLX:         // closes cell default
     305             :         {
     306           0 :             bNewDef = true;
     307           0 :             pInsDefault->nCol = nColCnt;
     308           0 :             pInsDefault->nTwips = pInfo->nTokenValue; // Right cell border
     309           0 :             maDefaultList.push_back( pInsDefault );
     310             :             // New free-flying pInsDefault
     311           0 :             pInsDefault = new ScRTFCellDefault( pPool );
     312           0 :             if ( ++nColCnt > nColMax )
     313           0 :                 nColMax = nColCnt;
     314           0 :             nLastToken = pInfo->nToken;
     315             :         }
     316           0 :         break;
     317             :         case RTF_INTBL:         // before the first RTF_CELL
     318             :         {
     319             :             // Once over NextToken and once over UnknownAttrToken
     320             :             // or e.g. \intbl ... \cell \pard \intbl ... \cell
     321           0 :             if ( nLastToken != RTF_INTBL && nLastToken != RTF_CELL && nLastToken != RTF_PAR )
     322             :             {
     323           0 :                 NewCellRow( pInfo );
     324           0 :                 nLastToken = pInfo->nToken;
     325             :             }
     326             :         }
     327           0 :         break;
     328             :         case RTF_CELL:          // denotes the end of a cell.
     329             :         {
     330             :             OSL_ENSURE( pActDefault, "RTF_CELL: pActDefault==0" );
     331           0 :             if ( bNewDef || !pActDefault )
     332           0 :                 NewCellRow( pInfo );    // davor war kein \intbl, bad behavior
     333             :             // Broken RTF? Let's save what we can
     334           0 :             if ( !pActDefault )
     335           0 :                 pActDefault = pInsDefault;
     336           0 :             if ( pActDefault->nColOverlap > 0 )
     337             :             {   // Not merged with preceding
     338           0 :                 pActEntry->nCol = pActDefault->nCol;
     339           0 :                 pActEntry->nColOverlap = pActDefault->nColOverlap;
     340           0 :                 pActEntry->nTwips = pActDefault->nTwips;
     341           0 :                 pActEntry->nRow = nRowCnt;
     342           0 :                 pActEntry->aItemSet.Set( pActDefault->aItemSet );
     343           0 :                 EntryEnd( pActEntry, pInfo->aSelection );
     344             : 
     345           0 :                 if ( nStartAdjust == (sal_uLong)~0 )
     346           0 :                     nStartAdjust = maList.size();
     347           0 :                 maList.push_back( pActEntry );
     348           0 :                 NewActEntry( pActEntry ); // New free-flying pActEntry
     349             :             }
     350             :             else
     351             :             {   // Assign current Twips to MergeCell
     352           0 :                 if ( !maList.empty() )
     353             :                 {
     354           0 :                     pE = maList.back();
     355           0 :                     pE->nTwips = pActDefault->nTwips;
     356             :                 }
     357             :                 // Adjust selection of free-flying pActEntry
     358             :                 // Paragraph -1 due to separated text in EditEngine during parsing
     359           0 :                 pActEntry->aSel.nStartPara = pInfo->aSelection.nEndPara - 1;
     360             :             }
     361             : 
     362           0 :             pActDefault = NULL;
     363           0 :             if (!maDefaultList.empty() && (mnCurPos+1) < maDefaultList.size())
     364           0 :                 pActDefault = &maDefaultList[++mnCurPos];
     365             : 
     366           0 :             nLastToken = pInfo->nToken;
     367             :         }
     368           0 :         break;
     369             :         case RTF_ROW:           // denotes the end of a row
     370             :         {
     371           0 :             NextRow();
     372           0 :             nLastToken = pInfo->nToken;
     373             :         }
     374           0 :         break;
     375             :         case RTF_PAR:           // Paragraph
     376             :         {
     377           0 :             if ( !pActDefault )
     378             :             {   // text not in table
     379           0 :                 ColAdjust();    // close the processing table
     380           0 :                 pActEntry->nCol = 0;
     381           0 :                 pActEntry->nRow = nRowCnt;
     382           0 :                 EntryEnd( pActEntry, pInfo->aSelection );
     383           0 :                 maList.push_back( pActEntry );
     384           0 :                 NewActEntry( pActEntry );   // new pActEntry
     385           0 :                 NextRow();
     386             :             }
     387           0 :             nLastToken = pInfo->nToken;
     388             :         }
     389           0 :         break;
     390             :         default:
     391             :         {   // do not set nLastToken
     392           0 :             switch ( pInfo->nToken & ~(0xff | RTF_TABLEDEF) )
     393             :             {
     394             :                 case RTF_SHADINGDEF:
     395             :                     static_cast<SvxRTFParser*>(pInfo->pParser)->ReadBackgroundAttr(
     396           0 :                         pInfo->nToken, pInsDefault->aItemSet, sal_True );
     397           0 :                 break;
     398             :                 case RTF_BRDRDEF:
     399             :                     static_cast<SvxRTFParser*>(pInfo->pParser)->ReadBorderAttr(
     400           0 :                         pInfo->nToken, pInsDefault->aItemSet, sal_True );
     401           0 :                 break;
     402             :             }
     403             :         }
     404             :     }
     405          48 : }
     406             : 
     407             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10