os/textandloc/textrendering/textformatting/tbox/FRMPAGE.CPP
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     1 /*
     2 * Copyright (c) 1996-2009 Nokia Corporation and/or its subsidiary(-ies).
     3 * All rights reserved.
     4 * This component and the accompanying materials are made available
     5 * under the terms of "Eclipse Public License v1.0"
     6 * which accompanies this distribution, and is available
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
     8 *
     9 * Initial Contributors:
    10 * Nokia Corporation - initial contribution.
    11 *
    12 * Contributors:
    13 *
    14 * Description: 
    15 *
    16 */
    17 
    18 
    19 #include "FRMPAGE.H"
    20 #include "FRMTLAY.H"
    21 #include "FRMCONST.H"
    22 #include <txtlaydc.h>
    23 
    24 #include "OstTraceDefinitions.h"
    25 #ifdef OST_TRACE_COMPILER_IN_USE
    26 #include "FRMPAGETraces.h"
    27 #endif
    28 
    29 #ifdef SYMBIAN_ENABLE_SPLIT_HEADERS
    30 #include "FRMCONST_INTERNAL.H"
    31 #include "FRMCONST_PARTNER.H"
    32 #endif
    33 
    34 /** Allocates and constructs a CTextPaginator object with a page list, the
    35 printer device for which the document is to be paginated and an active object
    36 priority.
    37 
    38 @param aPrinterDevice Pointer to the printer device for which the document is
    39 to be paginated. This must be provided.
    40 @param aCharsPerPage The page list. This is a client-provided array into which
    41 characters-per-page values are written. Ownership of the array remains with the
    42 client.
    43 @param aPriority Integer specifying the active object priority. A number of
    44 standard priorities are specified in CActive::TPriority.
    45 @return Pointer to the new paginator object. */
    46 EXPORT_C CTextPaginator* CTextPaginator::NewL(CPrinterDevice* aPrinterDevice,CArrayFix<TInt>* aPageList,TInt aPriority)
    47 	{
    48 	CTextPaginator* self=new(ELeave) CTextPaginator(aPriority); 
    49 	CleanupStack::PushL(self);
    50 	self->ConstructL(aPrinterDevice,aPageList);
    51 	CleanupStack::Pop();
    52 	return self;
    53 	}
    54 
    55 /** Destructor. Cancels the active object, if any. */
    56 EXPORT_C CTextPaginator::~CTextPaginator()
    57 	{
    58 	Cancel();
    59 	delete iLayout;
    60 	delete iPageLineArray;
    61 	delete iTempPageList;
    62 	}
    63 
    64 /** Sets a pagination observer (an instance of a class inherited from
    65 MPaginateObserver). The use of an observer is optional.
    66 
    67 An observer may be used when paginating a complete document in the background
    68 using the function PaginateCompleteDocumentL(). The observer notifies
    69 completion of pages, cancellation, errors, and on completion of multiple
    70 pagination.
    71 
    72 @param aObserver Observer object inherited from MPaginateObserver. */
    73 EXPORT_C void CTextPaginator::SetObserver(MPaginateObserver* aObserver)
    74 	{
    75 
    76 	iObserver=aObserver;
    77 	}
    78 
    79 /** Sets a pointer to the document which is to be paginated.
    80 @param aLayDoc The document to paginate. */
    81 EXPORT_C void CTextPaginator::SetDocumentL(MLayDoc* aLayDoc)
    82 	{
    83 
    84 	SetOrReplaceDocumentL(aLayDoc);
    85 	iPaginator.Reset();
    86 	iDocPos=0;
    87 	SetLayoutDimensions();
    88 	}
    89 
    90 /** Sets a pointer to the printer device for which the document is to be
    91 paginated.
    92 
    93 Note: This function must be called, and SetDocumentL() must have been called
    94 beforehand.
    95 
    96 @param aPrinterDevice The printer device. */
    97 EXPORT_C void CTextPaginator::SetPrinterDevice(CPrinterDevice* aPrinterDevice)
    98 	{
    99 	if (!iLayout)
   100 	    {
   101 	    OstTrace0( TRACE_FATAL, CTEXTPAGINATOR_SETPRINTERDEVICE, "EFDocumentToPaginateNotSet" );
   102 	    }
   103  	__ASSERT_ALWAYS(iLayout,FormPanic(EFDocumentToPaginateNotSet));
   104 	iPrinterDevice=aPrinterDevice;
   105 	iLayout->SetImageDeviceMap(aPrinterDevice);
   106 
   107 	iPageSizeInTwips=aPrinterDevice->CurrentPageSpecInTwips().OrientedPageSize();
   108  	SetLayoutDimensions();
   109 	}
   110 
   111 /** Sets the page width and height in twips, overriding the current values
   112 specified in the printer device.
   113 @param aPageSpec Contains the new page dimensions. */
   114 EXPORT_C void CTextPaginator::SetPageSpecInTwips(const TPageSpec& aPageSpec)
   115 	{
   116 
   117 	iPageSizeInTwips=aPageSpec.OrientedPageSize();
   118  	SetLayoutDimensions();
   119 	}
   120 
   121 /** Sets the widths of the page margins in twips.
   122 
   123 The page margin exists on all four sides of the page. It does not include the
   124 line cursor or labels margins. The labels and line cursor margins are set using
   125 SetTextMarginWidthsInTwips().
   126 
   127 @param aPageMargins The page margin widths. */
   128 EXPORT_C void CTextPaginator::SetPageMarginsInTwips(const TMargins& aPageMargins)
   129 	{
   130 	iPageMarginsInTwips=aPageMargins;
   131  	SetLayoutDimensions();
   132 	}
   133 
   134  /** Sets the widths in twips of:
   135 
   136 the labels margin the area within which paragraph labels are displayed,
   137 
   138 the gutter margin (also known as the line cursor margin) exists between the
   139 labels margin and the text area.
   140 
   141 @param aLabelMarginWidth The labels margin width.
   142 @param aGutterMarginWidth The gutter margin width. */
   143 EXPORT_C void CTextPaginator::SetTextMarginWidthsInTwips(TInt aLabelMarginWidth
   144 	,TInt aGutterMarginWidth) 
   145 	{
   146 	iLabelMarginWidthInTwips=aLabelMarginWidth;
   147 	iGutterMarginWidthInTwips=aGutterMarginWidth;
   148  	SetLayoutDimensions();
   149 	}
   150 
   151 CTextPaginator::CTextPaginator(TInt aPriority)
   152 	:CActive(aPriority)
   153 	{
   154 	}
   155 
   156 void CTextPaginator::ConstructL(CPrinterDevice* aPrinterDevice,CArrayFix<TInt>* aPageList)
   157 	{
   158 
   159 	iPageLineArray=new(ELeave) CArrayFixFlat<TPageLine>(EPageLineArrayGranularity);
   160 	iTempPageList=new(ELeave) CArrayFixFlat<TInt>(EPageListArrayGranularity);
   161 	iPrinterDevice=aPrinterDevice;
   162 	iPageList=aPageList;
   163 
   164 	iPaginator.SetArray(iTempPageList);
   165 	iPaginator.SetPageHeight(TextSizeInPixels().iHeight);
   166 
   167 	iPageSizeInTwips=iPrinterDevice->CurrentPageSpecInTwips().OrientedPageSize();
   168 	SetLayoutDimensions();
   169 	ResetPaginator();
   170 	}
   171 
   172 /** Initiates pagination of a complete document in the background using an
   173 active object. To start pagination, use either this function, or else
   174 incrementally paginate with AppendTextL() do not try to use both functions
   175 together.
   176 
   177 Note: SetDocumentL() must have been called beforehand, or a panic occurs. */
   178 EXPORT_C void CTextPaginator::PaginateCompleteDocumentL()
   179 	{
   180 	if (!iLayout)
   181 	    {
   182 	    OstTrace0( TRACE_FATAL, CTEXTPAGINATOR_PAGINATECOMPLETEDOCUMENTL, "EFDocumentToPaginateNotSet" );
   183 	    }
   184  	__ASSERT_ALWAYS(iLayout,FormPanic(EFDocumentToPaginateNotSet));
   185   	if (iPageList->Count()==0)
   186 		iPageList->AppendL(iLayDoc->LdDocumentLength());
   187 	if (!IsAdded())
   188 		CActiveScheduler::Add(this); // Adds itself to the active scheduler
   189  	iMode=EFPaginateCompleteDocument;
   190 	ResetPaginator();
   191 	Reque();
   192 	}
   193 
   194 /** Paginates incrementally as a document is being constructed (by appending
   195 paragraphs, for example). Call this function every time text is added to the
   196 document.
   197 
   198 The function PaginationCompletedL() should be called at the end (in order to
   199 complete the last entry in the characters-per-page array).
   200 
   201 Use either this function, or else paginate in the background with
   202 PaginateCompleteDocumentL() - do not try to use both functions together.
   203 
   204 Note: SetDocumentL() must have been called beforehand, or a panic occurs.
   205 
   206 @param aCumulativeDocPos The first time the function is called, this should be
   207 given a value of zero. Returns the last document position which has been
   208 paginated.
   209 @return A count of the current number of pages. */
   210 EXPORT_C TInt CTextPaginator::AppendTextL(TInt& aCumulativeDocPos)
   211 	{
   212 	if (!iLayout)
   213 	    {
   214 	    OstTrace0( TRACE_FATAL, CTEXTPAGINATOR_APPENDTEXTL, "EFDocumentToPaginateNotSet" );
   215 	    }
   216 	__ASSERT_ALWAYS(iLayout,FormPanic(EFDocumentToPaginateNotSet));
   217 	if (aCumulativeDocPos>=iLayout->DocumentLength())
   218 	    {
   219 	    OstTrace0( TRACE_FATAL, DUP1_CTEXTPAGINATOR_APPENDTEXTL, "EFInvalidDocPos" );
   220 	    }
   221  	__ASSERT_ALWAYS(aCumulativeDocPos<iLayout->DocumentLength(),FormPanic(EFInvalidDocPos));
   222  	iMode=EFPaginateIncrementally;
   223 
   224   	if (iPageList->Count()==0)
   225 		ResetPaginator();
   226 
   227 	TBool moreToDo=ETrue;
   228 	while(moreToDo)
   229 		{
   230 		moreToDo = iDocPos<=iLayDoc->LdDocumentLength();
   231 		if (moreToDo)
   232 			{
   233 			TrapPaginateParagraphL();
   234 			}
   235 		else
   236 			{
   237 			if (iMode==EFPaginateCompleteDocument)
   238 				{
   239 				iPaginator.FlushL(iDocPos);
   240 				PageCompleted();
   241 				}
   242 			iPageLineArray->Reset();
   243 			iPageLineArray->Compress();
   244 			}
   245 		}
   246 
   247 	aCumulativeDocPos=iDocPos;
   248 
   249 	TRAPD(err,CopyTempPageListL());
   250 	if (err)
   251 	    {
   252 		LeaveL(err);
   253 	    }
   254 	return iPageList->Count();
   255 	}
   256 
   257 /** This function should be called when incremental pagination has completed
   258 (see AppendTextL()), to complete the final entry in the page list. If an
   259 observer has been set, calls its NotifyCompletion() function.
   260 
   261 @return Count of total number of pages. */
   262 EXPORT_C TInt CTextPaginator::PaginationCompletedL()
   263 	{
   264 	TRAPD(err,iPaginator.FlushL(iDocPos));
   265 	if (err)
   266 		LeaveL(err);
   267 	iLayout->DiscardFormat();
   268 	TRAP(err,CopyTempPageListL());
   269 	if (err)
   270 		LeaveL(err);
   271 	if (iObserver)
   272 		iObserver->NotifyCompletion();
   273 	return iPageList->Count();
   274 	}
   275 
   276 void CTextPaginator::RunL()
   277 //
   278 // Called by active scheduler.
   279 // Paginates a document one paragraph at a time through succeeding    
   280 // calls.
   281 //
   282 	{
   283 	TBool moreToDo = iDocPos<=iLayDoc->LdDocumentLength();
   284 	if (moreToDo)
   285 		{
   286 		TrapPaginateParagraphL();
   287 		}
   288 	else
   289 		{
   290 		if (iMode==EFPaginateCompleteDocument)
   291 			{
   292 			iPaginator.FlushL(iDocPos);
   293 			PageCompleted();
   294 			}
   295 		iPageLineArray->Reset();
   296 		iPageLineArray->Compress();
   297 		}
   298 	
   299 	if (moreToDo)
   300 		Reque();
   301 	else
   302 		{
   303 		iLayout->DiscardFormat();
   304 		TRAPD(err,CopyTempPageListL());
   305 		if (err)
   306 			LeaveL(err);
   307 		if (iObserver)
   308 			iObserver->NotifyCompletion();
   309 		}
   310 	}
   311 
   312 void CTextPaginator::DoCancel()
   313 	{
   314 	iPaginator.Reset();
   315 	iLayout->DiscardFormat();
   316 	iDocPos=0;
   317 	iPageBreakChar=EFalse;
   318 
   319 	if (iObserver)
   320 		iObserver->NotifyError(KErrCancel);	
   321 	}
   322 
   323 void CTextPaginator::SetLayoutDimensions()
   324 	{
   325 	iPaginator.SetPageHeight(TextSizeInPixels().iHeight);
   326 	if (iLayout)
   327 		iLayout->SetFormatMode(CLayoutData::EFPrintMode,TextRectInTwips().Width(),iPrinterDevice);
   328 	}
   329 
   330 void CTextPaginator::SetOrReplaceDocumentL(MLayDoc* aLayDoc)
   331 	{
   332 
   333 	iLayDoc=aLayDoc;
   334 	if (iLayout)
   335 		iLayout->SetLayDoc(aLayDoc);
   336 	else
   337 		iLayout=CTextLayout::NewL(aLayDoc,TextSizeInPixels().iWidth);
   338 	iLayout->SetImageDeviceMap(iPrinterDevice);
   339 	}
   340 
   341 TRect CTextPaginator::TextRectInTwips() const
   342 	{
   343 	TRect textRect;
   344 
   345 	textRect.iTl.iX=iPageMarginsInTwips.iLeft+iGutterMarginWidthInTwips+iLabelMarginWidthInTwips;
   346 	textRect.iTl.iY=iPageMarginsInTwips.iTop;
   347 	textRect.iBr.iX=iPageSizeInTwips.iWidth-iPageMarginsInTwips.iRight;
   348 	textRect.iBr.iY=iPageSizeInTwips.iHeight-iPageMarginsInTwips.iBottom;
   349 
   350 	return textRect;
   351 	}
   352 
   353 TSize CTextPaginator::TextSizeInPixels() const
   354 	{
   355 	TRect textRect=iPrinterDevice->TwipsToPixels(TextRectInTwips());
   356 
   357 	return textRect.Size();
   358 	}
   359 
   360 void CTextPaginator::TrapPaginateParagraphL()
   361 	{
   362 	TRAPD(err,PaginateParagraphL());
   363 	if (err)
   364 		LeaveL(err);
   365 	}
   366 
   367 void CTextPaginator::PaginateParagraphL()
   368 	{
   369 	TInt lineHeight;
   370 	TBool keepTogether;  // Prevents page break in a paragraph when ETrue.
   371 	TBool keepWithNext;  // Prevents page break between this & next para when ETrue.
   372 	TBool startNewPage;  // Inserts page break before this paragraph when ETrue.
   373 	TBool widowOrphan;   // Prevents widowing/orphaning of para. lines when ETrue.
   374 	TPageLine pageLine;
   375 	TInt numLines;
   376 	CParaFormat* paraFormat=NULL;
   377 
   378 	paraFormat=CParaFormat::NewLC();
   379 	iLayDoc->GetParagraphFormatL(paraFormat,iDocPos);
   380 	TInt docPos=iDocPos;
   381 	TBool startOfPara=(iLayDoc->LdToParagraphStart(docPos)==0);
   382 
   383 	keepTogether=paraFormat->iKeepTogether;
   384 	keepWithNext=paraFormat->iKeepWithNext;
   385 	startNewPage=paraFormat->iStartNewPage;
   386 	widowOrphan=paraFormat->iWidowOrphan;
   387 
   388 	iPageLineArray->Reset();		   // Better safe than sorry at the moment ###
   389 	iPageLineArray->Compress();
   390 
   391 	TInt lines=0;
   392 	TBool moreToDo = ETrue;
   393 	do 
   394 		{
   395 		pageLine.iDocPos=iDocPos;
   396 		pageLine.iStartNewPage=EFalse;
   397 		if (iPageBreakChar)
   398 			pageLine.iStartNewPage=ETrue;
   399 		moreToDo=iLayout->FormatLineL(paraFormat,iDocPos,lineHeight,iPageBreakChar);
   400 		lines++;
   401 		pageLine.iLineHeight=lineHeight;
   402 		if (keepTogether)
   403 			pageLine.iKeepWithNext=ETrue;
   404 		else
   405 			pageLine.iKeepWithNext=EFalse;
   406 		iPageLineArray->AppendL(pageLine);
   407 		} while (moreToDo && lines<EFMaximumNumberLinesInBlock);
   408 
   409 
   410 	TBool endOfPara=(!moreToDo);
   411 	TBool penultimateLine=EFalse;
   412 	numLines=iPageLineArray->Count();
   413 	if (!endOfPara)
   414 		{
   415 		docPos=iDocPos;
   416 		TBool pageBreakChar;
   417 		penultimateLine=(!iLayout->FormatLineL(paraFormat,docPos,lineHeight,pageBreakChar));
   418 		}
   419 
   420 	if (startNewPage && startOfPara)
   421 		(*iPageLineArray)[0].iStartNewPage=ETrue;
   422 
   423 	if (keepTogether && endOfPara)
   424 		(*iPageLineArray)[numLines-1].iKeepWithNext=EFalse;
   425 
   426 	if (keepWithNext && endOfPara)
   427 		(*iPageLineArray)[numLines-1].iKeepWithNext=ETrue;
   428 		
   429 	if (widowOrphan)
   430 		{
   431 		if (startOfPara)
   432 			(*iPageLineArray)[0].iKeepWithNext=ETrue;
   433 		if (endOfPara && numLines>=2)
   434 			(*iPageLineArray)[numLines-2].iKeepWithNext=ETrue;
   435 		else if (penultimateLine)
   436 			(*iPageLineArray)[numLines-1].iKeepWithNext=ETrue;
   437 		}
   438 
   439 	TBool pageBreak = EFalse;
   440 	for (TInt i=0; i<numLines; i++)
   441 		{
   442 		pageBreak=iPaginator.AppendLineL((*iPageLineArray)[i]);
   443 		if (pageBreak)
   444 			PageCompleted();
   445 		}
   446 
   447 	iPageLineArray->Reset();
   448 	iPageLineArray->Compress();
   449 
   450 	CleanupStack::PopAndDestroy();	// delete format;
   451 	}
   452 
   453 void CTextPaginator::PageCompleted()
   454 	{
   455 	if (iObserver)
   456 		iObserver->NotifyPageCompletion(iTempPageList->Count());
   457 	}
   458 
   459 void CTextPaginator::Reque()
   460 //
   461 // Called just before Paginate Process goes to sleep to set it active 
   462 //
   463 	{
   464 	TRequestStatus *pS=(&iStatus);
   465 	User::RequestComplete(pS,0);
   466 	SetActive();
   467 	}
   468 
   469 void CTextPaginator::ResetPaginator()
   470 //
   471 	{
   472 	
   473 	iDocPos=0;
   474 	iPageBreakChar=EFalse;
   475 	iPaginator.Reset();
   476 	}
   477 
   478 void CTextPaginator::CopyTempPageListL()
   479 //
   480 // Copies temp page list to one that external user sees
   481 //
   482 	{
   483 	if (iTempPageList->Count()<1 && iMode!=EFPaginateIncrementally)
   484 	    {
   485 	    OstTrace0( TRACE_DUMP, CTEXTPAGINATOR_COPYTEMPPAGELISTL, "EFPageListEmpty" );
   486 	    }
   487 	__ASSERT_DEBUG(iTempPageList->Count()>=1||iMode==EFPaginateIncrementally,FormPanic(EFPageListEmpty));
   488 	TRAPD(err,iPageList->ResizeL(iTempPageList->Count()));
   489 	if (err)
   490 		LeaveL(err);
   491 
   492 	{for(TInt ii=0;ii<iTempPageList->Count();ii++)
   493 		(*iPageList)[ii]=(*iTempPageList)[ii];
   494 	}
   495 	}
   496 
   497 
   498 void CTextPaginator::LeaveL(TInt aErr)
   499 //
   500 // Something has left
   501 // Reset everything.
   502 //
   503 	{
   504 	iPaginator.Reset();
   505 	iLayout->DiscardFormat();
   506 	iDocPos=0;
   507 
   508 	iPageLineArray->Reset();
   509 	iPageLineArray->Compress();
   510 	iTempPageList->Reset();
   511 	iTempPageList->Compress();
   512 
   513 	if (iObserver)
   514 		iObserver->NotifyError(aErr);
   515 
   516 	OstTrace1( TRACE_FATAL, CTEXTPAGINATOR_LEAVEL, "CTextPaginator::LeaveL;aErr=%d", aErr );
   517 	
   518 	User::Leave(aErr);
   519 	}
   520