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