2001-09-28 20:14:13 +00:00
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version : NPL 1.1 / GPL 2.0 / LGPL 2.1
1998-09-08 22:34:40 +00:00
*
2001-09-28 20:14:13 +00:00
* The contents of this file are subject to the Netscape Public License
* Version 1.1 ( the " License " ) ; you may not use this file except in
* compliance with the License . You may obtain a copy of the License at
* http : //www.mozilla.org/NPL/
1998-09-08 22:34:40 +00:00
*
2001-09-28 20:14:13 +00:00
* Software distributed under the License is distributed on an " AS IS " basis ,
* WITHOUT WARRANTY OF ANY KIND , either express or implied . See the License
* for the specific language governing rights and limitations under the
* License .
1998-09-08 22:34:40 +00:00
*
1999-11-06 03:40:37 +00:00
* The Original Code is mozilla . org code .
*
2001-09-28 20:14:13 +00:00
* The Initial Developer of the Original Code is
* Netscape Communications Corporation .
* Portions created by the Initial Developer are Copyright ( C ) 1998
* the Initial Developer . All Rights Reserved .
1999-11-06 03:40:37 +00:00
*
2001-09-28 20:14:13 +00:00
* Contributor ( s ) :
2000-04-17 14:40:46 +00:00
* Robert O ' Callahan < roc + moz @ cs . cmu . edu >
2001-09-27 18:34:30 +00:00
* Roger B . Sidje < rbs @ maths . uq . edu . au >
* Pierre Phaneuf < pp @ ludusdesign . com >
2002-01-10 02:32:43 +00:00
* Prabhat Hegde < prabhat . hegde @ sun . com >
2001-09-28 20:14:13 +00:00
*
* Alternatively , the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later ( the " GPL " ) , or
* the GNU Lesser General Public License Version 2.1 or later ( the " LGPL " ) ,
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above . If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL , and not to allow others to
* use your version of this file under the terms of the NPL , indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL . If you do not delete
* the provisions above , a recipient may use your version of this file under
* the terms of any one of the NPL , the GPL or the LGPL .
*
* * * * * * END LICENSE BLOCK * * * * * */
1999-02-12 17:45:58 +00:00
# include "nsCOMPtr.h"
1998-09-08 22:34:40 +00:00
# include "nsHTMLParts.h"
# include "nsCRT.h"
# include "nsSplittableFrame.h"
1998-09-15 00:19:49 +00:00
# include "nsLineLayout.h"
1998-09-08 22:34:40 +00:00
# include "nsString.h"
2001-10-26 17:18:35 +00:00
# include "nsUnicharUtils.h"
1998-09-08 22:34:40 +00:00
# include "nsIPresContext.h"
1999-04-13 01:15:16 +00:00
# include "nsIContent.h"
1998-09-08 22:34:40 +00:00
# include "nsStyleConsts.h"
# include "nsIStyleContext.h"
# include "nsCoord.h"
# include "nsIFontMetrics.h"
# include "nsIRenderingContext.h"
# include "nsIPresShell.h"
# include "nsIView.h"
# include "nsIViewManager.h"
# include "nsITimerCallback.h"
# include "nsITimer.h"
# include "prtime.h"
# include "nsVoidArray.h"
# include "prprf.h"
# include "nsIDOMText.h"
# include "nsIDocument.h"
# include "nsIDeviceContext.h"
1999-02-11 23:12:28 +00:00
# include "nsIFocusTracker.h"
1999-06-16 23:55:48 +00:00
# include "nsICaret.h"
1998-10-26 17:27:53 +00:00
# include "nsHTMLAtoms.h"
1999-02-24 18:21:23 +00:00
# include "nsILineBreaker.h"
1999-04-06 22:41:44 +00:00
# include "nsIWordBreaker.h"
1998-09-08 22:34:40 +00:00
1998-10-20 00:21:18 +00:00
# include "nsITextContent.h"
# include "nsTextFragment.h"
# include "nsTextTransformer.h"
1999-02-24 05:33:40 +00:00
# include "nsLayoutAtoms.h"
1999-03-12 00:17:14 +00:00
# include "nsIFrameSelection.h"
2000-09-14 11:45:01 +00:00
# include "nsISelection.h"
1999-04-26 04:02:04 +00:00
# include "nsIDOMRange.h"
2000-04-04 09:07:41 +00:00
# include "nsILookAndFeel.h"
2001-05-10 14:19:58 +00:00
# include "nsCSSRendering.h"
1998-10-20 00:21:18 +00:00
1999-06-19 20:36:44 +00:00
# include "nsILineIterator.h"
1999-10-13 01:15:26 +00:00
# include "nsIPref.h"
# include "nsIServiceManager.h"
2001-08-17 03:13:07 +00:00
# ifdef ACCESSIBILITY
2001-04-01 01:01:33 +00:00
# include "nsIAccessible.h"
# include "nsIAccessibilityService.h"
2001-08-17 03:13:07 +00:00
# endif
# include "nsINameSpaceManager.h"
2001-07-16 02:40:48 +00:00
# include "nsGUIEvent.h"
1999-10-13 01:15:26 +00:00
2001-04-11 23:32:21 +00:00
# ifdef IBMBIDI
# include "nsBidiFrames.h"
# include "nsBidiPresUtils.h"
# include "nsITextFrame.h"
//ahmed
2002-02-19 20:41:32 +00:00
# include "nsBidiUtils.h"
2001-04-11 23:32:21 +00:00
//ahmed end
# endif // IBMBIDI
2002-01-10 02:32:43 +00:00
# ifdef SUNCTL
# include "nsILE.h"
# endif /* SUNCTL */
2000-05-16 22:48:28 +00:00
static NS_DEFINE_CID ( kPrefCID , NS_PREF_CID ) ;
1998-09-08 22:34:40 +00:00
# ifdef NS_DEBUG
# undef NOISY_BLINK
1999-09-22 00:41:13 +00:00
# undef DEBUG_WORD_WRAPPING
1999-09-17 23:14:47 +00:00
# undef NOISY_REFLOW
1999-09-21 00:12:50 +00:00
# undef NOISY_TRIM
1998-09-08 22:34:40 +00:00
# else
# undef NOISY_BLINK
1998-10-10 04:35:21 +00:00
# undef DEBUG_WORD_WRAPPING
1999-09-17 23:14:47 +00:00
# undef NOISY_REFLOW
1999-09-21 00:12:50 +00:00
# undef NOISY_TRIM
1998-09-08 22:34:40 +00:00
# endif
1999-08-19 06:06:57 +00:00
// #define DEBUGWORDJUMP
2001-03-22 01:27:13 +00:00
# define kSZLIG 0x00DF
1999-09-22 00:40:56 +00:00
//----------------------------------------------------------------------
# define TEXT_BUF_SIZE 100
//----------------------------------------
2002-02-15 14:48:12 +00:00
// checks to see if the text can be lightened..
// text is darkend
inline PRBool CanDarken ( nsIPresContext * aPresContext )
{
PRBool darken , haveBackground ;
aPresContext - > GetBackgroundColorDraw ( haveBackground ) ;
if ( PR_TRUE = = haveBackground ) {
darken = PR_FALSE ;
} else {
aPresContext - > GetBackgroundImageDraw ( haveBackground ) ;
if ( PR_TRUE = = haveBackground ) {
darken = PR_FALSE ;
} else {
darken = PR_TRUE ;
}
}
return darken ;
}
1999-09-22 00:40:56 +00:00
struct nsAutoIndexBuffer {
nsAutoIndexBuffer ( ) ;
~ nsAutoIndexBuffer ( ) ;
nsresult GrowTo ( PRInt32 aAtLeast ) ;
PRInt32 * mBuffer ;
PRInt32 mBufferLen ;
PRInt32 mAutoBuffer [ TEXT_BUF_SIZE ] ;
} ;
nsAutoIndexBuffer : : nsAutoIndexBuffer ( )
: mBuffer ( mAutoBuffer ) ,
mBufferLen ( TEXT_BUF_SIZE )
{
2002-02-05 01:41:13 +00:00
memset ( mAutoBuffer , 0 , sizeof ( mAutoBuffer ) ) ;
1999-09-22 00:40:56 +00:00
}
nsAutoIndexBuffer : : ~ nsAutoIndexBuffer ( )
{
if ( mBuffer & & ( mBuffer ! = mAutoBuffer ) ) {
delete [ ] mBuffer ;
}
}
nsresult
nsAutoIndexBuffer : : GrowTo ( PRInt32 aAtLeast )
{
2000-02-14 01:54:20 +00:00
if ( aAtLeast > mBufferLen )
{
PRInt32 newSize = mBufferLen * 2 ;
if ( newSize < mBufferLen + aAtLeast ) {
newSize = mBufferLen * 2 + aAtLeast ;
}
PRInt32 * newBuffer = new PRInt32 [ newSize ] ;
if ( ! newBuffer ) {
return NS_ERROR_OUT_OF_MEMORY ;
}
2002-02-05 01:41:13 +00:00
memset ( newBuffer , 0 , sizeof ( PRInt32 ) * newSize ) ;
2002-01-12 03:18:55 +00:00
memcpy ( newBuffer , mBuffer , sizeof ( PRInt32 ) * mBufferLen ) ;
2000-02-14 01:54:20 +00:00
if ( mBuffer ! = mAutoBuffer ) {
delete [ ] mBuffer ;
}
mBuffer = newBuffer ;
mBufferLen = newSize ;
1999-09-22 00:40:56 +00:00
}
return NS_OK ;
}
2000-03-31 07:26:07 +00:00
1999-09-22 00:40:56 +00:00
//----------------------------------------------------------------------
1998-10-20 00:21:18 +00:00
1999-04-20 00:23:33 +00:00
// Helper class for managing blinking text
1998-09-08 22:34:40 +00:00
2000-03-25 00:49:58 +00:00
class nsBlinkTimer : public nsITimerCallback
{
1998-09-08 22:34:40 +00:00
public :
1999-04-20 00:23:33 +00:00
nsBlinkTimer ( ) ;
virtual ~ nsBlinkTimer ( ) ;
1998-09-08 22:34:40 +00:00
NS_DECL_ISUPPORTS
1999-10-26 04:44:41 +00:00
void AddFrame ( nsIPresContext * aPresContext , nsIFrame * aFrame ) ;
1998-09-08 22:34:40 +00:00
1999-04-20 00:23:33 +00:00
PRBool RemoveFrame ( nsIFrame * aFrame ) ;
1998-09-08 22:34:40 +00:00
PRInt32 FrameCount ( ) ;
void Start ( ) ;
void Stop ( ) ;
2000-01-21 21:56:09 +00:00
NS_IMETHOD_ ( void ) Notify ( nsITimer * timer ) ;
1998-09-08 22:34:40 +00:00
2000-03-25 00:49:58 +00:00
static nsresult AddBlinkFrame ( nsIPresContext * aPresContext , nsIFrame * aFrame ) ;
static nsresult RemoveBlinkFrame ( nsIFrame * aFrame ) ;
static PRBool GetBlinkIsOff ( ) { return sBlinkTextOff ; }
protected :
1999-10-26 04:44:41 +00:00
struct FrameData {
nsIPresContext * mPresContext ; // pres context associated with the frame
nsIFrame * mFrame ;
FrameData ( nsIPresContext * aPresContext ,
nsIFrame * aFrame )
: mPresContext ( aPresContext ) , mFrame ( aFrame ) { }
} ;
2000-05-17 02:49:35 +00:00
nsCOMPtr < nsITimer > mTimer ;
2000-03-25 00:49:58 +00:00
nsVoidArray mFrames ;
1999-10-26 04:44:41 +00:00
nsIPresContext * mPresContext ;
2000-03-25 00:49:58 +00:00
protected :
static nsBlinkTimer * sTextBlinker ;
static PRBool sBlinkTextOff ;
1998-09-08 22:34:40 +00:00
} ;
2000-03-25 00:49:58 +00:00
nsBlinkTimer * nsBlinkTimer : : sTextBlinker = nsnull ;
PRBool nsBlinkTimer : : sBlinkTextOff = PR_FALSE ;
1999-04-20 00:23:33 +00:00
# ifdef NOISY_BLINK
static PRTime gLastTick ;
# endif
nsBlinkTimer : : nsBlinkTimer ( )
{
NS_INIT_REFCNT ( ) ;
}
nsBlinkTimer : : ~ nsBlinkTimer ( )
{
Stop ( ) ;
2000-03-25 00:49:58 +00:00
sTextBlinker = nsnull ;
1999-04-20 00:23:33 +00:00
}
void nsBlinkTimer : : Start ( )
{
2000-05-17 02:49:35 +00:00
nsresult rv ;
2000-09-13 23:57:52 +00:00
mTimer = do_CreateInstance ( " @mozilla.org/timer;1 " , & rv ) ;
1999-04-20 00:23:33 +00:00
if ( NS_OK = = rv ) {
2002-06-11 20:47:04 +00:00
mTimer - > Init ( this , 750 , PR_TRUE , NS_TYPE_REPEATING_PRECISE ) ;
1999-04-20 00:23:33 +00:00
}
}
void nsBlinkTimer : : Stop ( )
{
if ( nsnull ! = mTimer ) {
mTimer - > Cancel ( ) ;
}
}
2001-08-21 01:48:11 +00:00
NS_IMPL_ISUPPORTS1 ( nsBlinkTimer , nsITimerCallback )
1999-04-20 00:23:33 +00:00
1999-10-26 04:44:41 +00:00
void nsBlinkTimer : : AddFrame ( nsIPresContext * aPresContext , nsIFrame * aFrame ) {
FrameData * frameData = new FrameData ( aPresContext , aFrame ) ;
mFrames . AppendElement ( frameData ) ;
1999-04-20 00:23:33 +00:00
if ( 1 = = mFrames . Count ( ) ) {
Start ( ) ;
}
}
PRBool nsBlinkTimer : : RemoveFrame ( nsIFrame * aFrame ) {
1999-10-26 04:44:41 +00:00
PRInt32 i , n = mFrames . Count ( ) ;
PRBool rv = PR_FALSE ;
for ( i = 0 ; i < n ; i + + ) {
FrameData * frameData = ( FrameData * ) mFrames . ElementAt ( i ) ;
if ( frameData - > mFrame = = aFrame ) {
rv = mFrames . RemoveElementAt ( i ) ;
delete frameData ;
break ;
}
}
1999-04-20 00:23:33 +00:00
if ( 0 = = mFrames . Count ( ) ) {
Stop ( ) ;
}
return rv ;
}
PRInt32 nsBlinkTimer : : FrameCount ( ) {
return mFrames . Count ( ) ;
}
2000-01-21 21:56:09 +00:00
NS_IMETHODIMP_ ( void ) nsBlinkTimer : : Notify ( nsITimer * timer )
1999-04-20 00:23:33 +00:00
{
// Toggle blink state bit so that text code knows whether or not to
// render. All text code shares the same flag so that they all blink
// in unison.
2000-03-25 00:49:58 +00:00
sBlinkTextOff = PRBool ( ! sBlinkTextOff ) ;
1999-04-20 00:23:33 +00:00
2000-01-21 21:56:09 +00:00
# ifndef REPEATING_TIMERS
1999-04-20 00:23:33 +00:00
// XXX hack to get auto-repeating timers; restart before doing
// expensive work so that time between ticks is more even
Stop ( ) ;
Start ( ) ;
2000-01-21 21:56:09 +00:00
# endif
1999-04-20 00:23:33 +00:00
# ifdef NOISY_BLINK
PRTime now = PR_Now ( ) ;
char buf [ 50 ] ;
PRTime delta ;
LL_SUB ( delta , now , gLastTick ) ;
gLastTick = now ;
PR_snprintf ( buf , sizeof ( buf ) , " %lldusec " , delta ) ;
2000-10-28 22:17:53 +00:00
printf ( " %s \n " , buf ) ;
1999-04-20 00:23:33 +00:00
# endif
PRInt32 i , n = mFrames . Count ( ) ;
for ( i = 0 ; i < n ; i + + ) {
1999-10-26 04:44:41 +00:00
FrameData * frameData = ( FrameData * ) mFrames . ElementAt ( i ) ;
1999-04-20 00:23:33 +00:00
// Determine damaged area and tell view manager to redraw it
nsPoint offset ;
nsRect bounds ;
1999-10-26 04:44:41 +00:00
frameData - > mFrame - > GetRect ( bounds ) ;
1999-04-20 00:23:33 +00:00
nsIView * view ;
1999-10-26 04:44:41 +00:00
frameData - > mFrame - > GetOffsetFromView ( frameData - > mPresContext , offset , & view ) ;
1999-04-20 00:23:33 +00:00
nsIViewManager * vm ;
view - > GetViewManager ( vm ) ;
bounds . x = offset . x ;
bounds . y = offset . y ;
vm - > UpdateView ( view , bounds , 0 ) ;
NS_RELEASE ( vm ) ;
}
}
2000-03-25 00:49:58 +00:00
// static
nsresult nsBlinkTimer : : AddBlinkFrame ( nsIPresContext * aPresContext , nsIFrame * aFrame )
{
if ( ! sTextBlinker )
{
sTextBlinker = new nsBlinkTimer ;
if ( ! sTextBlinker ) return NS_ERROR_OUT_OF_MEMORY ;
}
NS_ADDREF ( sTextBlinker ) ;
sTextBlinker - > AddFrame ( aPresContext , aFrame ) ;
return NS_OK ;
}
// static
nsresult nsBlinkTimer : : RemoveBlinkFrame ( nsIFrame * aFrame )
{
NS_ASSERTION ( sTextBlinker , " Should have blink timer here " ) ;
nsBlinkTimer * blinkTimer = sTextBlinker ; // copy so we can call NS_RELEASE on it
if ( ! blinkTimer ) return NS_OK ;
blinkTimer - > RemoveFrame ( aFrame ) ;
NS_RELEASE ( blinkTimer ) ;
return NS_OK ;
}
1999-04-20 00:23:33 +00:00
//----------------------------------------------------------------------
2001-04-11 23:32:21 +00:00
# ifdef IBMBIDI
class nsTextFrame : public nsFrame , public nsITextFrame {
# else
1999-10-23 23:19:14 +00:00
class nsTextFrame : public nsFrame {
2001-04-11 23:32:21 +00:00
# endif
1998-09-08 22:34:40 +00:00
public :
1999-04-20 00:23:33 +00:00
nsTextFrame ( ) ;
1998-09-08 22:34:40 +00:00
// nsIFrame
2001-04-01 01:01:33 +00:00
NS_IMETHOD QueryInterface ( const nsIID & aIID ,
void * * aInstancePtrResult ) ;
2001-09-19 12:35:19 +00:00
NS_IMETHOD Paint ( nsIPresContext * aPresContext ,
1998-09-08 22:34:40 +00:00
nsIRenderingContext & aRenderingContext ,
2001-09-19 12:35:19 +00:00
const nsRect & aDirtyRect ,
nsFramePaintLayer aWhichLayer ,
PRUint32 aFlags ) ;
1998-09-08 22:34:40 +00:00
1999-11-24 06:03:41 +00:00
NS_IMETHOD GetCursor ( nsIPresContext * aPresContext ,
1998-11-18 05:25:26 +00:00
nsPoint & aPoint ,
PRInt32 & aCursor ) ;
1998-09-08 22:34:40 +00:00
1998-09-29 23:48:07 +00:00
NS_IMETHOD ContentChanged ( nsIPresContext * aPresContext ,
1998-09-08 22:34:40 +00:00
nsIContent * aChild ,
nsISupports * aSubContent ) ;
1999-10-23 23:19:14 +00:00
NS_IMETHOD GetNextInFlow ( nsIFrame * * aNextInFlow ) const {
* aNextInFlow = mNextInFlow ;
return NS_OK ;
}
NS_IMETHOD SetNextInFlow ( nsIFrame * aNextInFlow ) {
mNextInFlow = aNextInFlow ;
return NS_OK ;
}
NS_IMETHOD IsSplittable ( nsSplittableType & aIsSplittable ) const {
aIsSplittable = NS_FRAME_SPLITTABLE ;
return NS_OK ;
}
1999-02-24 05:33:40 +00:00
/**
* Get the " type " of the frame
*
* @ see nsLayoutAtoms : : textFrame
*/
NS_IMETHOD GetFrameType ( nsIAtom * * aType ) const ;
1999-09-01 01:02:16 +00:00
# ifdef DEBUG
1999-11-01 22:12:45 +00:00
NS_IMETHOD List ( nsIPresContext * aPresContext , FILE * out , PRInt32 aIndent ) const ;
1999-08-31 03:09:40 +00:00
NS_IMETHOD SizeOf ( nsISizeOfHandler * aHandler , PRUint32 * aResult ) const ;
2001-11-14 01:33:42 +00:00
NS_IMETHOD GetFrameName ( nsAString & aResult ) const ;
1999-09-01 01:02:16 +00:00
# endif
1999-08-31 03:09:40 +00:00
1999-11-24 06:03:41 +00:00
NS_IMETHOD GetPosition ( nsIPresContext * aCX ,
1999-11-24 01:10:22 +00:00
const nsPoint & aPoint ,
1999-05-17 00:21:18 +00:00
nsIContent * * aNewContent ,
1999-06-10 21:08:17 +00:00
PRInt32 & aContentOffset ,
PRInt32 & aContentOffsetEnd ) ;
1998-09-08 22:34:40 +00:00
1999-11-24 06:03:41 +00:00
NS_IMETHOD GetContentAndOffsetsFromPoint ( nsIPresContext * aCX ,
1999-09-29 20:04:05 +00:00
const nsPoint & aPoint ,
nsIContent * * aNewContent ,
PRInt32 & aContentOffset ,
1999-10-13 01:15:26 +00:00
PRInt32 & aContentOffsetEnd ,
PRBool & aBeginFrameContent ) ;
1999-09-29 20:04:05 +00:00
1999-11-24 06:03:41 +00:00
NS_IMETHOD GetPositionSlowly ( nsIPresContext * aCX ,
1999-04-26 04:02:04 +00:00
nsIRenderingContext * aRendContext ,
1999-11-24 01:10:22 +00:00
const nsPoint & aPoint ,
nsIContent * * aNewContent ,
PRInt32 & aOffset ) ;
1999-04-26 04:02:04 +00:00
1999-10-26 04:44:41 +00:00
NS_IMETHOD SetSelected ( nsIPresContext * aPresContext ,
nsIDOMRange * aRange ,
PRBool aSelected ,
nsSpread aSpread ) ;
1999-04-26 04:02:04 +00:00
1999-10-26 04:44:41 +00:00
NS_IMETHOD PeekOffset ( nsIPresContext * aPresContext , nsPeekOffsetStruct * aPos ) ;
2000-07-26 11:31:12 +00:00
NS_IMETHOD CheckVisibility ( nsIPresContext * aContext , PRInt32 aStartIndex , PRInt32 aEndIndex , PRBool aRecurse , PRBool * aFinished , PRBool * _retval ) ;
1999-02-02 00:23:40 +00:00
1999-11-24 06:03:41 +00:00
NS_IMETHOD HandleMultiplePress ( nsIPresContext * aPresContext ,
1999-05-17 00:21:18 +00:00
nsGUIEvent * aEvent ,
1999-11-24 06:03:41 +00:00
nsEventStatus * aEventStatus ) ;
1999-05-17 00:21:18 +00:00
1999-01-22 18:58:14 +00:00
NS_IMETHOD GetOffsets ( PRInt32 & start , PRInt32 & end ) const ;
1999-02-12 00:02:31 +00:00
NS_IMETHOD GetPointFromOffset ( nsIPresContext * inPresContext ,
nsIRenderingContext * inRendContext ,
PRInt32 inOffset ,
nsPoint * outPoint ) ;
NS_IMETHOD GetChildFrameContainingOffset ( PRInt32 inContentOffset ,
1999-09-11 00:18:02 +00:00
PRBool inHint ,
1999-02-12 00:02:31 +00:00
PRInt32 * outFrameContentOffset ,
nsIFrame * * outChildFrame ) ;
2001-01-27 14:09:34 +00:00
NS_IMETHOD IsVisibleForPainting ( nsIPresContext * aPresContext ,
nsIRenderingContext & aRenderingContext ,
PRBool aCheckVis ,
PRBool * aIsVisible ) ;
2001-10-25 01:08:40 +00:00
NS_IMETHOD IsEmpty ( PRBool aIsQuirkMode , PRBool aIsPre , PRBool * aResult ) ;
2001-08-17 03:13:07 +00:00
# ifdef ACCESSIBILITY
2001-05-17 23:52:32 +00:00
NS_IMETHOD GetAccessible ( nsIAccessible * * aAccessible ) ;
2001-08-17 03:13:07 +00:00
# endif
2001-05-17 23:52:32 +00:00
1998-10-03 04:28:05 +00:00
// nsIHTMLReflow
1999-11-24 06:03:41 +00:00
NS_IMETHOD Reflow ( nsIPresContext * aPresContext ,
1998-10-03 04:28:05 +00:00
nsHTMLReflowMetrics & aMetrics ,
const nsHTMLReflowState & aReflowState ,
nsReflowStatus & aStatus ) ;
2000-07-28 22:29:28 +00:00
NS_IMETHOD CanContinueTextRun ( PRBool & aContinueTextRun ) const ;
1998-10-27 16:52:34 +00:00
NS_IMETHOD AdjustFrameSize ( nscoord aExtraSpace , nscoord & aUsedSpace ) ;
1999-05-03 20:55:12 +00:00
NS_IMETHOD TrimTrailingWhiteSpace ( nsIPresContext * aPresContext ,
1998-10-27 16:52:34 +00:00
nsIRenderingContext & aRC ,
nscoord & aDeltaWidth ) ;
1998-09-08 22:34:40 +00:00
1998-10-26 17:27:53 +00:00
struct TextStyle {
const nsStyleFont * mFont ;
const nsStyleText * mText ;
const nsStyleColor * mColor ;
2001-05-31 22:19:43 +00:00
const nsStyleVisibility * mVisibility ;
1998-10-26 17:27:53 +00:00
nsIFontMetrics * mNormalFont ;
nsIFontMetrics * mSmallFont ;
nsIFontMetrics * mLastFont ;
PRBool mSmallCaps ;
nscoord mWordSpacing ;
nscoord mLetterSpacing ;
nscolor mSelectionTextColor ;
nscolor mSelectionBGColor ;
nscoord mSpaceWidth ;
2000-03-31 04:27:43 +00:00
nscoord mAveCharWidth ;
1998-10-27 16:52:34 +00:00
PRBool mJustifying ;
1999-03-31 04:12:46 +00:00
PRBool mPreformatted ;
2000-04-17 14:40:46 +00:00
PRInt32 mNumSpacesToRender ;
PRInt32 mNumSpacesToMeasure ;
1998-10-27 16:52:34 +00:00
nscoord mExtraSpacePerSpace ;
2000-04-17 14:40:46 +00:00
PRInt32 mNumSpacesReceivingExtraJot ;
1998-10-26 17:27:53 +00:00
1999-04-20 00:23:33 +00:00
TextStyle ( nsIPresContext * aPresContext ,
1998-10-26 17:27:53 +00:00
nsIRenderingContext & aRenderingContext ,
nsIStyleContext * sc )
{
1999-12-22 00:41:38 +00:00
mFont = nsnull ;
mText = nsnull ;
mColor = nsnull ;
mNormalFont = nsnull ;
mSmallFont = nsnull ;
mLastFont = nsnull ;
1998-10-26 17:27:53 +00:00
// Get style data
mColor = ( const nsStyleColor * ) sc - > GetStyleData ( eStyleStruct_Color ) ;
mFont = ( const nsStyleFont * ) sc - > GetStyleData ( eStyleStruct_Font ) ;
mText = ( const nsStyleText * ) sc - > GetStyleData ( eStyleStruct_Text ) ;
2001-05-31 22:19:43 +00:00
mVisibility = ( const nsStyleVisibility * ) sc - > GetStyleData ( eStyleStruct_Visibility ) ;
1998-10-26 17:27:53 +00:00
1999-06-07 21:18:51 +00:00
// Cache the original decorations and reuse the current font
// to query metrics, rather than creating a new font which is expensive.
1999-06-08 18:12:20 +00:00
nsFont * plainFont = ( nsFont * ) & mFont - > mFont ; //XXX: Change to use a CONST_CAST macro.
2001-12-07 00:03:48 +00:00
NS_ASSERTION ( plainFont , " null plainFont: font problems in TextStyle::TextStyle " ) ;
1999-06-08 18:12:20 +00:00
PRUint8 originalDecorations = plainFont - > decorations ;
plainFont - > decorations = NS_FONT_DECORATION_NONE ;
2000-05-09 21:20:38 +00:00
mAveCharWidth = 0 ;
2002-05-24 20:11:14 +00:00
SetFontFromStyle ( & aRenderingContext , sc ) ; // some users of the struct expect this state
aRenderingContext . GetFontMetrics ( mNormalFont ) ;
2002-05-02 22:24:59 +00:00
mNormalFont - > GetSpaceWidth ( mSpaceWidth ) ;
2001-01-02 23:26:25 +00:00
# if defined(_WIN32) || defined(XP_OS2)
2002-05-02 22:24:59 +00:00
mNormalFont - > GetAveCharWidth ( mAveCharWidth ) ;
2000-03-31 05:10:36 +00:00
# endif
2000-05-09 21:20:38 +00:00
if ( 0 = = mAveCharWidth ) {
// provide a default if it could not be resolved
mAveCharWidth = 10 ;
}
1998-10-26 17:27:53 +00:00
mLastFont = mNormalFont ;
// Get the small-caps font if needed
1999-06-08 18:12:20 +00:00
mSmallCaps = NS_STYLE_FONT_VARIANT_SMALL_CAPS = = plainFont - > variant ;
1998-10-26 17:27:53 +00:00
if ( mSmallCaps ) {
1999-06-08 18:12:20 +00:00
nscoord originalSize = plainFont - > size ;
2000-03-19 07:47:23 +00:00
plainFont - > size = nscoord ( 0.8 * plainFont - > size ) ;
1999-06-08 18:12:20 +00:00
aPresContext - > GetMetricsFor ( * plainFont , & mSmallFont ) ;
1999-06-07 21:18:51 +00:00
// Reset to the size value saved earlier.
1999-06-08 18:12:20 +00:00
plainFont - > size = originalSize ;
1998-10-26 17:27:53 +00:00
}
else {
mSmallFont = nsnull ;
}
1999-06-07 21:18:51 +00:00
// Reset to the decoration saved earlier
1999-06-08 18:12:20 +00:00
plainFont - > decorations = originalDecorations ;
1999-06-07 21:18:51 +00:00
2000-04-04 09:07:41 +00:00
// Get colors from look&feel
1998-10-26 17:27:53 +00:00
mSelectionBGColor = NS_RGB ( 0 , 0 , 0 ) ;
mSelectionTextColor = NS_RGB ( 255 , 255 , 255 ) ;
2000-04-04 09:07:41 +00:00
nsILookAndFeel * look = nsnull ;
if ( NS_SUCCEEDED ( aPresContext - > GetLookAndFeel ( & look ) ) & & look ) {
look - > GetColor ( nsILookAndFeel : : eColor_TextSelectBackground , mSelectionBGColor ) ;
look - > GetColor ( nsILookAndFeel : : eColor_TextSelectForeground , mSelectionTextColor ) ;
NS_RELEASE ( look ) ;
}
1998-10-26 17:27:53 +00:00
// Get the word and letter spacing
mWordSpacing = 0 ;
1999-03-31 04:12:46 +00:00
PRIntn unit = mText - > mWordSpacing . GetUnit ( ) ;
if ( eStyleUnit_Coord = = unit ) {
mWordSpacing = mText - > mWordSpacing . GetCoordValue ( ) ;
}
2000-04-17 14:40:46 +00:00
mLetterSpacing = 0 ;
1999-03-31 04:12:46 +00:00
unit = mText - > mLetterSpacing . GetUnit ( ) ;
if ( eStyleUnit_Coord = = unit ) {
mLetterSpacing = mText - > mLetterSpacing . GetCoordValue ( ) ;
1998-10-26 17:27:53 +00:00
}
2000-10-09 08:39:29 +00:00
2000-04-17 14:40:46 +00:00
mNumSpacesToRender = 0 ;
mNumSpacesToMeasure = 0 ;
mNumSpacesReceivingExtraJot = 0 ;
1998-10-27 16:52:34 +00:00
mExtraSpacePerSpace = 0 ;
1999-03-31 04:12:46 +00:00
mPreformatted = ( NS_STYLE_WHITESPACE_PRE = = mText - > mWhiteSpace ) | |
( NS_STYLE_WHITESPACE_MOZ_PRE_WRAP = = mText - > mWhiteSpace ) ;
2000-04-17 14:40:46 +00:00
mJustifying = ( NS_STYLE_TEXT_ALIGN_JUSTIFY = = mText - > mTextAlign ) & &
! mPreformatted ;
1998-10-26 17:27:53 +00:00
}
~ TextStyle ( ) {
2002-02-26 00:13:49 +00:00
NS_IF_RELEASE ( mNormalFont ) ;
1998-10-26 17:27:53 +00:00
NS_IF_RELEASE ( mSmallFont ) ;
1999-12-22 00:41:38 +00:00
mFont = nsnull ;
mText = nsnull ;
mColor = nsnull ;
mNormalFont = nsnull ;
mSmallFont = nsnull ;
mLastFont = nsnull ;
1998-10-26 17:27:53 +00:00
}
} ;
2000-03-23 22:58:43 +00:00
struct TextReflowData {
PRInt32 mX ; // OUT
PRInt32 mOffset ; // IN/OUT How far along we are in the content
nscoord mMaxWordWidth ; // OUT
2001-09-27 18:34:30 +00:00
nscoord mAscent ; // OUT
nscoord mDescent ; // OUT
2000-03-23 22:58:43 +00:00
PRPackedBool mWrapping ; // IN
PRPackedBool mSkipWhitespace ; // IN
PRPackedBool mMeasureText ; // IN
PRPackedBool mInWord ; // IN
PRPackedBool mFirstLetterOK ; // IN
2000-03-31 04:27:43 +00:00
PRPackedBool mIsBreakable ; // IN
PRPackedBool mComputeMaxWordWidth ; // IN
2001-12-20 02:25:55 +00:00
PRPackedBool mTrailingSpaceTrimmed ; // IN/OUT
2000-03-23 22:58:43 +00:00
TextReflowData ( PRInt32 aStartingOffset ,
PRBool aWrapping ,
PRBool aSkipWhitespace ,
PRBool aMeasureText ,
PRBool aInWord ,
PRBool aFirstLetterOK ,
2000-03-31 04:27:43 +00:00
PRBool aIsBreakable ,
2001-12-20 02:25:55 +00:00
PRBool aComputeMaxWordWidth ,
PRBool aTrailingSpaceTrimmed )
2000-03-23 22:58:43 +00:00
: mX ( 0 ) ,
mOffset ( aStartingOffset ) ,
mMaxWordWidth ( 0 ) ,
2001-09-27 18:34:30 +00:00
mAscent ( 0 ) ,
mDescent ( 0 ) ,
2000-03-23 22:58:43 +00:00
mWrapping ( aWrapping ) ,
mSkipWhitespace ( aSkipWhitespace ) ,
mMeasureText ( aMeasureText ) ,
mInWord ( aInWord ) ,
mFirstLetterOK ( aFirstLetterOK ) ,
mIsBreakable ( aIsBreakable ) ,
2001-12-20 02:25:55 +00:00
mComputeMaxWordWidth ( aComputeMaxWordWidth ) ,
mTrailingSpaceTrimmed ( aTrailingSpaceTrimmed )
2000-03-23 22:58:43 +00:00
{ }
} ;
1999-04-20 00:23:33 +00:00
nsIDocument * GetDocument ( nsIPresContext * aPresContext ) ;
1999-02-10 18:55:25 +00:00
PRIntn PrepareUnicodeText ( nsTextTransformer & aTransformer ,
1999-09-22 00:40:56 +00:00
nsAutoIndexBuffer * aIndexBuffer ,
nsAutoTextBuffer * aTextBuffer ,
1999-04-20 00:23:33 +00:00
PRInt32 * aTextLen ) ;
2000-04-17 14:40:46 +00:00
void ComputeExtraJustificationSpacing ( nsIRenderingContext & aRenderingContext ,
TextStyle & aTextStyle ,
PRUnichar * aBuffer , PRInt32 aLength , PRInt32 aNumSpaces ) ;
1998-09-08 22:34:40 +00:00
1998-09-17 00:18:25 +00:00
void PaintTextDecorations ( nsIRenderingContext & aRenderingContext ,
1998-10-26 17:27:53 +00:00
nsIStyleContext * aStyleContext ,
TextStyle & aStyle ,
1999-07-15 18:19:03 +00:00
nscoord aX , nscoord aY , nscoord aWidth ,
PRUnichar * aText = nsnull ,
SelectionDetails * aDetails = nsnull ,
PRUint32 aIndex = 0 ,
PRUint32 aLength = 0 ,
const nscoord * aSpacing = nsnull ) ;
1998-09-17 00:18:25 +00:00
1999-04-20 00:23:33 +00:00
void PaintTextSlowly ( nsIPresContext * aPresContext ,
1998-10-26 17:27:53 +00:00
nsIRenderingContext & aRenderingContext ,
nsIStyleContext * aStyleContext ,
TextStyle & aStyle ,
nscoord aX , nscoord aY ) ;
void RenderString ( nsIRenderingContext & aRenderingContext ,
nsIStyleContext * aStyleContext ,
TextStyle & aStyle ,
PRUnichar * aBuffer , PRInt32 aLength ,
nscoord aX , nscoord aY ,
1999-07-15 18:19:03 +00:00
nscoord aWidth ,
SelectionDetails * aDetails = nsnull ) ;
1998-10-20 16:46:14 +00:00
void MeasureSmallCapsText ( const nsHTMLReflowState & aReflowState ,
1998-10-26 17:27:53 +00:00
TextStyle & aStyle ,
1998-10-20 16:46:14 +00:00
PRUnichar * aWord ,
PRInt32 aWordLength ,
2001-09-27 18:34:30 +00:00
nsTextDimensions * aDimensionsResult ) ;
1998-10-20 16:46:14 +00:00
2000-03-31 04:27:43 +00:00
nsReflowStatus MeasureText ( nsIPresContext * aPresContext ,
const nsHTMLReflowState & aReflowState ,
nsTextTransformer & aTx ,
nsILineBreaker * aLb ,
TextStyle & aTs ,
TextReflowData & aTextData ) ;
2001-09-27 18:34:30 +00:00
void GetTextDimensions ( nsIRenderingContext & aRenderingContext ,
1998-10-26 17:27:53 +00:00
TextStyle & aStyle ,
PRUnichar * aBuffer , PRInt32 aLength ,
2001-09-27 18:34:30 +00:00
nsTextDimensions * aDimensionsResult ) ;
1998-10-20 16:46:14 +00:00
2000-03-31 07:26:07 +00:00
//this returns the index into the PAINTBUFFER of the x coord aWidth(based on 0 as far left)
//also note: this is NOT added to mContentOffset since that would imply that this return is
//meaningful to content yet. use index buffer from prepareunicodestring to find the content offset.
PRInt32 GetLengthSlowly ( nsIRenderingContext & aRenderingContext ,
TextStyle & aStyle ,
PRUnichar * aBuffer , PRInt32 aLength ,
nscoord aWidth ) ;
2001-01-27 14:09:34 +00:00
PRBool IsTextInSelection ( nsIPresContext * aPresContext ,
nsIRenderingContext & aRenderingContext ) ;
nsresult GetTextInfoForPainting ( nsIPresContext * aPresContext ,
nsIRenderingContext & aRenderingContext ,
nsIPresShell * * aPresShell ,
nsISelectionController * * aSelectionController ,
PRBool & aDisplayingSelection ,
PRBool & aIsPaginated ,
PRBool & aIsSelected ,
PRInt16 & aSelectionValue ,
nsILineBreaker * * aLineBreaker ) ;
1999-04-20 00:23:33 +00:00
void PaintUnicodeText ( nsIPresContext * aPresContext ,
1998-09-08 22:34:40 +00:00
nsIRenderingContext & aRenderingContext ,
1998-10-26 17:27:53 +00:00
nsIStyleContext * aStyleContext ,
TextStyle & aStyle ,
1998-09-08 22:34:40 +00:00
nscoord dx , nscoord dy ) ;
1999-04-20 00:23:33 +00:00
void PaintAsciiText ( nsIPresContext * aPresContext ,
1998-09-08 22:34:40 +00:00
nsIRenderingContext & aRenderingContext ,
1998-10-26 17:27:53 +00:00
nsIStyleContext * aStyleContext ,
TextStyle & aStyle ,
1998-09-08 22:34:40 +00:00
nscoord dx , nscoord dy ) ;
2001-09-27 18:34:30 +00:00
nsTextDimensions ComputeTotalWordDimensions ( nsIPresContext * aPresContext ,
1999-09-16 23:31:59 +00:00
nsILineBreaker * aLineBreaker ,
1999-03-29 04:15:07 +00:00
nsLineLayout & aLineLayout ,
1998-10-10 04:35:21 +00:00
const nsHTMLReflowState & aReflowState ,
nsIFrame * aNextFrame ,
2001-09-27 18:34:30 +00:00
const nsTextDimensions & aBaseDimensions ,
1999-11-01 15:36:02 +00:00
PRUnichar * aWordBuf ,
1999-07-27 14:47:24 +00:00
PRUint32 aWordBufLen ,
2002-03-05 23:23:09 +00:00
PRUint32 aWordBufSize ,
PRBool aIsBreakable ) ;
1998-10-10 04:35:21 +00:00
2001-09-27 18:34:30 +00:00
nsTextDimensions ComputeWordFragmentDimensions ( nsIPresContext * aPresContext ,
1999-09-16 23:31:59 +00:00
nsILineBreaker * aLineBreaker ,
1999-03-29 04:15:07 +00:00
nsLineLayout & aLineLayout ,
1998-10-10 04:35:21 +00:00
const nsHTMLReflowState & aReflowState ,
nsIFrame * aNextFrame ,
1999-09-17 23:14:47 +00:00
nsIContent * aContent ,
1998-10-10 04:35:21 +00:00
nsITextContent * aText ,
1999-07-27 14:47:24 +00:00
PRBool * aStop ,
const PRUnichar * aWordBuf ,
PRUint32 & aWordBufLen ,
2002-03-05 23:23:09 +00:00
PRUint32 aWordBufSize ,
PRBool aIsBreakable ) ;
1998-10-10 04:35:21 +00:00
1999-10-15 23:36:07 +00:00
void ToCString ( nsString & aBuf , PRInt32 * aTotalContentLength ) const ;
1998-10-20 00:21:18 +00:00
2001-04-11 23:32:21 +00:00
# ifdef IBMBIDI
// nsITextFrame methods here
NS_IMETHOD SetOffsets ( PRInt32 aStart , PRInt32 aEnd ) ;
# endif
1998-09-08 22:34:40 +00:00
protected :
1999-04-20 00:23:33 +00:00
virtual ~ nsTextFrame ( ) ;
1998-09-08 22:34:40 +00:00
1999-10-23 23:19:14 +00:00
nsIFrame * mNextInFlow ;
PRInt32 mContentOffset ;
PRInt32 mContentLength ;
PRInt32 mColumn ;
2001-09-27 18:34:30 +00:00
nscoord mAscent ;
//factored out method for GetTextDimensions and getlengthslowly. if aGetTextDimensions is non-zero number then measure to the width field and return the length. else shove total dimensions into result
PRInt32 GetTextDimensionsOrLength ( nsIRenderingContext & aRenderingContext ,
2000-03-31 07:26:07 +00:00
TextStyle & aStyle ,
PRUnichar * aBuffer , PRInt32 aLength ,
2001-09-27 18:34:30 +00:00
nsTextDimensions * aDimensionsResult ,
PRBool aGetTextDimensions /* true=get dimensions false = return length up to aDimensionsResult->width size*/ ) ;
2000-04-02 05:05:31 +00:00
nsresult GetContentAndOffsetsForSelection ( nsIPresContext * aPresContext , nsIContent * * aContent , PRInt32 * aOffset , PRInt32 * aLength ) ;
2001-10-19 14:10:22 +00:00
// prefs used to configure the double-click word selection behavior
static PRPackedBool sWordSelectPrefInited ; // have we read the prefs yet?
static PRPackedBool sWordSelectEatSpaceAfter ; // should we include whitespace up to next word?
2001-04-11 23:32:21 +00:00
# ifdef IBMBIDI
2001-10-24 11:12:31 +00:00
void AdjustSelectionPointsForBidi ( SelectionDetails * sdptr ,
PRInt32 textLength ,
PRBool isRTLChars ,
PRBool isOddLevel ,
PRBool isBidiSystem ) ;
2001-04-11 23:32:21 +00:00
private :
NS_IMETHOD_ ( nsrefcnt ) AddRef ( void ) ;
NS_IMETHOD_ ( nsrefcnt ) Release ( void ) ;
# endif
1999-10-23 23:19:14 +00:00
} ;
2001-08-17 03:13:07 +00:00
# ifdef ACCESSIBILITY
2001-05-17 23:52:32 +00:00
NS_IMETHODIMP nsTextFrame : : GetAccessible ( nsIAccessible * * aAccessible )
{
if ( mRect . width > 0 | | mRect . height > 0 ) {
nsCOMPtr < nsIAccessibilityService > accService = do_GetService ( " @mozilla.org/accessibilityService;1 " ) ;
if ( accService ) {
return accService - > CreateHTMLTextAccessible ( NS_STATIC_CAST ( nsIFrame * , this ) , aAccessible ) ;
}
}
return NS_ERROR_FAILURE ;
}
2001-08-17 03:13:07 +00:00
# endif
2001-05-17 23:52:32 +00:00
2001-10-19 14:10:22 +00:00
PRPackedBool nsTextFrame : : sWordSelectPrefInited = PR_FALSE ;
PRPackedBool nsTextFrame : : sWordSelectEatSpaceAfter = PR_TRUE ;
2001-04-01 01:01:33 +00:00
//-----------------------------------------------------------------------------
NS_IMETHODIMP nsTextFrame : : QueryInterface ( const nsIID & aIID ,
void * * aInstancePtrResult )
{
NS_PRECONDITION ( aInstancePtrResult , " null pointer " ) ;
if ( ! aInstancePtrResult )
return NS_ERROR_NULL_POINTER ;
2001-04-11 23:32:21 +00:00
# ifdef IBMBIDI
if ( aIID . Equals ( NS_GET_IID ( nsITextFrame ) ) ) {
* aInstancePtrResult = NS_STATIC_CAST ( nsITextFrame * , this ) ;
return NS_OK ;
}
# endif
2001-05-17 23:52:32 +00:00
return nsFrame : : QueryInterface ( aIID , aInstancePtrResult ) ;
2001-04-01 01:01:33 +00:00
}
1999-10-23 23:19:14 +00:00
class nsContinuingTextFrame : public nsTextFrame {
public :
1999-11-24 06:03:41 +00:00
NS_IMETHOD Init ( nsIPresContext * aPresContext ,
1999-10-23 23:19:14 +00:00
nsIContent * aContent ,
nsIFrame * aParent ,
nsIStyleContext * aContext ,
nsIFrame * aPrevInFlow ) ;
NS_IMETHOD GetPrevInFlow ( nsIFrame * * aPrevInFlow ) const {
* aPrevInFlow = mPrevInFlow ;
return NS_OK ;
}
NS_IMETHOD SetPrevInFlow ( nsIFrame * aPrevInFlow ) {
mPrevInFlow = aPrevInFlow ;
return NS_OK ;
}
# ifdef DEBUG
NS_IMETHOD SizeOf ( nsISizeOfHandler * aHandler , PRUint32 * aResult ) const ;
# endif
protected :
nsIFrame * mPrevInFlow ;
1998-09-08 22:34:40 +00:00
} ;
1999-10-23 23:19:14 +00:00
NS_IMETHODIMP
1999-11-24 06:03:41 +00:00
nsContinuingTextFrame : : Init ( nsIPresContext * aPresContext ,
1999-10-23 23:19:14 +00:00
nsIContent * aContent ,
nsIFrame * aParent ,
nsIStyleContext * aContext ,
nsIFrame * aPrevInFlow )
{
nsresult rv ;
rv = nsTextFrame : : Init ( aPresContext , aContent , aParent , aContext , aPrevInFlow ) ;
if ( aPrevInFlow ) {
// Hook the frame into the flow
mPrevInFlow = aPrevInFlow ;
aPrevInFlow - > SetNextInFlow ( this ) ;
2001-04-11 23:32:21 +00:00
# ifdef IBMBIDI
nsFrameState state ;
aPrevInFlow - > GetFrameState ( & state ) ;
if ( state & NS_FRAME_IS_BIDI ) {
PRInt32 start , end ;
aPrevInFlow - > GetOffsets ( start , mContentOffset ) ;
void * value ;
2001-06-21 12:35:48 +00:00
aPrevInFlow - > GetBidiProperty ( aPresContext , nsLayoutAtoms : : embeddingLevel , & value , sizeof ( value ) ) ;
2001-04-11 23:32:21 +00:00
SetBidiProperty ( aPresContext , nsLayoutAtoms : : embeddingLevel , value ) ;
2001-06-21 12:35:48 +00:00
aPrevInFlow - > GetBidiProperty ( aPresContext , nsLayoutAtoms : : baseLevel , & value , sizeof ( value ) ) ;
2001-04-11 23:32:21 +00:00
SetBidiProperty ( aPresContext , nsLayoutAtoms : : baseLevel , value ) ;
2001-06-21 12:35:48 +00:00
aPrevInFlow - > GetBidiProperty ( aPresContext , nsLayoutAtoms : : charType , & value , sizeof ( value ) ) ;
2001-04-11 23:32:21 +00:00
SetBidiProperty ( aPresContext , nsLayoutAtoms : : charType , value ) ;
2001-06-21 12:35:48 +00:00
aPrevInFlow - > GetBidiProperty ( aPresContext , nsLayoutAtoms : : nextBidi , & value , sizeof ( value ) ) ;
2001-04-11 23:32:21 +00:00
if ( value ) { // nextBidi
// aPrevInFlow and this frame will point to the same next bidi frame.
SetBidiProperty ( aPresContext , nsLayoutAtoms : : nextBidi , value ) ;
( ( nsIFrame * ) value ) - > GetOffsets ( start , end ) ;
mContentLength = PR_MAX ( 1 , start - mContentOffset ) ;
} // value
mState | = NS_FRAME_IS_BIDI ;
} // prev frame is bidi
# endif // IBMBIDI
1999-10-23 23:19:14 +00:00
}
return rv ;
}
# ifdef DEBUG
NS_IMETHODIMP
nsContinuingTextFrame : : SizeOf ( nsISizeOfHandler * aHandler , PRUint32 * aResult ) const
{
if ( ! aResult ) {
return NS_ERROR_NULL_POINTER ;
}
* aResult = sizeof ( * this ) ;
return NS_OK ;
}
# endif
2000-03-31 07:26:07 +00:00
2000-04-04 09:07:41 +00:00
inline nscolor EnsureDifferentColors ( nscolor colorA , nscolor colorB )
{
if ( colorA = = colorB )
{
nscolor res ;
res = NS_RGB ( NS_GET_R ( colorA ) ^ 0xff ,
NS_GET_G ( colorA ) ^ 0xff ,
NS_GET_B ( colorA ) ^ 0xff ) ;
return res ;
}
return colorA ;
}
2000-03-31 07:26:07 +00:00
//DRAW SELECTION ITERATOR USED FOR TEXTFRAMES ONLY
//helper class for drawing multiply selected text
class DrawSelectionIterator
{
2000-04-20 23:11:41 +00:00
enum { DISABLED_COLOR = NS_RGB ( 176 , 176 , 176 ) } ;
2000-04-27 07:37:12 +00:00
enum { SELECTION_TYPES_WE_CARE_ABOUT = nsISelectionController : : SELECTION_NONE + nsISelectionController : : SELECTION_NORMAL } ;
2000-03-31 07:26:07 +00:00
public :
2000-04-20 23:11:41 +00:00
DrawSelectionIterator ( const SelectionDetails * aSelDetails , PRUnichar * aText ,
PRUint32 aTextLength , nsTextFrame : : TextStyle & aTextStyle ,
2000-04-28 06:21:31 +00:00
PRInt16 aSelectionStatus ) ;
2000-04-08 00:17:14 +00:00
~ DrawSelectionIterator ( ) ;
2000-03-31 07:26:07 +00:00
PRBool First ( ) ;
PRBool Next ( ) ;
PRBool IsDone ( ) ;
PRUnichar * CurrentTextUnicharPtr ( ) ;
char * CurrentTextCStrPtr ( ) ;
PRUint32 CurrentLength ( ) ;
nsTextFrame : : TextStyle & CurrentStyle ( ) ;
nscolor CurrentForeGroundColor ( ) ;
PRBool CurrentBackGroundColor ( nscolor & aColor ) ;
2001-01-27 14:09:34 +00:00
PRBool IsBeforeOrAfter ( ) ;
2000-03-31 07:26:07 +00:00
private :
union {
PRUnichar * mUniStr ;
char * mCStr ;
} ;
PRUint32 mLength ;
PRUint32 mCurrentIdx ;
PRUint32 mCurrentLength ;
nsTextFrame : : TextStyle & mOldStyle ; //base new styles on this one???
const SelectionDetails * mDetails ;
PRBool mDone ;
PRUint8 * mTypes ;
PRBool mInit ;
2000-04-28 06:21:31 +00:00
PRInt16 mSelectionStatus ; //see nsIDocument.h SetDisplaySelection()
2000-04-20 23:11:41 +00:00
nscolor mDisabledColor ;
2000-03-31 07:26:07 +00:00
//private methods
void FillCurrentData ( ) ;
} ;
DrawSelectionIterator : : DrawSelectionIterator ( const SelectionDetails * aSelDetails , PRUnichar * aText ,
2000-04-28 06:21:31 +00:00
PRUint32 aTextLength , nsTextFrame : : TextStyle & aTextStyle , PRInt16 aSelectionStatus )
2000-03-31 07:26:07 +00:00
: mOldStyle ( aTextStyle )
{
mDetails = aSelDetails ;
mCurrentIdx = 0 ;
mUniStr = aText ;
mLength = aTextLength ;
mTypes = nsnull ;
mInit = PR_FALSE ;
2000-04-20 23:11:41 +00:00
mSelectionStatus = aSelectionStatus ;
mDisabledColor = EnsureDifferentColors ( DISABLED_COLOR , mOldStyle . mSelectionBGColor ) ;
2000-03-31 07:26:07 +00:00
if ( ! aSelDetails )
{
mDone = PR_TRUE ;
return ;
}
mDone = ( PRBool ) ( mCurrentIdx > = mLength ) ;
if ( mDone )
return ;
//special case for 1 selection. later
const SelectionDetails * details = aSelDetails ;
if ( details - > mNext )
{
mTypes = new PRUint8 [ mLength ] ;
if ( ! mTypes )
return ;
memset ( mTypes , 0 , mLength ) ; //initialize to 0
while ( details )
{
2000-04-07 19:32:46 +00:00
if ( ( details - > mType & SELECTION_TYPES_WE_CARE_ABOUT ) & &
( details - > mStart ! = details - > mEnd ) )
2000-03-31 07:26:07 +00:00
{
2000-04-07 19:32:46 +00:00
mInit = PR_TRUE ; //WE FOUND SOMETHING WE CARE ABOUT
for ( int i = details - > mStart ; i < details - > mEnd ; i + + )
{
if ( ( PRUint32 ) i > = mLength )
{
NS_ASSERTION ( 0 , " Selection Details out of range? " ) ;
return ; //eh
}
mTypes [ i ] | = details - > mType ; //add this bit
}
2000-03-31 07:26:07 +00:00
}
details = details - > mNext ;
}
2000-04-10 21:35:52 +00:00
if ( ! mInit & & mTypes ) //we have details but none that we care about.
{
delete mTypes ;
mTypes = nsnull ;
mDone = PR_TRUE ; //we are finished
}
2000-03-31 07:26:07 +00:00
}
else if ( details - > mStart = = details - > mEnd ) //no collapsed selections here!
{
2000-03-31 11:09:28 +00:00
mDone = PR_TRUE ;
2000-03-31 07:26:07 +00:00
return ;
}
2000-04-26 03:54:21 +00:00
else if ( ! ( details - > mType & SELECTION_TYPES_WE_CARE_ABOUT ) ) //if all we have is selection we DONT care about, do nothing
{
mDone = PR_TRUE ;
return ;
}
2000-03-31 11:09:28 +00:00
mInit = PR_TRUE ;
2000-03-31 07:26:07 +00:00
}
2000-04-08 00:17:14 +00:00
DrawSelectionIterator : : ~ DrawSelectionIterator ( )
{
if ( mTypes )
delete mTypes ;
}
2000-03-31 07:26:07 +00:00
void
DrawSelectionIterator : : FillCurrentData ( )
{
if ( mDone )
return ;
if ( ! mTypes )
{
mCurrentIdx + = mCurrentLength ;
if ( mCurrentIdx > = mLength )
{
2000-03-31 11:09:28 +00:00
mDone = PR_TRUE ;
2000-03-31 07:26:07 +00:00
return ;
}
if ( mCurrentIdx < ( PRUint32 ) mDetails - > mStart )
{
mCurrentLength = mDetails - > mStart ;
}
else if ( mCurrentIdx = = ( PRUint32 ) mDetails - > mStart )
{ //start
mCurrentLength = mDetails - > mEnd - mCurrentIdx ;
}
else if ( mCurrentIdx > ( PRUint32 ) mDetails - > mStart ) //last unselected part
{
mCurrentLength = mLength - mDetails - > mEnd ;
}
}
else
{
mCurrentIdx + = mCurrentLength ; //advance to this chunk
if ( mCurrentIdx > = mLength )
2000-04-10 21:02:25 +00:00
{
mDone = PR_TRUE ;
2000-03-31 07:26:07 +00:00
return ;
2000-04-10 21:02:25 +00:00
}
2000-03-31 07:26:07 +00:00
uint8 typevalue = mTypes [ mCurrentIdx ] ;
while ( typevalue = = mTypes [ mCurrentIdx + mCurrentLength ] & & ( mCurrentIdx + mCurrentLength ) < mLength )
{
mCurrentLength + + ;
}
}
}
PRBool
DrawSelectionIterator : : First ( )
{
if ( ! mInit )
return PR_FALSE ;
mCurrentIdx = 0 ;
mCurrentLength = 0 ;
if ( ! mTypes & & mDetails - > mStart = = mDetails - > mEnd ) //no collapsed selections here!
2000-03-31 11:09:28 +00:00
mDone = PR_TRUE ;
2000-03-31 07:26:07 +00:00
mDone = ( mCurrentIdx + mCurrentLength ) > = mLength ;
FillCurrentData ( ) ;
return PR_TRUE ;
}
PRBool
DrawSelectionIterator : : Next ( )
{
if ( mDone | | ! mInit )
return PR_FALSE ;
FillCurrentData ( ) ; //advances to next chunk
return PR_TRUE ;
}
PRBool
DrawSelectionIterator : : IsDone ( )
{
return mDone | | ! mInit ;
}
PRUnichar *
DrawSelectionIterator : : CurrentTextUnicharPtr ( )
{
return mUniStr + mCurrentIdx ;
}
char *
DrawSelectionIterator : : CurrentTextCStrPtr ( )
{
return mCStr + mCurrentIdx ;
}
PRUint32
DrawSelectionIterator : : CurrentLength ( )
{
return mCurrentLength ;
}
nsTextFrame : : TextStyle &
DrawSelectionIterator : : CurrentStyle ( )
{
return mOldStyle ;
}
nscolor
DrawSelectionIterator : : CurrentForeGroundColor ( )
{
2000-04-04 09:07:41 +00:00
nscolor foreColor ;
PRBool colorSet = PR_FALSE ;
2000-03-31 07:26:07 +00:00
if ( ! mTypes )
{
if ( mCurrentIdx = = ( PRUint32 ) mDetails - > mStart )
2000-04-04 09:07:41 +00:00
{
foreColor = mOldStyle . mSelectionTextColor ;
colorSet = PR_TRUE ;
}
2000-03-31 07:26:07 +00:00
}
2000-04-27 07:37:12 +00:00
else if ( mTypes [ mCurrentIdx ] | nsISelectionController : : SELECTION_NORMAL ) / / Find color based on mTypes [ mCurrentIdx ] ;
2000-04-04 09:07:41 +00:00
{
foreColor = mOldStyle . mSelectionTextColor ;
colorSet = PR_TRUE ;
}
if ( colorSet & & ( foreColor ! = NS_DONT_CHANGE_COLOR ) )
return foreColor ;
2000-03-31 07:26:07 +00:00
return mOldStyle . mColor - > mColor ;
}
PRBool
DrawSelectionIterator : : CurrentBackGroundColor ( nscolor & aColor )
2000-05-11 04:25:43 +00:00
{
2000-03-31 07:26:07 +00:00
//Find color based on mTypes[mCurrentIdx];
if ( ! mTypes )
{
if ( mCurrentIdx = = ( PRUint32 ) mDetails - > mStart )
{
2000-04-28 06:21:31 +00:00
aColor = ( mSelectionStatus = = nsISelectionController : : SELECTION_ON ) ? mOldStyle . mSelectionBGColor : mDisabledColor ;
2000-03-31 11:09:28 +00:00
return PR_TRUE ;
2000-03-31 07:26:07 +00:00
}
}
2000-04-27 07:37:12 +00:00
else if ( mTypes [ mCurrentIdx ] | nsISelectionController : : SELECTION_NORMAL )
2000-03-31 07:26:07 +00:00
{
2000-04-28 06:21:31 +00:00
aColor = ( mSelectionStatus = = nsISelectionController : : SELECTION_ON ) ? mOldStyle . mSelectionBGColor : mDisabledColor ;
2000-03-31 11:09:28 +00:00
return PR_TRUE ;
2000-03-31 07:26:07 +00:00
}
2000-03-31 11:09:28 +00:00
return PR_FALSE ;
2000-03-31 07:26:07 +00:00
}
2001-01-27 14:09:34 +00:00
PRBool
DrawSelectionIterator : : IsBeforeOrAfter ( )
{
return mCurrentIdx ! = ( PRUint32 ) mDetails - > mStart ;
}
2000-03-31 07:26:07 +00:00
//END DRAWSELECTIONITERATOR!!
1998-09-08 22:34:40 +00:00
// Flag information used by rendering code. This information is
1999-09-01 01:02:16 +00:00
// computed by the ResizeReflow code. The flags are stored in the
// mState variable in the frame class private section.
1998-10-20 00:21:18 +00:00
// Flag indicating that whitespace was skipped
1999-09-01 01:02:16 +00:00
# define TEXT_SKIP_LEADING_WS 0x01000000
# define TEXT_HAS_MULTIBYTE 0x02000000
# define TEXT_IN_WORD 0x04000000
1999-03-26 00:41:36 +00:00
// This bit is set on the first frame in a continuation indicating
1999-09-01 01:02:16 +00:00
// that it was chopped short because of :first-letter style.
1999-09-21 00:12:50 +00:00
# define TEXT_FIRST_LETTER 0x08000000
2000-04-12 14:54:43 +00:00
# define TEXT_WAS_TRANSFORMED 0x10000000
1999-09-01 01:02:16 +00:00
// Bits in mState used for reflow flags
2000-04-12 14:54:43 +00:00
# define TEXT_REFLOW_FLAGS 0x1F000000
1999-09-21 00:12:50 +00:00
# define TEXT_TRIMMED_WS 0x20000000
1999-09-01 01:02:16 +00:00
1999-09-18 16:22:34 +00:00
# define TEXT_OPTIMIZE_RESIZE 0x40000000
1999-09-21 00:12:50 +00:00
1999-09-01 01:02:16 +00:00
# define TEXT_BLINK_ON 0x80000000
1999-03-26 00:41:36 +00:00
1998-09-08 22:34:40 +00:00
//----------------------------------------------------------------------
nsresult
1999-12-04 23:49:50 +00:00
NS_NewTextFrame ( nsIPresShell * aPresShell , nsIFrame * * aNewFrame )
1998-09-08 22:34:40 +00:00
{
1999-05-11 22:03:29 +00:00
NS_PRECONDITION ( aNewFrame , " null OUT ptr " ) ;
if ( nsnull = = aNewFrame ) {
return NS_ERROR_NULL_POINTER ;
}
1999-12-04 23:49:50 +00:00
nsTextFrame * it = new ( aPresShell ) nsTextFrame ;
1999-05-11 22:03:29 +00:00
if ( nsnull = = it ) {
1998-09-08 22:34:40 +00:00
return NS_ERROR_OUT_OF_MEMORY ;
}
1999-05-11 22:03:29 +00:00
* aNewFrame = it ;
1998-09-08 22:34:40 +00:00
return NS_OK ;
}
1999-10-23 23:19:14 +00:00
nsresult
1999-12-04 23:49:50 +00:00
NS_NewContinuingTextFrame ( nsIPresShell * aPresShell , nsIFrame * * aNewFrame )
1999-10-23 23:19:14 +00:00
{
NS_PRECONDITION ( aNewFrame , " null OUT ptr " ) ;
if ( nsnull = = aNewFrame ) {
return NS_ERROR_NULL_POINTER ;
}
1999-12-04 23:49:50 +00:00
nsContinuingTextFrame * it = new ( aPresShell ) nsContinuingTextFrame ;
1999-10-23 23:19:14 +00:00
if ( nsnull = = it ) {
return NS_ERROR_OUT_OF_MEMORY ;
}
* aNewFrame = it ;
return NS_OK ;
}
1999-04-20 00:23:33 +00:00
nsTextFrame : : nsTextFrame ( )
1998-09-08 22:34:40 +00:00
{
2001-10-19 14:10:22 +00:00
// read in our global word selection prefs
if ( ! sWordSelectPrefInited ) {
nsCOMPtr < nsIPref > prefService ( do_GetService ( NS_PREF_CONTRACTID ) ) ;
if ( prefService ) {
PRBool temp = PR_FALSE ;
prefService - > GetBoolPref ( " layout.word_select.eat_space_to_next_word " , & temp ) ;
sWordSelectEatSpaceAfter = temp ;
}
sWordSelectPrefInited = PR_TRUE ;
}
1998-09-08 22:34:40 +00:00
}
1999-04-20 00:23:33 +00:00
nsTextFrame : : ~ nsTextFrame ( )
1998-09-08 22:34:40 +00:00
{
2000-03-25 00:49:58 +00:00
if ( 0 ! = ( mState & TEXT_BLINK_ON ) )
{
nsBlinkTimer : : RemoveBlinkFrame ( this ) ;
1998-09-08 22:34:40 +00:00
}
}
2001-04-11 23:32:21 +00:00
# ifdef IBMBIDI
NS_IMETHODIMP_ ( nsrefcnt ) nsTextFrame : : AddRef ( void )
{
NS_WARNING ( " not supported for frames " ) ;
return 1 ;
}
NS_IMETHODIMP_ ( nsrefcnt ) nsTextFrame : : Release ( void )
{
NS_WARNING ( " not supported for frames " ) ;
return 1 ;
}
# endif // IBMBIDI
1999-04-20 00:23:33 +00:00
nsIDocument *
nsTextFrame : : GetDocument ( nsIPresContext * aPresContext )
{
nsIDocument * result = nsnull ;
if ( mContent ) {
mContent - > GetDocument ( result ) ;
}
if ( ! result & & aPresContext ) {
nsIPresShell * shell ;
aPresContext - > GetShell ( & shell ) ;
if ( shell ) {
shell - > GetDocument ( & result ) ;
NS_RELEASE ( shell ) ;
}
}
return result ;
}
1998-09-08 22:34:40 +00:00
NS_IMETHODIMP
1999-11-24 06:03:41 +00:00
nsTextFrame : : GetCursor ( nsIPresContext * aPresContext ,
1999-04-20 00:23:33 +00:00
nsPoint & aPoint ,
PRInt32 & aCursor )
1998-09-08 22:34:40 +00:00
{
2001-05-31 22:19:43 +00:00
const nsStyleUserInterface * ui = ( const nsStyleUserInterface * )
mStyleContext - > GetStyleData ( eStyleStruct_UserInterface ) ;
aCursor = ui - > mCursor ;
2001-05-02 11:03:03 +00:00
if ( NS_STYLE_CURSOR_AUTO = = aCursor ) {
aCursor = NS_STYLE_CURSOR_TEXT ;
1998-11-18 02:11:54 +00:00
}
1998-09-08 22:34:40 +00:00
return NS_OK ;
}
1999-10-23 23:19:14 +00:00
static nsIFrame *
GetLastInFlow ( nsIFrame * aFrame )
{
nsIFrame * lastInFlow ;
nsIFrame * nextInFlow = aFrame ;
while ( nsnull ! = nextInFlow ) {
lastInFlow = nextInFlow ;
lastInFlow - > GetNextInFlow ( & nextInFlow ) ;
}
NS_POSTCONDITION ( nsnull ! = lastInFlow , " illegal state in flow chain. " ) ;
return lastInFlow ;
}
1998-09-08 22:34:40 +00:00
NS_IMETHODIMP
1999-04-20 00:23:33 +00:00
nsTextFrame : : ContentChanged ( nsIPresContext * aPresContext ,
nsIContent * aChild ,
nsISupports * aSubContent )
1998-09-08 22:34:40 +00:00
{
1999-10-21 20:46:05 +00:00
nsIFrame * targetTextFrame = this ;
PRBool markAllDirty = PR_TRUE ;
if ( aSubContent ) {
nsCOMPtr < nsITextContentChangeData > tccd = do_QueryInterface ( aSubContent ) ;
if ( tccd ) {
nsITextContentChangeData : : ChangeType type ;
tccd - > GetChangeType ( & type ) ;
if ( nsITextContentChangeData : : Append = = type ) {
markAllDirty = PR_FALSE ;
1999-10-23 23:19:14 +00:00
nsTextFrame * frame = ( nsTextFrame * ) : : GetLastInFlow ( this ) ;
1999-10-21 20:46:05 +00:00
frame - > mState | = NS_FRAME_IS_DIRTY ;
targetTextFrame = frame ;
}
}
}
if ( markAllDirty ) {
// Mark this frame and all the next-in-flow frames as dirty
nsTextFrame * textFrame = this ;
while ( textFrame ) {
textFrame - > mState | = NS_FRAME_IS_DIRTY ;
2001-04-11 23:32:21 +00:00
# ifdef IBMBIDI
nsIFrame * nextBidi ;
2001-06-21 12:35:48 +00:00
textFrame - > GetBidiProperty ( aPresContext , nsLayoutAtoms : : nextBidi , ( void * * ) & nextBidi , sizeof ( nextBidi ) ) ;
2001-04-11 23:32:21 +00:00
if ( nextBidi )
textFrame = ( nsTextFrame * ) nextBidi ;
else
# endif
1999-10-21 20:46:05 +00:00
textFrame = ( nsTextFrame * ) textFrame - > mNextInFlow ;
}
1999-10-08 22:04:31 +00:00
}
2000-01-19 03:58:05 +00:00
// Ask the parent frame to reflow me.
nsresult rv ;
nsCOMPtr < nsIPresShell > shell ;
rv = aPresContext - > GetShell ( getter_AddRefs ( shell ) ) ;
if ( NS_SUCCEEDED ( rv ) & & shell & & mParent ) {
2000-02-11 07:11:43 +00:00
mParent - > ReflowDirtyChild ( shell , targetTextFrame ) ;
1998-09-08 22:34:40 +00:00
}
2000-01-19 03:58:05 +00:00
1998-09-08 22:34:40 +00:00
1999-02-12 17:45:58 +00:00
return rv ;
1998-09-08 22:34:40 +00:00
}
NS_IMETHODIMP
2001-09-19 12:35:19 +00:00
nsTextFrame : : Paint ( nsIPresContext * aPresContext ,
1999-04-20 00:23:33 +00:00
nsIRenderingContext & aRenderingContext ,
2001-09-19 12:35:19 +00:00
const nsRect & aDirtyRect ,
nsFramePaintLayer aWhichLayer ,
PRUint32 aFlags )
1998-09-08 22:34:40 +00:00
{
1999-03-26 00:41:36 +00:00
if ( NS_FRAME_PAINT_LAYER_FOREGROUND ! = aWhichLayer ) {
1998-12-18 15:54:23 +00:00
return NS_OK ;
}
2000-03-25 00:49:58 +00:00
if ( ( 0 ! = ( mState & TEXT_BLINK_ON ) ) & & nsBlinkTimer : : GetBlinkIsOff ( ) ) {
1998-09-08 22:34:40 +00:00
return NS_OK ;
}
1998-10-26 17:27:53 +00:00
nsIStyleContext * sc = mStyleContext ;
2001-01-27 14:09:34 +00:00
PRBool isVisible ;
if ( NS_SUCCEEDED ( IsVisibleForPainting ( aPresContext , aRenderingContext , PR_TRUE , & isVisible ) ) & & isVisible ) {
1999-11-24 06:03:41 +00:00
TextStyle ts ( aPresContext , aRenderingContext , mStyleContext ) ;
2000-04-17 14:40:46 +00:00
if ( ts . mSmallCaps | | ( 0 ! = ts . mWordSpacing ) | | ( 0 ! = ts . mLetterSpacing )
| | ts . mJustifying ) {
1999-11-24 06:03:41 +00:00
PaintTextSlowly ( aPresContext , aRenderingContext , sc , ts , 0 , 0 ) ;
1998-09-08 22:34:40 +00:00
}
else {
2000-04-12 14:54:43 +00:00
// Get the text fragment
nsCOMPtr < nsITextContent > tc = do_QueryInterface ( mContent ) ;
const nsTextFragment * frag = nsnull ;
if ( tc . get ( ) ) {
tc - > GetText ( & frag ) ;
}
if ( ! frag ) {
return NS_ERROR_FAILURE ;
}
// Choose rendering pathway based on rendering context performance
// hint, whether it needs to be transformed, and whether it's
// multi-byte
PRBool hasMultiByteChars = ( 0 ! = ( mState & TEXT_HAS_MULTIBYTE ) ) ;
1998-10-20 16:46:14 +00:00
PRUint32 hints = 0 ;
aRenderingContext . GetHints ( hints ) ;
2000-04-12 14:54:43 +00:00
2001-04-11 23:32:21 +00:00
# ifdef IBMBIDI
PRBool bidiEnabled ;
2001-05-16 13:40:08 +00:00
aPresContext - > GetBidiEnabled ( & bidiEnabled ) ;
2001-08-01 03:09:59 +00:00
# else
const PRBool bidiEnabled = PR_FALSE ;
2001-04-11 23:32:21 +00:00
# endif // IBMBIDI
2001-08-01 03:09:59 +00:00
// * BiDi text or text with multi-byte characters must always be
// rendered as Unicode.
// * Non-transformed, 1-byte text should always be rendered as
// ASCII.
// * Other transformed or 2-byte text should be rendered according
// to the preference of the hint from the rendering context.
if ( bidiEnabled | | hasMultiByteChars | |
( ( 0 = = ( hints & NS_RENDERING_HINT_FAST_8BIT_TEXT ) ) & &
( frag - > Is2b ( ) | | ( 0 ! = ( mState & TEXT_WAS_TRANSFORMED ) ) ) ) ) {
1999-11-24 06:03:41 +00:00
PaintUnicodeText ( aPresContext , aRenderingContext , sc , ts , 0 , 0 ) ;
1998-10-20 16:46:14 +00:00
}
else {
1999-11-24 06:03:41 +00:00
PaintAsciiText ( aPresContext , aRenderingContext , sc , ts , 0 , 0 ) ;
1998-10-20 16:46:14 +00:00
}
2001-01-27 14:09:34 +00:00
1998-09-08 22:34:40 +00:00
}
}
2001-03-13 01:47:22 +00:00
DO_GLOBAL_REFLOW_COUNT_DSP ( " nsTextFrame " , & aRenderingContext ) ;
1998-09-08 22:34:40 +00:00
return NS_OK ;
}
/**
* Prepare the text in the content for rendering . If aIndexes is not nsnull
* then fill in aIndexes ' s with the mapping from the original input to
* the prepared output .
*/
1998-10-27 16:52:34 +00:00
PRIntn
1999-04-20 00:23:33 +00:00
nsTextFrame : : PrepareUnicodeText ( nsTextTransformer & aTX ,
1999-09-22 00:40:56 +00:00
nsAutoIndexBuffer * aIndexBuffer ,
nsAutoTextBuffer * aTextBuffer ,
1999-04-20 00:23:33 +00:00
PRInt32 * aTextLen )
1998-09-08 22:34:40 +00:00
{
1998-10-27 16:52:34 +00:00
PRIntn numSpaces = 0 ;
1998-09-08 22:34:40 +00:00
1998-10-20 00:21:18 +00:00
// Setup transform to operate starting in the content at our content
// offset
1999-09-16 23:31:59 +00:00
aTX . Init ( this , mContent , mContentOffset ) ;
1998-09-08 22:34:40 +00:00
PRInt32 strInx = mContentOffset ;
1999-09-22 00:40:56 +00:00
PRInt32 * indexp = aIndexBuffer ? aIndexBuffer - > mBuffer : nsnull ;
1998-10-20 00:21:18 +00:00
// Skip over the leading whitespace
PRInt32 n = mContentLength ;
1999-09-01 01:02:16 +00:00
if ( 0 ! = ( mState & TEXT_SKIP_LEADING_WS ) ) {
2000-04-12 14:54:43 +00:00
PRBool isWhitespace , wasTransformed ;
1998-10-21 20:03:54 +00:00
PRInt32 wordLen , contentLen ;
2001-11-14 14:21:52 +00:00
# ifdef IBMBIDI
wordLen = ( mState & NS_FRAME_IS_BIDI ) ? mContentOffset + mContentLength : - 1 ;
# endif // IBMBIDI
2000-04-12 14:54:43 +00:00
aTX . GetNextWord ( PR_FALSE , & wordLen , & contentLen , & isWhitespace , & wasTransformed ) ;
2000-04-17 14:40:46 +00:00
// we trip this assertion in bug 31053, but I think it's unnecessary
//NS_ASSERTION(isWhitespace, "mState and content are out of sync");
2001-04-11 23:32:21 +00:00
# ifdef IBMBIDI
if ( mState & NS_FRAME_IS_BIDI
& & contentLen > mContentLength ) {
contentLen = mContentLength ;
}
# endif // IBMBIDI
2000-04-17 14:40:46 +00:00
1998-10-21 20:03:54 +00:00
if ( isWhitespace ) {
1999-09-22 00:40:56 +00:00
if ( nsnull ! = indexp ) {
1998-10-21 20:03:54 +00:00
// Point mapping indicies at the same content index since
// all of the compressed whitespace maps down to the same
// renderable character.
PRInt32 i = contentLen ;
while ( - - i > = 0 ) {
1999-09-22 00:40:56 +00:00
* indexp + + = strInx ;
1998-09-08 22:34:40 +00:00
}
}
1998-10-21 20:03:54 +00:00
n - = contentLen ;
2000-08-03 22:30:47 +00:00
if ( n < 0 )
NS_WARNING ( " mContentLength is < FragmentLength " ) ;
1998-09-08 22:34:40 +00:00
}
}
1998-10-20 00:21:18 +00:00
// Rescan the content and transform it. Stop when we have consumed
// mContentLength characters.
1999-09-01 01:02:16 +00:00
PRBool inWord = ( TEXT_IN_WORD & mState ) ? PR_TRUE : PR_FALSE ;
1998-10-20 00:21:18 +00:00
PRInt32 column = mColumn ;
PRInt32 textLength = 0 ;
1999-09-22 00:40:56 +00:00
PRInt32 dstOffset = 0 ;
1998-10-20 00:21:18 +00:00
while ( 0 ! = n ) {
PRUnichar * bp ;
2000-04-12 14:54:43 +00:00
PRBool isWhitespace , wasTransformed ;
1998-10-20 00:21:18 +00:00
PRInt32 wordLen , contentLen ;
1998-10-21 20:03:54 +00:00
2001-11-14 14:21:52 +00:00
# ifdef IBMBIDI
wordLen = ( mState & NS_FRAME_IS_BIDI ) ? mContentOffset + mContentLength : - 1 ;
# endif // IBMBIDI
1998-10-21 20:03:54 +00:00
// Get the next word
2000-04-12 14:54:43 +00:00
bp = aTX . GetNextWord ( inWord , & wordLen , & contentLen , & isWhitespace , & wasTransformed ) ;
1998-10-21 20:03:54 +00:00
if ( nsnull = = bp ) {
2001-04-11 23:32:21 +00:00
# ifdef IBMBIDI
if ( indexp & & ( mState & NS_FRAME_IS_BIDI ) ) {
while ( - - n > = 0 ) {
* indexp + + = strInx + + ;
}
}
# endif // IBMBIDI
1998-10-21 20:03:54 +00:00
break ;
}
1998-11-12 16:31:38 +00:00
if ( contentLen > n ) {
contentLen = n ;
}
if ( wordLen > n ) {
wordLen = n ;
}
1998-10-21 20:03:54 +00:00
inWord = PR_FALSE ;
if ( isWhitespace ) {
1998-10-20 00:21:18 +00:00
if ( ' \t ' = = bp [ 0 ] ) {
PRInt32 spaces = 8 - ( 7 & column ) ;
PRUnichar * tp = bp ;
wordLen = spaces ;
while ( - - spaces > = 0 ) {
* tp + + = ' ' ;
}
// XXX This is a one to many mapping that I think isn't handled well
1999-09-22 00:40:56 +00:00
if ( nsnull ! = indexp ) {
* indexp + + = strInx ;
1999-03-31 20:12:42 +00:00
strInx + = wordLen ;
1998-10-20 00:21:18 +00:00
}
1998-09-29 16:24:32 +00:00
}
1999-10-19 23:01:58 +00:00
else if ( ' \n ' = = bp [ 0 ] ) {
1999-09-22 00:40:56 +00:00
if ( nsnull ! = indexp ) {
* indexp + + = strInx ;
}
1998-10-20 00:21:18 +00:00
break ;
1998-09-08 22:34:40 +00:00
}
1999-09-22 00:40:56 +00:00
else if ( nsnull ! = indexp ) {
1999-10-19 23:01:58 +00:00
if ( 1 = = wordLen ) {
// Point mapping indicies at the same content index since
// all of the compressed whitespace maps down to the same
// renderable character.
PRInt32 i = contentLen ;
while ( - - i > = 0 ) {
* indexp + + = strInx ;
}
strInx + + ;
} else {
// Point mapping indicies at each content index in the word
PRInt32 i = contentLen ;
while ( - - i > = 0 ) {
* indexp + + = strInx + + ;
}
1998-10-20 00:21:18 +00:00
}
1998-09-29 16:24:32 +00:00
}
2000-04-17 14:40:46 +00:00
numSpaces + = wordLen ;
1998-09-08 22:34:40 +00:00
}
1998-10-20 00:21:18 +00:00
else {
2000-04-17 14:40:46 +00:00
PRInt32 i ;
1999-09-22 00:40:56 +00:00
if ( nsnull ! = indexp ) {
1998-10-21 20:03:54 +00:00
// Point mapping indicies at each content index in the word
2000-04-17 14:40:46 +00:00
i = contentLen ;
1998-10-21 20:03:54 +00:00
while ( - - i > = 0 ) {
1999-09-22 00:40:56 +00:00
* indexp + + = strInx + + ;
1998-10-20 00:21:18 +00:00
}
1998-09-08 22:34:40 +00:00
}
2000-04-17 14:40:46 +00:00
// Nonbreaking spaces count as spaces, not letters
PRUnichar * tp = bp ;
i = wordLen ;
while ( - - i > = 0 ) {
if ( * tp + + = = ' ' ) {
numSpaces + + ;
}
}
1998-09-08 22:34:40 +00:00
}
1999-09-22 00:40:56 +00:00
// Grow the buffer before we run out of room. The only time this
// happens is because of tab expansion.
2000-04-17 14:40:46 +00:00
if ( aTextBuffer ! = nsnull & & dstOffset + wordLen > aTextBuffer - > mBufferLen ) {
1999-09-22 00:40:56 +00:00
nsresult rv = aTextBuffer - > GrowBy ( wordLen ) ;
if ( NS_FAILED ( rv ) ) {
break ;
}
}
1998-10-21 20:03:54 +00:00
column + = wordLen ;
1998-10-20 00:21:18 +00:00
textLength + = wordLen ;
n - = contentLen ;
2000-04-17 14:40:46 +00:00
if ( aTextBuffer ! = nsnull ) {
2002-01-12 03:18:55 +00:00
memcpy ( aTextBuffer - > mBuffer + dstOffset , bp ,
2002-01-26 00:04:45 +00:00
sizeof ( PRUnichar ) * wordLen ) ;
2000-04-17 14:40:46 +00:00
}
1999-09-22 00:40:56 +00:00
dstOffset + = wordLen ;
1998-10-03 00:48:19 +00:00
}
1999-09-22 00:40:56 +00:00
# ifdef DEBUG
if ( aIndexBuffer ) {
NS_ASSERTION ( indexp < = aIndexBuffer - > mBuffer + aIndexBuffer - > mBufferLen ,
" yikes - we just overwrote memory " ) ;
}
2000-04-17 14:40:46 +00:00
if ( aTextBuffer ) {
NS_ASSERTION ( dstOffset < = aTextBuffer - > mBufferLen ,
" yikes - we just overwrote memory " ) ;
}
1999-09-22 00:40:56 +00:00
# endif
1998-10-27 16:52:34 +00:00
// Remove trailing whitespace if it was trimmed after reflow
2001-12-20 02:25:55 +00:00
// TEXT_TRIMMED_WS can be set in measureText during reflow, and
// nonexitent text buffer may occur in this situation.
if ( TEXT_TRIMMED_WS & mState & & aTextBuffer ) {
1999-09-22 00:40:56 +00:00
if ( - - dstOffset > = 0 ) {
PRUnichar ch = aTextBuffer - > mBuffer [ dstOffset ] ;
1998-10-27 16:52:34 +00:00
if ( XP_IS_SPACE ( ch ) ) {
1998-10-20 00:21:18 +00:00
textLength - - ;
2000-04-17 14:40:46 +00:00
numSpaces - - ;
1998-10-20 00:21:18 +00:00
}
}
}
1998-10-27 16:52:34 +00:00
1999-09-22 00:40:56 +00:00
if ( aIndexBuffer ) {
PRInt32 * ip = aIndexBuffer - > mBuffer ;
ip [ mContentLength ] = ip [ mContentLength - 1 ] ;
if ( ( ip [ mContentLength ] - mContentOffset ) < textLength ) {
// Must set up last one for selection beyond edge if in boundary
ip [ mContentLength ] + + ;
}
}
1999-04-20 00:23:33 +00:00
* aTextLen = textLength ;
1998-10-27 16:52:34 +00:00
return numSpaces ;
1998-09-08 22:34:40 +00:00
}
1999-03-31 04:12:46 +00:00
1999-04-15 20:42:53 +00:00
//#define SHOW_SELECTION_CURSOR // should be turned off when the caret code is activated
1999-02-12 00:05:19 +00:00
# ifdef SHOW_SELECTION_CURSOR
1998-09-08 22:34:40 +00:00
// XXX This clearly needs to be done by the container, *somehow*
# define CURSOR_COLOR NS_RGB(0,0,255)
static void
RenderSelectionCursor ( nsIRenderingContext & aRenderingContext ,
nscoord dx , nscoord dy , nscoord aHeight ,
nscolor aCursorColor )
{
nsPoint pnts [ 4 ] ;
nscoord ox = aHeight / 4 ;
nscoord oy = ox ;
nscoord x0 = dx ;
nscoord y0 = dy + aHeight ;
pnts [ 0 ] . x = x0 - ox ;
pnts [ 0 ] . y = y0 ;
pnts [ 1 ] . x = x0 ;
pnts [ 1 ] . y = y0 - oy ;
pnts [ 2 ] . x = x0 + ox ;
pnts [ 2 ] . y = y0 ;
pnts [ 3 ] . x = x0 - ox ;
pnts [ 3 ] . y = y0 ;
1998-09-09 16:18:40 +00:00
// Draw little blue triangle
aRenderingContext . SetColor ( aCursorColor ) ;
1998-09-08 22:34:40 +00:00
aRenderingContext . FillPolygon ( pnts , 4 ) ;
}
1999-02-12 00:05:19 +00:00
# endif
1998-09-08 22:34:40 +00:00
// XXX letter-spacing
// XXX word-spacing
1999-10-21 22:01:18 +00:00
# if defined(XP_PC) || defined(XP_UNIX) || defined(XP_MAC)
# define USE_INVERT_FOR_SELECTION
# endif
1998-09-08 22:34:40 +00:00
2000-02-02 23:39:25 +00:00
// XXX we should get the following from style sheet or LookAndFeel later
# define IME_RAW_COLOR NS_RGB(198,33,66)
# define IME_CONVERTED_COLOR NS_RGB(255,198,198)
1998-09-17 00:18:25 +00:00
void
1999-04-20 00:23:33 +00:00
nsTextFrame : : PaintTextDecorations ( nsIRenderingContext & aRenderingContext ,
nsIStyleContext * aStyleContext ,
TextStyle & aTextStyle ,
1999-07-15 18:19:03 +00:00
nscoord aX , nscoord aY , nscoord aWidth ,
PRUnichar * aText , /*=nsnull*/
SelectionDetails * aDetails , /*= nsnull*/
PRUint32 aIndex , /*= 0*/
PRUint32 aLength , /*= 0*/
const nscoord * aSpacing /* = nsnull*/ )
1998-09-17 00:18:25 +00:00
{
1998-10-28 02:03:40 +00:00
nscolor overColor ;
nscolor underColor ;
nscolor strikeColor ;
nsIStyleContext * context = aStyleContext ;
2001-05-31 22:19:43 +00:00
PRBool useOverride = PR_FALSE ;
nscolor overrideColor ;
PRUint8 decorations = NS_STYLE_TEXT_DECORATION_NONE ; // Begin with no decorations
PRUint8 decorMask = NS_STYLE_TEXT_DECORATION_UNDERLINE | NS_STYLE_TEXT_DECORATION_OVERLINE |
NS_STYLE_TEXT_DECORATION_LINE_THROUGH ; // A mask of all possible decorations.
PRBool hasDecorations = context - > HasTextDecorations ( ) ;
1998-10-28 02:03:40 +00:00
NS_ADDREF ( context ) ;
do { // find decoration colors
2001-05-31 22:19:43 +00:00
const nsStyleTextReset * styleText =
( const nsStyleTextReset * ) context - > GetStyleData ( eStyleStruct_TextReset ) ;
if ( ! useOverride & & ( NS_STYLE_TEXT_DECORATION_OVERRIDE_ALL & styleText - > mTextDecoration ) ) {
// This handles the <a href="blah.html"><font color="green">La la la</font></a> case.
// The link underline should be green.
const nsStyleColor * styleColor =
( const nsStyleColor * ) context - > GetStyleData ( eStyleStruct_Color ) ;
useOverride = PR_TRUE ;
overrideColor = styleColor - > mColor ;
}
1998-10-28 02:03:40 +00:00
if ( decorMask & styleText - > mTextDecoration ) { // a decoration defined here
const nsStyleColor * styleColor =
( const nsStyleColor * ) context - > GetStyleData ( eStyleStruct_Color ) ;
2001-05-31 22:19:43 +00:00
1998-10-28 02:03:40 +00:00
if ( NS_STYLE_TEXT_DECORATION_UNDERLINE & decorMask & styleText - > mTextDecoration ) {
2001-05-31 22:19:43 +00:00
underColor = useOverride ? overrideColor : styleColor - > mColor ;
1998-10-28 02:03:40 +00:00
decorMask & = ~ NS_STYLE_TEXT_DECORATION_UNDERLINE ;
2001-05-31 22:19:43 +00:00
decorations | = NS_STYLE_TEXT_DECORATION_UNDERLINE ;
1998-09-17 00:18:25 +00:00
}
1998-10-28 02:03:40 +00:00
if ( NS_STYLE_TEXT_DECORATION_OVERLINE & decorMask & styleText - > mTextDecoration ) {
2001-05-31 22:19:43 +00:00
overColor = useOverride ? overrideColor : styleColor - > mColor ;
1998-10-28 02:03:40 +00:00
decorMask & = ~ NS_STYLE_TEXT_DECORATION_OVERLINE ;
2001-05-31 22:19:43 +00:00
decorations | = NS_STYLE_TEXT_DECORATION_OVERLINE ;
1998-09-17 00:18:25 +00:00
}
1998-10-28 02:03:40 +00:00
if ( NS_STYLE_TEXT_DECORATION_LINE_THROUGH & decorMask & styleText - > mTextDecoration ) {
2001-05-31 22:19:43 +00:00
strikeColor = useOverride ? overrideColor : styleColor - > mColor ;
1998-10-28 02:03:40 +00:00
decorMask & = ~ NS_STYLE_TEXT_DECORATION_LINE_THROUGH ;
2001-05-31 22:19:43 +00:00
decorations | = NS_STYLE_TEXT_DECORATION_LINE_THROUGH ;
1998-09-17 00:18:25 +00:00
}
}
1998-10-28 02:03:40 +00:00
if ( 0 ! = decorMask ) {
nsIStyleContext * lastContext = context ;
context = context - > GetParent ( ) ;
2001-05-31 22:19:43 +00:00
hasDecorations = context - > HasTextDecorations ( ) ;
1998-10-28 02:03:40 +00:00
NS_RELEASE ( lastContext ) ;
}
2001-05-31 22:19:43 +00:00
} while ( ( nsnull ! = context ) & & hasDecorations & & ( 0 ! = decorMask ) ) ;
1998-10-28 02:03:40 +00:00
NS_IF_RELEASE ( context ) ;
nscoord offset ;
nscoord size ;
2001-09-27 18:34:30 +00:00
nscoord baseline = mAscent ;
1998-10-28 02:03:40 +00:00
if ( decorations & ( NS_FONT_DECORATION_OVERLINE | NS_FONT_DECORATION_UNDERLINE ) ) {
aTextStyle . mNormalFont - > GetUnderline ( offset , size ) ;
if ( decorations & NS_FONT_DECORATION_OVERLINE ) {
aRenderingContext . SetColor ( overColor ) ;
aRenderingContext . FillRect ( aX , aY , aWidth , size ) ;
}
if ( decorations & NS_FONT_DECORATION_UNDERLINE ) {
aRenderingContext . SetColor ( underColor ) ;
1998-09-17 00:18:25 +00:00
aRenderingContext . FillRect ( aX , aY + baseline - offset , aWidth , size ) ;
}
1998-10-28 02:03:40 +00:00
}
if ( decorations & NS_FONT_DECORATION_LINE_THROUGH ) {
aTextStyle . mNormalFont - > GetStrikeout ( offset , size ) ;
aRenderingContext . SetColor ( strikeColor ) ;
aRenderingContext . FillRect ( aX , aY + baseline - offset , aWidth , size ) ;
1998-09-17 00:18:25 +00:00
}
1999-07-15 18:19:03 +00:00
if ( aDetails ) {
nsRect rect ;
GetRect ( rect ) ;
while ( aDetails ) {
1999-11-30 22:16:12 +00:00
const nscoord * sp = aSpacing ;
PRInt32 startOffset = 0 ;
PRInt32 textWidth = 0 ;
1999-07-15 18:19:03 +00:00
PRInt32 start = PR_MAX ( 0 , ( aDetails - > mStart - ( PRInt32 ) aIndex ) ) ;
PRInt32 end = PR_MIN ( ( PRInt32 ) aLength , ( aDetails - > mEnd - ( PRInt32 ) aIndex ) ) ;
PRInt32 i ;
1999-11-30 22:16:12 +00:00
if ( ( start < end ) & & ( ( aLength - start ) > 0 ) )
1999-07-15 18:19:03 +00:00
{
//aDetails allready processed to have offsets from frame start not content offsets
if ( start < end ) {
if ( aLength = = 1 )
textWidth = aWidth ;
else {
if ( aDetails - > mStart > 0 ) {
1999-11-30 22:16:12 +00:00
if ( sp )
1999-07-15 18:19:03 +00:00
{
for ( i = 0 ; i < start ; i + + ) {
1999-11-30 22:16:12 +00:00
startOffset + = * sp + + ;
1999-07-15 18:19:03 +00:00
}
}
else
aRenderingContext . GetWidth ( aText , start , startOffset ) ;
}
1999-11-30 22:16:12 +00:00
if ( sp ) {
1999-07-15 18:19:03 +00:00
for ( i = start ; i < end ; i + + ) {
1999-11-30 22:16:12 +00:00
textWidth + = * sp + + ;
1999-07-15 18:19:03 +00:00
}
}
else
aRenderingContext . GetWidth ( aText + start ,
PRUint32 ( end - start ) , textWidth ) ;
}
switch ( aDetails - > mType )
{
2000-04-27 07:37:12 +00:00
case nsISelectionController : : SELECTION_NORMAL :
2000-03-31 07:26:07 +00:00
#if 0
{
//using new selectionpainting now
1999-07-20 07:26:09 +00:00
//
// XOR InvertRect is currently implemented only in the unix and windows
// rendering contexts. When other platforms implement InvertRect(), they
// can be added here. Eventually this #ifdef should die.
//
// For platforms that dont implement InvertRect(), the selection will be
// a non-filled rectangle.
1999-10-21 22:01:18 +00:00
# ifdef USE_INVERT_FOR_SELECTION
1999-07-20 07:26:09 +00:00
aRenderingContext . SetColor ( NS_RGB ( 255 , 255 , 255 ) ) ;
aRenderingContext . InvertRect ( aX + startOffset , aY , textWidth , rect . height ) ;
# else
1999-07-15 18:19:03 +00:00
aRenderingContext . SetColor ( NS_RGB ( 0 , 0 , 0 ) ) ;
aRenderingContext . DrawRect ( aX + startOffset , aY , textWidth , rect . height ) ;
1999-07-20 07:26:09 +00:00
# endif
2000-03-31 07:26:07 +00:00
}
# endif //0
break ;
2000-04-27 07:37:12 +00:00
case nsISelectionController : : SELECTION_SPELLCHECK : {
1999-07-15 18:19:03 +00:00
aTextStyle . mNormalFont - > GetUnderline ( offset , size ) ;
aRenderingContext . SetColor ( NS_RGB ( 255 , 0 , 0 ) ) ;
1999-10-21 22:01:18 +00:00
aRenderingContext . FillRect ( aX + startOffset , aY + baseline - offset , textWidth , size ) ;
} break ;
2000-04-27 07:37:12 +00:00
case nsISelectionController : : SELECTION_IME_SELECTEDRAWTEXT : {
1999-10-21 22:01:18 +00:00
# ifdef USE_INVERT_FOR_SELECTION
aRenderingContext . SetColor ( NS_RGB ( 255 , 255 , 255 ) ) ;
aRenderingContext . InvertRect ( aX + startOffset , aY , textWidth , rect . height ) ;
# else
aRenderingContext . SetColor ( NS_RGB ( 255 , 255 , 128 ) ) ;
aRenderingContext . DrawRect ( aX + startOffset , aY , textWidth , rect . height ) ;
# endif
aTextStyle . mNormalFont - > GetUnderline ( offset , size ) ;
2000-02-02 23:39:25 +00:00
aRenderingContext . SetColor ( IME_RAW_COLOR ) ;
aRenderingContext . FillRect ( aX + startOffset + size , aY + baseline - offset , textWidth - 2 * size , size ) ;
1999-07-15 18:19:03 +00:00
} break ;
2000-04-27 07:37:12 +00:00
case nsISelectionController : : SELECTION_IME_RAWINPUT : {
1999-07-15 18:19:03 +00:00
aTextStyle . mNormalFont - > GetUnderline ( offset , size ) ;
2000-02-02 23:39:25 +00:00
aRenderingContext . SetColor ( IME_RAW_COLOR ) ;
aRenderingContext . FillRect ( aX + startOffset + size , aY + baseline - offset , textWidth - 2 * size , size ) ;
1999-10-21 22:01:18 +00:00
} break ;
2000-04-27 07:37:12 +00:00
case nsISelectionController : : SELECTION_IME_SELECTEDCONVERTEDTEXT : {
1999-10-21 22:01:18 +00:00
# ifdef USE_INVERT_FOR_SELECTION
aRenderingContext . SetColor ( NS_RGB ( 255 , 255 , 255 ) ) ;
aRenderingContext . InvertRect ( aX + startOffset , aY , textWidth , rect . height ) ;
# else
aRenderingContext . SetColor ( NS_RGB ( 255 , 255 , 128 ) ) ;
aRenderingContext . DrawRect ( aX + startOffset , aY , textWidth , rect . height ) ;
# endif
aTextStyle . mNormalFont - > GetUnderline ( offset , size ) ;
2000-02-02 23:39:25 +00:00
aRenderingContext . SetColor ( IME_CONVERTED_COLOR ) ;
aRenderingContext . FillRect ( aX + startOffset + size , aY + baseline - offset , textWidth - 2 * size , size ) ;
1999-07-15 18:19:03 +00:00
} break ;
2000-04-27 07:37:12 +00:00
case nsISelectionController : : SELECTION_IME_CONVERTEDTEXT : {
1999-07-15 18:19:03 +00:00
aTextStyle . mNormalFont - > GetUnderline ( offset , size ) ;
2000-02-02 23:39:25 +00:00
aRenderingContext . SetColor ( IME_CONVERTED_COLOR ) ;
aRenderingContext . FillRect ( aX + startOffset + size , aY + baseline - offset , textWidth - 2 * size , size ) ;
1999-07-15 18:19:03 +00:00
} break ;
1999-09-01 21:40:16 +00:00
default :
NS_ASSERTION ( 0 , " what type of selection do i not know about? " ) ;
break ;
1999-07-15 18:19:03 +00:00
}
}
}
aDetails = aDetails - > mNext ;
}
}
1998-09-17 00:18:25 +00:00
}
2000-04-02 05:05:31 +00:00
nsresult
nsTextFrame : : GetContentAndOffsetsForSelection ( nsIPresContext * aPresContext , nsIContent * * aContent , PRInt32 * aOffset , PRInt32 * aLength )
{
if ( ! aContent | | ! aOffset | | ! aLength )
return NS_ERROR_NULL_POINTER ;
//ARE WE GENERATED??
* aContent = nsnull ;
* aOffset = mContentOffset ;
* aLength = mContentLength ;
nsIFrame * parent ;
nsresult rv = GetParent ( & parent ) ;
if ( NS_SUCCEEDED ( rv ) & & parent )
{
2001-06-20 04:48:10 +00:00
if ( ( mState & NS_FRAME_GENERATED_CONTENT ) ! = 0 ) //parent is generated so so are we.
2000-04-02 05:05:31 +00:00
{
//we COULD check the previous sibling but I dont think that is reliable
rv = parent - > GetContent ( aContent ) ;
2001-10-13 09:27:46 +00:00
if ( NS_FAILED ( rv ) )
return rv ;
if ( ! * aContent )
return NS_ERROR_FAILURE ;
2000-04-02 05:05:31 +00:00
//ARE WE A BEFORE FRAME? if not then we assume we are an after frame. this may be bad later
nsIFrame * grandParent ;
nsIFrame * firstParent ;
rv = parent - > GetParent ( & grandParent ) ;
if ( NS_SUCCEEDED ( rv ) & & grandParent )
{
rv = grandParent - > FirstChild ( aPresContext , nsnull , & firstParent ) ;
if ( NS_SUCCEEDED ( rv ) & & firstParent )
{
* aLength = 0 ;
if ( firstParent = = parent ) //then our parent is the first child of granddad. use BEFORE
{
* aOffset = 0 ;
}
else
{
PRInt32 numChildren ;
if ( NS_SUCCEEDED ( rv = ( * aContent ) - > ChildCount ( numChildren ) ) )
* aOffset = numChildren ;
else
return rv ;
}
}
else
return rv ;
}
}
}
//END GENERATED BLOCK
if ( ! * aContent )
{
* aContent = mContent ;
NS_IF_ADDREF ( * aContent ) ;
}
return NS_OK ;
}
2001-01-27 14:09:34 +00:00
//---------------------------------------------------------
nsresult nsTextFrame : : GetTextInfoForPainting ( nsIPresContext * aPresContext ,
nsIRenderingContext & aRenderingContext ,
nsIPresShell * * aPresShell ,
nsISelectionController * * aSelectionController ,
PRBool & aDisplayingSelection ,
PRBool & aIsPaginated ,
PRBool & aIsSelected ,
PRInt16 & aSelectionValue ,
nsILineBreaker * * aLineBreaker )
{
NS_ENSURE_ARG_POINTER ( aPresContext ) ;
NS_ENSURE_ARG_POINTER ( aPresShell ) ;
NS_ENSURE_ARG_POINTER ( aSelectionController ) ;
NS_ENSURE_ARG_POINTER ( aLineBreaker ) ;
//get the presshell
nsresult rv = aPresContext - > GetShell ( aPresShell ) ;
if ( NS_FAILED ( rv ) | | ( * aPresShell ) = = nsnull )
return NS_ERROR_FAILURE ;
//get the selection controller
rv = GetSelectionController ( aPresContext , aSelectionController ) ;
if ( NS_FAILED ( rv ) | | ! ( * aSelectionController ) )
return NS_ERROR_FAILURE ;
aPresContext - > IsPaginated ( & aIsPaginated ) ;
PRBool isRenderingOnlySelection ;
aPresContext - > IsRenderingOnlySelection ( & isRenderingOnlySelection ) ;
( * aSelectionController ) - > GetDisplaySelection ( & aSelectionValue ) ;
2001-06-29 05:32:56 +00:00
if ( aIsPaginated ) {
aDisplayingSelection = isRenderingOnlySelection ;
} else {
//if greater than hidden then we display some kind of selection
aDisplayingSelection = ( aSelectionValue > nsISelectionController : : SELECTION_HIDDEN ) ;
}
2001-12-18 01:29:49 +00:00
PRInt16 textSel = 0 ;
( * aSelectionController ) - > GetSelectionFlags ( & textSel ) ;
if ( ! ( textSel & nsISelectionDisplay : : DISPLAY_TEXT ) )
2001-12-18 06:15:46 +00:00
aDisplayingSelection = PR_FALSE ;
2001-01-27 14:09:34 +00:00
// Transform text from content into renderable form
// XXX If the text fragment is already Unicode and text text wasn't
// transformed when we formatted it, then there's no need to do all
// this and we should just render the text fragment directly. See
// PaintAsciiText()...
nsCOMPtr < nsIDocument > doc ;
( * aPresShell ) - > GetDocument ( getter_AddRefs ( doc ) ) ;
if ( ! doc )
return NS_ERROR_FAILURE ;
doc - > GetLineBreaker ( aLineBreaker ) ;
nsFrameState frameState ;
GetFrameState ( & frameState ) ;
aIsSelected = ( frameState & NS_FRAME_SELECTED_CONTENT ) = = NS_FRAME_SELECTED_CONTENT ;
return NS_OK ;
}
PRBool
nsTextFrame : : IsTextInSelection ( nsIPresContext * aPresContext ,
nsIRenderingContext & aRenderingContext )
{
nsCOMPtr < nsISelectionController > selCon ;
nsCOMPtr < nsIPresShell > shell ;
PRBool displaySelection ;
PRBool isPaginated ;
PRBool isSelected ;
PRInt16 selectionValue ;
nsCOMPtr < nsILineBreaker > lb ;
if ( NS_FAILED ( GetTextInfoForPainting ( aPresContext ,
aRenderingContext ,
getter_AddRefs ( shell ) ,
getter_AddRefs ( selCon ) ,
displaySelection ,
isPaginated ,
isSelected ,
selectionValue ,
getter_AddRefs ( lb ) ) ) ) {
return PR_FALSE ;
}
// Make enough space to transform
nsAutoTextBuffer paintBuffer ;
nsAutoIndexBuffer indexBuffer ;
if ( NS_FAILED ( indexBuffer . GrowTo ( mContentLength + 1 ) ) ) {
return PR_FALSE ;
}
TextStyle ts ( aPresContext , aRenderingContext , mStyleContext ) ;
// Transform text from content into renderable form
// XXX If the text fragment is already Unicode and text text wasn't
// transformed when we formatted it, then there's no need to do all
// this and we should just render the text fragment directly. See
// PaintAsciiText()...
nsTextTransformer tx ( lb , nsnull , aPresContext ) ;
PRInt32 textLength ;
// no need to worry about justification, that's always on the slow path
PrepareUnicodeText ( tx , & indexBuffer , & paintBuffer , & textLength ) ;
PRInt32 * ip = indexBuffer . mBuffer ;
PRUnichar * text = paintBuffer . mBuffer ;
if ( 0 ! = textLength ) {
SelectionDetails * details = nsnull ;
nsCOMPtr < nsIFrameSelection > frameSelection ;
//get the frameSelection from the selection controller
if ( selCon ) {
frameSelection = do_QueryInterface ( selCon ) ; //this MAY implement
}
nsresult rv = NS_OK ;
//if that failed get it from the pres shell
if ( ! frameSelection )
rv = shell - > GetFrameSelection ( getter_AddRefs ( frameSelection ) ) ;
if ( NS_SUCCEEDED ( rv ) & & frameSelection ) {
nsCOMPtr < nsIContent > content ;
PRInt32 offset ;
PRInt32 length ;
rv = GetContentAndOffsetsForSelection ( aPresContext , getter_AddRefs ( content ) , & offset , & length ) ;
if ( NS_SUCCEEDED ( rv ) & & content ) {
rv = frameSelection - > LookUpSelection ( content , mContentOffset ,
mContentLength , & details , PR_FALSE ) ;
}
}
//where are the selection points "really"
SelectionDetails * sdptr = details ;
while ( sdptr ) {
sdptr - > mStart = ip [ sdptr - > mStart ] - mContentOffset ;
sdptr - > mEnd = ip [ sdptr - > mEnd ] - mContentOffset ;
sdptr = sdptr - > mNext ;
}
//while we have substrings...
//PRBool drawn = PR_FALSE;
DrawSelectionIterator iter ( details , text , ( PRUint32 ) textLength , ts , nsISelectionController : : SELECTION_NORMAL ) ;
if ( ! iter . IsDone ( ) & & iter . First ( ) ) {
return PR_TRUE ;
}
sdptr = details ;
if ( details ) {
while ( ( sdptr = details - > mNext ) ! = nsnull ) {
delete details ;
details = sdptr ;
}
delete details ;
}
}
return PR_FALSE ;
}
NS_IMETHODIMP
nsTextFrame : : IsVisibleForPainting ( nsIPresContext * aPresContext ,
nsIRenderingContext & aRenderingContext ,
PRBool aCheckVis ,
PRBool * aIsVisible )
{
if ( aCheckVis ) {
nsIStyleContext * sc = mStyleContext ;
2001-05-31 22:19:43 +00:00
const nsStyleVisibility * vis =
( const nsStyleVisibility * ) mStyleContext - > GetStyleData ( eStyleStruct_Visibility ) ;
if ( ! vis - > IsVisible ( ) ) {
2001-01-27 14:09:34 +00:00
* aIsVisible = PR_FALSE ;
return NS_OK ;
}
}
// Start by assuming we are visible and need to be painted
PRBool isVisible = PR_TRUE ;
PRBool isPaginated ;
aPresContext - > IsPaginated ( & isPaginated ) ;
if ( isPaginated ) {
PRBool isRendingSelection ;
aPresContext - > IsRenderingOnlySelection ( & isRendingSelection ) ;
if ( isRendingSelection ) {
// Check the quick way first
PRBool isSelected = ( mState & NS_FRAME_SELECTED_CONTENT ) = = NS_FRAME_SELECTED_CONTENT ;
if ( isSelected ) {
isVisible = IsTextInSelection ( aPresContext , aRenderingContext ) ;
} else {
isVisible = PR_FALSE ;
}
}
}
* aIsVisible = isVisible ;
return NS_OK ;
}
2000-04-02 05:05:31 +00:00
1998-09-08 22:34:40 +00:00
void
1999-04-20 00:23:33 +00:00
nsTextFrame : : PaintUnicodeText ( nsIPresContext * aPresContext ,
nsIRenderingContext & aRenderingContext ,
nsIStyleContext * aStyleContext ,
TextStyle & aTextStyle ,
nscoord dx , nscoord dy )
1998-09-08 22:34:40 +00:00
{
2000-04-28 06:21:31 +00:00
nsCOMPtr < nsISelectionController > selCon ;
2001-01-27 14:09:34 +00:00
nsCOMPtr < nsIPresShell > shell ;
2002-02-19 07:30:58 +00:00
PRBool displaySelection , canDarkenColor = PR_FALSE ;
2001-01-27 14:09:34 +00:00
PRBool isPaginated ;
PRBool isSelected ;
2000-05-11 04:25:43 +00:00
PRInt16 selectionValue ;
2001-01-27 14:09:34 +00:00
nsCOMPtr < nsILineBreaker > lb ;
2001-04-11 23:32:21 +00:00
# ifdef IBMBIDI
2001-06-21 12:35:48 +00:00
PRUint8 level = 0 ;
2001-04-11 23:32:21 +00:00
# endif
2002-02-15 14:48:12 +00:00
2001-01-27 14:09:34 +00:00
if ( NS_FAILED ( GetTextInfoForPainting ( aPresContext ,
aRenderingContext ,
getter_AddRefs ( shell ) ,
getter_AddRefs ( selCon ) ,
displaySelection ,
isPaginated ,
isSelected ,
selectionValue ,
getter_AddRefs ( lb ) ) ) ) {
return ;
}
2002-02-15 14:48:12 +00:00
if ( isPaginated ) {
canDarkenColor = CanDarken ( aPresContext ) ;
}
1998-10-20 00:21:18 +00:00
// Make enough space to transform
1999-09-22 00:40:56 +00:00
nsAutoTextBuffer paintBuffer ;
nsAutoIndexBuffer indexBuffer ;
if ( displaySelection ) {
if ( NS_FAILED ( indexBuffer . GrowTo ( mContentLength + 1 ) ) ) {
return ;
}
1998-09-08 22:34:40 +00:00
}
1998-10-03 00:48:19 +00:00
nscoord width = mRect . width ;
1998-10-20 00:21:18 +00:00
// Transform text from content into renderable form
2000-04-12 14:54:43 +00:00
// XXX If the text fragment is already Unicode and text text wasn't
// transformed when we formatted it, then there's no need to do all
// this and we should just render the text fragment directly. See
// PaintAsciiText()...
2001-01-27 14:09:34 +00:00
2000-09-20 23:00:32 +00:00
nsTextTransformer tx ( lb , nsnull , aPresContext ) ;
1999-09-22 00:40:56 +00:00
PRInt32 textLength ;
2000-04-17 14:40:46 +00:00
// no need to worry about justification, that's always on the slow path
1999-09-22 00:40:56 +00:00
PrepareUnicodeText ( tx , ( displaySelection ? & indexBuffer : nsnull ) ,
& paintBuffer , & textLength ) ;
PRInt32 * ip = indexBuffer . mBuffer ;
PRUnichar * text = paintBuffer . mBuffer ;
1999-04-26 04:02:04 +00:00
2000-05-13 20:47:42 +00:00
if ( 0 ! = textLength )
{
2001-04-11 23:32:21 +00:00
# ifdef IBMBIDI
PRBool isRightToLeftOnBidiPlatform = PR_FALSE ;
2001-10-24 11:12:31 +00:00
PRBool isBidiSystem = PR_FALSE ;
2001-04-11 23:32:21 +00:00
PRBool bidiEnabled ;
2001-10-24 11:12:31 +00:00
nsCharType charType = eCharType_LeftToRight ;
2001-05-16 13:40:08 +00:00
aPresContext - > GetBidiEnabled ( & bidiEnabled ) ;
2001-04-11 23:32:21 +00:00
if ( bidiEnabled ) {
2002-06-11 21:00:20 +00:00
aPresContext - > GetIsBidiSystem ( isBidiSystem ) ;
2001-06-21 12:35:48 +00:00
GetBidiProperty ( aPresContext , nsLayoutAtoms : : embeddingLevel , ( void * * ) & level , sizeof ( level ) ) ;
GetBidiProperty ( aPresContext , nsLayoutAtoms : : charType , ( void * * ) & charType , sizeof ( charType ) ) ;
2001-04-11 23:32:21 +00:00
2002-06-11 21:00:20 +00:00
isRightToLeftOnBidiPlatform = ( isBidiSystem & &
( eCharType_RightToLeft = = charType | |
eCharType_RightToLeftArabic = = charType ) ) ;
2001-04-11 23:32:21 +00:00
if ( isRightToLeftOnBidiPlatform ) {
// indicate that the platform should use its native
// capabilities to reorder the text with right-to-left
// base direction
aRenderingContext . SetRightToLeftText ( PR_TRUE ) ;
}
nsBidiPresUtils * bidiUtils ;
aPresContext - > GetBidiUtils ( & bidiUtils ) ;
if ( bidiUtils ) {
2002-06-11 21:00:20 +00:00
PRInt32 rememberTextLength = textLength ;
bidiUtils - > ReorderUnicodeText ( text , textLength ,
charType , level & 1 , isBidiSystem ) ;
NS_ASSERTION ( rememberTextLength = = textLength , " Bidi formatting changed text length " ) ;
2001-04-11 23:32:21 +00:00
}
}
# endif // IBMBIDI
2000-05-13 20:47:42 +00:00
if ( ! displaySelection | | ! isSelected ) //draw text normally
{
1998-09-08 22:34:40 +00:00
// When there is no selection showing, use the fastest and
// simplest rendering approach
2002-02-15 14:48:12 +00:00
aRenderingContext . SetColor ( nsCSSRendering : : TransformColor ( aTextStyle . mColor - > mColor , canDarkenColor ) ) ;
2001-10-30 22:58:00 +00:00
aRenderingContext . DrawString ( text , PRUint32 ( textLength ) , dx , dy + mAscent ) ;
1998-10-26 17:27:53 +00:00
PaintTextDecorations ( aRenderingContext , aStyleContext , aTextStyle ,
dx , dy , width ) ;
1998-09-08 22:34:40 +00:00
}
2000-05-13 20:47:42 +00:00
else
{ //we draw according to selection rules
1999-07-15 18:19:03 +00:00
SelectionDetails * details = nsnull ;
1999-04-26 04:02:04 +00:00
nsCOMPtr < nsIFrameSelection > frameSelection ;
2001-01-27 14:09:34 +00:00
//get the frameSelection from the selection controller
if ( selCon )
2000-05-13 20:47:42 +00:00
{
frameSelection = do_QueryInterface ( selCon ) ; //this MAY implement
}
2001-01-27 14:09:34 +00:00
//if that failed get it from the pres shell
nsresult rv = NS_OK ;
2000-05-13 20:47:42 +00:00
if ( ! frameSelection )
rv = shell - > GetFrameSelection ( getter_AddRefs ( frameSelection ) ) ;
if ( NS_SUCCEEDED ( rv ) & & frameSelection ) {
nsCOMPtr < nsIContent > content ;
PRInt32 offset ;
PRInt32 length ;
rv = GetContentAndOffsetsForSelection ( aPresContext , getter_AddRefs ( content ) , & offset , & length ) ;
if ( NS_SUCCEEDED ( rv ) & & content ) {
rv = frameSelection - > LookUpSelection ( content , mContentOffset ,
mContentLength , & details , PR_FALSE ) ;
1999-04-26 04:02:04 +00:00
}
1998-12-14 18:34:14 +00:00
}
1999-02-13 04:46:47 +00:00
1999-04-26 04:02:04 +00:00
1999-07-15 18:19:03 +00:00
//where are the selection points "really"
SelectionDetails * sdptr = details ;
while ( sdptr ) {
sdptr - > mStart = ip [ sdptr - > mStart ] - mContentOffset ;
sdptr - > mEnd = ip [ sdptr - > mEnd ] - mContentOffset ;
2002-01-10 02:32:43 +00:00
# ifdef SUNCTL
static NS_DEFINE_CID ( kLECID , NS_ULE_CID ) ;
nsCOMPtr < nsILE > mCtlObj ;
mCtlObj = do_CreateInstance ( kLECID , & rv ) ;
if ( NS_FAILED ( rv ) ) {
NS_WARNING ( " Cell based cursor movement will not be supported \n " ) ;
mCtlObj = nsnull ;
}
else {
PRInt32 mStart , mEnd ;
if ( sdptr - > mEnd < textLength ) {
mCtlObj - > GetRangeOfCluster ( text , PRInt32 ( textLength ) , sdptr - > mEnd , & mStart , & mEnd ) ;
if ( sdptr - > mStart > sdptr - > mEnd ) /* Left Edge */
sdptr - > mEnd = mStart ;
else
sdptr - > mEnd = mEnd ;
}
/* Always start selection from a Right Edge */
if ( sdptr - > mStart > 0 ) {
mCtlObj - > GetRangeOfCluster ( text , PRInt32 ( textLength ) , sdptr - > mStart , & mStart , & mEnd ) ;
sdptr - > mStart = mEnd ;
}
}
# endif /* SUNCTL */
2001-10-24 11:12:31 +00:00
# ifdef IBMBIDI
AdjustSelectionPointsForBidi ( sdptr , textLength , CHARTYPE_IS_RTL ( charType ) , level & 1 , isBidiSystem ) ;
2001-04-11 23:32:21 +00:00
# endif
1999-07-15 18:19:03 +00:00
sdptr = sdptr - > mNext ;
}
2000-03-31 07:26:07 +00:00
//while we have substrings...
2000-05-16 22:48:28 +00:00
//PRBool drawn = PR_FALSE;
2000-05-11 04:25:43 +00:00
DrawSelectionIterator iter ( details , text , ( PRUint32 ) textLength , aTextStyle , selectionValue ) ;
2000-04-10 21:02:25 +00:00
if ( ! iter . IsDone ( ) & & iter . First ( ) )
2000-03-31 07:26:07 +00:00
{
2000-04-10 21:02:25 +00:00
nscoord currentX = dx ;
nscoord newWidth ; //temp
2001-04-11 23:32:21 +00:00
# ifdef IBMBIDI // Simon - display substrings RTL in RTL frame
nscoord FrameWidth = 0 ;
if ( isRightToLeftOnBidiPlatform )
if ( NS_SUCCEEDED ( aRenderingContext . GetWidth ( text , textLength , FrameWidth ) ) )
currentX = dx + FrameWidth ;
# endif
2000-04-10 21:02:25 +00:00
while ( ! iter . IsDone ( ) )
2000-03-31 07:26:07 +00:00
{
2000-04-10 21:02:25 +00:00
PRUnichar * currenttext = iter . CurrentTextUnicharPtr ( ) ;
PRUint32 currentlength = iter . CurrentLength ( ) ;
2000-05-16 22:48:28 +00:00
//TextStyle ¤tStyle = iter.CurrentStyle();
2000-04-10 21:02:25 +00:00
nscolor currentFGColor = iter . CurrentForeGroundColor ( ) ;
nscolor currentBKColor ;
2000-03-31 07:26:07 +00:00
2001-04-11 23:32:21 +00:00
# ifdef IBMBIDI
2001-11-14 14:21:52 +00:00
if ( currentlength > 0
& & NS_SUCCEEDED ( aRenderingContext . GetWidth ( currenttext , currentlength , newWidth ) ) ) //ADJUST FOR CHAR SPACING
{
2001-04-11 23:32:21 +00:00
if ( isRightToLeftOnBidiPlatform )
currentX - = newWidth ;
2001-11-14 14:21:52 +00:00
# else // not IBMBIDI
if ( NS_SUCCEEDED ( aRenderingContext . GetWidth ( currenttext , currentlength , newWidth ) ) ) //ADJUST FOR CHAR SPACING
{
2001-04-11 23:32:21 +00:00
# endif
2001-01-27 14:09:34 +00:00
if ( iter . CurrentBackGroundColor ( currentBKColor ) & & ! isPaginated )
2000-04-10 21:02:25 +00:00
{ //DRAW RECT HERE!!!
aRenderingContext . SetColor ( currentBKColor ) ;
aRenderingContext . FillRect ( currentX , dy , newWidth , mRect . height ) ;
currentFGColor = EnsureDifferentColors ( currentFGColor , currentBKColor ) ;
2000-03-31 07:26:07 +00:00
}
2000-04-10 21:02:25 +00:00
}
else
newWidth = 0 ;
2001-01-27 14:09:34 +00:00
if ( isPaginated & & ! iter . IsBeforeOrAfter ( ) ) {
2002-02-15 14:48:12 +00:00
aRenderingContext . SetColor ( nsCSSRendering : : TransformColor ( aTextStyle . mColor - > mColor , canDarkenColor ) ) ;
2001-10-30 22:58:00 +00:00
aRenderingContext . DrawString ( currenttext , currentlength , currentX , dy + mAscent ) ;
2001-01-27 14:09:34 +00:00
} else if ( ! isPaginated ) {
2002-02-15 14:48:12 +00:00
aRenderingContext . SetColor ( nsCSSRendering : : TransformColor ( currentFGColor , canDarkenColor ) ) ;
2001-10-30 22:58:00 +00:00
aRenderingContext . DrawString ( currenttext , currentlength , currentX , dy + mAscent ) ;
2001-01-27 14:09:34 +00:00
}
2000-03-31 07:26:07 +00:00
2001-04-11 23:32:21 +00:00
# ifdef IBMBIDI
2001-11-14 14:21:52 +00:00
if ( ! isRightToLeftOnBidiPlatform )
2001-04-11 23:32:21 +00:00
# endif
2000-04-10 21:02:25 +00:00
currentX + = newWidth ; //increment twips X start
2000-03-31 07:26:07 +00:00
2000-04-10 21:02:25 +00:00
iter . Next ( ) ;
2000-03-31 07:26:07 +00:00
}
}
2001-01-27 14:09:34 +00:00
else if ( ! isPaginated )
2000-03-31 07:26:07 +00:00
{
2002-02-15 14:48:12 +00:00
aRenderingContext . SetColor ( nsCSSRendering : : TransformColor ( aTextStyle . mColor - > mColor , canDarkenColor ) ) ;
2001-10-30 22:58:00 +00:00
aRenderingContext . DrawString ( text , PRUint32 ( textLength ) , dx , dy + mAscent ) ;
2000-03-31 07:26:07 +00:00
}
1999-07-15 18:19:03 +00:00
PaintTextDecorations ( aRenderingContext , aStyleContext ,
aTextStyle , dx , dy , width , text , details , 0 , ( PRUint32 ) textLength ) ;
sdptr = details ;
if ( details ) {
1999-08-09 19:15:04 +00:00
while ( ( sdptr = details - > mNext ) ! = nsnull ) {
1999-07-15 18:19:03 +00:00
delete details ;
details = sdptr ;
1998-09-08 22:34:40 +00:00
}
1999-07-15 18:19:03 +00:00
delete details ;
1998-09-08 22:34:40 +00:00
}
}
2001-04-11 23:32:21 +00:00
# ifdef IBMBIDI
if ( isRightToLeftOnBidiPlatform ) {
// indicate that future text should not be reordered with
// right-to-left base direction
aRenderingContext . SetRightToLeftText ( PR_FALSE ) ;
}
# endif // IBMBIDI
1998-09-08 22:34:40 +00:00
}
}
1999-03-12 21:38:16 +00:00
//measure Spaced Textvoid
1999-04-20 00:23:33 +00:00
nsresult
1999-11-24 06:03:41 +00:00
nsTextFrame : : GetPositionSlowly ( nsIPresContext * aPresContext ,
1999-04-20 00:23:33 +00:00
nsIRenderingContext * aRendContext ,
1999-11-24 01:10:22 +00:00
const nsPoint & aPoint ,
1999-05-17 19:50:29 +00:00
nsIContent * * aNewContent ,
1999-04-26 04:02:04 +00:00
PRInt32 & aOffset )
1999-03-12 21:38:16 +00:00
{
2000-10-27 14:16:36 +00:00
// pre-condition tests
NS_PRECONDITION ( aPresContext & & aRendContext & & aNewContent , " null arg " ) ;
if ( ! aPresContext | | ! aRendContext | | ! aNewContent ) {
1999-03-12 21:38:16 +00:00
return NS_ERROR_NULL_POINTER ;
1999-04-20 00:23:33 +00:00
}
2000-10-27 14:16:36 +00:00
// initialize out param
* aNewContent = nsnull ;
1999-04-20 00:23:33 +00:00
1999-11-24 06:03:41 +00:00
TextStyle ts ( aPresContext , * aRendContext , mStyleContext ) ;
2000-04-17 14:40:46 +00:00
if ( ! ts . mSmallCaps & & ! ts . mWordSpacing & & ! ts . mLetterSpacing & & ! ts . mJustifying ) {
1999-03-12 21:38:16 +00:00
return NS_ERROR_INVALID_ARG ;
1999-04-20 00:23:33 +00:00
}
1999-09-14 23:16:22 +00:00
nsIView * view ;
nsPoint origin ;
1999-11-24 06:03:41 +00:00
GetOffsetFromView ( aPresContext , origin , & view ) ;
1999-03-12 21:38:16 +00:00
2000-10-27 14:16:36 +00:00
/* This if clause is the cause of much pain. If aNewContent is set, then any
* code path that returns an error must set aNewContent to null before returning ,
* or risk the caller unknowingly decrementing aNewContent inappropriately .
* Here ' s what Robert O ' Callahan has to say on the matter :
If I ' m not mistaken , in GetPositionSlowly , the values of aNewContent and
aOffset set in the conditional " if (aPoint.x - origin.x < 0) " are
overwritten on all successful return paths . Since they should never be
used by the caller if the function fails , that entire " if " statement is
- - - or should be - - - a no - op . Come to think of it , it doesn ' t make sense
either ; setting aOffset to zero is nonsense .
I recommend you just delete that " if " statement .
*
* If this clause is removed , then some of the bullet - proofing code
* prefaced with " bug 56704 " comments can be removed as well .
*/
1999-11-24 01:10:22 +00:00
if ( aPoint . x - origin . x < 0 )
1999-09-14 23:16:22 +00:00
{
* aNewContent = mContent ;
aOffset = 0 ;
}
1999-11-24 06:03:41 +00:00
nsCOMPtr < nsIDocument > doc ( getter_AddRefs ( GetDocument ( aPresContext ) ) ) ;
1999-03-12 21:38:16 +00:00
// Make enough space to transform
1999-09-22 00:40:56 +00:00
nsAutoTextBuffer paintBuffer ;
nsAutoIndexBuffer indexBuffer ;
nsresult rv = indexBuffer . GrowTo ( mContentLength + 1 ) ;
if ( NS_FAILED ( rv ) ) {
2000-10-27 14:16:36 +00:00
// If we've already assigned aNewContent, make sure to 0 it out here.
// See bug 56704.
* aNewContent = nsnull ;
1999-09-22 00:40:56 +00:00
return rv ;
1999-03-12 21:38:16 +00:00
}
// Transform text from content into renderable form
nsCOMPtr < nsILineBreaker > lb ;
doc - > GetLineBreaker ( getter_AddRefs ( lb ) ) ;
2000-09-20 23:00:32 +00:00
nsTextTransformer tx ( lb , nsnull , aPresContext ) ;
1999-09-22 00:40:56 +00:00
PRInt32 textLength ;
2000-04-17 14:40:46 +00:00
PRInt32 numSpaces ;
2002-06-11 21:00:20 +00:00
# ifdef IBMBIDI
// Simulate a non-Bidi system for char by char measuring
PRBool isBidiSystem = PR_FALSE ;
aPresContext - > GetIsBidiSystem ( isBidiSystem ) ;
aPresContext - > SetIsBidiSystem ( PR_FALSE ) ;
# endif
2000-04-17 14:40:46 +00:00
numSpaces = PrepareUnicodeText ( tx , & indexBuffer , & paintBuffer , & textLength ) ;
2002-06-11 21:00:20 +00:00
# ifdef IBMBIDI
aPresContext - > SetIsBidiSystem ( isBidiSystem ) ;
# endif
1999-09-22 00:40:56 +00:00
if ( textLength < = 0 ) {
2000-10-27 14:16:36 +00:00
// If we've already assigned aNewContent, make sure to 0 it out here.
// aNewContent is undefined in the case that we return a failure,
// If we were to return a valid pointer, we risk decrementing that node's
// ref count an extra time by the caller.
// See bug 56704 for more details.
* aNewContent = nsnull ;
1999-06-19 20:36:44 +00:00
return NS_ERROR_FAILURE ;
1999-09-22 00:40:56 +00:00
}
1999-03-12 21:38:16 +00:00
2001-04-11 23:32:21 +00:00
# ifdef IBMBIDI // Simon -- reverse RTL text here
2001-06-21 12:35:48 +00:00
PRUint8 level ;
GetBidiProperty ( aPresContext , nsLayoutAtoms : : embeddingLevel , ( void * * ) & level , sizeof ( level ) ) ;
2001-04-11 23:32:21 +00:00
PRBool isOddLevel = ( level & 1 ) ;
if ( isOddLevel ) {
PRUnichar * tStart , * tEnd ;
PRUnichar tSwap ;
for ( tStart = paintBuffer . mBuffer , tEnd = tStart + textLength - 1 ; tEnd > tStart ; tStart + + , tEnd - - ) {
tSwap = * tStart ;
* tStart = * tEnd ;
* tEnd = tSwap ;
}
}
# endif // IBMBIDI
2000-04-17 14:40:46 +00:00
ComputeExtraJustificationSpacing ( * aRendContext , ts , paintBuffer . mBuffer , textLength , numSpaces ) ;
//IF STYLE SAYS TO SELECT TO END OF FRAME HERE...
2000-12-09 04:21:51 +00:00
nsCOMPtr < nsIPref > prefs ( do_GetService ( kPrefCID , & rv ) ) ;
1999-11-24 01:10:22 +00:00
PRInt32 prefInt = 0 ;
PRBool outofstylehandled = PR_FALSE ;
if ( NS_SUCCEEDED ( rv ) & & prefs )
{
if ( NS_SUCCEEDED ( prefs - > GetIntPref ( " browser.drag_out_of_frame_style " , & prefInt ) ) & & prefInt )
{
2002-04-29 22:03:41 +00:00
if ( aPoint . y < origin . y ) //above rectangle
1999-11-24 01:10:22 +00:00
{
aOffset = mContentOffset ;
outofstylehandled = PR_TRUE ;
}
2002-04-29 22:03:41 +00:00
else if ( ( aPoint . y - origin . y ) > mRect . height )
1999-11-24 01:10:22 +00:00
{
aOffset = mContentOffset + mContentLength ;
outofstylehandled = PR_TRUE ;
}
}
}
if ( ! outofstylehandled ) //then we drag to closest X point and dont worry about the 'Y'
//END STYLE RULE
{
2000-03-31 07:26:07 +00:00
//the following will first get the index into the PAINTBUFFER then the actual content
nscoord adjustedX = PR_MAX ( 0 , aPoint . x - origin . x ) ;
1999-11-24 01:10:22 +00:00
2001-04-11 23:32:21 +00:00
# ifdef IBMBIDI
if ( isOddLevel )
aOffset = mContentOffset + textLength - GetLengthSlowly ( * aRendContext , ts , paintBuffer . mBuffer , textLength , adjustedX ) ;
else
# endif
2000-03-31 07:26:07 +00:00
aOffset = mContentOffset + GetLengthSlowly ( * aRendContext , ts , paintBuffer . mBuffer , textLength , adjustedX ) ;
1999-11-24 01:10:22 +00:00
PRInt32 i ;
2002-03-27 03:28:34 +00:00
PRInt32 * ip = indexBuffer . mBuffer ;
1999-11-24 01:10:22 +00:00
for ( i = 0 ; i < = mContentLength ; i + + ) {
2002-03-27 03:28:34 +00:00
if ( ( ip [ i ] > = aOffset ) & & //reverse mapping
( ! IS_LOW_SURROGATE ( paintBuffer . mBuffer [ ip [ i ] - mContentOffset ] ) ) ) {
2000-03-31 07:26:07 +00:00
aOffset = i + mContentOffset ;
break ;
1999-03-12 21:38:16 +00:00
}
}
}
1999-04-20 00:23:33 +00:00
1999-05-17 19:50:29 +00:00
* aNewContent = mContent ;
if ( * aNewContent )
( * aNewContent ) - > AddRef ( ) ;
1999-03-12 21:38:16 +00:00
return NS_OK ;
}
1998-10-20 16:46:14 +00:00
void
1999-04-20 00:23:33 +00:00
nsTextFrame : : RenderString ( nsIRenderingContext & aRenderingContext ,
nsIStyleContext * aStyleContext ,
TextStyle & aTextStyle ,
PRUnichar * aBuffer , PRInt32 aLength ,
nscoord aX , nscoord aY ,
1999-07-15 18:19:03 +00:00
nscoord aWidth ,
SelectionDetails * aDetails /*=nsnull*/ )
1998-10-20 16:46:14 +00:00
{
PRUnichar buf [ TEXT_BUF_SIZE ] ;
PRUnichar * bp0 = buf ;
2002-04-07 17:37:30 +00:00
nscoord spacingMem [ TEXT_BUF_SIZE ] ;
nscoord * sp0 = spacingMem ;
2001-03-22 01:27:13 +00:00
2002-04-07 17:37:30 +00:00
PRBool spacing = ( 0 ! = aTextStyle . mLetterSpacing ) | |
( 0 ! = aTextStyle . mWordSpacing ) | | aTextStyle . mJustifying ;
2001-03-22 01:27:13 +00:00
//German 0x00df might expand to "SS", but no need to count it for speed reason
if ( aTextStyle . mSmallCaps ) {
2002-04-07 17:37:30 +00:00
if ( aLength * 2 > TEXT_BUF_SIZE ) {
2001-03-22 01:27:13 +00:00
bp0 = new PRUnichar [ aLength * 2 ] ;
2002-04-07 17:37:30 +00:00
if ( spacing )
sp0 = new nscoord [ aLength * 2 ] ;
}
2001-03-22 01:27:13 +00:00
}
else if ( aLength > TEXT_BUF_SIZE ) {
1998-10-20 16:46:14 +00:00
bp0 = new PRUnichar [ aLength ] ;
2002-04-07 17:37:30 +00:00
if ( spacing )
sp0 = new nscoord [ aLength ] ;
1998-10-20 16:46:14 +00:00
}
2002-04-07 17:37:30 +00:00
PRUnichar * bp = bp0 ;
nscoord * sp = sp0 ;
1998-10-26 17:27:53 +00:00
nsIFontMetrics * lastFont = aTextStyle . mLastFont ;
1998-10-20 16:46:14 +00:00
PRInt32 pendingCount ;
PRUnichar * runStart = bp ;
1998-10-26 17:27:53 +00:00
nscoord charWidth , width = 0 ;
1999-07-15 18:19:03 +00:00
PRInt32 countSoFar = 0 ;
1998-10-20 16:46:14 +00:00
for ( ; - - aLength > = 0 ; aBuffer + + ) {
nsIFontMetrics * nextFont ;
2001-10-30 22:58:00 +00:00
nscoord glyphWidth ;
1998-10-20 16:46:14 +00:00
PRUnichar ch = * aBuffer ;
2001-10-26 17:18:35 +00:00
if ( aTextStyle . mSmallCaps & &
( IsLowerCase ( ch ) | | ( ch = = kSZLIG ) ) ) {
1998-10-26 17:27:53 +00:00
nextFont = aTextStyle . mSmallFont ;
2001-03-22 01:27:13 +00:00
PRUnichar upper_ch ;
// German szlig should be expanded to "SS".
if ( ch = = kSZLIG )
upper_ch = ( PRUnichar ) ' S ' ;
else
2001-10-26 17:18:35 +00:00
upper_ch = ToUpperCase ( ch ) ;
1998-10-26 17:27:53 +00:00
if ( lastFont ! = aTextStyle . mSmallFont ) {
aRenderingContext . SetFont ( aTextStyle . mSmallFont ) ;
2001-03-22 01:27:13 +00:00
aRenderingContext . GetWidth ( upper_ch , charWidth ) ;
1998-10-26 17:27:53 +00:00
aRenderingContext . SetFont ( aTextStyle . mNormalFont ) ;
}
else {
2001-03-22 01:27:13 +00:00
aRenderingContext . GetWidth ( upper_ch , charWidth ) ;
1998-10-26 17:27:53 +00:00
}
glyphWidth = charWidth + aTextStyle . mLetterSpacing ;
2001-03-22 01:27:13 +00:00
if ( ch = = kSZLIG ) //add an additional 'S' here.
{
* bp + + = upper_ch ;
2002-04-07 17:37:30 +00:00
if ( spacing )
* sp + + = glyphWidth ;
2001-03-22 01:27:13 +00:00
width + = glyphWidth ;
}
ch = upper_ch ;
1998-10-26 17:27:53 +00:00
}
else if ( ch = = ' ' ) {
nextFont = aTextStyle . mNormalFont ;
2001-09-28 22:39:10 +00:00
glyphWidth = aTextStyle . mSpaceWidth + aTextStyle . mWordSpacing + aTextStyle . mLetterSpacing
2000-04-17 14:40:46 +00:00
+ aTextStyle . mExtraSpacePerSpace ;
if ( ( PRUint32 ) - - aTextStyle . mNumSpacesToRender <
( PRUint32 ) aTextStyle . mNumSpacesReceivingExtraJot ) {
glyphWidth + + ;
1998-10-27 16:52:34 +00:00
}
1998-10-20 16:46:14 +00:00
}
else {
1998-10-26 17:27:53 +00:00
if ( lastFont ! = aTextStyle . mNormalFont ) {
aRenderingContext . SetFont ( aTextStyle . mNormalFont ) ;
}
2002-03-27 03:28:34 +00:00
if ( IS_HIGH_SURROGATE ( ch ) & & aLength > 0 & &
IS_LOW_SURROGATE ( * ( aBuffer + 1 ) ) ) {
// special handling for surrogate pair
aRenderingContext . GetWidth ( aBuffer , 2 , charWidth ) ;
glyphWidth = charWidth + aTextStyle . mLetterSpacing ;
// copy the surrogate low
* bp + + = ch ;
- - aLength ;
aBuffer + + ;
ch = * aBuffer ;
// put the width into the space buffer
width + = glyphWidth ;
* sp + + = glyphWidth ;
// set the glyphWidth to 0 so the code later will
// set a 0 for one element in space array for surrogate low to 0
glyphWidth = 0 ;
} else {
1998-10-26 17:27:53 +00:00
aRenderingContext . GetWidth ( ch , charWidth ) ;
2002-03-27 03:28:34 +00:00
glyphWidth = charWidth + aTextStyle . mLetterSpacing ;
}
if ( lastFont ! = aTextStyle . mNormalFont ) {
aRenderingContext . SetFont ( aTextStyle . mSmallFont ) ;
1998-10-26 17:27:53 +00:00
}
nextFont = aTextStyle . mNormalFont ;
1998-10-20 16:46:14 +00:00
}
if ( nextFont ! = lastFont ) {
pendingCount = bp - runStart ;
if ( 0 ! = pendingCount ) {
// Measure previous run of characters using the previous font
2000-04-21 21:38:08 +00:00
//aRenderingContext.SetColor(aTextStyle.mColor->mColor); commenting out redundat(and destructive) call to setcolor
2001-10-30 22:58:00 +00:00
aRenderingContext . DrawString ( runStart , pendingCount ,
aX , aY + mAscent , - 1 ,
1998-10-26 17:27:53 +00:00
spacing ? sp0 : nsnull ) ;
1998-10-28 02:03:40 +00:00
// Note: use aY not small-y so that decorations are drawn with
// respect to the normal-font not the current font.
1998-10-26 17:27:53 +00:00
PaintTextDecorations ( aRenderingContext , aStyleContext , aTextStyle ,
1999-07-15 18:19:03 +00:00
aX , aY , width , runStart , aDetails , countSoFar , pendingCount , spacing ? sp0 : nsnull ) ;
countSoFar + = pendingCount ;
1998-10-27 16:52:34 +00:00
aWidth - = width ;
1998-10-26 17:27:53 +00:00
aX + = width ;
runStart = bp = bp0 ;
sp = sp0 ;
width = 0 ;
1998-10-20 16:46:14 +00:00
}
aRenderingContext . SetFont ( nextFont ) ;
lastFont = nextFont ;
}
* bp + + = ch ;
2002-04-07 17:37:30 +00:00
if ( spacing )
* sp + + = glyphWidth ;
1998-10-26 17:27:53 +00:00
width + = glyphWidth ;
1998-10-20 16:46:14 +00:00
}
pendingCount = bp - runStart ;
if ( 0 ! = pendingCount ) {
// Measure previous run of characters using the previous font
2001-10-30 22:58:00 +00:00
aRenderingContext . DrawString ( runStart , pendingCount , aX , aY + mAscent , - 1 ,
1998-10-26 17:27:53 +00:00
spacing ? sp0 : nsnull ) ;
1998-10-28 02:03:40 +00:00
// Note: use aY not small-y so that decorations are drawn with
// respect to the normal-font not the current font.
1998-10-26 17:27:53 +00:00
PaintTextDecorations ( aRenderingContext , aStyleContext , aTextStyle ,
1999-07-15 18:19:03 +00:00
aX , aY , aWidth , runStart , aDetails , countSoFar , pendingCount ,
spacing ? sp0 : nsnull ) ;
1998-10-20 16:46:14 +00:00
}
1998-10-26 17:27:53 +00:00
aTextStyle . mLastFont = lastFont ;
1998-10-20 16:46:14 +00:00
if ( bp0 ! = buf ) {
delete [ ] bp0 ;
}
1998-10-26 17:27:53 +00:00
if ( sp0 ! = spacingMem ) {
delete [ ] sp0 ;
}
1998-10-20 16:46:14 +00:00
}
1998-10-26 17:27:53 +00:00
inline void
1999-04-20 00:23:33 +00:00
nsTextFrame : : MeasureSmallCapsText ( const nsHTMLReflowState & aReflowState ,
TextStyle & aTextStyle ,
PRUnichar * aWord ,
PRInt32 aWordLength ,
2001-09-27 18:34:30 +00:00
nsTextDimensions * aDimensionsResult )
1998-10-20 16:46:14 +00:00
{
nsIRenderingContext & rc = * aReflowState . rendContext ;
2001-09-27 18:34:30 +00:00
aDimensionsResult - > Clear ( ) ;
GetTextDimensions ( rc , aTextStyle , aWord , aWordLength , aDimensionsResult ) ;
1998-10-26 17:27:53 +00:00
if ( aTextStyle . mLastFont ! = aTextStyle . mNormalFont ) {
rc . SetFont ( aTextStyle . mNormalFont ) ;
aTextStyle . mLastFont = aTextStyle . mNormalFont ;
1998-10-20 16:46:14 +00:00
}
}
2000-03-31 07:26:07 +00:00
PRInt32
2001-09-27 18:34:30 +00:00
nsTextFrame : : GetTextDimensionsOrLength ( nsIRenderingContext & aRenderingContext ,
2000-03-31 07:26:07 +00:00
TextStyle & aStyle ,
PRUnichar * aBuffer , PRInt32 aLength ,
2001-09-27 18:34:30 +00:00
nsTextDimensions * aDimensionsResult ,
PRBool aGetTextDimensions /* true=get dimensions false = return length up to aDimensionsResult.width size*/ )
1998-10-20 16:46:14 +00:00
{
2000-02-14 01:54:20 +00:00
PRUnichar * inBuffer = aBuffer ;
PRInt32 length = aLength ;
2001-09-27 18:34:30 +00:00
nsAutoTextBuffer dimensionsBuffer ;
if ( NS_FAILED ( dimensionsBuffer . GrowTo ( length ) ) ) {
aDimensionsResult - > Clear ( ) ;
2000-03-31 07:26:07 +00:00
return 0 ;
1998-10-20 16:46:14 +00:00
}
2001-09-27 18:34:30 +00:00
PRUnichar * bp = dimensionsBuffer . mBuffer ;
1998-10-20 16:46:14 +00:00
2000-03-31 07:26:07 +00:00
nsIFontMetrics * lastFont = aStyle . mLastFont ;
2001-09-27 18:34:30 +00:00
nsTextDimensions sum , glyphDimensions ;
2000-02-14 01:54:20 +00:00
while ( - - length > = 0 ) {
PRUnichar ch = * inBuffer + + ;
2001-10-26 17:18:35 +00:00
if ( aStyle . mSmallCaps & &
( IsLowerCase ( ch ) | | ( ch = = kSZLIG ) ) ) {
2001-03-22 01:27:13 +00:00
PRUnichar upper_ch ;
// German szlig should be expanded to "SS".
if ( ch = = kSZLIG )
upper_ch = ( PRUnichar ) ' S ' ;
else
2001-10-26 17:18:35 +00:00
upper_ch = ToUpperCase ( ch ) ;
2000-03-31 07:26:07 +00:00
if ( lastFont ! = aStyle . mSmallFont ) {
lastFont = aStyle . mSmallFont ;
1999-03-18 21:02:40 +00:00
aRenderingContext . SetFont ( lastFont ) ;
1999-03-12 21:38:16 +00:00
}
2001-09-27 18:34:30 +00:00
aRenderingContext . GetTextDimensions ( & upper_ch , ( PRUint32 ) 1 , glyphDimensions ) ;
glyphDimensions . width + = aStyle . mLetterSpacing ;
2001-03-22 01:27:13 +00:00
if ( ch = = kSZLIG )
2001-09-27 18:34:30 +00:00
glyphDimensions . width + = glyphDimensions . width ;
1998-10-20 16:46:14 +00:00
}
1999-03-12 21:38:16 +00:00
else if ( ch = = ' ' ) {
2001-09-28 22:39:10 +00:00
glyphDimensions . width = aStyle . mSpaceWidth + aStyle . mLetterSpacing
2001-09-27 18:34:30 +00:00
+ aStyle . mWordSpacing + aStyle . mExtraSpacePerSpace ;
2000-04-17 14:40:46 +00:00
if ( ( PRUint32 ) - - aStyle . mNumSpacesToMeasure
< ( PRUint32 ) aStyle . mNumSpacesReceivingExtraJot ) {
2001-09-27 18:34:30 +00:00
+ + glyphDimensions . width ;
1999-03-12 21:38:16 +00:00
}
1998-10-20 16:46:14 +00:00
}
1999-03-12 21:38:16 +00:00
else {
2000-03-31 07:26:07 +00:00
if ( lastFont ! = aStyle . mNormalFont ) {
lastFont = aStyle . mNormalFont ;
1999-03-18 21:02:40 +00:00
aRenderingContext . SetFont ( lastFont ) ;
1998-10-20 16:46:14 +00:00
}
2001-09-27 18:34:30 +00:00
aRenderingContext . GetTextDimensions ( & ch , ( PRUint32 ) 1 , glyphDimensions ) ;
glyphDimensions . width + = aStyle . mLetterSpacing ;
1998-10-20 16:46:14 +00:00
}
2001-09-27 18:34:30 +00:00
sum . Combine ( glyphDimensions ) ;
1998-10-20 16:46:14 +00:00
* bp + + = ch ;
2001-09-27 18:34:30 +00:00
if ( ! aGetTextDimensions & & sum . width > = aDimensionsResult - > width ) {
2000-03-31 07:26:07 +00:00
PRInt32 result = aLength - length ;
2001-09-27 18:34:30 +00:00
if ( 2 * ( sum . width - aDimensionsResult - > width ) > glyphDimensions . width ) //then we have gone too far, back up 1
2000-03-31 07:26:07 +00:00
result - - ;
aStyle . mLastFont = lastFont ;
return result ;
}
1998-10-20 16:46:14 +00:00
}
2000-03-31 07:26:07 +00:00
aStyle . mLastFont = lastFont ;
2001-09-27 18:34:30 +00:00
* aDimensionsResult = sum ;
2000-03-31 07:26:07 +00:00
return aLength ;
}
// XXX factor in logic from RenderString into here; gaps, justification, etc.
void
2001-09-27 18:34:30 +00:00
nsTextFrame : : GetTextDimensions ( nsIRenderingContext & aRenderingContext ,
2000-03-31 07:26:07 +00:00
TextStyle & aTextStyle ,
PRUnichar * aBuffer , PRInt32 aLength ,
2001-09-27 18:34:30 +00:00
nsTextDimensions * aDimensionsResult )
2000-03-31 07:26:07 +00:00
{
2001-09-27 18:34:30 +00:00
GetTextDimensionsOrLength ( aRenderingContext , aTextStyle , aBuffer , aLength , aDimensionsResult , PR_TRUE ) ;
2000-03-31 07:26:07 +00:00
}
PRInt32
nsTextFrame : : GetLengthSlowly ( nsIRenderingContext & aRenderingContext ,
TextStyle & aStyle ,
PRUnichar * aBuffer , PRInt32 aLength ,
nscoord aWidth )
{
2001-09-27 18:34:30 +00:00
nsTextDimensions dimensions ;
dimensions . width = aWidth ;
return GetTextDimensionsOrLength ( aRenderingContext , aStyle , aBuffer , aLength , & dimensions , PR_FALSE ) ;
1998-10-20 16:46:14 +00:00
}
2000-04-17 14:40:46 +00:00
void
nsTextFrame : : ComputeExtraJustificationSpacing ( nsIRenderingContext & aRenderingContext ,
TextStyle & aTextStyle ,
PRUnichar * aBuffer , PRInt32 aLength ,
PRInt32 aNumSpaces )
{
if ( aTextStyle . mJustifying ) {
2001-09-27 18:34:30 +00:00
nsTextDimensions trueDimensions ;
2000-04-17 14:40:46 +00:00
// OK, so this is a bit ugly. The problem is that to get the right margin
// nice and clean, we have to apply a little extra space to *some* of the
// spaces. It has to be the same ones every time or things will go haywire.
2001-09-27 18:34:30 +00:00
// This implies that the GetTextDimensionsOrLength and RenderString functions depend
2000-04-17 14:40:46 +00:00
// on a little bit of secret state: which part of the prepared text they are
// looking at. It turns out that they get called in a regular way: they look
// at the text from the beginning to the end. So we just count which spaces
// we're up to, for each context.
// This is not a great solution, but a perfect solution requires much more
// widespread changes, to explicitly annotate all the transformed text fragments
// that are passed around with their position in the transformed text
// for the entire frame.
aTextStyle . mNumSpacesToMeasure = 0 ;
aTextStyle . mExtraSpacePerSpace = 0 ;
aTextStyle . mNumSpacesReceivingExtraJot = 0 ;
2001-09-27 18:34:30 +00:00
GetTextDimensions ( aRenderingContext , aTextStyle , aBuffer , aLength , & trueDimensions ) ;
2000-04-17 14:40:46 +00:00
aTextStyle . mNumSpacesToMeasure = aNumSpaces ;
aTextStyle . mNumSpacesToRender = aNumSpaces ;
2001-09-27 18:34:30 +00:00
nscoord extraSpace = mRect . width - trueDimensions . width ;
2000-04-17 14:40:46 +00:00
if ( extraSpace > 0 & & aNumSpaces > 0 ) {
aTextStyle . mExtraSpacePerSpace = extraSpace / aNumSpaces ;
aTextStyle . mNumSpacesReceivingExtraJot =
extraSpace - aTextStyle . mExtraSpacePerSpace * aNumSpaces ;
}
}
}
2000-03-31 07:26:07 +00:00
1998-10-20 16:46:14 +00:00
void
1999-04-20 00:23:33 +00:00
nsTextFrame : : PaintTextSlowly ( nsIPresContext * aPresContext ,
nsIRenderingContext & aRenderingContext ,
nsIStyleContext * aStyleContext ,
TextStyle & aTextStyle ,
nscoord dx , nscoord dy )
1998-10-20 16:46:14 +00:00
{
2000-04-28 06:21:31 +00:00
nsCOMPtr < nsISelectionController > selCon ;
2001-01-27 14:09:34 +00:00
nsCOMPtr < nsIPresShell > shell ;
PRBool displaySelection ;
2002-02-19 07:30:58 +00:00
PRBool isPaginated , canDarkenColor = PR_FALSE ;
2001-01-27 14:09:34 +00:00
PRBool isSelected ;
2000-05-11 04:25:43 +00:00
PRInt16 selectionValue ;
2001-01-27 14:09:34 +00:00
nsCOMPtr < nsILineBreaker > lb ;
if ( NS_FAILED ( GetTextInfoForPainting ( aPresContext ,
aRenderingContext ,
getter_AddRefs ( shell ) ,
getter_AddRefs ( selCon ) ,
displaySelection ,
isPaginated ,
isSelected ,
selectionValue ,
getter_AddRefs ( lb ) ) ) ) {
return ;
}
1999-04-20 00:23:33 +00:00
1998-10-20 16:46:14 +00:00
2002-02-15 14:48:12 +00:00
if ( isPaginated ) {
canDarkenColor = CanDarken ( aPresContext ) ;
}
1998-10-20 16:46:14 +00:00
// Make enough space to transform
1999-09-22 00:40:56 +00:00
nsAutoTextBuffer paintBuffer ;
nsAutoIndexBuffer indexBuffer ;
if ( NS_FAILED ( indexBuffer . GrowTo ( mContentLength + 1 ) ) ) {
return ;
1998-10-20 16:46:14 +00:00
}
nscoord width = mRect . width ;
PRInt32 textLength ;
2000-09-20 23:00:32 +00:00
nsTextTransformer tx ( lb , nsnull , aPresContext ) ;
2000-04-17 14:40:46 +00:00
PRInt32 numSpaces ;
2002-06-11 21:00:20 +00:00
# ifdef IBMBIDI
// Simulate a non-Bidi system for char by char painting
PRBool isBidiSystem = PR_FALSE ;
aPresContext - > GetIsBidiSystem ( isBidiSystem ) ;
aPresContext - > SetIsBidiSystem ( PR_FALSE ) ;
# endif
2000-04-17 14:40:46 +00:00
numSpaces = PrepareUnicodeText ( tx , ( displaySelection ? & indexBuffer : nsnull ) ,
& paintBuffer , & textLength ) ;
2002-06-11 21:00:20 +00:00
# ifdef IBMBIDI
aPresContext - > SetIsBidiSystem ( isBidiSystem ) ;
# endif
1998-10-20 16:46:14 +00:00
1999-09-22 00:40:56 +00:00
PRInt32 * ip = indexBuffer . mBuffer ;
PRUnichar * text = paintBuffer . mBuffer ;
2001-01-27 14:09:34 +00:00
1998-10-20 16:46:14 +00:00
if ( 0 ! = textLength ) {
2001-04-11 23:32:21 +00:00
# ifdef IBMBIDI
PRBool bidiEnabled ;
2001-10-24 11:12:31 +00:00
PRUint8 level = 0 ;
nsCharType charType = eCharType_LeftToRight ;
2001-05-16 13:40:08 +00:00
aPresContext - > GetBidiEnabled ( & bidiEnabled ) ;
2001-04-11 23:32:21 +00:00
if ( bidiEnabled ) {
nsBidiPresUtils * bidiUtils ;
aPresContext - > GetBidiUtils ( & bidiUtils ) ;
if ( bidiUtils ) {
2001-10-01 03:43:42 +00:00
GetBidiProperty ( aPresContext , nsLayoutAtoms : : embeddingLevel ,
( void * * ) & level , sizeof ( level ) ) ;
GetBidiProperty ( aPresContext , nsLayoutAtoms : : charType ,
( void * * ) & charType , sizeof ( charType ) ) ;
2002-06-11 21:00:20 +00:00
PRInt32 rememberTextLength = textLength ;
2001-04-11 23:32:21 +00:00
// Since we paint char by char, handle the text like on non-bidi platform
2002-06-11 21:00:20 +00:00
bidiUtils - > ReorderUnicodeText ( text , textLength , charType ,
level & 1 , PR_FALSE ) ;
NS_ASSERTION ( rememberTextLength = = textLength , " Bidi formatting changed text length " ) ;
2001-04-11 23:32:21 +00:00
}
}
# endif // IBMBIDI
2000-04-17 14:40:46 +00:00
ComputeExtraJustificationSpacing ( aRenderingContext , aTextStyle , text , textLength , numSpaces ) ;
1999-04-26 04:02:04 +00:00
if ( ! displaySelection | | ! isSelected ) {
1998-10-20 16:46:14 +00:00
// When there is no selection showing, use the fastest and
// simplest rendering approach
2002-02-15 14:48:12 +00:00
aRenderingContext . SetColor ( nsCSSRendering : : TransformColor ( aTextStyle . mColor - > mColor , canDarkenColor ) ) ;
1998-10-26 17:27:53 +00:00
RenderString ( aRenderingContext , aStyleContext , aTextStyle ,
text , textLength , dx , dy , width ) ;
1998-10-20 16:46:14 +00:00
}
2000-05-13 20:47:42 +00:00
else
{
1999-07-15 18:19:03 +00:00
SelectionDetails * details = nsnull ;
1999-04-26 04:02:04 +00:00
nsCOMPtr < nsIFrameSelection > frameSelection ;
2000-05-13 20:47:42 +00:00
//get the frame selection
2001-01-27 14:09:34 +00:00
nsresult rv = NS_OK ;
2000-05-13 20:47:42 +00:00
frameSelection = do_QueryInterface ( selCon ) ; //this MAY implement
if ( ! frameSelection ) //if that failed get it from the presshell
rv = shell - > GetFrameSelection ( getter_AddRefs ( frameSelection ) ) ;
if ( NS_SUCCEEDED ( rv ) & & frameSelection )
{
nsCOMPtr < nsIContent > content ;
PRInt32 offset ;
PRInt32 length ;
rv = GetContentAndOffsetsForSelection ( aPresContext , getter_AddRefs ( content ) , & offset , & length ) ;
if ( NS_SUCCEEDED ( rv ) )
2000-05-08 03:59:53 +00:00
{
2000-05-13 20:47:42 +00:00
rv = frameSelection - > LookUpSelection ( content , mContentOffset ,
mContentLength , & details , PR_FALSE ) ;
1999-04-26 04:02:04 +00:00
}
}
1999-02-13 04:46:47 +00:00
1999-07-15 18:19:03 +00:00
//where are the selection points "really"
SelectionDetails * sdptr = details ;
while ( sdptr ) {
sdptr - > mStart = ip [ sdptr - > mStart ] - mContentOffset ;
sdptr - > mEnd = ip [ sdptr - > mEnd ] - mContentOffset ;
2001-10-24 11:12:31 +00:00
# ifdef IBMBIDI
AdjustSelectionPointsForBidi ( sdptr , textLength , CHARTYPE_IS_RTL ( charType ) , level & 1 , PR_FALSE ) ;
2001-04-11 23:32:21 +00:00
# endif
1999-07-15 18:19:03 +00:00
sdptr = sdptr - > mNext ;
}
2000-04-10 21:02:25 +00:00
2000-05-11 04:25:43 +00:00
DrawSelectionIterator iter ( details , text , ( PRUint32 ) textLength , aTextStyle , selectionValue ) ;
2000-04-10 21:02:25 +00:00
if ( ! iter . IsDone ( ) & & iter . First ( ) )
2000-03-31 07:26:07 +00:00
{
2000-04-10 21:02:25 +00:00
nscoord currentX = dx ;
2001-09-27 18:34:30 +00:00
nsTextDimensions newDimensions ; //temp
2000-04-10 21:02:25 +00:00
while ( ! iter . IsDone ( ) )
{
PRUnichar * currenttext = iter . CurrentTextUnicharPtr ( ) ;
PRUint32 currentlength = iter . CurrentLength ( ) ;
2000-05-16 22:48:28 +00:00
//TextStyle ¤tStyle = iter.CurrentStyle();
2000-04-10 21:02:25 +00:00
nscolor currentFGColor = iter . CurrentForeGroundColor ( ) ;
nscolor currentBKColor ;
2001-09-27 18:34:30 +00:00
GetTextDimensions ( aRenderingContext , aTextStyle , currenttext , ( PRInt32 ) currentlength , & newDimensions ) ;
if ( newDimensions . width )
2000-04-10 21:02:25 +00:00
{
if ( iter . CurrentBackGroundColor ( currentBKColor ) )
{ //DRAW RECT HERE!!!
aRenderingContext . SetColor ( currentBKColor ) ;
2001-09-27 18:34:30 +00:00
aRenderingContext . FillRect ( currentX , dy , newDimensions . width , mRect . height ) ;
2000-04-10 21:02:25 +00:00
currentFGColor = EnsureDifferentColors ( currentFGColor , currentBKColor ) ;
}
}
2001-09-27 18:34:30 +00:00
2001-01-27 14:09:34 +00:00
if ( isPaginated & & ! iter . IsBeforeOrAfter ( ) ) {
2002-02-15 14:48:12 +00:00
aRenderingContext . SetColor ( nsCSSRendering : : TransformColor ( aTextStyle . mColor - > mColor , canDarkenColor ) ) ;
2001-01-27 14:09:34 +00:00
RenderString ( aRenderingContext , aStyleContext , aTextStyle , currenttext ,
currentlength , currentX , dy , width , details ) ;
} else if ( ! isPaginated ) {
2002-02-15 14:48:12 +00:00
aRenderingContext . SetColor ( nsCSSRendering : : TransformColor ( currentFGColor , canDarkenColor ) ) ;
2001-01-27 14:09:34 +00:00
RenderString ( aRenderingContext , aStyleContext , aTextStyle , currenttext ,
currentlength , currentX , dy , width , details ) ;
}
//increment twips X start but remember to get ready for next draw by reducing current x by letter spacing amount
2001-09-27 18:34:30 +00:00
currentX + = newDimensions . width ; // + aTextStyle.mLetterSpacing;
2000-04-10 21:02:25 +00:00
iter . Next ( ) ;
}
2000-03-31 07:26:07 +00:00
}
2001-01-27 14:09:34 +00:00
else if ( ! isPaginated )
2000-03-31 07:26:07 +00:00
{
2002-02-15 14:48:12 +00:00
aRenderingContext . SetColor ( nsCSSRendering : : TransformColor ( aTextStyle . mColor - > mColor , canDarkenColor ) ) ;
2000-03-31 07:26:07 +00:00
RenderString ( aRenderingContext , aStyleContext , aTextStyle , text ,
1999-07-15 18:19:03 +00:00
PRUint32 ( textLength ) , dx , dy , width , details ) ;
2000-03-31 07:26:07 +00:00
}
1999-07-15 18:19:03 +00:00
sdptr = details ;
if ( details ) {
1999-08-09 19:15:04 +00:00
while ( ( sdptr = details - > mNext ) ! = nsnull ) {
1999-07-15 18:19:03 +00:00
delete details ;
details = sdptr ;
1998-10-20 16:46:14 +00:00
}
1999-07-15 18:19:03 +00:00
delete details ;
1998-10-20 16:46:14 +00:00
}
}
}
}
1998-09-08 22:34:40 +00:00
void
1999-04-20 00:23:33 +00:00
nsTextFrame : : PaintAsciiText ( nsIPresContext * aPresContext ,
nsIRenderingContext & aRenderingContext ,
nsIStyleContext * aStyleContext ,
TextStyle & aTextStyle ,
nscoord dx , nscoord dy )
1998-09-08 22:34:40 +00:00
{
2000-04-12 14:54:43 +00:00
NS_PRECONDITION ( 0 = = ( TEXT_HAS_MULTIBYTE & mState ) , " text is multi-byte " ) ;
1999-04-20 00:23:33 +00:00
2001-01-27 14:09:34 +00:00
nsCOMPtr < nsISelectionController > selCon ;
nsCOMPtr < nsIPresShell > shell ;
2002-02-19 07:30:58 +00:00
PRBool displaySelection , canDarkenColor = PR_FALSE ;
2001-01-27 14:09:34 +00:00
PRBool isPaginated ;
PRBool isSelected ;
2000-05-11 04:25:43 +00:00
PRInt16 selectionValue ;
2001-01-27 14:09:34 +00:00
nsCOMPtr < nsILineBreaker > lb ;
if ( NS_FAILED ( GetTextInfoForPainting ( aPresContext ,
aRenderingContext ,
getter_AddRefs ( shell ) ,
getter_AddRefs ( selCon ) ,
displaySelection ,
isPaginated ,
isSelected ,
selectionValue ,
getter_AddRefs ( lb ) ) ) ) {
return ;
}
1998-09-08 22:34:40 +00:00
2002-02-15 14:48:12 +00:00
if ( isPaginated ) {
canDarkenColor = CanDarken ( aPresContext ) ;
}
2000-04-12 14:54:43 +00:00
// Get the text fragment
nsCOMPtr < nsITextContent > tc = do_QueryInterface ( mContent ) ;
const nsTextFragment * frag = nsnull ;
if ( tc . get ( ) ) {
tc - > GetText ( & frag ) ;
}
if ( ! frag ) {
return ;
}
1998-10-20 00:21:18 +00:00
// Make enough space to transform
1999-09-22 00:40:56 +00:00
nsAutoTextBuffer unicodePaintBuffer ;
nsAutoIndexBuffer indexBuffer ;
if ( displaySelection ) {
if ( NS_FAILED ( indexBuffer . GrowTo ( mContentLength + 1 ) ) ) {
return ;
}
1998-09-08 22:34:40 +00:00
}
1998-10-20 00:21:18 +00:00
2000-09-20 23:00:32 +00:00
nsTextTransformer tx ( lb , nsnull , aPresContext ) ;
2000-04-12 14:54:43 +00:00
// See if we need to transform the text. If the text fragment is ascii and
// wasn't transformed, then we can skip this step. If we're displaying the
// selection and the text is selected, then we need to do this step so we
// can create the index buffer
2001-05-24 18:40:45 +00:00
PRInt32 textLength = 0 ;
2000-04-12 14:54:43 +00:00
const char * text ;
char paintBufMem [ TEXT_BUF_SIZE ] ;
char * paintBuf = paintBufMem ;
if ( frag - > Is2b ( ) | |
( 0 ! = ( mState & TEXT_WAS_TRANSFORMED ) ) | |
( displaySelection & & isSelected ) ) {
// Transform text from content into Unicode renderable form
// XXX If the text fragment is ascii, then we should ask the
// text transformer to leave the text in ascii. That way we can
// elimninate the conversion from Unicode back to ascii...
PrepareUnicodeText ( tx , ( displaySelection ? & indexBuffer : nsnull ) ,
& unicodePaintBuffer , & textLength ) ;
// Translate unicode data into ascii for rendering
if ( textLength > TEXT_BUF_SIZE ) {
paintBuf = new char [ textLength ] ;
if ( ! paintBuf ) {
return ;
}
1999-09-22 00:40:56 +00:00
}
2000-04-12 14:54:43 +00:00
char * dst = paintBuf ;
char * end = dst + textLength ;
PRUnichar * src = unicodePaintBuffer . mBuffer ;
while ( dst < end ) {
* dst + + = ( char ) ( ( unsigned char ) * src + + ) ;
}
text = paintBuf ;
2001-05-24 18:40:45 +00:00
}
else if ( mContentOffset + mContentLength < = frag - > GetLength ( ) ) {
2000-04-12 14:54:43 +00:00
text = frag - > Get1b ( ) + mContentOffset ;
textLength = mContentLength ;
// See if we should skip leading whitespace
if ( 0 ! = ( mState & TEXT_SKIP_LEADING_WS ) ) {
2000-04-13 20:55:40 +00:00
while ( ( textLength > 0 ) & & XP_IS_SPACE ( * text ) ) {
2000-04-12 14:54:43 +00:00
text + + ;
textLength - - ;
}
}
// See if the text ends in a newline
if ( ( textLength > 0 ) & & ( text [ textLength - 1 ] = = ' \n ' ) ) {
textLength - - ;
}
NS_ASSERTION ( textLength > = 0 , " bad text length " ) ;
1998-10-21 20:03:54 +00:00
}
2001-05-24 18:40:45 +00:00
else {
// This might happen if a paint event beats the reflow; e.g., as
// is the case in bug 73291. Not a big deal, because the reflow
// will schedule another invalidate.
NS_WARNING ( " content length exceeds fragment length " ) ;
}
1998-10-20 00:21:18 +00:00
1999-09-22 00:40:56 +00:00
nscoord width = mRect . width ;
PRInt32 * ip = indexBuffer . mBuffer ;
1999-04-26 04:02:04 +00:00
1998-09-08 22:34:40 +00:00
if ( 0 ! = textLength ) {
1999-04-26 04:02:04 +00:00
if ( ! displaySelection | | ! isSelected ) {
1999-01-25 23:29:53 +00:00
//if selection is > content length then selection has "slid off"
1998-09-08 22:34:40 +00:00
// When there is no selection showing, use the fastest and
// simplest rendering approach
2002-02-15 14:48:12 +00:00
aRenderingContext . SetColor ( nsCSSRendering : : TransformColor ( aTextStyle . mColor - > mColor , canDarkenColor ) ) ;
2001-10-30 22:58:00 +00:00
aRenderingContext . DrawString ( text , PRUint32 ( textLength ) , dx , dy + mAscent ) ;
1998-10-26 17:27:53 +00:00
PaintTextDecorations ( aRenderingContext , aStyleContext , aTextStyle ,
dx , dy , width ) ;
1998-09-08 22:34:40 +00:00
}
else {
1999-07-15 18:19:03 +00:00
SelectionDetails * details ;
1999-04-26 04:02:04 +00:00
nsCOMPtr < nsIFrameSelection > frameSelection ;
2000-05-13 20:47:42 +00:00
//get the frame selection
frameSelection = do_QueryInterface ( selCon ) ; //this MAY implement
2001-01-27 14:09:34 +00:00
nsresult rv = NS_OK ;
2000-05-13 20:47:42 +00:00
if ( ! frameSelection ) //if that failed get it from the presshell
rv = shell - > GetFrameSelection ( getter_AddRefs ( frameSelection ) ) ;
if ( NS_SUCCEEDED ( rv ) & & frameSelection ) {
nsCOMPtr < nsIContent > content ;
PRInt32 offset ;
PRInt32 length ;
rv = GetContentAndOffsetsForSelection ( aPresContext , getter_AddRefs ( content ) , & offset , & length ) ;
if ( NS_SUCCEEDED ( rv ) ) {
rv = frameSelection - > LookUpSelection ( content , mContentOffset ,
mContentLength , & details , PR_FALSE ) ;
1999-04-26 04:02:04 +00:00
}
1998-09-08 22:34:40 +00:00
}
1999-04-26 04:02:04 +00:00
1999-07-15 18:19:03 +00:00
//where are the selection points "really"
SelectionDetails * sdptr = details ;
while ( sdptr ) {
sdptr - > mStart = ip [ sdptr - > mStart ] - mContentOffset ;
sdptr - > mEnd = ip [ sdptr - > mEnd ] - mContentOffset ;
sdptr = sdptr - > mNext ;
}
2000-05-11 04:25:43 +00:00
DrawSelectionIterator iter ( details , ( PRUnichar * ) text , ( PRUint32 ) textLength , aTextStyle , selectionValue ) ; //ITS OK TO CAST HERE THE RESULT WE USE WILLNOT DO BAD CONVERSION
2000-04-10 21:02:25 +00:00
if ( ! iter . IsDone ( ) & & iter . First ( ) )
2000-03-31 07:26:07 +00:00
{
2000-04-10 21:02:25 +00:00
nscoord currentX = dx ;
nscoord newWidth ; //temp
while ( ! iter . IsDone ( ) )
2000-03-31 07:26:07 +00:00
{
2000-04-10 21:02:25 +00:00
char * currenttext = iter . CurrentTextCStrPtr ( ) ;
PRUint32 currentlength = iter . CurrentLength ( ) ;
2000-05-16 22:48:28 +00:00
//TextStyle ¤tStyle = iter.CurrentStyle();
2000-04-10 21:02:25 +00:00
nscolor currentFGColor = iter . CurrentForeGroundColor ( ) ;
nscolor currentBKColor ;
2000-03-31 07:26:07 +00:00
2000-04-10 21:02:25 +00:00
if ( NS_SUCCEEDED ( aRenderingContext . GetWidth ( currenttext , currentlength , newWidth ) ) ) //ADJUST FOR CHAR SPACING
{
2001-01-27 14:09:34 +00:00
if ( iter . CurrentBackGroundColor ( currentBKColor ) & & ! isPaginated )
2000-04-10 21:02:25 +00:00
{ //DRAW RECT HERE!!!
aRenderingContext . SetColor ( currentBKColor ) ;
aRenderingContext . FillRect ( currentX , dy , newWidth , mRect . height ) ;
currentFGColor = EnsureDifferentColors ( currentFGColor , currentBKColor ) ;
2000-03-31 07:26:07 +00:00
}
2000-04-10 21:02:25 +00:00
}
else
newWidth = 0 ;
2001-01-27 14:09:34 +00:00
if ( isPaginated & & ! iter . IsBeforeOrAfter ( ) ) {
2002-02-15 14:48:12 +00:00
aRenderingContext . SetColor ( nsCSSRendering : : TransformColor ( aTextStyle . mColor - > mColor , canDarkenColor ) ) ;
2001-10-30 22:58:00 +00:00
aRenderingContext . DrawString ( currenttext , currentlength , currentX , dy + mAscent ) ;
2001-01-27 14:09:34 +00:00
} else if ( ! isPaginated ) {
2001-05-10 14:19:58 +00:00
aRenderingContext . SetColor ( nsCSSRendering : : TransformColor ( currentFGColor , isPaginated ) ) ;
2001-10-30 22:58:00 +00:00
aRenderingContext . DrawString ( currenttext , currentlength , currentX , dy + mAscent ) ;
2001-01-27 14:09:34 +00:00
}
2000-03-31 07:26:07 +00:00
2000-04-10 21:02:25 +00:00
currentX + = newWidth ; //increment twips X start
2000-04-12 15:42:55 +00:00
2000-04-10 21:02:25 +00:00
iter . Next ( ) ;
2000-03-31 07:26:07 +00:00
}
}
2001-01-27 14:09:34 +00:00
else if ( ! isPaginated )
2000-03-31 07:26:07 +00:00
{
2002-02-15 14:48:12 +00:00
aRenderingContext . SetColor ( nsCSSRendering : : TransformColor ( aTextStyle . mColor - > mColor , canDarkenColor ) ) ;
2001-10-30 22:58:00 +00:00
aRenderingContext . DrawString ( text , PRUint32 ( textLength ) , dx , dy + mAscent ) ;
2000-03-31 07:26:07 +00:00
}
1999-07-15 18:19:03 +00:00
PaintTextDecorations ( aRenderingContext , aStyleContext ,
1999-09-22 00:40:56 +00:00
aTextStyle , dx , dy , width ,
unicodePaintBuffer . mBuffer ,
details , 0 , textLength ) ;
1999-07-15 18:19:03 +00:00
sdptr = details ;
if ( details ) {
1999-08-09 19:15:04 +00:00
while ( ( sdptr = details - > mNext ) ! = nsnull ) {
1999-07-15 18:19:03 +00:00
delete details ;
details = sdptr ;
1998-09-08 22:34:40 +00:00
}
1999-07-15 18:19:03 +00:00
delete details ;
1998-09-08 22:34:40 +00:00
}
}
}
// Cleanup
1998-10-20 00:21:18 +00:00
if ( paintBuf ! = paintBufMem ) {
delete [ ] paintBuf ;
1998-09-08 22:34:40 +00:00
}
}
1998-09-10 19:18:01 +00:00
//---------------------------------------------------
2002-04-26 11:30:33 +00:00
// Also defined for external use in nsTextFrame.h
//
1998-09-10 19:18:01 +00:00
// Uses a binary search for find where the cursor falls in the line of text
// It also keeps track of the part of the string that has already been measured
// so it doesn't have to keep measuring the same text over and over
//
// Param "aBaseWidth" contains the width in twips of the portion
// of the text that has already been measured, and aBaseInx contains
// the index of the text that has already been measured.
//
// aTextWidth returns the (in twips) the length of the text that falls before the cursor
// aIndex contains the index of the text where the cursor falls
2002-04-26 11:30:33 +00:00
PRBool
1998-10-02 01:12:39 +00:00
BinarySearchForPosition ( nsIRenderingContext * acx ,
2002-04-26 11:30:33 +00:00
const PRUnichar * aText ,
1998-09-10 19:18:01 +00:00
PRInt32 aBaseWidth ,
PRInt32 aBaseInx ,
PRInt32 aStartInx ,
PRInt32 aEndInx ,
PRInt32 aCursorPos ,
PRInt32 & aIndex ,
PRInt32 & aTextWidth )
{
PRInt32 range = aEndInx - aStartInx ;
if ( range = = 1 ) {
aIndex = aStartInx + aBaseInx ;
1998-12-14 18:34:14 +00:00
acx - > GetWidth ( aText , aIndex , aTextWidth ) ;
1998-09-10 19:18:01 +00:00
return PR_TRUE ;
}
PRInt32 inx = aStartInx + ( range / 2 ) ;
1999-04-26 04:02:04 +00:00
PRInt32 textWidth = 0 ;
1998-10-02 01:12:39 +00:00
acx - > GetWidth ( aText , inx , textWidth ) ;
1998-09-10 19:18:01 +00:00
PRInt32 fullWidth = aBaseWidth + textWidth ;
if ( fullWidth = = aCursorPos ) {
1999-09-15 01:57:50 +00:00
aTextWidth = textWidth ;
1998-09-10 19:18:01 +00:00
aIndex = inx ;
return PR_TRUE ;
} else if ( aCursorPos < fullWidth ) {
aTextWidth = aBaseWidth ;
1998-10-02 01:12:39 +00:00
if ( BinarySearchForPosition ( acx , aText , aBaseWidth , aBaseInx , aStartInx , inx , aCursorPos , aIndex , aTextWidth ) ) {
1998-09-10 19:18:01 +00:00
return PR_TRUE ;
}
} else {
aTextWidth = fullWidth ;
1998-12-14 18:34:14 +00:00
if ( BinarySearchForPosition ( acx , aText , aBaseWidth , aBaseInx , inx , aEndInx , aCursorPos , aIndex , aTextWidth ) ) {
1998-09-10 19:18:01 +00:00
return PR_TRUE ;
}
}
return PR_FALSE ;
}
1998-09-08 22:34:40 +00:00
1998-09-10 19:18:01 +00:00
//---------------------------------------------------------------------------
// Uses a binary search to find the position of the cursor in the text.
// The "indices array is used to map from the compressed text back to the
// un-compressed text, selection is based on the un-compressed text, the visual
// display of selection is based on the compressed text.
//---------------------------------------------------------------------------
1998-10-02 01:12:39 +00:00
NS_IMETHODIMP
1999-11-24 06:03:41 +00:00
nsTextFrame : : GetPosition ( nsIPresContext * aCX ,
1999-11-24 01:10:22 +00:00
const nsPoint & aPoint ,
1999-06-10 21:08:17 +00:00
nsIContent * * aNewContent ,
PRInt32 & aContentOffset ,
PRInt32 & aContentOffsetEnd )
1998-09-08 22:34:40 +00:00
{
2000-10-27 14:16:36 +00:00
// pre-condition tests
NS_PRECONDITION ( aCX & & aNewContent , " null arg " ) ;
if ( ! aCX | | ! aNewContent ) {
return NS_ERROR_NULL_POINTER ;
}
// initialize out param
* aNewContent = nsnull ;
1999-06-08 02:19:26 +00:00
nsCOMPtr < nsIPresShell > shell ;
1999-11-24 06:03:41 +00:00
nsresult rv = aCX - > GetShell ( getter_AddRefs ( shell ) ) ;
1999-06-08 02:19:26 +00:00
if ( NS_SUCCEEDED ( rv ) & & shell ) {
nsCOMPtr < nsIRenderingContext > acx ;
rv = shell - > CreateRenderingContext ( this , getter_AddRefs ( acx ) ) ;
if ( NS_SUCCEEDED ( rv ) ) {
1999-11-24 06:03:41 +00:00
TextStyle ts ( aCX , * acx , mStyleContext ) ;
2000-04-17 14:40:46 +00:00
if ( ts . mSmallCaps | | ts . mWordSpacing | | ts . mLetterSpacing | | ts . mJustifying ) {
1999-11-24 01:10:22 +00:00
nsresult result = GetPositionSlowly ( aCX , acx , aPoint , aNewContent ,
1999-06-10 21:08:17 +00:00
aContentOffset ) ;
aContentOffsetEnd = aContentOffset ;
1999-06-08 02:19:26 +00:00
return result ;
}
1999-04-20 00:23:33 +00:00
1999-09-22 00:40:56 +00:00
// Make enough space to transform
nsAutoTextBuffer paintBuffer ;
nsAutoIndexBuffer indexBuffer ;
rv = indexBuffer . GrowTo ( mContentLength + 1 ) ;
if ( NS_FAILED ( rv ) ) {
return rv ;
1999-06-08 02:19:26 +00:00
}
// Find the font metrics for this text
2002-05-24 20:11:14 +00:00
SetFontFromStyle ( acx , mStyleContext ) ;
1999-06-08 02:19:26 +00:00
// Get the renderable form of the text
1999-11-24 06:03:41 +00:00
nsCOMPtr < nsIDocument > doc ( getter_AddRefs ( GetDocument ( aCX ) ) ) ;
1999-06-08 02:19:26 +00:00
nsCOMPtr < nsILineBreaker > lb ;
doc - > GetLineBreaker ( getter_AddRefs ( lb ) ) ;
2000-09-20 23:00:32 +00:00
nsTextTransformer tx ( lb , nsnull , aCX ) ;
1999-09-22 00:40:56 +00:00
PRInt32 textLength ;
2000-04-17 14:40:46 +00:00
// no need to worry about justification, that's always on the slow path
1999-09-22 00:40:56 +00:00
PrepareUnicodeText ( tx , & indexBuffer , & paintBuffer , & textLength ) ;
if ( textLength < = 0 ) {
//invalid frame to get position on
1999-06-19 20:36:44 +00:00
return NS_ERROR_FAILURE ;
1999-06-08 02:19:26 +00:00
}
1998-09-08 22:34:40 +00:00
1999-06-08 02:19:26 +00:00
nsPoint origin ;
nsIView * view ;
1999-11-24 06:03:41 +00:00
GetOffsetFromView ( aCX , origin , & view ) ;
1999-11-24 01:10:22 +00:00
2000-04-17 14:40:46 +00:00
//IF STYLE SAYS TO SELECT TO END OF FRAME HERE...
2000-12-09 04:21:51 +00:00
nsCOMPtr < nsIPref > prefs ( do_GetService ( kPrefCID , & rv ) ) ;
1999-11-24 01:10:22 +00:00
PRInt32 prefInt = 0 ;
PRBool outofstylehandled = PR_FALSE ;
if ( NS_SUCCEEDED ( rv ) & & prefs )
{
if ( NS_SUCCEEDED ( prefs - > GetIntPref ( " browser.drag_out_of_frame_style " , & prefInt ) ) & & prefInt )
{
if ( ( aPoint . y - origin . y ) < 0 ) //above rectangle
{
aContentOffset = mContentOffset ;
aContentOffsetEnd = aContentOffset ;
outofstylehandled = PR_TRUE ;
}
else if ( ( aPoint . y - origin . y ) > mRect . height )
{
aContentOffset = mContentOffset + mContentLength ;
aContentOffsetEnd = aContentOffset ;
outofstylehandled = PR_TRUE ;
}
1999-06-08 02:19:26 +00:00
}
1998-09-10 19:18:01 +00:00
}
1998-09-08 22:34:40 +00:00
1999-11-24 01:10:22 +00:00
if ( ! outofstylehandled ) //then we need to track based on the X coord only
{
//END STYLE IF
PRInt32 * ip = indexBuffer . mBuffer ;
PRInt32 indx ;
PRInt32 textWidth = 0 ;
PRUnichar * text = paintBuffer . mBuffer ;
2001-04-11 23:32:21 +00:00
# ifdef IBMBIDI
PRBool getReversedPos = PR_FALSE ;
2001-10-24 11:12:31 +00:00
PRUint8 level = 0 ;
GetBidiProperty ( aCX , nsLayoutAtoms : : embeddingLevel , ( void * * ) & level , sizeof ( level ) ) ;
getReversedPos = level & 1 ;
2001-04-11 23:32:21 +00:00
nscoord posX = ( getReversedPos ) ?
( mRect . width + origin . x ) - ( aPoint . x - origin . x ) : aPoint . x ;
PRBool found = BinarySearchForPosition ( acx , text , origin . x , 0 , 0 ,
PRInt32 ( textLength ) ,
PRInt32 ( posX ) , //go to local coordinates
indx , textWidth ) ;
# else
1999-11-24 01:10:22 +00:00
PRBool found = BinarySearchForPosition ( acx , text , origin . x , 0 , 0 ,
PRInt32 ( textLength ) ,
PRInt32 ( aPoint . x ) , //go to local coordinates
indx , textWidth ) ;
2001-04-11 23:32:21 +00:00
# endif // IBMBIDI
1999-11-24 01:10:22 +00:00
if ( found ) {
PRInt32 charWidth ;
acx - > GetWidth ( text [ indx ] , charWidth ) ;
charWidth / = 2 ;
2001-04-11 23:32:21 +00:00
# ifdef IBMBIDI
if ( getReversedPos ) {
if ( mRect . width - aPoint . x + origin . x > textWidth + charWidth ) {
indx + + ;
}
}
else
# endif // IBMBIDI
2000-03-22 02:10:37 +00:00
if ( ( aPoint . x - origin . x ) > textWidth + charWidth ) {
1999-11-24 01:10:22 +00:00
indx + + ;
}
1999-06-08 02:19:26 +00:00
}
1999-11-24 01:10:22 +00:00
aContentOffset = indx + mContentOffset ;
//reusing wordBufMem
PRInt32 i ;
for ( i = 0 ; i < = mContentLength ; i + + ) {
2002-03-27 03:28:34 +00:00
if ( ( ip [ i ] > = aContentOffset ) & & //reverse mapping
( ! IS_LOW_SURROGATE ( paintBuffer . mBuffer [ ip [ i ] - mContentOffset ] ) ) ) {
1999-11-24 01:10:22 +00:00
aContentOffset = i + mContentOffset ;
break ;
}
}
2001-04-11 23:32:21 +00:00
# ifdef IBMBIDI
2001-05-25 13:20:38 +00:00
PRInt32 bidiStopOffset = mContentOffset + mContentLength ;
if ( aContentOffset > = mContentOffset & & aContentOffset < bidiStopOffset ) {
PRInt32 curindx = ip [ aContentOffset - mContentOffset ] - mContentOffset ;
while ( curindx < textLength & & IS_BIDI_DIACRITIC ( text [ curindx ] ) ) {
if ( + + aContentOffset > = bidiStopOffset )
break ;
curindx = ip [ aContentOffset - mContentOffset ] - mContentOffset ;
2001-05-23 22:05:30 +00:00
}
2001-04-11 23:32:21 +00:00
}
# endif // IBMBIDI
1999-11-24 01:10:22 +00:00
aContentOffsetEnd = aContentOffset ;
NS_ASSERTION ( i < = mContentLength , " offset we got from binary search is messed up " ) ;
}
1999-06-08 02:19:26 +00:00
* aNewContent = mContent ;
if ( * aNewContent ) {
( * aNewContent ) - > AddRef ( ) ;
}
1999-01-25 23:29:53 +00:00
}
}
1998-12-14 18:34:14 +00:00
return NS_OK ;
}
1998-10-02 01:12:39 +00:00
1999-09-29 20:04:05 +00:00
NS_IMETHODIMP
1999-11-24 06:03:41 +00:00
nsTextFrame : : GetContentAndOffsetsFromPoint ( nsIPresContext * aCX ,
1999-09-29 20:04:05 +00:00
const nsPoint & aPoint ,
nsIContent * * aNewContent ,
PRInt32 & aContentOffset ,
1999-10-13 01:15:26 +00:00
PRInt32 & aContentOffsetEnd ,
PRBool & aBeginFrameContent )
1999-09-29 20:04:05 +00:00
{
2001-03-27 23:02:21 +00:00
if ( ! aNewContent )
return NS_ERROR_NULL_POINTER ;
* aNewContent = nsnull ; //initialize
aContentOffset = 0 ;
aContentOffsetEnd = 0 ;
aBeginFrameContent = 0 ;
1999-11-24 01:10:22 +00:00
nsPoint newPoint ;
newPoint . y = aPoint . y ;
if ( aPoint . x < 0 )
newPoint . x = 0 ;
else
newPoint . x = aPoint . x ;
nsresult rv = GetPosition ( aCX , newPoint , aNewContent , aContentOffset , aContentOffsetEnd ) ;
2001-03-27 23:02:21 +00:00
if ( NS_FAILED ( rv ) )
return rv ;
1999-10-13 01:15:26 +00:00
if ( aContentOffset = = mContentOffset )
aBeginFrameContent = PR_TRUE ;
else
aBeginFrameContent = PR_FALSE ;
return rv ;
1999-09-29 20:04:05 +00:00
}
1999-03-12 00:17:14 +00:00
1999-04-26 04:02:04 +00:00
// [HACK] Foward Declarations
void ForceDrawFrame ( nsFrame * aFrame ) ;
1998-12-14 18:34:14 +00:00
1999-05-20 00:52:00 +00:00
//null range means the whole thing
1999-01-22 18:58:14 +00:00
NS_IMETHODIMP
1999-10-26 04:44:41 +00:00
nsTextFrame : : SetSelected ( nsIPresContext * aPresContext ,
nsIDOMRange * aRange ,
PRBool aSelected ,
nsSpread aSpread )
1999-01-22 18:58:14 +00:00
{
1999-04-26 04:02:04 +00:00
nsresult result ;
1999-06-01 23:04:13 +00:00
if ( aSelected & & ParentDisablesSelection ( ) )
return NS_OK ;
1999-09-20 21:47:37 +00:00
1999-05-20 00:52:00 +00:00
nsFrameState frameState ;
GetFrameState ( & frameState ) ;
2000-03-30 03:21:26 +00:00
#if 0
1999-06-03 02:09:03 +00:00
PRBool isSelected = ( ( frameState & NS_FRAME_SELECTED_CONTENT ) = = NS_FRAME_SELECTED_CONTENT ) ;
2000-03-30 03:21:26 +00:00
if ( ! aSelected & & ! isSelected ) //already set thanks
1999-06-01 23:04:13 +00:00
{
return NS_OK ;
2000-03-30 03:21:26 +00:00
}
# endif
1999-01-25 01:48:01 +00:00
2000-01-11 19:44:59 +00:00
// check whether style allows selection
2000-08-05 04:41:33 +00:00
PRBool selectable ;
2000-08-08 23:38:00 +00:00
IsSelectable ( & selectable , nsnull ) ;
2000-08-05 04:41:33 +00:00
if ( ! selectable )
return NS_OK ; //do not continue no selection for this frame.
2000-01-11 19:44:59 +00:00
1999-05-17 22:31:10 +00:00
PRBool found = PR_FALSE ;
1999-09-20 21:47:37 +00:00
PRBool wholeContentFound = PR_FALSE ; //if the entire content we look at is selected.
1999-05-20 00:52:00 +00:00
if ( aRange ) {
//lets see if the range contains us, if so we must redraw!
nsCOMPtr < nsIDOMNode > endNode ;
PRInt32 endOffset ;
nsCOMPtr < nsIDOMNode > startNode ;
PRInt32 startOffset ;
2000-08-24 03:54:30 +00:00
aRange - > GetEndContainer ( getter_AddRefs ( endNode ) ) ;
1999-05-20 00:52:00 +00:00
aRange - > GetEndOffset ( & endOffset ) ;
2000-08-24 03:54:30 +00:00
aRange - > GetStartContainer ( getter_AddRefs ( startNode ) ) ;
1999-05-20 00:52:00 +00:00
aRange - > GetStartOffset ( & startOffset ) ;
nsCOMPtr < nsIContent > content ;
result = GetContent ( getter_AddRefs ( content ) ) ;
nsCOMPtr < nsIDOMNode > thisNode ;
thisNode = do_QueryInterface ( content ) ;
1999-09-21 22:58:14 +00:00
if ( thisNode = = startNode )
{
if ( ( mContentOffset + mContentLength ) > = startOffset )
{
1999-05-20 00:52:00 +00:00
found = PR_TRUE ;
1999-09-21 22:58:14 +00:00
if ( thisNode = = endNode )
{ //special case
1999-08-09 19:15:04 +00:00
if ( endOffset = = startOffset ) //no need to redraw since drawing takes place with cursor
1999-05-20 00:52:00 +00:00
found = PR_FALSE ;
1999-08-09 19:15:04 +00:00
1999-05-20 00:52:00 +00:00
if ( mContentOffset > endOffset )
found = PR_FALSE ;
}
1999-01-25 01:48:01 +00:00
}
}
1999-09-21 22:58:14 +00:00
else if ( thisNode = = endNode )
{
1999-05-20 00:52:00 +00:00
if ( mContentOffset < endOffset )
found = PR_TRUE ;
else
1999-09-21 22:58:14 +00:00
{
1999-05-20 00:52:00 +00:00
found = PR_FALSE ;
1999-09-21 22:58:14 +00:00
wholeContentFound = PR_TRUE ;
}
1999-05-20 00:52:00 +00:00
}
1999-09-21 22:58:14 +00:00
else
1999-09-20 21:47:37 +00:00
{
1999-05-20 00:52:00 +00:00
found = PR_TRUE ;
1999-09-20 21:47:37 +00:00
}
1999-01-22 18:58:14 +00:00
}
1999-05-20 00:52:00 +00:00
else {
if ( aSelected ! = ( PRBool ) ( frameState | NS_FRAME_SELECTED_CONTENT ) ) {
1999-05-18 22:29:27 +00:00
found = PR_TRUE ;
1999-05-20 00:52:00 +00:00
}
1999-05-18 22:29:27 +00:00
}
1999-05-20 00:52:00 +00:00
1999-06-01 23:04:13 +00:00
if ( aSelected )
frameState | = NS_FRAME_SELECTED_CONTENT ;
else
2000-01-08 00:31:32 +00:00
{ //we need to see if any other selection available.
SelectionDetails * details = nsnull ;
nsCOMPtr < nsIPresShell > shell ;
nsCOMPtr < nsIFrameSelection > frameSelection ;
nsresult rv = aPresContext - > GetShell ( getter_AddRefs ( shell ) ) ;
if ( NS_SUCCEEDED ( rv ) & & shell ) {
2000-05-08 03:59:53 +00:00
nsCOMPtr < nsISelectionController > selCon ;
rv = GetSelectionController ( aPresContext , getter_AddRefs ( selCon ) ) ;
if ( NS_SUCCEEDED ( rv ) & & selCon )
{
frameSelection = do_QueryInterface ( selCon ) ; //this MAY implement
}
if ( ! frameSelection )
rv = shell - > GetFrameSelection ( getter_AddRefs ( frameSelection ) ) ;
2000-01-08 00:31:32 +00:00
if ( NS_SUCCEEDED ( rv ) & & frameSelection ) {
nsCOMPtr < nsIContent > content ;
2000-04-02 05:05:31 +00:00
PRInt32 offset ;
PRInt32 length ;
rv = GetContentAndOffsetsForSelection ( aPresContext , getter_AddRefs ( content ) , & offset , & length ) ;
2000-01-08 00:31:32 +00:00
if ( NS_SUCCEEDED ( rv ) & & content ) {
2000-04-02 05:05:31 +00:00
rv = frameSelection - > LookUpSelection ( content , offset ,
length , & details , PR_TRUE ) ;
2000-01-08 00:31:32 +00:00
// PR_TRUE last param used here! we need to see if we are still selected. so no shortcut
}
}
}
if ( ! details )
frameState & = ~ NS_FRAME_SELECTED_CONTENT ;
2000-02-10 07:55:34 +00:00
else
{
SelectionDetails * sdptr = details ;
while ( ( sdptr = details - > mNext ) ! = nsnull ) {
delete details ;
details = sdptr ;
}
delete details ;
}
2000-01-08 00:31:32 +00:00
}
1999-04-26 04:02:04 +00:00
SetFrameState ( frameState ) ;
1999-04-28 02:43:02 +00:00
if ( found ) { //if range contains this frame...
nsRect frameRect ;
GetRect ( frameRect ) ;
nsRect rect ( 0 , 0 , frameRect . width , frameRect . height ) ;
2001-11-29 22:54:15 +00:00
if ( ! rect . IsEmpty ( ) )
Invalidate ( aPresContext , rect , PR_FALSE ) ;
1999-04-28 02:43:02 +00:00
// ForceDrawFrame(this);
}
1999-09-20 21:47:37 +00:00
if ( aSpread = = eSpreadDown )
{
1999-10-23 23:19:14 +00:00
nsIFrame * frame ;
GetPrevInFlow ( & frame ) ;
1999-09-20 21:47:37 +00:00
while ( frame ) {
1999-10-26 04:44:41 +00:00
frame - > SetSelected ( aPresContext , aRange , aSelected , eSpreadNone ) ;
1999-09-20 21:47:37 +00:00
result = frame - > GetPrevInFlow ( & frame ) ;
if ( NS_FAILED ( result ) )
break ;
}
1999-10-23 23:19:14 +00:00
GetNextInFlow ( & frame ) ;
1999-09-29 20:36:00 +00:00
while ( frame ) {
1999-10-26 04:44:41 +00:00
frame - > SetSelected ( aPresContext , aRange , aSelected , eSpreadNone ) ;
1999-09-29 20:36:00 +00:00
result = frame - > GetNextInFlow ( & frame ) ;
if ( NS_FAILED ( result ) )
break ;
1999-09-20 21:47:37 +00:00
}
2001-04-11 23:32:21 +00:00
# ifdef IBMBIDI
2001-06-21 12:35:48 +00:00
GetBidiProperty ( aPresContext , nsLayoutAtoms : : nextBidi , ( void * * ) & frame , sizeof ( frame ) ) ;
2001-04-11 23:32:21 +00:00
if ( frame ) {
frame - > SetSelected ( aPresContext , aRange , aSelected , aSpread ) ;
}
# endif // IBMBIDI
1999-09-20 21:47:37 +00:00
}
1998-10-02 01:12:39 +00:00
return NS_OK ;
1998-09-08 22:34:40 +00:00
}
1999-02-12 00:02:31 +00:00
NS_IMETHODIMP
1999-04-20 00:23:33 +00:00
nsTextFrame : : GetPointFromOffset ( nsIPresContext * aPresContext ,
nsIRenderingContext * inRendContext ,
PRInt32 inOffset ,
nsPoint * outPoint )
1999-02-12 00:02:31 +00:00
{
1999-04-20 00:23:33 +00:00
if ( ! aPresContext | | ! inRendContext | | ! outPoint )
1999-03-12 21:38:16 +00:00
return NS_ERROR_NULL_POINTER ;
1999-03-16 22:55:49 +00:00
if ( mContentLength < = 0 ) {
outPoint - > x = 0 ;
outPoint - > y = 0 ;
return NS_OK ;
}
1999-03-12 21:38:16 +00:00
inOffset - = mContentOffset ;
if ( inOffset < 0 ) {
NS_ASSERTION ( 0 , " offset less than this frame has in GetPointFromOffset " ) ;
inOffset = 0 ;
}
2000-06-01 01:00:15 +00:00
if ( inOffset > = mContentLength )
inOffset = mContentLength ;
1999-04-20 00:23:33 +00:00
TextStyle ts ( aPresContext , * inRendContext , mStyleContext ) ;
1999-02-12 00:02:31 +00:00
1999-09-22 00:40:56 +00:00
// Make enough space to transform
nsAutoTextBuffer paintBuffer ;
nsAutoIndexBuffer indexBuffer ;
nsresult rv = indexBuffer . GrowTo ( mContentLength + 1 ) ;
if ( NS_FAILED ( rv ) ) {
return rv ;
1999-02-12 00:02:31 +00:00
}
1999-03-12 21:38:16 +00:00
1999-04-20 00:23:33 +00:00
// Transform text from content into renderable form
1999-09-22 00:40:56 +00:00
nsCOMPtr < nsIDocument > doc ( getter_AddRefs ( GetDocument ( aPresContext ) ) ) ;
1999-02-24 18:21:23 +00:00
nsCOMPtr < nsILineBreaker > lb ;
doc - > GetLineBreaker ( getter_AddRefs ( lb ) ) ;
2000-09-20 23:00:32 +00:00
nsTextTransformer tx ( lb , nsnull , aPresContext ) ;
1999-09-22 00:40:56 +00:00
PRInt32 textLength ;
2000-04-17 14:40:46 +00:00
PRInt32 numSpaces ;
numSpaces = PrepareUnicodeText ( tx , & indexBuffer , & paintBuffer , & textLength ) ;
ComputeExtraJustificationSpacing ( * inRendContext , ts , paintBuffer . mBuffer , textLength , numSpaces ) ;
1999-09-22 00:40:56 +00:00
PRInt32 * ip = indexBuffer . mBuffer ;
1999-03-12 21:38:16 +00:00
if ( inOffset > mContentLength ) {
NS_ASSERTION ( 0 , " invalid offset passed to GetPointFromOffset " ) ;
inOffset = mContentLength ;
}
1999-09-22 00:40:56 +00:00
2000-06-01 01:00:15 +00:00
while ( inOffset > = 0 & & ip [ inOffset ] < mContentOffset ) //buffer has shrunk
inOffset - - ;
1999-09-22 00:40:56 +00:00
nscoord width = mRect . width ;
2000-06-01 01:00:15 +00:00
if ( inOffset < 0 )
2000-03-31 07:26:07 +00:00
{
2000-06-01 01:00:15 +00:00
NS_ASSERTION ( 0 , " invalid offset passed to GetPointFromOffset " ) ;
inOffset = 0 ;
width = 0 ;
2000-03-31 07:26:07 +00:00
}
else
{
2002-04-04 02:15:57 +00:00
PRInt32 hitLength = ip [ inOffset ] - mContentOffset ;
2000-06-01 01:00:15 +00:00
if ( ts . mSmallCaps | | ( 0 ! = ts . mWordSpacing ) | | ( 0 ! = ts . mLetterSpacing ) | | ts . mJustifying )
{
2001-09-27 18:34:30 +00:00
nsTextDimensions dimensions ;
2002-04-04 02:15:57 +00:00
GetTextDimensions ( * inRendContext , ts , paintBuffer . mBuffer , hitLength , & dimensions ) ;
2001-09-27 18:34:30 +00:00
width = dimensions . width ;
2000-06-01 01:00:15 +00:00
}
else
{
2002-04-04 02:15:57 +00:00
PRInt32 totalLength = 0 ; // length up to the last-in-flow frame
nsCOMPtr < nsITextContent > tc ( do_QueryInterface ( mContent ) ) ;
if ( tc ) {
const nsTextFragment * frag ;
tc - > GetText ( & frag ) ;
totalLength = frag - > GetLength ( ) ; // raw value which includes whitespace
}
if ( ( hitLength = = textLength ) & & ( inOffset = mContentLength ) & &
( mContentOffset + mContentLength = = totalLength ) ) {
// no need to re-measure when at the end of the last-in-flow
}
else
inRendContext - > GetWidth ( paintBuffer . mBuffer , hitLength , width ) ;
2000-06-01 01:00:15 +00:00
}
2002-04-04 02:15:57 +00:00
if ( ( hitLength = = textLength ) & & ( TEXT_TRIMMED_WS & mState ) ) {
2000-06-01 01:00:15 +00:00
//
// Offset must be after a space that has
// been trimmed off the end of the frame.
// Add the width of the trimmed space back
// to the total width, so the caret appears
// in the proper place!
//
2001-09-28 22:39:10 +00:00
// NOTE: the trailing whitespace includes the word and letter spacing!!
width + = ts . mSpaceWidth + ts . mWordSpacing + ts . mLetterSpacing ;
2000-06-01 01:00:15 +00:00
}
1999-10-29 13:43:11 +00:00
}
2001-04-11 23:32:21 +00:00
# ifdef IBMBIDI
2001-06-21 12:35:48 +00:00
PRUint8 level ;
GetBidiProperty ( aPresContext , nsLayoutAtoms : : embeddingLevel , ( void * * ) & level , sizeof ( level ) ) ;
2001-04-11 23:32:21 +00:00
if ( level & 1 ) {
outPoint - > x = mRect . width - width ;
}
else
# endif // IBMBIDI
2002-04-04 02:15:57 +00:00
//XXX callers need to safeguard themselves against empty frames, I noted that
//the caret can be locked when leftarrow'ing in: <span>...</span>\n<br>line
2001-06-05 02:40:27 +00:00
if ( width > mRect . width )
outPoint - > x = mRect . width ;
else
outPoint - > x = width ;
1999-09-22 00:40:56 +00:00
outPoint - > y = 0 ;
1999-02-12 00:02:31 +00:00
return NS_OK ;
}
2000-06-01 01:00:15 +00:00
1999-02-12 00:02:31 +00:00
NS_IMETHODIMP
1999-04-20 00:23:33 +00:00
nsTextFrame : : GetChildFrameContainingOffset ( PRInt32 inContentOffset ,
1999-09-11 00:18:02 +00:00
PRBool inHint ,
1999-04-20 00:23:33 +00:00
PRInt32 * outFrameContentOffset ,
nsIFrame * * outChildFrame )
1999-02-12 00:02:31 +00:00
{
if ( nsnull = = outChildFrame )
return NS_ERROR_NULL_POINTER ;
1999-07-15 18:19:03 +00:00
nsresult result ;
1999-02-12 00:02:31 +00:00
PRInt32 contentOffset = inContentOffset ;
if ( contentOffset ! = - 1 ) //-1 signified the end of the current content
contentOffset = inContentOffset - mContentOffset ;
1999-09-11 00:18:02 +00:00
if ( ( contentOffset > mContentLength ) | | ( ( contentOffset = = mContentLength ) & & inHint ) )
1999-02-12 00:02:31 +00:00
{
//this is not the frame we are looking for.
1999-05-13 00:44:23 +00:00
nsIFrame * nextInFlow ;
1999-10-23 23:19:14 +00:00
GetNextInFlow ( & nextInFlow ) ;
1999-02-12 00:02:31 +00:00
if ( nextInFlow )
1999-09-13 22:19:31 +00:00
{
1999-09-11 00:18:02 +00:00
return nextInFlow - > GetChildFrameContainingOffset ( inContentOffset , inHint , outFrameContentOffset , outChildFrame ) ;
1999-09-13 22:19:31 +00:00
}
2001-04-11 23:32:21 +00:00
else {
# ifdef IBMBIDI // Simon
2001-05-16 13:17:40 +00:00
// There is no nextInFlow - check if there is a bidi
// continuation frame
if ( mState & NS_FRAME_IS_BIDI )
{
2001-04-11 23:32:21 +00:00
nsIFrame * nextBidi ;
GetNextSibling ( & nextBidi ) ;
if ( nextBidi )
2001-05-16 13:17:40 +00:00
{
PRInt32 start , end ;
if ( NS_SUCCEEDED ( nextBidi - > GetOffsets ( start , end ) ) & & start > 0 )
{
return nextBidi - > GetChildFrameContainingOffset ( inContentOffset ,
2001-10-24 11:12:31 +00:00
inHint , outFrameContentOffset , outChildFrame ) ;
2001-05-16 13:17:40 +00:00
}
}
}
2001-04-11 23:32:21 +00:00
# endif // IBMBIDI
{
if ( contentOffset ! = mContentLength ) //that condition was only for when there is a choice
return NS_ERROR_FAILURE ;
}
}
1999-02-12 00:02:31 +00:00
}
1999-09-13 22:19:31 +00:00
if ( inContentOffset < mContentOffset ) //could happen with floaters!
1999-07-15 18:19:03 +00:00
{
result = GetPrevInFlow ( outChildFrame ) ;
2001-04-11 23:32:21 +00:00
if ( NS_SUCCEEDED ( result ) & & * outChildFrame )
1999-09-11 00:18:02 +00:00
return ( * outChildFrame ) - > GetChildFrameContainingOffset ( inContentOffset , inHint ,
1999-07-15 18:19:03 +00:00
outFrameContentOffset , outChildFrame ) ;
else
return result ;
}
1999-02-12 00:02:31 +00:00
* outFrameContentOffset = contentOffset ;
* outChildFrame = this ;
return NS_OK ;
}
1999-01-22 18:58:14 +00:00
1999-02-02 00:23:40 +00:00
NS_IMETHODIMP
1999-10-26 04:44:41 +00:00
nsTextFrame : : PeekOffset ( nsIPresContext * aPresContext , nsPeekOffsetStruct * aPos )
1999-02-02 00:23:40 +00:00
{
2001-04-11 23:32:21 +00:00
# ifdef IBMBIDI
2001-06-21 12:35:48 +00:00
PRUint8 level , baseLevel ;
GetBidiProperty ( aPresContext , nsLayoutAtoms : : embeddingLevel , ( void * * ) & level , sizeof ( level ) ) ;
GetBidiProperty ( aPresContext , nsLayoutAtoms : : baseLevel , ( void * * ) & baseLevel , sizeof ( baseLevel ) ) ;
2001-04-11 23:32:21 +00:00
PRBool isOddLevel = ( level & 1 ) ;
if ( ( eSelectCharacter = = aPos - > mAmount )
| | ( eSelectWord = = aPos - > mAmount ) )
aPos - > mPreferLeft ^ = isOddLevel ;
# endif
1999-05-13 00:44:23 +00:00
1999-09-10 18:29:37 +00:00
if ( ! aPos | | ! mContent )
1999-02-02 00:23:40 +00:00
return NS_ERROR_NULL_POINTER ;
1999-09-10 18:29:37 +00:00
if ( aPos - > mStartOffset < 0 )
aPos - > mStartOffset = mContentLength + mContentOffset ;
if ( aPos - > mStartOffset < mContentOffset ) {
aPos - > mStartOffset = mContentOffset ;
1999-05-13 00:44:23 +00:00
}
1999-09-10 18:29:37 +00:00
if ( aPos - > mStartOffset > ( mContentOffset + mContentLength ) ) {
1999-05-13 00:44:23 +00:00
nsIFrame * nextInFlow ;
2001-04-11 23:32:21 +00:00
# ifdef IBMBIDI
if ( isOddLevel ) {
2001-06-21 12:35:48 +00:00
GetBidiProperty ( aPresContext , nsLayoutAtoms : : nextBidi , ( void * * ) & nextInFlow , sizeof ( nextInFlow ) ) ;
2001-04-11 23:32:21 +00:00
}
else
# endif
1999-10-23 23:19:14 +00:00
GetNextInFlow ( & nextInFlow ) ;
1999-05-13 00:44:23 +00:00
if ( ! nextInFlow ) {
NS_ASSERTION ( PR_FALSE , " nsTextFrame::PeekOffset no more flow \n " ) ;
return NS_ERROR_INVALID_ARG ;
}
1999-10-26 04:44:41 +00:00
return nextInFlow - > PeekOffset ( aPresContext , aPos ) ;
1999-05-13 00:44:23 +00:00
}
1999-09-10 18:29:37 +00:00
if ( aPos - > mAmount = = eSelectLine | | aPos - > mAmount = = eSelectBeginLine
2000-05-16 22:48:28 +00:00
| | aPos - > mAmount = = eSelectEndLine | | aPos - > mAmount = = eSelectParagraph )
1999-09-01 21:40:16 +00:00
{
1999-10-26 04:44:41 +00:00
return nsFrame : : PeekOffset ( aPresContext , aPos ) ;
1999-09-01 21:40:16 +00:00
}
1999-05-13 00:44:23 +00:00
1999-09-22 00:40:56 +00:00
nsAutoTextBuffer paintBuffer ;
nsAutoIndexBuffer indexBuffer ;
nsresult rv = indexBuffer . GrowTo ( mContentLength + 1 ) ;
if ( NS_FAILED ( rv ) ) {
return rv ;
1999-02-02 00:23:40 +00:00
}
1999-09-22 00:40:56 +00:00
PRInt32 * ip = indexBuffer . mBuffer ;
1999-02-02 00:23:40 +00:00
PRInt32 textLength ;
1999-09-22 04:12:23 +00:00
nsresult result ( NS_ERROR_FAILURE ) ;
1999-09-11 00:18:02 +00:00
aPos - > mResultContent = mContent ; //do this right off
1999-09-10 18:29:37 +00:00
switch ( aPos - > mAmount ) {
1999-09-22 00:40:56 +00:00
case eSelectNoAmount :
{
1999-09-25 23:33:02 +00:00
// Transform text from content into renderable form
nsIDocument * doc ;
result = mContent - > GetDocument ( doc ) ;
if ( NS_FAILED ( result ) | | ! doc ) {
return result ;
}
nsCOMPtr < nsILineBreaker > lb ;
doc - > GetLineBreaker ( getter_AddRefs ( lb ) ) ;
NS_RELEASE ( doc ) ;
2000-09-20 23:00:32 +00:00
nsTextTransformer tx ( lb , nsnull , aPresContext ) ;
1999-09-25 23:33:02 +00:00
PrepareUnicodeText ( tx , & indexBuffer , & paintBuffer , & textLength ) ;
if ( textLength ) //if no renderable length, you cant park here.
{
aPos - > mContentOffset = aPos - > mStartOffset ;
result = NS_OK ;
}
else
{
aPos - > mAmount = eSelectDir ; //go to "next" or previous frame based on direction not THIS frame
2000-01-22 01:16:50 +00:00
result = GetFrameFromDirection ( aPresContext , aPos ) ;
1999-11-23 20:30:21 +00:00
if ( NS_SUCCEEDED ( result ) & & aPos - > mResultFrame & & aPos - > mResultFrame ! = this )
return aPos - > mResultFrame - > PeekOffset ( aPresContext , aPos ) ;
2001-05-11 08:04:29 +00:00
else if ( NS_FAILED ( result ) )
return result ;
1999-09-25 23:33:02 +00:00
}
1999-02-16 02:42:08 +00:00
}
1999-02-10 18:55:25 +00:00
break ;
1999-08-10 07:23:56 +00:00
1999-09-22 00:40:56 +00:00
case eSelectCharacter :
{
// Transform text from content into renderable form
nsIDocument * doc ;
result = mContent - > GetDocument ( doc ) ;
if ( NS_FAILED ( result ) | | ! doc ) {
return result ;
1999-02-10 18:55:25 +00:00
}
1999-09-22 00:40:56 +00:00
nsCOMPtr < nsILineBreaker > lb ;
doc - > GetLineBreaker ( getter_AddRefs ( lb ) ) ;
NS_RELEASE ( doc ) ;
2000-09-20 23:00:32 +00:00
nsTextTransformer tx ( lb , nsnull , aPresContext ) ;
1999-09-22 00:40:56 +00:00
PrepareUnicodeText ( tx , & indexBuffer , & paintBuffer , & textLength ) ;
nsIFrame * frameUsed = nsnull ;
PRInt32 start ;
PRBool found = PR_TRUE ;
2001-04-11 23:32:21 +00:00
# ifdef IBMBIDI // Simon - RTL frames reverse meaning of previous and next
// so that right arrow always moves to the right on screen
// and left arrow always moves left
if ( ( ( aPos - > mDirection = = eDirPrevious ) & & ! isOddLevel ) | |
( ( aPos - > mDirection = = eDirNext ) & & isOddLevel ) ) {
# else
1999-09-22 00:40:56 +00:00
if ( aPos - > mDirection = = eDirPrevious ) {
2001-04-11 23:32:21 +00:00
# endif
1999-09-22 00:40:56 +00:00
aPos - > mContentOffset = 0 ;
PRInt32 i ;
2002-01-10 02:32:43 +00:00
# ifdef SUNCTL
static NS_DEFINE_CID ( kLECID , NS_ULE_CID ) ;
nsCOMPtr < nsILE > mCtlObj ;
mCtlObj = do_CreateInstance ( kLECID , & rv ) ;
if ( NS_FAILED ( rv ) ) {
NS_WARNING ( " Cell based cursor movement will not be supported \n " ) ;
mCtlObj = nsnull ;
# endif /* SUNCTL */
1999-09-22 00:40:56 +00:00
for ( i = aPos - > mStartOffset - 1 - mContentOffset ; i > = 0 ; i - - ) {
2002-03-27 03:28:34 +00:00
if ( ( ip [ i ] < ip [ aPos - > mStartOffset - mContentOffset ] ) & &
( ! IS_LOW_SURROGATE ( paintBuffer . mBuffer [ ip [ i ] - mContentOffset ] ) ) )
{
1999-09-22 00:40:56 +00:00
aPos - > mContentOffset = i + mContentOffset ;
break ;
}
}
2002-01-10 02:32:43 +00:00
# ifdef SUNCTL
}
else {
PRInt32 mPreviousOffset ;
mCtlObj - > PrevCluster ( ( const PRUnichar * ) paintBuffer . mBuffer ,
textLength , aPos - > mStartOffset ,
& mPreviousOffset ) ;
aPos - > mContentOffset = i = mPreviousOffset ;
}
# endif /* SUNCTL */
1999-09-22 00:40:56 +00:00
if ( i < 0 ) {
found = PR_FALSE ;
1999-10-23 23:19:14 +00:00
GetPrevInFlow ( & frameUsed ) ;
1999-09-22 00:40:56 +00:00
start = mContentOffset ;
1999-10-13 01:15:26 +00:00
aPos - > mContentOffset = start ; //in case next call fails we stop at this offset
1999-02-10 18:55:25 +00:00
}
1999-02-02 00:23:40 +00:00
}
2001-04-11 23:32:21 +00:00
# ifdef IBMBIDI // Simon, as above
else if ( ( ( aPos - > mDirection = = eDirNext ) & & ! isOddLevel ) | |
( ( aPos - > mDirection = = eDirPrevious ) & & isOddLevel ) ) {
# else
1999-09-22 00:40:56 +00:00
else if ( aPos - > mDirection = = eDirNext ) {
2001-04-11 23:32:21 +00:00
# endif
1999-09-22 00:40:56 +00:00
PRInt32 i ;
aPos - > mContentOffset = mContentLength ;
2002-01-10 02:32:43 +00:00
# ifdef SUNCTL
static NS_DEFINE_CID ( kLECID , NS_ULE_CID ) ;
nsCOMPtr < nsILE > mCtlObj ;
mCtlObj = do_CreateInstance ( kLECID , & rv ) ;
if ( NS_FAILED ( rv ) ) {
NS_WARNING ( " Cell based cursor movement will not be supported \n " ) ;
mCtlObj = nsnull ;
# endif /* SUNCTL */
1999-09-22 00:40:56 +00:00
for ( i = aPos - > mStartOffset + 1 - mContentOffset ; i < = mContentLength ; i + + ) {
2002-03-27 03:28:34 +00:00
if ( ( ip [ i ] > ip [ aPos - > mStartOffset - mContentOffset ] ) & &
( ! IS_LOW_SURROGATE ( paintBuffer . mBuffer [ ip [ i ] - mContentOffset ] ) ) )
{
1999-09-22 00:40:56 +00:00
aPos - > mContentOffset = i + mContentOffset ;
break ;
}
}
2002-01-10 02:32:43 +00:00
# ifdef SUNCTL
}
else {
PRInt32 mNextOffset ;
mCtlObj - > NextCluster ( ( const PRUnichar * ) paintBuffer . mBuffer ,
textLength , aPos - > mStartOffset ,
& mNextOffset ) ;
aPos - > mContentOffset = i = mNextOffset ;
}
# endif /* SUNCTL */
1999-09-01 01:02:16 +00:00
/* if (aStartOffset == 0 && (mState & TEXT_SKIP_LEADING_WS))
1999-02-22 03:20:59 +00:00
i - - ; //back up because we just skipped over some white space. why skip over the char also?
1999-09-22 00:40:56 +00:00
*/
if ( i > mContentLength ) {
found = PR_FALSE ;
1999-10-23 23:19:14 +00:00
GetNextInFlow ( & frameUsed ) ;
1999-09-22 00:40:56 +00:00
start = mContentOffset + mContentLength ;
1999-10-13 01:15:26 +00:00
aPos - > mContentOffset = start ; //in case next call fails we stop at this offset
1999-09-22 00:40:56 +00:00
}
1999-02-22 03:20:59 +00:00
}
1999-10-13 01:15:26 +00:00
1999-09-22 04:12:23 +00:00
if ( ! found )
1999-10-22 00:19:18 +00:00
{
2000-01-22 01:16:50 +00:00
result = GetFrameFromDirection ( aPresContext , aPos ) ;
1999-10-22 00:19:18 +00:00
if ( NS_SUCCEEDED ( result ) & & aPos - > mResultFrame & & aPos - > mResultFrame ! = this )
2001-05-11 08:04:29 +00:00
{
1999-10-26 04:44:41 +00:00
result = aPos - > mResultFrame - > PeekOffset ( aPresContext , aPos ) ;
2001-05-11 08:04:29 +00:00
if ( NS_FAILED ( result ) )
return result ;
}
1999-10-22 00:19:18 +00:00
}
1999-09-22 04:12:23 +00:00
else
1999-09-22 00:40:56 +00:00
aPos - > mResultContent = mContent ;
1999-02-22 03:20:59 +00:00
}
1999-09-22 00:40:56 +00:00
break ;
case eSelectWord :
{
// Transform text from content into renderable form
nsIDocument * doc ;
result = mContent - > GetDocument ( doc ) ;
if ( NS_FAILED ( result ) | | ! doc ) {
return result ;
}
nsCOMPtr < nsILineBreaker > lb ;
doc - > GetLineBreaker ( getter_AddRefs ( lb ) ) ;
nsCOMPtr < nsIWordBreaker > wb ;
doc - > GetWordBreaker ( getter_AddRefs ( wb ) ) ;
NS_RELEASE ( doc ) ;
2000-09-20 23:00:32 +00:00
nsTextTransformer tx ( lb , wb , aPresContext ) ;
1999-09-22 00:40:56 +00:00
PrepareUnicodeText ( tx , & indexBuffer , & paintBuffer , & textLength ) ;
nsIFrame * frameUsed = nsnull ;
PRBool keepSearching ; //if you run out of chars before you hit the end of word, maybe next frame has more text to select?
PRInt32 start ;
PRBool found = PR_FALSE ;
2000-04-12 22:22:58 +00:00
PRBool isWhitespace , wasTransformed ;
1999-09-22 00:40:56 +00:00
PRInt32 wordLen , contentLen ;
2001-04-11 23:32:21 +00:00
# ifdef IBMBIDI // Simon - RTL frames reverse meaning of previous and next
// so that right arrow always moves to the right on screen
// and left arrow always moves left
if ( ( ( aPos - > mDirection = = eDirPrevious ) & & ! isOddLevel ) | |
( ( aPos - > mDirection = = eDirNext ) & & isOddLevel ) ) {
# else
1999-09-22 00:40:56 +00:00
if ( aPos - > mDirection = = eDirPrevious ) {
2001-04-11 23:32:21 +00:00
# endif
1999-09-22 00:40:56 +00:00
keepSearching = PR_TRUE ;
tx . Init ( this , mContent , aPos - > mStartOffset ) ;
1999-10-22 00:19:18 +00:00
aPos - > mContentOffset = mContentOffset ; //initialize
2001-11-14 14:21:52 +00:00
# ifdef IBMBIDI
wordLen = ( mState & NS_FRAME_IS_BIDI ) ? mContentOffset : - 1 ;
# endif // IBMBIDI
1999-10-19 23:01:58 +00:00
if ( tx . GetPrevWord ( PR_FALSE , & wordLen , & contentLen , & isWhitespace ,
PR_FALSE ) & &
1999-09-22 07:09:41 +00:00
( aPos - > mStartOffset - contentLen > = mContentOffset ) ) {
1999-09-22 00:40:56 +00:00
if ( ( aPos - > mEatingWS & & ! isWhitespace ) | | ! aPos - > mEatingWS ) {
aPos - > mContentOffset = aPos - > mStartOffset - contentLen ;
//check for whitespace next.
1999-09-22 05:56:44 +00:00
if ( isWhitespace & & aPos - > mContentOffset < = mContentOffset )
{
1999-09-22 00:40:56 +00:00
keepSearching = PR_FALSE ; //reached the beginning of a word
1999-09-22 05:56:44 +00:00
aPos - > mEatingWS = PR_FALSE ; //if no real word then
1999-09-22 00:40:56 +00:00
}
1999-09-22 05:56:44 +00:00
else {
2001-11-14 14:21:52 +00:00
# ifdef IBMBIDI
wordLen = ( mState & NS_FRAME_IS_BIDI ) ? mContentOffset : - 1 ;
# endif // IBMBIDI
1999-10-19 23:01:58 +00:00
while ( isWhitespace & &
tx . GetPrevWord ( PR_FALSE , & wordLen , & contentLen ,
& isWhitespace , PR_FALSE ) ) {
1999-09-22 05:56:44 +00:00
aPos - > mContentOffset - = contentLen ;
aPos - > mEatingWS = PR_TRUE ;
2001-11-14 14:21:52 +00:00
# ifdef IBMBIDI
wordLen = ( mState & NS_FRAME_IS_BIDI ) ? mContentOffset : - 1 ;
# endif // IBMBIDI
1999-09-22 05:56:44 +00:00
}
1999-09-22 07:09:41 +00:00
aPos - > mEatingWS = ! isWhitespace ; //nowhite space, just eat chars.
1999-09-22 05:56:44 +00:00
keepSearching = aPos - > mContentOffset < = mContentOffset ;
if ( ! isWhitespace ) {
if ( ! keepSearching )
found = PR_TRUE ;
1999-09-22 00:40:56 +00:00
else
aPos - > mEatingWS = PR_TRUE ;
1999-09-22 05:56:44 +00:00
}
1999-09-22 00:40:56 +00:00
}
1999-03-03 01:51:21 +00:00
}
1999-09-22 00:40:56 +00:00
else {
aPos - > mContentOffset = mContentLength + mContentOffset ;
found = PR_TRUE ;
1999-03-03 01:51:21 +00:00
}
}
1999-02-22 03:20:59 +00:00
}
2001-04-11 23:32:21 +00:00
# ifdef IBMBIDI // Simon, as above
else if ( ( ( aPos - > mDirection = = eDirNext ) & & ! isOddLevel ) | |
( ( aPos - > mDirection = = eDirPrevious ) & & isOddLevel ) ) {
# else
1999-09-22 00:40:56 +00:00
else if ( aPos - > mDirection = = eDirNext ) {
2001-04-11 23:32:21 +00:00
# endif
1999-09-22 00:40:56 +00:00
tx . Init ( this , mContent , aPos - > mStartOffset ) ;
1999-10-22 00:19:18 +00:00
aPos - > mContentOffset = mContentOffset + mContentLength ; //initialize
1999-08-19 06:06:57 +00:00
2001-11-14 14:21:52 +00:00
# ifdef IBMBIDI
wordLen = ( mState & NS_FRAME_IS_BIDI ) ? mContentOffset + mContentLength : - 1 ;
# endif // IBMBIDI
2000-04-12 22:22:58 +00:00
if ( tx . GetNextWord ( PR_FALSE , & wordLen , & contentLen , & isWhitespace , & wasTransformed , PR_TRUE , PR_FALSE ) & &
1999-09-22 07:09:41 +00:00
( aPos - > mStartOffset + contentLen < = ( mContentLength + mContentOffset ) ) ) {
1999-08-19 06:06:57 +00:00
1999-09-22 00:40:56 +00:00
if ( ( aPos - > mEatingWS & & isWhitespace ) | | ! aPos - > mEatingWS ) {
aPos - > mContentOffset = aPos - > mStartOffset + contentLen ;
2001-10-19 14:10:22 +00:00
// check for whitespace next. On some platforms (mac), we want the selection to end
// at the end of the word (not the beginning of the next one), so don't slurp up any extra whitespace.
if ( sWordSelectEatSpaceAfter ) {
keepSearching = PR_TRUE ;
aPos - > mEatingWS = PR_TRUE ;
2001-11-14 14:21:52 +00:00
if ( ! isWhitespace ) {
# ifdef IBMBIDI
wordLen = ( mState & NS_FRAME_IS_BIDI )
? mContentOffset + mContentLength : - 1 ;
# endif // IBMBIDI
2001-10-19 14:10:22 +00:00
while ( tx . GetNextWord ( PR_FALSE , & wordLen , & contentLen , & isWhitespace , & wasTransformed , PR_TRUE , PR_FALSE ) )
{
if ( aPos - > mStartOffset + contentLen > ( mContentLength + mContentOffset ) )
goto TryNextFrame ;
if ( isWhitespace )
aPos - > mContentOffset + = contentLen ;
else
break ;
2001-11-14 14:21:52 +00:00
# ifdef IBMBIDI
wordLen = ( mState & NS_FRAME_IS_BIDI )
? mContentOffset + mContentLength : - 1 ;
# endif // IBMBIDI
2001-10-19 14:10:22 +00:00
}
keepSearching = PR_FALSE ;
found = PR_TRUE ;
}
else //we just need to jump the space, done here
{
2001-11-14 14:21:52 +00:00
# ifdef IBMBIDI
wordLen = ( mState & NS_FRAME_IS_BIDI )
? mContentOffset + mContentLength : - 1 ;
# endif // IBMBIDI
2001-10-19 14:10:22 +00:00
while ( tx . GetNextWord ( PR_FALSE , & wordLen , & contentLen , & isWhitespace , & wasTransformed , PR_TRUE , PR_FALSE ) )
{
if ( aPos - > mStartOffset + contentLen > ( mContentLength + mContentOffset ) )
goto TryNextFrame ;
if ( isWhitespace )
aPos - > mContentOffset + = contentLen ;
else
break ;
2001-11-14 14:21:52 +00:00
# ifdef IBMBIDI
wordLen = ( mState & NS_FRAME_IS_BIDI ) ? mContentOffset + mContentLength : - 1 ;
# endif // IBMBIDI
2001-10-19 14:10:22 +00:00
}
keepSearching = PR_FALSE ;
found = PR_TRUE ;
}
} // if we should eat space to the next word
else {
keepSearching = PR_FALSE ;
found = PR_TRUE ;
1999-09-22 00:40:56 +00:00
}
1999-03-03 01:51:21 +00:00
}
1999-09-22 00:40:56 +00:00
else if ( aPos - > mEatingWS )
2000-05-16 19:51:09 +00:00
{
1999-09-22 00:40:56 +00:00
aPos - > mContentOffset = mContentOffset ;
2000-05-16 19:51:09 +00:00
found = PR_TRUE ;
}
1999-09-22 00:40:56 +00:00
if ( ! isWhitespace ) {
aPos - > mEatingWS = PR_FALSE ;
}
else if ( ! keepSearching ) //we have found the "whole" word so just looking for WS
aPos - > mEatingWS = PR_TRUE ;
1999-10-22 00:19:18 +00:00
}
2000-08-03 23:03:08 +00:00
TryNextFrame :
GetNextInFlow ( & frameUsed ) ;
1999-09-22 00:40:56 +00:00
start = 0 ;
1999-02-22 03:20:59 +00:00
}
2000-08-03 23:03:08 +00:00
1999-09-22 04:12:23 +00:00
if ( ! found | | ( aPos - > mContentOffset > ( mContentOffset + mContentLength ) ) | | ( aPos - > mContentOffset < mContentOffset ) )
1999-09-22 07:09:41 +00:00
{
aPos - > mContentOffset = PR_MIN ( aPos - > mContentOffset , mContentOffset + mContentLength ) ;
aPos - > mContentOffset = PR_MAX ( aPos - > mContentOffset , mContentOffset ) ;
2000-01-22 01:16:50 +00:00
result = GetFrameFromDirection ( aPresContext , aPos ) ;
1999-10-22 00:19:18 +00:00
if ( NS_SUCCEEDED ( result ) & & aPos - > mResultFrame & & aPos - > mResultFrame ! = this )
{
1999-10-26 04:44:41 +00:00
if ( NS_SUCCEEDED ( result = aPos - > mResultFrame - > PeekOffset ( aPresContext , aPos ) ) )
1999-10-22 00:19:18 +00:00
return NS_OK ; //else fall through
2000-01-12 21:39:36 +00:00
else if ( aPos - > mDirection = = eDirNext )
aPos - > mContentOffset = mContentOffset + mContentLength ;
else
aPos - > mContentOffset = mContentOffset ;
1999-10-22 00:19:18 +00:00
}
else
aPos - > mResultContent = mContent ;
1999-09-22 07:09:41 +00:00
}
1999-09-22 04:12:23 +00:00
else
1999-10-22 00:19:18 +00:00
{
1999-09-22 00:40:56 +00:00
aPos - > mResultContent = mContent ;
1999-10-22 00:19:18 +00:00
}
1999-02-22 03:20:59 +00:00
}
break ;
2001-04-11 23:32:21 +00:00
# ifdef IBMBIDI
case eSelectDir :
result = GetFrameFromDirection ( aPresContext , aPos ) ;
if ( NS_SUCCEEDED ( result ) & & aPos - > mResultFrame & & aPos - > mResultFrame ! = this )
return aPos - > mResultFrame - > PeekOffset ( aPresContext , aPos ) ;
else {
return result ;
}
break ;
# endif
1999-09-22 00:40:56 +00:00
default :
result = NS_ERROR_FAILURE ; break ;
1999-02-02 00:23:40 +00:00
}
1999-09-22 00:40:56 +00:00
1999-10-13 01:15:26 +00:00
aPos - > mContentOffsetEnd = aPos - > mContentOffset ;
1999-03-03 01:51:21 +00:00
if ( NS_FAILED ( result ) ) {
1999-09-10 18:29:37 +00:00
aPos - > mResultContent = mContent ;
1999-09-11 00:18:02 +00:00
//aPos->mContentOffset = aPos->mStartOffset;
1999-03-03 01:51:21 +00:00
result = NS_OK ;
}
1999-09-10 18:29:37 +00:00
aPos - > mResultFrame = this ;
1999-09-22 00:40:56 +00:00
1999-02-02 00:23:40 +00:00
return result ;
}
1999-05-17 00:21:18 +00:00
NS_IMETHODIMP
1999-11-24 06:03:41 +00:00
nsTextFrame : : HandleMultiplePress ( nsIPresContext * aPresContext ,
2000-05-16 22:48:28 +00:00
nsGUIEvent * aEvent ,
nsEventStatus * aEventStatus )
1999-05-17 00:21:18 +00:00
{
2000-04-30 18:56:26 +00:00
if ( DisplaySelection ( aPresContext ) = = nsISelectionController : : SELECTION_OFF ) {
1999-05-17 00:21:18 +00:00
return NS_OK ;
}
1999-10-13 01:15:26 +00:00
2000-05-16 22:48:28 +00:00
nsMouseEvent * me = ( nsMouseEvent * ) aEvent ;
if ( ! me ) return NS_OK ;
// Triple- and greater click counts are handled by nsFrame.
if ( me - > clickCount > 2 )
return nsFrame : : HandleMultiplePress ( aPresContext , aEvent , aEventStatus ) ;
// Double-click: word selection, handled here:
PRInt32 startPos = 0 ;
PRInt32 contentOffsetEnd = 0 ;
nsCOMPtr < nsIContent > newContent ;
nsresult rv = GetPosition ( aPresContext , aEvent - > point ,
getter_AddRefs ( newContent ) , startPos ,
contentOffsetEnd ) ;
if ( NS_FAILED ( rv ) )
return rv ;
1999-05-17 00:21:18 +00:00
2000-05-16 22:48:28 +00:00
return PeekBackwardAndForward ( eSelectWord , eSelectWord , startPos ,
aPresContext , PR_FALSE ) ;
1999-05-17 00:21:18 +00:00
}
1999-10-22 00:19:18 +00:00
2000-07-26 11:31:12 +00:00
NS_IMETHODIMP
nsTextFrame : : CheckVisibility ( nsIPresContext * aContext , PRInt32 aStartIndex , PRInt32 aEndIndex , PRBool aRecurse , PRBool * aFinished , PRBool * _retval )
{
if ( ! aFinished | | ! _retval )
return NS_ERROR_NULL_POINTER ;
if ( * aFinished )
return NS_ERROR_FAILURE ; //dont call with finished != false
if ( mContentOffset > aEndIndex )
return NS_OK ; //reached the end
if ( mContentOffset > aStartIndex )
aStartIndex = mContentOffset ;
if ( aStartIndex > = aEndIndex ) //how can it be greater?? check anyway
return NS_OK ; //reached the end.
nsresult rv ;
if ( aStartIndex < ( mContentOffset + mContentLength ) )
{
//get the presshell
nsCOMPtr < nsIPresShell > shell ;
rv = aContext - > GetShell ( getter_AddRefs ( shell ) ) ;
2001-10-13 09:27:46 +00:00
if ( NS_FAILED ( rv ) )
return rv ;
if ( ! shell )
return NS_ERROR_FAILURE ;
2000-07-26 11:31:12 +00:00
//get the document
nsCOMPtr < nsIDocument > doc ;
rv = shell - > GetDocument ( getter_AddRefs ( doc ) ) ;
2001-10-13 09:27:46 +00:00
if ( NS_FAILED ( rv ) )
return rv ;
2000-07-26 11:31:12 +00:00
if ( ! doc )
2001-10-13 09:27:46 +00:00
return NS_ERROR_FAILURE ;
2000-07-26 11:31:12 +00:00
//get the linebreaker
nsCOMPtr < nsILineBreaker > lb ;
doc - > GetLineBreaker ( getter_AddRefs ( lb ) ) ;
//create texttransformer
2000-09-20 23:00:32 +00:00
nsTextTransformer tx ( lb , nsnull , aContext ) ;
2000-07-26 11:31:12 +00:00
//create the buffers
nsAutoTextBuffer paintBuffer ;
nsAutoIndexBuffer indexBuffer ;
if ( NS_FAILED ( indexBuffer . GrowTo ( mContentLength + 1 ) ) )
return NS_ERROR_FAILURE ; //bail out
PRInt32 textLength ;
PrepareUnicodeText ( tx , & indexBuffer , & paintBuffer , & textLength ) ;
if ( textLength ) //we have something to measure?
{
PRInt32 start = PR_MAX ( aStartIndex , mContentOffset ) ;
PRInt32 end = PR_MIN ( mContentOffset + mContentLength - 1 , aEndIndex ) ; //base 0 index of array
while ( start ! = end )
{
if ( indexBuffer . mBuffer [ start ] < indexBuffer . mBuffer [ start + 1 ] ) //we have a rendered char!
{
* aFinished = PR_TRUE ; //we are done bubble out.
* _retval = PR_TRUE ; //hit a drawn char
return NS_OK ;
}
start + + ;
}
if ( start = = aEndIndex )
{
* aFinished = PR_TRUE ;
}
}
}
if ( aRecurse ) //recurse through the siblings.
{
nsIFrame * nextInFlow = this ;
rv = NS_OK ;
while ( ! aFinished & & nextInFlow & & NS_SUCCEEDED ( rv ) & & ! * _retval ) //while we havent found anything visible
{
rv = nextInFlow - > GetNextInFlow ( & nextInFlow ) ;
if ( nextInFlow )
{
rv = nextInFlow - > CheckVisibility ( aContext , aStartIndex , aEndIndex , PR_FALSE , aFinished , _retval ) ;
}
}
}
return NS_OK ;
}
1999-01-22 18:58:14 +00:00
NS_IMETHODIMP
1999-04-20 00:23:33 +00:00
nsTextFrame : : GetOffsets ( PRInt32 & start , PRInt32 & end ) const
1999-01-22 18:58:14 +00:00
{
start = mContentOffset ;
end = mContentOffset + mContentLength ;
return NS_OK ;
}
2000-03-23 22:58:43 +00:00
2000-03-31 04:27:43 +00:00
# define TEXT_MAX_NUM_SEGMENTS 65
struct SegmentData {
PRUint32 mIsWhitespace : 1 ;
PRUint32 mContentLen : 31 ; // content length
PRBool IsWhitespace ( ) { return PRBool ( mIsWhitespace ) ; }
// Get the content length. This is a running total of all
// the previous segments as well
PRInt32 ContentLen ( ) { return PRInt32 ( mContentLen ) ; }
} ;
struct TextRun {
2000-04-04 14:14:47 +00:00
// Total number of characters and the accumulated content length
PRInt32 mTotalNumChars , mTotalContentLen ;
2000-03-31 04:27:43 +00:00
// Words and whitespace each count as a segment
PRInt32 mNumSegments ;
// Possible break points specified as offsets into the buffer
PRInt32 mBreaks [ TEXT_MAX_NUM_SEGMENTS ] ;
// Per segment data
SegmentData mSegments [ TEXT_MAX_NUM_SEGMENTS ] ;
TextRun ( )
{
2000-04-04 14:14:47 +00:00
Reset ( ) ;
2000-03-31 04:27:43 +00:00
}
void Reset ( )
{
mNumSegments = 0 ;
2000-04-04 14:14:47 +00:00
mTotalNumChars = 0 ;
mTotalContentLen = 0 ;
2000-03-31 04:27:43 +00:00
}
// Returns PR_TRUE if we're currently buffering text
PRBool IsBuffering ( )
{
return mNumSegments > 0 ;
}
2000-04-04 14:14:47 +00:00
void AddSegment ( PRInt32 aNumChars , PRInt32 aContentLen , PRBool aIsWhitespace )
2000-03-31 04:27:43 +00:00
{
NS_PRECONDITION ( mNumSegments < TEXT_MAX_NUM_SEGMENTS , " segment overflow " ) ;
2001-04-11 23:32:21 +00:00
# ifdef IBMBIDI
if ( mNumSegments > = TEXT_MAX_NUM_SEGMENTS ) {
return ;
}
# endif // IBMBIDI
2000-04-04 14:14:47 +00:00
mTotalNumChars + = aNumChars ;
mBreaks [ mNumSegments ] = mTotalNumChars ;
mSegments [ mNumSegments ] . mIsWhitespace = aIsWhitespace ;
mTotalContentLen + = aContentLen ;
mSegments [ mNumSegments ] . mContentLen = PRUint32 ( mTotalContentLen ) ;
2000-03-31 04:27:43 +00:00
mNumSegments + + ;
}
} ;
2000-04-12 14:54:43 +00:00
// Transforms characters in place from ascii to Unicode
2000-04-12 22:48:54 +00:00
static void
2000-04-12 14:54:43 +00:00
TransformTextToUnicode ( char * aText , PRInt32 aNumChars )
{
// Go backwards over the characters and convert them.
unsigned char * cp1 = ( unsigned char * ) aText + aNumChars - 1 ;
PRUnichar * cp2 = ( PRUnichar * ) aText + ( aNumChars - 1 ) ;
while ( aNumChars - - > 0 ) {
* cp2 - - = PRUnichar ( * cp1 - - ) ;
}
}
2000-03-31 04:27:43 +00:00
nsReflowStatus
nsTextFrame : : MeasureText ( nsIPresContext * aPresContext ,
const nsHTMLReflowState & aReflowState ,
nsTextTransformer & aTx ,
nsILineBreaker * aLb ,
TextStyle & aTs ,
TextReflowData & aTextData )
2000-03-23 22:58:43 +00:00
{
PRBool firstThing = PR_TRUE ;
nscoord maxWidth = aReflowState . availableWidth ;
2000-03-31 04:27:43 +00:00
nsLineLayout & lineLayout = * aReflowState . mLineLayout ;
PRInt32 contentLength = aTx . GetContentLength ( ) ;
PRInt32 startingOffset = aTextData . mOffset ;
PRInt32 prevOffset = - 1 ;
PRInt32 column = mColumn ;
PRInt32 prevColumn = column ;
2001-09-27 18:34:30 +00:00
nscoord prevMaxWordWidth = 0 , prevAscent = 0 , prevDescent = 0 ;
2000-03-31 04:27:43 +00:00
PRInt32 lastWordLen = 0 ;
2000-04-04 14:14:47 +00:00
PRUnichar * lastWordPtr = nsnull ;
2000-03-31 04:27:43 +00:00
PRBool textStartsWithNBSP = PR_FALSE ;
PRBool endsInWhitespace = PR_FALSE ;
PRBool endsInNewline = PR_FALSE ;
PRBool justDidFirstLetter = PR_FALSE ;
2001-09-27 18:34:30 +00:00
nsTextDimensions dimensions , lastWordDimensions ;
2001-12-12 23:14:55 +00:00
# if defined(_WIN32) || defined(XP_OS2)
2000-03-31 04:27:43 +00:00
PRBool measureTextRuns = ! aTextData . mComputeMaxWordWidth & & ! aTs . mPreformatted & &
2000-08-10 23:03:11 +00:00
! aTs . mSmallCaps & & ! aTs . mWordSpacing & & ! aTs . mLetterSpacing & &
aTextData . mWrapping ;
2000-04-17 14:40:46 +00:00
// Don't measure text runs with letter spacing active, it doesn't work
2000-08-10 23:03:11 +00:00
// it also doesn't work if we are not word-wrapping (bug 42832)
2000-03-31 04:27:43 +00:00
# else
PRBool measureTextRuns = PR_FALSE ;
# endif
TextRun textRun ;
PRInt32 estimatedNumChars ;
// Estimate the number of characters that will fit. Use 105% of the available
// width divided by the average character width
estimatedNumChars = ( maxWidth - aTextData . mX ) / aTs . mAveCharWidth ;
estimatedNumChars + = estimatedNumChars / 20 ;
2001-04-11 23:32:21 +00:00
# ifdef IBMBIDI
nsTextFrame * nextBidi = nsnull ;
PRInt32 start = - 1 , end ;
if ( mState & NS_FRAME_IS_BIDI ) {
2001-06-21 12:35:48 +00:00
GetBidiProperty ( aPresContext , nsLayoutAtoms : : nextBidi , ( void * * ) & nextBidi , sizeof ( nextBidi ) ) ;
2001-04-11 23:32:21 +00:00
if ( nextBidi ) {
if ( mContentLength < 1 ) {
mContentLength = 1 ;
}
nextBidi - > GetOffsets ( start , end ) ;
if ( start < = mContentOffset ) {
nextBidi - > SetOffsets ( mContentOffset + mContentLength , end ) ;
nsFrameState frameState ;
nextBidi - > GetFrameState ( & frameState ) ;
frameState | = NS_FRAME_IS_BIDI ;
nextBidi - > SetFrameState ( frameState ) ;
}
else {
mContentLength = start - mContentOffset ;
}
}
}
# endif //IBMBIDI
2000-03-23 22:58:43 +00:00
aTextData . mX = 0 ;
2001-09-27 18:34:30 +00:00
if ( aTextData . mMeasureText ) {
2002-05-02 22:24:59 +00:00
aTs . mNormalFont - > GetMaxAscent ( aTextData . mAscent ) ;
aTs . mNormalFont - > GetMaxDescent ( aTextData . mDescent ) ;
2001-09-27 18:34:30 +00:00
}
2000-03-31 04:27:43 +00:00
for ( ; ; firstThing = PR_FALSE ) {
2001-04-11 23:32:21 +00:00
# ifdef IBMBIDI
if ( nextBidi & & ( mContentLength < = 0 ) ) {
if ( textRun . IsBuffering ( ) ) {
// Measure the remaining text
goto MeasureTextRun ;
}
else {
break ;
}
}
# endif // IBMBIDI
2000-03-23 22:58:43 +00:00
// Get next word/whitespace from the text
2000-04-12 14:54:43 +00:00
PRBool isWhitespace , wasTransformed ;
2000-03-23 22:58:43 +00:00
PRInt32 wordLen , contentLen ;
2000-04-12 14:54:43 +00:00
union {
char * bp1 ;
PRUnichar * bp2 ;
} ;
2001-11-14 14:21:52 +00:00
# ifdef IBMBIDI
wordLen = start ;
# endif // IBMBIDI
2000-04-12 14:54:43 +00:00
bp2 = aTx . GetNextWord ( aTextData . mInWord , & wordLen , & contentLen , & isWhitespace ,
& wasTransformed , textRun . mNumSegments = = 0 ) ;
2001-04-11 23:32:21 +00:00
# ifdef IBMBIDI
if ( nextBidi ) {
mContentLength - = contentLen ;
if ( mContentLength < 0 ) {
contentLen + = mContentLength ;
wordLen = PR_MIN ( wordLen , contentLen ) ;
}
}
# endif // IBMBIDI
2000-04-12 14:54:43 +00:00
// Remember if the text was transformed
if ( wasTransformed ) {
mState | = TEXT_WAS_TRANSFORMED ;
}
if ( nsnull = = bp2 ) {
2000-03-31 04:27:43 +00:00
if ( textRun . IsBuffering ( ) ) {
// Measure the remaining text
goto MeasureTextRun ;
}
else {
// Advance the offset in case we just consumed a bunch of
// discarded characters. Otherwise, if this is the first piece
// of content for this frame we will attempt to break-before it.
aTextData . mOffset + = contentLen ;
break ;
}
2000-03-23 22:58:43 +00:00
}
2000-03-31 04:27:43 +00:00
lastWordLen = wordLen ;
2000-04-12 14:54:43 +00:00
lastWordPtr = bp2 ;
2000-03-23 22:58:43 +00:00
aTextData . mInWord = PR_FALSE ;
// Measure the word/whitespace
2000-04-12 14:54:43 +00:00
PRUnichar firstChar ;
if ( aTx . TransformedTextIsAscii ( ) ) {
firstChar = * bp1 ;
} else {
firstChar = * bp2 ;
}
2000-03-23 22:58:43 +00:00
if ( isWhitespace ) {
2000-04-12 14:54:43 +00:00
if ( ' \n ' = = firstChar ) {
2000-03-23 22:58:43 +00:00
// We hit a newline. Stop looping.
NS_WARN_IF_FALSE ( aTs . mPreformatted , " newline w/o ts.mPreformatted " ) ;
2000-03-31 04:27:43 +00:00
prevOffset = aTextData . mOffset ;
2000-03-23 22:58:43 +00:00
aTextData . mOffset + + ;
2000-03-31 04:27:43 +00:00
endsInWhitespace = PR_TRUE ;
endsInNewline = PR_TRUE ;
2000-03-23 22:58:43 +00:00
break ;
}
if ( aTextData . mSkipWhitespace ) {
aTextData . mOffset + = contentLen ;
aTextData . mSkipWhitespace = PR_FALSE ;
2000-04-12 14:54:43 +00:00
if ( wasTransformed ) {
// As long as there were no discarded characters, then don't consider
// skipped leading whitespace as being transformed
if ( wordLen = = contentLen ) {
mState & = ~ TEXT_WAS_TRANSFORMED ;
}
}
2000-03-23 22:58:43 +00:00
// Only set flag when we actually do skip whitespace
mState | = TEXT_SKIP_LEADING_WS ;
continue ;
}
2000-04-17 14:40:46 +00:00
// NOTE: Even if the textRun absorbs the whitespace below, we still
// want to remember that we're breakable.
aTextData . mIsBreakable = PR_TRUE ;
aTextData . mFirstLetterOK = PR_FALSE ;
2000-04-12 14:54:43 +00:00
if ( ' \t ' = = firstChar ) {
2000-03-23 22:58:43 +00:00
// Expand tabs to the proper width
2000-03-31 04:27:43 +00:00
wordLen = 8 - ( 7 & column ) ;
2000-04-17 14:40:46 +00:00
// Apply word spacing to every space derived from a tab
2001-09-28 22:39:10 +00:00
dimensions . width = ( aTs . mSpaceWidth + aTs . mWordSpacing + aTs . mLetterSpacing ) * wordLen ;
2000-04-12 14:54:43 +00:00
// Because we have to expand the tab when rendering consider that
// a transformation of the text
mState | = TEXT_WAS_TRANSFORMED ;
2000-03-23 22:58:43 +00:00
}
2000-03-31 04:27:43 +00:00
else if ( textRun . IsBuffering ( ) ) {
2000-04-04 14:14:47 +00:00
// Add a whitespace segment
textRun . AddSegment ( wordLen , contentLen , PR_TRUE ) ;
2000-03-31 04:27:43 +00:00
continue ;
}
2000-03-23 22:58:43 +00:00
else {
2000-04-17 14:40:46 +00:00
// Apply word spacing to every space, if there's more than one
2001-09-28 22:39:10 +00:00
dimensions . width = wordLen * ( aTs . mWordSpacing + aTs . mLetterSpacing + aTs . mSpaceWidth ) ; // XXX simplistic
2000-03-23 22:58:43 +00:00
}
2000-03-31 04:27:43 +00:00
2001-06-05 02:40:27 +00:00
//Even if there is not enough space for this "space", we still put it
//here instead of next line
2000-03-31 04:27:43 +00:00
prevColumn = column ;
column + = wordLen ;
endsInWhitespace = PR_TRUE ;
prevOffset = aTextData . mOffset ;
aTextData . mOffset + = contentLen ;
2001-06-05 02:40:27 +00:00
if ( aTextData . mMeasureText ) {
//if we're wrapping, then don't add the whitespace width to the
// x-offset unless the whitespace will fit within maxWidth.''
if ( aTextData . mWrapping ) {
2001-09-27 18:34:30 +00:00
if ( aTextData . mX + dimensions . width < = maxWidth ) {
aTextData . mX + = dimensions . width ;
}
2001-12-20 02:25:55 +00:00
else {
// since we didn't add the trailing space width, set this flag so that
// we will not trim this non-existing space
aTextData . mTrailingSpaceTrimmed = PR_TRUE ;
2001-06-05 02:40:27 +00:00
break ;
2001-12-20 02:25:55 +00:00
}
2001-06-05 02:40:27 +00:00
}
else {
//if we're not wrapping, then always advance
// the x-offset regardless of maxWidth
2001-09-27 18:34:30 +00:00
aTextData . mX + = dimensions . width ;
2001-06-05 02:40:27 +00:00
}
} //(aTextData.mMeasureText)
2001-09-27 18:34:30 +00:00
}
else {
2000-03-31 04:27:43 +00:00
// See if the first thing in the section of text is a
// non-breaking space (html nbsp entity). If it is then make
// note of that fact for the line layout logic.
2000-04-12 14:54:43 +00:00
if ( aTextData . mWrapping & & firstThing & & ( firstChar = = ' ' ) ) {
2000-03-31 04:27:43 +00:00
textStartsWithNBSP = PR_TRUE ;
}
aTextData . mSkipWhitespace = PR_FALSE ;
2000-03-23 22:58:43 +00:00
if ( aTextData . mFirstLetterOK ) {
// XXX need a lookup function here; plus look ahead using the
// text-runs
2000-04-12 14:54:43 +00:00
if ( ( firstChar = = ' \' ' ) | | ( firstChar = = ' \" ' ) ) {
2000-07-10 22:32:54 +00:00
if ( contentLen > 1 )
{
wordLen = 2 ;
contentLen = 2 ;
}
2000-03-23 22:58:43 +00:00
}
else {
wordLen = 1 ;
contentLen = 1 ;
}
2000-03-31 04:27:43 +00:00
justDidFirstLetter = PR_TRUE ;
2000-03-23 22:58:43 +00:00
}
if ( aTextData . mMeasureText ) {
2000-03-31 04:27:43 +00:00
if ( measureTextRuns & & ! justDidFirstLetter ) {
// Add another word to the text run
2000-04-04 14:14:47 +00:00
textRun . AddSegment ( wordLen , contentLen , PR_FALSE ) ;
2000-03-31 04:27:43 +00:00
// See if we should measure the text
2000-04-04 14:14:47 +00:00
if ( ( textRun . mTotalNumChars > = estimatedNumChars ) | |
2000-03-31 04:27:43 +00:00
( textRun . mNumSegments > = ( TEXT_MAX_NUM_SEGMENTS - 1 ) ) ) {
goto MeasureTextRun ;
}
2000-03-23 22:58:43 +00:00
}
else {
2000-03-31 04:27:43 +00:00
if ( aTs . mSmallCaps ) {
2001-09-27 18:34:30 +00:00
MeasureSmallCapsText ( aReflowState , aTs , bp2 , wordLen , & dimensions ) ;
2000-03-31 04:27:43 +00:00
}
else {
// Measure just the one word
2000-04-12 14:54:43 +00:00
if ( aTx . TransformedTextIsAscii ( ) ) {
2001-09-27 18:34:30 +00:00
aReflowState . rendContext - > GetTextDimensions ( bp1 , wordLen , dimensions ) ;
2000-04-12 14:54:43 +00:00
} else {
2001-09-27 18:34:30 +00:00
aReflowState . rendContext - > GetTextDimensions ( bp2 , wordLen , dimensions ) ;
2000-04-12 14:54:43 +00:00
}
2000-03-31 04:27:43 +00:00
if ( aTs . mLetterSpacing ) {
2001-09-27 18:34:30 +00:00
dimensions . width + = aTs . mLetterSpacing * wordLen ;
2000-03-31 04:27:43 +00:00
}
}
2001-09-27 18:34:30 +00:00
lastWordDimensions = dimensions ;
2000-03-31 04:27:43 +00:00
// See if there is room for the text
2001-09-27 18:34:30 +00:00
if ( ( 0 ! = aTextData . mX ) & & aTextData . mWrapping & & ( aTextData . mX + dimensions . width > maxWidth ) ) {
2000-03-31 04:27:43 +00:00
// The text will not fit.
break ;
}
prevMaxWordWidth = aTextData . mMaxWordWidth ;
2001-09-27 18:34:30 +00:00
prevAscent = aTextData . mAscent ;
prevDescent = aTextData . mDescent ;
aTextData . mX + = dimensions . width ;
if ( dimensions . width > aTextData . mMaxWordWidth ) {
aTextData . mMaxWordWidth = dimensions . width ;
}
if ( aTextData . mAscent < dimensions . ascent ) {
aTextData . mAscent = dimensions . ascent ;
}
if ( aTextData . mDescent < dimensions . descent ) {
aTextData . mDescent = dimensions . descent ;
2000-03-31 04:27:43 +00:00
}
prevColumn = column ;
column + = wordLen ;
endsInWhitespace = PR_FALSE ;
prevOffset = aTextData . mOffset ;
aTextData . mOffset + = contentLen ;
if ( justDidFirstLetter ) {
// Time to stop
break ;
2000-03-23 22:58:43 +00:00
}
}
}
2000-03-31 04:27:43 +00:00
else {
// We didn't measure the text, but we need to update our state
prevColumn = column ;
column + = wordLen ;
endsInWhitespace = PR_FALSE ;
prevOffset = aTextData . mOffset ;
aTextData . mOffset + = contentLen ;
if ( justDidFirstLetter ) {
// Time to stop
break ;
}
2000-03-23 22:58:43 +00:00
}
}
2000-03-31 04:27:43 +00:00
continue ;
2000-03-23 22:58:43 +00:00
2000-03-31 04:27:43 +00:00
MeasureTextRun :
2001-11-27 22:58:37 +00:00
# if defined(_WIN32) || defined(XP_OS2)
2000-03-31 04:27:43 +00:00
PRInt32 numCharsFit ;
2000-04-17 14:40:46 +00:00
// These calls can return numCharsFit not positioned at a break in the textRun. Beware.
2000-04-12 14:54:43 +00:00
if ( aTx . TransformedTextIsAscii ( ) ) {
2001-09-27 18:34:30 +00:00
aReflowState . rendContext - > GetTextDimensions ( ( char * ) aTx . GetWordBuffer ( ) , textRun . mTotalNumChars ,
2000-04-12 14:54:43 +00:00
maxWidth - aTextData . mX ,
textRun . mBreaks , textRun . mNumSegments ,
2001-09-27 18:34:30 +00:00
dimensions , numCharsFit , lastWordDimensions ) ;
2000-04-12 14:54:43 +00:00
} else {
2001-09-27 18:34:30 +00:00
aReflowState . rendContext - > GetTextDimensions ( aTx . GetWordBuffer ( ) , textRun . mTotalNumChars ,
2000-04-12 14:54:43 +00:00
maxWidth - aTextData . mX ,
textRun . mBreaks , textRun . mNumSegments ,
2001-09-27 18:34:30 +00:00
dimensions , numCharsFit , lastWordDimensions ) ;
2000-04-12 14:54:43 +00:00
}
2000-03-31 04:27:43 +00:00
// See how much of the text fit
2001-09-27 18:34:30 +00:00
if ( ( 0 ! = aTextData . mX ) & & aTextData . mWrapping & & ( aTextData . mX + dimensions . width > maxWidth ) ) {
2000-03-31 04:27:43 +00:00
// None of the text fits
2001-04-11 23:32:21 +00:00
# ifdef IBMBIDI
nextBidi = nsnull ;
# endif // IBMBIDI
2000-03-31 04:27:43 +00:00
break ;
}
// Find the index of the last segment that fit
2000-04-17 14:40:46 +00:00
PRInt32 lastSegment ;
if ( numCharsFit = = textRun . mTotalNumChars ) { // fast path, normal case
lastSegment = textRun . mNumSegments - 1 ;
} else {
2000-03-31 04:27:43 +00:00
for ( lastSegment = 0 ; textRun . mBreaks [ lastSegment ] < numCharsFit ; lastSegment + + ) ;
NS_ASSERTION ( lastSegment < textRun . mNumSegments , " failed to find segment " ) ;
2000-04-17 14:40:46 +00:00
// now we have textRun.mBreaks[lastSegment] >= numCharsFit
/* O'Callahan XXX: This snippet together with the snippet below prevents mail from loading
Justification seems to work just fine without these changes .
We get into trouble in a case where lastSegment gets set to - 1
if ( textRun . mBreaks [ lastSegment ] > numCharsFit ) {
// NOTE: this segment did not actually fit!
lastSegment - - ;
}
*/
2000-03-31 04:27:43 +00:00
}
2000-04-17 14:40:46 +00:00
/* O'Callahan XXX: This snippet together with the snippet above prevents mail from loading
if ( lastSegment < 0 ) {
// no segments fit
break ;
} else */
2000-03-31 04:27:43 +00:00
if ( lastSegment = = 0 ) {
// Only one segment fit
prevColumn = column ;
prevOffset = aTextData . mOffset ;
} else {
// The previous state is for the next to last word
2000-04-17 14:40:46 +00:00
// NOTE: The textRun data are relative to the last updated column and offset!
prevColumn = column + textRun . mBreaks [ lastSegment - 1 ] ;
prevOffset = aTextData . mOffset + textRun . mSegments [ lastSegment - 1 ] . ContentLen ( ) ;
2000-03-31 04:27:43 +00:00
}
2000-04-17 14:40:46 +00:00
2001-09-27 18:34:30 +00:00
aTextData . mX + = dimensions . width ;
if ( aTextData . mAscent < dimensions . ascent ) {
aTextData . mAscent = dimensions . ascent ;
}
if ( aTextData . mDescent < dimensions . descent ) {
aTextData . mDescent = dimensions . descent ;
}
// this is where to backup if line-breaking happens to push the last word
prevAscent = aTextData . mAscent ;
prevDescent = aTextData . mDescent ;
// we can now consider the last word since we know where to backup
if ( aTextData . mAscent < lastWordDimensions . ascent ) {
aTextData . mAscent = lastWordDimensions . ascent ;
}
if ( aTextData . mDescent < lastWordDimensions . descent ) {
aTextData . mDescent = lastWordDimensions . descent ;
}
2000-03-31 04:27:43 +00:00
column + = numCharsFit ;
aTextData . mOffset + = textRun . mSegments [ lastSegment ] . ContentLen ( ) ;
endsInWhitespace = textRun . mSegments [ lastSegment ] . IsWhitespace ( ) ;
// If all the text didn't fit, then we're done
2000-04-04 14:14:47 +00:00
if ( numCharsFit ! = textRun . mTotalNumChars ) {
2001-04-11 23:32:21 +00:00
# ifdef IBMBIDI
nextBidi = nsnull ;
# endif // IBMBIDI
2000-03-31 04:27:43 +00:00
break ;
}
2001-04-11 23:32:21 +00:00
# ifdef IBMBIDI
if ( nextBidi & & ( mContentLength < = 0 ) ) {
break ;
}
# endif // IBMBIDI
2000-04-12 14:54:43 +00:00
if ( nsnull = = bp2 ) {
2000-04-04 14:14:47 +00:00
// No more text so we're all finished. Advance the offset in case the last
// call to GetNextWord() discarded characters
2000-03-31 04:27:43 +00:00
aTextData . mOffset + = contentLen ;
break ;
}
// Reset the number of text run segments
textRun . Reset ( ) ;
2000-04-04 14:14:47 +00:00
// Estimate the remaining number of characters we think will fit
2000-03-31 04:27:43 +00:00
estimatedNumChars = ( maxWidth - aTextData . mX ) / aTs . mAveCharWidth ;
estimatedNumChars + = estimatedNumChars / 20 ;
2000-03-31 05:10:36 +00:00
# else
int unused = - 1 ;
2000-03-23 22:58:43 +00:00
# endif
2000-03-31 04:27:43 +00:00
}
// If we didn't actually measure any text, then make sure it looks
// like we did
if ( ! aTextData . mMeasureText ) {
2001-09-27 18:34:30 +00:00
aTextData . mAscent = mAscent ;
aTextData . mDescent = mRect . height - aTextData . mAscent ;
2000-03-31 04:27:43 +00:00
aTextData . mX = mRect . width ;
if ( mState & TEXT_TRIMMED_WS ) {
// Add back in the width of a space since it was trimmed away last time
2001-09-28 22:39:10 +00:00
// NOTE: Trailing whitespace includes word and letter spacing!
aTextData . mX + = aTs . mSpaceWidth + aTs . mWordSpacing + aTs . mLetterSpacing ;
2000-03-31 04:27:43 +00:00
}
}
// Post processing logic to deal with word-breaking that spans
// multiple frames.
if ( lineLayout . InWord ( ) ) {
// We are already in a word. This means a text frame prior to this
// one had a fragment of a nbword that is joined with this
// frame. It also means that the prior frame already found this
// frame and recorded it as part of the word.
# ifdef DEBUG_WORD_WRAPPING
ListTag ( stdout ) ;
2000-10-28 22:17:53 +00:00
printf ( " : in word; skipping \n " ) ;
2000-03-31 04:27:43 +00:00
# endif
lineLayout . ForgetWordFrame ( this ) ;
}
if ( ! lineLayout . InWord ( ) ) {
// There is no currently active word. This frame may contain the
// start of one.
if ( endsInWhitespace ) {
// Nope, this frame doesn't start a word.
lineLayout . ForgetWordFrames ( ) ;
}
else if ( ( aTextData . mOffset = = contentLength ) & & ( prevOffset > = 0 ) ) {
// Force breakable to false when we aren't wrapping (this
// guarantees that the combined word will stay together)
if ( ! aTextData . mWrapping ) {
aTextData . mIsBreakable = PR_FALSE ;
2000-03-23 22:58:43 +00:00
}
2000-03-31 04:27:43 +00:00
// This frame does start a word. However, there is no point
// messing around with it if we are already out of room. We
// always have room if we are not breakable.
if ( ! aTextData . mIsBreakable | | ( aTextData . mX < = maxWidth ) ) {
// There is room for this word fragment. It's possible that
// this word fragment is the end of the text-run. If it's not
// then we continue with the look-ahead processing.
2000-07-27 05:16:08 +00:00
nsIFrame * next = lineLayout . FindNextText ( aPresContext , this ) ;
2000-03-31 04:27:43 +00:00
if ( nsnull ! = next ) {
# ifdef DEBUG_WORD_WRAPPING
nsAutoString tmp ( aTx . GetWordBuffer ( ) , lastWordLen ) ;
ListTag ( stdout ) ;
2000-10-28 22:17:53 +00:00
printf ( " : start=' " ) ;
2001-10-16 03:53:44 +00:00
fputs ( NS_LossyConvertUCS2toASCII ( tmp ) . get ( ) , stdout ) ;
2000-10-28 22:17:53 +00:00
printf ( " ' lastWordLen=%d baseWidth=%d prevOffset=%d offset=%d next= " ,
2001-09-27 18:34:30 +00:00
lastWordLen , lastWordDimensions . width , prevOffset , aTextData . mOffset ) ;
2000-03-31 04:27:43 +00:00
ListTag ( stdout , next ) ;
2000-10-28 22:17:53 +00:00
printf ( " \n " ) ;
2000-03-31 04:27:43 +00:00
# endif
2000-04-04 14:14:47 +00:00
PRUnichar * pWordBuf = lastWordPtr ;
PRUint32 wordBufLen = aTx . GetWordBufferLength ( ) -
( lastWordPtr - aTx . GetWordBuffer ( ) ) ;
2000-03-31 04:27:43 +00:00
2000-04-12 14:54:43 +00:00
if ( aTx . TransformedTextIsAscii ( ) ) {
// The text transform buffer contains ascii characters, so
// transform it to Unicode
NS_ASSERTION ( wordBufLen > = PRUint32 ( lastWordLen ) , " no room to transform in place " ) ;
TransformTextToUnicode ( ( char * ) lastWordPtr , lastWordLen ) ;
}
2000-03-31 04:27:43 +00:00
// Look ahead in the text-run and compute the final word
// width, taking into account any style changes and stopping
// at the first breakable point.
2001-09-27 18:34:30 +00:00
if ( ! aTextData . mMeasureText | | ( lastWordDimensions . width = = - 1 ) ) {
2000-04-04 14:14:47 +00:00
// We either didn't measure any text or we measured multiple words
2001-09-27 18:34:30 +00:00
// at once so either way we don't know lastWordDimensions. We'll have to
2000-04-04 14:14:47 +00:00
// compute it now
2000-03-31 04:27:43 +00:00
if ( prevOffset = = startingOffset ) {
// There's only one word, so we don't have to measure after all
2001-09-27 18:34:30 +00:00
lastWordDimensions . width = aTextData . mX ;
2000-03-31 04:27:43 +00:00
}
else if ( aTs . mSmallCaps ) {
2000-04-04 14:14:47 +00:00
MeasureSmallCapsText ( aReflowState , aTs , pWordBuf ,
2001-09-27 18:34:30 +00:00
lastWordLen , & lastWordDimensions ) ;
2000-03-31 04:27:43 +00:00
}
else {
2001-09-27 18:34:30 +00:00
aReflowState . rendContext - > GetTextDimensions ( pWordBuf , lastWordLen , lastWordDimensions ) ;
2000-03-31 04:27:43 +00:00
if ( aTs . mLetterSpacing ) {
2001-09-27 18:34:30 +00:00
lastWordDimensions . width + = aTs . mLetterSpacing * lastWordLen ;
2000-03-31 04:27:43 +00:00
}
}
}
2001-09-27 18:34:30 +00:00
nsTextDimensions wordDimensions = ComputeTotalWordDimensions ( aPresContext , aLb ,
2000-03-31 04:27:43 +00:00
lineLayout ,
aReflowState , next ,
2001-09-27 18:34:30 +00:00
lastWordDimensions ,
2000-03-31 04:27:43 +00:00
pWordBuf ,
lastWordLen ,
2002-03-05 23:23:09 +00:00
wordBufLen ,
aTextData . mIsBreakable ) ;
2001-09-27 18:34:30 +00:00
if ( ! aTextData . mIsBreakable | | ( aTextData . mX - lastWordDimensions . width + wordDimensions . width < = maxWidth ) ) {
2000-03-31 04:27:43 +00:00
// The fully joined word has fit. Account for the joined
// word's affect on the max-element-size here (since the
// joined word is large than it's pieces, the right effect
// will occur from the perspective of the container
// reflowing this frame)
2001-09-27 18:34:30 +00:00
if ( wordDimensions . width > aTextData . mMaxWordWidth ) {
aTextData . mMaxWordWidth = wordDimensions . width ;
}
// Now that we now that we will retain the last word, we should
// account for its ascent and descent
if ( aTextData . mAscent < lastWordDimensions . ascent ) {
aTextData . mAscent = lastWordDimensions . ascent ;
}
if ( aTextData . mDescent < lastWordDimensions . descent ) {
aTextData . mDescent = lastWordDimensions . descent ;
2000-03-31 04:27:43 +00:00
}
}
else {
# ifdef NOISY_REFLOW
ListTag ( stdout ) ;
2000-10-28 22:17:53 +00:00
printf ( " : look-ahead (didn't fit) x=%d wordWidth=%d lastWordWidth=%d \n " ,
2001-09-27 18:34:30 +00:00
aTextData . mX , wordDimensions . width , lastWordDimensions . width ) ;
2000-03-31 04:27:43 +00:00
# endif
// The fully joined word won't fit. We need to reduce our
2001-09-27 18:34:30 +00:00
// size by lastWordDimensions
aTextData . mX - = lastWordDimensions . width ;
2000-03-31 04:27:43 +00:00
aTextData . mMaxWordWidth = prevMaxWordWidth ;
aTextData . mOffset = prevOffset ;
column = prevColumn ;
2001-09-27 18:34:30 +00:00
if ( aTextData . mMeasureText ) {
aTextData . mAscent = prevAscent ;
aTextData . mDescent = prevDescent ;
}
// else {
// XXX we didn't measure the text, and so we don't know where to back up,
// we will retain our current height. However, there is a possible
// edge case that is not handled: since we just chopped the last word,
// our remaining text could have got shorter.
// }
2000-03-31 04:27:43 +00:00
# ifdef DEBUG_WORD_WRAPPING
2000-10-28 22:17:53 +00:00
printf ( " x=%d maxWordWidth=%d len=%d \n " , aTextData . mX , aTextData . mMaxWordWidth ,
2000-03-31 04:27:43 +00:00
aTextData . mOffset - startingOffset ) ;
# endif
lineLayout . ForgetWordFrames ( ) ;
}
}
2000-03-23 22:58:43 +00:00
}
}
2000-03-31 04:27:43 +00:00
}
2000-03-23 22:58:43 +00:00
2000-03-31 04:27:43 +00:00
// Inform line layout of how this piece of text ends in whitespace
// (only text objects do this). Note that if x is zero then this
// text object collapsed into nothingness which means it shouldn't
// effect the current setting of the ends-in-whitespace flag.
lineLayout . SetColumn ( column ) ;
lineLayout . SetUnderstandsWhiteSpace ( PR_TRUE ) ;
lineLayout . SetTextStartsWithNBSP ( textStartsWithNBSP ) ;
if ( 0 ! = aTextData . mX ) {
lineLayout . SetEndsInWhiteSpace ( endsInWhitespace ) ;
}
if ( justDidFirstLetter ) {
lineLayout . SetFirstLetterFrame ( this ) ;
lineLayout . SetFirstLetterStyleOK ( PR_FALSE ) ;
mState | = TEXT_FIRST_LETTER ;
2000-03-23 22:58:43 +00:00
}
2000-03-31 04:27:43 +00:00
// Return our reflow status
nsReflowStatus rs = ( aTextData . mOffset = = contentLength )
2001-04-11 23:32:21 +00:00
# ifdef IBMBIDI
| | ( aTextData . mOffset = = start )
# endif // IBMBIDI
2000-03-31 04:27:43 +00:00
? NS_FRAME_COMPLETE
: NS_FRAME_NOT_COMPLETE ;
if ( endsInNewline ) {
rs = NS_INLINE_LINE_BREAK_AFTER ( rs ) ;
}
else if ( ( aTextData . mOffset ! = contentLength ) & & ( aTextData . mOffset = = startingOffset ) ) {
// Break-before a long-word that doesn't fit here
rs = NS_INLINE_LINE_BREAK_BEFORE ( ) ;
}
return rs ;
2000-03-23 22:58:43 +00:00
}
1999-01-22 18:58:14 +00:00
1998-09-08 22:34:40 +00:00
NS_IMETHODIMP
2001-10-29 01:43:59 +00:00
nsTextFrame : : Reflow ( nsIPresContext * aPresContext ,
nsHTMLReflowMetrics & aMetrics ,
1999-04-20 00:23:33 +00:00
const nsHTMLReflowState & aReflowState ,
2001-10-29 01:43:59 +00:00
nsReflowStatus & aStatus )
1998-09-08 22:34:40 +00:00
{
2000-04-21 14:59:47 +00:00
DO_GLOBAL_REFLOW_COUNT ( " nsTextFrame " , aReflowState . reason ) ;
2001-11-14 13:40:03 +00:00
DISPLAY_REFLOW ( aPresContext , this , aReflowState , aMetrics , aStatus ) ;
1999-09-17 23:14:47 +00:00
# ifdef NOISY_REFLOW
ListTag ( stdout ) ;
2000-10-28 22:17:53 +00:00
printf ( " : BeginReflow: availableSize=%d,%d \n " ,
1999-09-17 23:14:47 +00:00
aReflowState . availableWidth , aReflowState . availableHeight ) ;
# endif
1998-09-08 22:34:40 +00:00
1998-11-17 02:14:38 +00:00
// XXX If there's no line layout, we shouldn't even have created this
// frame. This may happen if, for example, this is text inside a table
// but not inside a cell. For now, just don't reflow.
1999-07-20 03:51:46 +00:00
if ( nsnull = = aReflowState . mLineLayout ) {
1999-04-27 22:13:42 +00:00
// XXX Add a method to aMetrics that does this; we do it several places
aMetrics . width = 0 ;
aMetrics . height = 0 ;
aMetrics . ascent = 0 ;
aMetrics . descent = 0 ;
if ( nsnull ! = aMetrics . maxElementSize ) {
aMetrics . maxElementSize - > width = 0 ;
aMetrics . maxElementSize - > height = 0 ;
}
2000-01-07 14:33:11 +00:00
# ifdef MOZ_MATHML
if ( NS_REFLOW_CALC_BOUNDING_METRICS & aMetrics . mFlags )
aMetrics . mBoundingMetrics . Clear ( ) ;
# endif
1998-11-17 02:14:38 +00:00
return NS_OK ;
}
1998-09-08 22:34:40 +00:00
// Get starting offset into the content
PRInt32 startingOffset = 0 ;
1999-10-23 23:19:14 +00:00
nsIFrame * prevInFlow ;
GetPrevInFlow ( & prevInFlow ) ;
if ( nsnull ! = prevInFlow ) {
nsTextFrame * prev = ( nsTextFrame * ) prevInFlow ;
1998-09-08 22:34:40 +00:00
startingOffset = prev - > mContentOffset + prev - > mContentLength ;
1999-09-18 16:22:34 +00:00
// If our starting offset doesn't agree with mContentOffset, then our
// prev-in-flow has changed the number of characters it maps and so we
// need to measure text and not try and optimize a resize reflow
if ( startingOffset ! = mContentOffset ) {
mState & = ~ TEXT_OPTIMIZE_RESIZE ;
}
1998-09-08 22:34:40 +00:00
}
2001-04-11 23:32:21 +00:00
# ifdef IBMBIDI
if ( ( mContentLength > 0 ) & & ( mState & NS_FRAME_IS_BIDI ) ) {
startingOffset = mContentOffset ;
}
2002-06-11 21:00:20 +00:00
PRBool bidiEnabled ;
aPresContext - > GetBidiEnabled ( & bidiEnabled ) ;
if ( bidiEnabled ) {
nsCharType charType = eCharType_LeftToRight ;
PRUint32 hints = 0 ;
aReflowState . rendContext - > GetHints ( hints ) ;
GetBidiProperty ( aPresContext , nsLayoutAtoms : : charType , ( void * * ) & charType , sizeof ( charType ) ) ;
PRBool isBidiSystem = ( eCharType_RightToLeftArabic = = charType ) ?
( hints & NS_RENDERING_HINT_ARABIC_SHAPING ) :
( hints & NS_RENDERING_HINT_BIDI_REORDERING ) ;
aPresContext - > SetIsBidiSystem ( isBidiSystem ) ;
}
2001-04-11 23:32:21 +00:00
# endif //IBMBIDI
1999-07-20 03:51:46 +00:00
nsLineLayout & lineLayout = * aReflowState . mLineLayout ;
1999-11-24 06:03:41 +00:00
TextStyle ts ( aPresContext , * aReflowState . rendContext , mStyleContext ) ;
1998-09-08 22:34:40 +00:00
1999-09-01 01:02:16 +00:00
// Clear out the reflow state flags in mState (without destroying
// the TEXT_BLINK_ON bit).
1999-09-21 00:12:50 +00:00
PRBool lastTimeWeSkippedLeadingWS = 0 ! = ( mState & TEXT_SKIP_LEADING_WS ) ;
1999-09-01 01:02:16 +00:00
mState & = ~ TEXT_REFLOW_FLAGS ;
2001-12-07 14:51:12 +00:00
if ( aReflowState . mFlags . mBlinks ) {
1999-09-01 01:02:16 +00:00
if ( 0 = = ( mState & TEXT_BLINK_ON ) ) {
mState | = TEXT_BLINK_ON ;
2000-03-25 00:49:58 +00:00
nsBlinkTimer : : AddBlinkFrame ( aPresContext , this ) ;
1998-09-08 22:34:40 +00:00
}
}
1998-11-06 00:50:27 +00:00
else {
1999-09-01 01:02:16 +00:00
if ( 0 ! = ( mState & TEXT_BLINK_ON ) ) {
mState & = ~ TEXT_BLINK_ON ;
2000-03-25 00:49:58 +00:00
nsBlinkTimer : : RemoveBlinkFrame ( this ) ;
1998-11-06 00:50:27 +00:00
}
}
1998-09-08 22:34:40 +00:00
1999-03-31 04:12:46 +00:00
PRBool wrapping = ( NS_STYLE_WHITESPACE_NORMAL = = ts . mText - > mWhiteSpace ) | |
( NS_STYLE_WHITESPACE_MOZ_PRE_WRAP = = ts . mText - > mWhiteSpace ) ;
1998-10-26 17:27:53 +00:00
1998-09-08 22:34:40 +00:00
// Set whitespace skip flag
PRBool skipWhitespace = PR_FALSE ;
1999-03-31 04:12:46 +00:00
if ( ! ts . mPreformatted ) {
1998-10-31 22:48:21 +00:00
if ( lineLayout . GetEndsInWhiteSpace ( ) ) {
1998-10-21 20:03:54 +00:00
skipWhitespace = PR_TRUE ;
}
1998-09-08 22:34:40 +00:00
}
1999-01-05 23:31:18 +00:00
nscoord maxWidth = aReflowState . availableWidth ;
1998-09-08 22:34:40 +00:00
1999-09-21 00:12:50 +00:00
// Setup text transformer to transform this frames text content
1999-02-24 18:21:23 +00:00
nsCOMPtr < nsIDocument > doc ;
1999-09-16 23:31:59 +00:00
mContent - > GetDocument ( * getter_AddRefs ( doc ) ) ;
2002-01-24 09:20:51 +00:00
if ( ! doc ) {
NS_WARNING ( " Content has no document. " ) ;
1999-12-07 22:04:52 +00:00
return NS_ERROR_FAILURE ;
}
1999-02-24 18:21:23 +00:00
nsCOMPtr < nsILineBreaker > lb ;
1999-09-19 00:59:38 +00:00
doc - > GetLineBreaker ( getter_AddRefs ( lb ) ) ;
2000-09-20 23:00:32 +00:00
nsTextTransformer tx ( lb , nsnull , aPresContext ) ;
2000-04-12 14:54:43 +00:00
// Keep the text in ascii if possible. Note that if we're measuring small
// caps text then transform to Unicode because the helper function only
// accepts Unicode text
nsresult rv = tx . Init ( this , mContent , startingOffset , ! ts . mSmallCaps ) ;
1998-10-20 00:21:18 +00:00
if ( NS_OK ! = rv ) {
return rv ;
}
2000-05-16 22:48:28 +00:00
//PRInt32 contentLength = tx.GetContentLength();
1998-10-20 00:21:18 +00:00
2000-03-31 04:27:43 +00:00
// Set inWord to true if we are part of a previous piece of text's word. This
1998-10-20 16:46:14 +00:00
// is only valid for one pass through the measuring loop.
2000-03-23 22:58:43 +00:00
PRBool inWord = lineLayout . InWord ( ) | | ( ( nsnull ! = prevInFlow ) & & ( ( ( nsTextFrame * ) prevInFlow ) - > mState & TEXT_FIRST_LETTER ) ) ;
1998-10-20 16:46:14 +00:00
if ( inWord ) {
1999-09-01 01:02:16 +00:00
mState | = TEXT_IN_WORD ;
1998-10-20 16:46:14 +00:00
}
1999-09-01 01:02:16 +00:00
mState & = ~ TEXT_FIRST_LETTER ;
2000-03-23 22:58:43 +00:00
1998-10-21 20:03:54 +00:00
PRInt32 column = lineLayout . GetColumn ( ) ;
2000-03-23 22:58:43 +00:00
PRInt32 prevColumn = mColumn ;
1998-10-21 20:03:54 +00:00
mColumn = column ;
1999-09-18 16:22:34 +00:00
PRBool measureText = PR_TRUE ;
2000-03-23 22:58:43 +00:00
1999-09-18 16:22:34 +00:00
// We can avoid actually measuring the text if:
// - this is a resize reflow
1999-10-08 22:04:31 +00:00
// - we're not dirty (see ContentChanged() function)
1999-09-18 16:22:34 +00:00
// - we don't have a next in flow
1999-09-21 00:12:50 +00:00
// - the previous reflow successfully reflowed all text in the
// available space
1999-09-18 16:22:34 +00:00
// - we aren't computing the max element size (that requires we measure
// text)
1999-10-08 22:04:31 +00:00
// - skipping leading whitespace is the same as it was the last time
// - we're wrapping text and the available width is at least as big as our
// current frame width -or-
// we're not wrapping text and we're at the same column as before (this is
// an issue for preformatted tabbed text only)
2000-04-17 14:40:46 +00:00
// - AND we aren't justified (in which case the frame width has already been tweaked and can't be used)
1999-10-08 22:04:31 +00:00
if ( ( eReflowReason_Resize = = aReflowState . reason ) & &
( 0 = = ( mState & NS_FRAME_IS_DIRTY ) ) ) {
1999-09-21 00:12:50 +00:00
nscoord realWidth = mRect . width ;
if ( mState & TEXT_TRIMMED_WS ) {
2001-09-28 22:39:10 +00:00
// NOTE: Trailing whitespace includes word and letter spacing!
realWidth + = ts . mSpaceWidth + ts . mWordSpacing + ts . mLetterSpacing ;
1999-09-21 00:12:50 +00:00
}
1999-10-08 22:04:31 +00:00
if ( ! mNextInFlow & &
( mState & TEXT_OPTIMIZE_RESIZE ) & &
! aMetrics . maxElementSize & &
1999-09-21 00:12:50 +00:00
( lastTimeWeSkippedLeadingWS = = skipWhitespace ) & &
1999-10-12 23:29:01 +00:00
( ( wrapping & & ( maxWidth > = realWidth ) ) | |
2000-04-17 14:40:46 +00:00
( ! wrapping & & ( prevColumn = = column ) ) ) & &
2001-04-11 23:32:21 +00:00
# ifdef IBMBIDI
( 0 = = ( mState & NS_FRAME_IS_BIDI ) ) & &
# endif // IBMBIDI
2000-04-17 14:40:46 +00:00
! ts . mJustifying ) {
1999-09-21 00:12:50 +00:00
// We can skip measuring of text and use the value from our
// previous reflow
1999-09-18 16:22:34 +00:00
measureText = PR_FALSE ;
1999-10-12 23:29:01 +00:00
# ifdef NOISY_REFLOW
2000-10-28 22:17:53 +00:00
printf ( " => measureText=%s wrapping=%s skipWhitespace=%s " ,
1999-10-12 23:29:01 +00:00
measureText ? " yes " : " no " ,
wrapping ? " yes " : " no " ,
skipWhitespace ? " yes " : " no " ) ;
2000-10-28 22:17:53 +00:00
printf ( " realWidth=%d maxWidth=%d \n " ,
1999-10-12 23:29:01 +00:00
realWidth , maxWidth ) ;
# endif
1999-09-18 16:22:34 +00:00
}
}
2000-03-23 22:58:43 +00:00
// Local state passed to the routines that do the actual text measurement
2000-03-31 04:27:43 +00:00
TextReflowData textData ( startingOffset , wrapping , skipWhitespace ,
2000-03-23 22:58:43 +00:00
measureText , inWord , lineLayout . GetFirstLetterStyleOK ( ) ,
2001-12-20 02:25:55 +00:00
lineLayout . LineIsBreakable ( ) , nsnull ! = aMetrics . maxElementSize ,
PR_FALSE ) ;
2000-03-23 22:58:43 +00:00
2000-03-31 04:27:43 +00:00
// Measure the text
2001-12-20 02:25:55 +00:00
// MeasureText may set TEXT_TRIMMED_WS flag, so don't clear after the call
2002-01-14 13:21:55 +00:00
if ( ts . mFont - > mSize )
aStatus = MeasureText ( aPresContext , aReflowState , tx , lb , ts , textData ) ;
else {
textData . mX = 0 ;
textData . mAscent = 0 ;
textData . mDescent = 0 ;
aStatus = NS_FRAME_COMPLETE ;
}
2001-12-20 02:25:55 +00:00
if ( textData . mTrailingSpaceTrimmed )
mState | = TEXT_TRIMMED_WS ;
else
mState & = ~ TEXT_TRIMMED_WS ;
1999-09-18 16:22:34 +00:00
1998-10-20 00:21:18 +00:00
if ( tx . HasMultibyte ( ) ) {
1999-09-01 01:02:16 +00:00
mState | = TEXT_HAS_MULTIBYTE ;
1998-09-08 22:34:40 +00:00
}
1999-09-18 16:22:34 +00:00
1998-10-20 00:21:18 +00:00
// Setup metrics for caller; store final max-element-size information
2000-03-23 22:58:43 +00:00
aMetrics . width = textData . mX ;
if ( ( 0 = = textData . mX ) & & ! ts . mPreformatted ) {
1998-10-20 00:21:18 +00:00
aMetrics . height = 0 ;
aMetrics . ascent = 0 ;
aMetrics . descent = 0 ;
}
else {
2001-09-27 18:34:30 +00:00
aMetrics . ascent = textData . mAscent ;
aMetrics . descent = textData . mDescent ;
aMetrics . height = aMetrics . ascent + aMetrics . descent ;
1998-10-20 00:21:18 +00:00
}
2001-09-27 18:34:30 +00:00
mAscent = aMetrics . ascent ;
1998-09-08 22:34:40 +00:00
if ( ! wrapping ) {
2000-03-23 22:58:43 +00:00
textData . mMaxWordWidth = textData . mX ;
1998-09-08 22:34:40 +00:00
}
if ( nsnull ! = aMetrics . maxElementSize ) {
2000-03-23 22:58:43 +00:00
aMetrics . maxElementSize - > width = textData . mMaxWordWidth ;
1998-10-20 00:21:18 +00:00
aMetrics . maxElementSize - > height = aMetrics . height ;
1998-09-08 22:34:40 +00:00
}
1998-10-26 17:27:53 +00:00
1998-10-21 20:03:54 +00:00
// Set content offset and length
mContentOffset = startingOffset ;
2000-03-23 22:58:43 +00:00
mContentLength = textData . mOffset - startingOffset ;
1998-10-21 20:03:54 +00:00
2000-04-17 14:40:46 +00:00
// Compute space and letter counts for justification, if required
if ( ts . mJustifying ) {
PRInt32 numSpaces ;
PRInt32 textLength ;
// This will include a space for trailing whitespace, if any is present.
// This is corrected for in nsLineLayout::TrimWhiteSpaceIn.
// This work could be done in MeasureText, but it's complex to do accurately
// there because of the need to repair counts when wrapped words are backed out.
// So I do it via PrepareUnicodeText ... a little slower perhaps, but a lot saner,
// and it localizes the counting logic to one place.
numSpaces = PrepareUnicodeText ( tx , nsnull , nsnull , & textLength ) ;
lineLayout . SetTextJustificationWeights ( numSpaces , textLength - numSpaces ) ;
}
2000-01-07 14:33:11 +00:00
# ifdef MOZ_MATHML
// Simple minded code to also return the bounding metrics if the caller wants it...
// More consolidation is needed -- a better approach is to follow what is done by
// the other routines that are doing measurements.
if ( NS_REFLOW_CALC_BOUNDING_METRICS & aMetrics . mFlags ) {
rv = NS_ERROR_UNEXPECTED ; // initialize with an error; it is reset if things turn out well
aMetrics . mBoundingMetrics . Clear ( ) ;
// Get the text to measure.
nsCOMPtr < nsIDOMText > domText ( do_QueryInterface ( mContent ) ) ;
if ( domText . get ( ) ) {
nsAutoString aData ;
domText - > GetData ( aData ) ;
// Extract the piece of text relevant to us -- XXX whitespace cause a mess here
nsAutoString aText ;
aData . Mid ( aText , mContentOffset , mContentLength ) ;
// Set the font
2002-05-24 20:11:14 +00:00
SetFontFromStyle ( aReflowState . rendContext , mStyleContext ) ;
2000-01-07 14:33:11 +00:00
// Now get the exact bounding metrics of the text
nsBoundingMetrics bm ;
2001-06-30 11:02:25 +00:00
rv = aReflowState . rendContext - > GetBoundingMetrics ( aText . get ( ) , PRUint32 ( mContentLength ) , bm ) ;
2000-01-07 14:33:11 +00:00
if ( NS_SUCCEEDED ( rv ) ) aMetrics . mBoundingMetrics = bm ;
}
if ( NS_FAILED ( rv ) ) {
// Things didn't turn out well, just return the reflow metrics.
2000-01-17 07:34:24 +00:00
aMetrics . mBoundingMetrics . ascent = aMetrics . ascent ;
aMetrics . mBoundingMetrics . descent = aMetrics . descent ;
aMetrics . mBoundingMetrics . width = aMetrics . width ;
# ifdef MOZ_MATHML_BOUNDINGMETRICS
2000-10-28 22:17:53 +00:00
printf ( " nsTextFrame: could not perform GetBoundingMetrics() \n " ) ;
2000-01-17 07:34:24 +00:00
# endif
2000-01-07 14:33:11 +00:00
}
}
# endif
2000-08-16 23:12:19 +00:00
nscoord maxFrameWidth = mRect . width ;
nscoord maxFrameHeight = mRect . height ;
1999-07-14 15:20:01 +00:00
1999-09-18 16:22:34 +00:00
// For future resize reflows we would like to avoid measuring the text.
// We can only do this if after this reflow we're:
// - complete. If we're not complete then our desired width doesn't
// represent our total size
// - we fit in the available space. We may be complete, but if we
// return a larger desired width than is available we may get pushed
// and our frame width won't get set
2002-05-28 22:50:43 +00:00
if ( NS_FRAME_IS_COMPLETE ( aStatus ) & & ( aMetrics . width < = maxWidth ) ) {
1999-09-18 16:22:34 +00:00
mState | = TEXT_OPTIMIZE_RESIZE ;
mRect . width = aMetrics . width ;
}
else {
mState & = ~ TEXT_OPTIMIZE_RESIZE ;
}
2001-02-12 07:06:49 +00:00
2000-08-16 23:12:19 +00:00
// If it's an incremental reflow command, then invalidate our existing
// bounds.
// XXX We need a finer granularity than this, but it isn't clear what
// has actually changed...
2001-02-12 07:06:49 +00:00
/*if (eReflowReason_Incremental == aReflowState.reason ||
eReflowReason_Dirty = = aReflowState . reason ) { */
2001-03-23 14:36:28 +00:00
// XXX See bug 71523 We should really adjust the frames x coordinate to
// a pixel boundary to solve this.
// For now we add 1 pixel to the width of the invalidated rect.
// This fixes cases where the twips to pixel roundoff causes the invalidated
// rect's width to be one pixel short.
float p2t ;
aPresContext - > GetScaledPixelsToTwips ( & p2t ) ;
nscoord onePixel = NSIntPixelsToTwips ( 1 , p2t ) ;
maxFrameWidth = PR_MAX ( maxFrameWidth , mRect . width ) + onePixel ;
2000-08-16 23:12:19 +00:00
maxFrameHeight = PR_MAX ( maxFrameHeight , mRect . height ) ;
2001-11-06 01:44:20 +00:00
nsRect damage ( 0 , 0 , maxFrameWidth , maxFrameHeight ) ;
if ( ! damage . IsEmpty ( ) ) {
Invalidate ( aPresContext , damage ) ;
}
2001-02-12 07:06:49 +00:00
/*}*/
2000-08-16 23:12:19 +00:00
1999-09-17 23:14:47 +00:00
# ifdef NOISY_REFLOW
ListTag ( stdout ) ;
2000-10-28 22:17:53 +00:00
printf ( " : desiredSize=%d,%d(a=%d/d=%d) status=%x \n " ,
1999-09-17 23:14:47 +00:00
aMetrics . width , aMetrics . height , aMetrics . ascent , aMetrics . descent ,
aStatus ) ;
# endif
2002-05-28 22:50:43 +00:00
NS_FRAME_SET_TRUNCATION ( aStatus , aReflowState , aMetrics ) ;
1998-10-21 20:03:54 +00:00
return NS_OK ;
1998-09-08 22:34:40 +00:00
}
2000-07-28 22:29:28 +00:00
NS_IMETHODIMP
nsTextFrame : : CanContinueTextRun ( PRBool & aContinueTextRun ) const
{
// We can continue a text run through a text frame
aContinueTextRun = PR_TRUE ;
return NS_OK ;
}
1998-10-27 16:52:34 +00:00
NS_IMETHODIMP
1999-04-20 00:23:33 +00:00
nsTextFrame : : AdjustFrameSize ( nscoord aExtraSpace , nscoord & aUsedSpace )
1998-10-27 16:52:34 +00:00
{
aUsedSpace = 0 ;
return NS_OK ;
}
NS_IMETHODIMP
1999-05-03 20:55:12 +00:00
nsTextFrame : : TrimTrailingWhiteSpace ( nsIPresContext * aPresContext ,
1999-04-20 00:23:33 +00:00
nsIRenderingContext & aRC ,
nscoord & aDeltaWidth )
1998-10-27 16:52:34 +00:00
{
2001-12-20 02:25:55 +00:00
// in some situation (for instance, in wrapping mode, last space will not
// be added to total width if it exceed maxwidth), this flag will be set
// and we shouldn't trim non-added space
if ( mState & TEXT_TRIMMED_WS ) {
aDeltaWidth = 0 ;
return NS_OK ;
}
1998-10-27 16:52:34 +00:00
nscoord dw = 0 ;
const nsStyleText * textStyle = ( const nsStyleText * )
mStyleContext - > GetStyleData ( eStyleStruct_Text ) ;
1999-09-21 00:12:50 +00:00
if ( mContentLength & &
( NS_STYLE_WHITESPACE_PRE ! = textStyle - > mWhiteSpace ) & &
1999-03-31 04:12:46 +00:00
( NS_STYLE_WHITESPACE_MOZ_PRE_WRAP ! = textStyle - > mWhiteSpace ) ) {
1998-10-27 16:52:34 +00:00
// Get the text fragments that make up our content
1999-09-21 00:12:50 +00:00
nsCOMPtr < nsITextContent > tc = do_QueryInterface ( mContent ) ;
if ( tc ) {
const nsTextFragment * frag ;
1999-10-15 23:36:07 +00:00
tc - > GetText ( & frag ) ;
1999-09-21 00:12:50 +00:00
PRInt32 lastCharIndex = mContentOffset + mContentLength - 1 ;
if ( lastCharIndex < frag - > GetLength ( ) ) {
PRUnichar ch = frag - > CharAt ( lastCharIndex ) ;
if ( XP_IS_SPACE ( ch ) ) {
// Get font metrics for a space so we can adjust the width by the
// right amount.
2002-05-24 20:11:14 +00:00
SetFontFromStyle ( & aRC , mStyleContext ) ;
1999-09-21 00:12:50 +00:00
aRC . GetWidth ( ' ' , dw ) ;
2001-09-28 22:39:10 +00:00
// NOTE: Trailing whitespace includes word and letter spacing!
nsStyleUnit unit ;
unit = textStyle - > mWordSpacing . GetUnit ( ) ;
2000-04-17 14:40:46 +00:00
if ( eStyleUnit_Coord = = unit ) {
dw + = textStyle - > mWordSpacing . GetCoordValue ( ) ;
}
2001-09-28 22:39:10 +00:00
unit = textStyle - > mLetterSpacing . GetUnit ( ) ;
if ( eStyleUnit_Coord = = unit ) {
dw + = textStyle - > mLetterSpacing . GetCoordValue ( ) ;
}
1998-10-27 16:52:34 +00:00
}
}
}
}
1999-09-21 00:12:50 +00:00
# ifdef NOISY_TRIM
ListTag ( stdout ) ;
2000-10-28 22:17:53 +00:00
printf ( " : trim => %d \n " , dw ) ;
1999-09-21 00:12:50 +00:00
# endif
1998-10-27 16:52:34 +00:00
if ( 0 ! = dw ) {
1999-09-01 01:02:16 +00:00
mState | = TEXT_TRIMMED_WS ;
1998-10-27 16:52:34 +00:00
}
else {
1999-09-01 01:02:16 +00:00
mState & = ~ TEXT_TRIMMED_WS ;
1998-10-27 16:52:34 +00:00
}
aDeltaWidth = dw ;
return NS_OK ;
}
1999-11-01 15:36:02 +00:00
static void
RevertSpacesToNBSP ( PRUnichar * aBuffer , PRInt32 aWordLen )
{
PRUnichar * end = aBuffer + aWordLen ;
for ( ; aBuffer < end ; aBuffer + + ) {
PRUnichar ch = * aBuffer ;
if ( ch = = ' ' ) {
* aBuffer = CH_NBSP ;
}
}
}
2001-09-27 18:34:30 +00:00
nsTextDimensions
nsTextFrame : : ComputeTotalWordDimensions ( nsIPresContext * aPresContext ,
1999-09-16 23:31:59 +00:00
nsILineBreaker * aLineBreaker ,
1999-04-20 00:23:33 +00:00
nsLineLayout & aLineLayout ,
const nsHTMLReflowState & aReflowState ,
nsIFrame * aNextFrame ,
2001-09-27 18:34:30 +00:00
const nsTextDimensions & aBaseDimensions ,
1999-11-01 15:36:02 +00:00
PRUnichar * aWordBuf ,
1999-09-22 00:40:56 +00:00
PRUint32 aWordLen ,
2002-03-05 23:23:09 +00:00
PRUint32 aWordBufSize ,
PRBool aIsBreakable )
1998-10-10 04:35:21 +00:00
{
2002-03-05 23:23:09 +00:00
if ( aIsBreakable ) {
// Before we get going, convert any spaces in the current word back
// to nbsp's. This keeps the breaking logic happy.
RevertSpacesToNBSP ( aWordBuf , ( PRInt32 ) aWordLen ) ;
}
1999-11-01 15:36:02 +00:00
2001-09-27 18:34:30 +00:00
nsTextDimensions addedDimensions ;
2001-06-13 21:48:43 +00:00
PRUnichar * newWordBuf = aWordBuf ;
PRUint32 newWordBufSize = aWordBufSize ;
1998-10-10 04:35:21 +00:00
while ( nsnull ! = aNextFrame ) {
2002-05-23 00:00:34 +00:00
nsCOMPtr < nsIContent > content ;
aNextFrame - > GetContent ( getter_AddRefs ( content ) ) ;
1998-10-10 04:35:21 +00:00
# ifdef DEBUG_WORD_WRAPPING
2002-05-23 00:00:34 +00:00
printf ( " next textRun= " ) ;
nsFrame : : ListTag ( stdout , aNextFrame ) ;
printf ( " \n " ) ;
1998-10-10 04:35:21 +00:00
# endif
2001-06-19 22:57:50 +00:00
2002-05-23 00:00:34 +00:00
nsCOMPtr < nsITextContent > tc ( do_QueryInterface ( content ) ) ;
if ( tc ) {
PRBool stop = PR_FALSE ;
nsTextDimensions moreDimensions ;
moreDimensions = ComputeWordFragmentDimensions ( aPresContext ,
aLineBreaker ,
aLineLayout ,
aReflowState ,
aNextFrame , content , tc ,
& stop ,
newWordBuf ,
aWordLen ,
newWordBufSize ,
aIsBreakable ) ;
if ( moreDimensions . width < 0 ) {
PRUint32 moreSize = - moreDimensions . width ;
//Oh, wordBuf is too small, we have to grow it
newWordBufSize + = moreSize ;
if ( newWordBuf ! = aWordBuf ) {
newWordBuf = ( PRUnichar * ) nsMemory : : Realloc ( newWordBuf , sizeof ( PRUnichar ) * newWordBufSize ) ;
NS_ASSERTION ( newWordBuf , " not enough memory " ) ;
} else {
newWordBuf = ( PRUnichar * ) nsMemory : : Alloc ( sizeof ( PRUnichar ) * newWordBufSize ) ;
NS_ASSERTION ( newWordBuf , " not enough memory " ) ;
2001-06-19 22:57:50 +00:00
if ( newWordBuf ) {
2002-05-23 00:00:34 +00:00
memcpy ( ( void * ) newWordBuf , aWordBuf , sizeof ( PRUnichar ) * ( newWordBufSize - moreSize ) ) ;
}
2001-06-13 21:48:43 +00:00
}
2002-05-23 00:00:34 +00:00
if ( newWordBuf ) {
moreDimensions =
ComputeWordFragmentDimensions ( aPresContext , aLineBreaker ,
aLineLayout , aReflowState ,
aNextFrame , content , tc , & stop ,
newWordBuf , aWordLen , newWordBufSize ,
aIsBreakable ) ;
NS_ASSERTION ( ( moreDimensions . width > = 0 ) ,
" ComputeWordFragmentWidth is returning negative " ) ;
} else {
stop = PR_TRUE ;
moreDimensions . Clear ( ) ;
}
}
addedDimensions . Combine ( moreDimensions ) ;
1998-10-10 04:35:21 +00:00
# ifdef DEBUG_WORD_WRAPPING
2002-05-23 00:00:34 +00:00
printf ( " moreWidth=%d (addedWidth=%d) stop=%c \n " , moreDimensions . width ,
addedDimensions . width , stop ? ' T ' : ' F ' ) ;
1998-10-10 04:35:21 +00:00
# endif
2002-05-23 00:00:34 +00:00
if ( stop ) {
1999-04-21 19:59:16 +00:00
goto done ;
}
1998-10-10 04:35:21 +00:00
}
2002-05-23 00:00:34 +00:00
else {
// It claimed it was text but it doesn't implement the
// nsITextContent API. Therefore I don't know what to do with it
// and can't look inside it. Oh well.
goto done ;
}
1998-10-10 04:35:21 +00:00
// Move on to the next frame in the text-run
2000-07-27 05:16:08 +00:00
aNextFrame = aLineLayout . FindNextText ( aPresContext , aNextFrame ) ;
1998-10-10 04:35:21 +00:00
}
done : ;
# ifdef DEBUG_WORD_WRAPPING
2001-09-27 18:34:30 +00:00
printf ( " total word width=%d \n " , aBaseDimensions . width + addedDimensions . width ) ;
1998-10-10 04:35:21 +00:00
# endif
2001-06-19 22:57:50 +00:00
if ( newWordBuf & & ( newWordBuf ! = aWordBuf ) ) {
2001-06-13 21:48:43 +00:00
nsMemory : : Free ( newWordBuf ) ;
2001-06-19 22:57:50 +00:00
}
2001-09-27 18:34:30 +00:00
addedDimensions . Combine ( aBaseDimensions ) ;
return addedDimensions ;
1998-10-10 04:35:21 +00:00
}
1999-04-20 00:23:33 +00:00
2001-09-27 18:34:30 +00:00
nsTextDimensions
nsTextFrame : : ComputeWordFragmentDimensions ( nsIPresContext * aPresContext ,
1999-09-16 23:31:59 +00:00
nsILineBreaker * aLineBreaker ,
1999-04-20 00:23:33 +00:00
nsLineLayout & aLineLayout ,
const nsHTMLReflowState & aReflowState ,
nsIFrame * aTextFrame ,
1999-09-17 23:14:47 +00:00
nsIContent * aContent ,
1999-04-20 00:23:33 +00:00
nsITextContent * aText ,
1999-07-27 14:47:24 +00:00
PRBool * aStop ,
const PRUnichar * aWordBuf ,
1999-09-22 00:40:56 +00:00
PRUint32 & aRunningWordLen ,
2002-03-05 23:23:09 +00:00
PRUint32 aWordBufSize ,
PRBool aIsBreakable )
1998-10-10 04:35:21 +00:00
{
2000-09-20 23:00:32 +00:00
nsTextTransformer tx ( aLineBreaker , nsnull , aPresContext ) ;
1999-09-17 23:14:47 +00:00
tx . Init ( aTextFrame , aContent , 0 ) ;
2000-04-12 14:54:43 +00:00
PRBool isWhitespace , wasTransformed ;
1998-10-20 00:21:18 +00:00
PRInt32 wordLen , contentLen ;
2001-09-27 18:34:30 +00:00
nsTextDimensions dimensions ;
2001-11-14 14:21:52 +00:00
# ifdef IBMBIDI
wordLen = ( mState & NS_FRAME_IS_BIDI ) ? mContentOffset + mContentLength : - 1 ;
# endif // IBMBIDI
2000-04-12 22:22:58 +00:00
PRUnichar * bp = tx . GetNextWord ( PR_TRUE , & wordLen , & contentLen , & isWhitespace , & wasTransformed ) ;
2001-07-09 20:47:58 +00:00
if ( ! bp ) {
//empty text node, but we need to continue lookahead measurement
// AND we need to remember the text frame for later so that we don't
// bother doing the word look ahead.
aLineLayout . RecordWordFrame ( aTextFrame ) ;
2001-09-27 18:34:30 +00:00
return dimensions ; // 0
2001-07-09 20:47:58 +00:00
}
if ( isWhitespace ) {
1998-10-10 04:35:21 +00:00
// Don't bother measuring nothing
1999-04-20 00:23:33 +00:00
* aStop = PR_TRUE ;
2001-09-27 18:34:30 +00:00
return dimensions ; // 0
1998-10-10 04:35:21 +00:00
}
2001-06-13 21:48:43 +00:00
// We need to adjust the length by look at the two pieces together
// but if we have to grow aWordBuf, ask caller do it by return a negative value of size
2001-09-27 18:34:30 +00:00
if ( ( wordLen + aRunningWordLen ) > aWordBufSize ) {
dimensions . width = aWordBufSize - wordLen - aRunningWordLen ;
return dimensions ;
}
1999-04-20 00:23:33 +00:00
* aStop = contentLen < tx . GetContentLength ( ) ;
1998-10-10 04:35:21 +00:00
2002-03-05 23:23:09 +00:00
if ( aIsBreakable ) {
// Convert any spaces in the current word back to nbsp's. This keeps
// the breaking logic happy.
RevertSpacesToNBSP ( bp , wordLen ) ;
1999-07-27 14:47:24 +00:00
2002-03-05 23:23:09 +00:00
if ( wordLen > 0 )
1999-07-27 14:47:24 +00:00
{
2002-03-05 23:23:09 +00:00
memcpy ( ( void * ) & ( aWordBuf [ aRunningWordLen ] ) , bp , sizeof ( PRUnichar ) * wordLen ) ;
PRUint32 breakP = 0 ;
PRBool needMore = PR_TRUE ;
nsresult lres = aLineBreaker - > Next ( aWordBuf , aRunningWordLen + wordLen ,
0 , & breakP , & needMore ) ;
if ( NS_SUCCEEDED ( lres ) )
{
// when we look at two pieces text together, we might decide to break
// eariler than if we only look at the 2nd pieces of text
if ( ! needMore & & ( breakP < ( aRunningWordLen + wordLen ) ) )
{
wordLen = breakP - aRunningWordLen ;
if ( wordLen < 0 )
wordLen = 0 ;
* aStop = PR_TRUE ;
}
}
// if we don't stop, we need to extend the buf so the next one can
// see this part otherwise, it does not matter since we will stop
// anyway
if ( ! * aStop )
aRunningWordLen + = wordLen ;
}
1999-07-27 14:47:24 +00:00
}
if ( ( * aStop ) & & ( wordLen = = 0 ) )
2001-09-27 18:34:30 +00:00
return dimensions ; // 0;
1999-07-27 14:47:24 +00:00
1999-09-22 00:40:56 +00:00
nsCOMPtr < nsIStyleContext > sc ;
aTextFrame - > GetStyleContext ( getter_AddRefs ( sc ) ) ;
if ( sc ) {
1998-10-10 04:35:21 +00:00
// Measure the piece of text. Note that we have to select the
// appropriate font into the text first because the rendering
// context has our font in it, not the font that aText is using.
nsIRenderingContext & rc = * aReflowState . rendContext ;
1999-09-22 00:40:56 +00:00
nsCOMPtr < nsIFontMetrics > oldfm ;
rc . GetFontMetrics ( * getter_AddRefs ( oldfm ) ) ;
1998-10-26 17:27:53 +00:00
1999-11-24 06:03:41 +00:00
TextStyle ts ( aLineLayout . mPresContext , rc , sc ) ;
1998-10-26 17:27:53 +00:00
if ( ts . mSmallCaps ) {
2001-09-27 18:34:30 +00:00
MeasureSmallCapsText ( aReflowState , ts , bp , wordLen , & dimensions ) ;
1998-10-20 00:21:18 +00:00
}
else {
2001-09-27 18:34:30 +00:00
rc . GetTextDimensions ( bp , wordLen , dimensions ) ;
2000-04-17 14:40:46 +00:00
// NOTE: Don't forget to add letter spacing for the word fragment!
2001-09-27 18:34:30 +00:00
dimensions . width + = wordLen * ts . mLetterSpacing ;
1998-10-20 00:21:18 +00:00
}
1998-10-10 04:35:21 +00:00
rc . SetFont ( oldfm ) ;
1998-10-20 00:21:18 +00:00
1998-10-10 04:35:21 +00:00
# ifdef DEBUG_WORD_WRAPPING
1998-10-20 00:21:18 +00:00
nsAutoString tmp ( bp , wordLen ) ;
2000-10-28 22:17:53 +00:00
printf ( " fragment=' " ) ;
2001-10-16 03:53:44 +00:00
fputs ( NS_LossyConvertUCS2toASCII ( tmp ) . get ( ) , stdout ) ;
2000-10-28 22:17:53 +00:00
printf ( " ' width=%d [wordLen=%d contentLen=%d ContentLength=%d] \n " ,
2001-09-27 18:34:30 +00:00
dimensions . width , wordLen , contentLen , tx . GetContentLength ( ) ) ;
1998-10-10 04:35:21 +00:00
# endif
// Remember the text frame for later so that we don't bother doing
// the word look ahead.
aLineLayout . RecordWordFrame ( aTextFrame ) ;
2001-09-27 18:34:30 +00:00
return dimensions ;
1998-10-10 04:35:21 +00:00
}
1999-04-20 00:23:33 +00:00
* aStop = PR_TRUE ;
2001-09-27 18:34:30 +00:00
return dimensions ; // 0
1998-10-10 04:35:21 +00:00
}
1998-10-20 00:21:18 +00:00
// Translate the mapped content into a string that's printable
void
1999-10-15 23:36:07 +00:00
nsTextFrame : : ToCString ( nsString & aBuf , PRInt32 * aTotalContentLength ) const
1998-09-08 22:34:40 +00:00
{
1998-10-20 00:21:18 +00:00
const nsTextFragment * frag ;
// Get the frames text content
2002-05-23 00:00:34 +00:00
nsCOMPtr < nsITextContent > tc ( do_QueryInterface ( mContent ) ) ;
if ( ! tc ) {
1998-10-20 00:21:18 +00:00
return ;
}
1999-10-15 23:36:07 +00:00
tc - > GetText ( & frag ) ;
1998-10-20 00:21:18 +00:00
// Compute the total length of the text content.
1999-10-15 23:36:07 +00:00
* aTotalContentLength = frag - > GetLength ( ) ;
1998-10-20 00:21:18 +00:00
// Set current fragment and current fragment offset
if ( 0 = = mContentLength ) {
return ;
}
1999-10-15 23:36:07 +00:00
PRInt32 fragOffset = mContentOffset ;
1999-10-19 23:01:58 +00:00
PRInt32 n = fragOffset + mContentLength ;
1999-10-15 23:36:07 +00:00
while ( fragOffset < n ) {
PRUnichar ch = frag - > CharAt ( fragOffset + + ) ;
1998-09-08 22:34:40 +00:00
if ( ch = = ' \r ' ) {
2001-12-16 11:58:03 +00:00
aBuf . Append ( NS_LITERAL_STRING ( " \\ r " ) ) ;
1998-09-08 22:34:40 +00:00
} else if ( ch = = ' \n ' ) {
2001-12-16 11:58:03 +00:00
aBuf . Append ( NS_LITERAL_STRING ( " \\ n " ) ) ;
1998-09-08 22:34:40 +00:00
} else if ( ch = = ' \t ' ) {
2001-12-16 11:58:03 +00:00
aBuf . Append ( NS_LITERAL_STRING ( " \\ t " ) ) ;
1998-09-08 22:34:40 +00:00
} else if ( ( ch < ' ' ) | | ( ch > = 127 ) ) {
2001-12-16 11:58:03 +00:00
aBuf . Append ( NS_LITERAL_STRING ( " \\ 0 " ) ) ;
2000-04-15 21:18:29 +00:00
aBuf . AppendInt ( ( PRInt32 ) ch , 8 ) ;
1998-09-08 22:34:40 +00:00
} else {
aBuf . Append ( ch ) ;
}
}
}
1999-02-24 05:33:40 +00:00
NS_IMETHODIMP
1999-04-20 00:23:33 +00:00
nsTextFrame : : GetFrameType ( nsIAtom * * aType ) const
1999-02-24 05:33:40 +00:00
{
NS_PRECONDITION ( nsnull ! = aType , " null OUT parameter pointer " ) ;
* aType = nsLayoutAtoms : : textFrame ;
NS_ADDREF ( * aType ) ;
return NS_OK ;
}
2001-10-25 01:08:40 +00:00
NS_IMETHODIMP
nsTextFrame : : IsEmpty ( PRBool aIsQuirkMode , PRBool aIsPre , PRBool * aResult )
{
// XXXldb Should this check aIsQuirkMode as well???
if ( aIsPre ) {
* aResult = PR_FALSE ;
return NS_OK ;
}
nsCOMPtr < nsITextContent > textContent ( do_QueryInterface ( mContent ) ) ;
if ( ! textContent ) {
NS_NOTREACHED ( " text frame has no text content " ) ;
* aResult = PR_TRUE ;
return NS_ERROR_UNEXPECTED ;
}
return textContent - > IsOnlyWhitespace ( aResult ) ;
}
1999-09-01 01:02:16 +00:00
# ifdef DEBUG
1999-08-31 03:09:40 +00:00
NS_IMETHODIMP
nsTextFrame : : SizeOf ( nsISizeOfHandler * aHandler , PRUint32 * aResult ) const
{
if ( ! aResult ) {
return NS_ERROR_NULL_POINTER ;
}
* aResult = sizeof ( * this ) ;
return NS_OK ;
}
1998-09-08 22:34:40 +00:00
NS_IMETHODIMP
2001-11-14 01:33:42 +00:00
nsTextFrame : : GetFrameName ( nsAString & aResult ) const
1998-09-08 22:34:40 +00:00
{
2001-11-14 01:33:42 +00:00
return MakeFrameName ( NS_LITERAL_STRING ( " Text " ) , aResult ) ;
1998-09-08 22:34:40 +00:00
}
NS_IMETHODIMP
1999-10-26 04:44:41 +00:00
nsTextFrame : : List ( nsIPresContext * aPresContext , FILE * out , PRInt32 aIndent ) const
1998-09-08 22:34:40 +00:00
{
// Output the tag
1999-03-05 04:28:40 +00:00
IndentBy ( out , aIndent ) ;
1998-09-08 22:34:40 +00:00
ListTag ( out ) ;
2000-07-27 05:16:08 +00:00
# ifdef DEBUG_waterson
2000-10-28 22:17:53 +00:00
fprintf ( out , " [parent=%p] " , mParent ) ;
2000-07-27 05:16:08 +00:00
# endif
1998-09-08 22:34:40 +00:00
nsIView * view ;
1999-10-26 04:44:41 +00:00
GetView ( aPresContext , & view ) ;
1998-09-08 22:34:40 +00:00
if ( nsnull ! = view ) {
2001-10-25 01:08:40 +00:00
fprintf ( out , " [view=%p] " , NS_STATIC_CAST ( void * , view ) ) ;
1998-09-08 22:34:40 +00:00
}
1999-10-15 23:36:07 +00:00
PRInt32 totalContentLength ;
1998-10-20 00:21:18 +00:00
nsAutoString tmp ;
1999-10-15 23:36:07 +00:00
ToCString ( tmp , & totalContentLength ) ;
1998-09-08 22:34:40 +00:00
1998-10-20 00:21:18 +00:00
// Output the first/last content offset and prev/next in flow info
1999-10-15 23:36:07 +00:00
PRBool isComplete = ( mContentOffset + mContentLength ) = = totalContentLength ;
1999-09-01 01:02:16 +00:00
fprintf ( out , " [%d,%d,%c] " ,
1999-09-21 00:12:50 +00:00
mContentOffset , mContentLength ,
1999-09-01 01:02:16 +00:00
isComplete ? ' T ' : ' F ' ) ;
1999-03-26 00:41:36 +00:00
1999-04-27 22:13:42 +00:00
if ( nsnull ! = mNextSibling ) {
2001-10-25 01:08:40 +00:00
fprintf ( out , " next=%p " , NS_STATIC_CAST ( void * , mNextSibling ) ) ;
1999-04-27 22:13:42 +00:00
}
1999-10-23 23:19:14 +00:00
nsIFrame * prevInFlow ;
GetPrevInFlow ( & prevInFlow ) ;
if ( nsnull ! = prevInFlow ) {
2001-10-25 01:08:40 +00:00
fprintf ( out , " prev-in-flow=%p " , NS_STATIC_CAST ( void * , prevInFlow ) ) ;
1998-09-08 22:34:40 +00:00
}
if ( nsnull ! = mNextInFlow ) {
2001-10-25 01:08:40 +00:00
fprintf ( out , " next-in-flow=%p " , NS_STATIC_CAST ( void * , mNextInFlow ) ) ;
1998-09-08 22:34:40 +00:00
}
// Output the rect and state
1999-03-05 04:28:40 +00:00
fprintf ( out , " {%d,%d,%d,%d} " , mRect . x , mRect . y , mRect . width , mRect . height ) ;
1998-09-08 22:34:40 +00:00
if ( 0 ! = mState ) {
2001-01-27 14:09:34 +00:00
if ( mState & NS_FRAME_SELECTED_CONTENT ) {
fprintf ( out , " [state=%08x] SELECTED " , mState ) ;
} else {
fprintf ( out , " [state=%08x] " , mState ) ;
}
1998-09-08 22:34:40 +00:00
}
2001-10-25 01:08:40 +00:00
fprintf ( out , " sc=%p< \n " , NS_STATIC_CAST ( void * , mStyleContext ) ) ;
1998-09-08 22:34:40 +00:00
// Output the text
aIndent + + ;
1999-03-05 04:28:40 +00:00
IndentBy ( out , aIndent ) ;
2000-10-28 22:17:53 +00:00
fputs ( " \" " , out ) ;
2001-10-16 03:53:44 +00:00
fputs ( NS_LossyConvertUCS2toASCII ( tmp ) . get ( ) , out ) ;
2000-10-28 22:17:53 +00:00
fputs ( " \" \n " , out ) ;
1998-09-08 22:34:40 +00:00
aIndent - - ;
1999-03-05 04:28:40 +00:00
IndentBy ( out , aIndent ) ;
2000-10-28 22:17:53 +00:00
fputs ( " > \n " , out ) ;
1998-09-08 22:34:40 +00:00
return NS_OK ;
}
1999-11-01 22:12:45 +00:00
# endif
2001-04-11 23:32:21 +00:00
# ifdef IBMBIDI
2001-10-24 11:12:31 +00:00
void nsTextFrame : : AdjustSelectionPointsForBidi ( SelectionDetails * sdptr ,
PRInt32 textLength ,
PRBool isRTLChars ,
PRBool isOddLevel ,
PRBool isBidiSystem )
{
/* This adjustment is required whenever the text has been reversed by
* Mozilla before rendering .
*
* In theory this means any text whose Bidi embedding level has been
* set by the Unicode Bidi algorithm to an odd value , but this is
* only true in practice on a non - Bidi platform .
*
* On a Bidi platform the situation is more complicated because the
* platform will automatically reverse right - to - left characters ; so
* Mozilla reverses text whose natural directionality is the opposite
* of its embedding level : right - to - left characters whose Bidi
* embedding level is even ( e . g . Visual Hebrew ) or left - to - right and
* neutral characters whose Bidi embedding level is odd ( e . g . English
* text with < bdo dir = " rtl " > ) .
*
* The following condition is accordingly an optimization of
* if ( ( ! isBidiSystem & & isOddLevel ) | |
* ( isBidiSystem & &
* ( ( isRTLChars & & ! isOddLevel ) | |
* ( ! isRTLChars & & isOddLevel ) ) ) )
*/
if ( isOddLevel ^ ( isRTLChars & & isBidiSystem ) ) {
PRInt32 swap = sdptr - > mStart ;
sdptr - > mStart = textLength - sdptr - > mEnd ;
sdptr - > mEnd = textLength - swap ;
// temp fix for 75026 crasher untill we fix the bidi code
// the above bidi code cause mStart < 0 in some case
// the problem is we have whitespace compression code in
// nsTextTransformer which cause mEnd > textLength
NS_ASSERTION ( ( sdptr - > mStart > = 0 ) , " mStart >= 0 " ) ;
if ( sdptr - > mStart < 0 )
sdptr - > mStart = 0 ;
NS_ASSERTION ( ( sdptr - > mEnd > = 0 ) , " mEnd >= 0 " ) ;
if ( sdptr - > mEnd < 0 )
sdptr - > mEnd = 0 ;
NS_ASSERTION ( ( sdptr - > mStart < = sdptr - > mEnd ) , " mStart <= mEnd " ) ;
if ( sdptr - > mStart > sdptr - > mEnd )
sdptr - > mEnd = sdptr - > mStart ;
}
return ;
}
2001-04-11 23:32:21 +00:00
NS_IMETHODIMP
nsTextFrame : : SetOffsets ( PRInt32 aStart , PRInt32 aEnd )
{
mContentOffset = aStart ;
mContentLength = aEnd - aStart ;
return NS_OK ;
}
# endif // IBMBIDI