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