OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libjava/] [classpath/] [gnu/] [java/] [awt/] [peer/] [gtk/] [BufferedImageGraphics.java] - Blame information for rev 769

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 769 jeremybenn
/* BufferedImageGraphics.java
2
   Copyright (C) 2006 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 java.awt.AlphaComposite;
42
import java.awt.Color;
43
import java.awt.Composite;
44
import java.awt.Graphics;
45
import java.awt.Graphics2D;
46
import java.awt.GraphicsConfiguration;
47
import java.awt.Image;
48
import java.awt.Rectangle;
49
import java.awt.Shape;
50
import java.awt.Toolkit;
51
import java.awt.font.GlyphVector;
52
import java.awt.geom.AffineTransform;
53
import java.awt.geom.Rectangle2D;
54
import java.awt.image.BufferedImage;
55
import java.awt.image.ColorModel;
56
import java.awt.image.DataBufferInt;
57
import java.awt.image.ImageObserver;
58
import java.awt.image.ImageProducer;
59
import java.awt.image.Raster;
60
import java.awt.image.RenderedImage;
61
import java.awt.image.SinglePixelPackedSampleModel;
62
import java.util.WeakHashMap;
63
 
64
/**
65
 * Implementation of Graphics2D on a Cairo surface.
66
 *
67
 * Simutanously maintains a CairoSurface and updates the
68
 * BufferedImage from that after each drawing operation.
69
 */
