1998-09-08 22:34:40 +00:00
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
1999-11-06 03:40:37 +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
*
1999-11-06 03:40:37 +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 .
*
* The Initial Developer of the Original Code is Netscape
1998-09-08 22:34:40 +00:00
* Communications Corporation . Portions created by Netscape are
1999-11-06 03:40:37 +00:00
* Copyright ( C ) 1998 Netscape Communications Corporation . All
* Rights Reserved .
*
* Contributor ( s ) :
2000-02-02 22:24:56 +00:00
* Pierre Phaneuf < pp @ ludusdesign . com >
1998-09-08 22:34:40 +00:00
*/
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"
# 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 "nsHTMLIIDs.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-09-08 22:34:40 +00:00
# include "nsXIFConverter.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"
1999-04-20 00:23:33 +00:00
# include "nsTextRun.h"
1998-10-20 00:21:18 +00:00
# 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"
1999-04-26 04:02:04 +00:00
# include "nsIDOMSelection.h"
# include "nsIDOMRange.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
//tripple click includes
# include "nsIPref.h"
# include "nsIServiceManager.h"
1999-09-15 01:57:50 +00:00
# ifndef PR_ABS
2000-03-11 16:50:52 +00:00
# define PR_ABS(x) ((x) < 0 ? -(x) : (x))
1999-09-15 01:57:50 +00:00
# endif
1998-09-08 22:34:40 +00:00
static NS_DEFINE_IID ( kIDOMTextIID , NS_IDOMTEXT_IID ) ;
1999-10-13 01:15:26 +00:00
static NS_DEFINE_CID ( kPrefCID , NS_PREF_CID ) ; //for tripple click pref
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
1999-09-22 00:40:56 +00:00
//----------------------------------------------------------------------
# define TEXT_BUF_SIZE 100
//----------------------------------------
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 )
{
2000-02-14 01:54:20 +00:00
nsCRT : : 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 ;
}
nsCRT : : memset ( newBuffer , 0 , sizeof ( PRInt32 ) * newSize ) ;
nsCRT : : memcpy ( newBuffer , mBuffer , sizeof ( PRInt32 ) * mBufferLen ) ;
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-03-25 00:49:58 +00:00
nsITimer * mTimer ;
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 ( ) ;
mTimer = nsnull ;
}
nsBlinkTimer : : ~ nsBlinkTimer ( )
{
Stop ( ) ;
2000-03-25 00:49:58 +00:00
sTextBlinker = nsnull ;
1999-04-20 00:23:33 +00:00
}
void nsBlinkTimer : : Start ( )
{
nsresult rv = NS_NewTimer ( & mTimer ) ;
if ( NS_OK = = rv ) {
2000-01-21 21:56:09 +00:00
mTimer - > Init ( this , 750 , NS_PRIORITY_NORMAL , NS_TYPE_REPEATING_PRECISE ) ;
1999-04-20 00:23:33 +00:00
}
}
void nsBlinkTimer : : Stop ( )
{
if ( nsnull ! = mTimer ) {
mTimer - > Cancel ( ) ;
NS_RELEASE ( mTimer ) ;
}
}
static NS_DEFINE_IID ( kITimerCallbackIID , NS_ITIMERCALLBACK_IID ) ;
NS_IMPL_ISUPPORTS ( nsBlinkTimer , kITimerCallbackIID ) ;
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 ) ;
printf ( " %s \n " , buf ) ;
# 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
//----------------------------------------------------------------------
1999-10-23 23:19:14 +00:00
class nsTextFrame : public nsFrame {
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
1999-11-24 06:03:41 +00:00
NS_IMETHOD Paint ( nsIPresContext * aPresContext ,
1998-09-08 22:34:40 +00:00
nsIRenderingContext & aRenderingContext ,
1998-12-18 15:54:23 +00:00
const nsRect & aDirtyRect ,
nsFramePaintLayer aWhichLayer ) ;
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 ;
1999-11-01 22:12:45 +00:00
NS_IMETHOD GetFrameName ( nsString & 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 ) ;
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 ) ;
1998-10-03 04:28:05 +00:00
// nsIHTMLReflow
1998-10-09 23:46:02 +00:00
NS_IMETHOD FindTextRuns ( nsLineLayout & aLineLayout ) ;
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 ) ;
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 ;
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 ;
1998-10-27 16:52:34 +00:00
PRIntn mNumSpaces ;
nscoord mExtraSpacePerSpace ;
nscoord mRemainingExtraSpace ;
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 ) ;
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.
PRUint8 originalDecorations = plainFont - > decorations ;
plainFont - > decorations = NS_FONT_DECORATION_NONE ;
aPresContext - > GetMetricsFor ( * plainFont , & mNormalFont ) ;
1998-10-26 17:27:53 +00:00
aRenderingContext . SetFont ( mNormalFont ) ;
aRenderingContext . GetWidth ( ' ' , mSpaceWidth ) ;
2000-03-31 05:10:36 +00:00
# ifdef _WIN32
2000-03-31 04:27:43 +00:00
mNormalFont - > GetAveCharWidth ( mAveCharWidth ) ;
2000-03-31 05:10:36 +00:00
# else
2000-03-31 05:40:35 +00:00
mAveCharWidth = 10 ;
2000-03-31 05:10:36 +00:00
# endif
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
1998-10-26 17:27:53 +00:00
// XXX Get these from style
mSelectionBGColor = NS_RGB ( 0 , 0 , 0 ) ;
mSelectionTextColor = NS_RGB ( 255 , 255 , 255 ) ;
// Get the word and letter spacing
mWordSpacing = 0 ;
mLetterSpacing = 0 ;
1999-03-31 04:12:46 +00:00
PRIntn unit = mText - > mWordSpacing . GetUnit ( ) ;
if ( eStyleUnit_Coord = = unit ) {
mWordSpacing = mText - > mWordSpacing . GetCoordValue ( ) ;
}
unit = mText - > mLetterSpacing . GetUnit ( ) ;
if ( eStyleUnit_Coord = = unit ) {
mLetterSpacing = mText - > mLetterSpacing . GetCoordValue ( ) ;
1998-10-26 17:27:53 +00:00
}
1998-10-27 16:52:34 +00:00
mNumSpaces = 0 ;
mRemainingExtraSpace = 0 ;
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 ) ;
1998-10-26 17:27:53 +00:00
}
~ TextStyle ( ) {
NS_RELEASE ( mNormalFont ) ;
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
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
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 ,
PRBool aComputeMaxWordWidth )
2000-03-23 22:58:43 +00:00
: mX ( 0 ) ,
mOffset ( aStartingOffset ) ,
mMaxWordWidth ( 0 ) ,
mWrapping ( aWrapping ) ,
mSkipWhitespace ( aSkipWhitespace ) ,
mMeasureText ( aMeasureText ) ,
mInWord ( aInWord ) ,
mFirstLetterOK ( aFirstLetterOK ) ,
mIsBreakable ( aIsBreakable ) ,
2000-03-31 04:27:43 +00:00
mComputeMaxWordWidth ( aComputeMaxWordWidth )
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 ) ;
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 ,
1999-04-20 00:23:33 +00:00
nscoord * aWidthResult ) ;
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 ) ;
1998-10-26 17:27:53 +00:00
void GetWidth ( nsIRenderingContext & aRenderingContext ,
TextStyle & aStyle ,
PRUnichar * aBuffer , PRInt32 aLength ,
1999-04-20 00:23:33 +00:00
nscoord * aWidthResult ) ;
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 ) ;
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 ) ;
1999-04-20 00:23:33 +00:00
nscoord ComputeTotalWordWidth ( 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-07-27 14:47:24 +00:00
nscoord aBaseWidth ,
1999-11-01 15:36:02 +00:00
PRUnichar * aWordBuf ,
1999-07-27 14:47:24 +00:00
PRUint32 aWordBufLen ,
PRUint32 aWordBufSize ) ;
1998-10-10 04:35:21 +00:00
1999-04-20 00:23:33 +00:00
nscoord ComputeWordFragmentWidth ( 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 ,
PRUint32 aWordBufSize ) ;
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
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 ;
2000-03-31 07:26:07 +00:00
//factored out method for getwidth and getlengthslowly. if aGetWidth is non-zero number then measure to that width and return the length. else shove total width into result
PRInt32 GetWidthOrLength ( nsIRenderingContext & aRenderingContext ,
TextStyle & aStyle ,
PRUnichar * aBuffer , PRInt32 aLength ,
nscoord * aWidthResult ,
PRBool aGetWidth /* true=get width false = return length up to aWidthResult size*/ ) ;
2000-04-02 05:05:31 +00:00
nsresult GetContentAndOffsetsForSelection ( nsIPresContext * aPresContext , nsIContent * * aContent , PRInt32 * aOffset , PRInt32 * aLength ) ;
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 ) ;
}
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
//DRAW SELECTION ITERATOR USED FOR TEXTFRAMES ONLY
//helper class for drawing multiply selected text
class DrawSelectionIterator
{
enum { SELECTION_TYPES_WE_CARE_ABOUT = SELECTION_NONE + SELECTION_NORMAL } ;
public :
DrawSelectionIterator ( const SelectionDetails * aSelDetails , PRUnichar * aText , PRUint32 aTextLength , nsTextFrame : : TextStyle & aTextStyle ) ;
PRBool First ( ) ;
PRBool Next ( ) ;
PRBool IsDone ( ) ;
PRUnichar * CurrentTextUnicharPtr ( ) ;
char * CurrentTextCStrPtr ( ) ;
PRUint32 CurrentLength ( ) ;
nsTextFrame : : TextStyle & CurrentStyle ( ) ;
nscolor CurrentForeGroundColor ( ) ;
PRBool CurrentBackGroundColor ( nscolor & aColor ) ;
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 ;
//private methods
void FillCurrentData ( ) ;
} ;
DrawSelectionIterator : : DrawSelectionIterator ( const SelectionDetails * aSelDetails , PRUnichar * aText ,
PRUint32 aTextLength , nsTextFrame : : TextStyle & aTextStyle )
: mOldStyle ( aTextStyle )
{
mDetails = aSelDetails ;
mCurrentIdx = 0 ;
mUniStr = aText ;
mLength = aTextLength ;
mTypes = nsnull ;
mInit = PR_FALSE ;
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 )
{
if ( ! ( details - > mType & SELECTION_TYPES_WE_CARE_ABOUT ) )
continue ;
if ( details - > mStart = = details - > mEnd )
continue ; //collapsed selections need not apply
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
}
details = details - > mNext ;
}
}
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-03-31 11:09:28 +00:00
mInit = PR_TRUE ;
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 )
return ;
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 ( )
{
if ( ! mTypes )
{
if ( mCurrentIdx = = ( PRUint32 ) mDetails - > mStart )
return NS_RGB ( 255 , 255 , 255 ) ;
}
else if ( mTypes [ mCurrentIdx ] | SELECTION_NORMAL ) / / Find color based on mTypes [ mCurrentIdx ] ;
return NS_RGB ( 255 , 255 , 255 ) ;
return mOldStyle . mColor - > mColor ;
}
PRBool
DrawSelectionIterator : : CurrentBackGroundColor ( nscolor & aColor )
{
//Find color based on mTypes[mCurrentIdx];
if ( ! mTypes )
{
if ( mCurrentIdx = = ( PRUint32 ) mDetails - > mStart )
{
aColor = NS_RGB ( 0 , 128 , 0 ) ;
2000-03-31 11:09:28 +00:00
return PR_TRUE ;
2000-03-31 07:26:07 +00:00
}
}
else if ( mTypes [ mCurrentIdx ] | SELECTION_NORMAL )
{
aColor = NS_RGB ( 0 , 128 , 0 ) ;
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
}
//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
1998-10-20 00:21:18 +00:00
1999-09-01 01:02:16 +00:00
# define TEXT_HAS_MULTIBYTE 0x02000000
1998-09-08 22:34:40 +00:00
1999-09-01 01:02:16 +00:00
# define TEXT_IN_WORD 0x04000000
1998-09-08 22:34:40 +00:00
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
1999-09-01 01:02:16 +00:00
// Bits in mState used for reflow flags
1999-09-21 00:12:50 +00:00
# define TEXT_REFLOW_FLAGS 0x0F000000
# 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
{
}
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
}
}
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
{
1998-11-18 05:25:26 +00:00
const nsStyleColor * styleColor ;
GetStyleData ( eStyleStruct_Color , ( const nsStyleStruct * & ) styleColor ) ;
aCursor = styleColor - > mCursor ;
1999-01-14 05:16:23 +00:00
if ( NS_STYLE_CURSOR_AUTO = = aCursor & & nsnull ! = mParent ) {
mParent - > GetCursor ( aPresContext , aPoint , aCursor ) ;
1998-11-18 05:25:26 +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 ;
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
1999-11-24 06:03:41 +00:00
nsTextFrame : : Paint ( nsIPresContext * aPresContext ,
1999-04-20 00:23:33 +00:00
nsIRenderingContext & aRenderingContext ,
const nsRect & aDirtyRect ,
nsFramePaintLayer aWhichLayer )
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 ;
const nsStyleDisplay * disp = ( const nsStyleDisplay * )
sc - > GetStyleData ( eStyleStruct_Display ) ;
2000-03-17 10:15:13 +00:00
if ( disp - > IsVisible ( ) ) {
1999-11-24 06:03:41 +00:00
TextStyle ts ( aPresContext , aRenderingContext , mStyleContext ) ;
1999-09-21 00:12:50 +00:00
if ( ts . mSmallCaps | | ( 0 ! = ts . mWordSpacing ) | | ( 0 ! = ts . mLetterSpacing ) ) {
1999-11-24 06:03:41 +00:00
PaintTextSlowly ( aPresContext , aRenderingContext , sc , ts , 0 , 0 ) ;
1998-09-08 22:34:40 +00:00
}
else {
1998-10-26 17:27:53 +00:00
// Choose rendering pathway based on rendering context
// performance hint.
1998-10-20 16:46:14 +00:00
PRUint32 hints = 0 ;
aRenderingContext . GetHints ( hints ) ;
1999-09-01 01:02:16 +00:00
if ( ( TEXT_HAS_MULTIBYTE & mState ) | |
1998-10-20 16:46:14 +00:00
( 0 = = ( hints & NS_RENDERING_HINT_FAST_8BIT_TEXT ) ) ) {
// Use PRUnichar rendering routine
1999-11-24 06:03:41 +00:00
PaintUnicodeText ( aPresContext , aRenderingContext , sc , ts , 0 , 0 ) ;
1998-10-20 16:46:14 +00:00
}
else {
// Use char rendering routine
1999-11-24 06:03:41 +00:00
PaintAsciiText ( aPresContext , aRenderingContext , sc , ts , 0 , 0 ) ;
1998-10-20 16:46:14 +00:00
}
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 ) ) {
1998-10-21 20:03:54 +00:00
PRBool isWhitespace ;
PRInt32 wordLen , contentLen ;
1999-10-19 23:01:58 +00:00
aTX . GetNextWord ( PR_FALSE , & wordLen , & contentLen , & isWhitespace ) ;
1999-09-01 01:02:16 +00:00
NS_ASSERTION ( isWhitespace , " mState and content are out of sync " ) ;
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 ;
NS_ASSERTION ( n > = 0 , " whoops " ) ;
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 ;
1998-10-21 20:03:54 +00:00
PRBool isWhitespace ;
1998-10-20 00:21:18 +00:00
PRInt32 wordLen , contentLen ;
1998-10-21 20:03:54 +00:00
// Get the next word
1999-10-19 23:01:58 +00:00
bp = aTX . GetNextWord ( inWord , & wordLen , & contentLen , & isWhitespace ) ;
1998-10-21 20:03:54 +00:00
if ( nsnull = = bp ) {
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-27 16:52:34 +00:00
numSpaces + + ;
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
}
1998-09-08 22:34:40 +00:00
}
1998-10-20 00:21:18 +00:00
else {
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
PRInt32 i = contentLen ;
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
}
}
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.
if ( dstOffset + wordLen > aTextBuffer - > mBufferLen ) {
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 ;
1999-09-22 00:40:56 +00:00
nsCRT : : memcpy ( aTextBuffer - > mBuffer + dstOffset , bp ,
sizeof ( PRUnichar ) * wordLen ) ;
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 " ) ;
}
NS_ASSERTION ( dstOffset < = aTextBuffer - > mBufferLen ,
" yikes - we just overwrote memory " ) ;
# endif
1998-10-27 16:52:34 +00:00
// Remove trailing whitespace if it was trimmed after reflow
1999-09-01 01:02:16 +00:00
if ( TEXT_TRIMMED_WS & mState ) {
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 - - ;
}
}
1998-10-27 16:52:34 +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 ;
PRUint8 decorations = aTextStyle . mFont - > mFont . decorations ;
PRUint8 decorMask = decorations ;
NS_ADDREF ( context ) ;
do { // find decoration colors
const nsStyleText * styleText =
( const nsStyleText * ) context - > GetStyleData ( eStyleStruct_Text ) ;
if ( decorMask & styleText - > mTextDecoration ) { // a decoration defined here
const nsStyleColor * styleColor =
( const nsStyleColor * ) context - > GetStyleData ( eStyleStruct_Color ) ;
if ( NS_STYLE_TEXT_DECORATION_UNDERLINE & decorMask & styleText - > mTextDecoration ) {
underColor = styleColor - > mColor ;
decorMask & = ~ 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 ) {
overColor = styleColor - > mColor ;
decorMask & = ~ 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 ) {
strikeColor = styleColor - > mColor ;
decorMask & = ~ 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 ( ) ;
NS_RELEASE ( lastContext ) ;
}
} while ( ( nsnull ! = context ) & & ( 0 ! = decorMask ) ) ;
NS_IF_RELEASE ( context ) ;
nscoord offset ;
nscoord size ;
nscoord baseline ;
aTextStyle . mNormalFont - > GetMaxAscent ( baseline ) ;
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-03-31 07:26:07 +00:00
case SELECTION_NORMAL :
#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 ;
1999-10-21 22:01:18 +00:00
case 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 ;
case SELECTION_IME_SELECTEDRAWTEXT : {
# 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 ;
1999-10-21 22:01:18 +00:00
case 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 ;
case SELECTION_IME_SELECTEDCONVERTEDTEXT : {
# 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 ;
1999-10-21 22:01:18 +00:00
case 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 )
{
nsFrameState parentFrameState ;
parent - > GetFrameState ( & parentFrameState ) ;
if ( ( parentFrameState & NS_FRAME_GENERATED_CONTENT ) ! = 0 ) //parent is generated so so are we.
{
//we COULD check the previous sibling but I dont think that is reliable
rv = parent - > GetContent ( aContent ) ;
if ( NS_FAILED ( rv ) | | ! * aContent )
return rv ? rv : NS_ERROR_FAILURE ;
//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 ;
}
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
{
1999-04-20 00:23:33 +00:00
nsCOMPtr < nsIDocument > doc ( getter_AddRefs ( GetDocument ( aPresContext ) ) ) ;
1999-09-19 00:59:38 +00:00
PRBool displaySelection ;
displaySelection = doc - > GetDisplaySelection ( ) ;
1998-09-08 22:34:40 +00:00
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
1999-02-24 18:21:23 +00:00
nsCOMPtr < nsILineBreaker > lb ;
1999-09-19 00:59:38 +00:00
doc - > GetLineBreaker ( getter_AddRefs ( lb ) ) ;
1999-09-22 00:40:56 +00:00
nsTextTransformer tx ( lb , nsnull ) ;
PRInt32 textLength ;
PrepareUnicodeText ( tx , ( displaySelection ? & indexBuffer : nsnull ) ,
& paintBuffer , & textLength ) ;
PRInt32 * ip = indexBuffer . mBuffer ;
PRUnichar * text = paintBuffer . mBuffer ;
1999-04-26 04:02:04 +00:00
nsFrameState frameState ;
PRBool isSelected ;
GetFrameState ( & frameState ) ;
isSelected = ( frameState & NS_FRAME_SELECTED_CONTENT ) = = NS_FRAME_SELECTED_CONTENT ;
1998-09-08 22:34:40 +00:00
if ( 0 ! = textLength ) {
1999-04-26 04:02:04 +00:00
if ( ! displaySelection | | ! isSelected ) {
1998-09-08 22:34:40 +00:00
// When there is no selection showing, use the fastest and
// simplest rendering approach
1999-07-08 19:52:57 +00:00
aRenderingContext . SetColor ( aTextStyle . mColor - > mColor ) ;
1999-01-28 05:03:58 +00:00
aRenderingContext . DrawString ( text , PRUint32 ( textLength ) , dx , dy ) ;
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 = nsnull ;
1999-04-26 04:02:04 +00:00
nsCOMPtr < nsIPresShell > shell ;
nsCOMPtr < nsIFrameSelection > frameSelection ;
nsresult rv = aPresContext - > GetShell ( getter_AddRefs ( shell ) ) ;
if ( NS_SUCCEEDED ( rv ) & & shell ) {
1999-07-18 02:27:19 +00:00
rv = shell - > GetFrameSelection ( getter_AddRefs ( frameSelection ) ) ;
if ( NS_SUCCEEDED ( rv ) & & frameSelection ) {
1999-04-26 04:02:04 +00:00
nsCOMPtr < nsIContent > content ;
2000-04-02 05:05:31 +00:00
PRInt32 offset ;
PRInt32 length ;
rv = GetContentAndOffsetsForSelection ( aPresContext , getter_AddRefs ( content ) , & offset , & length ) ;
1999-07-18 02:27:19 +00:00
if ( NS_SUCCEEDED ( rv ) & & content ) {
1999-04-26 04:02:04 +00:00
rv = frameSelection - > LookUpSelection ( content , mContentOffset ,
2000-01-08 00:31:32 +00:00
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 ;
sdptr = sdptr - > mNext ;
}
2000-03-31 07:26:07 +00:00
//while we have substrings...
if ( details )
{
DrawSelectionIterator iter ( details , text , ( PRUint32 ) textLength , aTextStyle ) ;
if ( iter . First ( ) )
{
nscoord currentX = dx ;
nscoord newWidth ; //temp
while ( ! iter . IsDone ( ) )
{
PRUnichar * currenttext = iter . CurrentTextUnicharPtr ( ) ;
PRUint32 currentlength = iter . CurrentLength ( ) ;
TextStyle & currentStyle = iter . CurrentStyle ( ) ;
nscolor currentFGColor = iter . CurrentForeGroundColor ( ) ;
nscolor currentBKColor ;
if ( NS_SUCCEEDED ( aRenderingContext . GetWidth ( currenttext , currentlength , newWidth ) ) ) //ADJUST FOR CHAR SPACING
{
if ( iter . CurrentBackGroundColor ( currentBKColor ) )
{ //DRAW RECT HERE!!!
aRenderingContext . SetColor ( currentBKColor ) ;
aRenderingContext . FillRect ( currentX , dy , newWidth , mRect . height ) ;
}
}
else
newWidth = 0 ;
aRenderingContext . SetColor ( currentFGColor ) ;
aRenderingContext . DrawString ( currenttext , currentlength , currentX , dy ) ;
currentX + = newWidth ; //increment twips X start
iter . Next ( ) ;
}
}
else
{
aRenderingContext . SetColor ( aTextStyle . mColor - > mColor ) ;
aRenderingContext . DrawString ( text , PRUint32 ( textLength ) , dx , dy ) ;
}
}
else
{
aRenderingContext . SetColor ( aTextStyle . mColor - > mColor ) ;
aRenderingContext . DrawString ( text , PRUint32 ( textLength ) , dx , dy ) ;
}
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
}
}
}
}
1999-06-10 21:08:17 +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
{
1999-06-10 21:08:17 +00:00
if ( ! aRendContext | | ! aNewContent ) {
1999-03-12 21:38:16 +00:00
return NS_ERROR_NULL_POINTER ;
1999-04-20 00:23:33 +00:00
}
1999-11-24 06:03:41 +00:00
TextStyle ts ( aPresContext , * aRendContext , mStyleContext ) ;
1999-04-20 00:23:33 +00:00
if ( ! ts . mSmallCaps & & ! ts . mWordSpacing & & ! ts . mLetterSpacing ) {
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
GetView ( aPresContext , & view ) ;
GetOffsetFromView ( aPresContext , origin , & view ) ;
1999-03-12 21:38:16 +00:00
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 ) ) {
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 ) ) ;
1999-09-22 00:40:56 +00:00
nsTextTransformer tx ( lb , nsnull ) ;
PRInt32 textLength ;
PrepareUnicodeText ( tx , & indexBuffer , & paintBuffer , & textLength ) ;
if ( textLength < = 0 ) {
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
1999-12-22 00:41:38 +00:00
//IF STYLE SAYS TO SELCT TO END OF FRAME HERE...
1999-11-24 01:10:22 +00:00
nsCOMPtr < nsIPref > prefs ;
PRInt32 prefInt = 0 ;
rv = nsServiceManager : : GetService ( kPrefCID ,
2000-02-02 22:24:56 +00:00
NS_GET_IID ( nsIPref ) ,
1999-11-24 01:10:22 +00:00
( nsISupports * * ) & prefs ) ;
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 < mRect . y ) //above rectangle
{
aOffset = mContentOffset ;
outofstylehandled = PR_TRUE ;
}
else if ( aPoint . y > ( mRect . y + mRect . height ) )
{
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
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 ;
for ( i = 0 ; i < = mContentLength ; i + + ) {
2000-03-31 07:26:07 +00:00
if ( indexBuffer . mBuffer [ i ] > = aOffset ) { //reverse mapping
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 ;
if ( aLength > TEXT_BUF_SIZE ) {
bp0 = new PRUnichar [ aLength ] ;
}
PRUnichar * bp = bp0 ;
1998-10-26 17:27:53 +00:00
PRBool spacing = ( 0 ! = aTextStyle . mLetterSpacing ) | |
1999-09-21 00:12:50 +00:00
( 0 ! = aTextStyle . mWordSpacing ) ;
1998-10-26 17:27:53 +00:00
nscoord spacingMem [ TEXT_BUF_SIZE ] ;
PRIntn * sp0 = spacingMem ;
if ( spacing & & ( aLength > TEXT_BUF_SIZE ) ) {
sp0 = new nscoord [ aLength ] ;
}
PRIntn * sp = sp0 ;
nscoord smallY = aY ;
if ( aTextStyle . mSmallCaps ) {
nscoord normalAscent , smallAscent ;
aTextStyle . mNormalFont - > GetMaxAscent ( normalAscent ) ;
aTextStyle . mSmallFont - > GetMaxAscent ( smallAscent ) ;
if ( normalAscent > smallAscent ) {
smallY = aY + normalAscent - smallAscent ;
}
1998-10-20 16:46:14 +00:00
}
1998-10-26 17:27:53 +00:00
nsIFontMetrics * lastFont = aTextStyle . mLastFont ;
nscoord lastY = aY ;
if ( lastFont = = aTextStyle . mSmallFont ) {
lastY = smallY ;
}
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 ;
1998-10-26 17:27:53 +00:00
nscoord nextY , glyphWidth ;
1998-10-20 16:46:14 +00:00
PRUnichar ch = * aBuffer ;
1999-03-02 18:25:22 +00:00
if ( aTextStyle . mSmallCaps & & nsCRT : : IsLower ( ch ) ) {
1998-10-26 17:27:53 +00:00
nextFont = aTextStyle . mSmallFont ;
nextY = smallY ;
1999-03-02 18:25:22 +00:00
ch = nsCRT : : ToUpper ( ch ) ;
1998-10-26 17:27:53 +00:00
if ( lastFont ! = aTextStyle . mSmallFont ) {
aRenderingContext . SetFont ( aTextStyle . mSmallFont ) ;
aRenderingContext . GetWidth ( ch , charWidth ) ;
aRenderingContext . SetFont ( aTextStyle . mNormalFont ) ;
}
else {
aRenderingContext . GetWidth ( ch , charWidth ) ;
}
glyphWidth = charWidth + aTextStyle . mLetterSpacing ;
}
else if ( ch = = ' ' ) {
nextFont = aTextStyle . mNormalFont ;
nextY = aY ;
glyphWidth = aTextStyle . mSpaceWidth + aTextStyle . mWordSpacing ;
1998-10-27 16:52:34 +00:00
nscoord extra = aTextStyle . mExtraSpacePerSpace ;
if ( - - aTextStyle . mNumSpaces = = 0 ) {
extra + = aTextStyle . mRemainingExtraSpace ;
}
glyphWidth + = extra ;
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 ) ;
aRenderingContext . GetWidth ( ch , charWidth ) ;
aRenderingContext . SetFont ( aTextStyle . mSmallFont ) ;
}
else {
aRenderingContext . GetWidth ( ch , charWidth ) ;
}
nextFont = aTextStyle . mNormalFont ;
nextY = aY ;
glyphWidth = charWidth + aTextStyle . mLetterSpacing ;
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
1999-07-08 19:52:57 +00:00
aRenderingContext . SetColor ( aTextStyle . mColor - > mColor ) ;
1998-10-26 17:27:53 +00:00
aRenderingContext . DrawString ( runStart , pendingCount ,
1999-01-28 05:03:58 +00:00
aX , lastY , - 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 ;
1998-10-26 17:27:53 +00:00
lastY = nextY ;
1998-10-20 16:46:14 +00:00
}
* bp + + = ch ;
1998-10-26 17:27:53 +00:00
* sp + + = glyphWidth ;
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
1999-01-28 05:03:58 +00:00
aRenderingContext . DrawString ( runStart , pendingCount , aX , lastY , - 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 ,
nscoord * aWidthResult )
1998-10-20 16:46:14 +00:00
{
nsIRenderingContext & rc = * aReflowState . rendContext ;
2000-03-31 07:26:07 +00:00
* aWidthResult = 0 ;
1998-10-26 17:27:53 +00:00
GetWidth ( rc , aTextStyle , aWord , aWordLength , aWidthResult ) ;
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
nsTextFrame : : GetWidthOrLength ( nsIRenderingContext & aRenderingContext ,
TextStyle & aStyle ,
PRUnichar * aBuffer , PRInt32 aLength ,
nscoord * aWidthResult ,
PRBool aGetWidth /* true=get width false = return length up to aWidthResult size*/ )
1998-10-20 16:46:14 +00:00
{
2000-02-14 01:54:20 +00:00
PRUnichar * inBuffer = aBuffer ;
PRInt32 length = aLength ;
1999-09-22 00:40:56 +00:00
nsAutoTextBuffer widthBuffer ;
2000-02-14 01:54:20 +00:00
if ( NS_FAILED ( widthBuffer . GrowTo ( length ) ) ) {
1999-09-22 00:40:56 +00:00
* aWidthResult = 0 ;
2000-03-31 07:26:07 +00:00
return 0 ;
1998-10-20 16:46:14 +00:00
}
1999-09-22 00:40:56 +00:00
PRUnichar * bp = widthBuffer . mBuffer ;
1998-10-20 16:46:14 +00:00
2000-03-31 07:26:07 +00:00
nsIFontMetrics * lastFont = aStyle . mLastFont ;
1999-03-12 21:38:16 +00:00
nscoord sum = 0 ;
nscoord charWidth ;
2000-02-14 01:54:20 +00:00
while ( - - length > = 0 ) {
1999-03-18 21:02:40 +00:00
nscoord glyphWidth ;
2000-02-14 01:54:20 +00:00
PRUnichar ch = * inBuffer + + ;
2000-03-31 07:26:07 +00:00
if ( aStyle . mSmallCaps & & nsCRT : : IsLower ( ch ) ) {
1999-03-02 18:25:22 +00:00
ch = nsCRT : : ToUpper ( 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
}
1999-03-18 21:02:40 +00:00
aRenderingContext . GetWidth ( ch , charWidth ) ;
2000-03-31 07:26:07 +00:00
glyphWidth = charWidth + aStyle . mLetterSpacing ;
1998-10-20 16:46:14 +00:00
}
1999-03-12 21:38:16 +00:00
else if ( ch = = ' ' ) {
2000-03-31 07:26:07 +00:00
glyphWidth = aStyle . mSpaceWidth + aStyle . mWordSpacing ;
nscoord extra = aStyle . mExtraSpacePerSpace ;
if ( - - aStyle . mNumSpaces = = 0 ) {
extra + = aStyle . mRemainingExtraSpace ;
1999-03-12 21:38:16 +00:00
}
glyphWidth + = extra ;
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
}
1999-03-18 21:02:40 +00:00
aRenderingContext . GetWidth ( ch , charWidth ) ;
2000-03-31 07:26:07 +00:00
glyphWidth = charWidth + aStyle . mLetterSpacing ;
1998-10-20 16:46:14 +00:00
}
1999-03-12 21:38:16 +00:00
sum + = glyphWidth ;
1998-10-20 16:46:14 +00:00
* bp + + = ch ;
2000-03-31 07:26:07 +00:00
if ( ! aGetWidth & & sum > = * aWidthResult )
{
PRInt32 result = aLength - length ;
if ( 2 * ( sum - * aWidthResult ) > glyphWidth ) //then we have gone too far, back up 1
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 ;
1999-04-20 00:23:33 +00:00
* aWidthResult = sum ;
2000-03-31 07:26:07 +00:00
return aLength ;
}
// XXX factor in logic from RenderString into here; gaps, justification, etc.
void
nsTextFrame : : GetWidth ( nsIRenderingContext & aRenderingContext ,
TextStyle & aTextStyle ,
PRUnichar * aBuffer , PRInt32 aLength ,
nscoord * aWidthResult )
{
GetWidthOrLength ( aRenderingContext , aTextStyle , aBuffer , aLength , aWidthResult , PR_TRUE ) ;
}
PRInt32
nsTextFrame : : GetLengthSlowly ( nsIRenderingContext & aRenderingContext ,
TextStyle & aStyle ,
PRUnichar * aBuffer , PRInt32 aLength ,
nscoord aWidth )
{
return GetWidthOrLength ( aRenderingContext , aStyle , aBuffer , aLength , & aWidth , PR_FALSE ) ;
1998-10-20 16:46:14 +00:00
}
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
{
1999-04-20 00:23:33 +00:00
nsCOMPtr < nsIDocument > doc ( getter_AddRefs ( GetDocument ( aPresContext ) ) ) ;
1998-10-20 16:46:14 +00:00
PRBool displaySelection ;
displaySelection = doc - > GetDisplaySelection ( ) ;
// 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 ;
// Transform text from content into renderable form
1999-02-24 18:21:23 +00:00
nsCOMPtr < nsILineBreaker > lb ;
doc - > GetLineBreaker ( getter_AddRefs ( lb ) ) ;
1999-09-22 00:40:56 +00:00
nsTextTransformer tx ( lb , nsnull ) ;
1999-02-10 18:55:25 +00:00
aTextStyle . mNumSpaces = PrepareUnicodeText ( tx ,
1999-09-22 00:40:56 +00:00
( displaySelection
? & indexBuffer : nsnull ) ,
& paintBuffer , & textLength ) ;
1998-10-20 16:46:14 +00:00
1999-09-22 00:40:56 +00:00
PRInt32 * ip = indexBuffer . mBuffer ;
PRUnichar * text = paintBuffer . mBuffer ;
1999-04-26 04:02:04 +00:00
nsFrameState frameState ;
PRBool isSelected ;
GetFrameState ( & frameState ) ;
isSelected = ( frameState & NS_FRAME_SELECTED_CONTENT ) = = NS_FRAME_SELECTED_CONTENT ;
1998-10-20 16:46:14 +00:00
if ( 0 ! = textLength ) {
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
2000-03-31 07:26:07 +00:00
aRenderingContext . SetColor ( aTextStyle . mColor - > mColor ) ;
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
}
else {
1999-07-15 18:19:03 +00:00
SelectionDetails * details = nsnull ;
1999-04-26 04:02:04 +00:00
nsCOMPtr < nsIPresShell > shell ;
nsCOMPtr < nsIFrameSelection > frameSelection ;
nsresult rv = aPresContext - > GetShell ( getter_AddRefs ( shell ) ) ;
if ( NS_SUCCEEDED ( rv ) & & shell ) {
1999-07-18 02:27:19 +00:00
rv = shell - > GetFrameSelection ( getter_AddRefs ( frameSelection ) ) ;
if ( NS_SUCCEEDED ( rv ) & & frameSelection ) {
1999-04-26 04:02:04 +00:00
nsCOMPtr < nsIContent > content ;
2000-04-02 05:05:31 +00:00
PRInt32 offset ;
PRInt32 length ;
rv = GetContentAndOffsetsForSelection ( aPresContext , getter_AddRefs ( content ) , & offset , & length ) ;
1999-04-26 04:02:04 +00:00
if ( NS_SUCCEEDED ( rv ) ) {
rv = frameSelection - > LookUpSelection ( content , mContentOffset ,
2000-01-08 00:31:32 +00:00
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 ;
sdptr = sdptr - > mNext ;
}
2000-03-31 07:26:07 +00:00
if ( details )
{
DrawSelectionIterator iter ( details , text , ( PRUint32 ) textLength , aTextStyle ) ;
if ( iter . First ( ) )
{
nscoord currentX = dx ;
nscoord newWidth ; //temp
while ( ! iter . IsDone ( ) )
{
PRUnichar * currenttext = iter . CurrentTextUnicharPtr ( ) ;
PRUint32 currentlength = iter . CurrentLength ( ) ;
TextStyle & currentStyle = iter . CurrentStyle ( ) ;
nscolor currentFGColor = iter . CurrentForeGroundColor ( ) ;
nscolor currentBKColor ;
GetWidth ( aRenderingContext , aTextStyle , currenttext , ( PRInt32 ) currentlength , & newWidth ) ;
if ( newWidth )
{
if ( iter . CurrentBackGroundColor ( currentBKColor ) )
{ //DRAW RECT HERE!!!
aRenderingContext . SetColor ( currentBKColor ) ;
aRenderingContext . FillRect ( currentX , dy , newWidth , mRect . height ) ;
}
}
else
newWidth = 0 ;
aRenderingContext . SetColor ( currentFGColor ) ;
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
currentX + = newWidth ; // + aTextStyle.mLetterSpacing;
iter . Next ( ) ;
}
}
else
{
aRenderingContext . SetColor ( aTextStyle . mColor - > mColor ) ;
RenderString ( aRenderingContext , aStyleContext , aTextStyle , text ,
PRUint32 ( textLength ) , dx , dy , width , details ) ;
}
}
else
{
aRenderingContext . SetColor ( aTextStyle . mColor - > mColor ) ;
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
{
1999-04-20 00:23:33 +00:00
nsCOMPtr < nsIDocument > doc ( getter_AddRefs ( GetDocument ( aPresContext ) ) ) ;
1998-09-08 22:34:40 +00:00
PRBool displaySelection ;
displaySelection = doc - > GetDisplaySelection ( ) ;
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
// Transform text from content into renderable form
1999-02-24 18:21:23 +00:00
nsCOMPtr < nsILineBreaker > lb ;
doc - > GetLineBreaker ( getter_AddRefs ( lb ) ) ;
1999-09-22 00:40:56 +00:00
nsTextTransformer tx ( lb , nsnull ) ;
PRInt32 textLength ;
PrepareUnicodeText ( tx , ( displaySelection ? & indexBuffer : nsnull ) ,
& unicodePaintBuffer , & textLength ) ;
1998-10-21 20:03:54 +00:00
// Translate unicode data into ascii for rendering
1999-09-22 00:40:56 +00:00
char paintBufMem [ TEXT_BUF_SIZE ] ;
char * paintBuf = paintBufMem ;
if ( textLength > TEXT_BUF_SIZE ) {
paintBuf = new char [ textLength ] ;
if ( ! paintBuf ) {
return ;
}
}
1998-10-21 20:03:54 +00:00
char * dst = paintBuf ;
char * end = dst + textLength ;
1999-09-22 00:40:56 +00:00
PRUnichar * src = unicodePaintBuffer . mBuffer ;
1998-10-21 20:03:54 +00:00
while ( dst < end ) {
* dst + + = ( char ) ( ( unsigned char ) * src + + ) ;
}
1998-10-20 00:21:18 +00:00
1999-09-22 00:40:56 +00:00
nscoord width = mRect . width ;
PRInt32 * ip = indexBuffer . mBuffer ;
1998-10-20 00:21:18 +00:00
char * text = paintBuf ;
1999-04-26 04:02:04 +00:00
nsFrameState frameState ;
PRBool isSelected ;
GetFrameState ( & frameState ) ;
isSelected = ( frameState & NS_FRAME_SELECTED_CONTENT ) = = NS_FRAME_SELECTED_CONTENT ;
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
1999-07-08 19:52:57 +00:00
aRenderingContext . SetColor ( aTextStyle . mColor - > mColor ) ;
1999-01-28 05:03:58 +00:00
aRenderingContext . DrawString ( text , PRUint32 ( textLength ) , dx , dy ) ;
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 < nsIPresShell > shell ;
nsCOMPtr < nsIFrameSelection > frameSelection ;
nsresult rv = aPresContext - > GetShell ( getter_AddRefs ( shell ) ) ;
if ( NS_SUCCEEDED ( rv ) & & shell ) {
1999-07-18 02:27:19 +00:00
rv = shell - > GetFrameSelection ( getter_AddRefs ( frameSelection ) ) ;
if ( NS_SUCCEEDED ( rv ) & & frameSelection ) {
1999-04-26 04:02:04 +00:00
nsCOMPtr < nsIContent > content ;
2000-04-02 05:05:31 +00:00
PRInt32 offset ;
PRInt32 length ;
rv = GetContentAndOffsetsForSelection ( aPresContext , getter_AddRefs ( content ) , & offset , & length ) ;
1999-04-26 04:02:04 +00:00
if ( NS_SUCCEEDED ( rv ) ) {
rv = frameSelection - > LookUpSelection ( content , mContentOffset ,
2000-01-08 00:31:32 +00:00
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-03-31 07:26:07 +00:00
if ( details )
{
DrawSelectionIterator iter ( details , ( PRUnichar * ) text , ( PRUint32 ) textLength , aTextStyle ) ; //ITS OK TO CAST HERE THE RESULT WE USE WILLNOT DO BAD CONVERSION
if ( iter . First ( ) )
{
nscoord currentX = dx ;
nscoord newWidth ; //temp
while ( ! iter . IsDone ( ) )
{
char * currenttext = iter . CurrentTextCStrPtr ( ) ;
PRUint32 currentlength = iter . CurrentLength ( ) ;
TextStyle & currentStyle = iter . CurrentStyle ( ) ;
nscolor currentFGColor = iter . CurrentForeGroundColor ( ) ;
nscolor currentBKColor ;
if ( NS_SUCCEEDED ( aRenderingContext . GetWidth ( currenttext , currentlength , newWidth ) ) ) //ADJUST FOR CHAR SPACING
{
if ( iter . CurrentBackGroundColor ( currentBKColor ) )
{ //DRAW RECT HERE!!!
aRenderingContext . SetColor ( currentBKColor ) ;
aRenderingContext . FillRect ( currentX , dy , newWidth , mRect . height ) ;
}
}
else
newWidth = 0 ;
aRenderingContext . SetColor ( currentFGColor ) ;
aRenderingContext . DrawString ( currenttext , currentlength , currentX , dy ) ;
currentX + = newWidth ; //increment twips X start
iter . Next ( ) ;
}
}
else
{
aRenderingContext . SetColor ( aTextStyle . mColor - > mColor ) ;
aRenderingContext . DrawString ( text , PRUint32 ( textLength ) , dx , dy ) ;
}
}
else
{
aRenderingContext . SetColor ( aTextStyle . mColor - > mColor ) ;
aRenderingContext . DrawString ( text , PRUint32 ( textLength ) , dx , dy ) ;
}
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
}
}
NS_IMETHODIMP
1999-04-20 00:23:33 +00:00
nsTextFrame : : FindTextRuns ( nsLineLayout & aLineLayout )
1998-09-08 22:34:40 +00:00
{
1999-10-23 23:19:14 +00:00
nsIFrame * prevInFlow ;
GetPrevInFlow ( & prevInFlow ) ;
if ( nsnull = = prevInFlow ) {
1998-09-08 22:34:40 +00:00
aLineLayout . AddText ( this ) ;
}
return NS_OK ;
}
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
static PRBool
1998-10-02 01:12:39 +00:00
BinarySearchForPosition ( nsIRenderingContext * acx ,
1998-09-10 19:18:01 +00:00
PRUnichar * aText ,
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
{
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 ) ;
1999-06-08 02:19:26 +00:00
if ( ts . mSmallCaps | | ts . mWordSpacing | | ts . mLetterSpacing ) {
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
nsIStyleContext * styleContext ;
1999-06-10 21:08:17 +00:00
GetStyleContext ( & styleContext ) ;
1999-06-08 02:19:26 +00:00
const nsStyleFont * font = ( const nsStyleFont * )
styleContext - > GetStyleData ( eStyleStruct_Font ) ;
NS_RELEASE ( styleContext ) ;
nsCOMPtr < nsIFontMetrics > fm ;
1999-11-24 06:03:41 +00:00
aCX - > GetMetricsFor ( font - > mFont , getter_AddRefs ( fm ) ) ;
1999-06-08 02:19:26 +00:00
acx - > SetFont ( fm ) ;
// 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 ) ) ;
1999-09-22 00:40:56 +00:00
nsTextTransformer tx ( lb , nsnull ) ;
PRInt32 textLength ;
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
//IF SYLE SAYS TO SELCT TO END OF FRAME HERE...
nsCOMPtr < nsIPref > prefs ;
PRInt32 prefInt = 0 ;
rv = nsServiceManager : : GetService ( kPrefCID ,
2000-02-02 22:24:56 +00:00
NS_GET_IID ( nsIPref ) ,
1999-11-24 01:10:22 +00:00
( nsISupports * * ) & prefs ) ;
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 ;
PRBool found = BinarySearchForPosition ( acx , text , origin . x , 0 , 0 ,
PRInt32 ( textLength ) ,
PRInt32 ( aPoint . x ) , //go to local coordinates
indx , textWidth ) ;
if ( found ) {
PRInt32 charWidth ;
acx - > GetWidth ( text [ indx ] , charWidth ) ;
charWidth / = 2 ;
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 + + ) {
2000-02-10 07:48:17 +00:00
if ( ip [ i ] > = aContentOffset ) { //reverse mapping
1999-11-24 01:10:22 +00:00
aContentOffset = i + mContentOffset ;
break ;
}
}
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
{
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 ) ;
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
const nsStyleUserInterface * userinterface ;
GetStyleData ( eStyleStruct_UserInterface , ( const nsStyleStruct * & ) userinterface ) ;
if ( userinterface ) {
if ( userinterface - > mUserSelect = = NS_STYLE_USER_SELECT_AUTO ) {
// if 'user-select' isn't set for this frame, use the parent's
if ( mParent ) {
mParent - > GetStyleData ( eStyleStruct_UserInterface , ( const nsStyleStruct * & ) userinterface ) ;
}
}
if ( userinterface - > mUserSelect = = NS_STYLE_USER_SELECT_NONE ) {
return NS_OK ; //do not continue no selection for this frame.
}
}
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 ;
aRange - > GetEndParent ( getter_AddRefs ( endNode ) ) ;
aRange - > GetEndOffset ( & endOffset ) ;
aRange - > GetStartParent ( getter_AddRefs ( startNode ) ) ;
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 ) {
rv = shell - > GetFrameSelection ( getter_AddRefs ( frameSelection ) ) ;
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 ) ;
1999-10-26 04:44:41 +00:00
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
}
}
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 ;
}
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 ) ) ;
1999-09-22 00:40:56 +00:00
nsTextTransformer tx ( lb , nsnull ) ;
PRInt32 textLength ;
PrepareUnicodeText ( tx , & indexBuffer , & paintBuffer , & textLength ) ;
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
nscoord width = mRect . width ;
2000-03-31 07:26:07 +00:00
if ( ts . mSmallCaps | | ( 0 ! = ts . mWordSpacing ) | | ( 0 ! = ts . mLetterSpacing ) )
{
GetWidth ( * inRendContext , ts ,
paintBuffer . mBuffer , ip [ inOffset ] - mContentOffset ,
& width ) ;
}
else
{
inRendContext - > GetWidth ( paintBuffer . mBuffer , ip [ inOffset ] - mContentOffset , width ) ;
}
1999-10-29 13:43:11 +00:00
if ( inOffset > textLength & & ( TEXT_TRIMMED_WS & mState ) ) {
//
// 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!
//
width + = ts . mSpaceWidth ;
}
1999-09-22 00:40:56 +00:00
outPoint - > x = width ;
outPoint - > y = 0 ;
1999-02-12 00:02:31 +00:00
return NS_OK ;
}
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
}
else if ( contentOffset ! = mContentLength ) //that condition was only for when there is a choice
1999-02-12 00:02:31 +00:00
return NS_ERROR_FAILURE ;
}
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 ) ;
1999-09-14 23:16:22 +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
{
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 ;
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
| | aPos - > mAmount = = eSelectEndLine )
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 ) ;
nsTextTransformer tx ( lb , nsnull ) ;
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 ) ;
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 ) ;
nsTextTransformer tx ( lb , nsnull ) ;
PrepareUnicodeText ( tx , & indexBuffer , & paintBuffer , & textLength ) ;
nsIFrame * frameUsed = nsnull ;
PRInt32 start ;
PRBool found = PR_TRUE ;
if ( aPos - > mDirection = = eDirPrevious ) {
aPos - > mContentOffset = 0 ;
PRInt32 i ;
for ( i = aPos - > mStartOffset - 1 - mContentOffset ; i > = 0 ; i - - ) {
if ( ip [ i ] < ip [ aPos - > mStartOffset - mContentOffset ] ) {
aPos - > mContentOffset = i + mContentOffset ;
break ;
}
}
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
}
1999-09-22 00:40:56 +00:00
else if ( aPos - > mDirection = = eDirNext ) {
PRInt32 i ;
aPos - > mContentOffset = mContentLength ;
for ( i = aPos - > mStartOffset + 1 - mContentOffset ; i < = mContentLength ; i + + ) {
if ( ip [ i ] > ip [ aPos - > mStartOffset - mContentOffset ] ) {
aPos - > mContentOffset = i + mContentOffset ;
break ;
}
}
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 )
1999-10-26 04:44:41 +00:00
result = aPos - > mResultFrame - > PeekOffset ( aPresContext , aPos ) ;
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 ) ;
nsTextTransformer tx ( lb , wb ) ;
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 ;
PRBool isWhitespace ;
PRInt32 wordLen , contentLen ;
if ( aPos - > mDirection = = eDirPrevious ) {
keepSearching = PR_TRUE ;
tx . Init ( this , mContent , aPos - > mStartOffset ) ;
1999-10-22 00:19:18 +00:00
aPos - > mContentOffset = mContentOffset ; //initialize
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 {
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 ;
}
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
}
1999-09-22 00:40:56 +00:00
else if ( aPos - > mDirection = = eDirNext ) {
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
# ifdef DEBUGWORDJUMP
1999-09-22 00:40:56 +00:00
printf ( " Next- Start=%d aPos->mEatingWS=%s \n " , aPos - > mStartOffset , aPos - > mEatingWS ? " TRUE " : " FALSE " ) ;
1999-08-19 06:06:57 +00:00
# endif
1999-10-19 23:01:58 +00:00
if ( tx . GetNextWord ( PR_FALSE , & wordLen , & contentLen , & isWhitespace , PR_FALSE ) & &
1999-09-22 07:09:41 +00:00
( aPos - > mStartOffset + contentLen < = ( mContentLength + mContentOffset ) ) ) {
1999-08-19 06:06:57 +00:00
# ifdef DEBUGWORDJUMP
1999-09-22 00:40:56 +00:00
printf ( " GetNextWord return non null, wordLen%d, contentLen%d isWhitespace=%s \n " ,
wordLen , contentLen , isWhitespace ? " WS " : " NOT WS " ) ;
1999-08-19 06:06:57 +00:00
# endif
1999-09-22 00:40:56 +00:00
if ( ( aPos - > mEatingWS & & isWhitespace ) | | ! aPos - > mEatingWS ) {
aPos - > mContentOffset = aPos - > mStartOffset + contentLen ;
//check for whitespace next.
keepSearching = PR_TRUE ;
1999-09-22 07:09:41 +00:00
aPos - > mEatingWS = PR_TRUE ;
1999-10-19 23:01:58 +00:00
while ( ! isWhitespace & & tx . GetNextWord ( PR_FALSE , & wordLen , & contentLen , & isWhitespace , PR_FALSE ) ) {
1999-08-19 06:06:57 +00:00
# ifdef DEBUGWORDJUMP
1999-09-22 00:40:56 +00:00
printf ( " 2-GetNextWord return non null, wordLen%d, contentLen%d isWhitespace=%s \n " ,
wordLen , contentLen , isWhitespace ? " WS " : " NOT WS " ) ;
1999-08-19 06:06:57 +00:00
# endif
1999-09-22 00:40:56 +00:00
aPos - > mContentOffset + = contentLen ;
keepSearching = PR_FALSE ;
}
1999-03-03 01:51:21 +00:00
}
1999-09-22 00:40:56 +00:00
else if ( aPos - > mEatingWS )
aPos - > mContentOffset = mContentOffset ;
1999-09-22 07:09:41 +00:00
found = isWhitespace ;
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
}
1999-10-23 23:19:14 +00:00
GetNextInFlow ( & frameUsed ) ;
1999-09-22 00:40:56 +00:00
start = 0 ;
1999-02-22 03:20:59 +00:00
}
1999-08-19 06:06:57 +00:00
# ifdef DEBUGWORDJUMP
1999-09-22 00:40:56 +00:00
printf ( " aEatingWS = %s \n " , aPos - > mEatingWS ? " TRUE " : " FALSE " ) ;
1999-08-19 06:06:57 +00:00
# endif
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 ;
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 ,
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
{
if ( ! DisplaySelection ( aPresContext ) ) {
return NS_OK ;
}
1999-10-13 01:15:26 +00:00
1999-09-11 00:18:02 +00:00
nsMouseEvent * me = ( nsMouseEvent * ) aEvent ;
1999-05-17 00:21:18 +00:00
nsCOMPtr < nsIPresShell > shell ;
1999-10-13 01:15:26 +00:00
1999-11-24 06:03:41 +00:00
nsresult rv = aPresContext - > GetShell ( getter_AddRefs ( shell ) ) ;
1999-10-13 01:15:26 +00:00
if ( me - > clickCount > 2 ) //triple clicking
{
nsCOMPtr < nsIPref > mPrefs ;
PRInt32 prefInt = 0 ;
rv = nsServiceManager : : GetService ( kPrefCID ,
2000-02-02 22:24:56 +00:00
NS_GET_IID ( nsIPref ) ,
1999-10-13 01:15:26 +00:00
( nsISupports * * ) & mPrefs ) ;
if ( NS_SUCCEEDED ( rv ) & & mPrefs )
{
1999-11-24 01:10:22 +00:00
if ( NS_FAILED ( mPrefs - > GetIntPref ( " browser.triple_click_style " , & prefInt ) ) | | ! prefInt )
1999-10-13 01:15:26 +00:00
return nsFrame : : HandleMultiplePress ( aPresContext , aEvent , aEventStatus ) ;
}
1999-10-22 00:19:18 +00:00
//THIS NEXT CODE IS FOR PARAGRAPH
1999-10-13 01:15:26 +00:00
nsCOMPtr < nsIDOMNode > startNode ;
nsCOMPtr < nsIDOMNode > endNode ;
1999-10-23 23:19:14 +00:00
nsIFrame * currentFrame = this ;
nsIFrame * prevFrame ;
GetPrevInFlow ( & prevFrame ) ;
1999-10-13 01:15:26 +00:00
while ( prevFrame ) {
currentFrame = prevFrame ;
1999-10-23 23:19:14 +00:00
currentFrame - > GetPrevInFlow ( & prevFrame ) ;
1999-10-13 01:15:26 +00:00
if ( NS_FAILED ( rv ) )
break ;
}
prevFrame = currentFrame ;
currentFrame = this ;
1999-10-23 23:19:14 +00:00
nsIFrame * nextFrame ;
GetNextInFlow ( & nextFrame ) ;
1999-10-13 01:15:26 +00:00
while ( nextFrame ) {
currentFrame = nextFrame ;
1999-10-23 23:19:14 +00:00
currentFrame - > GetNextInFlow ( & nextFrame ) ;
1999-10-13 01:15:26 +00:00
if ( NS_FAILED ( rv ) )
break ;
}
nextFrame = currentFrame ;
nsCOMPtr < nsIContent > content ;
if ( prevFrame )
prevFrame - > GetContent ( getter_AddRefs ( content ) ) ;
startNode = do_QueryInterface ( content , & rv ) ;
if ( NS_FAILED ( rv ) | | ! startNode )
return rv ? rv : NS_ERROR_FAILURE ;
nextFrame - > GetContent ( getter_AddRefs ( content ) ) ;
endNode = do_QueryInterface ( content , & rv ) ;
if ( NS_FAILED ( rv ) | | ! endNode )
return rv ? rv : NS_ERROR_FAILURE ;
PRInt32 startOffset ;
PRInt32 endOffset ;
PRInt32 unusedOffset ;
rv = prevFrame - > GetOffsets ( startOffset , unusedOffset ) ;
if ( NS_FAILED ( rv ) )
return rv ;
rv = nextFrame - > GetOffsets ( unusedOffset , endOffset ) ;
if ( NS_FAILED ( rv ) )
return rv ;
nsCOMPtr < nsIDOMSelection > selection ;
if ( NS_SUCCEEDED ( shell - > GetSelection ( SELECTION_NORMAL , getter_AddRefs ( selection ) ) ) ) {
rv = selection - > Collapse ( startNode , startOffset ) ;
if ( NS_FAILED ( rv ) )
return rv ;
rv = selection - > Extend ( endNode , endOffset ) ;
if ( NS_FAILED ( rv ) )
return rv ;
}
}
else if ( NS_SUCCEEDED ( rv ) & & shell ) {
1999-05-17 00:21:18 +00:00
nsCOMPtr < nsIRenderingContext > acx ;
1999-06-19 20:36:44 +00:00
nsCOMPtr < nsIFocusTracker > tracker ;
tracker = do_QueryInterface ( shell , & rv ) ;
if ( NS_FAILED ( rv ) | | ! tracker )
1999-10-13 01:15:26 +00:00
return rv ? rv : NS_ERROR_FAILURE ;
1999-05-17 00:21:18 +00:00
rv = shell - > CreateRenderingContext ( this , getter_AddRefs ( acx ) ) ;
if ( NS_SUCCEEDED ( rv ) ) {
PRInt32 startPos = 0 ;
PRInt32 contentOffsetEnd = 0 ;
nsCOMPtr < nsIContent > newContent ;
1999-10-13 01:15:26 +00:00
//find which word needs to be selected! use peek offset one way then the other
nsCOMPtr < nsIDOMNode > startNode ;
nsCOMPtr < nsIDOMNode > endNode ;
1999-11-24 01:10:22 +00:00
if ( NS_SUCCEEDED ( GetPosition ( aPresContext , aEvent - > point ,
1999-06-10 21:08:17 +00:00
getter_AddRefs ( newContent ) , startPos , contentOffsetEnd ) ) ) {
1999-05-17 00:21:18 +00:00
//peeks{}
1999-09-10 18:29:37 +00:00
nsPeekOffsetStruct startpos ;
startpos . SetData ( tracker ,
1999-06-19 20:36:44 +00:00
0 ,
1999-06-10 21:08:17 +00:00
eSelectWord ,
1999-05-17 00:21:18 +00:00
eDirPrevious ,
1999-06-10 21:08:17 +00:00
startPos ,
1999-09-10 18:29:37 +00:00
PR_FALSE ,
1999-10-22 00:19:18 +00:00
PR_TRUE ,
PR_FALSE ) ;
1999-11-24 06:03:41 +00:00
rv = PeekOffset ( aPresContext , & startpos ) ;
1999-05-17 00:21:18 +00:00
if ( NS_FAILED ( rv ) )
return rv ;
1999-09-10 18:29:37 +00:00
nsPeekOffsetStruct endpos ;
endpos . SetData ( tracker ,
1999-06-19 20:36:44 +00:00
0 ,
1999-06-10 21:08:17 +00:00
eSelectWord ,
1999-05-17 00:21:18 +00:00
eDirNext ,
1999-06-10 21:08:17 +00:00
startPos ,
1999-09-10 18:29:37 +00:00
PR_FALSE ,
1999-10-22 00:19:18 +00:00
PR_FALSE ,
1999-09-11 00:18:02 +00:00
PR_FALSE ) ;
1999-11-24 06:03:41 +00:00
rv = PeekOffset ( aPresContext , & endpos ) ;
1999-05-17 00:21:18 +00:00
if ( NS_FAILED ( rv ) )
return rv ;
1999-09-10 18:29:37 +00:00
endNode = do_QueryInterface ( endpos . mResultContent , & rv ) ;
1999-05-17 00:21:18 +00:00
if ( NS_FAILED ( rv ) )
return rv ;
1999-09-10 18:29:37 +00:00
startNode = do_QueryInterface ( startpos . mResultContent , & rv ) ;
1999-05-17 00:21:18 +00:00
if ( NS_FAILED ( rv ) )
return rv ;
1999-10-22 00:19:18 +00:00
1999-05-17 00:21:18 +00:00
nsCOMPtr < nsIDOMSelection > selection ;
1999-07-18 02:27:19 +00:00
if ( NS_SUCCEEDED ( shell - > GetSelection ( SELECTION_NORMAL , getter_AddRefs ( selection ) ) ) ) {
1999-09-10 18:29:37 +00:00
rv = selection - > Collapse ( startNode , startpos . mContentOffset ) ;
1999-05-17 00:21:18 +00:00
if ( NS_FAILED ( rv ) )
return rv ;
1999-09-10 18:29:37 +00:00
rv = selection - > Extend ( endNode , endpos . mContentOffset ) ;
1999-05-17 00:21:18 +00:00
if ( NS_FAILED ( rv ) )
return rv ;
}
//no release
}
}
}
return NS_OK ;
}
1999-10-22 00:19:18 +00:00
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 ) ; }
} ;
# define IS_ODD_NUMBER(n) \
( 0 ! = ( ( n ) & 0x1 ) )
# define IS_EVEN_NUMBER(n) \
( 0 = = ( ( n ) & 0x1 ) )
# define IS_32BIT_ALIGNED_PTR(p) \
( 0 = = ( long ( p ) & 0x3 ) )
struct TextRun {
PRUnichar mBufSpace [ 256 ] ;
PRUnichar * mBuf ;
PRInt32 mBufSize , mBufLength ;
// 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 ( )
{
mBuf = mBufSpace ;
mBufSize = 256 ;
mBufLength = mNumSegments = 0 ;
}
~ TextRun ( )
{
if ( mBuf ! = mBufSpace ) {
delete [ ] mBuf ;
}
}
void Reset ( )
{
mBufLength = 0 ;
mNumSegments = 0 ;
}
// Returns PR_TRUE if we're currently buffering text
PRBool IsBuffering ( )
{
return mNumSegments > 0 ;
}
void GrowBuffer ( PRInt32 aMinBufSize )
{
// Allocate a new buffer
do {
mBufSize + = 100 ;
} while ( mBufSize < aMinBufSize ) ;
PRUnichar * newBufSpace = new PRUnichar [ mBufSize ] ;
memcpy ( newBufSpace , mBuf , mBufLength * sizeof ( PRUnichar ) ) ;
if ( mBuf ! = mBufSpace ) {
delete [ ] mBuf ;
}
mBuf = newBufSpace ;
}
void AddWhitespace ( PRUnichar * aText ,
PRInt32 aNumChars ,
PRInt32 aContentLen )
{
NS_PRECONDITION ( mNumSegments < TEXT_MAX_NUM_SEGMENTS , " segment overflow " ) ;
NS_PRECONDITION ( IS_32BIT_ALIGNED_PTR ( aText ) , " unexpected alignment of text pointer " ) ;
// See if we have room in the buffer
PRInt32 newBufLength = mBufLength + aNumChars ;
if ( newBufLength > mBufSize ) {
GrowBuffer ( newBufLength ) ;
}
if ( 1 = = aNumChars ) {
mBuf [ mBufLength ] = * aText ;
} else {
: : memcpy ( & mBuf [ mBufLength ] , aText , aNumChars * sizeof ( PRUnichar * ) ) ;
}
mBufLength = newBufLength ;
mBreaks [ mNumSegments ] = mBufLength ;
mSegments [ mNumSegments ] . mIsWhitespace = PR_TRUE ;
mSegments [ mNumSegments ] . mContentLen = PRUint32 ( aContentLen ) ;
if ( mNumSegments > 0 ) {
mSegments [ mNumSegments ] . mContentLen + = mSegments [ mNumSegments - 1 ] . ContentLen ( ) ;
}
mNumSegments + + ;
}
void AddWord ( PRUnichar * aText ,
PRInt32 aNumChars ,
PRInt32 aContentLen )
{
NS_PRECONDITION ( mNumSegments < TEXT_MAX_NUM_SEGMENTS , " segment overflow " ) ;
NS_PRECONDITION ( IS_32BIT_ALIGNED_PTR ( aText ) , " unexpected alignment of text pointer " ) ;
// See if we have room in the buffer
PRInt32 newBufLength = mBufLength + aNumChars ;
if ( newBufLength > mBufSize ) {
GrowBuffer ( newBufLength ) ;
}
if ( IS_EVEN_NUMBER ( mBufLength ) ) {
// We have a small amount of text (a single word) and we're at a point
// in our buffer that is 32-bit aligned so copy 32-bit chunks at a time
int * dest = ( int * ) & mBuf [ mBufLength ] ;
int * src = ( int * ) aText ;
for ( int i = aNumChars / 2 ; i > 0 ; i - - ) {
* dest + + = * src + + ;
}
if ( IS_ODD_NUMBER ( aNumChars ) ) {
// Copy the one remaining character
* ( ( PRUnichar * ) dest ) = * ( ( PRUnichar * ) src ) ;
}
} else {
: : memcpy ( & mBuf [ mBufLength ] , aText , aNumChars * sizeof ( PRUnichar * ) ) ;
}
mBufLength = newBufLength ;
mBreaks [ mNumSegments ] = mBufLength ;
mSegments [ mNumSegments ] . mIsWhitespace = PR_FALSE ;
mSegments [ mNumSegments ] . mContentLen = PRUint32 ( aContentLen ) ;
if ( mNumSegments > 0 ) {
mSegments [ mNumSegments ] . mContentLen + = mSegments [ mNumSegments - 1 ] . ContentLen ( ) ;
}
mNumSegments + + ;
}
} ;
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 ;
nscoord prevMaxWordWidth = 0 ;
PRInt32 lastWordLen = 0 ;
PRInt32 lastWordWidth = 0 ;
PRBool textStartsWithNBSP = PR_FALSE ;
PRBool endsInWhitespace = PR_FALSE ;
PRBool endsInNewline = PR_FALSE ;
PRBool justDidFirstLetter = PR_FALSE ;
# ifdef _WIN32
PRBool measureTextRuns = ! aTextData . mComputeMaxWordWidth & & ! aTs . mPreformatted & &
! aTs . mSmallCaps & & ( 0 = = aTs . mWordSpacing ) ;
# 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 ;
2000-03-23 22:58:43 +00:00
aTextData . mX = 0 ;
2000-03-31 04:27:43 +00:00
for ( ; ; firstThing = PR_FALSE ) {
2000-03-23 22:58:43 +00:00
// Get next word/whitespace from the text
PRBool isWhitespace ;
PRInt32 wordLen , contentLen ;
PRUnichar * bp = aTx . GetNextWord ( aTextData . mInWord , & wordLen , & contentLen , & isWhitespace ) ;
if ( nsnull = = bp ) {
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-03-23 22:58:43 +00:00
aTextData . mInWord = PR_FALSE ;
// Measure the word/whitespace
nscoord width ;
if ( isWhitespace ) {
if ( ' \n ' = = bp [ 0 ] ) {
// 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 ;
// Only set flag when we actually do skip whitespace
mState | = TEXT_SKIP_LEADING_WS ;
continue ;
}
if ( ' \t ' = = bp [ 0 ] ) {
// Expand tabs to the proper width
2000-03-31 04:27:43 +00:00
wordLen = 8 - ( 7 & column ) ;
2000-03-23 22:58:43 +00:00
width = aTs . mSpaceWidth * wordLen ;
}
2000-03-31 04:27:43 +00:00
else if ( textRun . IsBuffering ( ) ) {
textRun . AddWhitespace ( bp , wordLen , contentLen ) ;
continue ;
}
2000-03-23 22:58:43 +00:00
else {
width = ( wordLen * aTs . mSpaceWidth ) + aTs . mWordSpacing ; // XXX simplistic
}
aTextData . mIsBreakable = PR_TRUE ;
aTextData . mFirstLetterOK = PR_FALSE ;
2000-03-31 04:27:43 +00:00
if ( aTextData . mMeasureText ) {
// See if there is room for the text
if ( ( 0 ! = aTextData . mX ) & & aTextData . mWrapping & & ( aTextData . mX + width > maxWidth ) ) {
// The text will not fit.
break ;
}
aTextData . mX + = width ;
}
prevColumn = column ;
column + = wordLen ;
endsInWhitespace = PR_TRUE ;
prevOffset = aTextData . mOffset ;
aTextData . mOffset + = contentLen ;
2000-03-23 22:58:43 +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.
if ( aTextData . mWrapping & & firstThing & & ( bp [ 0 ] = = ' ' ) ) {
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
if ( ( bp [ 0 ] = = ' \' ' ) | | ( bp [ 0 ] = = ' \" ' ) ) {
wordLen = 2 ;
contentLen = 2 ;
}
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
textRun . AddWord ( bp , wordLen , contentLen ) ;
// See if we should measure the text
if ( ( textRun . mBufLength > = estimatedNumChars ) | |
( 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 ) {
MeasureSmallCapsText ( aReflowState , aTs , bp , wordLen , & width ) ;
}
else {
// Measure just the one word
aReflowState . rendContext - > GetWidth ( bp , wordLen , width ) ;
if ( aTs . mLetterSpacing ) {
width + = aTs . mLetterSpacing * wordLen ;
}
}
lastWordWidth = width ;
// See if there is room for the text
if ( ( 0 ! = aTextData . mX ) & & aTextData . mWrapping & & ( aTextData . mX + width > maxWidth ) ) {
// The text will not fit.
break ;
}
aTextData . mX + = width ;
prevMaxWordWidth = aTextData . mMaxWordWidth ;
if ( width > aTextData . mMaxWordWidth ) {
aTextData . mMaxWordWidth = width ;
}
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 :
# ifdef _WIN32
PRInt32 numCharsFit ;
aReflowState . rendContext - > GetWidth ( textRun . mBuf , textRun . mBufLength ,
maxWidth - aTextData . mX ,
textRun . mBreaks , textRun . mNumSegments ,
width , numCharsFit ) ;
// See how much of the text fit
if ( ( 0 ! = aTextData . mX ) & & aTextData . mWrapping & & ( aTextData . mX + width > maxWidth ) ) {
// None of the text fits
break ;
}
// Find the index of the last segment that fit
PRInt32 lastSegment = textRun . mNumSegments - 1 ;
if ( textRun . mBufLength ! = numCharsFit ) {
for ( lastSegment = 0 ; textRun . mBreaks [ lastSegment ] < numCharsFit ; lastSegment + + ) ;
NS_ASSERTION ( lastSegment < textRun . mNumSegments , " failed to find segment " ) ;
}
if ( lastSegment = = 0 ) {
// Only one segment fit
prevColumn = column ;
prevOffset = aTextData . mOffset ;
} else {
// The previous state is for the next to last word
prevColumn = textRun . mBreaks [ lastSegment - 1 ] ;
prevOffset = textRun . mSegments [ lastSegment - 1 ] . ContentLen ( ) ;
}
aTextData . mX + = width ;
column + = numCharsFit ;
aTextData . mOffset + = textRun . mSegments [ lastSegment ] . ContentLen ( ) ;
endsInWhitespace = textRun . mSegments [ lastSegment ] . IsWhitespace ( ) ;
// If all the text didn't fit, then we're done
if ( textRun . mBufLength ! = numCharsFit ) {
break ;
}
if ( nsnull = = bp ) {
// No more text so we're all finished. Advance the offset in case we
// just consumed a bunch of discarded characters
aTextData . mOffset + = contentLen ;
break ;
}
// Reset the number of text run segments
textRun . Reset ( ) ;
// Estimate the number of characters we think will fit
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 ) {
aTextData . mX = mRect . width ;
if ( mState & TEXT_TRIMMED_WS ) {
// Add back in the width of a space since it was trimmed away last time
aTextData . mX + = aTs . mSpaceWidth ;
}
}
// 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 ) ;
printf ( " : in word; skipping \n " ) ;
# 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.
nsIFrame * next = lineLayout . FindNextText ( this ) ;
if ( nsnull ! = next ) {
# ifdef DEBUG_WORD_WRAPPING
nsAutoString tmp ( aTx . GetWordBuffer ( ) , lastWordLen ) ;
ListTag ( stdout ) ;
printf ( " : start=' " ) ;
fputs ( tmp , stdout ) ;
printf ( " ' lastWordLen=%d baseWidth=%d prevOffset=%d offset=%d next= " ,
lastWordLen , lastWordWidth , prevOffset , aTextData . mOffset ) ;
ListTag ( stdout , next ) ;
printf ( " \n " ) ;
# endif
PRUnichar * pWordBuf = aTx . GetWordBuffer ( ) ;
PRUint32 wordBufLen = aTx . GetWordBufferLength ( ) ;
// 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.
if ( ! aTextData . mMeasureText ) {
// We didn't measure any text so we don't know lastWordWidth.
// We have to compute it now
if ( prevOffset = = startingOffset ) {
// There's only one word, so we don't have to measure after all
lastWordWidth = aTextData . mX ;
}
else if ( aTs . mSmallCaps ) {
MeasureSmallCapsText ( aReflowState , aTs , aTx . GetWordBuffer ( ) ,
lastWordLen , & lastWordWidth ) ;
}
else {
aReflowState . rendContext - > GetWidth ( aTx . GetWordBuffer ( ) ,
lastWordLen , lastWordWidth ) ;
if ( aTs . mLetterSpacing ) {
lastWordWidth + = aTs . mLetterSpacing * lastWordLen ;
}
}
}
nscoord wordWidth = ComputeTotalWordWidth ( aPresContext , aLb ,
lineLayout ,
aReflowState , next ,
lastWordWidth ,
pWordBuf ,
lastWordLen ,
wordBufLen ) ;
if ( ! aTextData . mIsBreakable | | ( aTextData . mX - lastWordWidth + wordWidth < = maxWidth ) ) {
// 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)
if ( wordWidth > aTextData . mMaxWordWidth ) {
aTextData . mMaxWordWidth = wordWidth ;
}
}
else {
# ifdef NOISY_REFLOW
ListTag ( stdout ) ;
printf ( " : look-ahead (didn't fit) x=%d wordWidth=%d lastWordWidth=%d \n " ,
aTextData . mX , wordWidth , lastWordWidth ) ;
# endif
// The fully joined word won't fit. We need to reduce our
// size by the lastWordWidth.
aTextData . mX - = lastWordWidth ;
aTextData . mMaxWordWidth = prevMaxWordWidth ;
aTextData . mOffset = prevOffset ;
column = prevColumn ;
# ifdef DEBUG_WORD_WRAPPING
printf ( " x=%d maxWordWidth=%d len=%d \n " , aTextData . mX , aTextData . mMaxWordWidth ,
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 )
? 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
1999-11-24 06:03:41 +00:00
nsTextFrame : : Reflow ( nsIPresContext * aPresContext ,
1999-04-20 00:23:33 +00:00
nsHTMLReflowMetrics & aMetrics ,
const nsHTMLReflowState & aReflowState ,
nsReflowStatus & aStatus )
1998-09-08 22:34:40 +00:00
{
1999-09-17 23:14:47 +00:00
# ifdef NOISY_REFLOW
ListTag ( stdout ) ;
printf ( " : BeginReflow: availableSize=%d,%d \n " ,
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
}
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 ;
1998-10-26 17:27:53 +00:00
if ( ts . mFont - > mFont . decorations & NS_STYLE_TEXT_DECORATION_BLINK ) {
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 ) ) ;
1999-12-07 22:04:52 +00:00
if ( NS_WARN_IF_FALSE ( doc , " Content has no document. " ) ) {
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 ) ) ;
1999-09-22 00:40:56 +00:00
nsTextTransformer tx ( lb , nsnull ) ;
1999-09-16 23:31:59 +00:00
nsresult rv = tx . Init ( this , mContent , startingOffset ) ;
1998-10-20 00:21:18 +00:00
if ( NS_OK ! = rv ) {
return rv ;
}
PRInt32 contentLength = tx . GetContentLength ( ) ;
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)
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 ) {
realWidth + = ts . mSpaceWidth ;
}
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 ) ) | |
( ! wrapping & & ( prevColumn = = column ) ) ) ) {
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
printf ( " => measureText=%s wrapping=%s skipWhitespace=%s " ,
measureText ? " yes " : " no " ,
wrapping ? " yes " : " no " ,
skipWhitespace ? " yes " : " no " ) ;
printf ( " realWidth=%d maxWidth=%d \n " ,
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 ( ) ,
2000-03-31 04:27:43 +00:00
lineLayout . LineIsBreakable ( ) , nsnull ! = aMetrics . maxElementSize ) ;
2000-03-23 22:58:43 +00:00
2000-03-31 04:27:43 +00:00
// Measure the text
aStatus = MeasureText ( aPresContext , aReflowState , tx , lb , ts , textData ) ;
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
}
1998-10-10 04:35:21 +00:00
1999-09-21 00:12:50 +00:00
mState & = ~ TEXT_TRIMMED_WS ;
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 {
1998-10-26 17:27:53 +00:00
ts . mNormalFont - > GetHeight ( aMetrics . height ) ;
ts . mNormalFont - > GetMaxAscent ( aMetrics . ascent ) ;
ts . mNormalFont - > GetMaxDescent ( aMetrics . descent ) ;
1998-10-20 00:21:18 +00:00
}
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-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
nsStyleFont font ;
mStyleContext - > GetStyle ( eStyleStruct_Font , font ) ;
aReflowState . rendContext - > SetFont ( font . mFont ) ;
// Now get the exact bounding metrics of the text
nsBoundingMetrics bm ;
rv = aReflowState . rendContext - > GetBoundingMetrics ( aText . GetUnicode ( ) , PRUint32 ( mContentLength ) , bm ) ;
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-01-07 14:33:11 +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
1999-07-14 15:20:01 +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...
2000-01-19 03:58:05 +00:00
if ( eReflowReason_Incremental = = aReflowState . reason | |
eReflowReason_Dirty = = aReflowState . reason ) {
1999-11-24 06:03:41 +00:00
Invalidate ( aPresContext , mRect ) ;
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
if ( ( NS_FRAME_COMPLETE = = aStatus ) & & ( aMetrics . width < = maxWidth ) ) {
mState | = TEXT_OPTIMIZE_RESIZE ;
mRect . width = aMetrics . width ;
}
else {
mState & = ~ TEXT_OPTIMIZE_RESIZE ;
}
1999-09-17 23:14:47 +00:00
# ifdef NOISY_REFLOW
ListTag ( stdout ) ;
printf ( " : desiredSize=%d,%d(a=%d/d=%d) status=%x \n " ,
aMetrics . width , aMetrics . height , aMetrics . ascent , aMetrics . descent ,
aStatus ) ;
# endif
1998-10-21 20:03:54 +00:00
return NS_OK ;
1998-09-08 22:34:40 +00:00
}
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
{
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.
const nsStyleFont * fontStyle = ( const nsStyleFont * )
mStyleContext - > GetStyleData ( eStyleStruct_Font ) ;
aRC . SetFont ( fontStyle - > mFont ) ;
aRC . GetWidth ( ' ' , dw ) ;
1998-10-27 16:52:34 +00:00
}
}
}
}
1999-09-21 00:12:50 +00:00
# ifdef NOISY_TRIM
ListTag ( stdout ) ;
printf ( " : trim => %d \n " , dw ) ;
# 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 ;
}
}
}
1998-10-10 04:35:21 +00:00
nscoord
1999-04-20 00:23:33 +00:00
nsTextFrame : : ComputeTotalWordWidth ( 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 ,
1999-07-27 14:47:24 +00:00
nscoord aBaseWidth ,
1999-11-01 15:36:02 +00:00
PRUnichar * aWordBuf ,
1999-09-22 00:40:56 +00:00
PRUint32 aWordLen ,
1999-07-27 14:47:24 +00:00
PRUint32 aWordBufSize )
1998-10-10 04:35:21 +00:00
{
1999-11-01 15:36:02 +00:00
// 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 ) ;
1998-10-10 04:35:21 +00:00
nscoord addedWidth = 0 ;
while ( nsnull ! = aNextFrame ) {
1999-04-21 19:59:16 +00:00
nsIContent * content = nsnull ;
if ( ( NS_OK = = aNextFrame - > GetContent ( & content ) ) & & ( nsnull ! = content ) ) {
1998-10-10 04:35:21 +00:00
# ifdef DEBUG_WORD_WRAPPING
1999-04-21 19:59:16 +00:00
printf ( " next textRun= " ) ;
nsFrame : : ListTag ( stdout , aNextFrame ) ;
printf ( " \n " ) ;
1998-10-10 04:35:21 +00:00
# endif
1999-04-21 19:59:16 +00:00
nsITextContent * tc ;
if ( NS_OK = = content - > QueryInterface ( kITextContentIID , ( void * * ) & tc ) ) {
1999-11-01 15:36:02 +00:00
PRBool stop = PR_FALSE ;
1999-04-21 19:59:16 +00:00
nscoord moreWidth = ComputeWordFragmentWidth ( aPresContext ,
1999-09-16 23:31:59 +00:00
aLineBreaker ,
1999-04-21 19:59:16 +00:00
aLineLayout ,
aReflowState ,
1999-09-17 23:14:47 +00:00
aNextFrame , content , tc ,
1999-07-27 14:47:24 +00:00
& stop ,
aWordBuf ,
1999-09-22 00:40:56 +00:00
aWordLen ,
1999-07-27 14:47:24 +00:00
aWordBufSize ) ;
1999-04-21 19:59:16 +00:00
NS_RELEASE ( tc ) ;
NS_RELEASE ( content ) ;
addedWidth + = moreWidth ;
1998-10-10 04:35:21 +00:00
# ifdef DEBUG_WORD_WRAPPING
1999-04-21 19:59:16 +00:00
printf ( " moreWidth=%d (addedWidth=%d) stop=%c \n " , moreWidth ,
addedWidth , stop ? ' T ' : ' F ' ) ;
1998-10-10 04:35:21 +00:00
# endif
1999-04-21 19:59:16 +00:00
if ( stop ) {
1998-10-10 04:35:21 +00:00
goto done ;
}
}
1999-04-21 19:59:16 +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.
NS_RELEASE ( content ) ;
goto done ;
}
1998-10-10 04:35:21 +00:00
}
// Move on to the next frame in the text-run
aNextFrame = aLineLayout . FindNextText ( aNextFrame ) ;
}
done : ;
# ifdef DEBUG_WORD_WRAPPING
printf ( " total word width=%d \n " , aBaseWidth + addedWidth ) ;
# endif
return aBaseWidth + addedWidth ;
}
1999-04-20 00:23:33 +00:00
nscoord
nsTextFrame : : ComputeWordFragmentWidth ( 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 ,
1999-07-27 14:47:24 +00:00
PRUint32 aWordBufSize )
1998-10-10 04:35:21 +00:00
{
1999-09-22 00:40:56 +00:00
nsTextTransformer tx ( aLineBreaker , nsnull ) ;
1999-09-17 23:14:47 +00:00
tx . Init ( aTextFrame , aContent , 0 ) ;
1998-10-20 00:21:18 +00:00
PRBool isWhitespace ;
PRInt32 wordLen , contentLen ;
1999-10-19 23:01:58 +00:00
PRUnichar * bp = tx . GetNextWord ( PR_TRUE , & wordLen , & contentLen ,
& isWhitespace ) ;
1999-09-22 00:40:56 +00:00
if ( ! bp | | 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 ;
1998-10-10 04:35:21 +00:00
return 0 ;
}
1999-04-20 00:23:33 +00:00
* aStop = contentLen < tx . GetContentLength ( ) ;
1998-10-10 04:35:21 +00:00
1999-11-01 15:36:02 +00:00
// Convert any spaces in the current word back to nbsp's. This keeps
// the breaking logic happy.
RevertSpacesToNBSP ( bp , wordLen ) ;
1999-09-22 00:40:56 +00:00
// We need to adjust the length by look at the two pieces together
// XXX this should grow aWordBuf if necessary
PRUint32 copylen = sizeof ( PRUnichar ) *
( ( ( wordLen + aRunningWordLen ) > aWordBufSize )
? ( aWordBufSize - aRunningWordLen )
: wordLen
) ;
if ( ( aWordBufSize > aRunningWordLen ) & & ( copylen > 0 ) )
1999-07-27 14:47:24 +00:00
{
1999-09-22 00:40:56 +00:00
nsCRT : : memcpy ( ( void * ) & ( aWordBuf [ aRunningWordLen ] ) , bp , copylen ) ;
1999-07-27 14:47:24 +00:00
PRUint32 breakP = 0 ;
PRBool needMore = PR_TRUE ;
1999-09-22 00:40:56 +00:00
nsresult lres = aLineBreaker - > Next ( aWordBuf , aRunningWordLen + wordLen ,
0 , & breakP , & needMore ) ;
1999-07-27 14:47:24 +00:00
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
1999-09-22 00:40:56 +00:00
if ( ! needMore & & ( breakP < ( aRunningWordLen + wordLen ) ) )
1999-07-27 14:47:24 +00:00
{
1999-09-22 00:40:56 +00:00
wordLen = breakP - aRunningWordLen ;
1999-07-27 14:47:24 +00:00
if ( wordLen < 0 )
wordLen = 0 ;
* aStop = PR_TRUE ;
}
}
1999-09-22 00:40:56 +00:00
// 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
1999-07-27 14:47:24 +00:00
if ( ! * aStop )
1999-09-22 00:40:56 +00:00
aRunningWordLen + = wordLen ;
1999-07-27 14:47:24 +00:00
}
if ( ( * aStop ) & & ( wordLen = = 0 ) )
return 0 ;
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.
nscoord width ;
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 ) {
1999-09-22 00:40:56 +00:00
MeasureSmallCapsText ( aReflowState , ts , bp , wordLen , & width ) ;
1998-10-20 00:21:18 +00:00
}
else {
1999-09-22 00:40:56 +00:00
rc . GetWidth ( bp , wordLen , width ) ;
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 ) ;
1998-10-10 04:35:21 +00:00
printf ( " fragment=' " ) ;
fputs ( tmp , stdout ) ;
1998-10-20 00:21:18 +00:00
printf ( " ' width=%d [wordLen=%d contentLen=%d ContentLength=%d] \n " ,
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 ) ;
return width ;
}
1999-04-20 00:23:33 +00:00
* aStop = PR_TRUE ;
1998-10-10 04:35:21 +00:00
return 0 ;
}
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
nsITextContent * tc ;
if ( NS_OK ! = mContent - > QueryInterface ( kITextContentIID , ( void * * ) & tc ) ) {
return ;
}
1999-10-15 23:36:07 +00:00
tc - > GetText ( & frag ) ;
1998-10-20 00:21:18 +00:00
NS_RELEASE ( tc ) ;
// 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 ' ) {
aBuf . Append ( " \\ r " ) ;
} else if ( ch = = ' \n ' ) {
aBuf . Append ( " \\ n " ) ;
} else if ( ch = = ' \t ' ) {
aBuf . Append ( " \\ t " ) ;
} else if ( ( ch < ' ' ) | | ( ch > = 127 ) ) {
aBuf . Append ( " \\ 0 " ) ;
aBuf . Append ( ( PRInt32 ) ch , 8 ) ;
} 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 ;
}
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
1999-04-20 00:23:33 +00:00
nsTextFrame : : GetFrameName ( nsString & aResult ) const
1998-09-08 22:34:40 +00:00
{
1998-11-19 17:22:29 +00:00
return MakeFrameName ( " 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 ) ;
nsIView * view ;
1999-10-26 04:44:41 +00:00
GetView ( aPresContext , & view ) ;
1998-09-08 22:34:40 +00:00
if ( nsnull ! = view ) {
fprintf ( out , " [view=%p] " , view ) ;
}
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 ) {
fprintf ( out , " next=%p " , mNextSibling ) ;
}
1999-10-23 23:19:14 +00:00
nsIFrame * prevInFlow ;
GetPrevInFlow ( & prevInFlow ) ;
if ( nsnull ! = prevInFlow ) {
fprintf ( out , " prev-in-flow=%p " , prevInFlow ) ;
1998-09-08 22:34:40 +00:00
}
if ( nsnull ! = mNextInFlow ) {
1999-09-21 00:12:50 +00:00
fprintf ( out , " next-in-flow=%p " , 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 ) {
fprintf ( out , " [state=%08x] " , mState ) ;
}
1999-04-27 22:13:42 +00:00
fprintf ( out , " sc=%p< \n " , mStyleContext ) ;
1998-09-08 22:34:40 +00:00
// Output the text
aIndent + + ;
1999-03-05 04:28:40 +00:00
IndentBy ( out , aIndent ) ;
1998-09-08 22:34:40 +00:00
fputs ( " \" " , out ) ;
fputs ( tmp , out ) ;
fputs ( " \" \n " , out ) ;
aIndent - - ;
1999-03-05 04:28:40 +00:00
IndentBy ( out , aIndent ) ;
1998-09-08 22:34:40 +00:00
fputs ( " > \n " , out ) ;
return NS_OK ;
}
1999-11-01 22:12:45 +00:00
# endif