1 /* GdkTextLayout.java 2 Copyright (C) 2003, 2005 Free Software Foundation, Inc. 3 4 This file is part of GNU Classpath. 5 6 GNU Classpath is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 2, or (at your option) 9 any later version. 10 11 GNU Classpath is distributed in the hope that it will be useful, but 12 WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with GNU Classpath; see the file COPYING. If not, write to the 18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19 02110-1301 USA. 20 21 Linking this library statically or dynamically with other modules is 22 making a combined work based on this library. Thus, the terms and 23 conditions of the GNU General Public License cover the whole 24 combination. 25 26 As a special exception, the copyright holders of this library give you 27 permission to link this library with independent modules to produce an 28 executable, regardless of the license terms of these independent 29 modules, and to copy and distribute the resulting executable under 30 terms of your choice, provided that you also meet, for each linked 31 independent module, the terms and conditions of the license of that 32 module. An independent module is a module which is not derived from 33 or based on this library. If you modify this library, you may extend 34 this exception to your version of the library, but you are not 35 obligated to do so. If you do not wish to do so, delete this 36 exception statement from your version. */ 37 38 39 package gnu.java.awt.peer.gtk; 40 41 import gnu.classpath.Configuration; 42 import gnu.java.awt.peer.ClasspathTextLayoutPeer; 43 44 import java.awt.Font; 45 import java.awt.Graphics2D; 46 import java.awt.Shape; 47 import java.awt.font.FontRenderContext; 48 import java.awt.font.GlyphMetrics; 49 import java.awt.font.GlyphVector; 50 import java.awt.font.TextAttribute; 51 import java.awt.font.TextHitInfo; 52 import java.awt.font.TextLayout; 53 import java.awt.geom.AffineTransform; 54 import java.awt.geom.GeneralPath; 55 import java.awt.geom.Rectangle2D; 56 import java.text.AttributedCharacterIterator; 57 import java.text.AttributedString; 58 import java.text.CharacterIterator; 59 60 /** 61 * This is an implementation of the text layout peer interface which 62 * delegates all the hard work to pango. 63 * 64 * @author Graydon Hoare 65 */ 66 67 public class GdkTextLayout 68 implements ClasspathTextLayoutPeer 69 { 70 // native side, plumbing, etc. 71 static 72 { 73 if (Configuration.INIT_LOAD_LIBRARY) 74 { 75 System.loadLibrary("gtkpeer"); 76 } initStaticState()77 initStaticState (); 78 } setText(String str)79 private native void setText(String str); getExtents(double[] inkExtents, double[] logExtents)80 private native void getExtents(double[] inkExtents, 81 double[] logExtents); indexToPos(int idx, double[] pos)82 private native void indexToPos(int idx, double[] pos); initState()83 private native void initState (); dispose()84 private native void dispose (); initStaticState()85 static native void initStaticState(); 86 private final int native_state = GtkGenericPeer.getUniqueInteger (); finalize()87 protected void finalize () 88 { 89 dispose (); 90 } 91 92 // we hold on to these to make sure we can render when presented 93 // with non-GdkGraphics2D paint targets 94 private AttributedString attributedString; 95 private FontRenderContext fontRenderContext; 96 GdkTextLayout(AttributedString str, FontRenderContext frc)97 public GdkTextLayout(AttributedString str, FontRenderContext frc) 98 { 99 initState(); 100 attributedString = str; 101 fontRenderContext = frc; 102 } 103 104 protected class CharacterIteratorProxy 105 implements CharacterIterator 106 { 107 public CharacterIterator target; 108 public int begin; 109 public int limit; 110 public int index; 111 CharacterIteratorProxy(CharacterIterator ci)112 public CharacterIteratorProxy (CharacterIterator ci) 113 { 114 target = ci; 115 } 116 getBeginIndex()117 public int getBeginIndex () 118 { 119 return begin; 120 } 121 getEndIndex()122 public int getEndIndex () 123 { 124 return limit; 125 } 126 getIndex()127 public int getIndex () 128 { 129 return index; 130 } 131 setIndex(int idx)132 public char setIndex (int idx) 133 throws IllegalArgumentException 134 { 135 if (idx < begin || idx >= limit) 136 throw new IllegalArgumentException (); 137 char ch = target.setIndex (idx); 138 index = idx; 139 return ch; 140 } 141 first()142 public char first () 143 { 144 int save = target.getIndex (); 145 char ch = target.setIndex (begin); 146 target.setIndex (save); 147 return ch; 148 } 149 last()150 public char last () 151 { 152 if (begin == limit) 153 return this.first (); 154 155 int save = target.getIndex (); 156 char ch = target.setIndex (limit - 1); 157 target.setIndex (save); 158 return ch; 159 } 160 current()161 public char current () 162 { 163 return target.current(); 164 } 165 next()166 public char next () 167 { 168 if (index >= limit - 1) 169 return CharacterIterator.DONE; 170 else 171 { 172 index++; 173 return target.next(); 174 } 175 } 176 previous()177 public char previous () 178 { 179 if (index <= begin) 180 return CharacterIterator.DONE; 181 else 182 { 183 index--; 184 return target.previous (); 185 } 186 } 187 clone()188 public Object clone () 189 { 190 CharacterIteratorProxy cip = new CharacterIteratorProxy (this.target); 191 cip.begin = this.begin; 192 cip.limit = this.limit; 193 cip.index = this.index; 194 return cip; 195 } 196 197 } 198 199 200 // public side 201 draw(Graphics2D g2, float x, float y)202 public void draw (Graphics2D g2, float x, float y) 203 { 204 if (g2 instanceof GdkGraphics2D) 205 { 206 // we share pango structures directly with GdkGraphics2D 207 // when legal 208 GdkGraphics2D gg2 = (GdkGraphics2D) g2; 209 gg2.drawGdkTextLayout(this, x, y); 210 } 211 else 212 { 213 // falling back to a rather tedious layout algorithm when 214 // not legal 215 AttributedCharacterIterator ci = attributedString.getIterator (); 216 CharacterIteratorProxy proxy = new CharacterIteratorProxy (ci); 217 Font defFont = g2.getFont (); 218 219 /* Note: this implementation currently only interprets FONT text 220 * attributes. There is a reasonable argument to be made for some 221 * attributes being interpreted out here, where we have control of the 222 * Graphics2D and can construct or derive new fonts, and some 223 * attributes being interpreted by the GlyphVector itself. So far, for 224 * all attributes except FONT we do neither. 225 */ 226 227 for (char c = ci.first (); 228 c != CharacterIterator.DONE; 229 c = ci.next ()) 230 { 231 proxy.begin = ci.getIndex (); 232 proxy.limit = ci.getRunLimit(TextAttribute.FONT); 233 if (proxy.limit <= proxy.begin) 234 continue; 235 236 proxy.index = proxy.begin; 237 238 Object fnt = ci.getAttribute(TextAttribute.FONT); 239 GlyphVector gv; 240 if (fnt instanceof Font) 241 gv = ((Font)fnt).createGlyphVector (fontRenderContext, proxy); 242 else 243 gv = defFont.createGlyphVector (fontRenderContext, proxy); 244 245 g2.drawGlyphVector (gv, x, y); 246 247 int n = gv.getNumGlyphs (); 248 for (int i = 0; i < n; ++i) 249 { 250 GlyphMetrics gm = gv.getGlyphMetrics (i); 251 if (gm.getAdvanceX() == gm.getAdvance ()) 252 x += gm.getAdvanceX (); 253 else 254 y += gm.getAdvanceY (); 255 } 256 } 257 } 258 } 259 getStrongCaret(TextHitInfo hit1, TextHitInfo hit2)260 public TextHitInfo getStrongCaret (TextHitInfo hit1, 261 TextHitInfo hit2) 262 { 263 throw new Error("not implemented"); 264 } 265 getBaseline()266 public byte getBaseline () 267 { 268 throw new Error("not implemented"); 269 } 270 isLeftToRight()271 public boolean isLeftToRight () 272 { 273 throw new Error("not implemented"); 274 } 275 isVertical()276 public boolean isVertical () 277 { 278 throw new Error("not implemented"); 279 } 280 getAdvance()281 public float getAdvance () 282 { 283 throw new Error("not implemented"); 284 } 285 getAscent()286 public float getAscent () 287 { 288 throw new Error("not implemented"); 289 } 290 getDescent()291 public float getDescent () 292 { 293 throw new Error("not implemented"); 294 } 295 getLeading()296 public float getLeading () 297 { 298 throw new Error("not implemented"); 299 } 300 getCharacterCount()301 public int getCharacterCount () 302 { 303 throw new Error("not implemented"); 304 } 305 getCharacterLevel(int index)306 public byte getCharacterLevel (int index) 307 { 308 throw new Error("not implemented"); 309 } 310 getBaselineOffsets()311 public float[] getBaselineOffsets () 312 { 313 throw new Error("not implemented"); 314 } 315 getBlackBoxBounds(int firstEndpoint, int secondEndpoint)316 public Shape getBlackBoxBounds (int firstEndpoint, int secondEndpoint) 317 { 318 throw new Error("not implemented"); 319 } 320 getBounds()321 public Rectangle2D getBounds () 322 { 323 double[] inkExtents = new double[4]; 324 double[] logExtents = new double[4]; 325 getExtents(inkExtents, logExtents); 326 return new Rectangle2D.Double(logExtents[0], logExtents[1], 327 logExtents[2], logExtents[3]); 328 } 329 getCaretInfo(TextHitInfo hit, Rectangle2D bounds)330 public float[] getCaretInfo (TextHitInfo hit, Rectangle2D bounds) 331 { 332 throw new Error("not implemented"); 333 } 334 getCaretShape(TextHitInfo hit, Rectangle2D bounds)335 public Shape getCaretShape (TextHitInfo hit, Rectangle2D bounds) 336 { 337 throw new Error("not implemented"); 338 } 339 getCaretShapes(int offset, Rectangle2D bounds, TextLayout.CaretPolicy policy)340 public Shape[] getCaretShapes (int offset, Rectangle2D bounds, 341 TextLayout.CaretPolicy policy) 342 { 343 throw new Error("not implemented"); 344 } 345 getLogicalHighlightShape(int firstEndpoint, int secondEndpoint, Rectangle2D bounds)346 public Shape getLogicalHighlightShape (int firstEndpoint, int secondEndpoint, 347 Rectangle2D bounds) 348 { 349 AffineTransform at = new AffineTransform(); 350 GeneralPath gp = new GeneralPath(); 351 double [] rect = new double[4]; 352 Rectangle2D tmp = new Rectangle2D.Double(); 353 for (int i = firstEndpoint; i <= secondEndpoint; ++i) 354 { 355 indexToPos(i, rect); 356 tmp.setRect(rect[0], rect[1], rect[2], rect[3]); 357 Rectangle2D.intersect(tmp, bounds, tmp); 358 gp.append(tmp.getPathIterator(at), false); 359 } 360 return gp; 361 } 362 getLogicalRangesForVisualSelection(TextHitInfo firstEndpoint, TextHitInfo secondEndpoint)363 public int[] getLogicalRangesForVisualSelection (TextHitInfo firstEndpoint, 364 TextHitInfo secondEndpoint) 365 { 366 throw new Error("not implemented"); 367 } 368 getNextLeftHit(int offset, TextLayout.CaretPolicy policy)369 public TextHitInfo getNextLeftHit (int offset, TextLayout.CaretPolicy policy) 370 { 371 throw new Error("not implemented"); 372 } getNextRightHit(int offset, TextLayout.CaretPolicy policy)373 public TextHitInfo getNextRightHit (int offset, TextLayout.CaretPolicy policy) 374 { 375 throw new Error("not implemented"); 376 } hitTestChar(float x, float y, Rectangle2D bounds)377 public TextHitInfo hitTestChar (float x, float y, Rectangle2D bounds) 378 { 379 throw new Error("not implemented"); 380 } getVisualOtherHit(TextHitInfo hit)381 public TextHitInfo getVisualOtherHit (TextHitInfo hit) 382 { 383 throw new Error("not implemented"); 384 } 385 getVisibleAdvance()386 public float getVisibleAdvance () 387 { 388 throw new Error("not implemented"); 389 } 390 getOutline(AffineTransform tx)391 public native Shape getOutline (AffineTransform tx); 392 getVisualHighlightShape(TextHitInfo firstEndpoint, TextHitInfo secondEndpoint, Rectangle2D bounds)393 public Shape getVisualHighlightShape (TextHitInfo firstEndpoint, 394 TextHitInfo secondEndpoint, 395 Rectangle2D bounds) 396 { 397 throw new Error("not implemented"); 398 } 399 400 getJustifiedLayout(float justificationWidth)401 public TextLayout getJustifiedLayout (float justificationWidth) 402 { 403 throw new Error("not implemented"); 404 } 405 handleJustify(float justificationWidth)406 public void handleJustify (float justificationWidth) 407 { 408 throw new Error("not implemented"); 409 } 410 clone()411 public Object clone () 412 { 413 throw new Error("not implemented"); 414 } 415 hashCode()416 public int hashCode () 417 { 418 throw new Error("not implemented"); 419 } 420 equals(ClasspathTextLayoutPeer tl)421 public boolean equals (ClasspathTextLayoutPeer tl) 422 { 423 throw new Error("not implemented"); 424 } 425 toString()426 public String toString () 427 { 428 throw new Error("not implemented"); 429 } 430 431 } 432