70
public class BufferedImageGraphics extends CairoGraphics2D
71
{
72
  /**
73
   * the buffered Image.
74
   */
75
  private BufferedImage image, buffer;
76
 
77
  /**
78
   * Image size.
79
   */
80
  private int imageWidth, imageHeight;
81
 
82
  /**
83
   * The cairo surface that we actually draw on.
84
   */
85
  CairoSurface surface;
86
 
87
  /**
88
   * Cache BufferedImageGraphics surfaces.
89
   */
90
  static WeakHashMap<BufferedImage, CairoSurface> bufferedImages
91
    = new WeakHashMap<BufferedImage, CairoSurface>();
92
 
93
  /**
94
   * Its corresponding cairo_t.
95
   */
96
  private long cairo_t;
97
 
98
  private boolean hasFastCM;
99
  private boolean hasAlpha;
100
 
101
 
102
  public BufferedImageGraphics(BufferedImage bi)
103
  {
104
    this.image = bi;
105
    imageWidth = bi.getWidth();
106
    imageHeight = bi.getHeight();
107
 
108
    if (!(image.getSampleModel() instanceof SinglePixelPackedSampleModel))
109
      hasFastCM = false;
110
    else if(bi.getColorModel().equals(CairoSurface.cairoCM_opaque))
111
      {
112
        hasFastCM = true;
113
        hasAlpha = false;
114
      }
115
    else if(bi.getColorModel().equals(CairoSurface.cairoColorModel)
116
        || bi.getColorModel().equals(CairoSurface.cairoCM_pre))
117
      {
118
        hasFastCM = true;
119
        hasAlpha = true;
120
      }
121
    else
122
      hasFastCM = false;
123
 
124
    // Cache surfaces.
125
    if( bufferedImages.get( bi ) != null )
126
      surface = bufferedImages.get( bi );
127
    else
128
      {
129
        surface = new CairoSurface( imageWidth, imageHeight );
130
        bufferedImages.put(bi, surface);
131
      }
132
 
133
    cairo_t = surface.newCairoContext();
134
 
135
    // Get pixels out of buffered image and set in cairo surface
136
    Raster raster = bi.getRaster();
137
    int[] pixels;
138
 
139
    if (hasFastCM)
140
      {
141
        SinglePixelPackedSampleModel sm = (SinglePixelPackedSampleModel)image.getSampleModel();
142
        int minX = image.getRaster().getSampleModelTranslateX();
143
        int minY = image.getRaster().getSampleModelTranslateY();
144
 
145
        // Pull pixels directly out of data buffer
146
        pixels = ((DataBufferInt)raster.getDataBuffer()).getData();
147
 
148
        // Discard pixels that fall outside of the image's bounds
149
        // (ie, this image is actually a subimage of a different image)
150
        if (!(sm.getScanlineStride() == imageWidth && minX == 0 && minY == 0))
151
          {
152
            int[] pixels2 = new int[imageWidth * imageHeight];
153
            int scanline = sm.getScanlineStride();
154
 
155
            for (int i = 0; i < imageHeight; i++)
156
              System.arraycopy(pixels, (i - minY) * scanline - minX, pixels2,
157
                               i * imageWidth, imageWidth);
158
 
159
            pixels = pixels2;
160
          }
161
 
162
        // Fill the alpha channel as opaque if image does not have alpha
163
        if( !hasAlpha )
164
          for(int i = 0; i < pixels.length; i++)
165
            pixels[i] &= 0xFFFFFFFF;
166
      }
167
    else
168
      {
169
        pixels = CairoGraphics2D.findSimpleIntegerArray(image.getColorModel(),
170
                                                        image.getData());
171
        if (pixels != null)
172
          System.arraycopy(pixels, 0, surface.getData(),
173
                           0, pixels.length);
174
      }
175
 
176
    setup( cairo_t );
177
    setClip(0, 0, imageWidth, imageHeight);
178
  }
179
 
180
  BufferedImageGraphics(BufferedImageGraphics copyFrom)
181
  {
182
    image = copyFrom.image;
183
    surface = copyFrom.surface;
184
    cairo_t = surface.newCairoContext();
185
    imageWidth = copyFrom.imageWidth;
186
    imageHeight = copyFrom.imageHeight;
187
 
188
    hasFastCM = copyFrom.hasFastCM;
189
    hasAlpha = copyFrom.hasAlpha;
190
 
191
    copy( copyFrom, cairo_t );
192
  }
193
 
194
  /**
195
   * Update a rectangle of the bufferedImage. This can be improved upon a lot.
196
   */
197
  private void updateBufferedImage(int x, int y, int width, int height)
198
  {
199
    Rectangle bounds = new Rectangle(x, y, width, height);
200
    bounds = getTransformedBounds(bounds, transform).getBounds();
201
    x = bounds.x;
202
    y = bounds.y;
203
    width = bounds.width;
204
    height = bounds.height;
205
 
206
    int[] pixels = surface.getData();
207
 
208
    if( x > imageWidth || y > imageHeight )
209
      return;
210
 
211
    // Deal with negative width/height.
212
    if (height < 0)
213
      {
214
        y += height;
215
        height = -height;
216
      }
217
    if (width < 0)
218
      {
219
        x += width;
220
        width = -width;
221
      }
222
 
223
    // Clip edges.
224
    if( x < 0 )
225
      x = 0;
226
    if( y < 0 )
227
      y = 0;
228
 
229
    if( x + width > imageWidth )
230
      width = imageWidth - x;
231
    if( y + height > imageHeight )
232
      height = imageHeight - y;
233
 
234
    if(!hasFastCM)
235
      {
236
        image.setRGB(x, y, width, height, pixels,
237
                     x + y * imageWidth, imageWidth);
238
        // The setRGB method assumes (or should assume) that pixels are NOT
239
        // alpha-premultiplied, but Cairo stores data with premultiplication
240
        // (thus the pixels returned in getPixels are premultiplied).
241
        // This is ignored for consistency, however, since in
242
        // CairoGrahpics2D.drawImage we also use non-premultiplied data
243
 
244
      }
245
    else
246
      {
247
        int[] db = ((DataBufferInt)image.getRaster().getDataBuffer()).
248
                  getData();
249
 
250
        // This should not fail, as we check the image sample model when we
251
        // set the hasFastCM flag
252
        SinglePixelPackedSampleModel sm = (SinglePixelPackedSampleModel)image.getSampleModel() ;
253
 
254
        int minX = image.getRaster().getSampleModelTranslateX();
255
        int minY = image.getRaster().getSampleModelTranslateY();
256
 
257
        if (sm.getScanlineStride() == imageWidth && minX == 0)
258
          {
259
            System.arraycopy(pixels, y * imageWidth,
260
                             db, (y - minY) * imageWidth,
261
                             height * imageWidth);
262
          }
263
        else
264
          {
265
            int scanline = sm.getScanlineStride();
266
            for (int i = y; i < (height + y); i++)
267
              System.arraycopy(pixels, i * imageWidth + x, db,
268
                               (i - minY) * scanline + x - minX, width);
269
 
270
          }
271
      }
272
  }
273
 
274
  /**
275
   * Abstract methods.
276
   */
277
  public Graphics create()
278
  {
279
    return new BufferedImageGraphics(this);
280
  }
281
 
282
  public GraphicsConfiguration getDeviceConfiguration()
283
  {
284
    return null;
285
  }
286
 
287
  protected Rectangle2D getRealBounds()
288
  {
289
    return new Rectangle2D.Double(0.0, 0.0, imageWidth, imageHeight);
290
  }
291
 
292
  public void copyAreaImpl(int x, int y, int width, int height, int dx, int dy)
293
  {
294
    surface.copyAreaNative(x, y, width, height, dx, dy, surface.width);
295
    updateBufferedImage(x + dx, y + dy, width, height);
296
  }
297
 
298
  /**
299
   * Overloaded methods that do actual drawing need to enter the gdk threads
300
   * and also do certain things before and after.
301
   */
302
  public void draw(Shape s)
303
  {
304
    // Find total bounds of shape
305
    Rectangle r = findStrokedBounds(s);
306
    if (shiftDrawCalls)
307
      {
308
        r.width++;
309
        r.height++;
310
      }
311
 
312
    // Do the drawing
313
    if (comp == null || comp instanceof AlphaComposite)
314
      {
315
        super.draw(s);
316
        updateBufferedImage(r.x, r.y, r.width, r.height);
317
      }
318
    else
319
      {
320
        createBuffer();
321
 
322
        Graphics2D g2d = (Graphics2D)buffer.getGraphics();
323
        g2d.setStroke(this.getStroke());
324
        g2d.setColor(this.getColor());
325
        g2d.setTransform(transform);
326
        g2d.draw(s);
327
 
328
        drawComposite(r.getBounds2D(), null);
329
      }
330
  }
331
 
332
  public void fill(Shape s)
333
  {
334
    if (comp == null || comp instanceof AlphaComposite)
335
      {
336
        super.fill(s);
337
        Rectangle r = s.getBounds();
338
        updateBufferedImage(r.x, r.y, r.width, r.height);
339
      }
340
    else
341
      {
342
        createBuffer();
343
 
344
        Graphics2D g2d = (Graphics2D)buffer.getGraphics();
345
        g2d.setPaint(this.getPaint());
346
        g2d.setColor(this.getColor());
347
        g2d.setTransform(transform);
348
        g2d.fill(s);
349
 
350
        drawComposite(s.getBounds2D(), null);
351
      }
352
  }
353
 
354
  public void drawRenderedImage(RenderedImage image, AffineTransform xform)
355
  {
356
    if (comp == null || comp instanceof AlphaComposite)
357
      {
358
        super.drawRenderedImage(image, xform);
359
        updateBufferedImage(0, 0, imageWidth, imageHeight);
360
      }
361
    else
362
      {
363
        createBuffer();
364
 
365
        Graphics2D g2d = (Graphics2D)buffer.getGraphics();
366
        g2d.setRenderingHints(this.getRenderingHints());
367
        g2d.setTransform(transform);
368
        g2d.drawRenderedImage(image, xform);
369
 
370
        drawComposite(buffer.getRaster().getBounds(), null);
371
      }
372
 
373
  }
374
 
375
  protected boolean drawImage(Image img, AffineTransform xform,
376
                              Color bgcolor, ImageObserver obs)
377
  {
378
    if (comp == null || comp instanceof AlphaComposite)
379
      {
380
        boolean rv = super.drawImage(img, xform, bgcolor, obs);
381
        updateBufferedImage(0, 0, imageWidth, imageHeight);
382
        return rv;
383
      }
384
    else
385
      {
386
        // Get buffered image of source
387
        if( !(img instanceof BufferedImage) )
388
          {
389
            ImageProducer source = img.getSource();
390
            if (source == null)
391
              return false;
392
            img = Toolkit.getDefaultToolkit().createImage(source);
393
          }
394
        BufferedImage bImg = (BufferedImage) img;
395
 
396
        // Find translated bounds
397
        Rectangle2D bounds = new Rectangle(bImg.getMinX(), bImg.getMinY(),
398
                                           bImg.getWidth(), bImg.getHeight());
399
        if (xform != null)
400
          bounds = getTransformedBounds(bounds, xform);
401
 
402
        // Create buffer and draw image
403
        createBuffer();
404
 
405
        Graphics2D g2d = (Graphics2D)buffer.getGraphics();
406
        g2d.setRenderingHints(this.getRenderingHints());
407
        g2d.drawImage(img, xform, obs);
408
 
409
        // Perform compositing
410
        return drawComposite(bounds, obs);
411
      }
412
  }
413
 
414
  public void drawGlyphVector(GlyphVector gv, float x, float y)
415
  {
416
    // Find absolute bounds, in user-space, of this glyph vector
417
    Rectangle2D bounds = gv.getLogicalBounds();
418
    bounds = new Rectangle2D.Double(x + bounds.getX(), y + bounds.getY(),
419
                                    bounds.getWidth(), bounds.getHeight());
420
 
421
    // Perform draw operation
422
    if (comp == null || comp instanceof AlphaComposite)
423
      {
424
        super.drawGlyphVector(gv, x, y);
425
 
426
        // this returns an integer-based Rectangle (rather than a
427
        // Rectangle2D), which takes care of any necessary rounding for us.
428
        bounds = bounds.getBounds();
429
 
430
        updateBufferedImage((int)bounds.getX(), (int)bounds.getY(),
431
                            (int)bounds.getWidth(), (int)bounds.getHeight());
432
      }
433
    else
434
      {
435
        createBuffer();
436
 
437
        Graphics2D g2d = (Graphics2D)buffer.getGraphics();
438
        g2d.setPaint(this.getPaint());
439
        g2d.setStroke(this.getStroke());
440
        g2d.setTransform(transform);
441
        g2d.drawGlyphVector(gv, x, y);
442
 
443
        drawComposite(bounds, null);
444
      }
445
  }
446
 
447
  /**
448
   * Perform composite drawing from the buffer onto the main image.
449
   *
450
   * The image to be composited should already be drawn into the buffer, in the
451
   * proper place, after all necessary transforms have been applied.
452
   *
453
   * @param bounds The bounds to draw, in user-space.
454
   * @param observer The image observer, if any (may be null).
455
   * @return True on success, false on failure.
456
   */
457
  private boolean drawComposite(Rectangle2D bounds, ImageObserver observer)
458
  {
459
    // Find bounds in device space
460
    bounds = getTransformedBounds(bounds, transform);
461
 
462
    // Clip bounds by the stored clip, and by the internal buffer
463
    Rectangle2D devClip = this.getClipInDevSpace();
464
    Rectangle2D.intersect(bounds, devClip, bounds);
465
    devClip = new Rectangle(buffer.getMinX(), buffer.getMinY(),
466
                            buffer.getWidth(), buffer.getHeight());
467
    Rectangle2D.intersect(bounds, devClip, bounds);
468
 
469
    // Round bounds as needed, but be careful in our rounding
470
    // (otherwise it may leave unpainted stripes)
471
    double x = bounds.getX();
472
    double y = bounds.getY();
473
    double maxX = x + bounds.getWidth();
474
    double maxY = y + bounds.getHeight();
475
    x = Math.round(x);
476
    y = Math.round(y);
477
    bounds.setRect(x, y, Math.round(maxX - x), Math.round(maxY - y));
478
 
479
    // Find subimage of internal buffer for updating
480
    BufferedImage buffer2 = buffer;
481
    if (!bounds.equals(buffer2.getRaster().getBounds()))
482
      buffer2 = buffer2.getSubimage((int)bounds.getX(), (int)bounds.getY(),
483
                                    (int)bounds.getWidth(),
484
                                    (int)bounds.getHeight());
485
 
486
    // Find subimage of main image for updating
487
    BufferedImage current = image;
488
    current = current.getSubimage((int)bounds.getX(), (int)bounds.getY(),
489
                                  (int)bounds.getWidth(),
490
                                  (int)bounds.getHeight());
491
 
492
    // Perform actual composite operation
493
    compCtx.compose(buffer2.getRaster(), current.getRaster(),
494
                    current.getRaster());
495
 
496
    // Set cairo's composite to direct SRC, since we've already done our own
497
    // compositing
498
    Composite oldcomp = comp;
499
    setComposite(AlphaComposite.Src);
500
 
501
    // This MUST call directly into the "action" method in CairoGraphics2D,
502
    // not one of the wrappers, to ensure that the composite isn't processed
503
    // more than once!
504
    boolean rv = super.drawImage(current,
505
                                 AffineTransform.getTranslateInstance(bounds.getX(),
506
                                                                      bounds.getY()),
507
                                 null, null);
508
    setComposite(oldcomp);
509
    updateColor();
510
    return rv;
511
  }
512
 
513
  private void createBuffer()
514
  {
515
    if (buffer == null)
516
      {
517
        buffer = new BufferedImage(image.getWidth(), image.getHeight(),
518
                                   BufferedImage.TYPE_INT_ARGB);
519
      }
520
    else
521
      {
522
        Graphics2D g2d = ((Graphics2D)buffer.getGraphics());
523
 
524
        g2d.setBackground(new Color(0,0,0,0));
525
        g2d.clearRect(0, 0, buffer.getWidth(), buffer.getHeight());
526
      }
527
  }
528
 
529
  protected ColorModel getNativeCM()
530
  {
531
    return image.getColorModel();
532
  }
533
 
534
  protected ColorModel getBufferCM()
535
  {
536
    return ColorModel.getRGBdefault();
537
  }
538
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.