~ubuntu-branches/ubuntu/saucy/gnash/saucy-proposed

« back to all changes in this revision

Viewing changes to libbase/snappingrange.h

  • Committer: Bazaar Package Importer
  • Author(s): Alexander Sack
  • Date: 2008-10-13 14:29:49 UTC
  • mfrom: (1.1.9 upstream)
  • Revision ID: james.westby@ubuntu.com-20081013142949-f6qdvnu4mn05ltdc
Tags: 0.8.4~~bzr9980-0ubuntu1
* new upstream release 0.8.4 (LP: #240325)
* ship new lib usr/lib/gnash/libmozsdk.so.* in mozilla-plugin-gnash
  - update debian/mozilla-plugin-gnash.install
* ship new lib usr/lib/gnash/libgnashnet.so.* in gnash-common
  - update debian/gnash-common.install
* add basic debian/build_head script to build latest CVS head packages.
  - add debian/build_head
* new sound architecture requires build depend on libsdl1.2-dev
  - update debian/control
* head build script now has been completely migrated to bzr (upstream +
  ubuntu)
  - update debian/build_head
* disable kde gui until klash/qt4 has been fixed; keep kde packages as empty
  packages for now.
  - update debian/rules
  - debian/klash.install
  - debian/klash.links
  - debian/klash.manpages
  - debian/konqueror-plugin-gnash.install
* drop libkonq5-dev build dependency accordingly
  - update debian/control
* don't install headers manually anymore. gnash doesnt provide a -dev
  package after all
  - update debian/rules
* update libs installed in gnash-common; libgnashserver-*.so is not available
  anymore (removed); in turn we add the new libgnashcore-*.so
  - update debian/gnash-common.install
* use -Os for optimization and properly pass CXXFLAGS=$(CFLAGS) to configure
  - update debian/rules
* touch firefox .autoreg in postinst of mozilla plugin
  - update debian/mozilla-plugin-gnash.postinst
* link gnash in ubufox plugins directory for the plugin alternative switcher
  - add debian/mozilla-plugin-gnash.links
* suggest ubufox accordingly
  - update debian/control
* add new required build-depends on libgif-dev
  - update debian/control
* add Xb-Npp-Description and Xb-Npp-File as new plugin database meta data
  - update debian/control

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// 
 
2
//   Copyright (C) 2007, 2008 Free Software Foundation, Inc.
 
3
// 
 
4
// This program is free software; you can redistribute it and/or modify
 
5
// it under the terms of the GNU General Public License as published by
 
6
// the Free Software Foundation; either version 3 of the License, or
 
7
// (at your option) any later version.
 
8
// 
 
9
// This program is distributed in the hope that it will be useful,
 
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
12
// GNU General Public License for more details.
 
13
// 
 
14
// You should have received a copy of the GNU General Public License
 
15
// along with this program; if not, write to the Free Software
 
16
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
17
 
 
18
// 
 
19
 
 
20
#ifndef GNASH_SNAPPINGRANGE_H
 
21
#define GNASH_SNAPPINGRANGE_H
 
22
 
 
23
#include <list>
 
24
#include <vector>
 
25
#include "Range2d.h"
 
26
 
 
27
namespace gnash {
 
28
 
 
29
namespace geometry {
 
30
 
 
31
/// \brief
 
32
/// Snapping range class. Can hold a number of 2D ranges and combines 
 
33
/// ranges that come very close. This class is used for multiple invalidated
 
34
/// bounds calculation.
 
35
//
 
36
/// Additionally to merge intersecting ranges this class also "snaps" ranges
 
37
/// together which "probably" would be rendered in one single step. When the
 
38
/// area of the potential merged range is not much greater than the sum of
 
39
/// two single range areas, then these two ranges are merged together to one
 
40
/// single range. The "snap factor" defines how much bigger the merged area
 
41
/// can become to be a snap candidate (it's the maximum allowed factor that
 
42
/// the merged area can be greater than the sum).
 
43
///
 
44
/// Optimally the factor 1.0 would be best, but multiple snapping ranges also
 
45
/// increase rendering preprocessing overhead and the factor tries to equalize
 
46
/// this. The default value is usually fine for most situations.
 
47
///
 
48
/// The factor method makes sure that very close, but also very different 
 
49
/// shapes, don't get merged, like in the following example:
 
50
///
 
51
///          +---+
 
52
///          |   |    
 
53
///          |   |    
 
54
///          |   |    
 
55
///          |   |    
 
56
///          |   |
 
57
///          +---+
 
58
///   +-----------------------------------+
 
59
///   |                                   |
 
60
///   +-----------------------------------+    
 
61
///
 
62
/// Merging these two ranges would create a much bigger range which in some
 
63
/// situations means that rendering is notably slower (for example, when 
 
64
/// there is a scaled bitmap behind these shapes).
 
65
///
 
66
 
 
67
template <typename T>
 
68
class SnappingRanges2d
 
69
{
 
70
public:
 
71
  typedef geometry::Range2d<T> RangeType;
 
72
  typedef std::vector<RangeType> RangeList; // TODO: list might be more appropriate
 
73
  typedef typename RangeList::size_type size_type;  
 
74
 
 
75
  template <typename U>
 
76
  friend std::ostream& operator<< (std::ostream& os, const SnappingRanges2d<U>& r);
 
77
  
 
78
  SnappingRanges2d() 
 
79
    :
 
80
    snap_factor(1.3f),
 
81
    single_mode(false),
 
82
    ranges_limit(50),
 
83
    _combine_counter(0)
 
84
  {
 
85
  }
 
86
 
 
87
  /// Templated copy constructor, for casting between range types
 
88
  template <typename U>
 
89
  SnappingRanges2d(const SnappingRanges2d<U>& from)
 
90
    :
 
91
    snap_factor(from.getSnapFactor()), 
 
92
    single_mode(from.getSingleMode()),
 
93
    ranges_limit(from.getRangeCountLimit()),
 
94
    _combine_counter(0)
 
95
  {
 
96
    if ( from.isWorld() ) {
 
97
      setWorld();
 
98
    } else if ( from.isNull() ) {
 
99
      setNull();
 
100
    } else {
 
101
      // TODO: can we safely assume that the 'from' parameter was
 
102
      //       finalized ?
 
103
      // from.finalize(); // can't call finalize, it's private !!
 
104
 
 
105
      // TODO: use visitor pattern !
 
106
      unsigned rcount = from.size();
 
107
      for (unsigned int rno=0; rno<rcount; rno++)
 
108
      {
 
109
        Range2d<U> r = from.getRange(rno);
 
110
        RangeType rc(r);
 
111
        add(rc);
 
112
      }
 
113
    }
 
114
  }
 
115
  
 
116
  /// Sets the snapping factor (which must be > 1.0). Higher factors make
 
117
  /// the ranges more attractive for snapping. A good value is usually 1.3.
 
118
  void setSnapFactor(float factor) {
 
119
    assert(factor > 1.0f);
 
120
    snap_factor = factor;
 
121
  }
 
122
  
 
123
  float getSnapFactor() const {
 
124
    return snap_factor;
 
125
  }
 
126
  
 
127
  /// if mode==true, then the snapping ranges will act like a normal Range2d
 
128
  void setSingleMode(bool mode) {
 
129
    single_mode = mode;
 
130
  }
 
131
  
 
132
  bool getSingleMode() const {
 
133
    return single_mode;
 
134
  }  
 
135
  
 
136
  /// Sets the maximum number of ranges allowed (to avoid lots of small
 
137
  /// ranges)
 
138
  void setRangeCountLimit(unsigned limit) {
 
139
    ranges_limit = limit;
 
140
  }
 
141
  
 
142
  unsigned getRangeCountLimit() const {
 
143
    return ranges_limit;
 
144
  }
 
145
  
 
146
  /// Copy the snapping settings from another ranges list, without
 
147
  /// copying the ranges itself
 
148
  void inheritConfig(const SnappingRanges2d<T>& from) {
 
149
   snap_factor = from.snap_factor;
 
150
   single_mode = from.single_mode;
 
151
  }
 
152
  
 
153
  /// Add a Range to the set, merging when possible and appropriate
 
154
  void add(const RangeType& range) {
 
155
    if (range.isWorld()) {
 
156
      setWorld();
 
157
      return;
 
158
    }
 
159
    
 
160
    if (range.isNull()) return;
 
161
    
 
162
    if (single_mode) {
 
163
    
 
164
      // single range mode
 
165
    
 
166
      if (_ranges.empty()) {
 
167
        RangeType temp;
 
168
        _ranges.push_back(temp);
 
169
      }
 
170
      
 
171
      _ranges[0].expandTo(range);
 
172
    
 
173
    } else {  
 
174
    
 
175
      // multi range mode
 
176
    
 
177
      for (unsigned int rno=0; rno<_ranges.size(); rno++) {
 
178
        if (snaptest(_ranges[rno], range)) {
 
179
          _ranges[rno].expandTo(range);
 
180
          return;
 
181
        }
 
182
      }
 
183
      
 
184
      // reached this point we need a new range 
 
185
      _ranges.push_back(range);
 
186
      
 
187
      combine_ranges_lazy();
 
188
    }
 
189
  }
 
190
  
 
191
  
 
192
  /// combines two snapping ranges
 
193
  void add(SnappingRanges2d<T> other_ranges) {
 
194
    for (unsigned int rno=0; rno<other_ranges.size(); rno++)
 
195
      add(other_ranges.getRange(rno));
 
196
  }
 
197
  
 
198
  /// Grows all ranges by the specified amount 
 
199
  void growBy(T amount) {
 
200
  
 
201
    if (isWorld() || isNull()) 
 
202
      return;
 
203
    
 
204
    unsigned rcount = _ranges.size();
 
205
    
 
206
    for (unsigned int rno=0; rno<rcount; rno++)
 
207
      _ranges[rno].growBy(amount);
 
208
      
 
209
    combine_ranges_lazy();
 
210
  }
 
211
 
 
212
  /// Scale all ranges by the specified factor
 
213
  void scale(float factor) {
 
214
  
 
215
    if (isWorld() || isNull()) 
 
216
      return;
 
217
    
 
218
    unsigned rcount = _ranges.size();
 
219
    
 
220
    for (unsigned int rno=0; rno<rcount; rno++)
 
221
      _ranges[rno].scale(factor);
 
222
      
 
223
    combine_ranges_lazy();
 
224
  }
 
225
  
 
226
  /// Combines known ranges. Previously merged ranges may have come close
 
227
  /// to other ranges. Algorithm could be optimized. 
 
228
  void combine_ranges() {
 
229
  
 
230
    if (single_mode)  // makes no sense in single mode
 
231
      return;
 
232
  
 
233
    bool restart=true;
 
234
    
 
235
    _combine_counter=0;
 
236
    
 
237
    while (restart) {
 
238
    
 
239
      int rcount = _ranges.size();
 
240
 
 
241
      restart=false;
 
242
    
 
243
      for (int i=0; i<rcount; i++) {
 
244
      
 
245
        for (int j=i+1; j<rcount; j++) {
 
246
        
 
247
          if (snaptest(_ranges[i], _ranges[j])) {
 
248
            // merge i + j
 
249
            _ranges[i].expandTo(_ranges[j]);
 
250
            
 
251
            _ranges.erase(_ranges.begin() + j);
 
252
            
 
253
            restart=true; // restart from beginning
 
254
            break;
 
255
            
 
256
          } //if
 
257
        
 
258
        } //for
 
259
        
 
260
        if (restart)
 
261
          break;
 
262
      
 
263
      } //for
 
264
    
 
265
    } //while
 
266
    
 
267
    
 
268
    // limit number of ranges
 
269
    if (_ranges.size() > ranges_limit) {
 
270
    
 
271
      // We found way too much ranges, so reduce to just one single range.
 
272
      // We could also double the factor and try again, but that probably
 
273
      // won't make much difference, so we avoid the trouble...
 
274
      
 
275
      RangeType single = getFullArea();      
 
276
      _ranges.resize(1);
 
277
      _ranges[0] = single;
 
278
    
 
279
    }
 
280
  
 
281
  }
 
282
  
 
283
  
 
284
  /// Calls combine_ranges() once in a while, but not always. Avoids too many
 
285
  /// combine_ranges() checks, which could slow down everything.
 
286
  void combine_ranges_lazy() {
 
287
    _combine_counter++;
 
288
    if (_combine_counter > 5) 
 
289
      combine_ranges();
 
290
  }
 
291
      
 
292
  /// returns true, when two ranges should be merged together
 
293
  inline bool snaptest(const RangeType& range1, const RangeType& range2) {
 
294
  
 
295
    // when they intersect anyway, they should of course be merged! 
 
296
    // TODO: not really, a "+" style ranges list might be worth to 
 
297
    // remain unmerged (but needs special handling, i.e. create three
 
298
    // ranges out of two)...
 
299
    if (range1.intersects(range2)) 
 
300
      return true;
 
301
      
 
302
    // simply search for the minimum x or y distances
 
303
    /*
 
304
  
 
305
    T xdist = 99999999;
 
306
    T ydist = 99999999;
 
307
    T xa1 = range1.getMinX();
 
308
    T xa2 = range2.getMinX();
 
309
    T xb1 = range1.getMaxX();
 
310
    T xb2 = range2.getMaxX();
 
311
    T ya1 = range1.getMinY();
 
312
    T ya2 = range2.getMinY();
 
313
    T yb1 = range1.getMaxY();
 
314
    T yb2 = range2.getMaxY();
 
315
    
 
316
    xdist = absmin(xdist, xa1-xa2);
 
317
    xdist = absmin(xdist, xa1-xb2);
 
318
    xdist = absmin(xdist, xb1-xa2);
 
319
    xdist = absmin(xdist, xb1-xb2);
 
320
 
 
321
    ydist = absmin(ydist, ya1-ya2);
 
322
    ydist = absmin(ydist, ya1-yb2);
 
323
    ydist = absmin(ydist, yb1-ya2);
 
324
    ydist = absmin(ydist, yb1-yb2);
 
325
    
 
326
    return (xdist + ydist) <= snap_distance;
 
327
    */
 
328
    
 
329
    RangeType temp = range1;
 
330
    temp.expandTo(range2);
 
331
    
 
332
    return (range1.getArea() + range2.getArea()) * snap_factor > temp.getArea();
 
333
 
 
334
  } 
 
335
    
 
336
  /// Resets to NULL range
 
337
  void setNull() {
 
338
    _ranges.clear();
 
339
  }
 
340
  
 
341
  /// Resets to one range with world flags
 
342
  void setWorld() {
 
343
    if (isWorld()) return;
 
344
    _ranges.resize(1);
 
345
    _ranges[0].setWorld();
 
346
  }
 
347
  
 
348
  /// Returns true, when the ranges equal world range
 
349
  bool isWorld() const {
 
350
    return ( (size()==1) && (_ranges.front().isWorld()) );
 
351
  }
 
352
  
 
353
  /// Returns true, when there is no range
 
354
  bool isNull() const {
 
355
    return _ranges.empty();
 
356
  }
 
357
  
 
358
  /// Returns the number of ranges in the list
 
359
  size_type size() const {
 
360
    finalize();
 
361
    return _ranges.size();
 
362
  }
 
363
  
 
364
  /// Returns the range at the specified index
 
365
  //
 
366
  /// TODO: return by reference ?
 
367
  ///
 
368
  RangeType getRange(unsigned int index) const {
 
369
    finalize();
 
370
    assert(index<size());
 
371
    
 
372
    return _ranges[index];
 
373
  }
 
374
  
 
375
  /// Return a range that surrounds *all* added ranges. This is used mainly
 
376
  /// for compatibilty issues. 
 
377
  RangeType getFullArea() const {
 
378
    RangeType range;
 
379
    
 
380
    range.setNull();
 
381
    
 
382
    int rcount = _ranges.size();
 
383
    
 
384
    for (int rno=0; rno<rcount; rno++) 
 
385
      range.expandTo(_ranges[rno]);
 
386
    
 
387
    return range;   
 
388
  }
 
389
  
 
390
  
 
391
  /// Returns true if any of the ranges contains the point
 
392
  bool contains(T x, T y) const {
 
393
  
 
394
    finalize();
 
395
  
 
396
    for (unsigned rno=0, rcount=_ranges.size(); rno<rcount; rno++) 
 
397
    if (_ranges[rno].contains(x,y))
 
398
      return true;
 
399
      
 
400
    return false;
 
401
  
 
402
  }
 
403
 
 
404
  /// Returns true if any of the ranges contains the range
 
405
  //
 
406
  /// Note that a NULL range is not contained in any range and
 
407
  /// a WORLD range is onluy contained in another WORLD range.
 
408
  ///
 
409
  bool contains(const RangeType& r) const {
 
410
  
 
411
    finalize();
 
412
  
 
413
    for (unsigned rno=0, rcount=_ranges.size(); rno<rcount; rno++) 
 
414
    if (_ranges[rno].contains(r))
 
415
      return true;
 
416
      
 
417
    return false;
 
418
  
 
419
  }
 
420
 
 
421
  /// Returns true if any of the ranges intersect the given range
 
422
  //
 
423
  /// Note that a NULL range doesn't intersect anything
 
424
  /// and a WORLD range intersects everything except a NULL Range.
 
425
  ///
 
426
  bool intersects(const RangeType& r) const {
 
427
  
 
428
    finalize();
 
429
  
 
430
    for (unsigned rno=0, rcount=_ranges.size(); rno<rcount; rno++) 
 
431
    if (_ranges[rno].intersects(r))
 
432
      return true;
 
433
      
 
434
    return false;
 
435
  
 
436
  }
 
437
 
 
438
  /// \brief
 
439
  /// Returns true if all ranges in the given SnappingRanges2d 
 
440
  /// are contained in at least one of the ranges composing this
 
441
  /// one.
 
442
  ///
 
443
  /// Note that a NULL range is not contained in any range and
 
444
  /// a WORLD range is onluy contained in another WORLD range.
 
445
  ///
 
446
  bool contains(const SnappingRanges2d<T>& o) const
 
447
  {
 
448
  
 
449
    finalize();
 
450
    // o.finalize(); // should I finalize the other range too ?
 
451
 
 
452
    // Null range set doesn't contain and isn't contained by anything
 
453
    if ( isNull() ) return false;
 
454
    if ( o.isNull() ) return false;
 
455
 
 
456
    // World range contains everything (except null ranges)
 
457
    if ( isWorld() ) return true;
 
458
 
 
459
    // This snappingrange is neither NULL nor WORLD
 
460
    // The other can still be WORLD, but in that case the
 
461
    // first iteration would return false
 
462
    //
 
463
    /// TODO: use a visitor !
 
464
    ///
 
465
    for (unsigned rno=0, rcount=o.size(); rno<rcount; rno++) 
 
466
    {
 
467
      RangeType r = o.getRange(rno);
 
468
      if ( ! contains(r) )
 
469
      {
 
470
        return false;
 
471
      }
 
472
    }
 
473
      
 
474
    return true;
 
475
  
 
476
  }
 
477
  
 
478
  
 
479
  /// Intersect this ranges list with the given ranges list,
 
480
  /// updating the current ranges list.
 
481
  /// Note this is currently a relatively expensive operation  
 
482
  /// for complex lists.
 
483
  ///
 
484
  void intersect(const SnappingRanges2d<T>& o) 
 
485
  {
 
486
    if (o.isNull()) {
 
487
      setNull();
 
488
      return;
 
489
    }
 
490
    
 
491
    if (o.isWorld()) return;
 
492
    
 
493
    // We create a new ranges set for each range in "o" and
 
494
    // then update ourselves with the *union* of these ranges.
 
495
    // Anybody knows a better method (in terms of efficieny) ?  
 
496
   
 
497
    std::vector< SnappingRanges2d<T> > list;
 
498
  
 
499
    //TODO: use a visitor !
 
500
    for (unsigned rno=0, rcount=o.size(); rno<rcount; rno++) {
 
501
      
 
502
      // add a copy of ourselves to the list
 
503
      list.push_back(*this);
 
504
      
 
505
      // intersect that copy with the single range
 
506
      list.back().intersect(o.getRange(rno));
 
507
      
 
508
    } 
 
509
    
 
510
    // update ourselves with the union of the "list"
 
511
    setNull();
 
512
    for (unsigned lno=0, lcount=list.size(); lno<lcount; lno++) 
 
513
      add(list.at(lno));
 
514
              
 
515
  }
 
516
  
 
517
  
 
518
  /// Intersects this ranges list with the given single range,
 
519
  /// updating the current ranges list.
 
520
  void intersect(const RangeType& r) 
 
521
  {
 
522
  
 
523
    finalize();
 
524
 
 
525
    if (isWorld()) {      // world intersection with X = X
 
526
      setNull();  
 
527
      add(r);
 
528
      return;
 
529
    }
 
530
    
 
531
    if (isNull()) return; // NULL will always remain NULL
 
532
    
 
533
    if (r.isNull()) {     // X intersection with NULL = NULL
 
534
      setNull();
 
535
      return;
 
536
    }
 
537
    
 
538
    if (r.isWorld()) return;  // X intersection with WORLD = X
 
539
    
 
540
    
 
541
    // TODO: use a vector (remember to walk in reverse dir.)
 
542
    for (int rno=_ranges.size()-1; rno>=0; rno--) {   
 
543
    
 
544
      RangeType newrange = Intersection(_ranges[rno], r);
 
545
      
 
546
      if (newrange.isNull())
 
547
        _ranges.erase(_ranges.begin() + rno);
 
548
      else       
 
549
        _ranges[rno] = newrange;
 
550
    }
 
551
  }
 
552
  
 
553
  
 
554
  /// Visit the current Ranges set
 
555
  //
 
556
  /// Visitor functor will be invoked
 
557
  /// for each RangeType in the current set.
 
558
  /// 
 
559
  /// The visitor functor will 
 
560
  /// receive a RangeType reference; must return true if
 
561
  /// it wants next item or false to exit the loop.
 
562
  ///
 
563
  template <class V>
 
564
  inline void visit(V& visitor) const
 
565
  {
 
566
    for (typename RangeList::const_iterator
 
567
      it = _ranges.begin(), itEnd = _ranges.end();
 
568
      it != itEnd;
 
569
      ++it)
 
570
    {
 
571
      if ( ! visitor(*it) )
 
572
      {
 
573
        break;
 
574
      }
 
575
    }
 
576
  }
 
577
 
 
578
  /// Visit the current Ranges set
 
579
  //
 
580
  /// Visitor functor will be invoked inconditionally
 
581
  /// for each RangeType in the current set.
 
582
  /// 
 
583
  /// The visitor functor will receive a RangeType reference.
 
584
  ///
 
585
  template <class V>
 
586
  inline void visitAll(V& visitor) const
 
587
  {
 
588
    for (typename RangeList::const_iterator
 
589
      it = _ranges.begin(), itEnd = _ranges.end();
 
590
      it != itEnd;
 
591
      ++it)
 
592
    {
 
593
      visitor(*it);
 
594
    }
 
595
  }
 
596
  
 
597
private:
 
598
 
 
599
  // Unused...
 
600
  inline T absmin(T a, T b) {
 
601
    if (b<0) b*=-1;
 
602
    return std::min<T>(a,b);
 
603
  }
 
604
  
 
605
  void finalize() const {
 
606
    if (_combine_counter > 0) {
 
607
      SnappingRanges2d<T>* me_nonconst = const_cast< SnappingRanges2d<T>* > (this); 
 
608
      me_nonconst->combine_ranges();
 
609
    }
 
610
  } 
 
611
  
 
612
    
 
613
  // The current Ranges list
 
614
  RangeList _ranges;
 
615
 
 
616
  /// snapping factor - see setSnapFactor() 
 
617
  float snap_factor;
 
618
  
 
619
  /// if set, only a single, outer range is maintained (extended). 
 
620
  bool single_mode;
 
621
  
 
622
  /// maximum number of ranges allowed
 
623
  unsigned ranges_limit;   
 
624
  
 
625
  unsigned int _combine_counter;
 
626
    
 
627
}; //class SnappingRanges2d
 
628
 
 
629
template <class T>
 
630
std::ostream& operator<< (std::ostream& os, const SnappingRanges2d<T>& r)
 
631
{
 
632
  if ( r.isNull() ) return os << "NULL";
 
633
  if ( r.isWorld() ) return os << "WORLD";
 
634
 
 
635
  for (typename SnappingRanges2d<T>::RangeList::const_iterator
 
636
    it = r._ranges.begin(), itEnd = r._ranges.end();
 
637
    it != itEnd; ++it)
 
638
  {
 
639
    if ( it != r._ranges.begin() ) os << ", ";
 
640
    os << *it;
 
641
  }
 
642
  return os;
 
643
}
 
644
 
 
645
} //namespace gnash.geometry
 
646
 
 
647
/// Standard snapping 2d ranges type for invalidated bounds calculation  
 
648
typedef geometry::SnappingRanges2d<float> InvalidatedRanges;
 
649
 
 
650
 
 
651
} //namespace gnash
 
652
 
 
653
#endif