Author:	 Arunsakh Sachamuneewongse
Date: 	29th March 2001
1.	Introduction

One of the functional requirements in 6.2, as requested by the Pearl and the Crystal DFRDs, was auto-hyphenation. Since the Pearl and Crystal devices screens are smaller, they wanted to avoid a jagged white space on the right hand side of a text editable screen introduced when the lines are broken. The following was what was happening:

An example of how in text boxes, the extremely long words at the end of a line are wrapped to the next line leaving an uneven jagged white space on the right hand side of the screen which is undesirable.	

After a little consideration, it was decided that a fully fledge auto-hyphenation was out of the scope of the project for 6.2. An alternative solution was suggested, Custom Wrapping or Custom line breaking, which would allow a line to be broken in any way required to eliminate the jagged white spaces.  

2.	Custom Wrapping

The class MTmCustom in FORM defines the four virtual functions involving line breaking. These four functions are: 

TUint LineBreakClass(TUint aCode,TUint& aRangeStart,TUint& aRangeEnd) const;
TBool LineBreakPossible(TUint aPrevClass,TUint aNextClass,TBool aHaveSpaces) const;
TBool GetLineBreakInContext(const TDesC& aText,TInt aMinBreakPos,TInt aMaxBreakPos,
					TBool aForwards,TInt& aBreakPos) const;
TBool IsHangingCharacter(TUint aChar) const;

The function LineBreakClass returns the assigned line breaking class value for the character aCode. It also returns the range of characters that share the same line breaking class, starting from aRangeStart till aRangeEnd. 

LineBreakPossible returns TRUE if a line break is possible between characters of the two specified classes. If aHaveSpaces is TRUE, one or more characters in ESpLineBreakClass was found between the characters in the two specified classes.

GetLineBreakInContext returns the first (if aForwards is TRUE) or last (if aForwards is FALSE) linebreak in aText, this must be in the range aMinBreakPos...aMaxBreakPos, which is a run of characters in the class ESaLineBreakClass, usually employed for Thai, Lao and Khmer
letters, because these scripts don't use word spaces and need dictionary-based line breaking.
The break position is returned in aBreakPos, which must be > 0 and < aText.Length() - 1.
Return TRUE if a break is found, FALSE otherwise.

IsHangingCharacter return TRUE if this character, aChar, can overhang the measured right end of the line.

To change the line breaking behaviour one/all of these functions need to be overridden. It was decided to provide a new Interface class to override these line-breaking functions. So a new interface was added in FORM. This is the class MFormCustomWrap.

class MFormCustomWrap
	{
public:
	IMPORT_C virtual TUint LineBreakClass(TUint aCode,TUint& aRangeStart,TUint& aRangeEnd) const;
	IMPORT_C virtual TBool LineBreakPossible(TUint aPrevClass,TUint aNextClass,TBool aHaveSpaces) const;
	IMPORT_C virtual TBool GetLineBreakInContext(const TDesC& aText,TInt aMinBreakPos,TInt aMaxBreakPos,TBool aForwards,TInt& aBreakPos) const;
	IMPORT_C virtual TBool IsHangingCharacter(TUint aChar) const;
private:
	IMPORT_C virtual void MFormCustomWrap_Reserved_1();
	IMPORT_C virtual void MFormCustomWrap_Reserved_2();	
	};

Besides adding the new interface, a few more changes were made in FORM to allow custom wrapping to take place. The following were the changes made in FORM. 

A new member was added in class TLayDocTextSource, which is internal to Symbian. This class  is derived from the class MTmSource, which is derived from MTmCustom where the line breaking functions are defined. 

const MFormCustomWrap* iCustomWrap;	     // if non-null, points to custom wrapping routines

Also added in the class TLayDocTextSource were 4 function overrides 

TUint LineBreakClass(TUint aCode,TUint& aRangeStart,TUint& aRangeEnd) const;
TBool LineBreakPossible(TUint aPrevClass,TUint aNextClass,TBool aHaveSpaces) const;
TBool GetLineBreakInContext(const TDesC& aText,TInt aMinBreakPos,TInt aMaxBreakPos,
					TBool aForwards,TInt& aBreakPos) const;
TBool IsHangingCharacter(TUint aChar) const;

If iCustomWrap is set then the override implementations are called, else the base implementation of these functions are called, which is the implementation in MTmCustom. 

2 new functions were added in class CTextLayout: 

IMPORT_C void SetCustomWrap(const MFormCustomWrap* aCustomWrap);
IMPORT_C const MFormCustomWrap* CustomWrap() const;

The class CTextLayout is the lowest-level text formatting class provided by FORM. It has as its member a pointer to TLayDocTextSource, iSource. 

SetCustomWrap(const MFormCustomWrap* aCustomWrap) sets 
iSource.iCustomWrap = aCustomWrap and  CustomWrap() returns iSource.iCustomWrap. 

In order to use the custom wrapping interface, a class has to implement the custom wrapping interface MFormCustomWrap. That class then needs to be set as the custom wrapper by passing a pointer to that class in the function SetCustomWrap in CTextLayout.  

The following are the changes made in UIKLAF and UIKON to allow the text editable window – Edwin – to eliminate the jagged white space on the right hand side of the screen by implementing the custom wrapping interface. 

A new class implementing the MFormCustomWrap interface was added in the UIKLAFGT component. 

// Lafmain.h
class CLafEdwinCustomWrapBase : public CBase, public MFormCustomWrap
	{
…
…
	IMPORT_C TBool LineBreakPossible(TUint aPrevClass,TUint aNextClass,TBool aHaveSpaces) const;
…
…
	};

CLafEdwinCustomWrapBase implements MFormCustomWrap and overrides the interfaces virtual functions. Here I have shown one of the functions that have been overridden. LineBreakPossible returns TRUE if it is possible to break line between the two classes. The overridden implementation returns TRUE all the time, thus allowing a line break anywhere. 

In UIKON, in the class CEikEdwin the following changes were made.

A New flag was added to the enum TFlags: - ENoCustomWrap	 	=0x02000000

CEikEdwin has a pointer to CTextLayout – iLayout.  So what was needed now was to add a new member data to CEikEdwin, a pointer to CLafEdwinCustomWrapBase and call CTextLayouts SetCustomWrap function passing the pointer to CLafEdwinCustomWrapBase.  When creating a CEikEdwin, the flag ENoCustomWrap can be used to establish whether the Edwin is allowed custom wrapping or not.