mirror of
https://github.com/unicode-org/icu.git
synced 2025-04-14 17:24:01 +00:00
RichEdit control formatting engine. This package uses the Java2D Complex Text API's.
X-SVN-Rev: 1190
This commit is contained in:
parent
d6ed5975e9
commit
bf82494a6f
11 changed files with 4876 additions and 0 deletions
2053
icu4j/src/com/ibm/richtext/textformat/AsyncFormatter.java
Executable file
2053
icu4j/src/com/ibm/richtext/textformat/AsyncFormatter.java
Executable file
File diff suppressed because it is too large
Load diff
1150
icu4j/src/com/ibm/richtext/textformat/BidiParagraphRenderer.java
Executable file
1150
icu4j/src/com/ibm/richtext/textformat/BidiParagraphRenderer.java
Executable file
File diff suppressed because it is too large
Load diff
142
icu4j/src/com/ibm/richtext/textformat/ClipWorkaround.java
Executable file
142
icu4j/src/com/ibm/richtext/textformat/ClipWorkaround.java
Executable file
|
@ -0,0 +1,142 @@
|
|||
/*
|
||||
* @(#)$RCSfile: ClipWorkaround.java,v $ $Revision: 1.1 $ $Date: 2000/04/20 17:50:03 $
|
||||
*
|
||||
* (C) Copyright IBM Corp. 1998-1999. All Rights Reserved.
|
||||
*
|
||||
* The program is provided "as is" without any warranty express or
|
||||
* implied, including the warranty of non-infringement and the implied
|
||||
* warranties of merchantibility and fitness for a particular purpose.
|
||||
* IBM will not be liable for any damages suffered by you as a result
|
||||
* of using the Program. In no event will IBM be liable for any
|
||||
* special, indirect or consequential damages or lost profits even if
|
||||
* IBM has been advised of the possibility of their occurrence. IBM
|
||||
* will not be liable for any third party claims against you.
|
||||
*/
|
||||
// Requires Java2
|
||||
|
||||
package com.ibm.richtext.textformat;
|
||||
|
||||
import java.awt.Shape;
|
||||
///*JDK12IMPORTS
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.awt.geom.PathIterator;
|
||||
import java.awt.geom.Line2D;
|
||||
//JDK12IMPORTS*/
|
||||
/*JDK11IMPORTS
|
||||
import com.ibm.textlayout.Graphics2D;
|
||||
import com.ibm.textlayout.Rectangle2D;
|
||||
JDK11IMPORTS*/
|
||||
|
||||
/**
|
||||
* This class exists to work around a clipping bug in JDK 1.2.
|
||||
*/
|
||||
final class ClipWorkaround {
|
||||
|
||||
static final String COPYRIGHT =
|
||||
"(C) Copyright IBM Corp. 1998-1999 - All Rights Reserved";
|
||||
///*JDK12IMPORTS
|
||||
private static final String excuse =
|
||||
"Sorry, this method is a very limited workaround for a JDK 1.2 bug.";
|
||||
//JDK12IMPORTS*/
|
||||
|
||||
static Object saveClipState(Graphics2D g) {
|
||||
///*JDK12IMPORTS
|
||||
return null;
|
||||
//JDK12IMPORTS*/
|
||||
/*JDK11IMPORTS
|
||||
return g.getClip();
|
||||
JDK11IMPORTS*/
|
||||
}
|
||||
|
||||
static void restoreClipState(Graphics2D g, Object state) {
|
||||
///*JDK12IMPORTS
|
||||
if (state != null) {
|
||||
throw new Error("Invalid clip state for this class.");
|
||||
}
|
||||
//JDK12IMPORTS*/
|
||||
/*JDK11IMPORTS
|
||||
g.setClip((Shape)state);
|
||||
JDK11IMPORTS*/
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw the given Shape into the Graphics, translated by (dx, dy)
|
||||
* and clipped to clipRect.
|
||||
*/
|
||||
static void translateAndDrawShapeWithClip(Graphics2D g,
|
||||
int dx,
|
||||
int dy,
|
||||
Rectangle2D clipRect,
|
||||
Shape shape) {
|
||||
///*JDK12IMPORTS
|
||||
// really bogus implementation right now: basically only
|
||||
// draws carets from a TextLayout.
|
||||
// Oh yeah, it doesn't really clip correctly either...
|
||||
|
||||
PathIterator pathIter = shape.getPathIterator(null);
|
||||
float[] points = new float[6];
|
||||
|
||||
int type = pathIter.currentSegment(points);
|
||||
if (type != PathIterator.SEG_MOVETO) {
|
||||
throw new Error(excuse);
|
||||
}
|
||||
float x1 = points[0] + dx;
|
||||
float y1 = points[1] + dy;
|
||||
|
||||
if (pathIter.isDone()) {
|
||||
throw new Error(excuse);
|
||||
}
|
||||
|
||||
pathIter.next();
|
||||
type = pathIter.currentSegment(points);
|
||||
if (type != PathIterator.SEG_LINETO) {
|
||||
throw new Error(excuse);
|
||||
}
|
||||
float x2 = points[0] + dx;
|
||||
float y2 = points[1] + dy;
|
||||
|
||||
float minY = (float) clipRect.getY();
|
||||
float maxY = (float) clipRect.getMaxY();
|
||||
|
||||
// Now clip within vertical limits in clipRect
|
||||
if (y1 == y2) {
|
||||
if (y1 < minY || y1 >= maxY) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (y1 > y2) {
|
||||
float t = x1;
|
||||
x1 = x2;
|
||||
x2 = t;
|
||||
t = y1;
|
||||
y1 = y2;
|
||||
y2 = t;
|
||||
}
|
||||
|
||||
float invSlope = (x2-x1) / (y2-y1);
|
||||
if (y1 < minY) {
|
||||
x1 -= (minY-y1) * invSlope;
|
||||
y1 = minY;
|
||||
}
|
||||
if (y2 >= maxY) {
|
||||
x1 += (y2-maxY) * invSlope;
|
||||
y2 = maxY;
|
||||
}
|
||||
}
|
||||
|
||||
g.draw(new Line2D.Float(x1, y1, x2, y2));
|
||||
//JDK12IMPORTS*/
|
||||
/*JDK11IMPORTS
|
||||
g.setClip(clipRect);
|
||||
g.translate(dx, dy);
|
||||
try {
|
||||
g.draw(shape);
|
||||
}
|
||||
finally {
|
||||
g.translate(-dx, -dy);
|
||||
}
|
||||
JDK11IMPORTS*/
|
||||
}
|
||||
}
|
95
icu4j/src/com/ibm/richtext/textformat/DefaultCharacterMetric.java
Executable file
95
icu4j/src/com/ibm/richtext/textformat/DefaultCharacterMetric.java
Executable file
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* @(#)$RCSfile: DefaultCharacterMetric.java,v $ $Revision: 1.1 $ $Date: 2000/04/20 17:50:03 $
|
||||
*
|
||||
* (C) Copyright IBM Corp. 1998-1999. All Rights Reserved.
|
||||
*
|
||||
* The program is provided "as is" without any warranty express or
|
||||
* implied, including the warranty of non-infringement and the implied
|
||||
* warranties of merchantibility and fitness for a particular purpose.
|
||||
* IBM will not be liable for any damages suffered by you as a result
|
||||
* of using the Program. In no event will IBM be liable for any
|
||||
* special, indirect or consequential damages or lost profits even if
|
||||
* IBM has been advised of the possibility of their occurrence. IBM
|
||||
* will not be liable for any third party claims against you.
|
||||
*/
|
||||
// Requires Java2
|
||||
package com.ibm.richtext.textformat;
|
||||
|
||||
import java.util.Hashtable;
|
||||
|
||||
import com.ibm.textlayout.attributes.AttributeMap;
|
||||
|
||||
///*JDK12IMPORTS
|
||||
import java.awt.font.FontRenderContext;
|
||||
import java.awt.font.TextLayout;
|
||||
//JDK12IMPORTS*/
|
||||
|
||||
/*JDK11IMPORTS
|
||||
import com.ibm.textlayout.FontRenderContext;
|
||||
import com.ibm.textlayout.TextLayout;
|
||||
JDK11IMPORTS*/
|
||||
|
||||
/**
|
||||
* This class is used by the Formatter to estimate the height
|
||||
* of characters in a particular style.
|
||||
*/
|
||||
final class DefaultCharacterMetric {
|
||||
|
||||
static final String COPYRIGHT =
|
||||
"(C) Copyright IBM Corp. 1998-1999 - All Rights Reserved";
|
||||
|
||||
final class Metric {
|
||||
|
||||
private float fAscent;
|
||||
private float fDescent;
|
||||
private float fLeading;
|
||||
|
||||
private Metric(float ascent, float descent, float leading) {
|
||||
|
||||
fAscent = ascent;
|
||||
fDescent = descent;
|
||||
fLeading = leading;
|
||||
}
|
||||
|
||||
public int getAscent() {
|
||||
return (int) Math.ceil(fAscent);
|
||||
}
|
||||
|
||||
public int getDescent() {
|
||||
return (int) Math.ceil(fDescent);
|
||||
}
|
||||
|
||||
public int getLeading() {
|
||||
return (int) Math.ceil(fLeading);
|
||||
}
|
||||
}
|
||||
|
||||
private final Hashtable fCache = new Hashtable();
|
||||
private /*final*/ FontResolver fResolver;
|
||||
private /*final*/ FontRenderContext fFrc;
|
||||
|
||||
public DefaultCharacterMetric(FontResolver resolver,
|
||||
FontRenderContext frc) {
|
||||
|
||||
fResolver = resolver;
|
||||
fFrc = frc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a DefaultCharacterMetric instance for the given style. The
|
||||
* style is first resolved with FontResolver.
|
||||
*/
|
||||
public Metric getMetricForStyle(AttributeMap style) {
|
||||
|
||||
style = fResolver.applyFont(style);
|
||||
Metric metric = (Metric) fCache.get(style);
|
||||
if (metric == null) {
|
||||
TextLayout layout = new TextLayout(" ", style, fFrc);
|
||||
metric = new Metric(layout.getAscent(),
|
||||
layout.getDescent(),
|
||||
layout.getLeading());
|
||||
fCache.put(style, metric);
|
||||
}
|
||||
return metric;
|
||||
}
|
||||
}
|
85
icu4j/src/com/ibm/richtext/textformat/FontResolver.java
Executable file
85
icu4j/src/com/ibm/richtext/textformat/FontResolver.java
Executable file
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* @(#)$RCSfile: FontResolver.java,v $ $Revision: 1.1 $ $Date: 2000/04/20 17:50:03 $
|
||||
*
|
||||
* (C) Copyright IBM Corp. 1998-1999. All Rights Reserved.
|
||||
*
|
||||
* The program is provided "as is" without any warranty express or
|
||||
* implied, including the warranty of non-infringement and the implied
|
||||
* warranties of merchantibility and fitness for a particular purpose.
|
||||
* IBM will not be liable for any damages suffered by you as a result
|
||||
* of using the Program. In no event will IBM be liable for any
|
||||
* special, indirect or consequential damages or lost profits even if
|
||||
* IBM has been advised of the possibility of their occurrence. IBM
|
||||
* will not be liable for any third party claims against you.
|
||||
*/
|
||||
// Requires Java2
|
||||
package com.ibm.richtext.textformat;
|
||||
|
||||
import com.ibm.textlayout.attributes.AttributeMap;
|
||||
import com.ibm.textlayout.attributes.TextAttribute;
|
||||
|
||||
import com.ibm.textlayout.FontUtils;
|
||||
|
||||
import java.util.Hashtable;
|
||||
import java.awt.Font;
|
||||
|
||||
final class FontResolver {
|
||||
|
||||
static final String COPYRIGHT =
|
||||
"(C) Copyright IBM Corp. 1998-1999 - All Rights Reserved";
|
||||
|
||||
static {
|
||||
// Even though it violates the Prime Directive I'll conditionalize
|
||||
// this anyway, since it is just a 1.2 workaround which I greatly
|
||||
// resent.
|
||||
///*JDK12IMPORTS
|
||||
java.awt.GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts();
|
||||
//JDK12IMPORTS*/
|
||||
}
|
||||
|
||||
private Hashtable styleMap;
|
||||
private final AttributeMap fDefaultFontMap;
|
||||
|
||||
public FontResolver(AttributeMap defaults) {
|
||||
|
||||
styleMap = new Hashtable();
|
||||
Hashtable tempMap = new Hashtable();
|
||||
tempMap.put(TextAttribute.FAMILY, defaults.get(TextAttribute.FAMILY));
|
||||
tempMap.put(TextAttribute.WEIGHT, defaults.get(TextAttribute.WEIGHT));
|
||||
tempMap.put(TextAttribute.POSTURE, defaults.get(TextAttribute.POSTURE));
|
||||
tempMap.put(TextAttribute.SIZE, defaults.get(TextAttribute.SIZE));
|
||||
fDefaultFontMap = new AttributeMap(tempMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch result of resolve(style) from cache, if present.
|
||||
*/
|
||||
public AttributeMap applyFont(AttributeMap style) {
|
||||
|
||||
Object cachedMap = styleMap.get(style);
|
||||
|
||||
if (cachedMap == null) {
|
||||
AttributeMap resolvedMap = resolve(style);
|
||||
styleMap.put(style, resolvedMap);
|
||||
return resolvedMap;
|
||||
}
|
||||
else {
|
||||
return (AttributeMap) cachedMap;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an AttributeMap containing a Font computed from the
|
||||
* attributes in <tt>style</tt>.
|
||||
*/
|
||||
public AttributeMap resolve(AttributeMap style) {
|
||||
|
||||
if (style.get(TextAttribute.FONT) != null) {
|
||||
return style;
|
||||
}
|
||||
|
||||
Font font = FontUtils.getFont(fDefaultFontMap.addAttributes(style));
|
||||
|
||||
return style.addAttribute(TextAttribute.FONT, font);
|
||||
}
|
||||
}
|
199
icu4j/src/com/ibm/richtext/textformat/LayoutInfo.java
Executable file
199
icu4j/src/com/ibm/richtext/textformat/LayoutInfo.java
Executable file
|
@ -0,0 +1,199 @@
|
|||
/*
|
||||
* @(#)$RCSfile: LayoutInfo.java,v $ $Revision: 1.1 $ $Date: 2000/04/20 17:50:03 $
|
||||
*
|
||||
* (C) Copyright IBM Corp. 1998-1999. All Rights Reserved.
|
||||
*
|
||||
* The program is provided "as is" without any warranty express or
|
||||
* implied, including the warranty of non-infringement and the implied
|
||||
* warranties of merchantibility and fitness for a particular purpose.
|
||||
* IBM will not be liable for any damages suffered by you as a result
|
||||
* of using the Program. In no event will IBM be liable for any
|
||||
* special, indirect or consequential damages or lost profits even if
|
||||
* IBM has been advised of the possibility of their occurrence. IBM
|
||||
* will not be liable for any third party claims against you.
|
||||
*/
|
||||
// Requires Java2
|
||||
/** LayoutInfo
|
||||
|
||||
A line of text, possibly containing tab-segments.
|
||||
*/
|
||||
|
||||
package com.ibm.richtext.textformat;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Rectangle;
|
||||
|
||||
///*JDK12IMPORTS
|
||||
import java.awt.Graphics2D;
|
||||
//JDK12IMPORTS*/
|
||||
|
||||
/*JDK11IMPORTS
|
||||
import com.ibm.textlayout.Graphics2D;
|
||||
JDK11IMPORTS*/
|
||||
|
||||
import com.ibm.richtext.styledtext.MConstText;
|
||||
|
||||
abstract class LayoutInfo
|
||||
{
|
||||
static final String COPYRIGHT =
|
||||
"(C) Copyright IBM Corp. 1998-1999 - All Rights Reserved";
|
||||
private int fCharStart; // offset in text to start of line (was fStart)
|
||||
// neg. values indicate distance from end of text
|
||||
private int fGraphicStart; // min pixel offset in fill direction
|
||||
// negative values indicate distance from bottom of text view
|
||||
|
||||
/*
|
||||
These methods are for storing Layouts in a gap-storage,
|
||||
relative to either the start of end of text. See AsyncFormatter.
|
||||
|
||||
If you just want absolute (that is, start-relative) char and
|
||||
graphic starts, don't make them end-relative.
|
||||
*/
|
||||
|
||||
public final int getCharStart(int lengthBasis) {
|
||||
|
||||
if (fCharStart >= 0) {
|
||||
return fCharStart;
|
||||
}
|
||||
else {
|
||||
return lengthBasis + fCharStart;
|
||||
}
|
||||
}
|
||||
|
||||
public final int getGraphicStart(int graphicBasis) {
|
||||
|
||||
if (fGraphicStart >= 0) {
|
||||
return fGraphicStart;
|
||||
}
|
||||
else {
|
||||
return graphicBasis + fGraphicStart;
|
||||
}
|
||||
}
|
||||
|
||||
public final void setCharStart(int beginningRelativeStart) {
|
||||
|
||||
if (beginningRelativeStart < 0) {
|
||||
throw new IllegalArgumentException("charStart must be nonnegavitve");
|
||||
}
|
||||
fCharStart = beginningRelativeStart;
|
||||
}
|
||||
|
||||
public final void setGraphicStart(int beginningRelativeStart) {
|
||||
|
||||
if (beginningRelativeStart < 0) {
|
||||
throw new IllegalArgumentException("charStart must be nonnegavitve");
|
||||
}
|
||||
fGraphicStart = beginningRelativeStart;
|
||||
}
|
||||
|
||||
public final void makeRelativeToBeginning(int lengthBasis,
|
||||
int graphicBasis) {
|
||||
|
||||
if (lengthBasis < 0 || graphicBasis < 0) {
|
||||
throw new IllegalArgumentException("Bases must be positive.");
|
||||
}
|
||||
if (fCharStart >= 0 || fGraphicStart >= 0) {
|
||||
throw new Error("Already start-relative.");
|
||||
}
|
||||
|
||||
fCharStart += lengthBasis;
|
||||
fGraphicStart += graphicBasis;
|
||||
}
|
||||
|
||||
public final void makeRelativeToEnd(int lengthBasis,
|
||||
int graphicBasis) {
|
||||
|
||||
if (lengthBasis < 0 || graphicBasis < 0) {
|
||||
throw new IllegalArgumentException("Bases must be positive.");
|
||||
}
|
||||
if (fCharStart < 0 || fGraphicStart < 0) {
|
||||
throw new Error("Already end-relative.");
|
||||
}
|
||||
|
||||
fCharStart -= lengthBasis;
|
||||
fGraphicStart -= graphicBasis;
|
||||
}
|
||||
|
||||
|
||||
public abstract int getCharLength();
|
||||
public abstract int getAscent();
|
||||
public abstract int getDescent();
|
||||
public abstract int getLeading();
|
||||
|
||||
public abstract int getVisibleAdvance();
|
||||
public abstract int getTotalAdvance();
|
||||
public abstract int getLeadingMargin();
|
||||
|
||||
public abstract boolean isLeftToRight();
|
||||
|
||||
public int getHeight() {
|
||||
|
||||
return getAscent()+getDescent()+getLeading();
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws text with highlighting.
|
||||
*/
|
||||
public void renderWithHighlight(int lengthBasis,
|
||||
Graphics2D g,
|
||||
int lineBound,
|
||||
int x,
|
||||
int y,
|
||||
TextOffset selStart,
|
||||
TextOffset selStop,
|
||||
Color highlightColor)
|
||||
{
|
||||
}
|
||||
|
||||
/** Use layout information to render the line at x, y.*/
|
||||
|
||||
public void render(int lengthBasis,
|
||||
Graphics2D g,
|
||||
int lineBound,
|
||||
int x,
|
||||
int y)
|
||||
{
|
||||
}
|
||||
|
||||
public void renderCaret(MConstText text,
|
||||
int lengthBasis,
|
||||
Graphics2D g,
|
||||
int lineBound,
|
||||
int x,
|
||||
int y,
|
||||
int charOffset,
|
||||
Color strongCaretColor,
|
||||
Color weakCaretColor)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a point within this line, return the character offset corresponding to that point.
|
||||
*
|
||||
* @param result. This may be null, in which case a new TextOffset will be allocated.
|
||||
* This object is modified in place, and also returned as the function result.
|
||||
* @param text Text to inspect.
|
||||
* @param lineX Position on this line relative to top left corner of this line.
|
||||
* @param lineY Position on this line relative to top left corner of this line.
|
||||
*/
|
||||
public abstract TextOffset pixelToOffset(int lengthBasis,
|
||||
TextOffset result,
|
||||
int lineBound,
|
||||
int x,
|
||||
int y);
|
||||
|
||||
public abstract int strongCaretBaselinePosition(int lengthBasis,
|
||||
int lineBound,
|
||||
int charOffset);
|
||||
|
||||
public abstract Rectangle caretBounds(MConstText text,
|
||||
int lengthBasis,
|
||||
int lineBound,
|
||||
int charOffset,
|
||||
int x,
|
||||
int y);
|
||||
|
||||
public abstract int getNextOffset(int lengthBasis,
|
||||
int charOffset,
|
||||
short dir);
|
||||
}
|
351
icu4j/src/com/ibm/richtext/textformat/MFormatter.java
Executable file
351
icu4j/src/com/ibm/richtext/textformat/MFormatter.java
Executable file
|
@ -0,0 +1,351 @@
|
|||
/*
|
||||
* @(#)$RCSfile: MFormatter.java,v $ $Revision: 1.1 $ $Date: 2000/04/20 17:50:03 $
|
||||
*
|
||||
* (C) Copyright IBM Corp. 1998-1999. All Rights Reserved.
|
||||
*
|
||||
* The program is provided "as is" without any warranty express or
|
||||
* implied, including the warranty of non-infringement and the implied
|
||||
* warranties of merchantibility and fitness for a particular purpose.
|
||||
* IBM will not be liable for any damages suffered by you as a result
|
||||
* of using the Program. In no event will IBM be liable for any
|
||||
* special, indirect or consequential damages or lost profits even if
|
||||
* IBM has been advised of the possibility of their occurrence. IBM
|
||||
* will not be liable for any third party claims against you.
|
||||
*/
|
||||
|
||||
package com.ibm.richtext.textformat;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Point;
|
||||
import java.awt.Rectangle;
|
||||
|
||||
import com.ibm.richtext.styledtext.MConstText;
|
||||
import com.ibm.textlayout.attributes.AttributeMap;
|
||||
|
||||
/**
|
||||
*
|
||||
* This class formats lines of text to a given length.
|
||||
* It provides services needed for static text display,
|
||||
* and also editable text, including: displaying text,
|
||||
* reformatting text after an edit, converting between
|
||||
* screen locations and offsets into the text, calculating
|
||||
* areas of the screen for "highlighting," and computing
|
||||
* offsets into the text resulting from arrow keys.
|
||||
* <p>
|
||||
* Text clients instantiate this class with an
|
||||
* <tt>MConstText</tt> object and a format width. Text
|
||||
* can be formatted such that all lines fit within the
|
||||
* format length. Alternatively, text can be formatted
|
||||
* such that lines end only at the end of paragraphs.
|
||||
* <p>
|
||||
* The format length is specified with the <tt>setLineBound()</tt>
|
||||
* method.
|
||||
* <p>
|
||||
* Methods in the formatter which interact with the graphics
|
||||
* system generally take as a paramter a <tt>Point</tt> object
|
||||
* which represents the "origin" of the text display. The
|
||||
* origin represents the location, in the graphics system used to display the text, of
|
||||
* the top-left corner of the text.
|
||||
* <p>
|
||||
* To display the text, call <tt>draw()</tt>, passing the
|
||||
* a rectangle in which to draw as a parameter. Only lines
|
||||
* of text in the draw rectangle will be drawn.
|
||||
* <p>
|
||||
* When the formatter's text changes, it is important to first call
|
||||
* <tt>stopBackgroundFormatting()</tt> to prevent the Formatter from
|
||||
* accessing the text from a background thread. After modifications are
|
||||
* complete,
|
||||
* call the <tt>updateFormat()</tt> method before invoking any other
|
||||
* methods of the formatter. <tt>updateFormat()</tt> reformats the
|
||||
* new text, formatting no more text than is necessary.
|
||||
* <p>
|
||||
* The formatter provides services for responding to user input from the
|
||||
* mouse and keyboard. The method <tt>pointToTextOffset()</tt> converts
|
||||
* a screen location to an offset in the text. The method <tt>textOffsetToPoint</tt>
|
||||
* converts an offset in the text to an array of two <tt>Point</tt> objects, which can be
|
||||
* used to draw a verticle caret, denoting an insertion point. <tt>highlightArea</tt>
|
||||
* accepts two offsets into the text as paramters, and returns an array of <tt>Polygon</tt>
|
||||
* objects representing areas where visual highlighting should be applied.
|
||||
* <p>
|
||||
* Finally, for
|
||||
* keyboard handling, the <tt>findNewInsertionOffset()</tt> method accepts an "initial"
|
||||
* offset, a "previous" offset, as well as a direction, and returns a new offset. The direction
|
||||
* can be up, down, left, or right. The previous offset is the insertion point location, before
|
||||
* the arrow key is processed. The initial offset is the offset where an up or down arrow
|
||||
* key sequence began. Using the initial offset allows for "intelligent" handling of up and down
|
||||
* arrow keys.
|
||||
* <p>
|
||||
* Examples of using the MFormatter class
|
||||
* are given in the <tt>AsyncFormatter</tt> class
|
||||
* documentation.
|
||||
* <p>
|
||||
* @author John Raley
|
||||
*
|
||||
* @see MText
|
||||
*/
|
||||
|
||||
public abstract class MFormatter {
|
||||
static final String COPYRIGHT =
|
||||
"(C) Copyright IBM Corp. 1998-1999 - All Rights Reserved";
|
||||
|
||||
public abstract AttributeMap getDefaultValues();
|
||||
|
||||
/**
|
||||
* Display text in drawArea, with highlighting.
|
||||
* Does not reformat text
|
||||
* @param g the Graphics object in which to draw
|
||||
* @param drawArea the rectangle, in g's coordinate system, in which to draw
|
||||
* @param origin the top-left corner of the text, in g's coordinate system
|
||||
* @param selStart the offset where the current selection begins; pass <tt>null</tt> if no selection
|
||||
* @param selStop the offset where the current selection ends
|
||||
* @param highlight the color of the highlighting
|
||||
*/
|
||||
public abstract void draw(Graphics g, Rectangle drawArea, Point origin,
|
||||
TextOffset selStart, TextOffset selStop, Color highlight);
|
||||
|
||||
public abstract void draw(Graphics g, Rectangle drawArea, Point origin);
|
||||
|
||||
/**
|
||||
* Specify whether to wrap line at the edge of the destination area.
|
||||
* <tt>true</tt> means wrap lines; <tt>false</tt> means to break lines
|
||||
* only when an end-of-line character is reached.
|
||||
* @param wrap <tt>true</tt> to break lines at the edge of the destination
|
||||
* area; <tt>false</tt> otherwise.
|
||||
*/
|
||||
|
||||
public abstract void setWrap(boolean wrap);
|
||||
|
||||
/**
|
||||
* Return whether text is wrapped at the edge of the destination area.
|
||||
* @see #setWrap
|
||||
*/
|
||||
public abstract boolean wrap();
|
||||
|
||||
/**
|
||||
* Specify the number of pixels along the "line dimension".
|
||||
* Lines are formatted to fit within the line dimension. The
|
||||
* line dimension in Roman script is horizontal.
|
||||
* @param lineWidth the length, in pixels, to which lines will be formatted
|
||||
*/
|
||||
public abstract void setLineBound(int lineBound);
|
||||
|
||||
/**
|
||||
* Return the number of pixels along the line dimension.
|
||||
*/
|
||||
public abstract int lineBound();
|
||||
|
||||
/**
|
||||
* Format text down to given height.
|
||||
* @param height the height to which text will be formatted
|
||||
*/
|
||||
public abstract void formatToHeight(int height);
|
||||
|
||||
/**
|
||||
* Reformat text after a change.
|
||||
* After the formatter's text changes, call this method to reformat. Does
|
||||
* not redraw.
|
||||
* @param afStart the offset into the text where modification began; ie, the
|
||||
* first character in the text which is "different" in some way. Does not
|
||||
* have to be nonnegative.
|
||||
* @param afLength the number of new or changed characters in the text. Should never
|
||||
* be less than 0.
|
||||
* @param viewRect the Rectangle in which the text will be displayed. This is needed for
|
||||
* returning the "damaged" area - the area of the screen in which the text must be redrawn.
|
||||
* @param origin the top-left corner of the text, in the display's coordinate system
|
||||
* @returns a <tt>Rectangle</tt> which specifies the area in which text must be
|
||||
* redrawn to reflect the change to the text.
|
||||
*/
|
||||
public abstract Rectangle updateFormat(int afStart,
|
||||
int afLength,
|
||||
Rectangle viewRect,
|
||||
Point origin);
|
||||
|
||||
|
||||
public abstract int minY();
|
||||
|
||||
/**
|
||||
* Return the maximum vertical coordinate of the document area.
|
||||
*/
|
||||
public abstract int maxY();
|
||||
|
||||
public abstract int minX();
|
||||
|
||||
/**
|
||||
* Return the maximum horizontal coordinate of the document area.
|
||||
*/
|
||||
public abstract int maxX();
|
||||
|
||||
/**
|
||||
* Return the actual pixel length of the text which has been formatted.
|
||||
*/
|
||||
public abstract int formattedHeight();
|
||||
|
||||
public static final short eUp = -10, eDown = 10, eLeft = -1, eRight = 1;
|
||||
|
||||
/**
|
||||
* Given a screen location p, return the offset of the character in the text nearest to p.
|
||||
*
|
||||
* The offset may or may not include a newline at the end of a line, determined by anchor and infiniteMode.
|
||||
* The newline is not included if infiniteMode is true and the anchor is the position before the newline.
|
||||
*
|
||||
* @param result TextOffset to modify and return. If null, one will be allocated, modified, and returned.
|
||||
* @param px the x component of the point.
|
||||
* @param py the y component of the point.
|
||||
* @param origin the top-left corner of the text, in the display's coordinate system
|
||||
* @param anchor the previous offset. May be null. Used to determine whether newlines are included.
|
||||
* @param infiniteMode if true, treat newlines at end of line as having infinite width.
|
||||
*/
|
||||
public abstract TextOffset pointToTextOffset(TextOffset result, int px, int py, Point origin, TextOffset anchor, boolean infiniteMode);
|
||||
|
||||
/**
|
||||
* Given an offset, return the Rectangle bounding the caret at the offset.
|
||||
* @param offset an offset into the text
|
||||
* @param origin the top-left corner of the text, in the display's coordinate system
|
||||
* @return a Rectangle bounding the caret.
|
||||
*/
|
||||
public abstract Rectangle getCaretRect(TextOffset offset, Point origin);
|
||||
|
||||
/**
|
||||
* Draw the caret(s) associated with the given offset into the given Graphics.
|
||||
* @param g the Graphics to draw into
|
||||
* @param offset the offset in the text for which the caret is drawn
|
||||
* @param origin the top-left corner of the text, in the display's coordinate system
|
||||
* @param strongCaretColor the color of the strong caret
|
||||
* @param weakCaretColor the color of the weak caret (if any)
|
||||
*/
|
||||
public abstract void drawCaret(Graphics g,
|
||||
TextOffset offset,
|
||||
Point origin,
|
||||
Color strongCaretColor,
|
||||
Color weakCaretColor);
|
||||
|
||||
/**
|
||||
* @see #getBoundingRect
|
||||
*/
|
||||
public static final boolean LOOSE = false;
|
||||
/**
|
||||
* @see #getBoundingRect
|
||||
*/
|
||||
public static final boolean TIGHT = true;
|
||||
|
||||
/**
|
||||
* Given two offsets in the text, return a rectangle which encloses the lines containing the offsets.
|
||||
* Offsets do not need to be ordered or nonnegative.
|
||||
* @param offset1,offset2 offsets into the text
|
||||
* @param origin the top-left corner of the text, in the display's coordinate system
|
||||
* @param tight if equal to TIGHT, the bounds is as small as possible. If LOOSE, the width
|
||||
* of the bounds is allowed to be wider than necesary. Loose bounds are easier to compute.
|
||||
* @returns a <tt>Rectangle</tt>, relative to <tt>origin</tt>, which encloses the lines containing the offsets
|
||||
*/
|
||||
public abstract Rectangle getBoundingRect(TextOffset offset1,
|
||||
TextOffset offset2,
|
||||
Point origin,
|
||||
boolean tight);
|
||||
|
||||
public abstract void getBoundingRect(Rectangle boundingRect,
|
||||
TextOffset offset1,
|
||||
TextOffset offset2,
|
||||
Point origin,
|
||||
boolean tight);
|
||||
|
||||
/**
|
||||
* Compute the offset resulting from moving from a previous offset in direction dir.
|
||||
* For arrow keys.
|
||||
* @param previousOffset the insertion offset prior to the arrow key press
|
||||
* @param direction the direction of the arrow key (eUp, eDown, eLeft, or eRight)
|
||||
* @returns new offset based on direction and previous offset.
|
||||
*/
|
||||
public abstract TextOffset findInsertionOffset(TextOffset result,
|
||||
TextOffset previousOffset,
|
||||
short direction);
|
||||
|
||||
/**
|
||||
* Compute the offset resulting from moving from a previous offset, starting at an original offset, in direction dir.
|
||||
* For arrow keys. Use this for "smart" up/down keys.
|
||||
* @param result TextOffset to modify and return. If null, a new TextOffset is created, modified, and returned.
|
||||
* @param initialOffset The offset at which an up-down arrow key sequence began.
|
||||
* @param previousOffset The insertion offset prior to the arrow key press.
|
||||
* @param direction The direction of the arrow key (eUp, eDown, eLeft, or eRight)
|
||||
* @returns new offset based on direction and previous offset(s).
|
||||
*/
|
||||
public abstract TextOffset findNewInsertionOffset(TextOffset result,
|
||||
TextOffset initialOffset,
|
||||
TextOffset previousOffset,
|
||||
short direction);
|
||||
|
||||
/**
|
||||
* Return the index of the line containing the given character index.
|
||||
* This method has complicated semantics, arising from not knowing
|
||||
* which side of the index to check. The index will be given an
|
||||
* implicit AFTER bias, unless the index is the last index in the text,
|
||||
* the text length is non-zero, and there is not a paragraph separator
|
||||
* at the end of the text.
|
||||
*/
|
||||
public abstract int lineContaining(int index);
|
||||
|
||||
/**
|
||||
* Return the index of the line containing the given offset.
|
||||
*/
|
||||
public abstract int lineContaining(TextOffset offset);
|
||||
|
||||
/**
|
||||
* Return the number of lines.
|
||||
*/
|
||||
public abstract int getLineCount();
|
||||
|
||||
/**
|
||||
* Return the index of the first character on the given line.
|
||||
*/
|
||||
public abstract int lineRangeLow(int lineNumber);
|
||||
|
||||
/**
|
||||
* Return the index of the first character following the given line.
|
||||
*/
|
||||
public abstract int lineRangeLimit(int lineNumber);
|
||||
|
||||
/**
|
||||
* Tells the formatter to stop accessing the text until updateFormat is called.
|
||||
*/
|
||||
public abstract void stopBackgroundFormatting();
|
||||
|
||||
/**
|
||||
* Return the line number at the given graphic height. If height is greater than
|
||||
* the text height, maxLineNumber + 1 is returned.
|
||||
*/
|
||||
public abstract int lineAtHeight(int height);
|
||||
|
||||
/**
|
||||
* Return the graphic height where the given line begins. If the lineNumber is
|
||||
* maxLineNumber the entire text height is returned.
|
||||
*/
|
||||
public abstract int lineGraphicStart(int lineNumber);
|
||||
|
||||
/**
|
||||
* Return true if the given line is left-to-right.
|
||||
* @param lineNumber a valid line
|
||||
* @return true if lineNumber is left-to-right
|
||||
*/
|
||||
public abstract boolean lineIsLeftToRight(int lineNumber);
|
||||
|
||||
/**
|
||||
* Return a new <tt>MFormatter</tt>.
|
||||
* @param text the text to format
|
||||
* @param defaultValues values to use when certain attributes are not specified.
|
||||
* <tt>defaultValues</tt> must contain values for the following attributes:
|
||||
* <tt>FAMILY</tt>, <tt>WEIGHT</tt>, <tt>POSTURE</tt>, <tt>SIZE</tt>, <tt>SUPERSCRIPT</tt>,
|
||||
* <tt>FOREGROUND</tt>, <tt>UNDERLINE</tt>, <tt>STRIKETHROUGH</tt>,
|
||||
* <tt>EXTRA_LINE_SPACING</tt>, <tt>FIRST_LINE_INDENT</tt>,<tt>MIN_LINE_SPACING</tt>,
|
||||
* <tt>LINE_FLUSH</tt>, <tt>LEADING_MARGIN</tt>, <tt>TRAILING_MARGIN</tt>, <tt>TAB_RULER</tt>
|
||||
* @param lineBound length to which lines are formatted
|
||||
* @param wrap <tt>true</tt> if text should be "line wrapped" (formatted to fit destination area)
|
||||
*/
|
||||
public static MFormatter createFormatter(MConstText text,
|
||||
AttributeMap defaultValues,
|
||||
int lineBound,
|
||||
boolean wrap,
|
||||
Graphics g) {
|
||||
|
||||
return new AsyncFormatter(text, defaultValues, lineBound, wrap, g);
|
||||
}
|
||||
}
|
402
icu4j/src/com/ibm/richtext/textformat/MTextIterator.java
Executable file
402
icu4j/src/com/ibm/richtext/textformat/MTextIterator.java
Executable file
|
@ -0,0 +1,402 @@
|
|||
/*
|
||||
* @(#)$RCSfile: MTextIterator.java,v $ $Revision: 1.1 $ $Date: 2000/04/20 17:50:03 $
|
||||
*
|
||||
* (C) Copyright IBM Corp. 1998-1999. All Rights Reserved.
|
||||
*
|
||||
* The program is provided "as is" without any warranty express or
|
||||
* implied, including the warranty of non-infringement and the implied
|
||||
* warranties of merchantibility and fitness for a particular purpose.
|
||||
* IBM will not be liable for any damages suffered by you as a result
|
||||
* of using the Program. In no event will IBM be liable for any
|
||||
* special, indirect or consequential damages or lost profits even if
|
||||
* IBM has been advised of the possibility of their occurrence. IBM
|
||||
* will not be liable for any third party claims against you.
|
||||
*/
|
||||
// Requires Java2
|
||||
package com.ibm.richtext.textformat;
|
||||
|
||||
import com.ibm.richtext.styledtext.MConstText;
|
||||
import java.text.CharacterIterator;
|
||||
|
||||
import com.ibm.textlayout.attributes.AttributeMap;
|
||||
|
||||
///*JDK12IMPORTS
|
||||
import java.text.AttributedCharacterIterator;
|
||||
import java.text.AttributedCharacterIterator.Attribute;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
//JDK12IMPORTS*/
|
||||
|
||||
/*JDK11IMPORTS
|
||||
import com.ibm.textlayout.attributes.AttributedCharacterIterator;
|
||||
import com.ibm.textlayout.attributes.AttributedCharacterIterator.Attribute;
|
||||
import com.ibm.textlayout.attributes.Map;
|
||||
JDK11IMPORTS*/
|
||||
|
||||
public final class MTextIterator implements AttributedCharacterIterator,
|
||||
Cloneable {
|
||||
|
||||
static final String COPYRIGHT =
|
||||
"(C) Copyright IBM Corp. 1998-1999 - All Rights Reserved";
|
||||
// memory leak, since this cache is never flushed
|
||||
|
||||
private static class Matcher {
|
||||
|
||||
boolean matches(Map lhs, Map rhs, Object query) {
|
||||
|
||||
Object lhsVal = lhs.get(query);
|
||||
Object rhsVal = rhs.get(query);
|
||||
|
||||
if (lhsVal == null) {
|
||||
return rhsVal == null;
|
||||
}
|
||||
else {
|
||||
return lhsVal.equals(rhsVal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final Matcher ATTR_MATCHER = new Matcher();
|
||||
|
||||
// Not quite optimal. Could have a matcher that would decompose
|
||||
// a set once for repeated queries. Of course that would require
|
||||
// allocation...
|
||||
///*JDK12IMPORTS
|
||||
private static final Matcher SET_MATCHER = new Matcher() {
|
||||
|
||||
boolean matches(Map lhs, Map rhs, Object query) {
|
||||
|
||||
// Not using Iterator to simplify 1.1 port.
|
||||
Object[] elements = ((Set)query).toArray();
|
||||
for (int i=0; i < elements.length; i++) {
|
||||
if (!super.matches(lhs, rhs, elements[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
//JDK12IMPORTS*/
|
||||
|
||||
private final class StyleCache {
|
||||
|
||||
private int fRunStart = 0;
|
||||
private int fRunLimit = -1;
|
||||
private int fRangeStart;
|
||||
private int fRangeLimit;
|
||||
private AttributeMap fStyle;
|
||||
|
||||
StyleCache(MConstText text, int start, int limit) {
|
||||
fText = text;
|
||||
fRangeStart = start;
|
||||
fRangeLimit = limit;
|
||||
update(start);
|
||||
}
|
||||
|
||||
private void update(int pos) {
|
||||
if (pos < fRunStart || pos >= fRunLimit) {
|
||||
AttributeMap style = AttributeMap.EMPTY_ATTRIBUTE_MAP;
|
||||
if (pos < fRangeStart) {
|
||||
fRunLimit = fRangeStart;
|
||||
fRunStart = Integer.MIN_VALUE;
|
||||
}
|
||||
else if (pos > fRangeLimit) {
|
||||
fRunStart = fRangeLimit;
|
||||
fRunLimit = Integer.MAX_VALUE;
|
||||
}
|
||||
else {
|
||||
fRunStart = Math.max(fRangeStart, fText.characterStyleStart(pos));
|
||||
fRunStart = Math.max(fRunStart, fText.paragraphStart(pos));
|
||||
|
||||
fRunLimit = Math.min(fRangeLimit, fText.characterStyleLimit(pos));
|
||||
fRunLimit = Math.min(fRunLimit, fText.paragraphLimit(pos));
|
||||
if (fRunStart < fRunLimit) {
|
||||
style = fText.paragraphStyleAt(pos);
|
||||
style = style.addAttributes(fText.characterStyleAt(pos));
|
||||
}
|
||||
}
|
||||
fStyle = fFontResolver.applyFont(style);
|
||||
}
|
||||
}
|
||||
|
||||
int getRunStart(int pos) {
|
||||
update(pos);
|
||||
return fRunStart;
|
||||
}
|
||||
|
||||
int getRunLimit(int pos) {
|
||||
update(pos);
|
||||
return fRunLimit;
|
||||
}
|
||||
|
||||
Map getStyle(int pos) {
|
||||
update(pos);
|
||||
return fStyle;
|
||||
}
|
||||
}
|
||||
|
||||
private MConstText fText;
|
||||
private CharacterIterator fCharIter;
|
||||
private FontResolver fFontResolver;
|
||||
|
||||
private StyleCache fStyleCache;
|
||||
|
||||
/**
|
||||
* Create an MTextIterator over the range [start, limit).
|
||||
*/
|
||||
public MTextIterator(MConstText text,
|
||||
FontResolver resolver,
|
||||
int start,
|
||||
int limit) {
|
||||
|
||||
fText = text;
|
||||
fFontResolver = resolver;
|
||||
fCharIter = text.createCharacterIterator(start, limit);
|
||||
|
||||
fStyleCache = new StyleCache(text, start, limit);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the position to getBeginIndex() and returns the character at that
|
||||
* position.
|
||||
* @return the first character in the text, or DONE if the text is empty
|
||||
* @see getBeginIndex
|
||||
*/
|
||||
public char first() {
|
||||
return fCharIter.first();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the position to getEndIndex()-1 (getEndIndex() if the text is empty)
|
||||
* and returns the character at that position.
|
||||
* @return the last character in the text, or DONE if the text is empty
|
||||
* @see getEndIndex
|
||||
*/
|
||||
public char last() {
|
||||
return fCharIter.last();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the character at the current position (as returned by getIndex()).
|
||||
* @return the character at the current position or DONE if the current
|
||||
* position is off the end of the text.
|
||||
* @see getIndex
|
||||
*/
|
||||
public char current() {
|
||||
return fCharIter.current();
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments the iterator's index by one and returns the character
|
||||
* at the new index. If the resulting index is greater or equal
|
||||
* to getEndIndex(), the current index is reset to getEndIndex() and
|
||||
* a value of DONE is returned.
|
||||
* @return the character at the new position or DONE if the new
|
||||
* position is off the end of the text range.
|
||||
*/
|
||||
public char next() {
|
||||
return fCharIter.next();
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrements the iterator's index by one and returns the character
|
||||
* at the new index. If the current index is getBeginIndex(), the index
|
||||
* remains at getBeginIndex() and a value of DONE is returned.
|
||||
* @return the character at the new position or DONE if the current
|
||||
* position is equal to getBeginIndex().
|
||||
*/
|
||||
public char previous() {
|
||||
return fCharIter.previous();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the position to the specified position in the text and returns that
|
||||
* character.
|
||||
* @param position the position within the text. Valid values range from
|
||||
* getBeginIndex() to getEndIndex(). An IllegalArgumentException is thrown
|
||||
* if an invalid value is supplied.
|
||||
* @return the character at the specified position or DONE if the specified position is equal to getEndIndex()
|
||||
*/
|
||||
public char setIndex(int position) {
|
||||
return fCharIter.setIndex(position);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the start index of the text.
|
||||
* @return the index at which the text begins.
|
||||
*/
|
||||
public int getBeginIndex() {
|
||||
return fCharIter.getBeginIndex();;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the end index of the text. This index is the index of the first
|
||||
* character following the end of the text.
|
||||
* @return the index after the last character in the text
|
||||
*/
|
||||
public int getEndIndex() {
|
||||
return fCharIter.getEndIndex();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current index.
|
||||
* @return the current index.
|
||||
*/
|
||||
public int getIndex() {
|
||||
return fCharIter.getIndex();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of the first character of the run
|
||||
* with respect to all attributes containing the current character.
|
||||
*/
|
||||
public int getRunStart() {
|
||||
return fStyleCache.getRunStart(fCharIter.getIndex());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of the first character of the run
|
||||
* with respect to the given attribute containing the current character.
|
||||
*/
|
||||
public int getRunStart(Object attribute) {
|
||||
|
||||
return getRunStart(attribute, ATTR_MATCHER);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of the first character of the run
|
||||
* with respect to the given attribute containing the current character.
|
||||
*/
|
||||
///*JDK12IMPORTS
|
||||
public int getRunStart(Attribute attribute) {
|
||||
|
||||
return getRunStart(attribute, ATTR_MATCHER);
|
||||
}
|
||||
//JDK12IMPORTS*/
|
||||
|
||||
/**
|
||||
* Returns the index of the first character of the run
|
||||
* with respect to the given attributes containing the current character.
|
||||
*/
|
||||
///*JDK12IMPORTS
|
||||
public int getRunStart(Set attributes) {
|
||||
|
||||
return getRunStart(attributes, SET_MATCHER);
|
||||
}
|
||||
//JDK12IMPORTS*/
|
||||
|
||||
private int getRunStart(Object query, Matcher matcher) {
|
||||
|
||||
int runStart = getRunStart();
|
||||
int rangeStart = getBeginIndex();
|
||||
Map initialStyle = getAttributes();
|
||||
|
||||
while (runStart > rangeStart) {
|
||||
AttributeMap style = fText.characterStyleAt(runStart-1);
|
||||
if (!matcher.matches(initialStyle, style, query)) {
|
||||
return runStart;
|
||||
}
|
||||
runStart = fText.characterStyleStart(runStart-1);
|
||||
}
|
||||
return rangeStart;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of the first character following the run
|
||||
* with respect to all attributes containing the current character.
|
||||
*/
|
||||
public int getRunLimit() {
|
||||
return fStyleCache.getRunLimit(fCharIter.getIndex());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of the first character following the run
|
||||
* with respect to the given attribute containing the current character.
|
||||
*/
|
||||
public int getRunLimit(Object attribute) {
|
||||
|
||||
return getRunLimit(attribute, ATTR_MATCHER);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of the first character following the run
|
||||
* with respect to the given attribute containing the current character.
|
||||
*/
|
||||
///*JDK12IMPORTS
|
||||
public int getRunLimit(Attribute attribute) {
|
||||
|
||||
return getRunLimit(attribute, ATTR_MATCHER);
|
||||
}
|
||||
//JDK12IMPORTS*/
|
||||
|
||||
/**
|
||||
* Returns the index of the first character following the run
|
||||
* with respect to the given attributes containing the current character.
|
||||
*/
|
||||
///*JDK12IMPORTS
|
||||
public int getRunLimit(Set attributes) {
|
||||
|
||||
return getRunLimit(attributes, SET_MATCHER);
|
||||
}
|
||||
//JDK12IMPORTS*/
|
||||
|
||||
private int getRunLimit(Object query, Matcher matcher) {
|
||||
|
||||
int runLimit = getRunLimit();
|
||||
int rangeLimit = getEndIndex();
|
||||
Map initialStyle = getAttributes();
|
||||
|
||||
while (runLimit < rangeLimit) {
|
||||
AttributeMap style = fText.characterStyleAt(runLimit);
|
||||
if (!matcher.matches(initialStyle, style, query)) {
|
||||
return runLimit;
|
||||
}
|
||||
runLimit = fText.characterStyleLimit(runLimit);
|
||||
}
|
||||
return rangeLimit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a map with the attributes defined on the current
|
||||
* character.
|
||||
*/
|
||||
public Map getAttributes() {
|
||||
return fStyleCache.getStyle(fCharIter.getIndex());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the named attribute for the current character.
|
||||
* Returns null if the attribute is not defined.
|
||||
* @param attribute the key of the attribute whose value is requested.
|
||||
*/
|
||||
public Object getAttribute(Object attribute) {
|
||||
return getAttributes().get(attribute);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the named attribute for the current character.
|
||||
* Returns null if the attribute is not defined.
|
||||
* @param attribute the key of the attribute whose value is requested.
|
||||
*/
|
||||
public Object getAttribute(Attribute attribute) {
|
||||
return getAttributes().get(attribute);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the keys of all attributes defined on the
|
||||
* iterator's text range. The set is empty if no
|
||||
* attributes are defined.
|
||||
*/
|
||||
///*JDK12IMPORTS
|
||||
public Set getAllAttributeKeys() {
|
||||
throw new Error("Implement this method!");
|
||||
}
|
||||
//JDK12IMPORTS*/
|
||||
|
||||
public Object clone() {
|
||||
return new MTextIterator(fText,
|
||||
fFontResolver,
|
||||
getBeginIndex(),
|
||||
getEndIndex());
|
||||
}
|
||||
}
|
84
icu4j/src/com/ibm/richtext/textformat/ParagraphRenderer.java
Executable file
84
icu4j/src/com/ibm/richtext/textformat/ParagraphRenderer.java
Executable file
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* @(#)$RCSfile: ParagraphRenderer.java,v $ $Revision: 1.1 $ $Date: 2000/04/20 17:50:03 $
|
||||
*
|
||||
* (C) Copyright IBM Corp. 1998-1999. All Rights Reserved.
|
||||
*
|
||||
* The program is provided "as is" without any warranty express or
|
||||
* implied, including the warranty of non-infringement and the implied
|
||||
* warranties of merchantibility and fitness for a particular purpose.
|
||||
* IBM will not be liable for any damages suffered by you as a result
|
||||
* of using the Program. In no event will IBM be liable for any
|
||||
* special, indirect or consequential damages or lost profits even if
|
||||
* IBM has been advised of the possibility of their occurrence. IBM
|
||||
* will not be liable for any third party claims against you.
|
||||
*/
|
||||
// Requires Java2
|
||||
package com.ibm.richtext.textformat;
|
||||
|
||||
import com.ibm.textlayout.attributes.AttributeMap;
|
||||
import com.ibm.textlayout.attributes.TextAttribute;
|
||||
|
||||
import com.ibm.richtext.styledtext.MConstText;
|
||||
|
||||
import java.awt.Color;
|
||||
|
||||
///*JDK12IMPORTS
|
||||
import java.awt.font.FontRenderContext;
|
||||
import java.awt.font.LineBreakMeasurer;
|
||||
import java.awt.Graphics2D;
|
||||
//JDK12IMPORTS*/
|
||||
|
||||
/*JDK11IMPORTS
|
||||
import com.ibm.textlayout.FontRenderContext;
|
||||
import com.ibm.textlayout.LineBreakMeasurer;
|
||||
import com.ibm.textlayout.Graphics2D;
|
||||
JDK11IMPORTS*/
|
||||
|
||||
/**
|
||||
* ParagraphRenderer is a factory for LayoutInfo objects.
|
||||
*/
|
||||
abstract class ParagraphRenderer {
|
||||
|
||||
static final String COPYRIGHT =
|
||||
"(C) Copyright IBM Corp. 1998-1999 - All Rights Reserved";
|
||||
// If renderers can ever travel with their styles, then this attribute will denote a
|
||||
// renderer. For now, renderers are not added as styles so this isn't needed.
|
||||
//static final TextAttribute PARAGRAPH_RENDERER = new TextAttribute("Paragraph_Renderer") {};
|
||||
|
||||
/**
|
||||
* Reset the renderer to use information from this style. Since renderers may be shared, you should
|
||||
* make sure the renderer is initialized for the style you wish to render before you use it.
|
||||
*/
|
||||
public void initRenderer(AttributeMap pStyle) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a LayoutInfo for the paragraph represented by
|
||||
* measurer.
|
||||
* @param text the text containing the paragraph
|
||||
* @param layoutToReuse clients can pass in a LayoutInfo
|
||||
* which the ParagraphRenderer may choose to reuse
|
||||
* and return. If null, a new LayoutInfo will be
|
||||
* created and returned.
|
||||
* @param measurer the LineBreakMeasurer for this paragraph.
|
||||
* Current position should be the first character on the line.
|
||||
* If null, a 0-length line is generated. If measurer is null
|
||||
* then paragraphStart and paragraphLimit should be equal.
|
||||
* @param frc the FontRenderContext used for measurerment
|
||||
* @param paragraphStart the index in the text where the
|
||||
* current paragraph begins
|
||||
* @param paragraphLimit the index of the first character
|
||||
* after the current paragraph
|
||||
* @param totalFormatWidth the width in which the line should fit
|
||||
* @param lineBound where right-aligned lines are aligned
|
||||
*/
|
||||
public abstract LayoutInfo layout(MConstText text,
|
||||
LayoutInfo layoutToReuse,
|
||||
LineBreakMeasurer measurer,
|
||||
FontRenderContext frc,
|
||||
int paragraphStart,
|
||||
int paragraphLimit,
|
||||
int totalFormatWidth,
|
||||
int lineBound);
|
||||
|
||||
}
|
117
icu4j/src/com/ibm/richtext/textformat/TestMTextIterator.java
Executable file
117
icu4j/src/com/ibm/richtext/textformat/TestMTextIterator.java
Executable file
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
* @(#)$RCSfile: TestMTextIterator.java,v $ $Revision: 1.1 $ $Date: 2000/04/20 17:50:03 $
|
||||
*
|
||||
* (C) Copyright IBM Corp. 1998-1999. All Rights Reserved.
|
||||
*
|
||||
* The program is provided "as is" without any warranty express or
|
||||
* implied, including the warranty of non-infringement and the implied
|
||||
* warranties of merchantibility and fitness for a particular purpose.
|
||||
* IBM will not be liable for any damages suffered by you as a result
|
||||
* of using the Program. In no event will IBM be liable for any
|
||||
* special, indirect or consequential damages or lost profits even if
|
||||
* IBM has been advised of the possibility of their occurrence. IBM
|
||||
* will not be liable for any third party claims against you.
|
||||
*/
|
||||
// Requires Java2
|
||||
package com.ibm.richtext.textformat;
|
||||
|
||||
import com.ibm.richtext.styledtext.StyledText;
|
||||
import com.ibm.richtext.styledtext.MConstText;
|
||||
import com.ibm.richtext.styledtext.MText;
|
||||
|
||||
import com.ibm.textlayout.attributes.TextAttribute;
|
||||
import com.ibm.textlayout.attributes.AttributeMap;
|
||||
|
||||
import com.ibm.richtext.textpanel.TextPanel;
|
||||
|
||||
public class TestMTextIterator {
|
||||
|
||||
static final String COPYRIGHT =
|
||||
"(C) Copyright IBM Corp. 1998-1999 - All Rights Reserved";
|
||||
private static final FontResolver FONT_MAPPER;
|
||||
static {
|
||||
AttributeMap attrs = TextPanel.getDefaultSettings().getDefaultValues();
|
||||
FONT_MAPPER = new FontResolver(attrs);
|
||||
}
|
||||
|
||||
public static void compareIterToText(MTextIterator iter,
|
||||
MConstText text) {
|
||||
|
||||
//System.out.println("Text: " + text);
|
||||
final int beginIndex = iter.getBeginIndex();
|
||||
final int endIndex = iter.getEndIndex();
|
||||
|
||||
char ch = iter.setIndex(beginIndex);
|
||||
|
||||
for (int i=beginIndex; i < endIndex; i++) {
|
||||
//System.out.print(ch+ " ");
|
||||
if (ch != text.at(i)) {
|
||||
throw new Error("Characters are not the same.");
|
||||
}
|
||||
ch = iter.next();
|
||||
}
|
||||
|
||||
if (ch != iter.DONE) {
|
||||
throw new Error("Iterator is not done.");
|
||||
}
|
||||
|
||||
for (int i=endIndex-1; i >= beginIndex; i--) {
|
||||
ch = iter.previous();
|
||||
//System.out.print(ch+ " ");
|
||||
if (ch != text.at(i)) {
|
||||
throw new Error("Backward iteration failed.");
|
||||
}
|
||||
}
|
||||
|
||||
iter.setIndex(beginIndex);
|
||||
|
||||
int runLimit;
|
||||
for (int runStart = beginIndex; runStart < endIndex; runStart = runLimit) {
|
||||
|
||||
runLimit = Math.min(endIndex, text.characterStyleLimit(runStart));
|
||||
|
||||
if (iter.getRunStart() != runStart) {
|
||||
System.out.println(iter.getRunStart() + "; " + runStart);
|
||||
throw new Error("getRunStart is wrong.");
|
||||
}
|
||||
if (iter.getRunLimit() != runLimit) {
|
||||
System.out.println(iter.getRunLimit() + "; " + runLimit);
|
||||
throw new Error("getRunLimit is wrong.");
|
||||
}
|
||||
|
||||
AttributeMap style = text.characterStyleAt(runStart);
|
||||
|
||||
while (iter.getIndex() < runLimit) {
|
||||
AttributeMap resolved = FONT_MAPPER.applyFont(style);
|
||||
if (!iter.getAttributes().equals(resolved)) {
|
||||
throw new Error("Style is wrong.");
|
||||
}
|
||||
iter.next();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void test() {
|
||||
|
||||
AttributeMap bold = new AttributeMap(TextAttribute.WEIGHT,
|
||||
TextAttribute.WEIGHT_BOLD);
|
||||
MText text = new StyledText("Hello there!", AttributeMap.EMPTY_ATTRIBUTE_MAP);
|
||||
text.replace(2, 2, 'V', bold);
|
||||
|
||||
MTextIterator iter = new MTextIterator(text, FONT_MAPPER, 0, text.length());
|
||||
compareIterToText(iter, text);
|
||||
|
||||
text.replace(6, 8, new StyledText("ALL_BOLD", bold), 0, 8);
|
||||
iter = new MTextIterator(text, FONT_MAPPER, 1, text.length()-3);
|
||||
compareIterToText(iter, text);
|
||||
|
||||
iter = new MTextIterator(text, FONT_MAPPER, 0, text.length());
|
||||
compareIterToText(iter, text);
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
new TestMTextIterator().test();
|
||||
System.out.println("PASSED");
|
||||
}
|
||||
}
|
198
icu4j/src/com/ibm/richtext/textformat/TextOffset.java
Executable file
198
icu4j/src/com/ibm/richtext/textformat/TextOffset.java
Executable file
|
@ -0,0 +1,198 @@
|
|||
/*
|
||||
* @(#)$RCSfile: TextOffset.java,v $ $Revision: 1.1 $ $Date: 2000/04/20 17:50:03 $
|
||||
*
|
||||
* (C) Copyright IBM Corp. 1998-1999. All Rights Reserved.
|
||||
*
|
||||
* The program is provided "as is" without any warranty express or
|
||||
* implied, including the warranty of non-infringement and the implied
|
||||
* warranties of merchantibility and fitness for a particular purpose.
|
||||
* IBM will not be liable for any damages suffered by you as a result
|
||||
* of using the Program. In no event will IBM be liable for any
|
||||
* special, indirect or consequential damages or lost profits even if
|
||||
* IBM has been advised of the possibility of their occurrence. IBM
|
||||
* will not be liable for any third party claims against you.
|
||||
*/
|
||||
// Revision: 03 1.16 richtext/TextOffset.java, richtext, richtext
|
||||
|
||||
/*
|
||||
9/5/96 {jbr} added set and equals methods
|
||||
*/
|
||||
|
||||
package com.ibm.richtext.textformat;
|
||||
|
||||
/**
|
||||
* A TextOffset indicates both an integer offset into text and a placement
|
||||
* on one of the characters adjacent to the offset. An offset is a
|
||||
* position between two characters; offset n
|
||||
* is between character n-1 and character n. The placement specifies whether
|
||||
* it is associated with the character
|
||||
* after the offset
|
||||
* (character n) or the character before the offset (character n-1).
|
||||
* <p>
|
||||
* Knowing which character the TextOffset is associated with is necessary
|
||||
* when displaying carets. In bidirectional text, a single offset may
|
||||
* have two distinct carets. Also, in multiline text, an offset at a line
|
||||
* break has a possible caret on each line.
|
||||
* <p>
|
||||
* Most clients will not be interested in the placement, and will just use
|
||||
* the offset.
|
||||
*/
|
||||
public final class TextOffset
|
||||
{
|
||||
static final String COPYRIGHT =
|
||||
"(C) Copyright IBM Corp. 1998-1999 - All Rights Reserved";
|
||||
/**
|
||||
* Indicates that the TextOffset is associated with character
|
||||
* <code>fOffset - 1</code> - ie the character before its offset.
|
||||
*/
|
||||
public final static boolean BEFORE_OFFSET = true;
|
||||
|
||||
/**
|
||||
* Indicates that the TextOffset is associated with character
|
||||
* <code>fOffset</code> - ie the character after its offset.
|
||||
*/
|
||||
public final static boolean AFTER_OFFSET = false;
|
||||
|
||||
/**
|
||||
* The offset into the text.
|
||||
*/
|
||||
public int fOffset = 0;
|
||||
|
||||
/**
|
||||
* The placement - before or after.
|
||||
*/
|
||||
public boolean fPlacement = AFTER_OFFSET;
|
||||
|
||||
/**
|
||||
* Constructs a new TextOffset
|
||||
* @param offset the offset into the text to represent. Placement is implicitly AFTER_OFFSET.
|
||||
*/
|
||||
public TextOffset(int offset)
|
||||
{
|
||||
if (offset < 0)
|
||||
throw new IllegalArgumentException("Offset is negative in TextOffset constructor.");
|
||||
|
||||
fOffset = offset;
|
||||
|
||||
fPlacement = AFTER_OFFSET;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new TextOffset at 0, with placement AFTER_OFFSET.
|
||||
*/
|
||||
public TextOffset() {
|
||||
this(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new TextOffset with the given offset and placement.
|
||||
* @param offset the offset into the text
|
||||
* @param placement indicates the position of the caret; one of BEFORE_OFFSET or AFTER_OFFSET
|
||||
*/
|
||||
public TextOffset(int offset, boolean placement)
|
||||
{
|
||||
if (offset < 0)
|
||||
throw new IllegalArgumentException("TextOffset constructor offset < 0: " + offset);
|
||||
|
||||
fOffset = offset;
|
||||
fPlacement = placement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new TextOffset from an existing one.
|
||||
* @param ths the TextOffset to copy
|
||||
*/
|
||||
public TextOffset(TextOffset rhs) {
|
||||
|
||||
this(rhs.fOffset, rhs.fPlacement);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of the TextOffset
|
||||
* @param offset the offset into the text
|
||||
* @param placement indicates the position of the caret; one of BEFORE_OFFSET or AFTER_OFFSET
|
||||
*/
|
||||
public void setOffset(int offset, boolean placement)
|
||||
{
|
||||
if (offset < 0)
|
||||
throw new IllegalArgumentException("TextOffset setOffset offset < 0: " + offset);
|
||||
|
||||
fOffset = offset;
|
||||
fPlacement = placement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare this to another Object.
|
||||
*/
|
||||
public boolean equals(Object other) {
|
||||
|
||||
try {
|
||||
return equals((TextOffset)other);
|
||||
}
|
||||
catch(ClassCastException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if offset and placement are the same.
|
||||
*
|
||||
* @param other offset to compare against
|
||||
* @return true if both offsets are equal
|
||||
*/
|
||||
public boolean equals(TextOffset other) {
|
||||
|
||||
return fOffset == other.fOffset && fPlacement == other.fPlacement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the hashCode for this object.
|
||||
*/
|
||||
public int hashCode() {
|
||||
|
||||
return fPlacement==AFTER_OFFSET? fOffset : -fOffset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this offset is 'greaterThan' other. If the fOffset fields are equal, the
|
||||
* placement field is considered, and AFTER_OFFSET is considered 'greaterThan' BEFORE_OFFSET.
|
||||
*
|
||||
* @param other the other offset
|
||||
* @return true if this offset appears after other
|
||||
*/
|
||||
public boolean greaterThan(TextOffset other)
|
||||
{
|
||||
return fOffset > other.fOffset ||
|
||||
(fOffset == other.fOffset && fPlacement == AFTER_OFFSET && other.fPlacement == BEFORE_OFFSET);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this offset is 'lessThan' other. If the fOffset fields are equal, the
|
||||
* placement field is considered, and BEFORE_OFFSET is considered 'lessThan' AFTER_OFFSET.
|
||||
*
|
||||
* @param other the other offset
|
||||
* @return true if this offset appears before other
|
||||
*/
|
||||
public boolean lessThan(TextOffset other) {
|
||||
|
||||
return fOffset < other.fOffset ||
|
||||
(fOffset == other.fOffset && fPlacement == BEFORE_OFFSET && other.fPlacement == AFTER_OFFSET);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy the value of another TextOffset into this
|
||||
* @param other the TextOffset to copy
|
||||
*/
|
||||
public void assign(TextOffset other) {
|
||||
fOffset = other.fOffset;
|
||||
fPlacement = other.fPlacement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a string representation of this object.
|
||||
*/
|
||||
public String toString() {
|
||||
|
||||
return "[" + (fPlacement ? "before " : "after ") + fOffset + "]";
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue