mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-01 22:55:23 +00:00
364 lines
12 KiB
C++
364 lines
12 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
*
|
|
* The contents of this file are subject to the Netscape Public License
|
|
* Version 1.0 (the "NPL"); you may not use this file except in
|
|
* compliance with the NPL. You may obtain a copy of the NPL at
|
|
* http://www.mozilla.org/NPL/
|
|
*
|
|
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
|
* for the specific language governing rights and limitations under the
|
|
* NPL.
|
|
*
|
|
* The Initial Developer of this code under the NPL is Netscape
|
|
* Communications Corporation. Portions created by Netscape are
|
|
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
|
* Reserved.
|
|
*/
|
|
|
|
// UTextBox.cp
|
|
|
|
// Based on "The TextBox You've Always Wanted" by Bryan K. Ressler (Beaker) in develop #9
|
|
|
|
#ifdef PowerPlant_PCH
|
|
#include PowerPlant_PCH
|
|
#endif
|
|
|
|
#include "UTextBox.h"
|
|
|
|
#include <Gestalt.h>
|
|
#include <Fonts.h>
|
|
#include <FixMath.h>
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// ¥ UTextBox
|
|
// ---------------------------------------------------------------------------
|
|
// Constructor
|
|
|
|
/*
|
|
void
|
|
UTextBox::UTextBox( void )
|
|
{
|
|
long gestResult;
|
|
|
|
::Gestalt( gestaltFontMgrAttr, &gestResult );
|
|
hasTrueType = ( gestResult & gestaltOutlineFonts );
|
|
}
|
|
*/
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// ¥ TBLineHeight
|
|
// ---------------------------------------------------------------------------
|
|
// Figures line height
|
|
//
|
|
// Input: theText the entire text that was given to the DrawTextBox call
|
|
// textLen the length in bytes of the text
|
|
// lhCode the line height code that was passed to DrawTextBox
|
|
// startY VAR - we return the starting vertical pen location here
|
|
//
|
|
// Output: returns the line height to use
|
|
//
|
|
|
|
unsigned short
|
|
UTextBox::TBLineHeight( Ptr theText, unsigned long textLen,
|
|
Rect *wrapBox, short lhCode, short *startY )
|
|
{
|
|
short asc,desc; /* Used in the OutlineMetrics calls */
|
|
FontInfo fInfo; /* The old-style font information record */
|
|
Point frac; /* The fraction for the TrueType calls */
|
|
unsigned short lineHeight; /* The return value */
|
|
Boolean hasTrueType;
|
|
long gestResult;
|
|
|
|
::Gestalt( gestaltFontMgrAttr, &gestResult );
|
|
hasTrueType = ( gestResult & gestaltOutlineFonts );
|
|
|
|
::GetFontInfo( &fInfo );
|
|
if (lhCode < 0) {
|
|
frac.h = frac.v = 1;
|
|
if ( hasTrueType && ::IsOutline(frac, frac) ) {
|
|
::OutlineMetrics( (short)textLen, theText, frac, frac, &asc, &desc,
|
|
nil, nil, nil );
|
|
lineHeight = MAXOF(fInfo.ascent, asc) + MAXOF(fInfo. descent,-desc) +
|
|
fInfo.leading;
|
|
*startY = wrapBox->top + MAXOF(fInfo.ascent, asc);
|
|
*startY += fInfo.leading;
|
|
} else {
|
|
lineHeight = fInfo.ascent + fInfo.descent + fInfo.leading;
|
|
*startY = wrapBox->top + fInfo.ascent + fInfo.leading;
|
|
}
|
|
} else if (lhCode == 0) {
|
|
lineHeight = fInfo.ascent + fInfo.descent + fInfo.leading;
|
|
*startY = wrapBox->top + fInfo.ascent + fInfo.leading;
|
|
} else {
|
|
lineHeight = lhCode;
|
|
*startY = wrapBox->top + lhCode + fInfo.leading;
|
|
}
|
|
|
|
return(lineHeight);
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// ¥ TBDraw
|
|
// ---------------------------------------------------------------------------
|
|
// Draws a line with appropriate justification
|
|
//
|
|
// Input: breakCode the break code that was returned from StyledLineBreak
|
|
// lineStart pointer to the beginning of the text for the current line
|
|
// lineBytes the length in bytes of the the text for this line
|
|
// wrapBox the box within which we're wrapping
|
|
// align the text alignment as specified by the user
|
|
// curY our current vertical pen coordinate
|
|
// boxWidth the width of wrapBox (since DrawTextBox already calculated it)
|
|
//
|
|
// Output: none (draws on the screen)
|
|
//
|
|
|
|
void
|
|
UTextBox::TBDraw( StyledLineBreakCode breakCode, Ptr lineStart,
|
|
long lineBytes, Rect *wrapBox, short align, short curY, short boxWidth )
|
|
{
|
|
unsigned long blackLen; /* Length of non-white characters */
|
|
short slop; /* Number of pixels of slop for full just */
|
|
|
|
blackLen = ::VisibleLength( (Ptr)lineStart, lineBytes);
|
|
|
|
if (align == ntbJustFull) {
|
|
slop = boxWidth - ::TextWidth(lineStart, 0, blackLen);
|
|
::MoveTo(wrapBox->left, curY);
|
|
if (breakCode == smBreakOverflow ||
|
|
*(lineStart + (lineBytes - 1)) == kReturnChar)
|
|
align = ::GetSysDirection();
|
|
else
|
|
::DrawJust( (Ptr)lineStart, blackLen, slop );
|
|
}
|
|
|
|
switch(align) {
|
|
case teForceLeft:
|
|
case teJustLeft:
|
|
::MoveTo(wrapBox->left, curY);
|
|
break;
|
|
case teJustRight:
|
|
::MoveTo(wrapBox->right - TextWidth(lineStart, 0, blackLen), curY);
|
|
break;
|
|
case teJustCenter:
|
|
::MoveTo(wrapBox->left + (boxWidth - ::TextWidth(lineStart, 0, blackLen)) / 2,
|
|
curY);
|
|
break;
|
|
}
|
|
if (align != ntbJustFull)
|
|
::DrawText(lineStart, 0, lineBytes);
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// ¥ DrawTextBox
|
|
// ---------------------------------------------------------------------------
|
|
// Word-wraps text inside a given box
|
|
//
|
|
// Input: theText the text we need to wrap
|
|
// textLen the length in bytes of the text
|
|
// wrapBox the box within which we're wrapping
|
|
// align the text alignment
|
|
// teForceLeft, teFlushLeft left justified
|
|
// teJustCenter, teCenter center justified
|
|
// teJustRight, teFlushRight right justified
|
|
// ntbJustFull full justified
|
|
// teJustLeft, teFlushDefault system justified
|
|
// lhCode the line height code that was passed to DrawTextBox
|
|
// < 0 variable - based on tallest character
|
|
// 0 default - based on GetFontInfo
|
|
// > 0 fixed - use lhCode as the line height
|
|
// endY VAR - if non-nil, the vertical coord of the last line
|
|
// lhUsed VAR - if non-nil, the line height used to draw the text
|
|
//
|
|
// Output: returns the number of line drawn total (even if they drew outside of
|
|
// the boundries of wrapBox)
|
|
//
|
|
|
|
short
|
|
UTextBox::DrawTextBox( Ptr theText, unsigned long textLen, Rect *wrapBox,
|
|
short align, short lhCode, short *endY, short *lhUsed)
|
|
{
|
|
StyledLineBreakCode breakCode; /* Returned code from StyledLineBreak */
|
|
Fixed fixedMax; /* boxWidth converted to fixed point */
|
|
Fixed wrapWid; /* Width to wrap to */
|
|
short boxWidth; /* Width of the wrapBox */
|
|
long lineBytes; /* Number of bytes in one line */
|
|
unsigned short lineHeight; /* Calculated line height */
|
|
short curY; /* Current vertical pen location */
|
|
unsigned short lineCount; /* Number of lines we've drawn */
|
|
long textLeft; /* Pointer to remaining bytes of text */
|
|
Ptr lineStart; /* Pointer to beginning of a line */
|
|
Ptr textEnd; /* Pointer to the end of input text */
|
|
|
|
boxWidth = wrapBox->right - wrapBox->left;
|
|
fixedMax = ::Long2Fix((long)boxWidth);
|
|
if (align == teFlushDefault)
|
|
align = ::GetSysDirection();
|
|
|
|
lineHeight = UTextBox::TBLineHeight(theText, textLen, wrapBox, lhCode, &curY);
|
|
lineCount = 0;
|
|
lineStart = theText;
|
|
textEnd = theText + textLen;
|
|
textLeft = textLen;
|
|
|
|
do {
|
|
lineBytes = 1;
|
|
wrapWid = fixedMax;
|
|
|
|
breakCode = ::StyledLineBreak( (Ptr)lineStart, textLeft, 0, textLeft, 0,
|
|
&wrapWid, &lineBytes );
|
|
|
|
UTextBox::TBDraw(breakCode, lineStart, lineBytes, wrapBox, align, curY, boxWidth);
|
|
curY += lineHeight;
|
|
lineStart += lineBytes;
|
|
textLeft -= lineBytes;
|
|
lineCount++;
|
|
|
|
} while (lineStart < textEnd);
|
|
|
|
if (endY)
|
|
*endY = curY - lineHeight;
|
|
if (lhUsed)
|
|
*lhUsed = lineHeight;
|
|
|
|
return(lineCount);
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// ¥ DrawTextBox
|
|
// ---------------------------------------------------------------------------
|
|
// Word-wraps text inside a given box
|
|
//
|
|
// Input: theText the text we need to wrap
|
|
// textLen the length in bytes of the text
|
|
// wrapBox the box within which we're wrapping
|
|
// align the text alignment
|
|
// teForceLeft, teFlushLeft left justified
|
|
// teJustCenter, teCenter center justified
|
|
// teJustRight, teFlushRight right justified
|
|
// ntbJustFull full justified
|
|
// teJustLeft, teFlushDefault system justified
|
|
// lhCode the line height code that was passed to DrawTextBox
|
|
// < 0 variable - based on tallest character
|
|
// 0 default - based on GetFontInfo
|
|
// > 0 fixed - use lhCode as the line height
|
|
//
|
|
//
|
|
|
|
void
|
|
UTextBox::DrawTextBox( Ptr theText, unsigned long textLen, Rect *wrapBox,
|
|
short align, short lhCode )
|
|
{
|
|
RgnHandle oldClip; /* Saved clipping region */
|
|
StyledLineBreakCode breakCode; /* Returned code from StyledLineBreak */
|
|
Fixed fixedMax; /* boxWidth converted to fixed point */
|
|
Fixed wrapWid; /* Width to wrap to */
|
|
short boxWidth; /* Width of the wrapBox */
|
|
long lineBytes; /* Number of bytes in one line */
|
|
unsigned short lineHeight; /* Calculated line height */
|
|
short curY; /* Current vertical pen location */
|
|
unsigned short lineCount; /* Number of lines we've drawn */
|
|
long textLeft; /* Pointer to remaining bytes of text */
|
|
Ptr lineStart; /* Pointer to beginning of a line */
|
|
Ptr textEnd; /* Pointer to the end of input text */
|
|
|
|
::GetClip((oldClip = ::NewRgn()));
|
|
::ClipRect(wrapBox);
|
|
boxWidth = wrapBox->right - wrapBox->left;
|
|
fixedMax = ::Long2Fix((long)boxWidth);
|
|
if (align == teFlushDefault)
|
|
align = ::GetSysDirection();
|
|
|
|
lineHeight = UTextBox::TBLineHeight(theText, textLen, wrapBox, lhCode, &curY);
|
|
lineCount = 0;
|
|
lineStart = theText;
|
|
textEnd = theText + textLen;
|
|
textLeft = textLen;
|
|
|
|
do {
|
|
lineBytes = 1;
|
|
wrapWid = fixedMax;
|
|
|
|
breakCode = ::StyledLineBreak( (Ptr)lineStart, textLeft, 0, textLeft, 0,
|
|
&wrapWid, &lineBytes );
|
|
|
|
UTextBox::TBDraw(breakCode, lineStart, lineBytes, wrapBox, align, curY, boxWidth);
|
|
|
|
curY += lineHeight;
|
|
lineStart += lineBytes;
|
|
textLeft -= lineBytes;
|
|
lineCount++;
|
|
|
|
} while ((lineStart < textEnd) & ( curY <= (wrapBox->bottom + lineHeight) ));
|
|
|
|
::SetClip(oldClip);
|
|
::DisposeRgn(oldClip);
|
|
|
|
}
|
|
|
|
// Hacked up, copied version of DrawTextBox. Returns the height needed for the lines
|
|
// DESTROYS THE ORIGINAL STRING
|
|
// pkc (6/6/96) added scan for '\n' to determine line breaks since StyledLineBreak doesn't
|
|
// consider '\n' to be a line break.
|
|
short UTextBox::TextBoxDialogHeight( Ptr theText, unsigned long textLen, Rect *wrapBox,
|
|
short align, short lhCode)
|
|
{
|
|
StyledLineBreakCode breakCode; /* Returned code from StyledLineBreak */
|
|
Fixed fixedMax; /* boxWidth converted to fixed point */
|
|
Fixed wrapWid; /* Width to wrap to */
|
|
short boxWidth; /* Width of the wrapBox */
|
|
long lineBytes; /* Number of bytes in one line */
|
|
unsigned short lineHeight; /* Calculated line height */
|
|
short curY; /* Current vertical pen location */
|
|
unsigned short lineCount; /* Number of lines we've drawn */
|
|
long textLeft; /* Pointer to remaining bytes of text */
|
|
Ptr lineStart; /* Pointer to beginning of a line */
|
|
Ptr textEnd; /* Pointer to the end of input text */
|
|
Ptr scanner; /* Pointer to scan for '\n' */
|
|
|
|
boxWidth = wrapBox->right - wrapBox->left;
|
|
fixedMax = ::Long2Fix((long)boxWidth);
|
|
if (align == teFlushDefault)
|
|
align = ::GetSysDirection();
|
|
|
|
lineHeight = UTextBox::TBLineHeight(theText, textLen, wrapBox, lhCode, &curY);
|
|
lineCount = 0;
|
|
lineStart = theText;
|
|
textEnd = theText + textLen;
|
|
textLeft = textLen;
|
|
|
|
// ¥¥¥ HACK
|
|
|
|
for (int i=0; i< textLen; i++)
|
|
{
|
|
if (theText[i] == '/')
|
|
theText[i] = 'w';
|
|
}
|
|
do {
|
|
lineBytes = 1;
|
|
wrapWid = fixedMax;
|
|
|
|
breakCode = ::StyledLineBreak( (Ptr)lineStart, textLeft, 0, textLeft, 0,
|
|
&wrapWid, &lineBytes );
|
|
// pkc (6/6/96) now scan for '\n' because StyledLineBreak doesn't take '\n' into account
|
|
scanner = lineStart;
|
|
while( *scanner != '\n' && scanner < textEnd )
|
|
++scanner;
|
|
// pkc (6/6/96) move past '\n'
|
|
++scanner;
|
|
// pkc (6/6/96) if there is a '\n' before where StyledLineBreak says that there should be
|
|
// a break, we should break at the '\n'
|
|
if( scanner < textEnd && scanner - lineStart < lineBytes )
|
|
lineBytes = scanner - lineStart;
|
|
curY += lineHeight;
|
|
lineStart += lineBytes;
|
|
textLeft -= lineBytes;
|
|
lineCount++;
|
|
|
|
} while (lineStart < textEnd);
|
|
|
|
|
|
return(lineCount * lineHeight);
|
|
}
|