LCOV - code coverage report
Current view: top level - sc/source/core/data - column2.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 1139 1564 72.8 %
Date: 2015-06-13 12:38:46 Functions: 111 144 77.1 %
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 "column.hxx"
      21             : #include "scitems.hxx"
      22             : #include "formulacell.hxx"
      23             : #include "document.hxx"
      24             : #include "docpool.hxx"
      25             : #include "drwlayer.hxx"
      26             : #include "attarray.hxx"
      27             : #include "patattr.hxx"
      28             : #include "cellform.hxx"
      29             : #include "stlsheet.hxx"
      30             : #include "rechead.hxx"
      31             : #include "brdcst.hxx"
      32             : #include "editutil.hxx"
      33             : #include "subtotal.hxx"
      34             : #include "markdata.hxx"
      35             : #include "compiler.hxx"
      36             : #include "dbdata.hxx"
      37             : #include "fillinfo.hxx"
      38             : #include "segmenttree.hxx"
      39             : #include "docparam.hxx"
      40             : #include "cellvalue.hxx"
      41             : #include "tokenarray.hxx"
      42             : #include "globalnames.hxx"
      43             : #include "formulagroup.hxx"
      44             : #include "listenercontext.hxx"
      45             : #include "mtvcellfunc.hxx"
      46             : #include "progress.hxx"
      47             : #include "scmatrix.hxx"
      48             : #include <rowheightcontext.hxx>
      49             : 
      50             : #include <math.h>
      51             : 
      52             : #include <editeng/eeitem.hxx>
      53             : 
      54             : #include <svx/algitem.hxx>
      55             : #include <editeng/editobj.hxx>
      56             : #include <editeng/editstat.hxx>
      57             : #include <editeng/emphasismarkitem.hxx>
      58             : #include <editeng/fhgtitem.hxx>
      59             : #include <editeng/forbiddencharacterstable.hxx>
      60             : #include <svx/rotmodit.hxx>
      61             : #include <editeng/scripttypeitem.hxx>
      62             : #include <editeng/unolingu.hxx>
      63             : #include <editeng/justifyitem.hxx>
      64             : #include <svl/zforlist.hxx>
      65             : #include <svl/broadcast.hxx>
      66             : #include <vcl/outdev.hxx>
      67             : #include <formula/errorcodes.hxx>
      68             : #include <formula/vectortoken.hxx>
      69             : 
      70             : #include <boost/scoped_ptr.hpp>
      71             : #include <algorithm>
      72             : 
      73             : // factor from font size to optimal cell height (text width)
      74             : #define SC_ROT_BREAK_FACTOR     6
      75             : 
      76       27751 : inline bool IsAmbiguousScript( SvtScriptType nScript )
      77             : {
      78             :     //TODO: move to a header file
      79           2 :     return ( nScript != SvtScriptType::LATIN &&
      80       27751 :              nScript != SvtScriptType::ASIAN &&
      81       27751 :              nScript != SvtScriptType::COMPLEX );
      82             : }
      83             : 
      84             : //  Data operations
      85             : 
      86        1548 : long ScColumn::GetNeededSize(
      87             :     SCROW nRow, OutputDevice* pDev, double nPPTX, double nPPTY,
      88             :     const Fraction& rZoomX, const Fraction& rZoomY,
      89             :     bool bWidth, const ScNeededSizeOptions& rOptions,
      90             :     const ScPatternAttr** ppPatternChange ) const
      91             : {
      92        1548 :     std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow);
      93        1548 :     sc::CellStoreType::const_iterator it = aPos.first;
      94        1548 :     if (it == maCells.end() || it->type == sc::element_type_empty)
      95             :         // Empty cell, or invalid row.
      96           0 :         return 0;
      97             : 
      98        1548 :     long nValue = 0;
      99        1548 :     ScRefCellValue aCell = GetCellValue(it, aPos.second);
     100        1548 :     double nPPT = bWidth ? nPPTX : nPPTY;
     101             : 
     102        1548 :     const ScPatternAttr* pPattern = rOptions.pPattern;
     103        1548 :     if (!pPattern)
     104          30 :         pPattern = pAttrArray->GetPattern( nRow );
     105             : 
     106             :     //      merged?
     107             :     //      Do not merge in conditional formatting
     108             : 
     109        1548 :     const ScMergeAttr*      pMerge = static_cast<const ScMergeAttr*>(&pPattern->GetItem(ATTR_MERGE));
     110        1548 :     const ScMergeFlagAttr*  pFlag = static_cast<const ScMergeFlagAttr*>(&pPattern->GetItem(ATTR_MERGE_FLAG));
     111             : 
     112        1548 :     if ( bWidth )
     113             :     {
     114         325 :         if ( pFlag->IsHorOverlapped() )
     115           0 :             return 0;
     116         325 :         if ( rOptions.bSkipMerged && pMerge->GetColMerge() > 1 )
     117           0 :             return 0;
     118             :     }
     119             :     else
     120             :     {
     121        1223 :         if ( pFlag->IsVerOverlapped() )
     122           0 :             return 0;
     123        1223 :         if ( rOptions.bSkipMerged && pMerge->GetRowMerge() > 1 )
     124           0 :             return 0;
     125             :     }
     126             : 
     127             :     //      conditional formatting
     128        1548 :     const SfxItemSet* pCondSet = pDocument->GetCondResult( nCol, nRow, nTab );
     129             : 
     130             :     //  line break?
     131             : 
     132             :     const SfxPoolItem* pCondItem;
     133             :     SvxCellHorJustify eHorJust;
     134        1548 :     if (pCondSet &&
     135           0 :             pCondSet->GetItemState(ATTR_HOR_JUSTIFY, true, &pCondItem) == SfxItemState::SET)
     136           0 :         eHorJust = (SvxCellHorJustify)static_cast<const SvxHorJustifyItem*>(pCondItem)->GetValue();
     137             :     else
     138             :         eHorJust = (SvxCellHorJustify)static_cast<const SvxHorJustifyItem&>(
     139        1548 :                                         pPattern->GetItem( ATTR_HOR_JUSTIFY )).GetValue();
     140             :     bool bBreak;
     141        1548 :     if ( eHorJust == SVX_HOR_JUSTIFY_BLOCK )
     142         385 :         bBreak = true;
     143        1163 :     else if ( pCondSet &&
     144           0 :                 pCondSet->GetItemState(ATTR_LINEBREAK, true, &pCondItem) == SfxItemState::SET)
     145           0 :         bBreak = static_cast<const SfxBoolItem*>(pCondItem)->GetValue();
     146             :     else
     147        1163 :         bBreak = static_cast<const SfxBoolItem&>(pPattern->GetItem(ATTR_LINEBREAK)).GetValue();
     148             : 
     149        1548 :     SvNumberFormatter* pFormatter = pDocument->GetFormatTable();
     150        1548 :     sal_uLong nFormat = pPattern->GetNumberFormat( pFormatter, pCondSet );
     151             :     // #i111387# disable automatic line breaks only for "General" number format
     152        1548 :     if (bBreak && ( nFormat % SV_COUNTRY_LANGUAGE_OFFSET ) == 0 )
     153             :     {
     154             :         // If a formula cell needs to be interpreted during aCell.hasNumeric()
     155             :         // to determine the type, the pattern may get invalidated because the
     156             :         // result may set a number format. In which case there's also the
     157             :         // General format not set anymore..
     158          66 :         bool bMayInvalidatePattern = (aCell.meType == CELLTYPE_FORMULA);
     159          66 :         const ScPatternAttr* pOldPattern = pPattern;
     160          66 :         bool bNumeric = aCell.hasNumeric();
     161          66 :         if (bMayInvalidatePattern)
     162             :         {
     163           0 :             pPattern = pAttrArray->GetPattern( nRow );
     164           0 :             if (ppPatternChange)
     165           0 :                 *ppPatternChange = pPattern;    // XXX caller may have to check for change!
     166             :         }
     167          66 :         if (bNumeric)
     168             :         {
     169           5 :             if (!bMayInvalidatePattern || pPattern == pOldPattern)
     170           5 :                 bBreak = false;
     171             :             else
     172             :             {
     173           0 :                 nFormat = pPattern->GetNumberFormat( pFormatter, pCondSet );
     174           0 :                 if ((nFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0)
     175           0 :                     bBreak = false;
     176             :             }
     177             :         }
     178             :     }
     179             : 
     180             :     //  get other attributes from pattern and conditional formatting
     181             : 
     182        1548 :     SvxCellOrientation eOrient = pPattern->GetCellOrientation( pCondSet );
     183        1550 :     bool bAsianVertical = ( eOrient == SVX_ORIENTATION_STACKED &&
     184        1550 :             static_cast<const SfxBoolItem&>(pPattern->GetItem( ATTR_VERTICAL_ASIAN, pCondSet )).GetValue() );
     185        1548 :     if ( bAsianVertical )
     186           0 :         bBreak = false;
     187             : 
     188        1548 :     if ( bWidth && bBreak )     // after determining bAsianVertical (bBreak may be reset)
     189           8 :         return 0;
     190             : 
     191        1540 :     long nRotate = 0;
     192        1540 :     SvxRotateMode eRotMode = SVX_ROTATE_MODE_STANDARD;
     193        1540 :     if ( eOrient == SVX_ORIENTATION_STANDARD )
     194             :     {
     195        1440 :         if (pCondSet &&
     196           0 :                 pCondSet->GetItemState(ATTR_ROTATE_VALUE, true, &pCondItem) == SfxItemState::SET)
     197           0 :             nRotate = static_cast<const SfxInt32Item*>(pCondItem)->GetValue();
     198             :         else
     199        1440 :             nRotate =static_cast<const SfxInt32Item&>(pPattern->GetItem(ATTR_ROTATE_VALUE)).GetValue();
     200        1440 :         if ( nRotate )
     201             :         {
     202         956 :             if (pCondSet &&
     203           0 :                     pCondSet->GetItemState(ATTR_ROTATE_MODE, true, &pCondItem) == SfxItemState::SET)
     204           0 :                 eRotMode = (SvxRotateMode)static_cast<const SvxRotateModeItem*>(pCondItem)->GetValue();
     205             :             else
     206             :                 eRotMode = (SvxRotateMode)static_cast<const SvxRotateModeItem&>(
     207         956 :                                             pPattern->GetItem(ATTR_ROTATE_MODE)).GetValue();
     208             : 
     209         956 :             if ( nRotate == 18000 )
     210           0 :                 eRotMode = SVX_ROTATE_MODE_STANDARD;    // no overflow
     211             :         }
     212             :     }
     213             : 
     214        1540 :     if ( eHorJust == SVX_HOR_JUSTIFY_REPEAT )
     215             :     {
     216             :         // ignore orientation/rotation if "repeat" is active
     217           0 :         eOrient = SVX_ORIENTATION_STANDARD;
     218           0 :         nRotate = 0;
     219           0 :         bAsianVertical = false;
     220             :     }
     221             : 
     222             :     const SvxMarginItem* pMargin;
     223        1540 :     if (pCondSet &&
     224           0 :             pCondSet->GetItemState(ATTR_MARGIN, true, &pCondItem) == SfxItemState::SET)
     225           0 :         pMargin = static_cast<const SvxMarginItem*>(pCondItem);
     226             :     else
     227        1540 :         pMargin = static_cast<const SvxMarginItem*>(&pPattern->GetItem(ATTR_MARGIN));
     228        1540 :     sal_uInt16 nIndent = 0;
     229        1540 :     if ( eHorJust == SVX_HOR_JUSTIFY_LEFT )
     230             :     {
     231         189 :         if (pCondSet &&
     232           0 :                 pCondSet->GetItemState(ATTR_INDENT, true, &pCondItem) == SfxItemState::SET)
     233           0 :             nIndent = static_cast<const SfxUInt16Item*>(pCondItem)->GetValue();
     234             :         else
     235         189 :             nIndent = static_cast<const SfxUInt16Item&>(pPattern->GetItem(ATTR_INDENT)).GetValue();
     236             :     }
     237             : 
     238        1540 :     SvtScriptType nScript = pDocument->GetScriptType(nCol, nRow, nTab);
     239        1540 :     if (nScript == SvtScriptType::NONE) nScript = ScGlobal::GetDefaultScriptType();
     240             : 
     241             :     //  also call SetFont for edit cells, because bGetFont may be set only once
     242             :     //  bGetFont is set also if script type changes
     243        1540 :     if (rOptions.bGetFont)
     244             :     {
     245        1540 :         Fraction aFontZoom = ( eOrient == SVX_ORIENTATION_STANDARD ) ? rZoomX : rZoomY;
     246        3080 :         vcl::Font aFont;
     247             :         // font color doesn't matter here
     248        1540 :         pPattern->GetFont( aFont, SC_AUTOCOL_BLACK, pDev, &aFontZoom, pCondSet, nScript );
     249        3080 :         pDev->SetFont(aFont);
     250             :     }
     251             : 
     252        1540 :     bool bAddMargin = true;
     253        1540 :     CellType eCellType = aCell.meType;
     254             : 
     255        1434 :     bool bEditEngine = (eCellType == CELLTYPE_EDIT ||
     256        1432 :                         eOrient == SVX_ORIENTATION_STACKED ||
     257        4512 :                         IsAmbiguousScript(nScript) ||
     258        1706 :                         ((eCellType == CELLTYPE_FORMULA) && aCell.mpFormula->IsMultilineResult()));
     259             : 
     260        1540 :     if (!bEditEngine)                                   // direct output
     261             :     {
     262             :         Color* pColor;
     263        1432 :         OUString aValStr;
     264             :         ScCellFormat::GetString(
     265        1432 :             aCell, nFormat, aValStr, &pColor, *pFormatter, pDocument, true, rOptions.bFormula, ftCheck);
     266             : 
     267        1432 :         if (!aValStr.isEmpty())
     268             :         {
     269             :             //  SetFont is moved up
     270             : 
     271        1432 :             Size aSize( pDev->GetTextWidth( aValStr ), pDev->GetTextHeight() );
     272        1432 :             if ( eOrient != SVX_ORIENTATION_STANDARD )
     273             :             {
     274          98 :                 long nTemp = aSize.Width();
     275          98 :                 aSize.Width() = aSize.Height();
     276          98 :                 aSize.Height() = nTemp;
     277             :             }
     278        1334 :             else if ( nRotate )
     279             :             {
     280             :                 //TODO: take different X/Y scaling into consideration
     281             : 
     282         955 :                 double nRealOrient = nRotate * F_PI18000;   // nRotate is in 1/100 Grad
     283         955 :                 double nCosAbs = fabs( cos( nRealOrient ) );
     284         955 :                 double nSinAbs = fabs( sin( nRealOrient ) );
     285         955 :                 long nHeight = (long)( aSize.Height() * nCosAbs + aSize.Width() * nSinAbs );
     286             :                 long nWidth;
     287         955 :                 if ( eRotMode == SVX_ROTATE_MODE_STANDARD )
     288         955 :                     nWidth  = (long)( aSize.Width() * nCosAbs + aSize.Height() * nSinAbs );
     289           0 :                 else if ( rOptions.bTotalSize )
     290             :                 {
     291           0 :                     nWidth = (long) ( pDocument->GetColWidth( nCol,nTab ) * nPPT );
     292           0 :                     bAddMargin = false;
     293             :                     //  only to the right:
     294             :                     //TODO: differ on direction up/down (only Text/whole height)
     295           0 :                     if ( pPattern->GetRotateDir( pCondSet ) == SC_ROTDIR_RIGHT )
     296           0 :                         nWidth += (long)( pDocument->GetRowHeight( nRow,nTab ) *
     297           0 :                                             nPPT * nCosAbs / nSinAbs );
     298             :                 }
     299             :                 else
     300           0 :                     nWidth  = (long)( aSize.Height() / nSinAbs );   //TODO: limit?
     301             : 
     302         955 :                 if ( bBreak && !rOptions.bTotalSize )
     303             :                 {
     304             :                     //  limit size for line break
     305         643 :                     long nCmp = pDev->GetFont().GetSize().Height() * SC_ROT_BREAK_FACTOR;
     306         643 :                     if ( nHeight > nCmp )
     307           0 :                         nHeight = nCmp;
     308             :                 }
     309             : 
     310         955 :                 aSize = Size( nWidth, nHeight );
     311             :             }
     312        1432 :             nValue = bWidth ? aSize.Width() : aSize.Height();
     313             : 
     314        1432 :             if ( bAddMargin )
     315             :             {
     316        1432 :                 if (bWidth)
     317             :                 {
     318         634 :                     nValue += (long) ( pMargin->GetLeftMargin() * nPPT ) +
     319         634 :                               (long) ( pMargin->GetRightMargin() * nPPT );
     320         317 :                     if ( nIndent )
     321           0 :                         nValue += (long) ( nIndent * nPPT );
     322             :                 }
     323             :                 else
     324        2230 :                     nValue += (long) ( pMargin->GetTopMargin() * nPPT ) +
     325        2230 :                               (long) ( pMargin->GetBottomMargin() * nPPT );
     326             :             }
     327             : 
     328             :             //  linebreak done ?
     329             : 
     330        1432 :             if ( bBreak && !bWidth )
     331             :             {
     332             :                 //  test with EditEngine the safety at 90%
     333             :                 //  (due to rounding errors and because EditEngine formats partially differently)
     334             : 
     335        1496 :                 long nDocPixel = (long) ( ( pDocument->GetColWidth( nCol,nTab ) -
     336        1496 :                                     pMargin->GetLeftMargin() - pMargin->GetRightMargin() -
     337             :                                     nIndent )
     338         748 :                                     * nPPT );
     339         748 :                 nDocPixel = (nDocPixel * 9) / 10;           // for safety
     340         748 :                 if ( aSize.Width() > nDocPixel )
     341         703 :                     bEditEngine = true;
     342             :             }
     343        1432 :         }
     344             :     }
     345             : 
     346        1540 :     if (bEditEngine)
     347             :     {
     348             :         //  the font is not reset each time with !bEditEngine
     349         811 :         vcl::Font aOldFont = pDev->GetFont();
     350             : 
     351        1622 :         MapMode aHMMMode( MAP_100TH_MM, Point(), rZoomX, rZoomY );
     352             : 
     353             :         // save in document ?
     354         811 :         ScFieldEditEngine* pEngine = pDocument->CreateFieldEditEngine();
     355             : 
     356         811 :         pEngine->SetUpdateMode( false );
     357         811 :         bool bTextWysiwyg = ( pDev->GetOutDevType() == OUTDEV_PRINTER );
     358         811 :         EEControlBits nCtrl = pEngine->GetControlWord();
     359         811 :         if ( bTextWysiwyg )
     360           0 :             nCtrl |= EEControlBits::FORMAT100;
     361             :         else
     362         811 :             nCtrl &= ~EEControlBits::FORMAT100;
     363         811 :         pEngine->SetControlWord( nCtrl );
     364        1622 :         MapMode aOld = pDev->GetMapMode();
     365         811 :         pDev->SetMapMode( aHMMMode );
     366         811 :         pEngine->SetRefDevice( pDev );
     367         811 :         pDocument->ApplyAsianEditSettings( *pEngine );
     368         811 :         SfxItemSet* pSet = new SfxItemSet( pEngine->GetEmptyItemSet() );
     369         811 :         if ( ScStyleSheet* pPreviewStyle = pDocument->GetPreviewCellStyle( nCol, nRow, nTab ) )
     370             :         {
     371           0 :             boost::scoped_ptr<ScPatternAttr> pPreviewPattern(new ScPatternAttr( *pPattern ));
     372           0 :             pPreviewPattern->SetStyleSheet(pPreviewStyle);
     373           0 :             pPreviewPattern->FillEditItemSet( pSet, pCondSet );
     374             :         }
     375             :         else
     376             :         {
     377         811 :             SfxItemSet* pFontSet = pDocument->GetPreviewFont( nCol, nRow, nTab );
     378         811 :             pPattern->FillEditItemSet( pSet, pFontSet ? pFontSet : pCondSet );
     379             :         }
     380             : //          no longer needed, are setted with the text (is faster)
     381             : //          pEngine->SetDefaults( pSet );
     382             : 
     383         811 :         if ( static_cast<const SfxBoolItem&>(pSet->Get(EE_PARA_HYPHENATE)).GetValue() ) {
     384             : 
     385         542 :             com::sun::star::uno::Reference<com::sun::star::linguistic2::XHyphenator> xXHyphenator( LinguMgr::GetHyphenator() );
     386         542 :             pEngine->SetHyphenator( xXHyphenator );
     387             :         }
     388             : 
     389         811 :         Size aPaper = Size( 1000000, 1000000 );
     390         811 :         if ( eOrient==SVX_ORIENTATION_STACKED && !bAsianVertical )
     391           2 :             aPaper.Width() = 1;
     392         809 :         else if (bBreak)
     393             :         {
     394         704 :             double fWidthFactor = nPPTX;
     395         704 :             if ( bTextWysiwyg )
     396             :             {
     397             :                 //  if text is formatted for printer, don't use PixelToLogic,
     398             :                 //  to ensure the exact same paper width (and same line breaks) as in
     399             :                 //  ScEditUtil::GetEditArea, used for output.
     400             : 
     401           0 :                 fWidthFactor = HMM_PER_TWIPS;
     402             :             }
     403             : 
     404             :             // use original width for hidden columns:
     405         704 :             long nDocWidth = (long) ( pDocument->GetOriginalWidth(nCol,nTab) * fWidthFactor );
     406         704 :             SCCOL nColMerge = pMerge->GetColMerge();
     407         704 :             if (nColMerge > 1)
     408           0 :                 for (SCCOL nColAdd=1; nColAdd<nColMerge; nColAdd++)
     409           0 :                     nDocWidth += (long) ( pDocument->GetColWidth(nCol+nColAdd,nTab) * fWidthFactor );
     410         704 :             nDocWidth -= (long) ( pMargin->GetLeftMargin() * fWidthFactor )
     411         704 :                        + (long) ( pMargin->GetRightMargin() * fWidthFactor )
     412         704 :                        + 1;     // output size is width-1 pixel (due to gridline)
     413         704 :             if ( nIndent )
     414          84 :                 nDocWidth -= (long) ( nIndent * fWidthFactor );
     415             : 
     416             :             // space for AutoFilter button:  20 * nZoom/100
     417         704 :             if ( pFlag->HasAutoFilter() && !bTextWysiwyg )
     418           0 :                 nDocWidth -= (rZoomX.GetNumerator()*20)/rZoomX.GetDenominator();
     419             : 
     420         704 :             aPaper.Width() = nDocWidth;
     421             : 
     422         704 :             if ( !bTextWysiwyg )
     423         704 :                 aPaper = pDev->PixelToLogic( aPaper, aHMMMode );
     424             :         }
     425         811 :         pEngine->SetPaperSize(aPaper);
     426             : 
     427         811 :         if (aCell.meType == CELLTYPE_EDIT)
     428             :         {
     429         106 :             pEngine->SetTextNewDefaults(*aCell.mpEditText, pSet);
     430             :         }
     431             :         else
     432             :         {
     433             :             Color* pColor;
     434         705 :             OUString aString;
     435             :             ScCellFormat::GetString(
     436             :                 aCell, nFormat, aString, &pColor, *pFormatter, pDocument, true,
     437         705 :                 rOptions.bFormula, ftCheck);
     438             : 
     439         705 :             if (!aString.isEmpty())
     440         705 :                 pEngine->SetTextNewDefaults(aString, pSet);
     441             :             else
     442           0 :                 pEngine->SetDefaults(pSet);
     443             :         }
     444             : 
     445         811 :         bool bEngineVertical = pEngine->IsVertical();
     446         811 :         pEngine->SetVertical( bAsianVertical );
     447         811 :         pEngine->SetUpdateMode( true );
     448             : 
     449         811 :         bool bEdWidth = bWidth;
     450         811 :         if ( eOrient != SVX_ORIENTATION_STANDARD && eOrient != SVX_ORIENTATION_STACKED )
     451          48 :             bEdWidth = !bEdWidth;
     452         811 :         if ( nRotate )
     453             :         {
     454             :             //TODO: take different X/Y scaling into consideration
     455             : 
     456         626 :             Size aSize( pEngine->CalcTextWidth(), pEngine->GetTextHeight() );
     457         626 :             double nRealOrient = nRotate * F_PI18000;   // nRotate is in 1/100 Grad
     458         626 :             double nCosAbs = fabs( cos( nRealOrient ) );
     459         626 :             double nSinAbs = fabs( sin( nRealOrient ) );
     460         626 :             long nHeight = (long)( aSize.Height() * nCosAbs + aSize.Width() * nSinAbs );
     461             :             long nWidth;
     462         626 :             if ( eRotMode == SVX_ROTATE_MODE_STANDARD )
     463         626 :                 nWidth  = (long)( aSize.Width() * nCosAbs + aSize.Height() * nSinAbs );
     464           0 :             else if ( rOptions.bTotalSize )
     465             :             {
     466           0 :                 nWidth = (long) ( pDocument->GetColWidth( nCol,nTab ) * nPPT );
     467           0 :                 bAddMargin = false;
     468           0 :                 if ( pPattern->GetRotateDir( pCondSet ) == SC_ROTDIR_RIGHT )
     469           0 :                     nWidth += (long)( pDocument->GetRowHeight( nRow,nTab ) *
     470           0 :                                         nPPT * nCosAbs / nSinAbs );
     471             :             }
     472             :             else
     473           0 :                 nWidth  = (long)( aSize.Height() / nSinAbs );   //TODO: limit?
     474         626 :             aSize = Size( nWidth, nHeight );
     475             : 
     476         626 :             Size aPixSize = pDev->LogicToPixel( aSize, aHMMMode );
     477         626 :             if ( bEdWidth )
     478           0 :                 nValue = aPixSize.Width();
     479             :             else
     480             :             {
     481         626 :                 nValue = aPixSize.Height();
     482             : 
     483         626 :                 if ( bBreak && !rOptions.bTotalSize )
     484             :                 {
     485             :                     //  limit size for line break
     486         626 :                     long nCmp = aOldFont.GetSize().Height() * SC_ROT_BREAK_FACTOR;
     487         626 :                     if ( nValue > nCmp )
     488           1 :                         nValue = nCmp;
     489             :                 }
     490             :             }
     491             :         }
     492         185 :         else if ( bEdWidth )
     493             :         {
     494          48 :             if (bBreak)
     495          48 :                 nValue = 0;
     496             :             else
     497           0 :                 nValue = pDev->LogicToPixel(Size( pEngine->CalcTextWidth(), 0 ),
     498           0 :                                     aHMMMode).Width();
     499             :         }
     500             :         else            // height
     501             :         {
     502         137 :             nValue = pDev->LogicToPixel(Size( 0, pEngine->GetTextHeight() ),
     503         137 :                                 aHMMMode).Height();
     504             : 
     505             :             // With non-100% zoom and several lines or paragraphs, don't shrink below the result with FORMAT100 set
     506         137 :             if ( !bTextWysiwyg && ( rZoomY.GetNumerator() != 1 || rZoomY.GetDenominator() != 1 ) &&
     507           0 :                  ( pEngine->GetParagraphCount() > 1 || ( bBreak && pEngine->GetLineCount(0) > 1 ) ) )
     508             :             {
     509           0 :                 pEngine->SetControlWord( nCtrl | EEControlBits::FORMAT100 );
     510           0 :                 pEngine->QuickFormatDoc( true );
     511           0 :                 long nSecondValue = pDev->LogicToPixel(Size( 0, pEngine->GetTextHeight() ), aHMMMode).Height();
     512           0 :                 if ( nSecondValue > nValue )
     513           0 :                     nValue = nSecondValue;
     514             :             }
     515             :         }
     516             : 
     517         811 :         if ( nValue && bAddMargin )
     518             :         {
     519         763 :             if (bWidth)
     520             :             {
     521           0 :                 nValue += (long) ( pMargin->GetLeftMargin() * nPPT ) +
     522           0 :                           (long) ( pMargin->GetRightMargin() * nPPT );
     523           0 :                 if (nIndent)
     524           0 :                     nValue += (long) ( nIndent * nPPT );
     525             :             }
     526             :             else
     527             :             {
     528        1526 :                 nValue += (long) ( pMargin->GetTopMargin() * nPPT ) +
     529        1526 :                           (long) ( pMargin->GetBottomMargin() * nPPT );
     530             : 
     531         763 :                 if ( bAsianVertical && pDev->GetOutDevType() != OUTDEV_PRINTER )
     532             :                 {
     533             :                     //  add 1pt extra (default margin value) for line breaks with SetVertical
     534           0 :                     nValue += (long) ( 20 * nPPT );
     535             :                 }
     536             :             }
     537             :         }
     538             : 
     539             :         //  EditEngine is cached and re-used, so the old vertical flag must be restored
     540         811 :         pEngine->SetVertical( bEngineVertical );
     541             : 
     542         811 :         pDocument->DisposeFieldEditEngine(pEngine);
     543             : 
     544         811 :         pDev->SetMapMode( aOld );
     545        1622 :         pDev->SetFont( aOldFont );
     546             :     }
     547             : 
     548        1540 :     if (bWidth)
     549             :     {
     550             :         //      place for Autofilter Button
     551             :         //      20 * nZoom/100
     552             :         //      Conditional formatting is not interesting here
     553             : 
     554         317 :         sal_Int16 nFlags = static_cast<const ScMergeFlagAttr&>(pPattern->GetItem(ATTR_MERGE_FLAG)).GetValue();
     555         317 :         if (nFlags & SC_MF_AUTO)
     556           0 :             nValue += (rZoomX.GetNumerator()*20)/rZoomX.GetDenominator();
     557             :     }
     558        1540 :     return nValue;
     559             : }
     560             : 
     561             : namespace {
     562             : 
     563          67 : class MaxStrLenFinder
     564             : {
     565             :     ScDocument& mrDoc;
     566             :     sal_uInt32 mnFormat;
     567             :     OUString maMaxLenStr;
     568             :     sal_Int32 mnMaxLen;
     569             : 
     570        1489 :     void checkLength(ScRefCellValue& rCell)
     571             :     {
     572             :         Color* pColor;
     573        1489 :         OUString aValStr;
     574             :         ScCellFormat::GetString(
     575        1489 :             rCell, mnFormat, aValStr, &pColor, *mrDoc.GetFormatTable(), &mrDoc, true, false, ftCheck);
     576             : 
     577        1489 :         if (aValStr.getLength() > mnMaxLen)
     578             :         {
     579          59 :             mnMaxLen = aValStr.getLength();
     580          59 :             maMaxLenStr = aValStr;
     581        1489 :         }
     582        1489 :     }
     583             : 
     584             : public:
     585          67 :     MaxStrLenFinder(ScDocument& rDoc, sal_uInt32 nFormat) :
     586          67 :         mrDoc(rDoc), mnFormat(nFormat), mnMaxLen(0) {}
     587             : 
     588        1473 :     void operator() (size_t /*nRow*/, double f)
     589             :     {
     590        1473 :         ScRefCellValue aCell(f);
     591        1473 :         checkLength(aCell);
     592        1473 :     }
     593             : 
     594        1116 :     void operator() (size_t /*nRow*/, const svl::SharedString& rSS)
     595             :     {
     596        1116 :         if (rSS.getLength() > mnMaxLen)
     597             :         {
     598          64 :             mnMaxLen = rSS.getLength();
     599          64 :             maMaxLenStr = rSS.getString();
     600             :         }
     601        1116 :     }
     602             : 
     603          16 :     void operator() (size_t /*nRow*/, const EditTextObject* p)
     604             :     {
     605          16 :         ScRefCellValue aCell(p);
     606          16 :         checkLength(aCell);
     607          16 :     }
     608             : 
     609           0 :     void operator() (size_t /*nRow*/, const ScFormulaCell* p)
     610             :     {
     611           0 :         ScRefCellValue aCell(const_cast<ScFormulaCell*>(p));
     612           0 :         checkLength(aCell);
     613           0 :     }
     614             : 
     615          67 :     const OUString& getMaxLenStr() const { return maMaxLenStr; }
     616             : };
     617             : 
     618             : }
     619             : 
     620          98 : sal_uInt16 ScColumn::GetOptimalColWidth(
     621             :     OutputDevice* pDev, double nPPTX, double nPPTY, const Fraction& rZoomX, const Fraction& rZoomY,
     622             :     bool bFormula, sal_uInt16 nOldWidth, const ScMarkData* pMarkData, const ScColWidthParam* pParam) const
     623             : {
     624          98 :     if (maCells.block_size() == 1 && maCells.begin()->type == sc::element_type_empty)
     625             :         // All cells are empty.
     626          13 :         return nOldWidth;
     627             : 
     628          85 :     sc::SingleColumnSpanSet aSpanSet;
     629         170 :     sc::SingleColumnSpanSet::SpansType aMarkedSpans;
     630          85 :     if (pMarkData && (pMarkData->IsMarked() || pMarkData->IsMultiMarked()))
     631             :     {
     632          77 :         aSpanSet.scan(*pMarkData, nTab, nCol);
     633          77 :         aSpanSet.getSpans(aMarkedSpans);
     634             :     }
     635             :     else
     636             :         // "Select" the entire column if no selection exists.
     637           8 :         aMarkedSpans.push_back(sc::RowSpan(0, MAXROW));
     638             : 
     639          85 :     sal_uInt16 nWidth = static_cast<sal_uInt16>(nOldWidth*nPPTX);
     640          85 :     bool bFound = false;
     641             : 
     642          85 :     if ( pParam && pParam->mbSimpleText )
     643             :     {   // all the same except for number format
     644          67 :         const ScPatternAttr* pPattern = GetPattern( 0 );
     645          67 :         vcl::Font aFont;
     646             :         // font color doesn't matter here
     647          67 :         pPattern->GetFont( aFont, SC_AUTOCOL_BLACK, pDev, &rZoomX, NULL );
     648          67 :         pDev->SetFont( aFont );
     649          67 :         const SvxMarginItem* pMargin = static_cast<const SvxMarginItem*>(&pPattern->GetItem(ATTR_MARGIN));
     650         134 :         long nMargin = (long) ( pMargin->GetLeftMargin() * nPPTX ) +
     651         134 :                         (long) ( pMargin->GetRightMargin() * nPPTX );
     652             : 
     653             :         // Try to find the row that has the longest string, and measure the width of that string.
     654          67 :         SvNumberFormatter* pFormatter = pDocument->GetFormatTable();
     655          67 :         sal_uInt32 nFormat = pPattern->GetNumberFormat( pFormatter );
     656         134 :         OUString aLongStr;
     657             :         Color* pColor;
     658          67 :         if (pParam->mnMaxTextRow >= 0)
     659             :         {
     660           0 :             ScRefCellValue aCell = GetCellValue(pParam->mnMaxTextRow);
     661             :             ScCellFormat::GetString(
     662           0 :                 aCell, nFormat, aLongStr, &pColor, *pFormatter, pDocument, true, false, ftCheck);
     663             :         }
     664             :         else
     665             :         {
     666             :             // Go though all non-empty cells within selection.
     667          67 :             MaxStrLenFinder aFunc(*pDocument, nFormat);
     668          67 :             sc::CellStoreType::const_iterator itPos = maCells.begin();
     669          67 :             sc::SingleColumnSpanSet::SpansType::const_iterator it = aMarkedSpans.begin(), itEnd = aMarkedSpans.end();
     670         134 :             for (; it != itEnd; ++it)
     671          67 :                 itPos = sc::ParseAllNonEmpty(itPos, maCells, it->mnRow1, it->mnRow2, aFunc);
     672             : 
     673          67 :             aLongStr = aFunc.getMaxLenStr();
     674             :         }
     675             : 
     676          67 :         if (!aLongStr.isEmpty())
     677             :         {
     678          67 :             nWidth = pDev->GetTextWidth(aLongStr) + static_cast<sal_uInt16>(nMargin);
     679          67 :             bFound = true;
     680          67 :         }
     681             :     }
     682             :     else
     683             :     {
     684          18 :         ScNeededSizeOptions aOptions;
     685          18 :         aOptions.bFormula = bFormula;
     686          18 :         const ScPatternAttr* pOldPattern = NULL;
     687          18 :         SvtScriptType nOldScript = SvtScriptType::NONE;
     688             : 
     689             :         // Go though all non-empty cells within selection.
     690          18 :         sc::CellStoreType::const_iterator itPos = maCells.begin();
     691          18 :         sc::SingleColumnSpanSet::SpansType::const_iterator it = aMarkedSpans.begin(), itEnd = aMarkedSpans.end();
     692          36 :         for (; it != itEnd; ++it)
     693             :         {
     694          18 :             SCROW nRow1 = it->mnRow1, nRow2 = it->mnRow2;
     695          18 :             SCROW nRow = nRow1;
     696         101 :             while (nRow <= nRow2)
     697             :             {
     698          65 :                 std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(itPos, nRow);
     699          65 :                 itPos = aPos.first;
     700          65 :                 if (itPos->type == sc::element_type_empty)
     701             :                 {
     702             :                     // Skip empty cells.
     703          32 :                     nRow += itPos->size - aPos.second;
     704          32 :                     continue;
     705             :                 }
     706             : 
     707         328 :                 for (size_t nOffset = aPos.second; nOffset < itPos->size; ++nOffset, ++nRow)
     708             :                 {
     709         295 :                     SvtScriptType nScript = pDocument->GetScriptType(nCol, nRow, nTab);
     710         295 :                     if (nScript == SvtScriptType::NONE)
     711           0 :                         nScript = ScGlobal::GetDefaultScriptType();
     712             : 
     713         295 :                     const ScPatternAttr* pPattern = GetPattern(nRow);
     714         295 :                     aOptions.pPattern = pPattern;
     715         295 :                     aOptions.bGetFont = (pPattern != pOldPattern || nScript != nOldScript);
     716         295 :                     pOldPattern = pPattern;
     717             :                     sal_uInt16 nThis = (sal_uInt16) GetNeededSize(
     718         295 :                         nRow, pDev, nPPTX, nPPTY, rZoomX, rZoomY, true, aOptions, &pOldPattern);
     719         295 :                     if (nThis)
     720             :                     {
     721         287 :                         if (nThis > nWidth || !bFound)
     722             :                         {
     723          26 :                             nWidth = nThis;
     724          26 :                             bFound = true;
     725             :                         }
     726             :                     }
     727             :                 }
     728             :             }
     729             :         }
     730             :     }
     731             : 
     732          85 :     if (bFound)
     733             :     {
     734          85 :         nWidth += 2;
     735          85 :         sal_uInt16 nTwips = (sal_uInt16) (nWidth / nPPTX);
     736          85 :         return nTwips;
     737             :     }
     738             :     else
     739          85 :         return nOldWidth;
     740             : }
     741             : 
     742      751336 : static sal_uInt16 lcl_GetAttribHeight( const ScPatternAttr& rPattern, sal_uInt16 nFontHeightId )
     743             : {
     744             :     const SvxFontHeightItem& rFontHeight =
     745      751336 :         static_cast<const SvxFontHeightItem&>(rPattern.GetItem(nFontHeightId));
     746             : 
     747      751336 :     sal_uInt16 nHeight = rFontHeight.GetHeight();
     748      751336 :     nHeight *= 1.18;
     749             : 
     750      751336 :     if ( static_cast<const SvxEmphasisMarkItem&>(rPattern.
     751      751336 :             GetItem(ATTR_FONT_EMPHASISMARK)).GetEmphasisMark() != EMPHASISMARK_NONE )
     752             :     {
     753             :         //  add height for emphasis marks
     754             :         //TODO: font metrics should be used instead
     755         670 :         nHeight += nHeight / 4;
     756             :     }
     757             : 
     758             :     const SvxMarginItem& rMargin =
     759      751336 :         static_cast<const SvxMarginItem&>(rPattern.GetItem(ATTR_MARGIN));
     760             : 
     761      751336 :     nHeight += rMargin.GetTopMargin() + rMargin.GetBottomMargin();
     762             : 
     763      751336 :     if (nHeight > STD_ROWHEIGHT_DIFF)
     764      751336 :         nHeight -= STD_ROWHEIGHT_DIFF;
     765             : 
     766      751336 :     if (nHeight < ScGlobal::nStdRowHeight)
     767      599177 :         nHeight = ScGlobal::nStdRowHeight;
     768             : 
     769      751336 :     return nHeight;
     770             : }
     771             : 
     772             : //  pHeight in Twips
     773             : //  optimize nMinHeight, nMinStart : with nRow >= nMinStart is at least nMinHeight
     774             : //  (is only evaluated with bStdAllowed)
     775             : 
     776      844800 : void ScColumn::GetOptimalHeight(
     777             :     sc::RowHeightContext& rCxt, SCROW nStartRow, SCROW nEndRow, sal_uInt16 nMinHeight, SCROW nMinStart )
     778             : {
     779      844800 :     std::vector<sal_uInt16>& rHeights = rCxt.getHeightArray();
     780      844800 :     ScAttrIterator aIter( pAttrArray, nStartRow, nEndRow );
     781             : 
     782      844800 :     SCROW nStart = -1;
     783      844800 :     SCROW nEnd = -1;
     784      844800 :     SCROW nEditPos = 0;
     785      844800 :     SCROW nNextEnd = 0;
     786             : 
     787             :     //  with conditional formatting, always consider the individual cells
     788             : 
     789      844800 :     const ScPatternAttr* pPattern = aIter.Next(nStart,nEnd);
     790     2537446 :     while ( pPattern )
     791             :     {
     792      847846 :         const ScMergeAttr*      pMerge = static_cast<const ScMergeAttr*>(&pPattern->GetItem(ATTR_MERGE));
     793      847846 :         const ScMergeFlagAttr*  pFlag = static_cast<const ScMergeFlagAttr*>(&pPattern->GetItem(ATTR_MERGE_FLAG));
     794      847846 :         if ( pMerge->GetRowMerge() > 1 || pFlag->IsOverlapped() )
     795             :         {
     796             :             //  do nothing - vertically with merged and overlapping,
     797             :             //        horizontally only with overlapped (invisible) -
     798             :             //        only one horizontal merged is always considered
     799             :         }
     800             :         else
     801             :         {
     802      847817 :             bool bStdAllowed = (pPattern->GetCellOrientation() == SVX_ORIENTATION_STANDARD);
     803      847817 :             bool bStdOnly = false;
     804      847817 :             if (bStdAllowed)
     805             :             {
     806     1470361 :                 bool bBreak = static_cast<const SfxBoolItem&>(pPattern->GetItem(ATTR_LINEBREAK)).GetValue() ||
     807             :                                 ((SvxCellHorJustify)static_cast<const SvxHorJustifyItem&>(pPattern->
     808      718920 :                                     GetItem( ATTR_HOR_JUSTIFY )).GetValue() ==
     809      751441 :                                     SVX_HOR_JUSTIFY_BLOCK);
     810      751441 :                 bStdOnly = !bBreak;
     811             : 
     812             :                 // conditional formatting: loop all cells
     813     1470292 :                 if (bStdOnly &&
     814             :                     !static_cast<const ScCondFormatItem&>(pPattern->GetItem(
     815      718851 :                             ATTR_CONDITIONAL)).GetCondFormatData().empty())
     816             :                 {
     817           1 :                     bStdOnly = false;
     818             :                 }
     819             : 
     820             :                 // rotated text: loop all cells
     821     1470291 :                 if ( bStdOnly && static_cast<const SfxInt32Item&>(pPattern->
     822      718850 :                                     GetItem(ATTR_ROTATE_VALUE)).GetValue() )
     823         208 :                     bStdOnly = false;
     824             :             }
     825             : 
     826      847817 :             if (bStdOnly)
     827      718642 :                 if (HasEditCells(nStart,nEnd,nEditPos))     // includes mixed script types
     828             :                 {
     829         105 :                     if (nEditPos == nStart)
     830             :                     {
     831         105 :                         bStdOnly = false;
     832         105 :                         if (nEnd > nEditPos)
     833           0 :                             nNextEnd = nEnd;
     834         105 :                         nEnd = nEditPos;                // calculate single
     835         105 :                         bStdAllowed = false;            // will be computed in any case per cell
     836             :                     }
     837             :                     else
     838             :                     {
     839           0 :                         nNextEnd = nEnd;
     840           0 :                         nEnd = nEditPos - 1;            // standard - part
     841             :                     }
     842             :                 }
     843             : 
     844      847817 :             sc::SingleColumnSpanSet aSpanSet;
     845      847817 :             aSpanSet.scan(*this, nStart, nEnd);
     846     1695634 :             sc::SingleColumnSpanSet::SpansType aSpans;
     847      847817 :             aSpanSet.getSpans(aSpans);
     848             : 
     849      847817 :             if (bStdAllowed)
     850             :             {
     851      751336 :                 sal_uInt16 nLatHeight = 0;
     852      751336 :                 sal_uInt16 nCjkHeight = 0;
     853      751336 :                 sal_uInt16 nCtlHeight = 0;
     854             :                 sal_uInt16 nDefHeight;
     855      751336 :                 SvtScriptType nDefScript = ScGlobal::GetDefaultScriptType();
     856      751336 :                 if ( nDefScript == SvtScriptType::ASIAN )
     857           0 :                     nDefHeight = nCjkHeight = lcl_GetAttribHeight( *pPattern, ATTR_CJK_FONT_HEIGHT );
     858      751336 :                 else if ( nDefScript == SvtScriptType::COMPLEX )
     859           0 :                     nDefHeight = nCtlHeight = lcl_GetAttribHeight( *pPattern, ATTR_CTL_FONT_HEIGHT );
     860             :                 else
     861      751336 :                     nDefHeight = nLatHeight = lcl_GetAttribHeight( *pPattern, ATTR_FONT_HEIGHT );
     862             : 
     863             :                 //  if everything below is already larger, the loop doesn't have to
     864             :                 //  be run again
     865      751336 :                 SCROW nStdEnd = nEnd;
     866      751336 :                 if ( nDefHeight <= nMinHeight && nStdEnd >= nMinStart )
     867      716346 :                     nStdEnd = (nMinStart>0) ? nMinStart-1 : 0;
     868             : 
     869   356744753 :                 for (SCROW nRow = nStart; nRow <= nStdEnd; ++nRow)
     870   355993417 :                     if (nDefHeight > rHeights[nRow-nStartRow])
     871    83890070 :                         rHeights[nRow-nStartRow] = nDefHeight;
     872             : 
     873      751336 :                 if ( bStdOnly )
     874             :                 {
     875             :                     //  if cells are not handled individually below,
     876             :                     //  check for cells with different script type
     877      718537 :                     sc::CellTextAttrStoreType::iterator itAttr = maCellTextAttrs.begin();
     878      718537 :                     sc::SingleColumnSpanSet::SpansType::const_iterator it = aSpans.begin(), itEnd = aSpans.end();
     879      718537 :                     sc::CellStoreType::iterator itCells = maCells.begin();
     880      721127 :                     for (; it != itEnd; ++it)
     881             :                     {
     882       34483 :                         for (SCROW nRow = it->mnRow1; nRow <= it->mnRow2; ++nRow)
     883             :                         {
     884       31893 :                             SvtScriptType nScript = GetRangeScriptType(itAttr, nRow, nRow, itCells);
     885       31893 :                             if (nScript == nDefScript)
     886       31722 :                                 continue;
     887             : 
     888         171 :                             if ( nScript == SvtScriptType::ASIAN )
     889             :                             {
     890           0 :                                 if ( nCjkHeight == 0 )
     891           0 :                                     nCjkHeight = lcl_GetAttribHeight( *pPattern, ATTR_CJK_FONT_HEIGHT );
     892           0 :                                 if (nCjkHeight > rHeights[nRow-nStartRow])
     893           0 :                                     rHeights[nRow-nStartRow] = nCjkHeight;
     894             :                             }
     895         171 :                             else if ( nScript == SvtScriptType::COMPLEX )
     896             :                             {
     897           0 :                                 if ( nCtlHeight == 0 )
     898           0 :                                     nCtlHeight = lcl_GetAttribHeight( *pPattern, ATTR_CTL_FONT_HEIGHT );
     899           0 :                                 if (nCtlHeight > rHeights[nRow-nStartRow])
     900           0 :                                     rHeights[nRow-nStartRow] = nCtlHeight;
     901             :                             }
     902             :                             else
     903             :                             {
     904         171 :                                 if ( nLatHeight == 0 )
     905           0 :                                     nLatHeight = lcl_GetAttribHeight( *pPattern, ATTR_FONT_HEIGHT );
     906         171 :                                 if (nLatHeight > rHeights[nRow-nStartRow])
     907           0 :                                     rHeights[nRow-nStartRow] = nLatHeight;
     908             :                             }
     909             :                         }
     910             :                     }
     911             :                 }
     912             :             }
     913             : 
     914      847817 :             if (!bStdOnly)                      // search covered cells
     915             :             {
     916      129280 :                 ScNeededSizeOptions aOptions;
     917             : 
     918      129280 :                 sc::SingleColumnSpanSet::SpansType::const_iterator it = aSpans.begin(), itEnd = aSpans.end();
     919      130072 :                 for (; it != itEnd; ++it)
     920             :                 {
     921        2354 :                     for (SCROW nRow = it->mnRow1; nRow <= it->mnRow2; ++nRow)
     922             :                     {
     923             :                         //  only calculate the cell height when it's used later (#37928#)
     924             : 
     925        1562 :                         if (rCxt.isForceAutoSize() || !(pDocument->GetRowFlags(nRow, nTab) & CR_MANUALSIZE) )
     926             :                         {
     927        1223 :                             aOptions.pPattern = pPattern;
     928        1223 :                             const ScPatternAttr* pOldPattern = pPattern;
     929             :                             sal_uInt16 nHeight = (sal_uInt16)
     930             :                                     ( GetNeededSize( nRow, rCxt.getOutputDevice(), rCxt.getPPTX(), rCxt.getPPTY(),
     931        1223 :                                                         rCxt.getZoomX(), rCxt.getZoomY(), false, aOptions,
     932        1223 :                                                         &pPattern) / rCxt.getPPTY() );
     933        1223 :                             if (nHeight > rHeights[nRow-nStartRow])
     934         818 :                                 rHeights[nRow-nStartRow] = nHeight;
     935             :                             // Pattern changed due to calculation? => sync.
     936        1223 :                             if (pPattern != pOldPattern)
     937             :                             {
     938           0 :                                 pPattern = aIter.Resync( nRow, nStart, nEnd);
     939           0 :                                 nNextEnd = 0;
     940             :                             }
     941             :                         }
     942             :                     }
     943             :                 }
     944      847817 :             }
     945             :         }
     946             : 
     947      847846 :         if (nNextEnd > 0)
     948             :         {
     949           0 :             nStart = nEnd + 1;
     950           0 :             nEnd = nNextEnd;
     951           0 :             nNextEnd = 0;
     952             :         }
     953             :         else
     954      847846 :             pPattern = aIter.Next(nStart,nEnd);
     955             :     }
     956      844800 : }
     957             : 
     958           0 : bool ScColumn::GetNextSpellingCell(SCROW& nRow, bool bInSel, const ScMarkData& rData) const
     959             : {
     960           0 :     bool bStop = false;
     961           0 :     sc::CellStoreType::const_iterator it = maCells.position(nRow).first;
     962           0 :     mdds::mtv::element_t eType = it->type;
     963           0 :     if (!bInSel && it != maCells.end() && eType != sc::element_type_empty)
     964             :     {
     965           0 :         if ( (eType == sc::element_type_string || eType == sc::element_type_edittext) &&
     966           0 :              !(HasAttrib( nRow, nRow, HASATTR_PROTECTED) &&
     967           0 :                pDocument->IsTabProtected(nTab)) )
     968           0 :             return true;
     969             :     }
     970           0 :     while (!bStop)
     971             :     {
     972           0 :         if (bInSel)
     973             :         {
     974           0 :             nRow = rData.GetNextMarked(nCol, nRow, false);
     975           0 :             if (!ValidRow(nRow))
     976             :             {
     977           0 :                 nRow = MAXROW+1;
     978           0 :                 bStop = true;
     979             :             }
     980             :             else
     981             :             {
     982           0 :                 it = maCells.position(it, nRow).first;
     983           0 :                 eType = it->type;
     984           0 :                 if ( (eType == sc::element_type_string || eType == sc::element_type_edittext) &&
     985           0 :                      !(HasAttrib( nRow, nRow, HASATTR_PROTECTED) &&
     986           0 :                        pDocument->IsTabProtected(nTab)) )
     987           0 :                     return true;
     988             :                 else
     989           0 :                     nRow++;
     990             :             }
     991             :         }
     992           0 :         else if (GetNextDataPos(nRow))
     993             :         {
     994           0 :             it = maCells.position(it, nRow).first;
     995           0 :             eType = it->type;
     996           0 :             if ( (eType == sc::element_type_string || eType == sc::element_type_edittext) &&
     997           0 :                  !(HasAttrib( nRow, nRow, HASATTR_PROTECTED) &&
     998           0 :                    pDocument->IsTabProtected(nTab)) )
     999           0 :                 return true;
    1000             :             else
    1001           0 :                 nRow++;
    1002             :         }
    1003             :         else
    1004             :         {
    1005           0 :             nRow = MAXROW+1;
    1006           0 :             bStop = true;
    1007             :         }
    1008             :     }
    1009           0 :     return false;
    1010             : }
    1011             : 
    1012             : namespace {
    1013             : 
    1014           0 : class StrEntries
    1015             : {
    1016             :     sc::CellStoreType& mrCells;
    1017             : 
    1018             : protected:
    1019           0 :     struct StrEntry
    1020             :     {
    1021             :         SCROW mnRow;
    1022             :         OUString maStr;
    1023             : 
    1024           0 :         StrEntry(SCROW nRow, const OUString& rStr) : mnRow(nRow), maStr(rStr) {}
    1025             :     };
    1026             : 
    1027             :     std::vector<StrEntry> maStrEntries;
    1028             :     ScDocument* mpDoc;
    1029             : 
    1030           0 :     StrEntries(sc::CellStoreType& rCells, ScDocument* pDoc) : mrCells(rCells), mpDoc(pDoc) {}
    1031             : 
    1032             : public:
    1033           0 :     void commitStrings()
    1034             :     {
    1035           0 :         svl::SharedStringPool& rPool = mpDoc->GetSharedStringPool();
    1036           0 :         sc::CellStoreType::iterator it = mrCells.begin();
    1037           0 :         std::vector<StrEntry>::iterator itStr = maStrEntries.begin(), itStrEnd = maStrEntries.end();
    1038           0 :         for (; itStr != itStrEnd; ++itStr)
    1039           0 :             it = mrCells.set(it, itStr->mnRow, rPool.intern(itStr->maStr));
    1040           0 :     }
    1041             : };
    1042             : 
    1043           0 : class RemoveEditAttribsHandler : public StrEntries
    1044             : {
    1045             :     boost::scoped_ptr<ScFieldEditEngine> mpEngine;
    1046             : 
    1047             : public:
    1048           0 :     RemoveEditAttribsHandler(sc::CellStoreType& rCells, ScDocument* pDoc) : StrEntries(rCells, pDoc) {}
    1049             : 
    1050           0 :     void operator() (size_t nRow, EditTextObject*& pObj)
    1051             :     {
    1052             :         //  For the test on hard formatting (ScEditAttrTester), are the defaults in the
    1053             :         //  EditEngine of no importance. When the tester would later recognise the same
    1054             :         //  attributes in default and hard formatting and has to remove them, the correct
    1055             :         //  defaults must be set in the EditEngine for each cell.
    1056             : 
    1057             :         //  test for attributes
    1058           0 :         if (!mpEngine)
    1059             :         {
    1060           0 :             mpEngine.reset(new ScFieldEditEngine(mpDoc, mpDoc->GetEditPool()));
    1061             :             //  EEControlBits::ONLINESPELLING if there are errors already
    1062           0 :             mpEngine->SetControlWord(mpEngine->GetControlWord() | EEControlBits::ONLINESPELLING);
    1063           0 :             mpDoc->ApplyAsianEditSettings(*mpEngine);
    1064             :         }
    1065           0 :         mpEngine->SetText(*pObj);
    1066           0 :         sal_Int32 nParCount = mpEngine->GetParagraphCount();
    1067           0 :         for (sal_Int32 nPar=0; nPar<nParCount; nPar++)
    1068             :         {
    1069           0 :             mpEngine->RemoveCharAttribs(nPar);
    1070           0 :             const SfxItemSet& rOld = mpEngine->GetParaAttribs(nPar);
    1071           0 :             if ( rOld.Count() )
    1072             :             {
    1073           0 :                 SfxItemSet aNew( *rOld.GetPool(), rOld.GetRanges() );   // empty
    1074           0 :                 mpEngine->SetParaAttribs( nPar, aNew );
    1075             :             }
    1076             :         }
    1077             :         //  change URL field to text (not possible otherwise, thus pType=0)
    1078           0 :         mpEngine->RemoveFields(true);
    1079             : 
    1080           0 :         bool bSpellErrors = mpEngine->HasOnlineSpellErrors();
    1081           0 :         bool bNeedObject = bSpellErrors || nParCount>1;         // keep errors/paragraphs
    1082             :         //  ScEditAttrTester is not needed anymore, arrays are gone
    1083             : 
    1084           0 :         if (bNeedObject)                                      // remains edit cell
    1085             :         {
    1086           0 :             EEControlBits nCtrl = mpEngine->GetControlWord();
    1087           0 :             EEControlBits nWantBig = bSpellErrors ? EEControlBits::ALLOWBIGOBJS : EEControlBits::NONE;
    1088           0 :             if ( ( nCtrl & EEControlBits::ALLOWBIGOBJS ) != nWantBig )
    1089           0 :                 mpEngine->SetControlWord( (nCtrl & ~EEControlBits::ALLOWBIGOBJS) | nWantBig );
    1090             : 
    1091             :             // Overwrite the existing object.
    1092           0 :             delete pObj;
    1093           0 :             pObj = mpEngine->CreateTextObject();
    1094             :         }
    1095             :         else                                            // create String
    1096             :         {
    1097             :             // Store the string replacement for later commits.
    1098           0 :             OUString aText = ScEditUtil::GetSpaceDelimitedString(*mpEngine);
    1099           0 :             maStrEntries.push_back(StrEntry(nRow, aText));
    1100             :         }
    1101           0 :     }
    1102             : };
    1103             : 
    1104             : class TestTabRefAbsHandler
    1105             : {
    1106             :     SCTAB mnTab;
    1107             :     bool mbTestResult;
    1108             : public:
    1109        1065 :     TestTabRefAbsHandler(SCTAB nTab) : mnTab(nTab), mbTestResult(false) {}
    1110             : 
    1111          21 :     void operator() (size_t /*nRow*/, const ScFormulaCell* pCell)
    1112             :     {
    1113          21 :         if (const_cast<ScFormulaCell*>(pCell)->TestTabRefAbs(mnTab))
    1114          10 :             mbTestResult = true;
    1115          21 :     }
    1116             : 
    1117        1065 :     bool getTestResult() const { return mbTestResult; }
    1118             : };
    1119             : 
    1120             : }
    1121             : 
    1122           0 : void ScColumn::RemoveEditAttribs( SCROW nStartRow, SCROW nEndRow )
    1123             : {
    1124           0 :     RemoveEditAttribsHandler aFunc(maCells, pDocument);
    1125           0 :     sc::ProcessEditText(maCells.begin(), maCells, nStartRow, nEndRow, aFunc);
    1126           0 :     aFunc.commitStrings();
    1127           0 : }
    1128             : 
    1129        1065 : bool ScColumn::TestTabRefAbs(SCTAB nTable) const
    1130             : {
    1131        1065 :     TestTabRefAbsHandler aFunc(nTable);
    1132        1065 :     sc::ParseFormula(maCells, aFunc);
    1133        1065 :     return aFunc.getTestResult();
    1134             : }
    1135             : 
    1136     9170500 : bool ScColumn::IsEmptyData() const
    1137             : {
    1138     9170500 :     return maCells.block_size() == 1 && maCells.begin()->type == sc::element_type_empty;
    1139             : }
    1140             : 
    1141             : namespace {
    1142             : 
    1143             : class CellCounter
    1144             : {
    1145             :     size_t mnCount;
    1146             : public:
    1147           4 :     CellCounter() : mnCount(0) {}
    1148             : 
    1149           4 :     void operator() (
    1150             :         const sc::CellStoreType::value_type& node, size_t /*nOffset*/, size_t nDataSize)
    1151             :     {
    1152           4 :         if (node.type == sc::element_type_empty)
    1153           8 :             return;
    1154             : 
    1155           0 :         mnCount += nDataSize;
    1156             :     }
    1157             : 
    1158           4 :     size_t getCount() const { return mnCount; }
    1159             : };
    1160             : 
    1161             : }
    1162             : 
    1163           4 : SCSIZE ScColumn::VisibleCount( SCROW nStartRow, SCROW nEndRow ) const
    1164             : {
    1165           4 :     CellCounter aFunc;
    1166           4 :     sc::ParseBlock(maCells.begin(), maCells, aFunc, nStartRow, nEndRow);
    1167           4 :     return aFunc.getCount();
    1168             : }
    1169             : 
    1170        7822 : bool ScColumn::HasVisibleDataAt(SCROW nRow) const
    1171             : {
    1172        7822 :     std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow);
    1173        7822 :     sc::CellStoreType::const_iterator it = aPos.first;
    1174        7822 :     if (it == maCells.end())
    1175             :         // Likely invalid row number.
    1176           0 :         return false;
    1177             : 
    1178        7822 :     return it->type != sc::element_type_empty;
    1179             : }
    1180             : 
    1181          60 : bool ScColumn::IsEmptyAttr() const
    1182             : {
    1183          60 :     if (pAttrArray)
    1184          60 :         return pAttrArray->IsEmpty();
    1185             :     else
    1186           0 :         return true;
    1187             : }
    1188             : 
    1189          60 : bool ScColumn::IsEmpty() const
    1190             : {
    1191          60 :     return (IsEmptyData() && IsEmptyAttr());
    1192             : }
    1193             : 
    1194     6032237 : bool ScColumn::IsEmptyBlock(SCROW nStartRow, SCROW nEndRow) const
    1195             : {
    1196     6032237 :     std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nStartRow);
    1197     6032237 :     sc::CellStoreType::const_iterator it = aPos.first;
    1198     6032237 :     if (it == maCells.end())
    1199             :         // Invalid row number.
    1200           0 :         return false;
    1201             : 
    1202     6032237 :     if (it->type != sc::element_type_empty)
    1203             :         // Non-empty cell at the start position.
    1204        1357 :         return false;
    1205             : 
    1206             :     // start position of next block which is not empty.
    1207     6030880 :     SCROW nNextRow = nStartRow + it->size - aPos.second;
    1208     6030880 :     return nEndRow < nNextRow;
    1209             : }
    1210             : 
    1211       92087 : bool ScColumn::IsNotesEmptyBlock(SCROW nStartRow, SCROW nEndRow) const
    1212             : {
    1213       92087 :     std::pair<sc::CellNoteStoreType::const_iterator,size_t> aPos = maCellNotes.position(nStartRow);
    1214       92087 :     sc::CellNoteStoreType::const_iterator it = aPos.first;
    1215       92087 :     if (it == maCellNotes.end())
    1216             :         // Invalid row number.
    1217           0 :         return false;
    1218             : 
    1219       92087 :     if (it->type != sc::element_type_empty)
    1220             :         // Non-empty cell at the start position.
    1221          35 :         return false;
    1222             : 
    1223             :     // start position of next block which is not empty.
    1224       92052 :     SCROW nNextRow = nStartRow + it->size - aPos.second;
    1225       92052 :     return nEndRow < nNextRow;
    1226             : }
    1227             : 
    1228          33 : SCSIZE ScColumn::GetEmptyLinesInBlock( SCROW nStartRow, SCROW nEndRow, ScDirection eDir ) const
    1229             : {
    1230             :     // Given a range of rows, find a top or bottom empty segment.  Skip the start row.
    1231          33 :     switch (eDir)
    1232             :     {
    1233             :         case DIR_TOP:
    1234             :         {
    1235             :             // Determine the length of empty head segment.
    1236          12 :             size_t nLength = nEndRow - nStartRow;
    1237          12 :             std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nStartRow);
    1238          12 :             sc::CellStoreType::const_iterator it = aPos.first;
    1239          12 :             if (it->type != sc::element_type_empty)
    1240             :                 // First row is already not empty.
    1241           8 :                 return 0;
    1242             : 
    1243             :             // length of this empty block minus the offset.
    1244           4 :             size_t nThisLen = it->size - aPos.second;
    1245           4 :             return std::min(nThisLen, nLength);
    1246             :         }
    1247             :         break;
    1248             :         case DIR_BOTTOM:
    1249             :         {
    1250             :             // Determine the length of empty tail segment.
    1251          21 :             size_t nLength = nEndRow - nStartRow;
    1252          21 :             std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nEndRow);
    1253          21 :             sc::CellStoreType::const_iterator it = aPos.first;
    1254          21 :             if (it->type != sc::element_type_empty)
    1255             :                 // end row is already not empty.
    1256          11 :                 return 0;
    1257             : 
    1258             :             // length of this empty block from the tip to the end row position.
    1259          10 :             size_t nThisLen = aPos.second + 1;
    1260          10 :             return std::min(nThisLen, nLength);
    1261             :         }
    1262             :         break;
    1263             :         default:
    1264             :             ;
    1265             :     }
    1266             : 
    1267           0 :     return 0;
    1268             : }
    1269             : 
    1270       12642 : SCROW ScColumn::GetFirstDataPos() const
    1271             : {
    1272       12642 :     if (IsEmptyData())
    1273           0 :         return 0;
    1274             : 
    1275       12642 :     sc::CellStoreType::const_iterator it = maCells.begin();
    1276       12642 :     if (it->type != sc::element_type_empty)
    1277       10194 :         return 0;
    1278             : 
    1279        2448 :     return it->size;
    1280             : }
    1281             : 
    1282     3275702 : SCROW ScColumn::GetLastDataPos() const
    1283             : {
    1284     3275702 :     if (IsEmptyData())
    1285     3223803 :         return 0;
    1286             : 
    1287       51899 :     sc::CellStoreType::const_reverse_iterator it = maCells.rbegin();
    1288       51899 :     if (it->type != sc::element_type_empty)
    1289           0 :         return MAXROW;
    1290             : 
    1291       51899 :     return MAXROW - static_cast<SCROW>(it->size);
    1292             : }
    1293             : 
    1294          89 : SCROW ScColumn::GetLastDataPos( SCROW nLastRow ) const
    1295             : {
    1296          89 :     sc::CellStoreType::const_position_type aPos = maCells.position(nLastRow);
    1297          89 :     if (aPos.first->type != sc::element_type_empty)
    1298          77 :         return nLastRow;
    1299             : 
    1300          12 :     if (aPos.first == maCells.begin())
    1301             :         // This is the first block, and is empty.
    1302           0 :         return 0;
    1303             : 
    1304          12 :     return static_cast<SCROW>(aPos.first->position - 1);
    1305             : }
    1306             : 
    1307           0 : bool ScColumn::GetPrevDataPos(SCROW& rRow) const
    1308             : {
    1309           0 :     std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(rRow);
    1310           0 :     sc::CellStoreType::const_iterator it = aPos.first;
    1311           0 :     if (it == maCells.end())
    1312           0 :         return false;
    1313             : 
    1314           0 :     if (it->type == sc::element_type_empty)
    1315             :     {
    1316           0 :         if (it == maCells.begin())
    1317             :             // No more previous non-empty cell.
    1318           0 :             return false;
    1319             : 
    1320           0 :         rRow -= aPos.second + 1; // Last row position of the previous block.
    1321           0 :         return true;
    1322             :     }
    1323             : 
    1324             :     // This block is not empty.
    1325           0 :     if (aPos.second)
    1326             :     {
    1327             :         // There are preceding cells in this block. Simply move back one cell.
    1328           0 :         --rRow;
    1329           0 :         return true;
    1330             :     }
    1331             : 
    1332             :     // This is the first cell in an non-empty block. Move back to the previous block.
    1333           0 :     if (it == maCells.begin())
    1334             :         // No more preceding block.
    1335           0 :         return false;
    1336             : 
    1337           0 :     --rRow; // Move to the last cell of the previous block.
    1338           0 :     --it;
    1339           0 :     if (it->type == sc::element_type_empty)
    1340             :     {
    1341             :         // This block is empty.
    1342           0 :         if (it == maCells.begin())
    1343             :             // No more preceding blocks.
    1344           0 :             return false;
    1345             : 
    1346             :         // Skip the whole empty block segment.
    1347           0 :         rRow -= it->size;
    1348             :     }
    1349             : 
    1350           0 :     return true;
    1351             : }
    1352             : 
    1353        4070 : bool ScColumn::GetNextDataPos(SCROW& rRow) const        // greater than rRow
    1354             : {
    1355        4070 :     std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(rRow);
    1356        4070 :     sc::CellStoreType::const_iterator it = aPos.first;
    1357        4070 :     if (it == maCells.end())
    1358           0 :         return false;
    1359             : 
    1360        4070 :     if (it->type == sc::element_type_empty)
    1361             :     {
    1362             :         // This block is empty. Skip ahead to the next block (if exists).
    1363         527 :         rRow += it->size - aPos.second;
    1364         527 :         ++it;
    1365         527 :         if (it == maCells.end())
    1366             :             // No more next block.
    1367          65 :             return false;
    1368             : 
    1369             :         // Next block exists, and is non-empty.
    1370         462 :         return true;
    1371             :     }
    1372             : 
    1373        3543 :     if (aPos.second < it->size - 1)
    1374             :     {
    1375             :         // There are still cells following the current position.
    1376        2347 :         ++rRow;
    1377        2347 :         return true;
    1378             :     }
    1379             : 
    1380             :     // This is the last cell in the block. Move ahead to the next block.
    1381        1196 :     rRow += it->size - aPos.second; // First cell in the next block.
    1382        1196 :     ++it;
    1383        1196 :     if (it == maCells.end())
    1384             :         // No more next block.
    1385           0 :         return false;
    1386             : 
    1387        1196 :     if (it->type == sc::element_type_empty)
    1388             :     {
    1389             :         // Next block is empty. Move to the next block.
    1390        1051 :         rRow += it->size;
    1391        1051 :         ++it;
    1392        1051 :         if (it == maCells.end())
    1393         551 :             return false;
    1394             :     }
    1395             : 
    1396         645 :     return true;
    1397             : }
    1398             : 
    1399      393382 : SCROW ScColumn::FindNextVisibleRow(SCROW nRow, bool bForward) const
    1400             : {
    1401      393382 :     if(bForward)
    1402             :     {
    1403      393343 :         nRow++;
    1404      393343 :         SCROW nEndRow = 0;
    1405      393343 :         bool bHidden = pDocument->RowHidden(nRow, nTab, NULL, &nEndRow);
    1406      393343 :         if(bHidden)
    1407           2 :             return std::min<SCROW>(MAXROW, nEndRow + 1);
    1408             :         else
    1409      393341 :             return nRow;
    1410             :     }
    1411             :     else
    1412             :     {
    1413          39 :         nRow--;
    1414          39 :         SCROW nStartRow = MAXROW;
    1415          39 :         bool bHidden = pDocument->RowHidden(nRow, nTab, &nStartRow, NULL);
    1416          39 :         if(bHidden)
    1417          24 :             return std::max<SCROW>(0, nStartRow - 1);
    1418             :         else
    1419          15 :             return nRow;
    1420             :     }
    1421             : }
    1422             : 
    1423          17 : SCROW ScColumn::FindNextVisibleRowWithContent(
    1424             :     sc::CellStoreType::const_iterator& itPos, SCROW nRow, bool bForward) const
    1425             : {
    1426          17 :     if (bForward)
    1427             :     {
    1428           6 :         do
    1429             :         {
    1430          12 :             nRow++;
    1431          12 :             SCROW nEndRow = 0;
    1432          12 :             bool bHidden = pDocument->RowHidden(nRow, nTab, NULL, &nEndRow);
    1433          12 :             if (bHidden)
    1434             :             {
    1435           1 :                 nRow = nEndRow + 1;
    1436           1 :                 if(nRow >= MAXROW)
    1437           6 :                     return MAXROW;
    1438             :             }
    1439             : 
    1440          12 :             std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(itPos, nRow);
    1441          12 :             itPos = aPos.first;
    1442          12 :             if (itPos == maCells.end())
    1443             :                 // Invalid row.
    1444           0 :                 return MAXROW;
    1445             : 
    1446          12 :             if (itPos->type != sc::element_type_empty)
    1447           6 :                 return nRow;
    1448             : 
    1449             :             // Move to the last cell of the current empty block.
    1450           6 :             nRow += itPos->size - aPos.second - 1;
    1451             :         }
    1452             :         while (nRow < MAXROW);
    1453             : 
    1454           5 :         return MAXROW;
    1455             :     }
    1456             : 
    1457           2 :     do
    1458             :     {
    1459           7 :         nRow--;
    1460           7 :         SCROW nStartRow = MAXROW;
    1461           7 :         bool bHidden = pDocument->RowHidden(nRow, nTab, &nStartRow, NULL);
    1462           7 :         if (bHidden)
    1463             :         {
    1464           0 :             nRow = nStartRow - 1;
    1465           0 :             if(nRow <= 0)
    1466           5 :                 return 0;
    1467             :         }
    1468             : 
    1469           7 :         std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(itPos, nRow);
    1470           7 :         itPos = aPos.first;
    1471           7 :         if (itPos == maCells.end())
    1472             :             // Invalid row.
    1473           0 :             return 0;
    1474             : 
    1475           7 :         if (itPos->type != sc::element_type_empty)
    1476           5 :             return nRow;
    1477             : 
    1478             :         // Move to the first cell of the current empty block.
    1479           2 :         nRow -= aPos.second;
    1480             :     }
    1481             :     while (nRow > 0);
    1482             : 
    1483           1 :     return 0;
    1484             : }
    1485             : 
    1486     3801852 : void ScColumn::CellStorageModified()
    1487             : {
    1488             :     // TODO: Update column's "last updated" timestamp here.
    1489             : 
    1490     3801852 :     mbDirtyGroups = true;
    1491             : 
    1492             : #if DEBUG_COLUMN_STORAGE
    1493             :     if (maCells.size() != MAXROWCOUNT)
    1494             :     {
    1495             :         cout << "ScColumn::CellStorageModified: Size of the cell array is incorrect." << endl;
    1496             :         cout.flush();
    1497             :         abort();
    1498             :     }
    1499             : 
    1500             :     if (maCellTextAttrs.size() != MAXROWCOUNT)
    1501             :     {
    1502             :         cout << "ScColumn::CellStorageModified: Size of the cell text attribute array is incorrect." << endl;
    1503             :         cout.flush();
    1504             :         abort();
    1505             :     }
    1506             : 
    1507             :     if (maBroadcasters.size() != MAXROWCOUNT)
    1508             :     {
    1509             :         cout << "ScColumn::CellStorageModified: Size of the broadcaster array is incorrect." << endl;
    1510             :         cout.flush();
    1511             :         abort();
    1512             :     }
    1513             : 
    1514             :     // Make sure that these two containers are synchronized wrt empty segments.
    1515             :     sc::CellStoreType::const_iterator itCell = maCells.begin();
    1516             :     sc::CellTextAttrStoreType::const_iterator itAttr = maCellTextAttrs.begin();
    1517             : 
    1518             :     // Move to the first empty blocks.
    1519             :     while (itCell != maCells.end() && itCell->type != sc::element_type_empty)
    1520             :         ++itCell;
    1521             : 
    1522             :     while (itAttr != maCellTextAttrs.end() && itAttr->type != sc::element_type_empty)
    1523             :         ++itAttr;
    1524             : 
    1525             :     while (itCell != maCells.end())
    1526             :     {
    1527             :         if (itCell->position != itAttr->position || itCell->size != itAttr->size)
    1528             :         {
    1529             :             cout << "ScColumn::CellStorageModified: Cell array and cell text attribute array are out of sync." << endl;
    1530             :             cout << "-- cell array" << endl;
    1531             :             maCells.dump_blocks(cout);
    1532             :             cout << "-- attribute array" << endl;
    1533             :             maCellTextAttrs.dump_blocks(cout);
    1534             :             cout.flush();
    1535             :             abort();
    1536             :         }
    1537             : 
    1538             :         // Move to the next empty blocks.
    1539             :         ++itCell;
    1540             :         while (itCell != maCells.end() && itCell->type != sc::element_type_empty)
    1541             :             ++itCell;
    1542             : 
    1543             :         ++itAttr;
    1544             :         while (itAttr != maCellTextAttrs.end() && itAttr->type != sc::element_type_empty)
    1545             :             ++itAttr;
    1546             :     }
    1547             : #endif
    1548     3801852 : }
    1549             : 
    1550             : #if DEBUG_COLUMN_STORAGE
    1551             : 
    1552             : namespace {
    1553             : 
    1554             : struct FormulaGroupDumper : std::unary_function<sc::CellStoreType::value_type, void>
    1555             : {
    1556             :     void operator() (const sc::CellStoreType::value_type& rNode) const
    1557             :     {
    1558             :         if (rNode.type != sc::element_type_formula)
    1559             :             return;
    1560             : 
    1561             :         cout << "  -- formula block" << endl;
    1562             :         sc::formula_block::const_iterator it = sc::formula_block::begin(*rNode.data);
    1563             :         sc::formula_block::const_iterator itEnd = sc::formula_block::end(*rNode.data);
    1564             : 
    1565             :         for (; it != itEnd; ++it)
    1566             :         {
    1567             :             const ScFormulaCell& rCell = **it;
    1568             :             if (!rCell.IsShared())
    1569             :             {
    1570             :                 cout << "  + row " << rCell.aPos.Row() << " not shared" << endl;
    1571             :                 continue;
    1572             :             }
    1573             : 
    1574             :             if (rCell.GetSharedTopRow() != rCell.aPos.Row())
    1575             :             {
    1576             :                 cout << "  + row " << rCell.aPos.Row() << " shared with top row " << rCell.GetSharedTopRow() << " with length " << rCell.GetSharedLength() << endl;
    1577             :                 continue;
    1578             :             }
    1579             : 
    1580             :             SCROW nLen = rCell.GetSharedLength();
    1581             :             cout << "  * group: start=" << rCell.aPos.Row() << ", length=" << nLen << endl;
    1582             :             std::advance(it, nLen-1);
    1583             :         }
    1584             :     }
    1585             : };
    1586             : 
    1587             : }
    1588             : 
    1589             : void ScColumn::DumpFormulaGroups() const
    1590             : {
    1591             :     cout << "-- formua groups" << endl;
    1592             :     std::for_each(maCells.begin(), maCells.end(), FormulaGroupDumper());
    1593             :     cout << "--" << endl;
    1594             : }
    1595             : #endif
    1596             : 
    1597           6 : void ScColumn::CopyCellTextAttrsToDocument(SCROW nRow1, SCROW nRow2, ScColumn& rDestCol) const
    1598             : {
    1599           6 :     rDestCol.maCellTextAttrs.set_empty(nRow1, nRow2); // Empty the destination range first.
    1600             : 
    1601           6 :     sc::CellTextAttrStoreType::const_iterator itBlk = maCellTextAttrs.begin(), itBlkEnd = maCellTextAttrs.end();
    1602             : 
    1603             :     // Locate the top row position.
    1604           6 :     size_t nOffsetInBlock = 0;
    1605           6 :     size_t nBlockStart = 0, nBlockEnd = 0, nRowPos = static_cast<size_t>(nRow1);
    1606           6 :     for (; itBlk != itBlkEnd; ++itBlk)
    1607             :     {
    1608           6 :         nBlockEnd = nBlockStart + itBlk->size;
    1609           6 :         if (nBlockStart <= nRowPos && nRowPos < nBlockEnd)
    1610             :         {
    1611             :             // Found.
    1612           6 :             nOffsetInBlock = nRowPos - nBlockStart;
    1613           6 :             break;
    1614             :         }
    1615             :     }
    1616             : 
    1617           6 :     if (itBlk == itBlkEnd)
    1618             :         // Specified range not found. Bail out.
    1619           6 :         return;
    1620             : 
    1621           6 :     nRowPos = static_cast<size_t>(nRow2); // End row position.
    1622             : 
    1623             :     // Keep copying until we hit the end row position.
    1624           6 :     sc::celltextattr_block::const_iterator itData, itDataEnd;
    1625           8 :     for (; itBlk != itBlkEnd; ++itBlk, nBlockStart = nBlockEnd, nOffsetInBlock = 0)
    1626             :     {
    1627           7 :         nBlockEnd = nBlockStart + itBlk->size;
    1628           7 :         if (!itBlk->data)
    1629             :         {
    1630             :             // Empty block.
    1631           1 :             if (nBlockStart <= nRowPos && nRowPos < nBlockEnd)
    1632             :                 // This block contains the end row.
    1633           1 :                 rDestCol.maCellTextAttrs.set_empty(nBlockStart + nOffsetInBlock, nRowPos);
    1634             :             else
    1635           0 :                 rDestCol.maCellTextAttrs.set_empty(nBlockStart + nOffsetInBlock, nBlockEnd-1);
    1636             : 
    1637           1 :             continue;
    1638             :         }
    1639             : 
    1640             :         // Non-empty block.
    1641           6 :         itData = sc::celltextattr_block::begin(*itBlk->data);
    1642           6 :         itDataEnd = sc::celltextattr_block::end(*itBlk->data);
    1643           6 :         std::advance(itData, nOffsetInBlock);
    1644             : 
    1645           6 :         if (nBlockStart <= nRowPos && nRowPos < nBlockEnd)
    1646             :         {
    1647             :             // This block contains the end row. Only copy partially.
    1648           5 :             size_t nOffset = nRowPos - nBlockStart + 1;
    1649           5 :             itDataEnd = sc::celltextattr_block::begin(*itBlk->data);
    1650           5 :             std::advance(itDataEnd, nOffset);
    1651             : 
    1652           5 :             rDestCol.maCellTextAttrs.set(nBlockStart + nOffsetInBlock, itData, itDataEnd);
    1653           5 :             break;
    1654             :         }
    1655             : 
    1656           1 :         rDestCol.maCellTextAttrs.set(nBlockStart + nOffsetInBlock, itData, itDataEnd);
    1657             :     }
    1658             : }
    1659             : 
    1660             : namespace {
    1661             : 
    1662             : class CopyCellNotesHandler
    1663             : {
    1664             :     ScColumn& mrDestCol;
    1665             :     sc::CellNoteStoreType& mrDestNotes;
    1666             :     sc::CellNoteStoreType::iterator miPos;
    1667             :     SCTAB mnSrcTab;
    1668             :     SCCOL mnSrcCol;
    1669             :     SCTAB mnDestTab;
    1670             :     SCCOL mnDestCol;
    1671             :     SCROW mnDestOffset; /// Add this to the source row position to get the destination row.
    1672             :     bool mbCloneCaption;
    1673             : 
    1674             : public:
    1675          39 :     CopyCellNotesHandler( const ScColumn& rSrcCol, ScColumn& rDestCol, SCROW nDestOffset, bool bCloneCaption ) :
    1676             :         mrDestCol(rDestCol),
    1677          39 :         mrDestNotes(rDestCol.GetCellNoteStore()),
    1678             :         miPos(mrDestNotes.begin()),
    1679          39 :         mnSrcTab(rSrcCol.GetTab()),
    1680          39 :         mnSrcCol(rSrcCol.GetCol()),
    1681          39 :         mnDestTab(rDestCol.GetTab()),
    1682          39 :         mnDestCol(rDestCol.GetCol()),
    1683             :         mnDestOffset(nDestOffset),
    1684         234 :         mbCloneCaption(bCloneCaption) {}
    1685             : 
    1686          49 :     void operator() ( size_t nRow, const ScPostIt* p )
    1687             :     {
    1688          49 :         SCROW nDestRow = nRow + mnDestOffset;
    1689          49 :         ScAddress aSrcPos(mnSrcCol, nRow, mnSrcTab);
    1690          49 :         ScAddress aDestPos(mnDestCol, nDestRow, mnDestTab);
    1691          49 :         miPos = mrDestNotes.set(miPos, nDestRow, p->Clone(aSrcPos, mrDestCol.GetDoc(), aDestPos, mbCloneCaption));
    1692          49 :     }
    1693             : };
    1694             : 
    1695             : }
    1696             : 
    1697       91670 : void ScColumn::CopyCellNotesToDocument(
    1698             :     SCROW nRow1, SCROW nRow2, ScColumn& rDestCol, bool bCloneCaption, SCROW nRowOffsetDest ) const
    1699             : {
    1700       91670 :     if (IsNotesEmptyBlock(nRow1, nRow2))
    1701             :         // The column has no cell notes to copy between specified rows.
    1702      183301 :         return;
    1703             : 
    1704          39 :     ScDrawLayer *pDrawLayer = rDestCol.GetDoc().GetDrawLayer();
    1705          39 :     bool bWasLocked = bool();
    1706          39 :     if (pDrawLayer)
    1707             :     {
    1708             :         // Avoid O(n^2) by temporary locking SdrModel which disables broadcasting.
    1709             :         // Each cell note adds undo listener, and all of them would be woken up in ScPostIt::CreateCaption.
    1710           7 :         bWasLocked = pDrawLayer->isLocked();
    1711           7 :         pDrawLayer->setLock(true);
    1712             :     }
    1713          39 :     CopyCellNotesHandler aFunc(*this, rDestCol, nRowOffsetDest, bCloneCaption);
    1714          39 :     sc::ParseNote(maCellNotes.begin(), maCellNotes, nRow1, nRow2, aFunc);
    1715          39 :     if (pDrawLayer)
    1716           7 :         pDrawLayer->setLock(bWasLocked);
    1717             : }
    1718             : 
    1719       91664 : void ScColumn::DuplicateNotes(SCROW nStartRow, size_t nDataSize, ScColumn& rDestCol, sc::ColumnBlockPosition& maDestBlockPos,
    1720             :                               bool bCloneCaption, SCROW nRowOffsetDest ) const
    1721             : {
    1722       91664 :     CopyCellNotesToDocument(nStartRow, nStartRow + nDataSize -1, rDestCol, bCloneCaption, nRowOffsetDest);
    1723       91664 :     maDestBlockPos.miCellNotePos = rDestCol.maCellNotes.begin();
    1724       91664 : }
    1725             : 
    1726       58164 : SvtBroadcaster* ScColumn::GetBroadcaster(SCROW nRow)
    1727             : {
    1728       58164 :     return maBroadcasters.get<SvtBroadcaster*>(nRow);
    1729             : }
    1730             : 
    1731          14 : const SvtBroadcaster* ScColumn::GetBroadcaster(SCROW nRow) const
    1732             : {
    1733          14 :     return maBroadcasters.get<SvtBroadcaster*>(nRow);
    1734             : }
    1735             : 
    1736         599 : const SvtBroadcaster* ScColumn::GetBroadcaster( sc::ColumnBlockConstPosition& rBlockPos, SCROW nRow ) const
    1737             : {
    1738         599 :     sc::BroadcasterStoreType::const_position_type aPos = maBroadcasters.position(rBlockPos.miBroadcasterPos, nRow);
    1739         599 :     rBlockPos.miBroadcasterPos = aPos.first;
    1740             : 
    1741         599 :     if (aPos.first->type != sc::element_type_broadcaster)
    1742         476 :         return NULL;
    1743             : 
    1744         123 :     return sc::broadcaster_block::at(*aPos.first->data, aPos.second);
    1745             : }
    1746             : 
    1747         125 : void ScColumn::DeleteBroadcasters( sc::ColumnBlockPosition& rBlockPos, SCROW nRow1, SCROW nRow2 )
    1748             : {
    1749         250 :     rBlockPos.miBroadcasterPos =
    1750         125 :         maBroadcasters.set_empty(rBlockPos.miBroadcasterPos, nRow1, nRow2);
    1751         125 : }
    1752             : 
    1753     2437120 : void ScColumn::PrepareBroadcastersForDestruction()
    1754             : {
    1755     2437120 :     sc::BroadcasterStoreType::iterator itPos = maBroadcasters.begin(), itPosEnd = maBroadcasters.end();
    1756     4878122 :     for (; itPos != itPosEnd; ++itPos)
    1757             :     {
    1758     2441002 :         if (itPos->type == sc::element_type_broadcaster)
    1759             :         {
    1760        2055 :             sc::broadcaster_block::iterator it = sc::broadcaster_block::begin(*itPos->data);
    1761        2055 :             sc::broadcaster_block::iterator itEnd = sc::broadcaster_block::end(*itPos->data);
    1762        9905 :             for (; it != itEnd; ++it)
    1763        7850 :                 (*it)->PrepareForDestruction();
    1764             :         }
    1765             :     }
    1766     2437120 : }
    1767             : 
    1768           0 : bool ScColumn::HasBroadcaster() const
    1769             : {
    1770           0 :     sc::BroadcasterStoreType::const_iterator it = maBroadcasters.begin(), itEnd = maBroadcasters.end();
    1771           0 :     for (; it != itEnd; ++it)
    1772             :     {
    1773           0 :         if (it->type == sc::element_type_broadcaster)
    1774             :             // Having a broadcaster block automatically means there is at least one broadcaster.
    1775           0 :             return true;
    1776             :     }
    1777           0 :     return false;
    1778             : }
    1779             : 
    1780      207031 : ScPostIt* ScColumn::GetCellNote(SCROW nRow)
    1781             : {
    1782      207031 :     return maCellNotes.get<ScPostIt*>(nRow);
    1783             : }
    1784             : 
    1785         131 : const ScPostIt* ScColumn::GetCellNote(SCROW nRow) const
    1786             : {
    1787         131 :     return maCellNotes.get<ScPostIt*>(nRow);
    1788             : }
    1789             : 
    1790         599 : const ScPostIt* ScColumn::GetCellNote( sc::ColumnBlockConstPosition& rBlockPos, SCROW nRow ) const
    1791             : {
    1792         599 :     sc::CellNoteStoreType::const_position_type aPos = maCellNotes.position(rBlockPos.miCellNotePos, nRow);
    1793         599 :     rBlockPos.miCellNotePos = aPos.first;
    1794             : 
    1795         599 :     if (aPos.first->type != sc::element_type_cellnote)
    1796         598 :         return NULL;
    1797             : 
    1798           1 :     return sc::cellnote_block::at(*aPos.first->data, aPos.second);
    1799             : }
    1800             : 
    1801          72 : void ScColumn::SetCellNote(SCROW nRow, ScPostIt* pNote)
    1802             : {
    1803             :     //pNote->UpdateCaptionPos(ScAddress(nCol, nRow, nTab)); // TODO notes useful ? slow import with many notes
    1804          72 :     maCellNotes.set(nRow, pNote);
    1805          72 : }
    1806             : 
    1807       48521 : void ScColumn::DeleteCellNotes( sc::ColumnBlockPosition& rBlockPos, SCROW nRow1, SCROW nRow2 )
    1808             : {
    1809       97042 :     rBlockPos.miCellNotePos =
    1810       48521 :         maCellNotes.set_empty(rBlockPos.miCellNotePos, nRow1, nRow2);
    1811       48521 : }
    1812             : 
    1813     4995083 : bool ScColumn::HasCellNotes() const
    1814             : {
    1815     4995083 :     sc::CellNoteStoreType::const_iterator it = maCellNotes.begin(), itEnd = maCellNotes.end();
    1816     9990155 :     for (; it != itEnd; ++it)
    1817             :     {
    1818     4995159 :         if (it->type == sc::element_type_cellnote)
    1819             :             // Having a cellnote block automatically means there is at least one cell note.
    1820          87 :             return true;
    1821             :     }
    1822     4994996 :     return false;
    1823             : }
    1824             : 
    1825          50 : SCROW ScColumn::GetCellNotesMaxRow() const
    1826             : {
    1827             :     // hypothesis : the column has cell notes (should be checked before)
    1828          50 :     SCROW maxRow = 0;
    1829          50 :     sc::CellNoteStoreType::const_iterator it = maCellNotes.begin(), itEnd = maCellNotes.end();
    1830         195 :     for (; it != itEnd; ++it)
    1831             :     {
    1832         145 :         if (it->type == sc::element_type_cellnote)
    1833          50 :             maxRow = it->position + it->size -1;
    1834             :     }
    1835          50 :     return maxRow;
    1836             : }
    1837          34 : SCROW ScColumn::GetCellNotesMinRow() const
    1838             : {
    1839             :     // hypothesis : the column has cell notes (should be checked before)
    1840          34 :     SCROW minRow = 0;
    1841          34 :     bool bFound = false;
    1842          34 :     sc::CellNoteStoreType::const_iterator it = maCellNotes.begin(), itEnd = maCellNotes.end();
    1843          99 :     for (; it != itEnd && !bFound; ++it)
    1844             :     {
    1845          65 :         if (it->type == sc::element_type_cellnote)
    1846             :         {
    1847          34 :             bFound = true;
    1848          34 :             minRow = it->position;
    1849             :         }
    1850             :     }
    1851          34 :     return minRow;
    1852             : }
    1853             : 
    1854          49 : sal_uInt16 ScColumn::GetTextWidth(SCROW nRow) const
    1855             : {
    1856          49 :     return maCellTextAttrs.get<sc::CellTextAttr>(nRow).mnTextWidth;
    1857             : }
    1858             : 
    1859          30 : void ScColumn::SetTextWidth(SCROW nRow, sal_uInt16 nWidth)
    1860             : {
    1861          30 :     sc::CellTextAttrStoreType::position_type aPos = maCellTextAttrs.position(nRow);
    1862          30 :     if (aPos.first->type != sc::element_type_celltextattr)
    1863          30 :         return;
    1864             : 
    1865             :     // Set new value only when the slot is not empty.
    1866          30 :     sc::celltextattr_block::at(*aPos.first->data, aPos.second).mnTextWidth = nWidth;
    1867          30 :     CellStorageModified();
    1868             : }
    1869             : 
    1870       31225 : SvtScriptType ScColumn::GetScriptType( SCROW nRow ) const
    1871             : {
    1872       31225 :     if (!ValidRow(nRow) || maCellTextAttrs.is_empty(nRow))
    1873        1657 :         return SvtScriptType::NONE;
    1874             : 
    1875       29568 :     return maCellTextAttrs.get<sc::CellTextAttr>(nRow).mnScriptType;
    1876             : }
    1877             : 
    1878       63889 : SvtScriptType ScColumn::GetRangeScriptType(
    1879             :     sc::CellTextAttrStoreType::iterator& itPos, SCROW nRow1, SCROW nRow2, const sc::CellStoreType::iterator& itrCells )
    1880             : {
    1881       63889 :     if (!ValidRow(nRow1) || !ValidRow(nRow2) || nRow1 > nRow2)
    1882           0 :         return SvtScriptType::NONE;
    1883             : 
    1884       63889 :     SCROW nRow = nRow1;
    1885             :     std::pair<sc::CellTextAttrStoreType::iterator,size_t> aRet =
    1886       63889 :         maCellTextAttrs.position(itPos, nRow1);
    1887             : 
    1888       63889 :     itPos = aRet.first; // Track the position of cell text attribute array.
    1889             : 
    1890       63889 :     SvtScriptType nScriptType = SvtScriptType::NONE;
    1891       63889 :     bool bUpdated = false;
    1892       63889 :     if (itPos->type == sc::element_type_celltextattr)
    1893             :     {
    1894       63745 :         sc::celltextattr_block::iterator it = sc::celltextattr_block::begin(*itPos->data);
    1895       63745 :         sc::celltextattr_block::iterator itEnd = sc::celltextattr_block::end(*itPos->data);
    1896       63745 :         std::advance(it, aRet.second);
    1897      127630 :         for (; it != itEnd; ++it, ++nRow)
    1898             :         {
    1899      125276 :             if (nRow > nRow2)
    1900       61391 :                 return nScriptType;
    1901             : 
    1902       63885 :             sc::CellTextAttr& rVal = *it;
    1903       63885 :             if (UpdateScriptType(rVal, nRow, itrCells))
    1904       24849 :                 bUpdated = true;
    1905       63885 :             nScriptType |= rVal.mnScriptType;
    1906             :         }
    1907             :     }
    1908             :     else
    1909             :     {
    1910             :         // Skip this whole block.
    1911         144 :         nRow += itPos->size - aRet.second;
    1912             :     }
    1913             : 
    1914        4996 :     while (nRow <= nRow2)
    1915             :     {
    1916           0 :         ++itPos;
    1917           0 :         if (itPos == maCellTextAttrs.end())
    1918           0 :             return nScriptType;
    1919             : 
    1920           0 :         if (itPos->type != sc::element_type_celltextattr)
    1921             :         {
    1922             :             // Skip this whole block.
    1923           0 :             nRow += itPos->size;
    1924           0 :             continue;
    1925             :         }
    1926             : 
    1927           0 :         sc::celltextattr_block::iterator it = sc::celltextattr_block::begin(*itPos->data);
    1928           0 :         sc::celltextattr_block::iterator itEnd = sc::celltextattr_block::end(*itPos->data);
    1929           0 :         for (; it != itEnd; ++it, ++nRow)
    1930             :         {
    1931           0 :             if (nRow > nRow2)
    1932           0 :                 return nScriptType;
    1933             : 
    1934           0 :             sc::CellTextAttr& rVal = *it;
    1935           0 :             if (UpdateScriptType(rVal, nRow, itrCells))
    1936           0 :                 bUpdated = true;
    1937             : 
    1938           0 :             nScriptType |= rVal.mnScriptType;
    1939             :         }
    1940             :     }
    1941             : 
    1942        2498 :     if (bUpdated)
    1943         550 :         CellStorageModified();
    1944             : 
    1945        2498 :     return nScriptType;
    1946             : }
    1947             : 
    1948        3642 : void ScColumn::SetScriptType( SCROW nRow, SvtScriptType nType )
    1949             : {
    1950        3642 :     if (!ValidRow(nRow))
    1951           0 :         return;
    1952             : 
    1953        3642 :     sc::CellTextAttrStoreType::position_type aPos = maCellTextAttrs.position(nRow);
    1954        3642 :     if (aPos.first->type != sc::element_type_celltextattr)
    1955             :         // Set new value only when the slot is already set.
    1956           0 :         return;
    1957             : 
    1958        3642 :     sc::celltextattr_block::at(*aPos.first->data, aPos.second).mnScriptType = nType;
    1959        3642 :     CellStorageModified();
    1960             : }
    1961             : 
    1962          38 : size_t ScColumn::GetFormulaHash( SCROW nRow ) const
    1963             : {
    1964          38 :     const ScFormulaCell* pCell = FetchFormulaCell(nRow);
    1965          38 :     return pCell ? pCell->GetHash() : 0;
    1966             : }
    1967             : 
    1968           6 : ScFormulaVectorState ScColumn::GetFormulaVectorState( SCROW nRow ) const
    1969             : {
    1970           6 :     const ScFormulaCell* pCell = FetchFormulaCell(nRow);
    1971           6 :     return pCell ? pCell->GetVectorState() : FormulaVectorUnknown;
    1972             : }
    1973             : 
    1974           0 : formula::FormulaTokenRef ScColumn::ResolveStaticReference( SCROW nRow )
    1975             : {
    1976           0 :     std::pair<sc::CellStoreType::iterator,size_t> aPos = maCells.position(nRow);
    1977           0 :     sc::CellStoreType::iterator it = aPos.first;
    1978           0 :     if (it == maCells.end())
    1979             :         // Invalid row. Return a null token.
    1980           0 :         return formula::FormulaTokenRef();
    1981             : 
    1982           0 :     switch (it->type)
    1983             :     {
    1984             :         case sc::element_type_numeric:
    1985             :         {
    1986           0 :             double fVal = sc::numeric_block::at(*it->data, aPos.second);
    1987           0 :             return formula::FormulaTokenRef(new formula::FormulaDoubleToken(fVal));
    1988             :         }
    1989             :         case sc::element_type_formula:
    1990             :         {
    1991           0 :             ScFormulaCell* p = sc::formula_block::at(*it->data, aPos.second);
    1992           0 :             if (p->IsValue())
    1993           0 :                 return formula::FormulaTokenRef(new formula::FormulaDoubleToken(p->GetValue()));
    1994             : 
    1995           0 :             return formula::FormulaTokenRef(new formula::FormulaStringToken(p->GetString()));
    1996             :         }
    1997             :         case sc::element_type_string:
    1998             :         {
    1999           0 :             const svl::SharedString& rSS = sc::string_block::at(*it->data, aPos.second);
    2000           0 :             return formula::FormulaTokenRef(new formula::FormulaStringToken(rSS.getString()));
    2001             :         }
    2002             :         case sc::element_type_edittext:
    2003             :         {
    2004           0 :             const EditTextObject* pText = sc::edittext_block::at(*it->data, aPos.second);
    2005           0 :             OUString aStr = ScEditUtil::GetString(*pText, pDocument);
    2006           0 :             return formula::FormulaTokenRef(new formula::FormulaStringToken(aStr));
    2007             :         }
    2008             :         case sc::element_type_empty:
    2009             :         default:
    2010             :             // Return a value of 0.0 in all the other cases.
    2011           0 :             return formula::FormulaTokenRef(new formula::FormulaDoubleToken(0.0));
    2012             :     }
    2013             : }
    2014             : 
    2015             : namespace {
    2016             : 
    2017             : class ToMatrixHandler
    2018             : {
    2019             :     ScMatrix& mrMat;
    2020             :     SCCOL mnMatCol;
    2021             :     SCROW mnTopRow;
    2022             :     ScDocument* mpDoc;
    2023             :     svl::SharedStringPool& mrStrPool;
    2024             : public:
    2025           0 :     ToMatrixHandler(ScMatrix& rMat, SCCOL nMatCol, SCROW nTopRow, ScDocument* pDoc) :
    2026             :         mrMat(rMat), mnMatCol(nMatCol), mnTopRow(nTopRow),
    2027           0 :         mpDoc(pDoc), mrStrPool(pDoc->GetSharedStringPool()) {}
    2028             : 
    2029           0 :     void operator() (size_t nRow, double fVal)
    2030             :     {
    2031           0 :         mrMat.PutDouble(fVal, mnMatCol, nRow - mnTopRow);
    2032           0 :     }
    2033             : 
    2034           0 :     void operator() (size_t nRow, const ScFormulaCell* p)
    2035             :     {
    2036             :         // Formula cell may need to re-calculate.
    2037           0 :         ScFormulaCell& rCell = const_cast<ScFormulaCell&>(*p);
    2038           0 :         if (rCell.IsValue())
    2039           0 :             mrMat.PutDouble(rCell.GetValue(), mnMatCol, nRow - mnTopRow);
    2040             :         else
    2041           0 :             mrMat.PutString(rCell.GetString(), mnMatCol, nRow - mnTopRow);
    2042           0 :     }
    2043             : 
    2044           0 :     void operator() (size_t nRow, const svl::SharedString& rSS)
    2045             :     {
    2046           0 :         mrMat.PutString(rSS, mnMatCol, nRow - mnTopRow);
    2047           0 :     }
    2048             : 
    2049           0 :     void operator() (size_t nRow, const EditTextObject* pStr)
    2050             :     {
    2051           0 :         mrMat.PutString(mrStrPool.intern(ScEditUtil::GetString(*pStr, mpDoc)), mnMatCol, nRow - mnTopRow);
    2052           0 :     }
    2053             : };
    2054             : 
    2055             : }
    2056             : 
    2057           0 : bool ScColumn::ResolveStaticReference( ScMatrix& rMat, SCCOL nMatCol, SCROW nRow1, SCROW nRow2 )
    2058             : {
    2059           0 :     if (nRow1 > nRow2)
    2060           0 :         return false;
    2061             : 
    2062           0 :     ToMatrixHandler aFunc(rMat, nMatCol, nRow1, pDocument);
    2063           0 :     sc::ParseAllNonEmpty(maCells.begin(), maCells, nRow1, nRow2, aFunc);
    2064           0 :     return true;
    2065             : }
    2066             : 
    2067             : namespace {
    2068             : 
    2069          50 : struct CellBucket
    2070             : {
    2071             :     SCSIZE mnEmpValStart;
    2072             :     SCSIZE mnNumValStart;
    2073             :     SCSIZE mnStrValStart;
    2074             :     SCSIZE mnEmpValCount;
    2075             :     std::vector<double> maNumVals;
    2076             :     std::vector<svl::SharedString> maStrVals;
    2077             : 
    2078          50 :     CellBucket() : mnEmpValStart(0), mnNumValStart(0), mnStrValStart(0), mnEmpValCount(0) {}
    2079             : 
    2080         100 :     void flush(ScMatrix& rMat, SCSIZE nCol)
    2081             :     {
    2082         100 :         if (mnEmpValCount)
    2083             :         {
    2084           0 :             rMat.PutEmptyResultVector(mnEmpValCount, nCol, mnEmpValStart);
    2085           0 :             reset();
    2086             :         }
    2087         100 :         else if (!maNumVals.empty())
    2088             :         {
    2089          50 :             const double* p = &maNumVals[0];
    2090          50 :             rMat.PutDouble(p, maNumVals.size(), nCol, mnNumValStart);
    2091          50 :             reset();
    2092             :         }
    2093          50 :         else if (!maStrVals.empty())
    2094             :         {
    2095           0 :             const svl::SharedString* p = &maStrVals[0];
    2096           0 :             rMat.PutString(p, maStrVals.size(), nCol, mnStrValStart);
    2097           0 :             reset();
    2098             :         }
    2099         100 :     }
    2100             : 
    2101          50 :     void reset()
    2102             :     {
    2103          50 :         mnEmpValStart = mnNumValStart = mnStrValStart = 0;
    2104          50 :         mnEmpValCount = 0;
    2105          50 :         maNumVals.clear();
    2106          50 :         maStrVals.clear();
    2107          50 :     }
    2108             : };
    2109             : 
    2110             : class FillMatrixHandler
    2111             : {
    2112             :     ScMatrix& mrMat;
    2113             :     size_t mnMatCol;
    2114             :     size_t mnTopRow;
    2115             : 
    2116             :     SCCOL mnCol;
    2117             :     SCTAB mnTab;
    2118             :     ScDocument* mpDoc;
    2119             :     svl::SharedStringPool& mrPool;
    2120             : 
    2121             : public:
    2122         247 :     FillMatrixHandler(ScMatrix& rMat, size_t nMatCol, size_t nTopRow, SCCOL nCol, SCTAB nTab, ScDocument* pDoc) :
    2123         247 :         mrMat(rMat), mnMatCol(nMatCol), mnTopRow(nTopRow), mnCol(nCol), mnTab(nTab), mpDoc(pDoc), mrPool(pDoc->GetSharedStringPool()) {}
    2124             : 
    2125         356 :     void operator() (const sc::CellStoreType::value_type& node, size_t nOffset, size_t nDataSize)
    2126             :     {
    2127         356 :         size_t nMatRow = node.position + nOffset - mnTopRow;
    2128             : 
    2129         356 :         switch (node.type)
    2130             :         {
    2131             :             case sc::element_type_numeric:
    2132             :             {
    2133         250 :                 const double* p = &sc::numeric_block::at(*node.data, nOffset);
    2134         250 :                 mrMat.PutDouble(p, nDataSize, mnMatCol, nMatRow);
    2135             :             }
    2136         250 :             break;
    2137             :             case sc::element_type_string:
    2138             :             {
    2139          13 :                 const svl::SharedString* p = &sc::string_block::at(*node.data, nOffset);
    2140          13 :                 mrMat.PutString(p, nDataSize, mnMatCol, nMatRow);
    2141             :             }
    2142          13 :             break;
    2143             :             case sc::element_type_edittext:
    2144             :             {
    2145           0 :                 std::vector<svl::SharedString> aSSs;
    2146           0 :                 aSSs.reserve(nDataSize);
    2147           0 :                 sc::edittext_block::const_iterator it = sc::edittext_block::begin(*node.data);
    2148           0 :                 std::advance(it, nOffset);
    2149           0 :                 sc::edittext_block::const_iterator itEnd = it;
    2150           0 :                 std::advance(itEnd, nDataSize);
    2151           0 :                 for (; it != itEnd; ++it)
    2152             :                 {
    2153           0 :                     OUString aStr = ScEditUtil::GetString(**it, mpDoc);
    2154           0 :                     aSSs.push_back(mrPool.intern(aStr));
    2155           0 :                 }
    2156             : 
    2157           0 :                 const svl::SharedString* p = &aSSs[0];
    2158           0 :                 mrMat.PutString(p, nDataSize, mnMatCol, nMatRow);
    2159             :             }
    2160           0 :             break;
    2161             :             case sc::element_type_formula:
    2162             :             {
    2163          50 :                 CellBucket aBucket;
    2164          50 :                 sc::formula_block::const_iterator it = sc::formula_block::begin(*node.data);
    2165          50 :                 std::advance(it, nOffset);
    2166          50 :                 sc::formula_block::const_iterator itEnd = it;
    2167          50 :                 std::advance(itEnd, nDataSize);
    2168             : 
    2169          50 :                 size_t nPrevRow = 0, nThisRow = node.position + nOffset;
    2170         150 :                 for (; it != itEnd; ++it, nPrevRow = nThisRow, ++nThisRow)
    2171             :                 {
    2172         100 :                     ScFormulaCell& rCell = const_cast<ScFormulaCell&>(**it);
    2173             : 
    2174         100 :                     if (rCell.IsEmpty())
    2175             :                     {
    2176           0 :                         if (aBucket.mnEmpValCount && nThisRow == nPrevRow + 1)
    2177             :                         {
    2178             :                             // Secondary empty results.
    2179           0 :                             ++aBucket.mnEmpValCount;
    2180             :                         }
    2181             :                         else
    2182             :                         {
    2183             :                             // First empty result.
    2184           0 :                             aBucket.flush(mrMat, mnMatCol);
    2185           0 :                             aBucket.mnEmpValStart = nThisRow - mnTopRow;
    2186           0 :                             ++aBucket.mnEmpValCount;
    2187             :                         }
    2188         100 :                         continue;
    2189             :                     }
    2190             : 
    2191             :                     sal_uInt16 nErr;
    2192             :                     double fVal;
    2193         100 :                     if (rCell.GetErrorOrValue(nErr, fVal))
    2194             :                     {
    2195         100 :                         ScAddress aAdr(mnCol, nThisRow, mnTab);
    2196             : 
    2197         100 :                         if (nErr)
    2198           5 :                             fVal = CreateDoubleError(nErr);
    2199             : 
    2200         100 :                         if (!aBucket.maNumVals.empty() && nThisRow == nPrevRow + 1)
    2201             :                         {
    2202             :                             // Secondary numbers.
    2203          50 :                             aBucket.maNumVals.push_back(fVal);
    2204             :                         }
    2205             :                         else
    2206             :                         {
    2207             :                             // First number.
    2208          50 :                             aBucket.flush(mrMat, mnMatCol);
    2209          50 :                             aBucket.mnNumValStart = nThisRow - mnTopRow;
    2210          50 :                             aBucket.maNumVals.push_back(fVal);
    2211             :                         }
    2212         100 :                         continue;
    2213             :                     }
    2214             : 
    2215           0 :                     svl::SharedString aStr = rCell.GetString();
    2216           0 :                     if (!aBucket.maStrVals.empty() && nThisRow == nPrevRow + 1)
    2217             :                     {
    2218             :                         // Secondary strings.
    2219           0 :                         aBucket.maStrVals.push_back(aStr);
    2220             :                     }
    2221             :                     else
    2222             :                     {
    2223             :                         // First string.
    2224           0 :                         aBucket.flush(mrMat, mnMatCol);
    2225           0 :                         aBucket.mnStrValStart = nThisRow - mnTopRow;
    2226           0 :                         aBucket.maStrVals.push_back(aStr);
    2227             :                     }
    2228           0 :                 }
    2229             : 
    2230          50 :                 aBucket.flush(mrMat, mnMatCol);
    2231             :             }
    2232          50 :             break;
    2233             :             default:
    2234             :                 ;
    2235             :         }
    2236         356 :     }
    2237             : };
    2238             : 
    2239             : }
    2240             : 
    2241         247 : void ScColumn::FillMatrix( ScMatrix& rMat, size_t nMatCol, SCROW nRow1, SCROW nRow2 ) const
    2242             : {
    2243         247 :     FillMatrixHandler aFunc(rMat, nMatCol, nRow1, nCol, nTab, pDocument);
    2244         247 :     sc::ParseBlock(maCells.begin(), maCells, aFunc, nRow1, nRow2);
    2245         247 : }
    2246             : 
    2247             : namespace {
    2248             : 
    2249             : template<typename _Blk>
    2250          18 : void getBlockIterators(
    2251             :     const sc::CellStoreType::iterator& it, size_t& rLenRemain,
    2252             :     typename _Blk::iterator& rData, typename _Blk::iterator& rDataEnd )
    2253             : {
    2254          18 :     rData = _Blk::begin(*it->data);
    2255          18 :     if (rLenRemain >= it->size)
    2256             :     {
    2257             :         // Block is shorter than the remaining requested length.
    2258          18 :         rDataEnd = _Blk::end(*it->data);
    2259          18 :         rLenRemain -= it->size;
    2260             :     }
    2261             :     else
    2262             :     {
    2263           0 :         rDataEnd = rData;
    2264           0 :         std::advance(rDataEnd, rLenRemain);
    2265           0 :         rLenRemain = 0;
    2266             :     }
    2267          18 : }
    2268             : 
    2269          11 : bool appendToBlock(
    2270             :     ScDocument* pDoc, sc::FormulaGroupContext& rCxt, sc::FormulaGroupContext::ColArray& rColArray,
    2271             :     size_t nPos, size_t nArrayLen, const sc::CellStoreType::iterator& _it, const sc::CellStoreType::iterator& itEnd )
    2272             : {
    2273          11 :     svl::SharedStringPool& rPool = pDoc->GetSharedStringPool();
    2274          11 :     size_t nLenRemain = nArrayLen - nPos;
    2275             :     double fNan;
    2276          11 :     rtl::math::setNan(&fNan);
    2277             : 
    2278          29 :     for (sc::CellStoreType::iterator it = _it; it != itEnd; ++it)
    2279             :     {
    2280          29 :         switch (it->type)
    2281             :         {
    2282             :             case sc::element_type_string:
    2283             :             {
    2284           5 :                 sc::string_block::iterator itData, itDataEnd;
    2285           5 :                 getBlockIterators<sc::string_block>(it, nLenRemain, itData, itDataEnd);
    2286           5 :                 rCxt.ensureStrArray(rColArray, nArrayLen);
    2287             : 
    2288          10 :                 for (; itData != itDataEnd; ++itData, ++nPos)
    2289           5 :                     (*rColArray.mpStrArray)[nPos] = itData->getDataIgnoreCase();
    2290             :             }
    2291           5 :             break;
    2292             :             case sc::element_type_edittext:
    2293             :             {
    2294           0 :                 sc::edittext_block::iterator itData, itDataEnd;
    2295           0 :                 getBlockIterators<sc::edittext_block>(it, nLenRemain, itData, itDataEnd);
    2296           0 :                 rCxt.ensureStrArray(rColArray, nArrayLen);
    2297             : 
    2298           0 :                 for (; itData != itDataEnd; ++itData, ++nPos)
    2299             :                 {
    2300           0 :                     OUString aStr = ScEditUtil::GetString(**itData, pDoc);
    2301           0 :                     (*rColArray.mpStrArray)[nPos] = rPool.intern(aStr).getDataIgnoreCase();
    2302           0 :                 }
    2303             :             }
    2304           0 :             break;
    2305             :             case sc::element_type_formula:
    2306             :             {
    2307           6 :                 sc::formula_block::iterator itData, itDataEnd;
    2308           6 :                 getBlockIterators<sc::formula_block>(it, nLenRemain, itData, itDataEnd);
    2309             : 
    2310             :                 /* tdf#91416 setting progress in triggers a resize of the window
    2311             :                    and so ScTabView::DoResize and an InterpretVisible and
    2312             :                    InterpretDirtyCells which resets the mpFormulaGroupCxt that
    2313             :                    the current rCxt points to, which is bad, so disable progress
    2314             :                    during GetResult
    2315             :                  */
    2316           6 :                 ScProgress *pProgress = ScProgress::GetInterpretProgress();
    2317           6 :                 bool bTempDisableProgress = pProgress && pProgress->Enabled();
    2318           6 :                 if (bTempDisableProgress)
    2319           6 :                     pProgress->Disable();
    2320             : 
    2321          14 :                 for (; itData != itDataEnd; ++itData, ++nPos)
    2322             :                 {
    2323           8 :                     ScFormulaCell& rFC = **itData;
    2324             : 
    2325           8 :                     sc::FormulaResultValue aRes = rFC.GetResult();
    2326             : 
    2327           8 :                     if (aRes.meType == sc::FormulaResultValue::Invalid || aRes.mnError)
    2328             :                     {
    2329           0 :                         if (aRes.mnError == ScErrorCodes::errCircularReference)
    2330             :                         {
    2331             :                             // This cell needs to be recalculated on next visit.
    2332           0 :                             rFC.SetErrCode(0);
    2333           0 :                             rFC.SetDirtyVar();
    2334             :                         }
    2335           0 :                         return false;
    2336             :                     }
    2337             : 
    2338           8 :                     if (aRes.meType == sc::FormulaResultValue::String)
    2339             :                     {
    2340           1 :                         rCxt.ensureStrArray(rColArray, nArrayLen);
    2341           1 :                         (*rColArray.mpStrArray)[nPos] = aRes.maString.getDataIgnoreCase();
    2342             :                     }
    2343             :                     else
    2344             :                     {
    2345           7 :                         rCxt.ensureNumArray(rColArray, nArrayLen);
    2346           7 :                         (*rColArray.mpNumArray)[nPos] = aRes.mfValue;
    2347             :                     }
    2348           8 :                 }
    2349             : 
    2350           6 :                 if (bTempDisableProgress)
    2351           6 :                     pProgress->Enable();
    2352             :             }
    2353           6 :             break;
    2354             :             case sc::element_type_empty:
    2355             :             {
    2356          11 :                 if (nLenRemain > it->size)
    2357             :                 {
    2358           3 :                     nPos += it->size;
    2359           3 :                     nLenRemain -= it->size;
    2360             :                 }
    2361             :                 else
    2362             :                 {
    2363           8 :                     nPos = nArrayLen;
    2364           8 :                     nLenRemain = 0;
    2365             :                 }
    2366             :             }
    2367          11 :             break;
    2368             :             case sc::element_type_numeric:
    2369             :             {
    2370           7 :                 sc::numeric_block::iterator itData, itDataEnd;
    2371           7 :                 getBlockIterators<sc::numeric_block>(it, nLenRemain, itData, itDataEnd);
    2372           7 :                 rCxt.ensureNumArray(rColArray, nArrayLen);
    2373             : 
    2374         756 :                 for (; itData != itDataEnd; ++itData, ++nPos)
    2375         749 :                     (*rColArray.mpNumArray)[nPos] = *itData;
    2376             :             }
    2377           7 :             break;
    2378             :             default:
    2379           0 :                 return false;
    2380             :         }
    2381             : 
    2382          29 :         if (!nLenRemain)
    2383          11 :             return true;
    2384             :     }
    2385             : 
    2386           0 :     return false;
    2387             : }
    2388             : 
    2389           4 : void copyFirstStringBlock(
    2390             :     ScDocument& rDoc, sc::FormulaGroupContext::StrArrayType& rArray, size_t nLen, const sc::CellStoreType::iterator& itBlk )
    2391             : {
    2392           4 :     sc::FormulaGroupContext::StrArrayType::iterator itArray = rArray.begin();
    2393             : 
    2394           4 :     switch (itBlk->type)
    2395             :     {
    2396             :         case sc::element_type_string:
    2397             :         {
    2398           4 :             sc::string_block::iterator it = sc::string_block::begin(*itBlk->data);
    2399           4 :             sc::string_block::iterator itEnd = it;
    2400           4 :             std::advance(itEnd, nLen);
    2401          20 :             for (; it != itEnd; ++it, ++itArray)
    2402          16 :                 *itArray = it->getDataIgnoreCase();
    2403             :         }
    2404           4 :         break;
    2405             :         case sc::element_type_edittext:
    2406             :         {
    2407           0 :             sc::edittext_block::iterator it = sc::edittext_block::begin(*itBlk->data);
    2408           0 :             sc::edittext_block::iterator itEnd = it;
    2409           0 :             std::advance(itEnd, nLen);
    2410             : 
    2411           0 :             svl::SharedStringPool& rPool = rDoc.GetSharedStringPool();
    2412           0 :             for (; it != itEnd; ++it, ++itArray)
    2413             :             {
    2414           0 :                 EditTextObject* pText = *it;
    2415           0 :                 OUString aStr = ScEditUtil::GetString(*pText, &rDoc);
    2416           0 :                 *itArray = rPool.intern(aStr).getDataIgnoreCase();
    2417           0 :             }
    2418             :         }
    2419           0 :         break;
    2420             :         default:
    2421             :             ;
    2422             :     }
    2423           4 : }
    2424             : 
    2425             : sc::FormulaGroupContext::ColArray*
    2426           4 : copyFirstFormulaBlock(
    2427             :     sc::FormulaGroupContext& rCxt, const sc::CellStoreType::iterator& itBlk, size_t nArrayLen,
    2428             :     SCTAB nTab, SCCOL nCol )
    2429             : {
    2430             :     double fNan;
    2431           4 :     rtl::math::setNan(&fNan);
    2432             : 
    2433           4 :     size_t nLen = std::min(itBlk->size, nArrayLen);
    2434             : 
    2435           4 :     sc::formula_block::iterator it = sc::formula_block::begin(*itBlk->data);
    2436           4 :     sc::formula_block::iterator itEnd;
    2437             : 
    2438           4 :     sc::FormulaGroupContext::NumArrayType* pNumArray = NULL;
    2439           4 :     sc::FormulaGroupContext::StrArrayType* pStrArray = NULL;
    2440             : 
    2441           4 :     itEnd = it;
    2442           4 :     std::advance(itEnd, nLen);
    2443           4 :     size_t nPos = 0;
    2444          32 :     for (; it != itEnd; ++it, ++nPos)
    2445             :     {
    2446          28 :         ScFormulaCell& rFC = **it;
    2447          28 :         sc::FormulaResultValue aRes = rFC.GetResult();
    2448          28 :         if (aRes.meType == sc::FormulaResultValue::Invalid || aRes.mnError)
    2449             :         {
    2450           0 :             if (aRes.mnError == ScErrorCodes::errCircularReference)
    2451             :             {
    2452             :                 // This cell needs to be recalculated on next visit.
    2453           0 :                 rFC.SetErrCode(0);
    2454           0 :                 rFC.SetDirtyVar();
    2455             :             }
    2456           0 :             return NULL;
    2457             :         }
    2458             : 
    2459          28 :         if (aRes.meType == sc::FormulaResultValue::Value)
    2460             :         {
    2461          28 :             if (!pNumArray)
    2462             :             {
    2463             :                 rCxt.maNumArrays.push_back(
    2464           4 :                     new sc::FormulaGroupContext::NumArrayType(nArrayLen, fNan));
    2465           4 :                 pNumArray = &rCxt.maNumArrays.back();
    2466             :             }
    2467             : 
    2468          28 :             (*pNumArray)[nPos] = aRes.mfValue;
    2469             :         }
    2470             :         else
    2471             :         {
    2472           0 :             if (!pStrArray)
    2473             :             {
    2474             :                 rCxt.maStrArrays.push_back(
    2475           0 :                     new sc::FormulaGroupContext::StrArrayType(nArrayLen, NULL));
    2476           0 :                 pStrArray = &rCxt.maStrArrays.back();
    2477             :             }
    2478             : 
    2479           0 :             (*pStrArray)[nPos] = aRes.maString.getDataIgnoreCase();
    2480             :         }
    2481          28 :     }
    2482             : 
    2483           4 :     if (!pNumArray && !pStrArray)
    2484             :         // At least one of these arrays should be allocated.
    2485           0 :         return NULL;
    2486             : 
    2487           4 :     return rCxt.setCachedColArray(nTab, nCol, pNumArray, pStrArray);
    2488             : }
    2489             : 
    2490             : struct NonNullStringFinder : std::unary_function<const rtl_uString*, bool>
    2491             : {
    2492         751 :     bool operator() (const rtl_uString* p) const { return p != NULL; }
    2493             : };
    2494             : 
    2495           5 : bool hasNonEmpty( const sc::FormulaGroupContext::StrArrayType& rArray, SCROW nRow1, SCROW nRow2 )
    2496             : {
    2497             :     // The caller has to make sure the array is at least nRow2+1 long.
    2498           5 :     sc::FormulaGroupContext::StrArrayType::const_iterator it = rArray.begin();
    2499           5 :     std::advance(it, nRow1);
    2500           5 :     sc::FormulaGroupContext::StrArrayType::const_iterator itEnd = it;
    2501           5 :     std::advance(itEnd, nRow2-nRow1+1);
    2502           5 :     return std::any_of(it, itEnd, NonNullStringFinder());
    2503             : }
    2504             : 
    2505             : }
    2506             : 
    2507          22 : formula::VectorRefArray ScColumn::FetchVectorRefArray( SCROW nRow1, SCROW nRow2 )
    2508             : {
    2509          22 :     if (nRow1 > nRow2)
    2510           0 :         return formula::VectorRefArray(formula::VectorRefArray::Invalid);
    2511             : 
    2512             :     // See if the requested range is already cached.
    2513          22 :     sc::FormulaGroupContext& rCxt = pDocument->GetFormulaGroupContext();
    2514          22 :     sc::FormulaGroupContext::ColArray* pColArray = rCxt.getCachedColArray(nTab, nCol, nRow2+1);
    2515          22 :     if (pColArray)
    2516             :     {
    2517           4 :         const double* pNum = NULL;
    2518           4 :         if (pColArray->mpNumArray)
    2519           4 :             pNum = &(*pColArray->mpNumArray)[nRow1];
    2520             : 
    2521           4 :         rtl_uString** pStr = NULL;
    2522           4 :         if (pColArray->mpStrArray && hasNonEmpty(*pColArray->mpStrArray, nRow1, nRow2))
    2523           0 :             pStr = &(*pColArray->mpStrArray)[nRow1];
    2524             : 
    2525           4 :         return formula::VectorRefArray(pNum, pStr);
    2526             :     }
    2527             : 
    2528             :     double fNan;
    2529          18 :     rtl::math::setNan(&fNan);
    2530             : 
    2531             :     // We need to fetch all cell values from row 0 to nRow2 for caching purposes.
    2532          18 :     sc::CellStoreType::iterator itBlk = maCells.begin();
    2533          18 :     switch (itBlk->type)
    2534             :     {
    2535             :         case sc::element_type_numeric:
    2536             :         {
    2537           3 :             if (static_cast<size_t>(nRow2) < itBlk->size)
    2538             :             {
    2539             :                 // Requested range falls within the first block. No need to cache.
    2540           1 :                 const double* p = &sc::numeric_block::at(*itBlk->data, nRow1);
    2541           1 :                 return formula::VectorRefArray(p);
    2542             :             }
    2543             : 
    2544             :             // Allocate a new array and copy the values to it.
    2545           2 :             sc::numeric_block::const_iterator it = sc::numeric_block::begin(*itBlk->data);
    2546           2 :             sc::numeric_block::const_iterator itEnd = sc::numeric_block::end(*itBlk->data);
    2547           2 :             rCxt.maNumArrays.push_back(new sc::FormulaGroupContext::NumArrayType(it, itEnd));
    2548           2 :             sc::FormulaGroupContext::NumArrayType& rArray = rCxt.maNumArrays.back();
    2549           2 :             rArray.resize(nRow2+1, fNan); // allocate to the requested length.
    2550             : 
    2551           2 :             pColArray = rCxt.setCachedColArray(nTab, nCol, &rArray, NULL);
    2552           2 :             if (!pColArray)
    2553             :                 // Failed to insert a new cached column array.
    2554           0 :                 return formula::VectorRefArray(formula::VectorRefArray::Invalid);
    2555             : 
    2556             :             // Fill the remaining array with values from the following blocks.
    2557           2 :             size_t nPos = itBlk->size;
    2558           2 :             ++itBlk;
    2559           2 :             if (!appendToBlock(pDocument, rCxt, *pColArray, nPos, nRow2+1, itBlk, maCells.end()))
    2560           0 :                 return formula::VectorRefArray(formula::VectorRefArray::Invalid);
    2561             : 
    2562           2 :             if (pColArray->mpStrArray)
    2563           1 :                 return formula::VectorRefArray(&(*pColArray->mpNumArray)[nRow1], &(*pColArray->mpStrArray)[nRow1]);
    2564             :             else
    2565           1 :                 return formula::VectorRefArray(&(*pColArray->mpNumArray)[nRow1]);
    2566             :         }
    2567             :         break;
    2568             :         case sc::element_type_string:
    2569             :         case sc::element_type_edittext:
    2570             :         {
    2571           4 :             rCxt.maStrArrays.push_back(new sc::FormulaGroupContext::StrArrayType(nRow2+1, NULL));
    2572           4 :             sc::FormulaGroupContext::StrArrayType& rArray = rCxt.maStrArrays.back();
    2573           4 :             pColArray = rCxt.setCachedColArray(nTab, nCol, NULL, &rArray);
    2574           4 :             if (!pColArray)
    2575             :                 // Failed to insert a new cached column array.
    2576           0 :                 return formula::VectorRefArray();
    2577             : 
    2578           4 :             if (static_cast<size_t>(nRow2) < itBlk->size)
    2579             :             {
    2580             :                 // Requested range falls within the first block.
    2581           2 :                 copyFirstStringBlock(*pDocument, rArray, nRow2+1, itBlk);
    2582           2 :                 return formula::VectorRefArray(&rArray[nRow1]);
    2583             :             }
    2584             : 
    2585           2 :             copyFirstStringBlock(*pDocument, rArray, itBlk->size, itBlk);
    2586             : 
    2587             :             // Fill the remaining array with values from the following blocks.
    2588           2 :             size_t nPos = itBlk->size;
    2589           2 :             ++itBlk;
    2590           2 :             if (!appendToBlock(pDocument, rCxt, *pColArray, nPos, nRow2+1, itBlk, maCells.end()))
    2591           0 :                 return formula::VectorRefArray(formula::VectorRefArray::Invalid);
    2592             : 
    2593           2 :             if (pColArray->mpNumArray)
    2594           1 :                 return formula::VectorRefArray(&(*pColArray->mpNumArray)[nRow1], &(*pColArray->mpStrArray)[nRow1]);
    2595             :             else
    2596           1 :                 return formula::VectorRefArray(&(*pColArray->mpStrArray)[nRow1]);
    2597             :         }
    2598             :         break;
    2599             :         case sc::element_type_formula:
    2600             :         {
    2601           4 :             if (static_cast<size_t>(nRow2) < itBlk->size)
    2602             :             {
    2603             :                 // Requested length is within a single block, and the data is
    2604             :                 // not cached.
    2605           2 :                 pColArray = copyFirstFormulaBlock(rCxt, itBlk, nRow2+1, nTab, nCol);
    2606           2 :                 if (!pColArray)
    2607             :                     // Failed to insert a new cached column array.
    2608           0 :                     return formula::VectorRefArray(formula::VectorRefArray::Invalid);
    2609             : 
    2610           2 :                 const double* pNum = NULL;
    2611           2 :                 rtl_uString** pStr = NULL;
    2612           2 :                 if (pColArray->mpNumArray)
    2613           2 :                     pNum = &(*pColArray->mpNumArray)[nRow1];
    2614           2 :                 if (pColArray->mpStrArray)
    2615           0 :                     pStr = &(*pColArray->mpStrArray)[nRow1];
    2616             : 
    2617           2 :                 return formula::VectorRefArray(pNum, pStr);
    2618             :             }
    2619             : 
    2620           2 :             pColArray = copyFirstFormulaBlock(rCxt, itBlk, nRow2+1, nTab, nCol);
    2621           2 :             if (!pColArray)
    2622             :                 // Failed to insert a new cached column array.
    2623           0 :                 return formula::VectorRefArray(formula::VectorRefArray::Invalid);
    2624             : 
    2625           2 :             size_t nPos = itBlk->size;
    2626           2 :             ++itBlk;
    2627           2 :             if (!appendToBlock(pDocument, rCxt, *pColArray, nPos, nRow2+1, itBlk, maCells.end()))
    2628           0 :                 return formula::VectorRefArray(formula::VectorRefArray::Invalid);
    2629             : 
    2630           2 :             const double* pNum = NULL;
    2631           2 :             rtl_uString** pStr = NULL;
    2632           2 :             if (pColArray->mpNumArray)
    2633           2 :                 pNum = &(*pColArray->mpNumArray)[nRow1];
    2634           2 :             if (pColArray->mpStrArray)
    2635           1 :                 pStr = &(*pColArray->mpStrArray)[nRow1];
    2636             : 
    2637           2 :             return formula::VectorRefArray(pNum, pStr);
    2638             :         }
    2639             :         break;
    2640             :         case sc::element_type_empty:
    2641             :         {
    2642             :             // Fill the whole length with NaN's.
    2643           7 :             rCxt.maNumArrays.push_back(new sc::FormulaGroupContext::NumArrayType(nRow2+1, fNan));
    2644           7 :             sc::FormulaGroupContext::NumArrayType& rArray = rCxt.maNumArrays.back();
    2645           7 :             pColArray = rCxt.setCachedColArray(nTab, nCol, &rArray, NULL);
    2646           7 :             if (!pColArray)
    2647             :                 // Failed to insert a new cached column array.
    2648           0 :                 return formula::VectorRefArray(formula::VectorRefArray::Invalid);
    2649             : 
    2650           7 :             if (static_cast<size_t>(nRow2) < itBlk->size)
    2651           2 :                 return formula::VectorRefArray(&(*pColArray->mpNumArray)[nRow1]);
    2652             : 
    2653             :             // Fill the remaining array with values from the following blocks.
    2654           5 :             size_t nPos = itBlk->size;
    2655           5 :             ++itBlk;
    2656           5 :             if (!appendToBlock(pDocument, rCxt, *pColArray, nPos, nRow2+1, itBlk, maCells.end()))
    2657           0 :                 return formula::VectorRefArray(formula::VectorRefArray::Invalid);
    2658             : 
    2659           5 :             if (pColArray->mpStrArray && hasNonEmpty(*pColArray->mpStrArray, nRow1, nRow2))
    2660           0 :                 return formula::VectorRefArray(&(*pColArray->mpNumArray)[nRow1], &(*pColArray->mpStrArray)[nRow1]);
    2661             :             else
    2662           5 :                 return formula::VectorRefArray(&(*pColArray->mpNumArray)[nRow1]);
    2663             :         }
    2664             :         break;
    2665             :         default:
    2666             :             ;
    2667             :     }
    2668             : 
    2669           0 :     return formula::VectorRefArray(formula::VectorRefArray::Invalid);
    2670             : }
    2671             : 
    2672           0 : void ScColumn::SetFormulaResults( SCROW nRow, const double* pResults, size_t nLen )
    2673             : {
    2674           0 :     sc::CellStoreType::position_type aPos = maCells.position(nRow);
    2675           0 :     sc::CellStoreType::iterator it = aPos.first;
    2676           0 :     if (it->type != sc::element_type_formula)
    2677             :         // This is not a formula block.
    2678           0 :         return;
    2679             : 
    2680           0 :     size_t nBlockLen = it->size - aPos.second;
    2681           0 :     if (nBlockLen < nLen)
    2682             :         // Result array is longer than the length of formula cells. Not good.
    2683           0 :         return;
    2684             : 
    2685           0 :     sc::formula_block::iterator itCell = sc::formula_block::begin(*it->data);
    2686           0 :     std::advance(itCell, aPos.second);
    2687             : 
    2688           0 :     const double* pResEnd = pResults + nLen;
    2689           0 :     for (; pResults != pResEnd; ++pResults, ++itCell)
    2690             :     {
    2691           0 :         ScFormulaCell& rCell = **itCell;
    2692           0 :         sal_uInt16 nErr = GetDoubleErrorValue(*pResults);
    2693           0 :         if (nErr != 0)
    2694           0 :             rCell.SetResultError(nErr);
    2695             :         else
    2696           0 :             rCell.SetResultDouble(*pResults);
    2697           0 :         rCell.ResetDirty();
    2698           0 :         rCell.SetChanged(true);
    2699             :     }
    2700             : }
    2701             : 
    2702           0 : void ScColumn::SetFormulaResults( SCROW nRow, const formula::FormulaTokenRef* pResults, size_t nLen )
    2703             : {
    2704           0 :     sc::CellStoreType::position_type aPos = maCells.position(nRow);
    2705           0 :     sc::CellStoreType::iterator it = aPos.first;
    2706           0 :     if (it->type != sc::element_type_formula)
    2707             :         // This is not a formula block.
    2708           0 :         return;
    2709             : 
    2710           0 :     size_t nBlockLen = it->size - aPos.second;
    2711           0 :     if (nBlockLen < nLen)
    2712             :         // Result array is longer than the length of formula cells. Not good.
    2713           0 :         return;
    2714             : 
    2715           0 :     sc::formula_block::iterator itCell = sc::formula_block::begin(*it->data);
    2716           0 :     std::advance(itCell, aPos.second);
    2717             : 
    2718           0 :     const formula::FormulaTokenRef* pResEnd = pResults + nLen;
    2719           0 :     for (; pResults != pResEnd; ++pResults, ++itCell)
    2720             :     {
    2721           0 :         ScFormulaCell& rCell = **itCell;
    2722           0 :         rCell.SetResultToken(pResults->get());
    2723           0 :         rCell.ResetDirty();
    2724           0 :         rCell.SetChanged(true);
    2725             :     }
    2726             : }
    2727             : 
    2728          78 : void ScColumn::SetNumberFormat( SCROW nRow, sal_uInt32 nNumberFormat )
    2729             : {
    2730          78 :     ApplyAttr(nRow, SfxUInt32Item(ATTR_VALUE_FORMAT, nNumberFormat));
    2731          78 : }
    2732             : 
    2733       37577 : ScFormulaCell * const * ScColumn::GetFormulaCellBlockAddress( SCROW nRow, size_t& rBlockSize ) const
    2734             : {
    2735       37577 :     if (!ValidRow(nRow))
    2736             :     {
    2737           0 :         rBlockSize = 0;
    2738           0 :         return NULL;
    2739             :     }
    2740             : 
    2741       37577 :     std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow);
    2742       37577 :     sc::CellStoreType::const_iterator it = aPos.first;
    2743       37577 :     if (it == maCells.end())
    2744             :     {
    2745           0 :         rBlockSize = 0;
    2746           0 :         return NULL;
    2747             :     }
    2748             : 
    2749       37577 :     if (it->type != sc::element_type_formula)
    2750             :     {
    2751             :         // Not a formula cell.
    2752       33112 :         rBlockSize = 0;
    2753       33112 :         return NULL;
    2754             :     }
    2755             : 
    2756        4465 :     rBlockSize = it->size;
    2757        4465 :     return &sc::formula_block::at(*it->data, aPos.second);
    2758             : }
    2759             : 
    2760       37556 : const ScFormulaCell* ScColumn::FetchFormulaCell( SCROW nRow ) const
    2761             : {
    2762       37556 :     size_t nBlockSize = 0;
    2763       37556 :     ScFormulaCell const * const * pp = GetFormulaCellBlockAddress( nRow, nBlockSize );
    2764       37556 :     return pp ? *pp : NULL;
    2765             : }
    2766             : 
    2767          49 : void ScColumn::FindDataAreaPos(SCROW& rRow, bool bDown) const
    2768             : {
    2769             :     // If the cell is empty, find the next non-empty cell position. If the
    2770             :     // cell is not empty, find the last non-empty cell position in the current
    2771             :     // contiguous cell block.
    2772             : 
    2773          49 :     std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(rRow);
    2774          49 :     sc::CellStoreType::const_iterator it = aPos.first;
    2775          49 :     if (it == maCells.end())
    2776             :         // Invalid row.
    2777          17 :         return;
    2778             : 
    2779          49 :     if (it->type == sc::element_type_empty)
    2780             :     {
    2781             :         // Current cell is empty. Find the next non-empty cell.
    2782          12 :         rRow = FindNextVisibleRowWithContent(it, rRow, bDown);
    2783          12 :         return;
    2784             :     }
    2785             : 
    2786             :     // Current cell is not empty.
    2787          37 :     SCROW nNextRow = FindNextVisibleRow(rRow, bDown);
    2788          37 :     aPos = maCells.position(it, nNextRow);
    2789          37 :     it = aPos.first;
    2790          37 :     if (it->type == sc::element_type_empty)
    2791             :     {
    2792             :         // Next visible cell is empty. Find the next non-empty cell.
    2793           5 :         rRow = FindNextVisibleRowWithContent(it, nNextRow, bDown);
    2794           5 :         return;
    2795             :     }
    2796             : 
    2797             :     // Next visible cell is non-empty. Find the edge that's still visible.
    2798          32 :     SCROW nLastRow = nNextRow;
    2799      393330 :     do
    2800             :     {
    2801      393345 :         nNextRow = FindNextVisibleRow(nLastRow, bDown);
    2802      393345 :         if (nNextRow == nLastRow)
    2803          15 :             break;
    2804             : 
    2805      393330 :         aPos = maCells.position(it, nNextRow);
    2806      393330 :         it = aPos.first;
    2807      393330 :         if (it->type != sc::element_type_empty)
    2808      393313 :             nLastRow = nNextRow;
    2809             :     }
    2810      393330 :     while (it->type != sc::element_type_empty);
    2811             : 
    2812          32 :     rRow = nLastRow;
    2813             : }
    2814             : 
    2815        5019 : bool ScColumn::HasDataAt(SCROW nRow) const
    2816             : {
    2817        5019 :     return maCells.get_type(nRow) != sc::element_type_empty;
    2818             : }
    2819             : 
    2820       43998 : bool ScColumn::IsAllAttrEqual( const ScColumn& rCol, SCROW nStartRow, SCROW nEndRow ) const
    2821             : {
    2822       43998 :     if (pAttrArray && rCol.pAttrArray)
    2823       43998 :         return pAttrArray->IsAllEqual( *rCol.pAttrArray, nStartRow, nEndRow );
    2824             :     else
    2825           0 :         return !pAttrArray && !rCol.pAttrArray;
    2826             : }
    2827             : 
    2828       12035 : bool ScColumn::IsVisibleAttrEqual( const ScColumn& rCol, SCROW nStartRow, SCROW nEndRow ) const
    2829             : {
    2830       12035 :     if (pAttrArray && rCol.pAttrArray)
    2831       12035 :         return pAttrArray->IsVisibleEqual( *rCol.pAttrArray, nStartRow, nEndRow );
    2832             :     else
    2833           0 :         return !pAttrArray && !rCol.pAttrArray;
    2834             : }
    2835             : 
    2836     2085888 : bool ScColumn::GetFirstVisibleAttr( SCROW& rFirstRow ) const
    2837             : {
    2838     2085888 :     if (pAttrArray)
    2839     2085888 :         return pAttrArray->GetFirstVisibleAttr( rFirstRow );
    2840             :     else
    2841           0 :         return false;
    2842             : }
    2843             : 
    2844     3248305 : bool ScColumn::GetLastVisibleAttr( SCROW& rLastRow, bool bFullFormattedArea ) const
    2845             : {
    2846     3248305 :     if (pAttrArray)
    2847             :     {
    2848             :         // row of last cell is needed
    2849     3248305 :         SCROW nLastData = GetLastDataPos();    // always including notes, 0 if none
    2850             : 
    2851     3248305 :         return pAttrArray->GetLastVisibleAttr( rLastRow, nLastData, bFullFormattedArea );
    2852             :     }
    2853             :     else
    2854           0 :         return false;
    2855             : }
    2856             : 
    2857           0 : bool ScColumn::HasVisibleAttrIn( SCROW nStartRow, SCROW nEndRow ) const
    2858             : {
    2859           0 :     if (pAttrArray)
    2860           0 :         return pAttrArray->HasVisibleAttrIn( nStartRow, nEndRow );
    2861             :     else
    2862           0 :         return false;
    2863             : }
    2864             : 
    2865             : namespace {
    2866             : 
    2867             : class FindUsedRowsHandler
    2868             : {
    2869             :     typedef mdds::flat_segment_tree<SCROW,bool> UsedRowsType;
    2870             :     UsedRowsType& mrUsed;
    2871             :     UsedRowsType::const_iterator miUsed;
    2872             : public:
    2873          10 :     FindUsedRowsHandler(UsedRowsType& rUsed) : mrUsed(rUsed), miUsed(rUsed.begin()) {}
    2874             : 
    2875          39 :     void operator() (const sc::CellStoreType::value_type& node, size_t nOffset, size_t nDataSize)
    2876             :     {
    2877          39 :         if (node.type == sc::element_type_empty)
    2878          51 :             return;
    2879             : 
    2880          27 :         SCROW nRow1 = node.position + nOffset;
    2881          27 :         SCROW nRow2 = nRow1 + nDataSize - 1;
    2882          27 :         miUsed = mrUsed.insert(miUsed, nRow1, nRow2+1, true).first;
    2883             :     }
    2884             : };
    2885             : 
    2886             : }
    2887             : 
    2888          10 : void ScColumn::FindUsed( SCROW nStartRow, SCROW nEndRow, mdds::flat_segment_tree<SCROW,bool>& rUsed ) const
    2889             : {
    2890          10 :     FindUsedRowsHandler aFunc(rUsed);
    2891          10 :     sc::ParseBlock(maCells.begin(), maCells, aFunc, nStartRow, nEndRow);
    2892          10 : }
    2893             : 
    2894             : namespace {
    2895             : 
    2896       14703 : void startListening(
    2897             :     sc::BroadcasterStoreType& rStore, sc::BroadcasterStoreType::iterator& itBlockPos, size_t nElemPos,
    2898             :     SCROW nRow, SvtListener& rLst)
    2899             : {
    2900       14703 :     switch (itBlockPos->type)
    2901             :     {
    2902             :         case sc::element_type_broadcaster:
    2903             :         {
    2904             :             // Broadcaster already exists here.
    2905        6136 :             SvtBroadcaster* pBC = sc::broadcaster_block::at(*itBlockPos->data, nElemPos);
    2906        6136 :             rLst.StartListening(*pBC);
    2907             :         }
    2908        6136 :         break;
    2909             :         case mdds::mtv::element_type_empty:
    2910             :         {
    2911             :             // No broadcaster exists at this position yet.
    2912        8567 :             SvtBroadcaster* pBC = new SvtBroadcaster;
    2913        8567 :             rLst.StartListening(*pBC);
    2914        8567 :             itBlockPos = rStore.set(itBlockPos, nRow, pBC); // Store the block position for next iteration.
    2915             :         }
    2916        8567 :         break;
    2917             :         default:
    2918             : #if DEBUG_COLUMN_STORAGE
    2919             :             cout << "ScColumn::StartListening: wrong block type encountered in the broadcaster storage." << endl;
    2920             :             cout.flush();
    2921             :             abort();
    2922             : #else
    2923             :             ;
    2924             : #endif
    2925             :     }
    2926       14703 : }
    2927             : 
    2928             : }
    2929             : 
    2930        1059 : void ScColumn::StartListening( SvtListener& rLst, SCROW nRow )
    2931             : {
    2932        1059 :     std::pair<sc::BroadcasterStoreType::iterator,size_t> aPos = maBroadcasters.position(nRow);
    2933        1059 :     startListening(maBroadcasters, aPos.first, aPos.second, nRow, rLst);
    2934        1059 : }
    2935             : 
    2936         775 : void ScColumn::EndListening( SvtListener& rLst, SCROW nRow )
    2937             : {
    2938         775 :     SvtBroadcaster* pBC = GetBroadcaster(nRow);
    2939         775 :     if (!pBC)
    2940         861 :         return;
    2941             : 
    2942         689 :     rLst.EndListening(*pBC);
    2943         689 :     if (!pBC->HasListeners())
    2944             :         // There is no more listeners for this cell. Remove the broadcaster.
    2945         423 :         maBroadcasters.set_empty(nRow, nRow);
    2946             : }
    2947             : 
    2948       13644 : void ScColumn::StartListening( sc::StartListeningContext& rCxt, SCROW nRow, SvtListener& rLst )
    2949             : {
    2950       13644 :     if (!ValidRow(nRow))
    2951           0 :         return;
    2952             : 
    2953       13644 :     sc::ColumnBlockPosition* p = rCxt.getBlockPosition(nTab, nCol);
    2954       13644 :     if (!p)
    2955           0 :         return;
    2956             : 
    2957       13644 :     sc::BroadcasterStoreType::iterator& it = p->miBroadcasterPos;
    2958       13644 :     std::pair<sc::BroadcasterStoreType::iterator,size_t> aPos = maBroadcasters.position(it, nRow);
    2959       13644 :     it = aPos.first; // store the block position for next iteration.
    2960       13644 :     startListening(maBroadcasters, it, aPos.second, nRow, rLst);
    2961             : }
    2962             : 
    2963         595 : void ScColumn::EndListening( sc::EndListeningContext& rCxt, SCROW nRow, SvtListener& rListener )
    2964             : {
    2965         595 :     sc::ColumnBlockPosition* p = rCxt.getBlockPosition(nTab, nCol);
    2966         595 :     if (!p)
    2967           6 :         return;
    2968             : 
    2969         595 :     sc::BroadcasterStoreType::iterator& it = p->miBroadcasterPos;
    2970         595 :     std::pair<sc::BroadcasterStoreType::iterator,size_t> aPos = maBroadcasters.position(it, nRow);
    2971         595 :     it = aPos.first; // store the block position for next iteration.
    2972         595 :     if (it->type != sc::element_type_broadcaster)
    2973           6 :         return;
    2974             : 
    2975         589 :     SvtBroadcaster* pBC = sc::broadcaster_block::at(*it->data, aPos.second);
    2976             :     OSL_ASSERT(pBC);
    2977             : 
    2978         589 :     rListener.EndListening(*pBC);
    2979         589 :     if (!pBC->HasListeners())
    2980             :         // There is no more listeners for this cell. Add it to the purge list for later purging.
    2981         348 :         rCxt.addEmptyBroadcasterPosition(nTab, nCol, nRow);
    2982             : }
    2983             : 
    2984             : namespace {
    2985             : 
    2986             : class CompileDBFormulaHandler
    2987             : {
    2988             :     sc::CompileFormulaContext& mrCxt;
    2989             : 
    2990             : public:
    2991        9216 :     CompileDBFormulaHandler( sc::CompileFormulaContext& rCxt ) :
    2992        9216 :         mrCxt(rCxt) {}
    2993             : 
    2994           2 :     void operator() (size_t, ScFormulaCell* p)
    2995             :     {
    2996           2 :         p->CompileDBFormula(mrCxt);
    2997           2 :     }
    2998             : };
    2999             : 
    3000             : struct CompileColRowNameFormulaHandler
    3001             : {
    3002             :     sc::CompileFormulaContext& mrCxt;
    3003             : public:
    3004        7168 :     CompileColRowNameFormulaHandler( sc::CompileFormulaContext& rCxt ) : mrCxt(rCxt) {}
    3005             : 
    3006           0 :     void operator() (size_t, ScFormulaCell* p)
    3007             :     {
    3008           0 :         p->CompileColRowNameFormula(mrCxt);
    3009           0 :     }
    3010             : };
    3011             : 
    3012             : }
    3013             : 
    3014        9216 : void ScColumn::CompileDBFormula( sc::CompileFormulaContext& rCxt )
    3015             : {
    3016        9216 :     CompileDBFormulaHandler aFunc(rCxt);
    3017        9216 :     sc::ProcessFormula(maCells, aFunc);
    3018        9216 :     RegroupFormulaCells();
    3019        9216 : }
    3020             : 
    3021        7168 : void ScColumn::CompileColRowNameFormula( sc::CompileFormulaContext& rCxt )
    3022             : {
    3023        7168 :     CompileColRowNameFormulaHandler aFunc(rCxt);
    3024        7168 :     sc::ProcessFormula(maCells, aFunc);
    3025        7168 :     RegroupFormulaCells();
    3026        7168 : }
    3027             : 
    3028             : namespace {
    3029             : 
    3030             : class UpdateSubTotalHandler
    3031             : {
    3032             :     ScFunctionData& mrData;
    3033             : 
    3034         117 :     void update(double fVal, bool bVal)
    3035             :     {
    3036         117 :         if (mrData.bError)
    3037           0 :             return;
    3038             : 
    3039         117 :         switch (mrData.eFunc)
    3040             :         {
    3041             :             case SUBTOTAL_FUNC_SUM:
    3042             :             case SUBTOTAL_FUNC_AVE:
    3043             :             {
    3044          30 :                 if (!bVal)
    3045           4 :                     return;
    3046             : 
    3047          26 :                 ++mrData.nCount;
    3048          26 :                 if (!SubTotal::SafePlus(mrData.nVal, fVal))
    3049           0 :                     mrData.bError = true;
    3050             :             }
    3051          26 :             break;
    3052             :             case SUBTOTAL_FUNC_CNT:             // only the value
    3053             :             {
    3054          13 :                 if (!bVal)
    3055           2 :                     return;
    3056             : 
    3057          11 :                 ++mrData.nCount;
    3058             :             }
    3059          11 :             break;
    3060             :             case SUBTOTAL_FUNC_CNT2:            // everything
    3061          48 :                 ++mrData.nCount;
    3062          48 :             break;
    3063             :             case SUBTOTAL_FUNC_MAX:
    3064             :             {
    3065          13 :                 if (!bVal)
    3066           2 :                     return;
    3067             : 
    3068          11 :                 if (++mrData.nCount == 1 || fVal > mrData.nVal)
    3069          11 :                     mrData.nVal = fVal;
    3070             :             }
    3071          11 :             break;
    3072             :             case SUBTOTAL_FUNC_MIN:
    3073             :             {
    3074          13 :                 if (!bVal)
    3075           2 :                     return;
    3076             : 
    3077          11 :                 if (++mrData.nCount == 1 || fVal < mrData.nVal)
    3078           3 :                     mrData.nVal = fVal;
    3079             :             }
    3080          11 :             break;
    3081             :             default:
    3082             :             {
    3083             :                 // added to avoid warnings
    3084             :             }
    3085             :         }
    3086             :     }
    3087             : 
    3088             : public:
    3089      207872 :     UpdateSubTotalHandler(ScFunctionData& rData) : mrData(rData) {}
    3090             : 
    3091          63 :     void operator() (size_t /*nRow*/, double fVal)
    3092             :     {
    3093          63 :         update(fVal, true);
    3094          63 :     }
    3095             : 
    3096          27 :     void operator() (size_t /*nRow*/, const svl::SharedString&)
    3097             :     {
    3098          27 :         update(0.0, false);
    3099          27 :     }
    3100             : 
    3101           2 :     void operator() (size_t /*nRow*/, const EditTextObject*)
    3102             :     {
    3103           2 :         update(0.0, false);
    3104           2 :     }
    3105             : 
    3106          25 :     void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
    3107             :     {
    3108          25 :         double fVal = 0.0;
    3109          25 :         bool bVal = false;
    3110          25 :         if (mrData.eFunc != SUBTOTAL_FUNC_CNT2) // it doesn't interest us
    3111             :         {
    3112             : 
    3113          20 :             if (pCell->GetErrCode())
    3114             :             {
    3115           0 :                 if (mrData.eFunc != SUBTOTAL_FUNC_CNT) // simply remove from count
    3116           0 :                     mrData.bError = true;
    3117             :             }
    3118          20 :             else if (pCell->IsValue())
    3119             :             {
    3120          10 :                 fVal = pCell->GetValue();
    3121          10 :                 bVal = true;
    3122             :             }
    3123             :             // otherwise text
    3124             :         }
    3125             : 
    3126          25 :         update(fVal, bVal);
    3127          25 :     }
    3128             : };
    3129             : 
    3130             : }
    3131             : 
    3132             : //  multiple selections:
    3133      217088 : void ScColumn::UpdateSelectionFunction(
    3134             :     const ScRangeList& rRanges, ScFunctionData& rData, ScFlatBoolRowSegments& rHiddenRows )
    3135             : {
    3136      217088 :     sc::SingleColumnSpanSet aSpanSet;
    3137      217088 :     aSpanSet.scan(rRanges, nTab, nCol); // mark all selected rows.
    3138             : 
    3139             :     // Exclude all hidden rows.
    3140             :     ScFlatBoolRowSegments::RangeData aRange;
    3141      217088 :     SCROW nRow = 0;
    3142      726016 :     while (nRow <= MAXROW)
    3143             :     {
    3144      291840 :         if (!rHiddenRows.getRangeData(nRow, aRange))
    3145           0 :             break;
    3146             : 
    3147      291840 :         if (aRange.mbValue)
    3148             :             // Hidden range detected.
    3149       38912 :             aSpanSet.set(nRow, aRange.mnRow2, false);
    3150             : 
    3151      291840 :         nRow = aRange.mnRow2 + 1;
    3152             :     }
    3153             : 
    3154      434176 :     sc::SingleColumnSpanSet::SpansType aSpans;
    3155      217088 :     aSpanSet.getSpans(aSpans);
    3156             : 
    3157      217088 :     sc::SingleColumnSpanSet::SpansType::const_iterator it = aSpans.begin(), itEnd = aSpans.end();
    3158             : 
    3159      217088 :     switch (rData.eFunc)
    3160             :     {
    3161             :         case SUBTOTAL_FUNC_SELECTION_COUNT:
    3162             :         {
    3163             :             // Simply count selected rows regardless of cell contents.
    3164        9231 :             for (; it != itEnd; ++it)
    3165          15 :                 rData.nCount += it->mnRow2 - it->mnRow1 + 1;
    3166             :         }
    3167        9216 :         break;
    3168             :         case SUBTOTAL_FUNC_CNT2:
    3169             :         {
    3170             :             // We need to parse all non-empty cells.
    3171        6144 :             sc::CellStoreType::const_iterator itCellPos = maCells.begin();
    3172        6144 :             UpdateSubTotalHandler aFunc(rData);
    3173        6166 :             for (; it != itEnd; ++it)
    3174             :             {
    3175          66 :                 itCellPos = sc::ParseAllNonEmpty(
    3176          66 :                     itCellPos, maCells, it->mnRow1, it->mnRow2, aFunc);
    3177             :             }
    3178             :         }
    3179        6144 :         break;
    3180             :         default:
    3181             :         {
    3182             :             // We need to parse only numeric values.
    3183      201728 :             sc::CellStoreType::const_iterator itCellPos = maCells.begin();
    3184      201728 :             UpdateSubTotalHandler aFunc(rData);
    3185      201964 :             for (; it != itEnd; ++it)
    3186             :             {
    3187         708 :                 itCellPos = sc::ParseFormulaNumeric(
    3188         708 :                     itCellPos, maCells, it->mnRow1, it->mnRow2, aFunc);
    3189             :             }
    3190             :         }
    3191      217088 :     }
    3192      217088 : }
    3193             : 
    3194             : namespace {
    3195             : 
    3196             : class WeightedCounter
    3197             : {
    3198             :     size_t mnCount;
    3199             : public:
    3200        4478 :     WeightedCounter() : mnCount(0) {}
    3201             : 
    3202       20095 :     void operator() (const sc::CellStoreType::value_type& node)
    3203             :     {
    3204       20095 :         switch (node.type)
    3205             :         {
    3206             :             case sc::element_type_numeric:
    3207             :             case sc::element_type_string:
    3208        8685 :                 mnCount += node.size;
    3209        8685 :             break;
    3210             :             case sc::element_type_formula:
    3211             :             {
    3212             :                 // Each formula cell is worth its code length plus 5.
    3213         778 :                 sc::formula_block::const_iterator it = sc::formula_block::begin(*node.data);
    3214         778 :                 sc::formula_block::const_iterator itEnd = sc::formula_block::end(*node.data);
    3215        3270 :                 for (; it != itEnd; ++it)
    3216             :                 {
    3217        2492 :                     const ScFormulaCell* p = *it;
    3218        2492 :                     mnCount += 5 + p->GetCode()->GetCodeLen();
    3219             :                 }
    3220             :             }
    3221         778 :             break;
    3222             :             case sc::element_type_edittext:
    3223             :                 // each edit-text cell is worth 50.
    3224         183 :                 mnCount += node.size * 50;
    3225         183 :             break;
    3226             :             default:
    3227             :                 ;
    3228             :         }
    3229       20095 :     }
    3230             : 
    3231        4478 :     size_t getCount() const { return mnCount; }
    3232             : };
    3233             : 
    3234             : }
    3235             : 
    3236        4478 : sal_uInt32 ScColumn::GetWeightedCount() const
    3237             : {
    3238        4478 :     WeightedCounter aFunc;
    3239        4478 :     std::for_each(maCells.begin(), maCells.end(), aFunc);
    3240        4478 :     return aFunc.getCount();
    3241             : }
    3242             : 
    3243             : namespace {
    3244             : 
    3245             : class CodeCounter
    3246             : {
    3247             :     size_t mnCount;
    3248             : public:
    3249           0 :     CodeCounter() : mnCount(0) {}
    3250             : 
    3251           0 :     void operator() (size_t, const ScFormulaCell* p)
    3252             :     {
    3253           0 :         mnCount += p->GetCode()->GetCodeLen();
    3254           0 :     }
    3255             : 
    3256           0 :     size_t getCount() const { return mnCount; }
    3257             : };
    3258             : 
    3259             : }
    3260             : 
    3261           0 : sal_uInt32 ScColumn::GetCodeCount() const
    3262             : {
    3263           0 :     CodeCounter aFunc;
    3264           0 :     sc::ParseFormula(maCells, aFunc);
    3265           0 :     return aFunc.getCount();
    3266             : }
    3267             : 
    3268           0 : SCSIZE ScColumn::GetPatternCount() const
    3269             : {
    3270           0 :     return pAttrArray ? pAttrArray->Count() : 0;
    3271             : }
    3272             : 
    3273         113 : SCSIZE ScColumn::GetPatternCount( SCROW nRow1, SCROW nRow2 ) const
    3274             : {
    3275         113 :     return pAttrArray ? pAttrArray->Count( nRow1, nRow2 ) : 0;
    3276             : }
    3277             : 
    3278           0 : bool ScColumn::ReservePatternCount( SCSIZE nReserve )
    3279             : {
    3280           0 :     return pAttrArray && pAttrArray->Reserve( nReserve );
    3281         156 : }
    3282             : 
    3283             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.11