[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

gEDA-cvs: pcb.git: branch: master updated (83c2866494fa9d9ad39e68b290bb74ac76333b6f)



The branch, master has been updated
       via  83c2866494fa9d9ad39e68b290bb74ac76333b6f (commit)
       via  abde5a811c4fec02f1a9f0109bc73a06d69398e6 (commit)
       via  daa542d3e1286ac390a034fe0c8d455c402a62c1 (commit)
       via  9045d1b2ab5916ad9c1a3ac58eacf19e47dca201 (commit)
       via  5b59be1fe0f9e3c489368840ba415902146715d4 (commit)
       via  4c05b67ed980813f0e9397b285f6687568e032fa (commit)
       via  1507957219673fad9ba2ea52f64964ed9b036337 (commit)
       via  e94479d7210870e7c52a95b5becfc1244dd7fdd3 (commit)
       via  264989905adddfadc4875d37be4331c6d0e18f4f (commit)
       via  4aed6d529217fcde9078026f100237b39249f390 (commit)
       via  193adfc2ca0d6365d4fa881c3870b88a1509d98b (commit)
       via  2d553c21045125dafb33137ae21adf4d5efc9314 (commit)
       via  8b162eca5ba77e4b9f06436a9fa7f9311532a61d (commit)
       via  2e09009091271e4efa7a3496a637e79427d714ac (commit)
       via  911388136478f1a12eb0cd7338ce165a8c12fc88 (commit)
       via  7bb66d19ddb72f6f17eb1295d6723d00729a71c8 (commit)
       via  06a432e7d509472c95fa0287de2c7d3f33c3933c (commit)
       via  eee43264a941ef1084a8888ec31325d6a37bae6c (commit)
       via  fe8e6a53ff8a0028360888f7927108ca7ffa498b (commit)
       via  880d3643711b332899e36fe7b3b9c0eeae3bc4af (commit)
       via  a76a26a2362b1a6ad5a8d8841d942f483bb16f20 (commit)
       via  802d52c2c9ad48781f1e6662cacb60fe20f64157 (commit)
       via  5118760e196039dad5eded4c1624254660963c9c (commit)
       via  1ad90700d1900a90c4537bb51889c3979dd47c9e (commit)
       via  2ffaef15bdf630c0c10db23c17d6ce3cb1b157fe (commit)
       via  fa86f244887fca50ad7487b377fecf64b0c44bb1 (commit)
       via  701effca7fe31d6ab3a778e8cac6f9d39b35f06f (commit)
       via  60aa80d5720b54939f37a225eba66aed1a483ec2 (commit)
       via  454639bf87001fd157269185fad73c3faf00196b (commit)
       via  b846ecafd19c062bc9e85a8d425c024d49fe32cc (commit)
       via  0296d3e1d08407747605103f0b99dcbeb168a331 (commit)
       via  0366b21ab674253f0567013bfe618429f028e3df (commit)
       via  fd1833e21b0b93851dce69218160d2d22a0cc97e (commit)
       via  efed4d20f64ddf37ad80e563ddb9710b2eef8535 (commit)
       via  275346d1b0a54347bd52ec364982a133f161700e (commit)
       via  c1ecaf676017a12d1d7c278af53d600a2c9f8e1b (commit)
       via  1b63d27b652009e7a6581c869fc021e73013ab2a (commit)
       via  09ed7763b9805678da73dd81a8c7f79d370741c7 (commit)
       via  56567acb4aa14cc324809c83f4dce6b0ae4cf944 (commit)
       via  44d00a5bee19f5b438524f7d1a7d71740f27368e (commit)
       via  b55ae28e513f02657aaa6196e3d44d96a2c4759c (commit)
       via  91849e58d99465bb9ec916f6594ae89ff90219ed (commit)
       via  d4fd0a435f87c637e902787bd274a8e624a2b204 (commit)
       via  a34d7e1b87354c65e3d13dcf8225c1b1e02efa68 (commit)
       via  ed7c2aa282fff2306d3a5451934bbb9402e4836c (commit)
       via  83c0c7d5eec7431e854592d0d14a0eb0b3dbc456 (commit)
       via  7c6ae5c49c59275e712efa453688c140f741fb3c (commit)
      from  04d8ae5526d9d2660572972d0cbeaf0ec53a8878 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.


=========
 Summary
=========

 configure.ac                            |   60 ++-
 configure.ac.system                     |  164 ++++
 globalconst.h                           |    2 +
 po/POTFILES.in                          |    2 +
 src/Makefile.am                         |   49 +-
 src/action.c                            |  141 ++--
 src/action.h                            |    2 +-
 src/autoroute.c                         |   57 +-
 src/buffer.c                            |  194 +++--
 src/cairo/cairo-bentley-ottmann.c       | 1569 ++++++++++++++++++++++++++++++
 src/cairo/cairo-combsort-private.h      |   71 ++
 src/cairo/cairo-compiler-private.h      |  203 ++++
 src/cairo/cairo-fixed-private.h         |  290 ++++++
 src/cairo/cairo-fixed-type-private.h    |   75 ++
 src/cairo/cairo-freelist-private.h      |  150 +++
 src/cairo/cairo-freelist.c              |  176 ++++
 src/cairo/cairo-malloc-private.h        |  148 +++
 src/cairo/cairo-minimal.h               |  208 ++++
 src/cairo/cairo-traps-private.h         |  152 +++
 src/cairo/cairo-traps.c                 |  438 +++++++++
 src/cairo/cairo-types-private.h         |  206 ++++
 src/cairo/cairo-wideint-private.h       |  329 +++++++
 src/cairo/cairo-wideint-type-private.h  |  153 +++
 src/cairo/cairo-wideint.c               |  819 ++++++++++++++++
 src/cairo/cairoint-minimal.h            |  146 +++
 src/change.c                            |  263 +++--
 src/change.h                            |    2 +-
 src/const.h                             |   14 +-
 src/copy.c                              |   53 +-
 src/copy.h                              |    4 +-
 src/create.c                            |   77 +-
 src/create.h                            |    9 +-
 src/crosshair.c                         |  333 +++++--
 src/draw.c                              |  224 ++++-
 src/draw.h                              |   15 +
 src/file.c                              |   17 +-
 src/find.c                              |  273 +++++--
 src/find.h                              |    3 +-
 src/flags.c                             |    5 +-
 src/global.h                            |   73 +-
 src/gpcb-menu.res                       |    4 +-
 src/hid.h                               |    1 +
 src/hid/common/hidgl.c                  |  796 ++++++++++++++++
 src/hid/common/hidgl.h                  |   85 ++
 src/hid/common/trackball.c              |  324 +++++++
 src/hid/common/trackball.h              |   78 ++
 src/hid/gcode/gcode.c                   |    2 +-
 src/hid/gerber/gerber.c                 |    5 +-
 src/hid/gtk/gtkhid-gl.c                 |  570 +++++++++++
 src/hid/gtk/gtkhid-main.c               |  168 ++--
 src/hid/gtk/gui-drc-window.c            |   20 +-
 src/hid/gtk/gui-icons-mode-buttons.data |    4 +-
 src/hid/gtk/gui-misc.c                  |    4 +-
 src/hid/gtk/gui-output-events.c         | 1448 ++++++++++++++++++++++++++--
 src/hid/gtk/gui-pinout-preview.c        |  100 ++-
 src/hid/gtk/gui-render-pixmap.c         |   76 ++-
 src/hid/gtk/gui-top-window.c            |   63 ++-
 src/hid/gtk/gui-trackball.c             |  423 ++++++++
 src/hid/gtk/gui-trackball.h             |   71 ++
 src/hid/gtk/gui.h                       |   41 +-
 src/hid/gtk/snavi.c                     |  187 ++++
 src/hid/gtk/snavi.h                     |    6 +
 src/hid/nelma/nelma.c                   |    6 +-
 src/hid/png/png.c                       |    6 +-
 src/hid/ps/eps.c                        |    6 +-
 src/hid/ps/ps.c                         |    6 +-
 src/insert.c                            |   50 +-
 src/insert.h                            |    2 +-
 src/macro.h                             |   37 +-
 src/mirror.c                            |    7 +-
 src/misc.c                              |   68 +-
 src/misc.h                              |    1 +
 src/move.c                              |  175 ++--
 src/move.h                              |    7 +-
 src/mymem.c                             |  147 +++-
 src/mymem.h                             |   10 +-
 src/parse_y.y                           |   39 +-
 src/pcb-menu.res                        |    4 +-
 src/polyarea.h                          |    1 +
 src/polygon.c                           | 1006 +++++---------------
 src/polygon.h                           |   23 +-
 src/polygon1.c                          | 1122 ++++++++++++++++++----
 src/pour.c                              | 1590 +++++++++++++++++++++++++++++++
 src/{mirror.h => pour.h}                |   37 +-
 src/puller.c                            |   16 +-
 src/rats.c                              |   30 +-
 src/remove.c                            |  187 ++--
 src/remove.h                            |    4 +-
 src/report.c                            |   35 +-
 src/report.h                            |    4 +-
 src/rotate.c                            |   28 +-
 src/rotate.h                            |    2 +-
 src/search.c                            |  176 +++-
 src/search.h                            |    6 +
 src/select.c                            |  107 ++-
 src/select.h                            |    2 +-
 src/set.c                               |    6 +-
 src/strflags.c                          |    4 +-
 src/sweep.h                             |    4 +
 src/undo.c                              |  119 ++--
 src/undo.h                              |    4 +-
 101 files changed, 14527 insertions(+), 2202 deletions(-)
 create mode 100644 configure.ac.system
 create mode 100644 src/cairo/cairo-bentley-ottmann.c
 create mode 100644 src/cairo/cairo-combsort-private.h
 create mode 100644 src/cairo/cairo-compiler-private.h
 create mode 100644 src/cairo/cairo-fixed-private.h
 create mode 100644 src/cairo/cairo-fixed-type-private.h
 create mode 100644 src/cairo/cairo-freelist-private.h
 create mode 100644 src/cairo/cairo-freelist.c
 create mode 100644 src/cairo/cairo-malloc-private.h
 create mode 100644 src/cairo/cairo-minimal.h
 create mode 100644 src/cairo/cairo-traps-private.h
 create mode 100644 src/cairo/cairo-traps.c
 create mode 100644 src/cairo/cairo-types-private.h
 create mode 100644 src/cairo/cairo-wideint-private.h
 create mode 100644 src/cairo/cairo-wideint-type-private.h
 create mode 100644 src/cairo/cairo-wideint.c
 create mode 100644 src/cairo/cairoint-minimal.h
 create mode 100644 src/hid/common/hidgl.c
 create mode 100644 src/hid/common/hidgl.h
 create mode 100644 src/hid/common/trackball.c
 create mode 100644 src/hid/common/trackball.h
 create mode 100644 src/hid/gtk/gtkhid-gl.c
 create mode 100644 src/hid/gtk/gui-trackball.c
 create mode 100644 src/hid/gtk/gui-trackball.h
 create mode 100644 src/hid/gtk/snavi.c
 create mode 100644 src/hid/gtk/snavi.h
 create mode 100644 src/pour.c
 copy src/{mirror.h => pour.h} (53%)
 create mode 100644 src/sweep.h


=================
 Commit Messages
=================

commit 83c2866494fa9d9ad39e68b290bb74ac76333b6f
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    Attempt to debug islandness after inserting hole bug

:100644 100644 6121665... 2f306f8... M	src/action.c

commit abde5a811c4fec02f1a9f0109bc73a06d69398e6
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    Use r-trees to find and remove touched polygons

:100644 100644 5e66d98... d4590d0... M	src/pour.c

commit daa542d3e1286ac390a034fe0c8d455c402a62c1
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    Island removal fixes
    
    Kept separate for now because they might have unknown side-effects.

:100644 100644 ece6fb7... 79b25a7... M	src/buffer.c
:100644 100644 a6d0ecf... ab59413... M	src/change.c
:100644 100644 ada4878... 65caaca... M	src/misc.c
:100644 100644 640955e... 64858f0... M	src/move.c
:100644 100644 1d0558c... 5e66d98... M	src/pour.c
:100644 100644 229e705... 406e025... M	src/rotate.c

commit 9045d1b2ab5916ad9c1a3ac58eacf19e47dca201
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    Off to find burried treasure on polygon island
    
    Add feature to remove islanded areas
    
    Known bugs:
    
    When dragging a via with a "solid" style thermal, a polygon piece
    will not (always?) be un-flagged as an island. The same via as part
    of a selection will re-create the polygon.

:100644 100644 3733071... a6d0ecf... M	src/change.c
:100644 100644 bcc1300... c800f8b... M	src/draw.c
:100644 100644 d8a955f... af9103c... M	src/find.c
:100644 100644 f93fca1... 0e0e1c9... M	src/find.h
:100644 100644 bf9670e... 640955e... M	src/move.c
:100644 100644 d45a690... 1d0558c... M	src/pour.c
:100644 100644 4711da7... c2b1385... M	src/pour.h
:100644 100644 200cc89... bb20f05... M	src/search.c

commit 5b59be1fe0f9e3c489368840ba415902146715d4
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    Add magic flag to stop pour clipping for off-screen buffers

:100644 100644 68f2f19... 3d879ff... M	src/create.c
:100644 100644 3d5f28f... 20f6cf1... M	src/global.h
:100644 100644 48a1525... d45a690... M	src/pour.c

commit 4c05b67ed980813f0e9397b285f6687568e032fa
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    Use the r_trees to avoid needing to check so many polygons all the time

:100644 100644 848edc9... d8a955f... M	src/find.c

commit 1507957219673fad9ba2ea52f64964ed9b036337
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    Fixup gtk hid drawing routines for pour support

:100644 100644 7f58605... efce5ec... M	src/hid/gtk/gui-output-events.c

commit e94479d7210870e7c52a95b5becfc1244dd7fdd3
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    Speed up initial clipping (pours version of what we had before)

:100644 100644 a3efa93... 48a1525... M	src/pour.c

commit 264989905adddfadc4875d37be4331c6d0e18f4f
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    Add support for a "poured" object.
    
    This takes half of the existing polygon functionality, and splits it
    such that the user defines a poured region (similar to drawing a polygon
    previously), and after clipping, this produces zero or more polygon
    objects which are drawn and connectivity checked with the existing
    polygon code.
    
    Selecting a "polygon" will cause the parent "pour" to be looked up, and
    all child polygons selected. Manipulations will always occur on the
    "pour", with "polygons" being updated after clipping.
    
    It remains to be seen whether "pour" will have its own file-format entry,
    or if it will take over the meaning of the existing "polygon" entry.

:100755 100755 cd6f4f9... 4ab3813... M	globalconst.h
:100644 100644 8db0918... 5faaf6d... M	po/POTFILES.in
:100644 100644 b709c27... 452e325... M	src/Makefile.am
:100644 100644 0a85391... 6121665... M	src/action.c
:100644 100644 ee116e8... 7529e8a... M	src/action.h
:100644 100644 3361f79... 9b90e61... M	src/autoroute.c
:100644 100644 b6d1e2b... ece6fb7... M	src/buffer.c
:100644 100644 0c55c69... 3733071... M	src/change.c
:100644 100644 7bae706... f0547b8... M	src/change.h
:100644 100644 676a6f0... 6d34ce8... M	src/const.h
:100644 100644 58ce9df... de5e92c... M	src/copy.c
:100644 100644 ac50e2c... 6a59832... M	src/copy.h
:100644 100644 b3d5bee... 68f2f19... M	src/create.c
:100644 100644 8086b1e... af7ace4... M	src/create.h
:100644 100644 ac22277... 90fcd66... M	src/crosshair.c
:100644 100644 a27c0dc... bcc1300... M	src/draw.c
:100644 100644 077c575... 5b4d73a... M	src/draw.h
:100644 100644 a61d53f... d44c3bb... M	src/file.c
:100644 100644 039bdfa... 848edc9... M	src/find.c
:100644 100644 5b04980... f93fca1... M	src/find.h
:100644 100644 60688dd... 95b72f6... M	src/flags.c
:100644 100644 bb78abc... 3d5f28f... M	src/global.h
:100644 100644 e92a59a... 01d2dab... M	src/gpcb-menu.res
:100644 100644 c3c2e4e... 86bac04... M	src/hid/gcode/gcode.c
:100644 100644 8a46c3c... e235349... M	src/hid/gerber/gerber.c
:100644 100644 e2fa201... 2726c07... M	src/hid/gtk/gui-drc-window.c
:100644 100644 be040f1... 432d47f... M	src/hid/gtk/gui-icons-mode-buttons.data
:100644 100644 a607a69... f36c400... M	src/hid/gtk/gui-misc.c
:100644 100644 37c2e48... 7f58605... M	src/hid/gtk/gui-output-events.c
:100644 100644 26f29b4... dbe0be5... M	src/hid/gtk/gui-top-window.c
:100644 100644 688adce... 885299b... M	src/hid/nelma/nelma.c
:100644 100644 0c292cd... 46bd92b... M	src/hid/png/png.c
:100644 100644 d67947d... 16e0718... M	src/hid/ps/eps.c
:100644 100644 2a7a4d7... 394f41b... M	src/hid/ps/ps.c
:100644 100644 5e62463... 19e61f2... M	src/insert.c
:100644 100644 350a0de... 67d1b78... M	src/insert.h
:100644 100644 819d202... f9200b0... M	src/macro.h
:100644 100644 7ef7d41... 1b76e88... M	src/mirror.c
:100644 100644 dfbb1d7... ada4878... M	src/misc.c
:100644 100644 d58e12e... b263efc... M	src/misc.h
:100644 100644 cd23253... bf9670e... M	src/move.c
:100644 100644 c4a844b... 9a65143... M	src/move.h
:100644 100644 bed0f9b... f3acc98... M	src/mymem.c
:100644 100644 81dff7a... bbd7897... M	src/mymem.h
:100644 100644 a5b2d23... 4d2b236... M	src/parse_y.y
:100644 100644 1166439... dcf8a8a... M	src/pcb-menu.res
:100644 100644 15b3534... ca36271... M	src/polygon.c
:100644 100644 5b3baf6... b8a3202... M	src/polygon.h
:100644 100644 4a761d5... 95c47bb... M	src/polygon1.c
:000000 100644 0000000... a3efa93... A	src/pour.c
:000000 100644 0000000... 4711da7... A	src/pour.h
:100644 100644 848d394... db123b1... M	src/puller.c
:100644 100644 29e9831... d986a26... M	src/rats.c
:100644 100644 98b9ade... d124284... M	src/remove.c
:100644 100644 9fd4625... 07e158b... M	src/remove.h
:100644 100644 dc01153... 306c8d9... M	src/report.c
:100644 100644 7abbb79... 39ce0ca... M	src/report.h
:100644 100644 9e19581... 229e705... M	src/rotate.c
:100644 100644 f032fcb... 8ad4f60... M	src/rotate.h
:100644 100644 c05a4b4... 200cc89... M	src/search.c
:100644 100644 add5661... 25d8103... M	src/search.h
:100644 100644 aa65f36... 9467931... M	src/select.c
:100644 100644 e24ab82... 36de895... M	src/select.h
:100644 100644 7a41f73... 4f2e591... M	src/set.c
:100644 100644 ac1fdcc... 26a2405... M	src/strflags.c
:100644 100644 68ea8ff... 2dacee3... M	src/undo.c
:100644 100644 0a4601f... b3c04d0... M	src/undo.h

commit 4aed6d529217fcde9078026f100237b39249f390
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    Workaround crash where contour is passed as NULL to poly_PreContour

:100644 100644 1a3d319... 15b3534... M	src/polygon.c

commit 193adfc2ca0d6365d4fa881c3870b88a1509d98b
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    Fix mesa crash on startup
    
    I'm not sure why it crashed, but it seems that providing a realize
    handler which fiddles with the GL context solves it. I've also
    removed a number of superfluous gtk_widget_realize() and an un-warraned
    gtk_widget_show_all()

:100644 100644 a3898cb... 26f29b4... M	src/hid/gtk/gui-top-window.c

commit 2d553c21045125dafb33137ae21adf4d5efc9314
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    Don't make GUI drawing calls to erase objects
    
    Changing the colour here is unnecessary (as drawing is deferred).
    Delete the gui->set_color() calls, and additionally, comment out
    all real-time drawing frmo the autorouter. This hasn't been ported
    to be compatible with the GL code, which requires specific setup
    and teardown around drawing.

:100644 100644 7fb7443... 3361f79... M	src/autoroute.c
:100644 100644 602b499... a27c0dc... M	src/draw.c

commit 8b162eca5ba77e4b9f06436a9fa7f9311532a61d
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    Debug GL calls out of context

:100644 100644 322e37d... 37c2e48... M	src/hid/gtk/gui-output-events.c

commit 2e09009091271e4efa7a3496a637e79427d714ac
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    Allow zero clearance pads and pins to touch polygons
    
    This was already supported for vias, lets be consistent.

:100644 100644 5546f1f... 0c55c69... M	src/change.c
:100644 100644 593be70... 039bdfa... M	src/find.c

commit 911388136478f1a12eb0cd7338ce165a8c12fc88
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    Board outline polygon generation
    
    FIXME: Make this work with the GL masking polygon drawing routines, rather
           than relying on the dicer.

:100644 100644 f6e7758... 322e37d... M	src/hid/gtk/gui-output-events.c
:100644 100644 eac9390... 1a3d319... M	src/polygon.c
:100644 100644 e29f67f... 5b3baf6... M	src/polygon.h

commit 7bb66d19ddb72f6f17eb1295d6723d00729a71c8
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    Fixup depth for layers and element marks

:100644 100644 89e21d0... 3b96103... M	src/hid/gtk/gtkhid-main.c
:100644 100644 7ebc25f... f6e7758... M	src/hid/gtk/gui-output-events.c

commit 06a432e7d509472c95fa0287de2c7d3f33c3933c
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    Layer fixes
    
    ** SHOULD MERGE SOME OF THIS COMMIT DOWN INTO OTHER PATCHES? **
    
    Fix mask display in 3D (Allow both side masks to display at once)
    Fix rendering depths for silk and mask layers

:100644 100644 6002b9a... 89e21d0... M	src/hid/gtk/gtkhid-main.c
:100644 100644 ae4bc48... 7ebc25f... M	src/hid/gtk/gui-output-events.c

commit eee43264a941ef1084a8888ec31325d6a37bae6c
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    Add routines to render just a single contour
    
    Use them rather than the GLU tessellator

:100644 100644 360aa83... 6931651... M	src/hid/common/hidgl.c

commit fe8e6a53ff8a0028360888f7927108ca7ffa498b
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    Remove unused intersection routines from cairo-bentley-ottman.c
    
    Our polygons are (supposed to be) free from intersections!

:100644 100644 778d69c... fcc0e66... M	src/cairo/cairo-bentley-ottmann.c

commit 880d3643711b332899e36fe7b3b9c0eeae3bc4af
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    Bentley-Ottann test implementation

:100644 100644 863e2ee... 7628e9d... M	configure.ac
:000000 100644 0000000... 3f6ab7e... A	configure.ac.system
:100644 100644 2ce0991... b709c27... M	src/Makefile.am
:000000 100644 0000000... 778d69c... A	src/cairo/cairo-bentley-ottmann.c
:000000 100644 0000000... ce31257... A	src/cairo/cairo-combsort-private.h
:000000 100644 0000000... 9fe8e9b... A	src/cairo/cairo-compiler-private.h
:000000 100644 0000000... e3add4a... A	src/cairo/cairo-fixed-private.h
:000000 100644 0000000... 730ed3e... A	src/cairo/cairo-fixed-type-private.h
:000000 100644 0000000... 5be22b1... A	src/cairo/cairo-freelist-private.h
:000000 100644 0000000... 6ea5c17... A	src/cairo/cairo-freelist.c
:000000 100644 0000000... d812058... A	src/cairo/cairo-malloc-private.h
:000000 100644 0000000... 9028299... A	src/cairo/cairo-minimal.h
:000000 100644 0000000... ac26aee... A	src/cairo/cairo-traps-private.h
:000000 100644 0000000... 089f3c6... A	src/cairo/cairo-traps.c
:000000 100644 0000000... 44c29b9... A	src/cairo/cairo-types-private.h
:000000 100644 0000000... 303dab1... A	src/cairo/cairo-wideint-private.h
:000000 100644 0000000... e18f48e... A	src/cairo/cairo-wideint-type-private.h
:000000 100644 0000000... 823ebca... A	src/cairo/cairo-wideint.c
:000000 100644 0000000... 4b6d20b... A	src/cairo/cairoint-minimal.h
:100644 100644 cb53763... 360aa83... M	src/hid/common/hidgl.c
:000000 100644 0000000... 257664f... A	src/sweep.h

commit a76a26a2362b1a6ad5a8d8841d942f483bb16f20
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    Play with display lists

:100644 100644 211e3e6... ae4bc48... M	src/hid/gtk/gui-output-events.c

commit 802d52c2c9ad48781f1e6662cacb60fe20f64157
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    Playing with stack rendering

:100644 100644 82dc295... 211e3e6... M	src/hid/gtk/gui-output-events.c

commit 5118760e196039dad5eded4c1624254660963c9c
Author: Bert Timmerman <bert.timmerman@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    From 22f4d1dd450f218172b8ee0edf9a2aaef6c20f2f Mon Sep 17 00:00:00 2001
    Subject: [PATCH] Additional defines for a 3D joystick for (older) linux versions which do not have these defines in <linux/input.h>

:100644 100644 6dd1b5f... 618be32... M	src/hid/gtk/snavi.c

commit 1ad90700d1900a90c4537bb51889c3979dd47c9e
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    Silly space navigator interface to allow funky views

:100644 100644 f21c807... 2ce0991... M	src/Makefile.am
:100644 100644 88cf644... 82dc295... M	src/hid/gtk/gui-output-events.c
:100644 100644 038ba6c... a3898cb... M	src/hid/gtk/gui-top-window.c
:100644 100644 26440bb... 33b8c81... M	src/hid/gtk/gui-trackball.c
:100644 100644 d6bd03c... 3af647e... M	src/hid/gtk/gui-trackball.h
:100644 100644 38f2148... af281b3... M	src/hid/gtk/gui.h
:000000 100644 0000000... 6dd1b5f... A	src/hid/gtk/snavi.c
:000000 100644 0000000... 9b5011c... A	src/hid/gtk/snavi.h

commit 2ffaef15bdf630c0c10db23c17d6ce3cb1b157fe
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    Major re-write to drawing routines

:100644 100644 c713965... 602b499... M	src/draw.c
:100644 100644 c0e23a3... 077c575... M	src/draw.h
:100644 100644 87daf19... 8705cd4... M	src/hid/gtk/gtkhid-gl.c
:100644 100644 7b01d27... 6002b9a... M	src/hid/gtk/gtkhid-main.c
:100644 100644 fabe334... 88cf644... M	src/hid/gtk/gui-output-events.c
:100644 100644 e676b43... 38f2148... M	src/hid/gtk/gui.h

commit fa86f244887fca50ad7487b377fecf64b0c44bb1
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    Fix grid extents in 3D view

:100644 100644 ae58cbb... 87daf19... M	src/hid/gtk/gtkhid-gl.c
:100644 100644 3295f23... fabe334... M	src/hid/gtk/gui-output-events.c
:100644 100644 dad9dea... e676b43... M	src/hid/gtk/gui.h

commit 701effca7fe31d6ab3a778e8cac6f9d39b35f06f
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    Shiny 3D eye-candy
    
    Experiments in progress - don't expect this to work yet!

:100644 100644 6b1e306... ae58cbb... M	src/hid/gtk/gtkhid-gl.c
:100644 100644 e2bc158... 7b01d27... M	src/hid/gtk/gtkhid-main.c
:100644 100644 1929d45... 3295f23... M	src/hid/gtk/gui-output-events.c

commit 60aa80d5720b54939f37a225eba66aed1a483ec2
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    Add support for depth to triangle rendering routines.
    
    Nasty global depth_state variable should be replaced!

:100644 100644 faf27c7... cb53763... M	src/hid/common/hidgl.c
:100644 100644 b956a65... aa2985e... M	src/hid/common/hidgl.h
:100644 100644 4693e5d... 1929d45... M	src/hid/gtk/gui-output-events.c

commit 454639bf87001fd157269185fad73c3faf00196b
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    Use trackball to allow rotation of 3D view

:100644 100644 db1fb31... 4693e5d... M	src/hid/gtk/gui-output-events.c
:100644 100644 8a4a11c... 89a3563... M	src/hid/gtk/gui-pinout-preview.c
:100644 100644 faa09fe... 15412ea... M	src/hid/gtk/gui-render-pixmap.c
:100644 100644 70f82a3... 038ba6c... M	src/hid/gtk/gui-top-window.c
:100644 100644 4dd32a3... dad9dea... M	src/hid/gtk/gui.h

commit b846ecafd19c062bc9e85a8d425c024d49fe32cc
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    Add virtual trackball code

:100644 100644 9ef4db5... 8db0918... M	po/POTFILES.in
:100644 100644 f66cca7... f21c807... M	src/Makefile.am
:000000 100644 0000000... c4b8501... A	src/hid/common/trackball.c
:000000 100644 0000000... ed0c267... A	src/hid/common/trackball.h
:000000 100644 0000000... 26440bb... A	src/hid/gtk/gui-trackball.c
:000000 100644 0000000... d6bd03c... A	src/hid/gtk/gui-trackball.h

commit 0296d3e1d08407747605103f0b99dcbeb168a331
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    Hack to make pretty translucent polygons in thindraw-poly mode
    
    TODO: Perhaps need some way to configure this.. it might be nice in
    non-thindraw mode too. If people want thin-draw to gain extra speed,
    rather than have it actually slower (due to fill + outline), then a
    way to turn it off would also be useful.

:100644 100644 fec839e... 6b1e306... M	src/hid/gtk/gtkhid-gl.c
:100644 100644 668da46... e2bc158... M	src/hid/gtk/gtkhid-main.c
:100644 100644 4342f3f... 4dd32a3... M	src/hid/gtk/gui.h

commit 0366b21ab674253f0567013bfe618429f028e3df
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    Use tags on circular contours to render them faster

:100644 100644 c2efdd4... faf27c7... M	src/hid/common/hidgl.c

commit fd1833e21b0b93851dce69218160d2d22a0cc97e
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    Work in progress on subcompositing / stencil buffers
    
    If we have many stencil buffer bits, we may as well use all of them before
    resorting to a costly clear and re-using the same bit-planes over.

:100644 100644 1bbbaa1... c713965... M	src/draw.c
:100644 100644 dd34b8e... 073dbae... M	src/hid.h
:100644 100644 4594c63... c2efdd4... M	src/hid/common/hidgl.c
:100644 100644 bb1383c... b956a65... M	src/hid/common/hidgl.h
:100644 100644 fa908ce... 8a46c3c... M	src/hid/gerber/gerber.c
:100644 100644 430059b... fec839e... M	src/hid/gtk/gtkhid-gl.c
:100644 100644 aae34fc... 668da46... M	src/hid/gtk/gtkhid-main.c
:100644 100644 76de7af... db1fb31... M	src/hid/gtk/gui-output-events.c
:100644 100644 b9d57da... 8a4a11c... M	src/hid/gtk/gui-pinout-preview.c
:100644 100644 4caddf2... faa09fe... M	src/hid/gtk/gui-render-pixmap.c
:100644 100644 197e886... 70f82a3... M	src/hid/gtk/gui-top-window.c
:100644 100644 68d7d5b... 688adce... M	src/hid/nelma/nelma.c
:100644 100644 d5d6617... 0c292cd... M	src/hid/png/png.c
:100644 100644 0c9345b... d67947d... M	src/hid/ps/eps.c
:100644 100644 7b42b5f... 2a7a4d7... M	src/hid/ps/ps.c

commit efed4d20f64ddf37ad80e563ddb9710b2eef8535
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    Add raw polygons support for the GTK HID, bypassing the no-holes dicer
    
    Uses the OpenGL stencil buffer to make drawing polygons with holes faster.
    
    1. Turn Stenciling on, updates to colour buffer off
    2. Clear stencil buffer to 0
    3. Paint polygon holes, setting those areas of the stencil buffer to 1
    4. Switch on stencil test (== 0), turn on updates to colour buffer
    5. Paint outer polygon through areas of the stencil buffer still 0
    6. Clear stencil buffer, switch off stencilling.
    
    ** BUGS? **
    
    Probably throws up if the function is used whilst drawing the mask,
    since that uses stenciling as well, and they don't know to co-operate.
    
    For now, we don't use polygons on the mask, so its not a a problem (?).
    (OR do we.. for some pins?)

:100644 100644 b0a5049... 4594c63... M	src/hid/common/hidgl.c
:100644 100644 73d9a34... bb1383c... M	src/hid/common/hidgl.h
:100644 100644 3e41c35... 430059b... M	src/hid/gtk/gtkhid-gl.c
:100644 100644 31fa88a... aae34fc... M	src/hid/gtk/gtkhid-main.c
:100644 100644 2ebed06... 4342f3f... M	src/hid/gtk/gui.h

commit 275346d1b0a54347bd52ec364982a133f161700e
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    Cure crosshair lagging on screen
    
    FIXME: SHOULD NOT RE-WRITE THE GTK HID

:100644 100644 4942fc0... 76de7af... M	src/hid/gtk/gui-output-events.c

commit c1ecaf676017a12d1d7c278af53d600a2c9f8e1b
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    Drop in PCB+GL code + various mess. Needs splitting up?
    
    Credits:
    
      Algorithm to calculate number of segments to use in circular
      curve approximation suggested by DJ Delorie.
    
    FIXME: SHOULD NOT RE-WRITE THE GTK HID!

:100644 100644 e719268... f66cca7... M	src/Makefile.am
:100644 100644 d54fad7... ac22277... M	src/crosshair.c
:000000 100644 0000000... b0a5049... A	src/hid/common/hidgl.c
:000000 100644 0000000... 73d9a34... A	src/hid/common/hidgl.h
:000000 100644 0000000... 3e41c35... A	src/hid/gtk/gtkhid-gl.c
:100644 100644 8c3ff67... 31fa88a... M	src/hid/gtk/gtkhid-main.c
:100644 100644 7230aa3... 4942fc0... M	src/hid/gtk/gui-output-events.c
:100644 100644 212d37a... b9d57da... M	src/hid/gtk/gui-pinout-preview.c
:100644 100644 b24e6c9... 4caddf2... M	src/hid/gtk/gui-render-pixmap.c
:100644 100644 3d3896f... 197e886... M	src/hid/gtk/gui-top-window.c
:100644 100644 0a2e747... 2ebed06... M	src/hid/gtk/gui.h

commit 1b63d27b652009e7a6581c869fc021e73013ab2a
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    Make --enable-gl default when building the GTK HID

:100644 100644 964e235... 863e2ee... M	configure.ac

commit 09ed7763b9805678da73dd81a8c7f79d370741c7
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    Add configure checks for GtkGLEext, add to CFLAGS and LIBS
    
    *** TODO: Need separate tests for libgl and libglut etc.. ***

:100644 100644 a220a82... 964e235... M	configure.ac

commit 56567acb4aa14cc324809c83f4dce6b0ae4cf944
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    Only snap to pads on the active layer

:100644 100644 923ab72... d54fad7... M	src/crosshair.c

commit 44d00a5bee19f5b438524f7d1a7d71740f27368e
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    Improve grid snapping heuristics

:100644 100644 b9a3dd2... 923ab72... M	src/crosshair.c
:100644 100644 3f23ff4... c05a4b4... M	src/search.c
:100644 100644 ae71967... add5661... M	src/search.h

commit b55ae28e513f02657aaa6196e3d44d96a2c4759c
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    Avoid re-starting the intersection routine when we don't have to
    
    Apparently this has a nice performance win for the NoHoles dicer.

:100644 100644 1a194b3... 4a761d5... M	src/polygon1.c

commit 91849e58d99465bb9ec916f6594ae89ff90219ed
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    We can just delete kicked out holes
    
    Since we don't keep holes from broken contours, if a contour is
    kicked out, we know it is destined for the bin.

:100644 100644 1127fbd... 1a194b3... M	src/polygon1.c

commit d4fd0a435f87c637e902787bd274a8e624a2b204
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    Various speedups to the polygon code.
    
    Attempt to fix polygon slowness by avoiding the need to create a
    completely new polygon for each boolean operation. This mostly relies
    upon r-tree searches to find contours to operate on - rather than
    searching each in turn.
    
    We avoid labelling all of the "A" polygon's contours, use the contour
    r-trees to dynamically search the required data.
    
    Added code to reparent holes which end up in the wrong polygon piece
    after inserting a new hole in InsertHoles. This means we don't have
    to dump every potental hole we encounter in the holes insersion queue,
    hopefully leading to better dynamic update performance.
    
    At this point, polygon performance has finally seen a net gain.
    
    HOWEVER: Due to differences in the order of polygon operations, the
             data-structures resulting from a boolean polygon operation
             may be sorted differently.
    
             In certain contrived cases, where a polygon is clipped into
             identically sized pieces, the resulting piece of polygon
             which PCB will keep and use on the board is different after
             this commit.

:100644 100644 a0be8e6... 1127fbd... M	src/polygon1.c

commit a34d7e1b87354c65e3d13dcf8225c1b1e02efa68
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    Use heap structure to insert holes quicker in InsertHoles()

:100644 100644 2799a67... a0be8e6... M	src/polygon1.c

commit ed7c2aa282fff2306d3a5451934bbb9402e4836c
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    Optimise polygon operations by keeping an rtree of POLYAREA contours
    
    Attempt to speed up the intersect() routine using this rtree rather
    than generating a new one at each call.
    
    Due to the increased overheads of keeping an r-tree up to date, there
    is a significant overall slow-down at this point in the patch series.

:100644 100644 958498b... ce427ad... M	src/polyarea.h
:100644 100644 474474e... eac9390... M	src/polygon.c
:100644 100644 d2c0798... 2799a67... M	src/polygon1.c

commit 83c0c7d5eec7431e854592d0d14a0eb0b3dbc456
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    Use rtree of countours when computing an intersection
    
    NOTE: This is more complex than the existing code, and on its own,
          actually slows things down a little.
    
          The intention is that the r-tree should be maintained continually,
          so it doesn't need to be recreated with each call to intersect().

:100644 100644 ec3db7e... 474474e... M	src/polygon.c
:100644 100644 329058e... d2c0798... M	src/polygon1.c

commit 7c6ae5c49c59275e712efa453688c140f741fb3c
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    polygon.c: Accumulate vias and lines into batches before subtracting them
    
    Accumulate polygons to clear from lines and pins in batches, then
    clear from the polygon. Not quite sure why, but this _really_ seems to
    speed up loading very complex boards. (e.g. 50sec -> 10sec for one example).
    
    Possibly this is because withing the assembled batches, it is cheaper to
    produce a more unified contour (touching lines), and the complex contours
    of the main polygon are broken less frequently.
    
    It isn't quite clear why this helps so much for pins / vias (which won't
    usually touch each-other), however it changes a 50sec load time to 10 sec.
    This could perhaps be because any contours which are smashed by clearance
    of closely spaced vias / pins now only incurr the penalty of breaking the
    main contour once every batch (100 vias / pins).
    
    Batch sizes (20 for lines, 100 for pins / vias) aren't necessarily optimal!
    
    
    Also, clear pins and vias last...
    
    There is a chance these objects are simpler, and just end up as holes in
    the main polygon, rather than causing a contour intersection. This means
    it is cheaper to add them last.
    
    If we add them first, and make the polygon complex, objects (usually
    lines) which pierce the polygon's outer contour cause all the holes to
    be removed and queued for re-insersion after the new contour is
    constructed.

:100644 100644 f2745ed... ec3db7e... M	src/polygon.c

=========
 Changes
=========

commit 83c2866494fa9d9ad39e68b290bb74ac76333b6f
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    Attempt to debug islandness after inserting hole bug

diff --git a/src/action.c b/src/action.c
index 6121665..2f306f8 100644
--- a/src/action.c
+++ b/src/action.c
@@ -1507,12 +1507,19 @@ NotifyMode (void)
 		   */
 		  SaveUndoSerialNumber ();
 		  Flags = ((PolygonType *)Crosshair.AttachedObject.Ptr2)->Flags;
-		  PolyToPoursOnLayer (PCB->Data, Crosshair.AttachedObject.Ptr1,
-				      result, Flags);
+#warning FIXME: Removing a pour should force a re-check of islanding!
+                  /* For now, do this before PolyToPours() which re-inits the
+                   * clipping for the pour(s) affected (?). Ideally RemoveObject
+                   * should fix any island response its self. Anyway.. removing
+                   * the old thing first saves us doing twice the work by
+                   * recomputing islands when it gets deleted.
+                   */
 		  RemoveObject (POUR_TYPE,
 				Crosshair.AttachedObject.Ptr1,
 				Crosshair.AttachedObject.Ptr2,
 				Crosshair.AttachedObject.Ptr3);
+		  PolyToPoursOnLayer (PCB->Data, Crosshair.AttachedObject.Ptr1,
+				      result, Flags);
 		  RestoreUndoSerialNumber ();
 		  IncrementUndoSerialNumber ();
 		  Draw ();

commit abde5a811c4fec02f1a9f0109bc73a06d69398e6
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    Use r-trees to find and remove touched polygons

diff --git a/src/pour.c b/src/pour.c
index 5e66d98..d4590d0 100644
--- a/src/pour.c
+++ b/src/pour.c
@@ -787,12 +787,64 @@ mark_islands (DataTypePtr Data, LayerTypePtr layer, PourTypePtr pour,
                    check_polygon_island_cb, &info);
 }
 
+struct touched_info
+{
+  PourType *pour;
+  POLYAREA *pg, *np;
+  jmp_buf env;
+  PolygonType *polygon;
+};
+
+static int
+touched_children_callback (const BoxType * b, void *cl)
+{
+  struct touched_info *touched = (struct touched_info *) cl;
+  PolygonType *polygon = (PolygonType *) b;
+
+  /* Do we actually intersect? */
+  if (isects (touched->np, polygon, false))
+    {
+      /* Steal the clipped contours, the delete the polygon. */
+      /* Add contour to local list to fiddle about with */
+
+      assert (poly_Valid (polygon->Clipped));
+      if (polygon->Clipped == NULL)
+        {
+          printf ("Got polygon->clipped == NULL!\n");
+          return 0;
+        }
+      if (touched->pg == NULL)
+        {
+          touched->pg = polygon->Clipped;
+          polygon->Clipped = NULL;
+        }
+      else
+        {
+          /* Link the _single_ polygon->Clipped into our circular pg list. */
+          polygon->Clipped->f = touched->pg;
+          polygon->Clipped->b = touched->pg->b;
+          touched->pg->b->f = polygon->Clipped;
+          touched->pg->b = polygon->Clipped;
+          polygon->Clipped = NULL;
+        }
+
+      touched->polygon = polygon;
+
+      longjmp (touched->env, 1);
+    }
+
+  return 0;
+}
+
+
 static int
 subtract_plow (DataTypePtr Data, LayerTypePtr layer, PourTypePtr pour,
               int type, void *ptr1, void *ptr2)
 {
   POLYAREA *np = NULL, *pg = NULL, *start_pg, *tmp;
-  int count, count_all, count_added;
+  BoxType box;
+  int count_all, count_added;
+  struct touched_info touched;
 
   switch (type)
     {
@@ -832,43 +884,44 @@ subtract_plow (DataTypePtr Data, LayerTypePtr layer, PourTypePtr pour,
 
   /* Make pg contain the polygons we're going to fiddle with */
 
-  count = 0;
-  POURPOLYGON_LOOP (pour);
-  {
-    /* Gather up children which are touched by np */
-    if (isects (np, polygon, false))
-      {
-        count++;
-        /* Steal their clipped contours, then delete them */
-        /* Add contour to local list to fiddle about with */
+  box.X1 = np->contours->xmin;
+  box.Y1 = np->contours->ymin;
+  box.X2 = np->contours->xmax;
+  box.Y2 = np->contours->ymax;
 
-        assert (poly_Valid (polygon->Clipped));
-        if (polygon->Clipped == NULL)
-          {
-            printf ("Got polygon->clipped == NULL!\n");
-            continue;
-          }
-        if (pg == NULL)
-          {
-            pg = polygon->Clipped;
-            polygon->Clipped = NULL;
-          }
-        else
-          {
-            /* Link the _single_ polygon->Clipped into our circular pg list. */
-            polygon->Clipped->f = pg;
-            polygon->Clipped->b = pg->b;
-            pg->b->f = polygon->Clipped;
-            pg->b = polygon->Clipped;
-            polygon->Clipped = NULL;
-          }
-        /* POURPOLYGON_LOOP iterates backwards, so it's OK
-         * to delete the current element we're sitting on */
-        DestroyPolygonInPour (pour, polygon);
-      }
-  }
-  END_LOOP;
-//  printf ("Subtract counted %i touching children, now removed\n", count);
+  tmp = np->f;
+  while (tmp != np)
+    {
+      MAKEMIN (box.X1, tmp->contours->xmin);
+      MAKEMIN (box.Y1, tmp->contours->ymin);
+      MAKEMAX (box.X2, tmp->contours->xmax);
+      MAKEMAX (box.Y2, tmp->contours->ymax);
+      tmp = tmp->f;
+    }
+
+  box.X1 -= UNSUBTRACT_BLOAT;
+  box.Y1 -= UNSUBTRACT_BLOAT;
+  box.X2 += UNSUBTRACT_BLOAT;
+  box.Y2 += UNSUBTRACT_BLOAT;
+
+  touched.pour = pour;
+  touched.np = np;
+  touched.pg = NULL;
+  touched.polygon = NULL;
+
+  /* This is a loop. Since we can't delete from an r_tree whilst we're
+   * searching it, we short-cut the search with a longjmp (returning 0),
+   * delete the polygon we found, then start searching again
+   */
+  setjmp (touched.env);
+
+  if (touched.polygon != NULL)
+    DestroyPolygonInPour (pour, touched.polygon);
+
+  r_search (pour->polygon_tree, &box, NULL, touched_children_callback, &touched);
+  /* Due to the setjmp / longjmp, we've just looped until the search is complete */
+
+  pg = touched.pg;
 
   if (pg == NULL)
     {
@@ -1068,7 +1121,9 @@ add_plow (DataTypePtr Data, LayerTypePtr layer, PourTypePtr pour,
 {
   POLYAREA *np = NULL, *pg = NULL, *tmp, *start_pg;
   POLYAREA *orig_poly;
-  int count, count_all, count_added;
+  BoxType box;
+  int count_all, count_added;
+  struct touched_info touched;
 
   switch (type)
     {
@@ -1119,43 +1174,44 @@ add_plow (DataTypePtr Data, LayerTypePtr layer, PourTypePtr pour,
 
   /* Make pg contain the polygons we're going to fiddle with */
 
-  count = 0;
-  POURPOLYGON_LOOP (pour);
-  {
-    /* Gather up children which are touched by np */
-    if (isects (np, polygon, false))
-      {
-        count++;
-        /* Steal their clipped contours, then delete them */
-        /* Add contour to local list to fiddle about with */
+  box.X1 = np->contours->xmin;
+  box.Y1 = np->contours->ymin;
+  box.X2 = np->contours->xmax;
+  box.Y2 = np->contours->ymax;
 
-        assert (poly_Valid (polygon->Clipped));
-        if (polygon->Clipped == NULL)
-          {
-            printf ("Got polygon->clipped == NULL!\n");
-            continue;
-          }
-        if (pg == NULL)
-          {
-            pg = polygon->Clipped;
-            polygon->Clipped = NULL;
-          }
-        else
-          {
-            /* Link the _single_ polygon->Clipped into our circular pg list. */
-            polygon->Clipped->f = pg;
-            polygon->Clipped->b = pg->b;
-            pg->b->f = polygon->Clipped;
-            pg->b = polygon->Clipped;
-            polygon->Clipped = NULL;
-          }
-        /* POURPOLYGON_LOOP iterates backwards, so it's OK
-         * to delete the current element we're sitting on */
-        DestroyPolygonInPour (pour, polygon);
-      }
-  }
-  END_LOOP;
-//  printf ("Unsubtract counted %i touching children, now removed\n", count);
+  tmp = np->f;
+  while (tmp != np)
+    {
+      MAKEMIN (box.X1, tmp->contours->xmin);
+      MAKEMIN (box.Y1, tmp->contours->ymin);
+      MAKEMAX (box.X2, tmp->contours->xmax);
+      MAKEMAX (box.Y2, tmp->contours->ymax);
+      tmp = tmp->f;
+    }
+
+  box.X1 -= UNSUBTRACT_BLOAT;
+  box.Y1 -= UNSUBTRACT_BLOAT;
+  box.X2 += UNSUBTRACT_BLOAT;
+  box.Y2 += UNSUBTRACT_BLOAT;
+
+  touched.pour = pour;
+  touched.np = np;
+  touched.pg = NULL;
+  touched.polygon = NULL;
+
+  /* This is a loop. Since we can't delete from an r_tree whilst we're
+   * searching it, we short-cut the search with a longjmp (returning 0),
+   * delete the polygon we found, then start searching again
+   */
+  setjmp (touched.env);
+
+  if (touched.polygon != NULL)
+    DestroyPolygonInPour (pour, touched.polygon);
+
+  r_search (pour->polygon_tree, &box, NULL, touched_children_callback, &touched);
+  /* Due to the setjmp / longjmp, we've just looped until the search is complete */
+
+  pg = touched.pg;
 
   if (pg == NULL)
     {

commit daa542d3e1286ac390a034fe0c8d455c402a62c1
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    Island removal fixes
    
    Kept separate for now because they might have unknown side-effects.

diff --git a/src/buffer.c b/src/buffer.c
index ece6fb7..79b25a7 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -249,8 +249,8 @@ MoveViaToBuffer (PinTypePtr Via)
 {
   PinTypePtr via;
 
-  RestoreToPours (Source, VIA_TYPE, Via, Via);
   r_delete_entry (Source->via_tree, (BoxType *) Via);
+  RestoreToPours (Source, VIA_TYPE, Via, Via);
   via = GetViaMemory (Dest);
   *via = *Via;
   CLEAR_FLAG (WARNFLAG | FOUNDFLAG, via);
@@ -302,8 +302,8 @@ MoveLineToBuffer (LayerTypePtr Layer, LineTypePtr Line)
   LayerTypePtr lay;
   LineTypePtr line;
 
-  RestoreToPours (Source, LINE_TYPE, Layer, Line);
   r_delete_entry (Layer->line_tree, (BoxTypePtr) Line);
+  RestoreToPours (Source, LINE_TYPE, Layer, Line);
   lay = &Dest->Layer[GetLayerNumber (Source, Layer)];
   line = GetLineMemory (lay);
   *line = *Line;
@@ -332,8 +332,8 @@ MoveArcToBuffer (LayerTypePtr Layer, ArcTypePtr Arc)
   LayerTypePtr lay;
   ArcTypePtr arc;
 
-  RestoreToPours (Source, ARC_TYPE, Layer, Arc);
   r_delete_entry (Layer->arc_tree, (BoxTypePtr) Arc);
+  RestoreToPours (Source, ARC_TYPE, Layer, Arc);
   lay = &Dest->Layer[GetLayerNumber (Source, Layer)];
   arc = GetArcMemory (lay);
   *arc = *Arc;
diff --git a/src/change.c b/src/change.c
index a6d0ecf..ab59413 100644
--- a/src/change.c
+++ b/src/change.c
@@ -492,10 +492,10 @@ ChangeViaClearSize (PinTypePtr Via)
     value = PCB->Bloat * 2 + 2;
   if (Via->Clearance == value)
     return NULL;
+  r_delete_entry (PCB->Data->via_tree, (BoxType *) Via);
   RestoreToPours (PCB->Data, VIA_TYPE, Via, Via);
   AddObjectToClearSizeUndoList (VIA_TYPE, Via, Via, Via);
   EraseVia (Via);
-  r_delete_entry (PCB->Data->via_tree, (BoxType *) Via);
   Via->Clearance = value;
   SetPinBoundingBox (Via);
   r_insert_entry (PCB->Data->via_tree, (BoxType *) Via, 0);
@@ -558,10 +558,10 @@ ChangePinClearSize (ElementTypePtr Element, PinTypePtr Pin)
     value = PCB->Bloat * 2 + 2;
   if (Pin->Clearance == value)
     return NULL;
+  r_delete_entry (PCB->Data->pin_tree, &Pin->BoundingBox);
   RestoreToPours (PCB->Data, PIN_TYPE, Element, Pin);
   AddObjectToClearSizeUndoList (PIN_TYPE, Element, Pin, Pin);
   ErasePin (Pin);
-  r_delete_entry (PCB->Data->pin_tree, &Pin->BoundingBox);
   Pin->Clearance = value;
   /* SetElementBB updates all associated rtrees */
   SetElementBoundingBox (PCB->Data, Element, &PCB->Font);
@@ -585,9 +585,9 @@ ChangePadSize (ElementTypePtr Element, PadTypePtr Pad)
     {
       AddObjectToSizeUndoList (PAD_TYPE, Element, Pad, Pad);
       AddObjectToMaskSizeUndoList (PAD_TYPE, Element, Pad, Pad);
+      r_delete_entry (PCB->Data->pad_tree, &Pad->BoundingBox);
       RestoreToPours (PCB->Data, PAD_TYPE, Element, Pad);
       ErasePad (Pad);
-      r_delete_entry (PCB->Data->pad_tree, &Pad->BoundingBox);
       Pad->Mask += value - Pad->Thickness;
       Pad->Thickness = value;
       /* SetElementBB updates all associated rtrees */
@@ -620,9 +620,9 @@ ChangePadClearSize (ElementTypePtr Element, PadTypePtr Pad)
   if (value == Pad->Clearance)
     return NULL;
   AddObjectToClearSizeUndoList (PAD_TYPE, Element, Pad, Pad);
+  r_delete_entry (PCB->Data->pad_tree, &Pad->BoundingBox);
   RestoreToPours (PCB->Data, PAD_TYPE, Element, Pad);
   ErasePad (Pad);
-  r_delete_entry (PCB->Data->pad_tree, &Pad->BoundingBox);
   Pad->Clearance = value;
   /* SetElementBB updates all associated rtrees */
   SetElementBoundingBox (PCB->Data, Element, &PCB->Font);
@@ -750,9 +750,9 @@ ChangeLineClearSize (LayerTypePtr Layer, LineTypePtr Line)
   if (value != Line->Clearance)
     {
       AddObjectToClearSizeUndoList (LINE_TYPE, Layer, Line, Line);
+      r_delete_entry (Layer->line_tree, (BoxTypePtr) Line);
       RestoreToPours (PCB->Data, LINE_TYPE, Layer, Line);
       EraseLine (Line);
-      r_delete_entry (Layer->line_tree, (BoxTypePtr) Line);
       Line->Clearance = value;
       if (Line->Clearance == 0)
 	{
diff --git a/src/misc.c b/src/misc.c
index ada4878..65caaca 100644
--- a/src/misc.c
+++ b/src/misc.c
@@ -1521,8 +1521,8 @@ ChangeArcAngles (LayerTypePtr Layer, ArcTypePtr a,
       new_da = 360;
       new_sa = 0;
     }
-  RestoreToPours (PCB->Data, ARC_TYPE, Layer, a);
   r_delete_entry (Layer->arc_tree, (BoxTypePtr) a);
+  RestoreToPours (PCB->Data, ARC_TYPE, Layer, a);
   AddObjectToChangeAnglesUndoList (ARC_TYPE, a, a, a);
   a->StartAngle = new_sa;
   a->Delta = new_da;
diff --git a/src/move.c b/src/move.c
index 640955e..64858f0 100644
--- a/src/move.c
+++ b/src/move.c
@@ -282,8 +282,8 @@ MoveLine (LayerTypePtr Layer, LineTypePtr Line)
 {
   if (Layer->On)
     EraseLine (Line);
-  RestoreToPours (PCB->Data, LINE_TYPE, Layer, Line);
   r_delete_entry (Layer->line_tree, (BoxTypePtr) Line);
+  RestoreToPours (PCB->Data, LINE_TYPE, Layer, Line);
   MOVE_LINE_LOWLEVEL (Line, DeltaX, DeltaY);
   r_insert_entry (Layer->line_tree, (BoxTypePtr) Line, 0);
   ClearFromPours (PCB->Data, LINE_TYPE, Layer, Line);
@@ -301,8 +301,8 @@ MoveLine (LayerTypePtr Layer, LineTypePtr Line)
 static void *
 MoveArc (LayerTypePtr Layer, ArcTypePtr Arc)
 {
-  RestoreToPours (PCB->Data, ARC_TYPE, Layer, Arc);
   r_delete_entry (Layer->arc_tree, (BoxTypePtr) Arc);
+  RestoreToPours (PCB->Data, ARC_TYPE, Layer, Arc);
   if (Layer->On)
     {
       EraseArc (Arc);
@@ -325,8 +325,8 @@ MoveArc (LayerTypePtr Layer, ArcTypePtr Arc)
 static void *
 MoveText (LayerTypePtr Layer, TextTypePtr Text)
 {
-  RestoreToPours (PCB->Data, TEXT_TYPE, Layer, Text);
   r_delete_entry (Layer->text_tree, (BoxTypePtr) Text);
+  RestoreToPours (PCB->Data, TEXT_TYPE, Layer, Text);
   if (Layer->On)
     {
       EraseText (Layer, Text);
@@ -388,8 +388,8 @@ MoveLinePoint (LayerTypePtr Layer, LineTypePtr Line, PointTypePtr Point)
     {
       if (Layer->On)
 	EraseLine (Line);
-      RestoreToPours (PCB->Data, LINE_TYPE, Layer, Line);
       r_delete_entry (Layer->line_tree, &Line->BoundingBox);
+      RestoreToPours (PCB->Data, LINE_TYPE, Layer, Line);
       MOVE (Point->X, Point->Y, DeltaX, DeltaY);
       SetLineBoundingBox (Line);
       r_insert_entry (Layer->line_tree, &Line->BoundingBox, 0);
@@ -659,8 +659,8 @@ MoveTextToLayerLowLevel (LayerTypePtr Source, TextTypePtr Text,
 {
   TextTypePtr new = GetTextMemory (Destination);
 
-  RestoreToPours (PCB->Data, TEXT_TYPE, Source, Text);
   r_delete_entry (Source->text_tree, (BoxTypePtr) Text);
+  RestoreToPours (PCB->Data, TEXT_TYPE, Source, Text);
   /* copy the data and remove it from the former layer */
   *new = *Text;
   *Text = Source->Text[--Source->TextN];
diff --git a/src/pour.c b/src/pour.c
index 1d0558c..5e66d98 100644
--- a/src/pour.c
+++ b/src/pour.c
@@ -823,7 +823,8 @@ subtract_plow (DataTypePtr Data, LayerTypePtr layer, PourTypePtr pour,
 
   if (np == NULL)
     {
-      printf ("Didn't get a POLYAREA to subtract, so bailing\n");
+      mark_islands (Data, layer, pour, type, ptr1, ptr2);
+      // printf ("Didn't get a POLYAREA to subtract, so bailing\n");
       return 0;
     }
 
@@ -873,6 +874,7 @@ subtract_plow (DataTypePtr Data, LayerTypePtr layer, PourTypePtr pour,
     {
       printf ("Hmm, got pg == NULL in subtract_plow\n");
       poly_Free (&np);
+      mark_islands (Data, layer, pour, type, ptr1, ptr2);
       return -1;
     }
 
@@ -1098,6 +1100,7 @@ add_plow (DataTypePtr Data, LayerTypePtr layer, PourTypePtr pour,
   if (np == NULL)
     {
       printf ("Didn't get a POLYAREA to add, so bailing\n");
+      mark_islands (Data, layer, pour, type, ptr1, ptr2);
       return 0;
     }
 
@@ -1108,6 +1111,7 @@ add_plow (DataTypePtr Data, LayerTypePtr layer, PourTypePtr pour,
   if (np == NULL)
     {
       printf ("POLYAREA to add got clipped away, so bailing\n");
+      mark_islands (Data, layer, pour, type, ptr1, ptr2);
       return 0;
     }
 
@@ -1389,9 +1393,10 @@ PlowPours (DataType * Data, int type, void *ptr1, void *ptr2,
     case POLYGON_TYPE:
     case POUR_TYPE:
       /* the cast works equally well for lines and arcs */
-      if (!ignore_clearflags &&
-          !TEST_FLAG (CLEARLINEFLAG, (LineTypePtr) ptr2))
-        return 0;
+// NEED TO KEEP GOING FOR POURS
+//      if (!ignore_clearflags &&
+//          !TEST_FLAG (CLEARLINEFLAG, (LineTypePtr) ptr2))
+//        return 0;
       /* silk doesn't plow */
       if (GetLayerNumber (Data, ptr1) >= max_layer)
         return 0;
diff --git a/src/rotate.c b/src/rotate.c
index 229e705..406e025 100644
--- a/src/rotate.c
+++ b/src/rotate.c
@@ -181,8 +181,8 @@ static void *
 RotateText (LayerTypePtr Layer, TextTypePtr Text)
 {
   EraseText (Layer, Text);
-  RestoreToPours (PCB->Data, TEXT_TYPE, Layer, Text);
   r_delete_entry (Layer->text_tree, (BoxTypePtr) Text);
+  RestoreToPours (PCB->Data, TEXT_TYPE, Layer, Text);
   RotateTextLowLevel (Text, CenterX, CenterY, Number);
   r_insert_entry (Layer->text_tree, (BoxTypePtr) Text, 0);
   ClearFromPours (PCB->Data, TEXT_TYPE, Layer, Text);
@@ -276,8 +276,8 @@ RotateLinePoint (LayerTypePtr Layer, LineTypePtr Line, PointTypePtr Point)
   EraseLine (Line);
   if (Layer)
     {
-      RestoreToPours (PCB->Data, LINE_TYPE, Layer, Line);
       r_delete_entry (Layer->line_tree, (BoxTypePtr) Line);
+      RestoreToPours (PCB->Data, LINE_TYPE, Layer, Line);
     }
   else
     r_delete_entry (PCB->Data->rat_tree, (BoxTypePtr) Line);
@@ -390,8 +390,8 @@ RotateObject (int Type, void *Ptr1, void *Ptr2, void *Ptr3,
       EraseLine (ptr->Line);
       if (ptr->Layer)
 	{
-	  RestoreToPours (PCB->Data, LINE_TYPE, ptr->Layer, ptr->Line);
 	  r_delete_entry (ptr->Layer->line_tree, (BoxType *) ptr->Line);
+	  RestoreToPours (PCB->Data, LINE_TYPE, ptr->Layer, ptr->Line);
 	}
       else
 	r_delete_entry (PCB->Data->rat_tree, (BoxType *) ptr->Line);

commit 9045d1b2ab5916ad9c1a3ac58eacf19e47dca201
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    Off to find burried treasure on polygon island
    
    Add feature to remove islanded areas
    
    Known bugs:
    
    When dragging a via with a "solid" style thermal, a polygon piece
    will not (always?) be un-flagged as an island. The same via as part
    of a selection will re-create the polygon.

diff --git a/src/change.c b/src/change.c
index 3733071..a6d0ecf 100644
--- a/src/change.c
+++ b/src/change.c
@@ -1177,10 +1177,12 @@ ChangeLineJoin (LayerTypePtr Layer, LineTypePtr Line)
   AddObjectToFlagUndoList (LINE_TYPE, Layer, Line, Line);
   TOGGLE_FLAG (CLEARLINEFLAG, Line);
   if (TEST_FLAG(CLEARLINEFLAG, Line))
-  {
-  AddObjectToClearPourUndoList (LINE_TYPE, Layer, Line, Line, true);
-  ClearFromPours (PCB->Data, LINE_TYPE, Layer, Line);
-  }
+    {
+      AddObjectToClearPourUndoList (LINE_TYPE, Layer, Line, Line, true);
+      ClearFromPours (PCB->Data, LINE_TYPE, Layer, Line);
+    }
+  else
+    MarkPourIslands (PCB->Data, LINE_TYPE, Layer, Line);
   DrawLine (Layer, Line, 0);
   return (Line);
 }
@@ -1225,9 +1227,11 @@ ChangeArcJoin (LayerTypePtr Layer, ArcTypePtr Arc)
   TOGGLE_FLAG (CLEARLINEFLAG, Arc);
   if (TEST_FLAG (CLEARLINEFLAG, Arc))
     {
-      ClearFromPours (PCB->Data, ARC_TYPE, Layer, Arc);
       AddObjectToClearPourUndoList (ARC_TYPE, Layer, Arc, Arc, true);
+      ClearFromPours (PCB->Data, ARC_TYPE, Layer, Arc);
     }
+  else
+    MarkPourIslands (PCB->Data, ARC_TYPE, Layer, Arc);
   DrawArc (Layer, Arc, 0);
   return (Arc);
 }
@@ -1271,10 +1275,12 @@ ChangeTextJoin (LayerTypePtr Layer, TextTypePtr Text)
   AddObjectToFlagUndoList (LINE_TYPE, Layer, Text, Text);
   TOGGLE_FLAG (CLEARLINEFLAG, Text);
   if (TEST_FLAG(CLEARLINEFLAG, Text))
-  {
-  AddObjectToClearPourUndoList (TEXT_TYPE, Layer, Text, Text, true);
-  ClearFromPours (PCB->Data, TEXT_TYPE, Layer, Text);
-  }
+    {
+      AddObjectToClearPourUndoList (TEXT_TYPE, Layer, Text, Text, true);
+      ClearFromPours (PCB->Data, TEXT_TYPE, Layer, Text);
+    }
+  else
+    MarkPourIslands (PCB->Data, TEXT_TYPE, Layer, Text);
   DrawText (Layer, Text, 0);
   return (Text);
 }
@@ -1625,6 +1631,8 @@ ChangeHole (PinTypePtr Via)
     {
       AddObjectTo2ndSizeUndoList (VIA_TYPE, Via, Via, Via);
       Via->DrillingHole = Via->Thickness - MIN_PINORVIACOPPER;
+#warning FIXME Later: Come back to check this
+      MarkPourIslands (PCB->Data, VIA_TYPE, Via, Via);
     }
   DrawVia (Via, 0);
   Draw ();
diff --git a/src/draw.c b/src/draw.c
index bcc1300..c800f8b 100644
--- a/src/draw.c
+++ b/src/draw.c
@@ -2113,6 +2113,10 @@ DrawPlainPolygon (LayerTypePtr Layer, PolygonTypePtr Polygon)
   if (!Polygon->Clipped)
     return;
 
+  /* Re-use HOLEFLAG to cut out islands */
+  if (TEST_FLAG (HOLEFLAG, Polygon))
+    return;
+
   if (Gathering)
     {
       AddPart (Polygon);
diff --git a/src/find.c b/src/find.c
index d8a955f..af9103c 100644
--- a/src/find.c
+++ b/src/find.c
@@ -2649,6 +2649,7 @@ LookupLOConnectionsToPolygon (PolygonTypePtr Polygon, Cardinal LayerGroup)
 
   if (!Polygon->Clipped)
     return false;
+
   info.polygon = *Polygon;
   EXPAND_BOUNDS (&info.polygon);
   info.layer = LayerGroup;
@@ -4000,6 +4001,70 @@ doIsBad:
 }
 
 /*-----------------------------------------------------------------------------
+ * Check for islanding of a polygon
+ * by determining if any non-polygon objects are connected to it.
+ */
+int
+IsPolygonAnIsland (LayerType *layer, PolygonType *polygon)
+{
+  int connected_count = 0;
+  int any_more;
+  int i;
+
+  InitConnectionLookup ();
+
+  /* Need to ensure we don't set the SELECTED flag as we find
+   * things, otherwise we don't get our quick escape due to the
+   * "drc" magic.
+   *
+   * (The connection scanning code doesn't stop on objects which are
+   *  SELECTED, even if "drc" is true).
+   *
+   * Ideally we'd clear the SELECTED flag on all objects before we
+   * start, ensuring we exit when we first find connectivity, but
+   * that causes all manner of breakage. I upsets other logic in
+   * PCB if we change the selection during certain operations we're
+   * called during.
+   */
+  TheFlag = FOUNDFLAG | DRCFLAG;
+
+  ResetConnections (false);
+
+  /* Let the search stop if we find something we haven't yet seen */
+  drc = true;
+  User = false;
+
+  ListStart (POLYGON_TYPE, layer, polygon, polygon);
+
+  do
+    {
+      any_more = DoIt (false, false);
+
+      /* Check if we got any useful hits */
+      connected_count = 0;
+      for (i = 0; i < max_layer; i++)
+        {
+          connected_count += LineList[ i ].Number;
+          /* No need to search all layers when one will do */
+          if (connected_count)
+            break;
+        }
+      connected_count += PadList[ COMPONENT_LAYER ].Number;
+      connected_count += PadList[ SOLDER_LAYER ].Number;
+      connected_count += PVList.Number;
+      if (connected_count)
+        break;
+    }
+  while (any_more);
+
+  drc = false;
+  ResetConnections (false);
+  FreeConnectionLookupMemory ();
+
+  return (connected_count == 0);
+}
+
+/*-----------------------------------------------------------------------------
  * Check for DRC violations
  * see if the connectivity changes when everything is bloated, or shrunk
  */
diff --git a/src/find.h b/src/find.h
index f93fca1..0e0e1c9 100644
--- a/src/find.h
+++ b/src/find.h
@@ -65,6 +65,7 @@ void FreeLayoutLookupMemory (void);
 void RatFindHook (int, void *, void *, void *, bool, bool);
 void SaveFindFlag (int);
 void RestoreFindFlag (void);
+int IsPolygonAnIsland (LayerTypePtr, PolygonTypePtr);
 int DRCAll (void);
 bool lineClear (LineTypePtr, Cardinal);
 bool IsLineInPolygon (LineTypePtr, PolygonTypePtr);
diff --git a/src/move.c b/src/move.c
index bf9670e..640955e 100644
--- a/src/move.c
+++ b/src/move.c
@@ -393,7 +393,10 @@ MoveLinePoint (LayerTypePtr Layer, LineTypePtr Line, PointTypePtr Point)
       MOVE (Point->X, Point->Y, DeltaX, DeltaY);
       SetLineBoundingBox (Line);
       r_insert_entry (Layer->line_tree, &Line->BoundingBox, 0);
-      ClearFromPours (PCB->Data, LINE_TYPE, Layer, Line);
+      if (TEST_FLAG (CLEARLINEFLAG, Line))
+        ClearFromPours (PCB->Data, LINE_TYPE, Layer, Line);
+      else
+        MarkPourIslands (PCB->Data, LINE_TYPE, Layer, Line);
       if (Layer->On)
 	{
 	  DrawLine (Layer, Line, 0);
diff --git a/src/pour.c b/src/pour.c
index d45a690..1d0558c 100644
--- a/src/pour.c
+++ b/src/pour.c
@@ -66,7 +66,7 @@ RCSID ("$Id$");
 
 #define ROUND(x) ((long)(((x) >= 0 ? (x) + 0.5  : (x) - 0.5)))
 
-#define UNSUBTRACT_BLOAT 100
+#define UNSUBTRACT_BLOAT 10
 #define SUBTRACT_PIN_VIA_BATCH_SIZE 100
 #define SUBTRACT_LINE_BATCH_SIZE 20
 
@@ -759,7 +759,36 @@ ClearPour (DataTypePtr Data, LayerTypePtr Layer, PourType * pour,
 }
 
 static int
-subtract_plow (DataTypePtr Data, LayerTypePtr Layer, PourTypePtr pour,
+check_polygon_island_cb (const BoxType * b, void *cl)
+{
+  PolygonTypePtr polygon = (PolygonTypePtr) b;
+  struct cpInfo *info = (struct cpInfo *) cl;
+
+  ASSIGN_FLAG (HOLEFLAG, IsPolygonAnIsland (info->layer, polygon), polygon);
+  return 1;
+}
+
+static int
+mark_islands (DataTypePtr Data, LayerTypePtr layer, PourTypePtr pour,
+              int type, void *ptr1, void *ptr2)
+{
+  struct cpInfo info;
+  BoxType region = ((PinTypePtr) ptr2)->BoundingBox;
+
+  region.X1 -= UNSUBTRACT_BLOAT;
+  region.Y1 -= UNSUBTRACT_BLOAT;
+  region.X2 += UNSUBTRACT_BLOAT;
+  region.Y2 += UNSUBTRACT_BLOAT;
+
+  info.region = &region;
+  info.layer = layer;
+
+  return r_search (pour->polygon_tree, info.region, NULL,
+                   check_polygon_island_cb, &info);
+}
+
+static int
+subtract_plow (DataTypePtr Data, LayerTypePtr layer, PourTypePtr pour,
               int type, void *ptr1, void *ptr2)
 {
   POLYAREA *np = NULL, *pg = NULL, *start_pg, *tmp;
@@ -769,7 +798,7 @@ subtract_plow (DataTypePtr Data, LayerTypePtr Layer, PourTypePtr pour,
     {
     case PIN_TYPE:
     case VIA_TYPE:
-      np = get_subtract_pin_poly (Data, (PinTypePtr) ptr2, Layer, pour);
+      np = get_subtract_pin_poly (Data, (PinTypePtr) ptr2, layer, pour);
       break;
     case LINE_TYPE:
       np = get_subtract_line_poly ((LineTypePtr) ptr2, pour);
@@ -783,6 +812,10 @@ subtract_plow (DataTypePtr Data, LayerTypePtr Layer, PourTypePtr pour,
     case POLYGON_TYPE:
       np = get_subtract_polygon_poly ((PolygonTypePtr) ptr2, pour);
       break;
+    case POUR_TYPE:
+#warning FIXME Later: Need to produce a function for this
+      np = NULL;
+      break;
     case TEXT_TYPE:
       np = get_subtract_text_poly ((TextTypePtr) ptr2, pour);
       break;
@@ -900,6 +933,8 @@ subtract_plow (DataTypePtr Data, LayerTypePtr Layer, PourTypePtr pour,
     }
   while ((pg = tmp) != start_pg);
 
+  mark_islands (Data, layer, pour, type, ptr1, ptr2);
+
   return 0;
 }
 
@@ -1026,7 +1061,7 @@ PourToPoly (PourType *p)
 }
 
 static int
-add_plow (DataTypePtr Data, LayerTypePtr Layer, PourTypePtr pour,
+add_plow (DataTypePtr Data, LayerTypePtr layer, PourTypePtr pour,
           int type, void *ptr1, void *ptr2)
 {
   POLYAREA *np = NULL, *pg = NULL, *tmp, *start_pg;
@@ -1037,22 +1072,26 @@ add_plow (DataTypePtr Data, LayerTypePtr Layer, PourTypePtr pour,
     {
     case PIN_TYPE:
     case VIA_TYPE:
-      np = get_unsubtract_pin_poly ((PinTypePtr) ptr2, Layer, pour);
+      np = get_unsubtract_pin_poly ((PinTypePtr) ptr2, layer, pour);
       break;
     case LINE_TYPE:
-      np = get_unsubtract_line_poly ((LineTypePtr) ptr2, Layer, pour);
+      np = get_unsubtract_line_poly ((LineTypePtr) ptr2, layer, pour);
       break;
     case ARC_TYPE:
-      np = get_unsubtract_arc_poly ((ArcTypePtr) ptr2, Layer, pour);
+      np = get_unsubtract_arc_poly ((ArcTypePtr) ptr2, layer, pour);
       break;
     case PAD_TYPE:
-      np = get_unsubtract_pad_poly ((PadTypePtr) ptr2, Layer, pour);
+      np = get_unsubtract_pad_poly ((PadTypePtr) ptr2, layer, pour);
       break;
     case POLYGON_TYPE:
-      np = get_unsubtract_polygon_poly ((PolygonTypePtr) ptr2, Layer, pour);
+      np = get_unsubtract_polygon_poly ((PolygonTypePtr) ptr2, layer, pour);
+      break;
+    case POUR_TYPE:
+#warning FIXME Later: Need to produce a function for this
+      np = NULL;
       break;
     case TEXT_TYPE:
-      np = get_unsubtract_text_poly ((TextTypePtr) ptr2, Layer, pour);
+      np = get_unsubtract_text_poly ((TextTypePtr) ptr2, layer, pour);
       break;
     }
 
@@ -1139,7 +1178,7 @@ add_plow (DataTypePtr Data, LayerTypePtr Layer, PourTypePtr pour,
   printf ("After unsubtract, counted %i polygon pieces\n", count);
 #endif
 
-  ClearPour (PCB->Data, Layer, pour, &pg, (const BoxType *) ptr2, 2 * UNSUBTRACT_BLOAT);
+  ClearPour (PCB->Data, layer, pour, &pg, (const BoxType *) ptr2, 2 * UNSUBTRACT_BLOAT);
 
   if (pg == NULL)
     {
@@ -1180,6 +1219,8 @@ add_plow (DataTypePtr Data, LayerTypePtr Layer, PourTypePtr pour,
     }
   while ((pg = tmp) != start_pg);
 
+  mark_islands (Data, layer, pour, type, ptr1, ptr2);
+
 //  printf ("ClearPour counted %i polygon pieces, and added the biggest %i\n", count_all, count_added);
 
   return 0;
@@ -1270,6 +1311,12 @@ InitPourClip (DataTypePtr Data, LayerTypePtr layer, PourType * pour)
     }
   while ((pg = tmp) != start_pg);
 
+  POURPOLYGON_LOOP (pour);
+  {
+    ASSIGN_FLAG (HOLEFLAG, IsPolygonAnIsland (layer, polygon), polygon);
+  }
+  END_LOOP;
+
   return 1;
 }
 
@@ -1299,7 +1346,8 @@ int
 PlowPours (DataType * Data, int type, void *ptr1, void *ptr2,
            int (*call_back) (DataTypePtr data, LayerTypePtr lay,
                              PourTypePtr poly, int type,
-                             void *ptr1, void *ptr2))
+                             void *ptr1, void *ptr2),
+           int ignore_clearflags)
 {
   BoxType sb = ((PinTypePtr) ptr2)->BoundingBox;
   int r = 0;
@@ -1339,8 +1387,10 @@ PlowPours (DataType * Data, int type, void *ptr1, void *ptr2,
     case ARC_TYPE:
     case TEXT_TYPE:
     case POLYGON_TYPE:
+    case POUR_TYPE:
       /* the cast works equally well for lines and arcs */
-      if (!TEST_FLAG (CLEARLINEFLAG, (LineTypePtr) ptr2))
+      if (!ignore_clearflags &&
+          !TEST_FLAG (CLEARLINEFLAG, (LineTypePtr) ptr2))
         return 0;
       /* silk doesn't plow */
       if (GetLayerNumber (Data, ptr1) >= max_layer)
@@ -1372,12 +1422,12 @@ PlowPours (DataType * Data, int type, void *ptr1, void *ptr2,
       {
         PIN_LOOP ((ElementType *) ptr1);
         {
-          PlowPours (Data, PIN_TYPE, ptr1, pin, call_back);
+          PlowPours (Data, PIN_TYPE, ptr1, pin, call_back, ignore_clearflags);
         }
         END_LOOP;
         PAD_LOOP ((ElementType *) ptr1);
         {
-          PlowPours (Data, PAD_TYPE, ptr1, pad, call_back);
+          PlowPours (Data, PAD_TYPE, ptr1, pad, call_back, ignore_clearflags);
         }
         END_LOOP;
       }
@@ -1397,7 +1447,7 @@ RestoreToPours (DataType * Data, int type, void *ptr1, void *ptr2)
 //      printf ("Calling InitPourClip from RestoreToPour\n");
       InitPourClip (PCB->Data, (LayerTypePtr) ptr1, (PourTypePtr) ptr2);
     }
-  PlowPours (Data, type, ptr1, ptr2, add_plow);
+  PlowPours (Data, type, ptr1, ptr2, add_plow, false);
 }
 
 void
@@ -1411,7 +1461,7 @@ ClearFromPours (DataType * Data, int type, void *ptr1, void *ptr2)
 //      printf ("Calling InitPourClip from ClearFromPour\n");
       InitPourClip (PCB->Data, (LayerTypePtr) ptr1, (PourTypePtr) ptr2);
     }
-  PlowPours (Data, type, ptr1, ptr2, subtract_plow);
+  PlowPours (Data, type, ptr1, ptr2, subtract_plow, false);
 }
 
 /* Convert a POLYAREA (and all linked POLYAREA) to
@@ -1468,3 +1518,12 @@ PolyToPoursOnLayer (DataType *Destination, LayerType *Layer,
 
   SetChangedFlag (true);
 }
+
+#warning FIXME Later: We could perhaps reduce un-necessary computation by using this function
+void
+MarkPourIslands (DataType * Data, int type, void *ptr1, void *ptr2)
+{
+  if (!Data->ClipPours)
+    return;
+  PlowPours (Data, type, ptr1, ptr2, mark_islands, true);
+}
diff --git a/src/pour.h b/src/pour.h
index 4711da7..c2b1385 100644
--- a/src/pour.h
+++ b/src/pour.h
@@ -47,6 +47,7 @@ void CopyAttachedPourToLayer (void);
 int InitPourClip(DataType *d, LayerType *l, PourType *p);
 void RestoreToPours(DataType *, int, void *, void *);
 void ClearFromPours(DataType *, int, void *, void *);
+void MarkPourIslands(DataType *, int, void *, void *);
 
 POLYAREA * PourToPoly (PourType *);
 void PolyToPoursOnLayer (DataType *, LayerType *, POLYAREA *, FlagType);
diff --git a/src/search.c b/src/search.c
index 200cc89..bb20f05 100644
--- a/src/search.c
+++ b/src/search.c
@@ -454,7 +454,7 @@ SearchPolygonByLocation (int locked, LayerTypePtr * Layer,
   return (true);
 }
 
-#warning FIXME Later: For now, can only select a pour if you're hitting its child polygons
+#warning FIXME Later: For now, can only select a pour if youre hitting its child polygons
 #if 0
 static int
 pour_callback (const BoxType * box, void *cl)
@@ -488,7 +488,7 @@ SearchPourByLocation (int locked, LayerTypePtr * Layer,
   info.ptr3 = (void **) Dummy;
   info.locked = (locked & LOCKED_TYPE) ? 0 : LOCKFLAG;
 
-#warning FIXME Later: For now, can only select a pour if you're hitting its child polygons
+#warning FIXME Later: For now, can only select a pour if youre hitting its child polygons
   if (setjmp (info.env) == 0)
     {
       r_search (SearchLayer->pour_tree, &SearchBox, NULL, pour_polygon_callback, &info);

commit 5b59be1fe0f9e3c489368840ba415902146715d4
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    Add magic flag to stop pour clipping for off-screen buffers

diff --git a/src/create.c b/src/create.c
index 68f2f19..3d879ff 100644
--- a/src/create.c
+++ b/src/create.c
@@ -139,6 +139,7 @@ CreateNewPCB (bool SetDefaultNames)
   ptr = MyCalloc (1, sizeof (PCBType), "CreateNewPCB()");
   ptr->Data = CreateNewBuffer ();
   ptr->Data->pcb = (void *) ptr;
+  ptr->Data->ClipPours = 1;
 
   ptr->ThermStyle = 4;
   ptr->IsleArea = 2.e8;
diff --git a/src/global.h b/src/global.h
index 3d5f28f..20f6cf1 100644
--- a/src/global.h
+++ b/src/global.h
@@ -417,6 +417,7 @@ typedef struct			/* holds all objects */
    *rat_tree;
   struct PCBType *pcb;
   LayerType Layer[MAX_LAYER + 2];	/* add 2 silkscreen layers */
+  int ClipPours;
 } DataType, *DataTypePtr;
 
 typedef struct			/* holds drill information */
diff --git a/src/pour.c b/src/pour.c
index 48a1525..d45a690 100644
--- a/src/pour.c
+++ b/src/pour.c
@@ -1389,6 +1389,8 @@ PlowPours (DataType * Data, int type, void *ptr1, void *ptr2,
 void
 RestoreToPours (DataType * Data, int type, void *ptr1, void *ptr2)
 {
+  if (!Data->ClipPours)
+    return;
   if (type == POUR_TYPE)
     {
 #warning FIXME Later: Why do we need to do this?
@@ -1401,6 +1403,8 @@ RestoreToPours (DataType * Data, int type, void *ptr1, void *ptr2)
 void
 ClearFromPours (DataType * Data, int type, void *ptr1, void *ptr2)
 {
+  if (!Data->ClipPours)
+    return;
   if (type == POUR_TYPE)
     {
 #warning FIXME Later: Why do we need to do this?

commit 4c05b67ed980813f0e9397b285f6687568e032fa
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    Use the r_trees to avoid needing to check so many polygons all the time

diff --git a/src/find.c b/src/find.c
index 848edc9..d8a955f 100644
--- a/src/find.c
+++ b/src/find.c
@@ -33,8 +33,6 @@
  * - lists for pins and vias, lines, arcs, pads and for polygons are created.
  *   Every object that has to be checked is added to its list.
  *   Coarse searching is accomplished with the data rtrees.
- * - there's no 'speed-up' mechanism for polygons because they are not used
- *   as often as other objects 
  * - the maximum distance between line and pin ... would depend on the angle
  *   between them. To speed up computation the limit is set to one half
  *   of the thickness of the objects (cause of square pins).
@@ -1978,6 +1976,7 @@ LookupLOConnectionsToArc (ArcTypePtr Arc, Cardinal LayerGroup)
             return true;
 
           /* now check all polygons */
+          printf ("Slow pour path for arcs\n");
           POUR_LOOP (LAYER_PTR (layer));
           {
             POURPOLYGON_LOOP (pour);
@@ -2059,6 +2058,30 @@ LOCtoLineRat_callback (const BoxType * b, void *cl)
 }
 
 static int
+LOCtoLinePolygon_callback (const BoxType * b, void *cl)
+{
+  PolygonTypePtr polygon = (PolygonTypePtr) b;
+  struct lo_info *i = (struct lo_info *) cl;
+
+  if (!TEST_FLAG (TheFlag, polygon) &&
+      IsLineInPolygon (&i->line, polygon) &&
+      ADD_POLYGON_TO_LIST (i->layer, polygon))
+    longjmp (i->env, 1);
+
+  return 0;
+}
+
+static int
+LOCtoLinePourPolygon_callback (const BoxType * b, void *cl)
+{
+  PourTypePtr pour = (PourTypePtr) b;
+  struct lo_info *i = (struct lo_info *) cl;
+
+  return r_search (pour->polygon_tree, (BoxType *) &i->line,
+                   NULL, LOCtoLinePolygon_callback, i);
+}
+
+static int
 LOCtoLinePad_callback (const BoxType * b, void *cl)
 {
   PadTypePtr pad = (PadTypePtr) b;
@@ -2121,18 +2144,11 @@ LookupLOConnectionsToLine (LineTypePtr Line, Cardinal LayerGroup,
           /* now check all polygons */
           if (PolysTo)
             {
-              POUR_LOOP (LAYER_PTR (layer));
-              {
-                POURPOLYGON_LOOP (pour);
-                {
-                  if (!TEST_FLAG (TheFlag, polygon) &&
-                      IsLineInPolygon (Line, polygon) &&
-                      ADD_POLYGON_TO_LIST (layer, polygon))
-                    return true;
-                }
-                END_LOOP;
-              }
-              END_LOOP;
+              if (setjmp (info.env) == 0)
+                r_search (LAYER_PTR (layer)->pour_tree, (BoxType *) & info.line,
+                          NULL, LOCtoLinePourPolygon_callback, &info);
+              else
+                return true;
             }
         }
       else
@@ -2220,6 +2236,7 @@ LOTouchesLine (LineTypePtr Line, Cardinal LayerGroup)
             return (true);
 
           /* now check all polygons */
+          printf ("Slow pour path for lines (LOTouchesLine)\n");
           POUR_LOOP (LAYER_PTR (layer));
           {
             POURPOLYGON_LOOP (pour);
@@ -2596,6 +2613,29 @@ LOCtoPolyRat_callback (const BoxType * b, void *cl)
   return 0;
 }
 
+static int
+LOCtoPolyPolygon_callback (const BoxType * b, void *cl)
+{
+  PolygonTypePtr polygon = (PolygonTypePtr) b;
+  struct lo_info *i = (struct lo_info *) cl;
+
+  if (!TEST_FLAG (TheFlag, polygon) &&
+      IsPolygonInPolygon (polygon, &i->polygon) &&
+      ADD_POLYGON_TO_LIST (i->layer, polygon))
+    longjmp (i->env, 1);
+
+  return 0;
+}
+
+static int
+LOCtoPolyPourPolygon_callback (const BoxType * b, void *cl)
+{
+  PourTypePtr pour = (PourTypePtr) b;
+  struct lo_info *i = (struct lo_info *) cl;
+
+  return r_search (pour->polygon_tree, (BoxType *) &i->polygon,
+                   NULL, LOCtoPolyPolygon_callback, i);
+}
 
 /* ---------------------------------------------------------------------------
  * looks up LOs that are connected to the given polygon
@@ -2631,19 +2671,12 @@ LookupLOConnectionsToPolygon (PolygonTypePtr Polygon, Cardinal LayerGroup)
           info.layer = layer;
 
           /* check all polygons */
-
-          POUR_LOOP (LAYER_PTR (layer));
-          {
-            POURPOLYGON_LOOP (pour);
-            {
-              if (!TEST_FLAG (TheFlag, polygon) &&
-                  IsPolygonInPolygon (polygon, Polygon) &&
-                  ADD_POLYGON_TO_LIST (layer, polygon))
-                return true;
-            }
-            END_LOOP;
-          }
-          END_LOOP;
+          if (setjmp (info.env) == 0)
+            r_search (LAYER_PTR (layer)->pour_tree,
+                      (BoxType *) & info.polygon, NULL,
+                      LOCtoPolyPourPolygon_callback, &info);
+          else
+            return true;
 
           /* check all lines */
           if (setjmp (info.env) == 0)

commit 1507957219673fad9ba2ea52f64964ed9b036337
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    Fixup gtk hid drawing routines for pour support

diff --git a/src/hid/gtk/gui-output-events.c b/src/hid/gtk/gui-output-events.c
index 7f58605..efce5ec 100644
--- a/src/hid/gtk/gui-output-events.c
+++ b/src/hid/gtk/gui-output-events.c
@@ -1174,6 +1174,10 @@ DrawPlainPolygon (LayerTypePtr Layer, PolygonTypePtr Polygon, const BoxType *dra
   if (!Polygon->Clipped)
     return;
 
+  /* Re-use HOLEFLAG to cut out islands */
+  if (TEST_FLAG (HOLEFLAG, Polygon))
+    return;
+
   if (TEST_FLAG (SELECTEDFLAG, Polygon))
     color = Layer->SelectedColor;
   else if (TEST_FLAG (FOUNDFLAG, Polygon))
@@ -1212,6 +1216,22 @@ poly_callback (const BoxType * b, void *cl)
   return 1;
 }
 
+static int
+pour_callback (const BoxType * b, void *cl)
+{
+  struct pin_info *i = (struct pin_info *) cl;
+  PourType *pour = (PourType *)b;
+
+  DrawPour (i->Layer, pour, 0);
+
+  if (pour->PolygonN)
+    {
+      r_search (pour->polygon_tree, i->drawn_area, NULL, poly_callback, i);
+    }
+
+  return 1;
+}
+
 static void
 DrawPadLowLevelSolid (hidGC gc, PadTypePtr Pad, bool clear, bool mask)
 {
@@ -1407,10 +1427,10 @@ DrawLayerGroup (int group, const BoxType * screen)
       }
 
       /* draw all polygons on this layer */
-      if (Layer->PolygonN) {
+      if (Layer->PourN) {
         info.Layer = Layer;
         info.drawn_area = screen;
-        r_search (Layer->polygon_tree, screen, NULL, poly_callback, &info);
+        r_search (Layer->pour_tree, screen, NULL, pour_callback, &info);
 
         /* HACK: Subcomposite polygons separately from other layer primitives */
         /* Reset the compositing */

commit e94479d7210870e7c52a95b5becfc1244dd7fdd3
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    Speed up initial clipping (pours version of what we had before)

diff --git a/src/pour.c b/src/pour.c
index a3efa93..48a1525 100644
--- a/src/pour.c
+++ b/src/pour.c
@@ -67,6 +67,8 @@ RCSID ("$Id$");
 #define ROUND(x) ((long)(((x) >= 0 ? (x) + 0.5  : (x) - 0.5)))
 
 #define UNSUBTRACT_BLOAT 100
+#define SUBTRACT_PIN_VIA_BATCH_SIZE 100
+#define SUBTRACT_LINE_BATCH_SIZE 20
 
 /* ---------------------------------------------------------------------------
  * local prototypes
@@ -526,9 +528,22 @@ struct cpInfo
   bool solder;
   POLYAREA *pg;
   BoxType *region;
+  POLYAREA *accumulate;
+  int batch_size;
   jmp_buf env;
 };
 
+static void
+subtract_accumulated (struct cpInfo *info)
+{
+  if (info->accumulate == NULL)
+    return;
+  if (subtract_poly (info->accumulate, &info->pg) < 0)
+    longjmp (info->env, 1);
+  info->accumulate = NULL;
+  info->batch_size = 0;
+}
+
 static int
 pin_sub_callback (const BoxType * b, void *cl)
 {
@@ -544,8 +559,12 @@ pin_sub_callback (const BoxType * b, void *cl)
   if (np == NULL)
     return 0;
 
-  if (subtract_poly (np, &info->pg) < 0)
-    longjmp (info->env, 1);
+  unite_poly (np, &info->accumulate);
+  info->batch_size ++;
+
+  if (info->batch_size == SUBTRACT_PIN_VIA_BATCH_SIZE)
+    subtract_accumulated (info);
+
   return 1;
 }
 
@@ -566,8 +585,12 @@ arc_sub_callback (const BoxType * b, void *cl)
   if (np == NULL)
     return 0;
 
-  if (subtract_poly (np, &info->pg) < 0)
-    longjmp (info->env, 1);
+  unite_poly (np, &info->accumulate);
+  info->batch_size ++;
+
+  if (info->batch_size == SUBTRACT_LINE_BATCH_SIZE)
+    subtract_accumulated (info);
+
   return 1;
 }
 
@@ -711,18 +734,23 @@ ClearPour (DataTypePtr Data, LayerTypePtr Layer, PourType * pour,
 
   if (setjmp (info.env) == 0)
     {
-      r  = r_search (Data->via_tree, &region, NULL, pin_sub_callback, &info);
-      r += r_search (Data->pin_tree, &region, NULL, pin_sub_callback, &info);
+      r = 0;
+      info.accumulate = NULL;
+      info.batch_size = 0;
+      if (info.solder || group == Group (Data, max_layer + COMPONENT_LAYER))
+        r += r_search (Data->pad_tree, &region, NULL, pad_sub_callback, &info);
       GROUP_LOOP (Data, group);
       {
         r += r_search (layer->line_tree, &region, NULL, line_sub_callback, &info);
+        subtract_accumulated (&info);
         r += r_search (layer->arc_tree,  &region, NULL, arc_sub_callback,  &info);
         r += r_search (layer->text_tree, &region, NULL, text_sub_callback, &info);
         r += r_search (layer->pour_tree, &region, NULL, pour_sub_callback, &info);
       }
       END_LOOP;
-      if (info.solder || group == Group (Data, max_layer + COMPONENT_LAYER))
-        r += r_search (Data->pad_tree, &region, NULL, pad_sub_callback, &info);
+      r += r_search (Data->via_tree, &region, NULL, pin_sub_callback, &info);
+      r += r_search (Data->pin_tree, &region, NULL, pin_sub_callback, &info);
+      subtract_accumulated (&info);
     }
 
   *pg = info.pg;

commit 264989905adddfadc4875d37be4331c6d0e18f4f
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    Add support for a "poured" object.
    
    This takes half of the existing polygon functionality, and splits it
    such that the user defines a poured region (similar to drawing a polygon
    previously), and after clipping, this produces zero or more polygon
    objects which are drawn and connectivity checked with the existing
    polygon code.
    
    Selecting a "polygon" will cause the parent "pour" to be looked up, and
    all child polygons selected. Manipulations will always occur on the
    "pour", with "polygons" being updated after clipping.
    
    It remains to be seen whether "pour" will have its own file-format entry,
    or if it will take over the meaning of the existing "polygon" entry.

diff --git a/globalconst.h b/globalconst.h
index cd6f4f9..4ab3813 100755
--- a/globalconst.h
+++ b/globalconst.h
@@ -118,6 +118,8 @@
 						/* line points */
 #define	MAX_POLYGON_POINT_DISTANCE	0	/* maximum distance when searching */
 						/* polygon points */
+#define	MAX_POUR_POINT_DISTANCE	0	/* maximum distance when searching */
+						/* pour points */
 #define	MAX_ELEMENTNAMES		3	/* number of supported names of */
 						/* an element */
 #define	MAX_LIBRARY_LINE_LENGTH		255	/* maximum line length in the */
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 8db0918..5faaf6d 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -40,6 +40,7 @@ src/netlist.c
 src/parse_y.c
 src/pcb-menu.res.h
 src/polygon.c
+src/pour.c
 src/rats.c
 src/report.c
 src/res_parse.c
diff --git a/src/Makefile.am b/src/Makefile.am
index b709c27..452e325 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -121,6 +121,8 @@ PCB_SRCS = \
 	polygon.h \
 	polygon1.c \
 	polyarea.h \
+	pour.c \
+	pour.h \
 	puller.c \
 	print.c \
 	print.h \
diff --git a/src/action.c b/src/action.c
index 0a85391..6121665 100644
--- a/src/action.c
+++ b/src/action.c
@@ -57,6 +57,7 @@
 #include "misc.h"
 #include "move.h"
 #include "polygon.h"
+#include "pour.h"
 /*#include "print.h"*/
 #include "rats.h"
 #include "remove.h"
@@ -144,8 +145,8 @@ typedef enum
   F_PinByName,
   F_PinOrPadName,
   F_Pinout,
-  F_Polygon,
-  F_PolygonHole,
+  F_Pour,
+  F_PourHole,
   F_PreviousPoint,
   F_RatsNest,
   F_Rectangle,
@@ -297,7 +298,7 @@ static PointType InsertedPoint;
 static LayerTypePtr lastLayer;
 static struct
 {
-  PolygonTypePtr poly;
+  PourTypePtr pour;
   LineType line;
 }
 fake;
@@ -380,8 +381,8 @@ static FunctionType Functions[] = {
   {"PinByName", F_PinByName},
   {"PinOrPadName", F_PinOrPadName},
   {"Pinout", F_Pinout},
-  {"Polygon", F_Polygon},
-  {"PolygonHole", F_PolygonHole},
+  {"Pour", F_Pour},
+  {"PourHole", F_PourHole},
   {"PreviousPoint", F_PreviousPoint},
   {"RatsNest", F_RatsNest},
   {"Rectangle", F_Rectangle},
@@ -843,9 +844,9 @@ AdjustAttachedObjects (void)
       AdjustAttachedBox ();
       break;
 
-      /* polygon creation mode */
-    case POLYGON_MODE:
-    case POLYGONHOLE_MODE:
+      /* pour creation mode */
+    case POUR_MODE:
+    case POURHOLE_MODE:
       AdjustAttachedLine ();
       break;
       /* line creation mode */
@@ -1354,12 +1355,12 @@ NotifyMode (void)
 	  Crosshair.AttachedBox.Point1.X != Crosshair.AttachedBox.Point2.X &&
 	  Crosshair.AttachedBox.Point1.Y != Crosshair.AttachedBox.Point2.Y)
 	{
-	  PolygonTypePtr polygon;
+	  PourTypePtr pour;
 
 	  int flags = CLEARPOLYFLAG;
 	  if (TEST_FLAG (NEWFULLPOLYFLAG, PCB))
 	    flags |= FULLPOLYFLAG;
-	  if ((polygon = CreateNewPolygonFromRectangle (CURRENT,
+	  if ((pour = CreateNewPourFromRectangle (CURRENT,
 							Crosshair.
 							AttachedBox.Point1.X,
 							Crosshair.
@@ -1372,10 +1373,10 @@ NotifyMode (void)
 							(flags))) !=
 	      NULL)
 	    {
-	      AddObjectToCreateUndoList (POLYGON_TYPE, CURRENT,
-					 polygon, polygon);
+	      AddObjectToCreateUndoList (POUR_TYPE, CURRENT,
+					 pour, pour);
 	      IncrementUndoSerialNumber ();
-	      DrawPolygon (CURRENT, polygon, 0);
+	      DrawPour (CURRENT, pour, 0);
 	      Draw ();
 	    }
 
@@ -1415,10 +1416,10 @@ NotifyMode (void)
 	break;
       }
 
-    case POLYGON_MODE:
+    case POUR_MODE:
       {
-	PointTypePtr points = Crosshair.AttachedPolygon.Points;
-	Cardinal n = Crosshair.AttachedPolygon.PointN;
+	PointTypePtr points = Crosshair.AttachedPour.Points;
+	Cardinal n = Crosshair.AttachedPour.PointN;
 
 	/* do update of position; use the 'LINE_MODE' mechanism */
 	NotifyLine ();
@@ -1428,7 +1429,7 @@ NotifyMode (void)
 	    points->X == Crosshair.AttachedLine.Point2.X &&
 	    points->Y == Crosshair.AttachedLine.Point2.Y)
 	  {
-	    CopyAttachedPolygonToLayer ();
+	    CopyAttachedPourToLayer ();
 	    Draw ();
 	    break;
 	  }
@@ -1440,9 +1441,9 @@ NotifyMode (void)
 	    points[n - 1].X != Crosshair.AttachedLine.Point2.X ||
 	    points[n - 1].Y != Crosshair.AttachedLine.Point2.Y)
 	  {
-	    CreateNewPointInPolygon (&Crosshair.AttachedPolygon,
-				     Crosshair.AttachedLine.Point2.X,
-				     Crosshair.AttachedLine.Point2.Y);
+	    CreateNewPointInPour (&Crosshair.AttachedPour,
+				  Crosshair.AttachedLine.Point2.X,
+				  Crosshair.AttachedLine.Point2.Y);
 
 	    /* copy the coordinates */
 	    Crosshair.AttachedLine.Point1.X = Crosshair.AttachedLine.Point2.X;
@@ -1451,14 +1452,14 @@ NotifyMode (void)
 	break;
       }
 
-    case POLYGONHOLE_MODE:
+    case POURHOLE_MODE:
       {
 	switch (Crosshair.AttachedObject.State)
 	  {
 	    /* first notify, lookup object */
 	  case STATE_FIRST:
 	    Crosshair.AttachedObject.Type =
-	      SearchScreen (Note.X, Note.Y, POLYGON_TYPE,
+	      SearchScreen (Note.X, Note.Y, POUR_TYPE,
 			    &Crosshair.AttachedObject.Ptr1,
 			    &Crosshair.AttachedObject.Ptr2,
 			    &Crosshair.AttachedObject.Ptr3);
@@ -1480,8 +1481,8 @@ NotifyMode (void)
             /* second notify, insert new point into object */
           case STATE_SECOND:
             {
-	      PointTypePtr points = Crosshair.AttachedPolygon.Points;
-	      Cardinal n = Crosshair.AttachedPolygon.PointN;
+	      PointTypePtr points = Crosshair.AttachedPour.Points;
+	      Cardinal n = Crosshair.AttachedPour.PointN;
 	      POLYAREA *original, *new_hole, *result;
 	      FlagType Flags;
 
@@ -1495,8 +1496,8 @@ NotifyMode (void)
 		{
 		  /* Create POLYAREAs from the original polygon
 		   * and the new hole polygon */
-		  original = PolygonToPoly (Crosshair.AttachedObject.Ptr2);
-		  new_hole = PolygonToPoly (&Crosshair.AttachedPolygon);
+		  original = PourToPoly (Crosshair.AttachedObject.Ptr2);
+		  new_hole = PourToPoly (&Crosshair.AttachedPour);
 
 		  /* Subtract the hole from the original polygon shape */
 		  poly_Boolean_free (original, new_hole, &result, PBO_SUB);
@@ -1506,9 +1507,9 @@ NotifyMode (void)
 		   */
 		  SaveUndoSerialNumber ();
 		  Flags = ((PolygonType *)Crosshair.AttachedObject.Ptr2)->Flags;
-		  PolyToPolygonsOnLayer (PCB->Data, Crosshair.AttachedObject.Ptr1,
-					 result, Flags);
-		  RemoveObject (POLYGON_TYPE,
+		  PolyToPoursOnLayer (PCB->Data, Crosshair.AttachedObject.Ptr1,
+				      result, Flags);
+		  RemoveObject (POUR_TYPE,
 				Crosshair.AttachedObject.Ptr1,
 				Crosshair.AttachedObject.Ptr2,
 				Crosshair.AttachedObject.Ptr3);
@@ -1517,7 +1518,7 @@ NotifyMode (void)
 		  Draw ();
 
 		/* reset state of attached line */
-		memset (&Crosshair.AttachedPolygon, 0, sizeof (PolygonType));
+		memset (&Crosshair.AttachedPour, 0, sizeof (PourType));
 		Crosshair.AttachedLine.State = STATE_FIRST;
 		addedLines = 0;
 
@@ -1531,9 +1532,9 @@ NotifyMode (void)
 		  points[n - 1].X != Crosshair.AttachedLine.Point2.X ||
 		  points[n - 1].Y != Crosshair.AttachedLine.Point2.Y)
 		{
-		  CreateNewPointInPolygon (&Crosshair.AttachedPolygon,
-					   Crosshair.AttachedLine.Point2.X,
-					   Crosshair.AttachedLine.Point2.Y);
+		  CreateNewPointInPour (&Crosshair.AttachedPour,
+					Crosshair.AttachedLine.Point2.X,
+					Crosshair.AttachedLine.Point2.Y);
 
 		  /* copy the coordinates */
 		  Crosshair.AttachedLine.Point1.X = Crosshair.AttachedLine.Point2.X;
@@ -1731,16 +1732,15 @@ NotifyMode (void)
 	      else
 		{
 		  /* get starting point of nearest segment */
-		  if (Crosshair.AttachedObject.Type == POLYGON_TYPE)
+		  if (Crosshair.AttachedObject.Type == POUR_TYPE)
 		    {
-		      fake.poly =
-			(PolygonTypePtr) Crosshair.AttachedObject.Ptr2;
+		      fake.pour = (PourTypePtr) Crosshair.AttachedObject.Ptr2;
 		      polyIndex =
-			GetLowestDistancePolygonPoint (fake.poly, Note.X,
+			GetLowestDistancePourPoint (fake.pour, Note.X,
 						       Note.Y);
-		      fake.line.Point1 = fake.poly->Points[polyIndex];
-		      fake.line.Point2 = fake.poly->Points[
-			  prev_contour_point (fake.poly, polyIndex)];
+		      fake.line.Point1 = fake.pour->Points[polyIndex];
+		      fake.line.Point2 = fake.pour->Points[
+			  prev_contour_point (fake.pour, polyIndex)];
 		      Crosshair.AttachedObject.Ptr2 = &fake.line;
 
 		    }
@@ -1752,9 +1752,9 @@ NotifyMode (void)
 
 	  /* second notify, insert new point into object */
 	case STATE_SECOND:
-	  if (Crosshair.AttachedObject.Type == POLYGON_TYPE)
-	    InsertPointIntoObject (POLYGON_TYPE,
-				   Crosshair.AttachedObject.Ptr1, fake.poly,
+	  if (Crosshair.AttachedObject.Type == POUR_TYPE)
+	    InsertPointIntoObject (POUR_TYPE,
+				   Crosshair.AttachedObject.Ptr1, fake.pour,
 				   &polyIndex,
 				   InsertedPoint.X, InsertedPoint.Y, false, false);
 	  else
@@ -3110,23 +3110,23 @@ ActionMode (int argc, char **argv, int x, int y)
 		  }
 		break;
 	  
-	      case POLYGON_MODE:
+	      case POUR_MODE:
 		if (Crosshair.AttachedLine.State == STATE_FIRST)
 		  SetMode (ARROW_MODE);
 		else
 		  {
 		    SetMode (NO_MODE);
-		    SetMode (POLYGON_MODE);
+		    SetMode (POUR_MODE);
 		  }
 		break;
 
-	      case POLYGONHOLE_MODE:
+	      case POURHOLE_MODE:
 		if (Crosshair.AttachedLine.State == STATE_FIRST)
 		  SetMode (ARROW_MODE);
 		else
 		  {
 		    SetMode (NO_MODE);
-		    SetMode (POLYGONHOLE_MODE);
+		    SetMode (POURHOLE_MODE);
 		  }
 		break;
 
@@ -3155,11 +3155,11 @@ ActionMode (int argc, char **argv, int x, int y)
 	case F_PasteBuffer:
 	  SetMode (PASTEBUFFER_MODE);
 	  break;
-	case F_Polygon:
-	  SetMode (POLYGON_MODE);
+	case F_Pour:
+	  SetMode (POUR_MODE);
 	  break;
-	case F_PolygonHole:
-	  SetMode (POLYGONHOLE_MODE);
+	case F_PourHole:
+	  SetMode (POURHOLE_MODE);
 	  break;
 #ifndef HAVE_LIBSTROKE
 	case F_Release:
@@ -3203,9 +3203,9 @@ ActionMode (int argc, char **argv, int x, int y)
 	  else if (Settings.Mode == RECTANGLE_MODE
 		   && Crosshair.AttachedBox.State != STATE_FIRST)
 	    SetMode (RECTANGLE_MODE);
-	  else if (Settings.Mode == POLYGON_MODE
+	  else if (Settings.Mode == POUR_MODE
 		   && Crosshair.AttachedLine.State != STATE_FIRST)
-	    SetMode (POLYGON_MODE);
+	    SetMode (POUR_MODE);
 	  else
 	    {
 	      SaveMode ();
@@ -4688,6 +4688,9 @@ off are automatically deleted.
 static int
 ActionMorphPolygon (int argc, char **argv, int x, int y)
 {
+#warning FIXME Later
+  Message ("Morph polygon not implemented. Pours are nice though!\n");
+#if 0
   char *function = ARG (0);
   if (function)
     {
@@ -4722,6 +4725,7 @@ ActionMorphPolygon (int argc, char **argv, int x, int y)
 	  break;
 	}
     }
+#endif
   return 0;
 }
 
@@ -6209,7 +6213,7 @@ ActionUndo (int argc, char **argv, int x, int y)
   if (!function || !*function)
     {
       /* don't allow undo in the middle of an operation */
-      if (Settings.Mode != POLYGONHOLE_MODE &&
+      if (Settings.Mode != POURHOLE_MODE &&
 	  Crosshair.AttachedObject.State != STATE_FIRST)
 	return 1;
       if (Crosshair.AttachedBox.State != STATE_FIRST
@@ -6218,11 +6222,11 @@ ActionUndo (int argc, char **argv, int x, int y)
       /* undo the last operation */
 
       HideCrosshair (true);
-      if ((Settings.Mode == POLYGON_MODE ||
-           Settings.Mode == POLYGONHOLE_MODE) &&
-          Crosshair.AttachedPolygon.PointN)
+      if ((Settings.Mode == POUR_MODE ||
+           Settings.Mode == POURHOLE_MODE) &&
+          Crosshair.AttachedPour.PointN)
 	{
-	  GoToPreviousPoint ();
+	  GoToPreviousPourPoint ();
 	  RestoreCrosshair (true);
 	  return 0;
 	}
@@ -6382,9 +6386,9 @@ three "undone" lines.
 static int
 ActionRedo (int argc, char **argv, int x, int y)
 {
-  if (((Settings.Mode == POLYGON_MODE ||
-        Settings.Mode == POLYGONHOLE_MODE) &&
-       Crosshair.AttachedPolygon.PointN) ||
+  if (((Settings.Mode == POUR_MODE ||
+        Settings.Mode == POURHOLE_MODE) &&
+       Crosshair.AttachedPour.PointN) ||
       Crosshair.AttachedLine.State == STATE_SECOND)
     return 1;
   HideCrosshair (true);
@@ -6434,19 +6438,19 @@ static int
 ActionPolygon (int argc, char **argv, int x, int y)
 {
   char *function = ARG (0);
-  if (function && Settings.Mode == POLYGON_MODE)
+  if (function && Settings.Mode == POUR_MODE)
     {
       HideCrosshair (true);
       switch (GetFunctionID (function))
 	{
-	  /* close open polygon if possible */
+	  /* close open pour if possible */
 	case F_Close:
-	  ClosePolygon ();
+	  ClosePour ();
 	  break;
 
 	  /* go back to the previous point */
 	case F_PreviousPoint:
-	  GoToPreviousPoint ();
+	  GoToPreviousPourPoint ();
 	  break;
 	}
       RestoreCrosshair (true);
diff --git a/src/action.h b/src/action.h
index ee116e8..7529e8a 100644
--- a/src/action.h
+++ b/src/action.h
@@ -33,7 +33,7 @@
 
 #include "global.h"
 
-#define CLONE_TYPES LINE_TYPE | ARC_TYPE | VIA_TYPE | POLYGON_TYPE
+#define CLONE_TYPES LINE_TYPE | ARC_TYPE | VIA_TYPE | POUR_TYPE
 
 void ActionMovePointer (char *, char *);
 void ActionAdjustStyle (char *);
diff --git a/src/autoroute.c b/src/autoroute.c
index 3361f79..9b90e61 100644
--- a/src/autoroute.c
+++ b/src/autoroute.c
@@ -74,6 +74,7 @@
 #include "misc.h"
 #include "mtspace.h"
 #include "mymem.h"
+#include "pour.h"
 #include "polygon.h"
 #include "rats.h"
 #include "remove.h"
@@ -767,6 +768,8 @@ AddPolygon (PointerListType layergroupboxes[], Cardinal layer,
 			     polygon->BoundingBox.X2,
 			     polygon->BoundingBox.Y2,
 			     layergroup, polygon, style);
+#warning FIXME LATER
+#if 0
   if (polygon->PointN == 4 &&
       polygon->HoleIndexN == 0 &&
       (polygon->Points[0].X == polygon->Points[1].X ||
@@ -778,6 +781,7 @@ AddPolygon (PointerListType layergroupboxes[], Cardinal layer,
       (polygon->Points[3].X == polygon->Points[0].X ||
        polygon->Points[3].Y == polygon->Points[0].Y))
     is_not_rectangle = 0;
+#endif
   rb->flags.nonstraight = is_not_rectangle;
   rb->layer = layer;
   rb->came_from = ALL;
@@ -1183,12 +1187,16 @@ CreateRouteData ()
       }
       END_LOOP;
       /* add all polygons */
-      POLYGON_LOOP (LAYER_PTR (i));
+      POUR_LOOP (LAYER_PTR (i));
       {
-	if (TEST_FLAG (DRCFLAG, polygon))
-	  CLEAR_FLAG (DRCFLAG, polygon);
-	else
-	  AddPolygon (layergroupboxes, i, polygon, rd->styles[NUM_STYLES]);
+        POURPOLYGON_LOOP (pour);
+        {
+          if (TEST_FLAG (DRCFLAG, polygon))
+            CLEAR_FLAG (DRCFLAG, polygon);
+          else
+            AddPolygon (layergroupboxes, i, polygon, rd->styles[NUM_STYLES]);
+        }
+        END_LOOP;
       }
       END_LOOP;
       /* add all copper text */
@@ -5069,20 +5077,18 @@ IronDownAllUnfixedPaths (routedata_t * rd)
 	  int type = FindPin (&p->box, &pin);
 	  if (pin)
 	    {
-	      AddObjectToClearPolyUndoList (type,
+	      AddObjectToClearPourUndoList (type,
 					    pin->Element ? pin->Element : pin,
 					    pin, pin, false);
-	      RestoreToPolygon (PCB->Data, VIA_TYPE, LAYER_PTR (p->layer),
-				pin);
+	      RestoreToPours (PCB->Data, VIA_TYPE, LAYER_PTR (p->layer), pin);
 	      AddObjectToFlagUndoList (type,
 				       pin->Element ? pin->Element : pin, pin,
 				       pin);
 	      ASSIGN_THERM (p->layer, PCB->ThermStyle, pin);
-	      AddObjectToClearPolyUndoList (type,
+	      AddObjectToClearPourUndoList (type,
 					    pin->Element ? pin->Element : pin,
 					    pin, pin, true);
-	      ClearFromPolygon (PCB->Data, VIA_TYPE, LAYER_PTR (p->layer),
-				pin);
+	      ClearFromPours (PCB->Data, VIA_TYPE, LAYER_PTR (p->layer), pin);
 	      changed = true;
 	    }
 	}
diff --git a/src/buffer.c b/src/buffer.c
index b6d1e2b..ece6fb7 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -50,6 +50,7 @@
 #include "misc.h"
 #include "parse_l.h"
 #include "polygon.h"
+#include "pour.h"
 #include "rats.h"
 #include "rotate.h"
 #include "remove.h"
@@ -72,14 +73,14 @@ static void *AddLineToBuffer (LayerTypePtr, LineTypePtr);
 static void *AddArcToBuffer (LayerTypePtr, ArcTypePtr);
 static void *AddRatToBuffer (RatTypePtr);
 static void *AddTextToBuffer (LayerTypePtr, TextTypePtr);
-static void *AddPolygonToBuffer (LayerTypePtr, PolygonTypePtr);
+static void *AddPourToBuffer (LayerTypePtr, PourTypePtr);
 static void *AddElementToBuffer (ElementTypePtr);
 static void *MoveViaToBuffer (PinTypePtr);
 static void *MoveLineToBuffer (LayerTypePtr, LineTypePtr);
 static void *MoveArcToBuffer (LayerTypePtr, ArcTypePtr);
 static void *MoveRatToBuffer (RatTypePtr);
 static void *MoveTextToBuffer (LayerTypePtr, TextTypePtr);
-static void *MovePolygonToBuffer (LayerTypePtr, PolygonTypePtr);
+static void *MovePourToBuffer (LayerTypePtr, PourTypePtr);
 static void *MoveElementToBuffer (ElementTypePtr);
 static void SwapBuffer (BufferTypePtr);
 
@@ -93,7 +94,8 @@ static DataTypePtr Dest, Source;
 static ObjectFunctionType AddBufferFunctions = {
   AddLineToBuffer,
   AddTextToBuffer,
-  AddPolygonToBuffer,
+  NULL,
+  AddPourToBuffer,
   AddViaToBuffer,
   AddElementToBuffer,
   NULL,
@@ -108,10 +110,17 @@ static ObjectFunctionType AddBufferFunctions = {
 {
 MoveLineToBuffer,
     MoveTextToBuffer,
-    MovePolygonToBuffer,
+    NULL,
+    MovePourToBuffer,
     MoveViaToBuffer,
     MoveElementToBuffer,
-    NULL, NULL, NULL, NULL, NULL, MoveArcToBuffer, MoveRatToBuffer};
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    MoveArcToBuffer,
+    MoveRatToBuffer};
 
 static int ExtraFlag = 0;
 
@@ -186,18 +195,18 @@ AddTextToBuffer (LayerTypePtr Layer, TextTypePtr Text)
 }
 
 /* ---------------------------------------------------------------------------
- * copies a polygon to buffer
+ * copies a pour to buffer
  */
 static void *
-AddPolygonToBuffer (LayerTypePtr Layer, PolygonTypePtr Polygon)
+AddPourToBuffer (LayerTypePtr Layer, PourTypePtr Pour)
 {
   LayerTypePtr layer = &Dest->Layer[GetLayerNumber (Source, Layer)];
-  PolygonTypePtr polygon;
+  PourTypePtr pour;
 
-  polygon = CreateNewPolygon (layer, Polygon->Flags);
-  CopyPolygonLowLevel (polygon, Polygon);
-  CLEAR_FLAG (FOUNDFLAG | ExtraFlag, polygon);
-  return (polygon);
+  pour = CreateNewPour (layer, Pour->Flags);
+  CopyPourLowLevel (pour, Pour);
+  CLEAR_FLAG (FOUNDFLAG | ExtraFlag, pour);
+  return (pour);
 }
 
 /* ---------------------------------------------------------------------------
@@ -240,7 +249,7 @@ MoveViaToBuffer (PinTypePtr Via)
 {
   PinTypePtr via;
 
-  RestoreToPolygon (Source, VIA_TYPE, Via, Via);
+  RestoreToPours (Source, VIA_TYPE, Via, Via);
   r_delete_entry (Source->via_tree, (BoxType *) Via);
   via = GetViaMemory (Dest);
   *via = *Via;
@@ -255,7 +264,7 @@ MoveViaToBuffer (PinTypePtr Via)
   if (!Dest->via_tree)
     Dest->via_tree = r_create_tree (NULL, 0, 0);
   r_insert_entry (Dest->via_tree, (BoxType *) via, 0);
-  ClearFromPolygon (Dest, VIA_TYPE, via, via);
+  ClearFromPours (Dest, VIA_TYPE, via, via);
   return (via);
 }
 
@@ -293,7 +302,7 @@ MoveLineToBuffer (LayerTypePtr Layer, LineTypePtr Line)
   LayerTypePtr lay;
   LineTypePtr line;
 
-  RestoreToPolygon (Source, LINE_TYPE, Layer, Line);
+  RestoreToPours (Source, LINE_TYPE, Layer, Line);
   r_delete_entry (Layer->line_tree, (BoxTypePtr) Line);
   lay = &Dest->Layer[GetLayerNumber (Source, Layer)];
   line = GetLineMemory (lay);
@@ -310,7 +319,7 @@ MoveLineToBuffer (LayerTypePtr Layer, LineTypePtr Line)
   if (!lay->line_tree)
     lay->line_tree = r_create_tree (NULL, 0, 0);
   r_insert_entry (lay->line_tree, (BoxTypePtr) line, 0);
-  ClearFromPolygon (Dest, LINE_TYPE, lay, line);
+  ClearFromPours (Dest, LINE_TYPE, lay, line);
   return (line);
 }
 
@@ -323,7 +332,7 @@ MoveArcToBuffer (LayerTypePtr Layer, ArcTypePtr Arc)
   LayerTypePtr lay;
   ArcTypePtr arc;
 
-  RestoreToPolygon (Source, ARC_TYPE, Layer, Arc);
+  RestoreToPours (Source, ARC_TYPE, Layer, Arc);
   r_delete_entry (Layer->arc_tree, (BoxTypePtr) Arc);
   lay = &Dest->Layer[GetLayerNumber (Source, Layer)];
   arc = GetArcMemory (lay);
@@ -340,7 +349,7 @@ MoveArcToBuffer (LayerTypePtr Layer, ArcTypePtr Arc)
   if (!lay->arc_tree)
     lay->arc_tree = r_create_tree (NULL, 0, 0);
   r_insert_entry (lay->arc_tree, (BoxTypePtr) arc, 0);
-  ClearFromPolygon (Dest, ARC_TYPE, lay, arc);
+  ClearFromPours (Dest, ARC_TYPE, lay, arc);
   return (arc);
 }
 
@@ -354,7 +363,7 @@ MoveTextToBuffer (LayerTypePtr Layer, TextTypePtr Text)
   LayerTypePtr lay;
 
   r_delete_entry (Layer->text_tree, (BoxTypePtr) Text);
-  RestoreToPolygon (Source, TEXT_TYPE, Layer, Text);
+  RestoreToPours (Source, TEXT_TYPE, Layer, Text);
   lay = &Dest->Layer[GetLayerNumber (Source, Layer)];
   text = GetTextMemory (lay);
   *text = *Text;
@@ -368,36 +377,39 @@ MoveTextToBuffer (LayerTypePtr Layer, TextTypePtr Text)
   if (!lay->text_tree)
     lay->text_tree = r_create_tree (NULL, 0, 0);
   r_insert_entry (lay->text_tree, (BoxTypePtr) text, 0);
-  ClearFromPolygon (Dest, TEXT_TYPE, lay, text);
+  ClearFromPours (Dest, TEXT_TYPE, lay, text);
   return (text);
 }
 
 /* ---------------------------------------------------------------------------
- * moves a polygon to buffer. Doesn't allocate memory for the points
+ * moves a pour to buffer. Doesn't allocate memory for the points
  */
 static void *
-MovePolygonToBuffer (LayerTypePtr Layer, PolygonTypePtr Polygon)
+MovePourToBuffer (LayerTypePtr Layer, PourTypePtr Pour)
 {
   LayerTypePtr lay;
-  PolygonTypePtr polygon;
+  PourTypePtr pour;
+  Cardinal i;
 
-  r_delete_entry (Layer->polygon_tree, (BoxTypePtr) Polygon);
+  r_delete_entry (Layer->pour_tree, (BoxTypePtr) Pour);
   lay = &Dest->Layer[GetLayerNumber (Source, Layer)];
-  polygon = GetPolygonMemory (lay);
-  *polygon = *Polygon;
-  CLEAR_FLAG (FOUNDFLAG, polygon);
-  if (Polygon != &Layer->Polygon[--Layer->PolygonN])
-  {
-  *Polygon = Layer->Polygon[Layer->PolygonN];
-  r_substitute (Layer->polygon_tree,
-		(BoxTypePtr) & Layer->Polygon[Layer->PolygonN],
-		(BoxTypePtr) Polygon);
-  }
-  memset (&Layer->Polygon[Layer->PolygonN], 0, sizeof (PolygonType));
-  if (!lay->polygon_tree)
-    lay->polygon_tree = r_create_tree (NULL, 0, 0);
-  r_insert_entry (lay->polygon_tree, (BoxTypePtr) polygon, 0);
-  return (polygon);
+  pour = GetPourMemory (lay);
+  *pour = *Pour;
+  CLEAR_FLAG (FOUNDFLAG, pour);
+  if (Pour != &Layer->Pour[--Layer->PourN])
+    {
+      *Pour = Layer->Pour[Layer->PourN];
+      r_substitute (Layer->pour_tree,
+                    (BoxTypePtr) & Layer->Pour[Layer->PourN],
+                    (BoxTypePtr) Pour);
+      for (i = 0; i < Pour->PolygonN; i++)
+        Pour->Polygons[i].ParentPour = Pour;
+    }
+  memset (&Layer->Pour[Layer->PourN], 0, sizeof (PourType));
+  if (!lay->pour_tree)
+    lay->pour_tree = r_create_tree (NULL, 0, 0);
+  r_insert_entry (lay->pour_tree, (BoxTypePtr) pour, 0);
+  return (pour);
 }
 
 /* ---------------------------------------------------------------------------
@@ -419,14 +431,14 @@ MoveElementToBuffer (ElementTypePtr Element)
   *element = *Element;
   PIN_LOOP (element);
   {
-    RestoreToPolygon(Source, PIN_TYPE, Element, pin);
+    RestoreToPours(Source, PIN_TYPE, Element, pin);
     CLEAR_FLAG (WARNFLAG | FOUNDFLAG, pin);
     pin->Element = element;
   }
   END_LOOP;
   PAD_LOOP (element);
   {
-    RestoreToPolygon(Source, PAD_TYPE, Element, pad);
+    RestoreToPours(Source, PAD_TYPE, Element, pad);
     CLEAR_FLAG (WARNFLAG | FOUNDFLAG, pad);
     pad->Element = element;
   }
@@ -442,12 +454,12 @@ MoveElementToBuffer (ElementTypePtr Element)
    */
   PIN_LOOP (element);
   {
-    ClearFromPolygon (Dest, PIN_TYPE, element, pin);
+    ClearFromPours (Dest, PIN_TYPE, element, pin);
   }
   END_LOOP;
   PAD_LOOP (element);
   {
-    ClearFromPolygon (Dest, PAD_TYPE, element, pad);
+    ClearFromPours (Dest, PAD_TYPE, element, pad);
   }
   END_LOOP;
 
@@ -991,6 +1003,8 @@ SmashBufferElement (BufferTypePtr Buffer)
   return (true);
 }
 
+#warning FIXME Later
+#if 0
 /*---------------------------------------------------------------------------
  *
  * see if a polygon is a rectangle.  If so, canonicalize it.
@@ -1027,6 +1041,7 @@ polygon_is_rectangle (PolygonTypePtr poly)
     return 1;
   return 0;
 }
+#endif
 
 /*---------------------------------------------------------------------------
  *
@@ -1093,34 +1108,40 @@ ConvertBufferToElement (BufferTypePtr Buffer)
       hasParts = true;
     }
     END_LOOP;
-    POLYGON_LOOP (layer);
+#warning FIXME Later
+#if 0
+    POUR_LOOP (layer);
     {
-      int x1, y1, x2, y2, w, h, t;
-
-      if (! polygon_is_rectangle (polygon))
-        {
-          crooked = true;
-	  continue;
-        }
-
-      w = polygon->Points[2].X - polygon->Points[0].X;
-      h = polygon->Points[1].Y - polygon->Points[0].Y;
-      t = (w < h) ? w : h;
-      x1 = polygon->Points[0].X + t/2;
-      y1 = polygon->Points[0].Y + t/2;
-      x2 = x1 + (w-t);
-      y2 = y1 + (h-t);
-
-      sprintf (num, "%d", pin_n++);
-      CreateNewPad (Element,
-		    x1, y1, x2, y2, t,
-		    2 * Settings.Keepaway,
-		    t + Settings.Keepaway,
-		    NULL, num,
-		    MakeFlags (SQUAREFLAG | (SWAP_IDENT ? ONSOLDERFLAG : NOFLAG)));
-      hasParts = true;
+      POURPOLYGON_LOOP (pour);
+      {
+        int x1, y1, x2, y2, w, h, t;
+
+        if (! polygon_is_rectangle (polygon))
+          {
+            crooked = true;
+            continue;
+          }
+
+        w = polygon->Points[2].X - polygon->Points[0].X;
+        h = polygon->Points[1].Y - polygon->Points[0].Y;
+        t = (w < h) ? w : h;
+        x1 = polygon->Points[0].X + t/2;
+        y1 = polygon->Points[0].Y + t/2;
+        x2 = x1 + (w-t);
+        y2 = y1 + (h-t);
+
+        sprintf (num, "%d", pin_n++);
+        CreateNewPad (Element, x1, y1, x2, y2, t,
+                      2 * Settings.Keepaway,
+                      t + Settings.Keepaway,
+                      NULL, num,
+                      MakeFlags (SQUAREFLAG | (SWAP_IDENT ? ONSOLDERFLAG : NOFLAG)));
+        hasParts = true;
+      }
+      END_LOOP;
     }
     END_LOOP;
+#endif
   }
   END_LOOP;
   /* now get the opposite side pads */
@@ -1273,6 +1294,8 @@ RotateBuffer (BufferTypePtr Buffer, BYTE Number)
     r_insert_entry (layer->text_tree, (BoxTypePtr) text, 0);
   }
   ENDALL_LOOP;
+#warning FIXME Later
+#if 0
   ALLPOLYGON_LOOP (Buffer->Data);
   {
     r_delete_entry (layer->polygon_tree, (BoxTypePtr) polygon);
@@ -1280,6 +1303,14 @@ RotateBuffer (BufferTypePtr Buffer, BYTE Number)
     r_insert_entry (layer->polygon_tree, (BoxTypePtr) polygon, 0);
   }
   ENDALL_LOOP;
+#endif
+  ALLPOUR_LOOP (Buffer->Data);
+  {
+    r_delete_entry (layer->pour_tree, (BoxTypePtr) pour);
+    RotatePourLowLevel (pour, Buffer->X, Buffer->Y, Number);
+    r_insert_entry (layer->pour_tree, (BoxTypePtr) pour, 0);
+  }
+  ENDALL_LOOP;
 
   /* finally the origin and the bounding box */
   ROTATE (Buffer->X, Buffer->Y, Buffer->X, Buffer->Y, Number);
@@ -1331,7 +1362,7 @@ FreeRotateElementLowLevel (DataTypePtr Data, ElementTypePtr Element,
     /* pre-delete the pins from the pin-tree before their coordinates change */
     if (Data)
       r_delete_entry (Data->pin_tree, (BoxType *) pin);
-    RestoreToPolygon (Data, PIN_TYPE, Element, pin);
+    RestoreToPours (Data, PIN_TYPE, Element, pin);
     free_rotate (&pin->X, &pin->Y, X, Y, cosa, sina);
     SetPinBoundingBox (pin);
   }
@@ -1341,7 +1372,7 @@ FreeRotateElementLowLevel (DataTypePtr Data, ElementTypePtr Element,
     /* pre-delete the pads before their coordinates change */
     if (Data)
       r_delete_entry (Data->pad_tree, (BoxType *) pad);
-    RestoreToPolygon (Data, PAD_TYPE, Element, pad);
+    RestoreToPours (Data, PAD_TYPE, Element, pad);
     free_rotate (&pad->Point1.X, &pad->Point1.Y, X, Y, cosa, sina);
     free_rotate (&pad->Point2.X, &pad->Point2.Y, X, Y, cosa, sina);
     SetLineBoundingBox ((LineType *) pad);
@@ -1357,7 +1388,7 @@ FreeRotateElementLowLevel (DataTypePtr Data, ElementTypePtr Element,
 
   free_rotate (&Element->MarkX, &Element->MarkY, X, Y, cosa, sina);
   SetElementBoundingBox (Data, Element, &PCB->Font);
-  ClearFromPolygon (Data, ELEMENT_TYPE, Element, Element);
+  ClearFromPours (Data, ELEMENT_TYPE, Element, Element);
 }
 
 void
@@ -1406,6 +1437,8 @@ FreeRotateBuffer (BufferTypePtr Buffer, double Angle)
   }
   ENDALL_LOOP;
   /* FIXME: rotate text */
+#warning FIXME Later
+#if 0
   ALLPOLYGON_LOOP (Buffer->Data);
   {
     r_delete_entry (layer->polygon_tree, (BoxTypePtr) polygon);
@@ -1418,6 +1451,19 @@ FreeRotateBuffer (BufferTypePtr Buffer, double Angle)
     r_insert_entry (layer->polygon_tree, (BoxTypePtr) polygon, 0);
   }
   ENDALL_LOOP;
+#endif
+  ALLPOUR_LOOP (Buffer->Data);
+  {
+    r_delete_entry (layer->pour_tree, (BoxTypePtr) pour);
+    POURPOINT_LOOP (pour);
+    {
+      free_rotate (&point->X, &point->Y, Buffer->X, Buffer->Y, cosa, sina);
+    }
+    END_LOOP;
+    SetPourBoundingBox (pour);
+    r_insert_entry (layer->pour_tree, (BoxTypePtr) pour, 0);
+  }
+  ENDALL_LOOP;
 
   SetBufferBoundingBox (Buffer);
 }
@@ -1523,6 +1569,8 @@ MirrorBuffer (BufferTypePtr Buffer)
     SetArcBoundingBox (arc);
   }
   ENDALL_LOOP;
+#warning FIXME Later
+#if 0
   ALLPOLYGON_LOOP (Buffer->Data);
   {
     POLYGONPOINT_LOOP (polygon);
@@ -1534,6 +1582,7 @@ MirrorBuffer (BufferTypePtr Buffer)
     SetPolygonBoundingBox (polygon);
   }
   ENDALL_LOOP;
+#endif
   SetBufferBoundingBox (Buffer);
 }
 
@@ -1588,6 +1637,8 @@ SwapBuffer (BufferTypePtr Buffer)
     r_insert_entry (layer->arc_tree, (BoxTypePtr) arc, 0);
   }
   ENDALL_LOOP;
+#warning FIXME Later
+#if 0
   ALLPOLYGON_LOOP (Buffer->Data);
   {
     r_delete_entry (layer->polygon_tree, (BoxTypePtr) polygon);
@@ -1602,6 +1653,7 @@ SwapBuffer (BufferTypePtr Buffer)
     /* hmmm, how to handle clip */
   }
   ENDALL_LOOP;
+#endif
   ALLTEXT_LOOP (Buffer->Data);
   {
     r_delete_entry (layer->text_tree, (BoxTypePtr) text);
diff --git a/src/change.c b/src/change.c
index 0c55c69..3733071 100644
--- a/src/change.c
+++ b/src/change.c
@@ -50,6 +50,7 @@
 #include "misc.h"
 #include "mirror.h"
 #include "polygon.h"
+#include "pour.h"
 #include "rats.h"
 #include "remove.h"
 #include "rtree.h"
@@ -83,6 +84,7 @@ static void *ChangeViaMaskSize (PinTypePtr);
 static void *ChangeLineSize (LayerTypePtr, LineTypePtr);
 static void *ChangeLineClearSize (LayerTypePtr, LineTypePtr);
 static void *ChangePolygonClearSize (LayerTypePtr, PolygonTypePtr);
+static void *ChangePourClearSize (LayerTypePtr, PourTypePtr);
 static void *ChangeArcSize (LayerTypePtr, ArcTypePtr);
 static void *ChangeArcClearSize (LayerTypePtr, ArcTypePtr);
 static void *ChangeTextSize (LayerTypePtr, TextTypePtr);
@@ -123,7 +125,7 @@ static void *ClrArcJoin (LayerTypePtr, ArcTypePtr);
 static void *ChangeTextJoin (LayerTypePtr, TextTypePtr);
 static void *SetTextJoin (LayerTypePtr, TextTypePtr);
 static void *ClrTextJoin (LayerTypePtr, TextTypePtr);
-static void *ChangePolyClear (LayerTypePtr, PolygonTypePtr);
+static void *ChangePourClear (LayerTypePtr, PourTypePtr);
 
 /* ---------------------------------------------------------------------------
  * some local identifiers
@@ -134,7 +136,8 @@ static char *NewName;		/* new name */
 static ObjectFunctionType ChangeSizeFunctions = {
   ChangeLineSize,
   ChangeTextSize,
-  ChangePolyClear,
+  NULL,
+  ChangePourClear,
   ChangeViaSize,
   ChangeElementSize,		/* changes silk screen line width */
   ChangeElementNameSize,
@@ -149,6 +152,7 @@ static ObjectFunctionType Change2ndSizeFunctions = {
   NULL,
   NULL,
   NULL,
+  NULL,
   ChangeVia2ndSize,
   ChangeElement2ndSize,
   NULL,
@@ -163,6 +167,7 @@ static ObjectFunctionType ChangeThermalFunctions = {
   NULL,
   NULL,
   NULL,
+  NULL,
   ChangeViaThermal,
   NULL,
   NULL,
@@ -177,6 +182,7 @@ static ObjectFunctionType ChangeClearSizeFunctions = {
   ChangeLineClearSize,
   NULL,
   ChangePolygonClearSize, /* just to tell the user not to :-) */
+  ChangePourClearSize, /* just to tell the user not to :-) */
   ChangeViaClearSize,
   NULL,
   NULL,
@@ -191,6 +197,7 @@ static ObjectFunctionType ChangeNameFunctions = {
   ChangeLineName,
   ChangeTextName,
   NULL,
+  NULL,
   ChangeViaName,
   ChangeElementName,
   NULL,
@@ -206,6 +213,7 @@ static ObjectFunctionType ChangeSquareFunctions = {
   NULL,
   NULL,
   NULL,
+  NULL,
   ChangeElementSquare,
   NULL,
   ChangePinSquare,
@@ -226,6 +234,7 @@ static ObjectFunctionType ChangeJoinFunctions = {
   NULL,
   NULL,
   NULL,
+  NULL,
   ChangeArcJoin,
   NULL
 };
@@ -233,6 +242,7 @@ static ObjectFunctionType ChangeOctagonFunctions = {
   NULL,
   NULL,
   NULL,
+  NULL,
   ChangeViaOctagon,
   ChangeElementOctagon,
   NULL,
@@ -247,6 +257,7 @@ static ObjectFunctionType ChangeMaskSizeFunctions = {
   NULL,
   NULL,
   NULL,
+  NULL,
   ChangeViaMaskSize,
 #if 0
   ChangeElementMaskSize,
@@ -266,6 +277,7 @@ static ObjectFunctionType SetSquareFunctions = {
   NULL,
   NULL,
   NULL,
+  NULL,
   SetElementSquare,
   NULL,
   SetPinSquare,
@@ -286,6 +298,7 @@ static ObjectFunctionType SetJoinFunctions = {
   NULL,
   NULL,
   NULL,
+  NULL,
   SetArcJoin,
   NULL
 };
@@ -293,6 +306,7 @@ static ObjectFunctionType SetOctagonFunctions = {
   NULL,
   NULL,
   NULL,
+  NULL,
   SetViaOctagon,
   SetElementOctagon,
   NULL,
@@ -308,6 +322,7 @@ static ObjectFunctionType ClrSquareFunctions = {
   NULL,
   NULL,
   NULL,
+  NULL,
   ClrElementSquare,
   NULL,
   ClrPinSquare,
@@ -328,6 +343,7 @@ static ObjectFunctionType ClrJoinFunctions = {
   NULL,
   NULL,
   NULL,
+  NULL,
   ClrArcJoin,
   NULL
 };
@@ -335,6 +351,7 @@ static ObjectFunctionType ClrOctagonFunctions = {
   NULL,
   NULL,
   NULL,
+  NULL,
   ClrViaOctagon,
   ClrElementOctagon,
   NULL,
@@ -353,15 +370,15 @@ static ObjectFunctionType ClrOctagonFunctions = {
 static void *
 ChangeViaThermal (PinTypePtr Via)
 {
-  AddObjectToClearPolyUndoList (VIA_TYPE, Via, Via, Via, false);
-  RestoreToPolygon (PCB->Data, VIA_TYPE, CURRENT, Via);
+  AddObjectToClearPourUndoList (VIA_TYPE, Via, Via, Via, false);
+  RestoreToPours (PCB->Data, VIA_TYPE, CURRENT, Via);
   AddObjectToFlagUndoList (VIA_TYPE, Via, Via, Via);
   if (!Delta)			/* remove the thermals */
     CLEAR_THERM (INDEXOFCURRENT, Via);
   else
     ASSIGN_THERM (INDEXOFCURRENT, Delta, Via);
-  AddObjectToClearPolyUndoList (VIA_TYPE, Via, Via, Via, true);
-  ClearFromPolygon (PCB->Data, VIA_TYPE, CURRENT, Via);
+  AddObjectToClearPourUndoList (VIA_TYPE, Via, Via, Via, true);
+  ClearFromPours (PCB->Data, VIA_TYPE, CURRENT, Via);
   DrawVia (Via, 0);
   return Via;
 }
@@ -373,15 +390,15 @@ ChangeViaThermal (PinTypePtr Via)
 static void *
 ChangePinThermal (ElementTypePtr element, PinTypePtr Pin)
 {
-  AddObjectToClearPolyUndoList (PIN_TYPE, element, Pin, Pin, false);
-  RestoreToPolygon (PCB->Data, VIA_TYPE, CURRENT, Pin);
+  AddObjectToClearPourUndoList (PIN_TYPE, element, Pin, Pin, false);
+  RestoreToPours (PCB->Data, VIA_TYPE, CURRENT, Pin);
   AddObjectToFlagUndoList (PIN_TYPE, element, Pin, Pin);
   if (!Delta)			/* remove the thermals */
     CLEAR_THERM (INDEXOFCURRENT, Pin);
   else
     ASSIGN_THERM (INDEXOFCURRENT, Delta, Pin);
-  AddObjectToClearPolyUndoList (PIN_TYPE, element, Pin, Pin, true);
-  ClearFromPolygon (PCB->Data, VIA_TYPE, CURRENT, Pin);
+  AddObjectToClearPourUndoList (PIN_TYPE, element, Pin, Pin, true);
+  ClearFromPours (PCB->Data, VIA_TYPE, CURRENT, Pin);
   DrawPin (Pin, 0);
   return Pin;
 }
@@ -405,7 +422,7 @@ ChangeViaSize (PinTypePtr Via)
       AddObjectToSizeUndoList (VIA_TYPE, Via, Via, Via);
       EraseVia (Via);
       r_delete_entry (PCB->Data->via_tree, (BoxType *) Via);
-      RestoreToPolygon (PCB->Data, PIN_TYPE, Via, Via);
+      RestoreToPours (PCB->Data, PIN_TYPE, Via, Via);
       if (Via->Mask)
 	{
 	  AddObjectToMaskSizeUndoList (VIA_TYPE, Via, Via, Via);
@@ -414,7 +431,7 @@ ChangeViaSize (PinTypePtr Via)
       Via->Thickness = value;
       SetPinBoundingBox (Via);
       r_insert_entry (PCB->Data->via_tree, (BoxType *) Via, 0);
-      ClearFromPolygon (PCB->Data, VIA_TYPE, Via, Via);
+      ClearFromPours (PCB->Data, VIA_TYPE, Via, Via);
       DrawVia (Via, 0);
       return (Via);
     }
@@ -443,10 +460,10 @@ ChangeVia2ndSize (PinTypePtr Via)
       Via->DrillingHole = value;
       if (TEST_FLAG (HOLEFLAG, Via))
 	{
-	  RestoreToPolygon (PCB->Data, VIA_TYPE, Via, Via);
+	  RestoreToPours (PCB->Data, VIA_TYPE, Via, Via);
 	  AddObjectToSizeUndoList (VIA_TYPE, Via, Via, Via);
 	  Via->Thickness = value;
-	  ClearFromPolygon (PCB->Data, VIA_TYPE, Via, Via);
+	  ClearFromPours (PCB->Data, VIA_TYPE, Via, Via);
 	}
       DrawVia (Via, 0);
       return (Via);
@@ -475,14 +492,14 @@ ChangeViaClearSize (PinTypePtr Via)
     value = PCB->Bloat * 2 + 2;
   if (Via->Clearance == value)
     return NULL;
-  RestoreToPolygon (PCB->Data, VIA_TYPE, Via, Via);
+  RestoreToPours (PCB->Data, VIA_TYPE, Via, Via);
   AddObjectToClearSizeUndoList (VIA_TYPE, Via, Via, Via);
   EraseVia (Via);
   r_delete_entry (PCB->Data->via_tree, (BoxType *) Via);
   Via->Clearance = value;
   SetPinBoundingBox (Via);
   r_insert_entry (PCB->Data->via_tree, (BoxType *) Via, 0);
-  ClearFromPolygon (PCB->Data, VIA_TYPE, Via, Via);
+  ClearFromPours (PCB->Data, VIA_TYPE, Via, Via);
   DrawVia (Via, 0);
   Via->Element = NULL;
   return (Via);
@@ -509,12 +526,12 @@ ChangePinSize (ElementTypePtr Element, PinTypePtr Pin)
       AddObjectToMaskSizeUndoList (PIN_TYPE, Element, Pin, Pin);
       ErasePin (Pin);
       r_delete_entry (PCB->Data->pin_tree, &Pin->BoundingBox);
-      RestoreToPolygon (PCB->Data, PIN_TYPE, Element, Pin);
+      RestoreToPours (PCB->Data, PIN_TYPE, Element, Pin);
       Pin->Mask += value - Pin->Thickness;
       Pin->Thickness = value;
       /* SetElementBB updates all associated rtrees */
       SetElementBoundingBox (PCB->Data, Element, &PCB->Font);
-      ClearFromPolygon (PCB->Data, PIN_TYPE, Element, Pin);
+      ClearFromPours (PCB->Data, PIN_TYPE, Element, Pin);
       DrawPin (Pin, 0);
       return (Pin);
     }
@@ -541,14 +558,14 @@ ChangePinClearSize (ElementTypePtr Element, PinTypePtr Pin)
     value = PCB->Bloat * 2 + 2;
   if (Pin->Clearance == value)
     return NULL;
-  RestoreToPolygon (PCB->Data, PIN_TYPE, Element, Pin);
+  RestoreToPours (PCB->Data, PIN_TYPE, Element, Pin);
   AddObjectToClearSizeUndoList (PIN_TYPE, Element, Pin, Pin);
   ErasePin (Pin);
   r_delete_entry (PCB->Data->pin_tree, &Pin->BoundingBox);
   Pin->Clearance = value;
   /* SetElementBB updates all associated rtrees */
   SetElementBoundingBox (PCB->Data, Element, &PCB->Font);
-  ClearFromPolygon (PCB->Data, PIN_TYPE, Element, Pin);
+  ClearFromPours (PCB->Data, PIN_TYPE, Element, Pin);
   DrawPin (Pin, 0);
   return (Pin);
 }
@@ -568,14 +585,14 @@ ChangePadSize (ElementTypePtr Element, PadTypePtr Pad)
     {
       AddObjectToSizeUndoList (PAD_TYPE, Element, Pad, Pad);
       AddObjectToMaskSizeUndoList (PAD_TYPE, Element, Pad, Pad);
-      RestoreToPolygon (PCB->Data, PAD_TYPE, Element, Pad);
+      RestoreToPours (PCB->Data, PAD_TYPE, Element, Pad);
       ErasePad (Pad);
       r_delete_entry (PCB->Data->pad_tree, &Pad->BoundingBox);
       Pad->Mask += value - Pad->Thickness;
       Pad->Thickness = value;
       /* SetElementBB updates all associated rtrees */
       SetElementBoundingBox (PCB->Data, Element, &PCB->Font);
-      ClearFromPolygon (PCB->Data, PAD_TYPE, Element, Pad);
+      ClearFromPours (PCB->Data, PAD_TYPE, Element, Pad);
       DrawPad (Pad, 0);
       return (Pad);
     }
@@ -603,13 +620,13 @@ ChangePadClearSize (ElementTypePtr Element, PadTypePtr Pad)
   if (value == Pad->Clearance)
     return NULL;
   AddObjectToClearSizeUndoList (PAD_TYPE, Element, Pad, Pad);
-  RestoreToPolygon (PCB->Data, PAD_TYPE, Element, Pad);
+  RestoreToPours (PCB->Data, PAD_TYPE, Element, Pad);
   ErasePad (Pad);
   r_delete_entry (PCB->Data->pad_tree, &Pad->BoundingBox);
   Pad->Clearance = value;
   /* SetElementBB updates all associated rtrees */
   SetElementBoundingBox (PCB->Data, Element, &PCB->Font);
-  ClearFromPolygon (PCB->Data, PAD_TYPE, Element, Pad);
+  ClearFromPours (PCB->Data, PAD_TYPE, Element, Pad);
   DrawPad (Pad, 0);
   return Pad;
 }
@@ -643,10 +660,10 @@ ChangeElement2ndSize (ElementTypePtr Element)
 	DrawPin (pin, 0);
 	if (TEST_FLAG (HOLEFLAG, pin))
 	  {
-	    RestoreToPolygon (PCB->Data, PIN_TYPE, Element, pin);
+	    RestoreToPours (PCB->Data, PIN_TYPE, Element, pin);
 	    AddObjectToSizeUndoList (PIN_TYPE, Element, pin, pin);
 	    pin->Thickness = value;
-	    ClearFromPolygon (PCB->Data, PIN_TYPE, Element, pin);
+	    ClearFromPours (PCB->Data, PIN_TYPE, Element, pin);
 	  }
       }
   }
@@ -680,10 +697,10 @@ ChangePin2ndSize (ElementTypePtr Element, PinTypePtr Pin)
       DrawPin (Pin, 0);
       if (TEST_FLAG (HOLEFLAG, Pin))
 	{
-	  RestoreToPolygon (PCB->Data, PIN_TYPE, Element, Pin);
+	  RestoreToPours (PCB->Data, PIN_TYPE, Element, Pin);
 	  AddObjectToSizeUndoList (PIN_TYPE, Element, Pin, Pin);
 	  Pin->Thickness = value;
-	  ClearFromPolygon (PCB->Data, PIN_TYPE, Element, Pin);
+	  ClearFromPours (PCB->Data, PIN_TYPE, Element, Pin);
 	}
       return (Pin);
     }
@@ -707,11 +724,11 @@ ChangeLineSize (LayerTypePtr Layer, LineTypePtr Line)
       AddObjectToSizeUndoList (LINE_TYPE, Layer, Line, Line);
       EraseLine (Line);
       r_delete_entry (Layer->line_tree, (BoxTypePtr) Line);
-      RestoreToPolygon (PCB->Data, LINE_TYPE, Layer, Line);
+      RestoreToPours (PCB->Data, LINE_TYPE, Layer, Line);
       Line->Thickness = value;
       SetLineBoundingBox (Line);
       r_insert_entry (Layer->line_tree, (BoxTypePtr) Line, 0);
-      ClearFromPolygon (PCB->Data, LINE_TYPE, Layer, Line);
+      ClearFromPours (PCB->Data, LINE_TYPE, Layer, Line);
       DrawLine (Layer, Line, 0);
       return (Line);
     }
@@ -733,7 +750,7 @@ ChangeLineClearSize (LayerTypePtr Layer, LineTypePtr Line)
   if (value != Line->Clearance)
     {
       AddObjectToClearSizeUndoList (LINE_TYPE, Layer, Line, Line);
-      RestoreToPolygon (PCB->Data, LINE_TYPE, Layer, Line);
+      RestoreToPours (PCB->Data, LINE_TYPE, Layer, Line);
       EraseLine (Line);
       r_delete_entry (Layer->line_tree, (BoxTypePtr) Line);
       Line->Clearance = value;
@@ -744,7 +761,7 @@ ChangeLineClearSize (LayerTypePtr Layer, LineTypePtr Line)
 	}
       SetLineBoundingBox (Line);
       r_insert_entry (Layer->line_tree, (BoxTypePtr) Line, 0);
-      ClearFromPolygon (PCB->Data, LINE_TYPE, Layer, Line);
+      ClearFromPours (PCB->Data, LINE_TYPE, Layer, Line);
       DrawLine (Layer, Line, 0);
       return (Line);
     }
@@ -772,6 +789,26 @@ ChangePolygonClearSize (LayerTypePtr Layer, PolygonTypePtr poly)
 }
 
 /* ---------------------------------------------------------------------------
+ * Handle attepts to change the clearance of a polygon.
+ */
+static void *
+ChangePourClearSize (LayerTypePtr Layer, PourTypePtr pour)
+{
+  static int shown_this_message = 0;
+  if (!shown_this_message)
+    {
+      gui->confirm_dialog ("To change the clearance of objects in a pour, "
+			   "change the objects, not the pour.\n"
+			   "Hint: To set a minimum clearance for a group of objects, "
+			   "select them all then :MinClearGap(Selected,=10,mil)",
+			   "Ok", NULL);
+      shown_this_message = 1;
+    }
+
+  return (NULL);
+}
+
+/* ---------------------------------------------------------------------------
  * changes the size of an arc
  * returns TRUE if changed
  */
@@ -788,11 +825,11 @@ ChangeArcSize (LayerTypePtr Layer, ArcTypePtr Arc)
       AddObjectToSizeUndoList (ARC_TYPE, Layer, Arc, Arc);
       EraseArc (Arc);
       r_delete_entry (Layer->arc_tree, (BoxTypePtr) Arc);
-      RestoreToPolygon (PCB->Data, ARC_TYPE, Layer, Arc);
+      RestoreToPours (PCB->Data, ARC_TYPE, Layer, Arc);
       Arc->Thickness = value;
       SetArcBoundingBox (Arc);
       r_insert_entry (Layer->arc_tree, (BoxTypePtr) Arc, 0);
-      ClearFromPolygon (PCB->Data, ARC_TYPE, Layer, Arc);
+      ClearFromPours (PCB->Data, ARC_TYPE, Layer, Arc);
       DrawArc (Layer, Arc, 0);
       return (Arc);
     }
@@ -816,7 +853,7 @@ ChangeArcClearSize (LayerTypePtr Layer, ArcTypePtr Arc)
       AddObjectToClearSizeUndoList (ARC_TYPE, Layer, Arc, Arc);
       EraseArc (Arc);
       r_delete_entry (Layer->arc_tree, (BoxTypePtr) Arc);
-      RestoreToPolygon (PCB->Data, ARC_TYPE, Layer, Arc);
+      RestoreToPours (PCB->Data, ARC_TYPE, Layer, Arc);
       Arc->Clearance = value;
       if (Arc->Clearance == 0)
 	{
@@ -825,7 +862,7 @@ ChangeArcClearSize (LayerTypePtr Layer, ArcTypePtr Arc)
 	}
       SetArcBoundingBox (Arc);
       r_insert_entry (Layer->arc_tree, (BoxTypePtr) Arc, 0);
-      ClearFromPolygon (PCB->Data, ARC_TYPE, Layer, Arc);
+      ClearFromPours (PCB->Data, ARC_TYPE, Layer, Arc);
       DrawArc (Layer, Arc, 0);
       return (Arc);
     }
@@ -849,11 +886,11 @@ ChangeTextSize (LayerTypePtr Layer, TextTypePtr Text)
       AddObjectToSizeUndoList (TEXT_TYPE, Layer, Text, Text);
       EraseText (Layer, Text);
       r_delete_entry (Layer->text_tree, (BoxTypePtr) Text);
-      RestoreToPolygon (PCB->Data, TEXT_TYPE, Layer, Text);
+      RestoreToPours (PCB->Data, TEXT_TYPE, Layer, Text);
       Text->Scale = value;
       SetTextBoundingBox (&PCB->Font, Text);
       r_insert_entry (Layer->text_tree, (BoxTypePtr) Text, 0);
-      ClearFromPolygon (PCB->Data, TEXT_TYPE, Layer, Text);
+      ClearFromPours (PCB->Data, TEXT_TYPE, Layer, Text);
       DrawText (Layer, Text, 0);
       return (Text);
     }
@@ -1075,12 +1112,12 @@ ChangeTextName (LayerTypePtr Layer, TextTypePtr Text)
   if (TEST_FLAG (LOCKFLAG, Text))
     return (NULL);
   EraseText (Layer, Text);
-  RestoreToPolygon (PCB->Data, TEXT_TYPE, Layer, Text);
+  RestoreToPours (PCB->Data, TEXT_TYPE, Layer, Text);
   Text->TextString = NewName;
 
   /* calculate size of the bounding box */
   SetTextBoundingBox (&PCB->Font, Text);
-  ClearFromPolygon (PCB->Data, TEXT_TYPE, Layer, Text);
+  ClearFromPours (PCB->Data, TEXT_TYPE, Layer, Text);
   DrawText (Layer, Text, 0);
   return (old);
 }
@@ -1134,15 +1171,15 @@ ChangeLineJoin (LayerTypePtr Layer, LineTypePtr Line)
   EraseLine (Line);
   if (TEST_FLAG(CLEARLINEFLAG, Line))
   {
-  AddObjectToClearPolyUndoList (LINE_TYPE, Layer, Line, Line, false);
-  RestoreToPolygon (PCB->Data, LINE_TYPE, Layer, Line);
+  AddObjectToClearPourUndoList (LINE_TYPE, Layer, Line, Line, false);
+  RestoreToPours (PCB->Data, LINE_TYPE, Layer, Line);
   }
   AddObjectToFlagUndoList (LINE_TYPE, Layer, Line, Line);
   TOGGLE_FLAG (CLEARLINEFLAG, Line);
   if (TEST_FLAG(CLEARLINEFLAG, Line))
   {
-  AddObjectToClearPolyUndoList (LINE_TYPE, Layer, Line, Line, true);
-  ClearFromPolygon (PCB->Data, LINE_TYPE, Layer, Line);
+  AddObjectToClearPourUndoList (LINE_TYPE, Layer, Line, Line, true);
+  ClearFromPours (PCB->Data, LINE_TYPE, Layer, Line);
   }
   DrawLine (Layer, Line, 0);
   return (Line);
@@ -1180,17 +1217,17 @@ ChangeArcJoin (LayerTypePtr Layer, ArcTypePtr Arc)
     return (NULL);
   EraseArc (Arc);
   if (TEST_FLAG (CLEARLINEFLAG, Arc))
-  {
-    RestoreToPolygon (PCB->Data, ARC_TYPE, Layer, Arc);
-    AddObjectToClearPolyUndoList (ARC_TYPE, Layer, Arc, Arc, false);
+    {
+      RestoreToPours (PCB->Data, ARC_TYPE, Layer, Arc);
+      AddObjectToClearPourUndoList (ARC_TYPE, Layer, Arc, Arc, false);
     }
   AddObjectToFlagUndoList (ARC_TYPE, Layer, Arc, Arc);
   TOGGLE_FLAG (CLEARLINEFLAG, Arc);
   if (TEST_FLAG (CLEARLINEFLAG, Arc))
-  {
-    ClearFromPolygon (PCB->Data, ARC_TYPE, Layer, Arc);
-  AddObjectToClearPolyUndoList (ARC_TYPE, Layer, Arc, Arc, true);
-  }
+    {
+      ClearFromPours (PCB->Data, ARC_TYPE, Layer, Arc);
+      AddObjectToClearPourUndoList (ARC_TYPE, Layer, Arc, Arc, true);
+    }
   DrawArc (Layer, Arc, 0);
   return (Arc);
 }
@@ -1228,15 +1265,15 @@ ChangeTextJoin (LayerTypePtr Layer, TextTypePtr Text)
   EraseText (Layer, Text);
   if (TEST_FLAG(CLEARLINEFLAG, Text))
   {
-  AddObjectToClearPolyUndoList (TEXT_TYPE, Layer, Text, Text, false);
-  RestoreToPolygon (PCB->Data, TEXT_TYPE, Layer, Text);
+  AddObjectToClearPourUndoList (TEXT_TYPE, Layer, Text, Text, false);
+  RestoreToPours (PCB->Data, TEXT_TYPE, Layer, Text);
   }
   AddObjectToFlagUndoList (LINE_TYPE, Layer, Text, Text);
   TOGGLE_FLAG (CLEARLINEFLAG, Text);
   if (TEST_FLAG(CLEARLINEFLAG, Text))
   {
-  AddObjectToClearPolyUndoList (TEXT_TYPE, Layer, Text, Text, true);
-  ClearFromPolygon (PCB->Data, TEXT_TYPE, Layer, Text);
+  AddObjectToClearPourUndoList (TEXT_TYPE, Layer, Text, Text, true);
+  ClearFromPours (PCB->Data, TEXT_TYPE, Layer, Text);
   }
   DrawText (Layer, Text, 0);
   return (Text);
@@ -1399,12 +1436,12 @@ ChangePadSquare (ElementTypePtr Element, PadTypePtr Pad)
   if (TEST_FLAG (LOCKFLAG, Pad))
     return (NULL);
   ErasePad (Pad);
-  AddObjectToClearPolyUndoList (PAD_TYPE, Element, Pad, Pad, false);
-  RestoreToPolygon (PCB->Data, PAD_TYPE, Element, Pad);
+  AddObjectToClearPourUndoList (PAD_TYPE, Element, Pad, Pad, false);
+  RestoreToPours (PCB->Data, PAD_TYPE, Element, Pad);
   AddObjectToFlagUndoList (PAD_TYPE, Element, Pad, Pad);
   TOGGLE_FLAG (SQUAREFLAG, Pad);
-  AddObjectToClearPolyUndoList (PAD_TYPE, Element, Pad, Pad, true);
-  ClearFromPolygon (PCB->Data, PAD_TYPE, Element, Pad);
+  AddObjectToClearPourUndoList (PAD_TYPE, Element, Pad, Pad, true);
+  ClearFromPours (PCB->Data, PAD_TYPE, Element, Pad);
   DrawPad (Pad, 0);
   return (Pad);
 }
@@ -1446,12 +1483,12 @@ ChangePinSquare (ElementTypePtr Element, PinTypePtr Pin)
   if (TEST_FLAG (LOCKFLAG, Pin))
     return (NULL);
   ErasePin (Pin);
-  AddObjectToClearPolyUndoList (PIN_TYPE, Element, Pin, Pin, false);
-  RestoreToPolygon (PCB->Data, PIN_TYPE, Element, Pin);
+  AddObjectToClearPourUndoList (PIN_TYPE, Element, Pin, Pin, false);
+  RestoreToPours (PCB->Data, PIN_TYPE, Element, Pin);
   AddObjectToFlagUndoList (PIN_TYPE, Element, Pin, Pin);
   TOGGLE_FLAG (SQUAREFLAG, Pin);
-  AddObjectToClearPolyUndoList (PIN_TYPE, Element, Pin, Pin, true);
-  ClearFromPolygon (PCB->Data, PIN_TYPE, Element, Pin);
+  AddObjectToClearPourUndoList (PIN_TYPE, Element, Pin, Pin, true);
+  ClearFromPours (PCB->Data, PIN_TYPE, Element, Pin);
   DrawPin (Pin, 0);
   return (Pin);
 }
@@ -1489,12 +1526,12 @@ ChangeViaOctagon (PinTypePtr Via)
   if (TEST_FLAG (LOCKFLAG, Via))
     return (NULL);
   EraseVia (Via);
-  AddObjectToClearPolyUndoList (VIA_TYPE, Via, Via, Via, false);
-  RestoreToPolygon (PCB->Data, VIA_TYPE, Via, Via);
+  AddObjectToClearPourUndoList (VIA_TYPE, Via, Via, Via, false);
+  RestoreToPours (PCB->Data, VIA_TYPE, Via, Via);
   AddObjectToFlagUndoList (VIA_TYPE, Via, Via, Via);
   TOGGLE_FLAG (OCTAGONFLAG, Via);
-  AddObjectToClearPolyUndoList (VIA_TYPE, Via, Via, Via, true);
-  ClearFromPolygon (PCB->Data, VIA_TYPE, Via, Via);
+  AddObjectToClearPourUndoList (VIA_TYPE, Via, Via, Via, true);
+  ClearFromPours (PCB->Data, VIA_TYPE, Via, Via);
   DrawVia (Via, 0);
   return (Via);
 }
@@ -1532,12 +1569,12 @@ ChangePinOctagon (ElementTypePtr Element, PinTypePtr Pin)
   if (TEST_FLAG (LOCKFLAG, Pin))
     return (NULL);
   ErasePin (Pin);
-  AddObjectToClearPolyUndoList (PIN_TYPE, Element, Pin, Pin, false);
-  RestoreToPolygon (PCB->Data, PIN_TYPE, Element, Pin);
+  AddObjectToClearPourUndoList (PIN_TYPE, Element, Pin, Pin, false);
+  RestoreToPours (PCB->Data, PIN_TYPE, Element, Pin);
   AddObjectToFlagUndoList (PIN_TYPE, Element, Pin, Pin);
   TOGGLE_FLAG (OCTAGONFLAG, Pin);
-  AddObjectToClearPolyUndoList (PIN_TYPE, Element, Pin, Pin, true);
-  ClearFromPolygon (PCB->Data, PIN_TYPE, Element, Pin);
+  AddObjectToClearPourUndoList (PIN_TYPE, Element, Pin, Pin, true);
+  ClearFromPours (PCB->Data, PIN_TYPE, Element, Pin);
   DrawPin (Pin, 0);
   return (Pin);
 }
@@ -1579,10 +1616,10 @@ ChangeHole (PinTypePtr Via)
   TOGGLE_FLAG (HOLEFLAG, Via);
   if (TEST_FLAG (HOLEFLAG, Via))
     {
-      RestoreToPolygon (PCB->Data, VIA_TYPE, Via, Via);
+      RestoreToPours (PCB->Data, VIA_TYPE, Via, Via);
       AddObjectToSizeUndoList (VIA_TYPE, Via, Via, Via);
       Via->Thickness = Via->Mask = Via->DrillingHole;
-      ClearFromPolygon (PCB->Data, VIA_TYPE, Via, Via);
+      ClearFromPours (PCB->Data, VIA_TYPE, Via, Via);
     }
   else
     {
@@ -1611,19 +1648,19 @@ ChangePaste (PadTypePtr Pad)
 }
 
 /* ---------------------------------------------------------------------------
- * changes the CLEARPOLY flag of a polygon
+ * changes the CLEARPOLY flag of a pour
  */
 static void *
-ChangePolyClear (LayerTypePtr Layer, PolygonTypePtr Polygon)
+ChangePourClear (LayerTypePtr Layer, PourTypePtr Pour)
 {
-  if (TEST_FLAG (LOCKFLAG, Polygon))
+  if (TEST_FLAG (LOCKFLAG, Pour))
     return (NULL);
-  AddObjectToClearPolyUndoList (POLYGON_TYPE, Layer, Polygon, Polygon, true);
-  AddObjectToFlagUndoList (POLYGON_TYPE, Layer, Polygon, Polygon);
-  TOGGLE_FLAG (CLEARPOLYFLAG, Polygon);
-  InitClip (PCB->Data, Layer, Polygon);
-  DrawPolygon (Layer, Polygon, 0);
-  return (Polygon);
+  AddObjectToClearPourUndoList (POUR_TYPE, Layer, Pour, Pour, true);
+  AddObjectToFlagUndoList (POUR_TYPE, Layer, Pour, Pour);
+  TOGGLE_FLAG (CLEARPOLYFLAG, Pour);
+  InitPourClip (PCB->Data, Layer, Pour);
+  DrawPour (Layer, Pour, 0);
+  return (Pour);
 }
 
 /* ----------------------------------------------------------------------
diff --git a/src/change.h b/src/change.h
index 7bae706..f0547b8 100644
--- a/src/change.h
+++ b/src/change.h
@@ -40,7 +40,7 @@
 	(VIA_TYPE | PIN_TYPE | PAD_TYPE | TEXT_TYPE | ELEMENT_TYPE | ELEMENTNAME_TYPE | LINE_TYPE)
 
 #define	CHANGESIZE_TYPES        \
-	(POLYGON_TYPE | VIA_TYPE | PIN_TYPE | PAD_TYPE | LINE_TYPE | \
+	(POUR_TYPE | VIA_TYPE | PIN_TYPE | PAD_TYPE | LINE_TYPE | \
 	 ARC_TYPE | TEXT_TYPE | ELEMENTNAME_TYPE | ELEMENT_TYPE)
 
 #define	CHANGE2NDSIZE_TYPES     \
diff --git a/src/const.h b/src/const.h
index 676a6f0..6d34ce8 100644
--- a/src/const.h
+++ b/src/const.h
@@ -78,7 +78,8 @@
 #define	VIA_MODE		1	/* draw vias */
 #define	LINE_MODE		2	/* draw lines */
 #define	RECTANGLE_MODE		3	/* create rectangles */
-#define	POLYGON_MODE		4	/* draw filled polygons */
+//#define	POLYGON_MODE		4	/* draw filled polygons */
+#define	POUR_MODE		4	/* draw poured areas */
 #define	PASTEBUFFER_MODE	5	/* paste objects from buffer */
 #define	TEXT_MODE		6	/* create text objects */
 #define	ROTATE_MODE		102	/* rotate objects */
@@ -92,7 +93,7 @@
 #define ARROW_MODE		110	/* selection with arrow mode */
 #define PAN_MODE                0	/* same as no mode */
 #define LOCK_MODE               111	/* lock/unlock objects */
-#define	POLYGONHOLE_MODE	112	/* cut holes in filled polygons */
+#define	POURHOLE_MODE		112	/* cut holes in poured areas */
 
 /* ---------------------------------------------------------------------------
  * object flags
@@ -303,17 +304,20 @@ When set, element names are not drawn.
 #define	PIN_TYPE		0x00100	/* objects that are part */
 #define	PAD_TYPE		0x00200	/* 'pin' of SMD element */
 #define	ELEMENTNAME_TYPE	0x00400	/* of others */
-#define	POLYGONPOINT_TYPE	0x00800
+//#define	POLYGONPOINT_TYPE	0x00800
+#define POURPOINT_TYPE 		0x00800
 #define	LINEPOINT_TYPE		0x01000
 #define ELEMENTLINE_TYPE        0x02000
 #define ARC_TYPE                0x04000
 #define ELEMENTARC_TYPE		0x08000
 
 #define LOCKED_TYPE 		0x10000	/* used to tell search to include locked items. */
+#define POUR_TYPE 		0x20000
 
 #define PIN_TYPES     (VIA_TYPE | PIN_TYPE)
-#define LOCK_TYPES    (VIA_TYPE | LINE_TYPE | ARC_TYPE | POLYGON_TYPE | ELEMENT_TYPE \
-                      | TEXT_TYPE | ELEMENTNAME_TYPE | LOCKED_TYPE)
+#define LOCK_TYPES    (VIA_TYPE | LINE_TYPE | ARC_TYPE | POUR_TYPE | \
+                       ELEMENT_TYPE | TEXT_TYPE | ELEMENTNAME_TYPE | \
+                       LOCKED_TYPE)
 
 #define	ALL_TYPES		(~0)	/* all bits set */
 
diff --git a/src/copy.c b/src/copy.c
index 58ce9df..de5e92c 100644
--- a/src/copy.c
+++ b/src/copy.c
@@ -47,7 +47,7 @@
 #include "mirror.h"
 #include "misc.h"
 #include "move.h"
-#include "polygon.h"
+#include "pour.h"
 #include "rats.h"
 #include "rtree.h"
 #include "select.h"
@@ -66,7 +66,7 @@ static void *CopyVia (PinTypePtr);
 static void *CopyLine (LayerTypePtr, LineTypePtr);
 static void *CopyArc (LayerTypePtr, ArcTypePtr);
 static void *CopyText (LayerTypePtr, TextTypePtr);
-static void *CopyPolygon (LayerTypePtr, PolygonTypePtr);
+static void *CopyPour (LayerTypePtr, PourTypePtr);
 static void *CopyElement (ElementTypePtr);
 
 /* ---------------------------------------------------------------------------
@@ -76,7 +76,8 @@ static LocationType DeltaX, DeltaY;	/* movement vector */
 static ObjectFunctionType CopyFunctions = {
   CopyLine,
   CopyText,
-  CopyPolygon,
+  NULL,
+  CopyPour,
   CopyVia,
   CopyElement,
   NULL,
@@ -89,11 +90,11 @@ static ObjectFunctionType CopyFunctions = {
 };
 
 /* ---------------------------------------------------------------------------
- * copies data from one polygon to another
+ * copies data from one pour to another
  * 'Dest' has to exist
  */
-PolygonTypePtr
-CopyPolygonLowLevel (PolygonTypePtr Dest, PolygonTypePtr Src)
+PourTypePtr
+CopyPourLowLevel (PourTypePtr Dest, PourTypePtr Src)
 {
   Cardinal hole = 0;
   Cardinal n;
@@ -102,12 +103,12 @@ CopyPolygonLowLevel (PolygonTypePtr Dest, PolygonTypePtr Src)
     {
       if (hole < Src->HoleIndexN && n == Src->HoleIndex[hole])
         {
-          CreateNewHoleInPolygon (Dest);
+          CreateNewHoleInPour (Dest);
           hole++;
         }
-      CreateNewPointInPolygon (Dest, Src->Points[n].X, Src->Points[n].Y);
+      CreateNewPointInPour (Dest, Src->Points[n].X, Src->Points[n].Y);
     }
-  SetPolygonBoundingBox (Dest);
+  SetPourBoundingBox (Dest);
   Dest->Flags = Src->Flags;
   CLEAR_FLAG (FOUNDFLAG, Dest);
   return (Dest);
@@ -263,23 +264,23 @@ CopyText (LayerTypePtr Layer, TextTypePtr Text)
 }
 
 /* ---------------------------------------------------------------------------
- * copies a polygon 
+ * copies a pour
  */
 static void *
-CopyPolygon (LayerTypePtr Layer, PolygonTypePtr Polygon)
+CopyPour (LayerTypePtr Layer, PourTypePtr Pour)
 {
-  PolygonTypePtr polygon;
-
-  polygon = CreateNewPolygon (Layer, NoFlags ());
-  CopyPolygonLowLevel (polygon, Polygon);
-  MovePolygonLowLevel (polygon, DeltaX, DeltaY);
-  if (!Layer->polygon_tree)
-    Layer->polygon_tree = r_create_tree (NULL, 0, 0);
-  r_insert_entry (Layer->polygon_tree, (BoxTypePtr) polygon, 0);
-  InitClip (PCB->Data, Layer, polygon);
-  DrawPolygon (Layer, polygon, 0);
-  AddObjectToCreateUndoList (POLYGON_TYPE, Layer, polygon, polygon);
-  return (polygon);
+  PourTypePtr pour;
+
+  pour = CreateNewPour (Layer, NoFlags ());
+  CopyPourLowLevel (pour, Pour);
+  MovePourLowLevel (pour, DeltaX, DeltaY);
+  if (!Layer->pour_tree)
+    Layer->pour_tree = r_create_tree (NULL, 0, 0);
+  r_insert_entry (Layer->pour_tree, (BoxTypePtr) pour, 0);
+  InitPourClip (PCB->Data, Layer, pour);
+  DrawPour (Layer, pour, 0);
+  AddObjectToCreateUndoList (POUR_TYPE, Layer, pour, pour);
+  return (pour);
 }
 
 /* ---------------------------------------------------------------------------
@@ -348,7 +349,7 @@ CopyPastebufferToLayout (LocationType X, LocationType Y)
 	  changed = changed ||
 	    (sourcelayer->LineN != 0) ||
 	    (sourcelayer->ArcN != 0) ||
-	    (sourcelayer->PolygonN != 0) || (sourcelayer->TextN != 0);
+	    (sourcelayer->PourN != 0) || (sourcelayer->TextN != 0);
 	  LINE_LOOP (sourcelayer);
 	  {
 	    CopyLine (destlayer, line);
@@ -364,9 +365,9 @@ CopyPastebufferToLayout (LocationType X, LocationType Y)
 	    CopyText (destlayer, text);
 	  }
 	  END_LOOP;
-	  POLYGON_LOOP (sourcelayer);
+	  POUR_LOOP (sourcelayer);
 	  {
-	    CopyPolygon (destlayer, polygon);
+	    CopyPour (destlayer, pour);
 	  }
 	  END_LOOP;
 	}
diff --git a/src/copy.h b/src/copy.h
index ac50e2c..6a59832 100644
--- a/src/copy.h
+++ b/src/copy.h
@@ -38,10 +38,10 @@
  */
 #define	COPY_TYPES              \
 	(VIA_TYPE | LINE_TYPE | TEXT_TYPE | \
-	ELEMENT_TYPE | ELEMENTNAME_TYPE | POLYGON_TYPE | ARC_TYPE)
+	ELEMENT_TYPE | ELEMENTNAME_TYPE | POUR_TYPE | ARC_TYPE)
 
 
-PolygonTypePtr CopyPolygonLowLevel (PolygonTypePtr, PolygonTypePtr);
+PourTypePtr CopyPourLowLevel (PourTypePtr, PourTypePtr);
 ElementTypePtr CopyElementLowLevel (DataTypePtr, ElementTypePtr,
 				    ElementTypePtr, bool, LocationType, LocationType);
 bool CopyPastebufferToLayout (LocationType, LocationType);
diff --git a/src/create.c b/src/create.c
index b3d5bee..68f2f19 100644
--- a/src/create.c
+++ b/src/create.c
@@ -545,29 +545,28 @@ CreateNewArcOnLayer (LayerTypePtr Layer,
   return (Arc);
 }
 
-
 /* ---------------------------------------------------------------------------
- * creates a new polygon from the old formats rectangle data
+ * creates a new pour from the old formats rectangle data
  */
-PolygonTypePtr
-CreateNewPolygonFromRectangle (LayerTypePtr Layer,
+PourTypePtr
+CreateNewPourFromRectangle (LayerTypePtr Layer,
 			       LocationType X1, LocationType Y1,
 			       LocationType X2, LocationType Y2,
 			       FlagType Flags)
 {
-  PolygonTypePtr polygon = CreateNewPolygon (Layer, Flags);
-  if (!polygon)
-    return (polygon);
-
-  CreateNewPointInPolygon (polygon, X1, Y1);
-  CreateNewPointInPolygon (polygon, X2, Y1);
-  CreateNewPointInPolygon (polygon, X2, Y2);
-  CreateNewPointInPolygon (polygon, X1, Y2);
-  SetPolygonBoundingBox (polygon);
-  if (!Layer->polygon_tree)
-    Layer->polygon_tree = r_create_tree (NULL, 0, 0);
-  r_insert_entry (Layer->polygon_tree, (BoxTypePtr) polygon, 0);
-  return (polygon);
+  PourTypePtr pour = CreateNewPour (Layer, Flags);
+  if (!pour)
+    return (pour);
+
+  CreateNewPointInPour (pour, X1, Y1);
+  CreateNewPointInPour (pour, X2, Y1);
+  CreateNewPointInPour (pour, X2, Y2);
+  CreateNewPointInPour (pour, X1, Y2);
+  SetPourBoundingBox (pour);
+  if (!Layer->pour_tree)
+    Layer->pour_tree = r_create_tree (NULL, 0, 0);
+  r_insert_entry (Layer->pour_tree, (BoxTypePtr) pour, 0);
+  return (pour);
 }
 
 /* ---------------------------------------------------------------------------
@@ -605,9 +604,9 @@ CreateNewText (LayerTypePtr Layer, FontTypePtr PCBFont,
  * creates a new polygon on a layer
  */
 PolygonTypePtr
-CreateNewPolygon (LayerTypePtr Layer, FlagType Flags)
+CreateNewPolygonInPour (PourType *pour, FlagType Flags)
 {
-  PolygonTypePtr polygon = GetPolygonMemory (Layer);
+  PolygonTypePtr polygon = GetPolygonMemoryInPour (pour);
 
   /* copy values */
   polygon->Flags = Flags;
@@ -615,17 +614,40 @@ CreateNewPolygon (LayerTypePtr Layer, FlagType Flags)
   polygon->Clipped = NULL;
   polygon->NoHoles = NULL;
   polygon->NoHolesValid = 0;
+  polygon->ParentPour = pour;
   return (polygon);
 }
 
 /* ---------------------------------------------------------------------------
- * creates a new point in a polygon
+ * creates a new pour on a layer
+ */
+PourTypePtr
+CreateNewPour (LayerTypePtr Layer, FlagType Flags)
+{
+  PourTypePtr pour = GetPourMemory (Layer);
+
+  /* copy values */
+  pour->Flags = Flags;
+  pour->ID = ID++;
+
+  pour->PointN = 0;
+  pour->PointMax = 0;
+  pour->Points = NULL;
+  pour->PolygonN = 0;
+  pour->PolygonMax = 0;
+  pour->Polygons = NULL;
+
+  return (pour);
+}
+
+/* ---------------------------------------------------------------------------
+ * creates a new point in a pour
  */
 PointTypePtr
-CreateNewPointInPolygon (PolygonTypePtr Polygon, LocationType X,
+CreateNewPointInPour (PourTypePtr Pour, LocationType X,
 			 LocationType Y)
 {
-  PointTypePtr point = GetPointMemoryInPolygon (Polygon);
+  PointTypePtr point = GetPointMemoryInPour (Pour);
 
   /* copy values */
   point->X = X;
@@ -637,12 +659,12 @@ CreateNewPointInPolygon (PolygonTypePtr Polygon, LocationType X,
 /* ---------------------------------------------------------------------------
  * creates a new hole in a polygon
  */
-PolygonType *
-CreateNewHoleInPolygon (PolygonType *Polygon)
+PourType *
+CreateNewHoleInPour (PourType *Pour)
 {
-  Cardinal *holeindex = GetHoleIndexMemoryInPolygon (Polygon);
-  *holeindex = Polygon->PointN;
-  return Polygon;
+  Cardinal *holeindex = GetHoleIndexMemoryInPour (Pour);
+  *holeindex = Pour->PointN;
+  return Pour;
 }
 
 /* ---------------------------------------------------------------------------
diff --git a/src/create.h b/src/create.h
index 8086b1e..af7ace4 100644
--- a/src/create.h
+++ b/src/create.h
@@ -54,15 +54,16 @@ RatTypePtr CreateNewRat (DataTypePtr, LocationType, LocationType,
 ArcTypePtr CreateNewArcOnLayer (LayerTypePtr, LocationType, LocationType,
 				BDimension, BDimension, int, int, BDimension, BDimension,
 				FlagType);
-PolygonTypePtr CreateNewPolygonFromRectangle (LayerTypePtr, LocationType,
+PourTypePtr CreateNewPourFromRectangle (LayerTypePtr, LocationType,
 					      LocationType, LocationType,
 					      LocationType, FlagType);
 TextTypePtr CreateNewText (LayerTypePtr, FontTypePtr, LocationType,
 			   LocationType, BYTE, int, char *, FlagType);
-PolygonTypePtr CreateNewPolygon (LayerTypePtr, FlagType);
-PointTypePtr CreateNewPointInPolygon (PolygonTypePtr,
+PolygonTypePtr CreateNewPolygonInPour (PourType *pour, FlagType);
+PourTypePtr CreateNewPour (LayerTypePtr, FlagType);
+PointTypePtr CreateNewPointInPour (PourTypePtr,
 				      LocationType, LocationType);
-PolygonType *CreateNewHoleInPolygon (PolygonType *polygon);
+PourType *CreateNewHoleInPour (PourType *);
 ElementTypePtr CreateNewElement (DataTypePtr, ElementTypePtr,
 				 FontTypePtr, FlagType, char *, char *,
 				 char *, LocationType, LocationType, BYTE,
diff --git a/src/crosshair.c b/src/crosshair.c
index ac22277..90fcd66 100644
--- a/src/crosshair.c
+++ b/src/crosshair.c
@@ -48,7 +48,7 @@
 #include "misc.h"
 #include "mymem.h"
 #include "search.h"
-#include "polygon.h"
+#include "pour.h"
 
 #ifdef HAVE_LIBDMALLOC
 #include <dmalloc.h>
@@ -78,6 +78,7 @@ static int CrosshairStackLocation = 0;
  * some local prototypes
  */
 static void XORPolygon (PolygonTypePtr, LocationType, LocationType);
+static void XORPour (PourTypePtr, LocationType, LocationType);
 static void XORDrawElement (ElementTypePtr, LocationType, LocationType);
 static void XORDrawBuffer (BufferTypePtr);
 static void XORDrawInsertPointObject (void);
@@ -93,6 +94,8 @@ static void XORDrawAttachedArc (BDimension);
 static void
 XORPolygon (PolygonTypePtr polygon, LocationType dx, LocationType dy)
 {
+#warning FIXME Later
+#if 0
   Cardinal i;
   for (i = 0; i < polygon->PointN; i++)
     {
@@ -103,6 +106,25 @@ XORPolygon (PolygonTypePtr polygon, LocationType dx, LocationType dy)
                       polygon->Points[next].X + dx,
                       polygon->Points[next].Y + dy);
     }
+#endif
+}
+
+/* ---------------------------------------------------------------------------
+ * creates a tmp pour with coordinates converted to screen system
+ */
+static void
+XORPour (PourTypePtr pour, LocationType dx, LocationType dy)
+{
+  Cardinal i;
+  for (i = 0; i < pour->PointN; i++)
+    {
+      Cardinal next = next_contour_point (pour, i);
+      gui->draw_line (Crosshair.GC,
+                      pour->Points[i].X + dx,
+                      pour->Points[i].Y + dy,
+                      pour->Points[next].X + dx,
+                      pour->Points[next].Y + dy);
+    }
 }
 
 /*-----------------------------------------------------------
@@ -351,9 +373,11 @@ XORDrawBuffer (BufferTypePtr Buffer)
 	/* the tmp polygon has n+1 points because the first
 	 * and the last one are set to the same coordinates
 	 */
-	POLYGON_LOOP (layer);
+	POUR_LOOP (layer);
 	{
-	  XORPolygon (polygon, x, y);
+	  XORPour (pour, x, y);
+#warning FIXME Later
+//	  XORPolygon (polygon, x, y);
 	}
 	END_LOOP;
       }
@@ -453,6 +477,18 @@ XORDrawMoveOrCopyObject (void)
 	break;
       }
 
+    case POUR_TYPE:
+      {
+	PourTypePtr pour =
+	  (PourTypePtr) Crosshair.AttachedObject.Ptr2;
+
+	/* the tmp pour has n+1 points because the first
+	 * and the last one are set to the same coordinates
+	 */
+	XORPour (pour, dx, dy);
+	break;
+      }
+
     case LINEPOINT_TYPE:
       {
 	LineTypePtr line;
@@ -471,27 +507,27 @@ XORDrawMoveOrCopyObject (void)
 	break;
       }
 
-    case POLYGONPOINT_TYPE:
+    case POURPOINT_TYPE:
       {
-	PolygonTypePtr polygon;
+	PourTypePtr pour;
 	PointTypePtr point;
 	Cardinal point_idx, prev, next;
 
-	polygon = (PolygonTypePtr) Crosshair.AttachedObject.Ptr2;
+	pour = (PourTypePtr) Crosshair.AttachedObject.Ptr2;
 	point = (PointTypePtr) Crosshair.AttachedObject.Ptr3;
-	point_idx = polygon_point_idx (polygon, point);
+	point_idx = pour_point_idx (pour, point);
 
 	/* get previous and following point */
-	prev = prev_contour_point (polygon, point_idx);
-	next = next_contour_point (polygon, point_idx);
+	prev = prev_contour_point (pour, point_idx);
+	next = next_contour_point (pour, point_idx);
 
 	/* draw the two segments */
 	gui->draw_line (Crosshair.GC,
-			polygon->Points[prev].X, polygon->Points[prev].Y,
+			pour->Points[prev].X, pour->Points[prev].Y,
 			point->X + dx, point->Y + dy);
 	gui->draw_line (Crosshair.GC,
 			point->X + dx, point->Y + dy,
-			polygon->Points[next].X, polygon->Points[next].Y);
+			pour->Points[next].X, pour->Points[next].Y);
 	break;
       }
 
@@ -588,9 +624,9 @@ DrawAttached (bool BlockToo)
 	}
       break;
 
-      /* the attached line is used by both LINEMODE, POLYGON_MODE and POLYGONHOLE_MODE*/
-    case POLYGON_MODE:
-    case POLYGONHOLE_MODE:
+      /* the attached line is used by both LINEMODE, POUR_MODE and POURHOLE_MODE */
+    case POUR_MODE:
+    case POURHOLE_MODE:
       /* draw only if starting point is set */
       if (Crosshair.AttachedLine.State != STATE_FIRST)
 	gui->draw_line (Crosshair.GC,
@@ -599,10 +635,10 @@ DrawAttached (bool BlockToo)
 			Crosshair.AttachedLine.Point2.X,
 			Crosshair.AttachedLine.Point2.Y);
 
-      /* draw attached polygon only if in POLYGON_MODE or POLYGONHOLE_MODE */
-      if (Crosshair.AttachedPolygon.PointN > 1)
+      /* draw attached polygon only if in POUR_MODE or POURHOLE_MODE */
+      if (Crosshair.AttachedPour.PointN > 1)
 	{
-	  XORPolygon (&Crosshair.AttachedPolygon, 0, 0);
+	  XORPour (&Crosshair.AttachedPour, 0, 0);
 	}
       break;
 
@@ -979,7 +1015,7 @@ FitCrosshairIntoGrid (LocationType X, LocationType Y)
 
   if (TEST_FLAG (SNAPPINFLAG, PCB))
     ans = SearchScreenGridSlop (Crosshair.X, Crosshair.Y,
-                                POLYGONPOINT_TYPE, &ptr1, &ptr2, &ptr3);
+                                POURPOINT_TYPE, &ptr1, &ptr2, &ptr3);
   else
     ans = NO_TYPE;
 
@@ -1154,6 +1190,6 @@ void
 DestroyCrosshair (void)
 {
   CrosshairOff (true);
-  FreePolygonMemory (&Crosshair.AttachedPolygon);
+  FreePourMemory (&Crosshair.AttachedPour);
   gui->destroy_gc (Crosshair.GC);
 }
diff --git a/src/draw.c b/src/draw.c
index a27c0dc..bcc1300 100644
--- a/src/draw.c
+++ b/src/draw.c
@@ -49,6 +49,7 @@
 #include "search.h"
 #include "select.h"
 #include "print.h"
+#include "pour.h"
 
 #ifdef HAVE_LIBDMALLOC
 #include <dmalloc.h>
@@ -100,6 +101,7 @@ static void DrawPadNameLowLevel (PadTypePtr);
 static void DrawLineLowLevel (LineTypePtr, bool);
 /* static */ void DrawRegularText (LayerTypePtr, TextTypePtr, int);
 static void DrawPolygonLowLevel (PolygonTypePtr);
+static void DrawPourLowLevel (PourTypePtr);
 static void DrawArcLowLevel (ArcTypePtr);
 static void DrawElementPackageLowLevel (ElementTypePtr Element, int);
 static void DrawPlainPolygon (LayerTypePtr Layer, PolygonTypePtr Polygon);
@@ -677,6 +679,7 @@ struct pin_info
 {
   bool arg;
   LayerTypePtr Layer;
+  const BoxType * clip;
 };
 
 /* static */ int
@@ -688,12 +691,32 @@ clearPin_callback (const BoxType * b, void *cl)
     ClearOnlyPin (pin, true);
   return 1;
 }
+
 static int
 poly_callback (const BoxType * b, void *cl)
 {
   struct pin_info *i = (struct pin_info *) cl;
 
+//  printf ("Got one poly callback, %p\n", b);
   DrawPlainPolygon (i->Layer, (PolygonTypePtr) b);
+
+  return 1;
+}
+
+static int
+pour_callback (const BoxType * b, void *cl)
+{
+  struct pin_info *i = (struct pin_info *) cl;
+  PourType *pour = (PourType *)b;
+
+  if (gui->gui)
+    DrawPour (i->Layer, pour, 0);
+
+  if (pour->PolygonN)
+    {
+      r_search (pour->polygon_tree, i->clip, NULL, poly_callback, i);
+    }
+
   return 1;
 }
 
@@ -769,6 +792,7 @@ DrawMask (BoxType * screen)
   OutputType *out = &Output;
 
   info.arg = true;
+  info.clip = screen;
 
   if (thin)
     gui->set_color (Output.pmGC, PCB->MaskColor);
@@ -867,8 +891,9 @@ DrawLayer (LayerTypePtr Layer, const BoxType * screen)
   /* print the non-clearing polys */
   info.Layer = Layer;
   info.arg = false;
+  info.clip = screen;
   clip_box = screen;
-  r_search (Layer->polygon_tree, screen, NULL, poly_callback, &info);
+  r_search (Layer->pour_tree, screen, NULL, pour_callback, &info);
 
   /* draw all visible lines this layer */
   r_search (Layer->line_tree, screen, NULL, line_callback, Layer);
@@ -906,13 +931,13 @@ DrawLayerGroup (int group, const BoxType * screen)
 	rv = 0;
       if (layernum < max_layer && Layer->On)
 	{
-	  /* draw all polygons on this layer */
-	  if (Layer->PolygonN)
+	  /* draw all pours on this layer */
+	  if (Layer->PourN)
 	    {
 	      info.Layer = Layer;
 	      info.arg = true;
-	      r_search (Layer->polygon_tree, screen, NULL, poly_callback,
-			&info);
+	      info.clip = screen;
+	      r_search (Layer->pour_tree, screen, NULL, pour_callback, &info);
 	      info.arg = false;
 
 	      /* HACK: Subcomposite polygons separately from other layer primitives */
@@ -1657,6 +1682,48 @@ DrawPolygonLowLevel (PolygonTypePtr Polygon)
 }
 
 /* ---------------------------------------------------------------------------
+ * lowlevel drawing routine for pours
+ */
+static void
+DrawPourLowLevel (PourTypePtr Pour)
+{
+  int *x, *y, n, i;
+
+  if (Gathering)
+    {
+      AddPart (Pour);
+      return;
+    }
+
+  n = Pour->PointN;
+  x = (int *) malloc (n * sizeof (int));
+  y = (int *) malloc (n * sizeof (int));
+  for (i = 0; i < n; i++)
+    {
+      x[i] = Pour->Points[i].X;
+      y[i] = Pour->Points[i].Y;
+    }
+
+//  if (TEST_FLAG (THINDRAWFLAG, PCB) ||
+//      TEST_FLAG (THINDRAWPOLYFLAG, PCB) ||
+//      TEST_FLAG (CLEARLINEFLAG, Pour))
+  if (1)
+    {
+      gui->set_line_width (Output.fgGC, 2);
+//      gui->set_line_width (Output.fgGC, 1);
+      for (i = 0; i < n; i++)
+        {
+          Cardinal next = next_contour_point (Pour, i);
+          gui->draw_line (Output.fgGC, x[i], y[i], x[next], y[next]);
+        }
+    }
+  else
+    gui->fill_polygon (Output.fgGC, n, x, y);
+  free (x);
+  free (y);
+}
+
+/* ---------------------------------------------------------------------------
  * lowlevel routine to element arcs
  */
 static void
@@ -1975,6 +2042,37 @@ DrawPolygon (LayerTypePtr Layer, PolygonTypePtr Polygon, int unused)
   DrawPolygonLowLevel (Polygon);
 }
 
+/* ---------------------------------------------------------------------------
+ * draws a pour on a layer
+ */
+void
+DrawPour (LayerTypePtr Layer, PourTypePtr Pour, int unused)
+{
+  int layernum;
+
+  if (TEST_FLAG (SELECTEDFLAG | FOUNDFLAG, Pour))
+    {
+      if (TEST_FLAG (SELECTEDFLAG, Pour))
+	gui->set_color (Output.fgGC, Layer->SelectedColor);
+      else
+	gui->set_color (Output.fgGC, PCB->ConnectedColor);
+    }
+  else
+    gui->set_color (Output.fgGC, Layer->Color);
+  layernum = GetLayerNumber (PCB->Data, Layer);
+  DrawPourLowLevel (Pour);
+#warning FIXME Later
+#if 0
+  if (TEST_FLAG (CLEARPOLYFLAG, Pour))
+    {
+      r_search (PCB->Data->pin_tree, &Pour->BoundingBox, NULL,
+		cp_callback, (void *) PIN_TYPE);
+      r_search (PCB->Data->via_tree, &Pour->BoundingBox, NULL,
+		cp_callback, (void *) VIA_TYPE);
+    }
+#endif
+}
+
 int
 thin_callback (PLINE * pl, LayerTypePtr lay, PolygonTypePtr poly)
 {
@@ -2268,6 +2366,18 @@ ErasePolygon (PolygonTypePtr Polygon)
 }
 
 /* ---------------------------------------------------------------------------
+ * erases a pour on a layer
+ */
+void
+ErasePour (PourTypePtr Pour)
+{
+  Erasing++;
+  gui->set_color (Output.fgGC, Settings.BackgroundColor);
+  DrawPourLowLevel (Pour);
+  Erasing--;
+}
+
+/* ---------------------------------------------------------------------------
  * erases an element
  */
 void
@@ -2344,6 +2454,9 @@ EraseObject (int type, void *lptr, void *ptr)
     case POLYGON_TYPE:
       ErasePolygon ((PolygonTypePtr) ptr);
       break;
+    case POUR_TYPE:
+      ErasePour ((PourTypePtr) ptr);
+      break;
     case ELEMENT_TYPE:
       EraseElement ((ElementTypePtr) ptr);
       break;
@@ -2391,6 +2504,10 @@ DrawObject (int type, void *ptr1, void *ptr2, int unused)
       if (((LayerTypePtr) ptr1)->On)
 	DrawPolygon ((LayerTypePtr) ptr1, (PolygonTypePtr) ptr2, 0);
       break;
+    case POUR_TYPE:
+      if (((LayerTypePtr) ptr1)->On)
+	DrawPour ((LayerTypePtr) ptr1, (PourTypePtr) ptr2, 0);
+      break;
     case ELEMENT_TYPE:
       if (PCB->ElementOn &&
 	  (FRONT ((ElementTypePtr) ptr2) || PCB->InvisibleObjectsOn))
diff --git a/src/draw.h b/src/draw.h
index 077c575..5b4d73a 100644
--- a/src/draw.h
+++ b/src/draw.h
@@ -50,6 +50,7 @@ void DrawArc (LayerTypePtr, ArcTypePtr, int);
 void DrawText (LayerTypePtr, TextTypePtr, int);
 void DrawTextLowLevel (TextTypePtr, int);
 void DrawPolygon (LayerTypePtr, PolygonTypePtr, int);
+void DrawPour (LayerTypePtr, PourTypePtr, int);
 void DrawElement (ElementTypePtr, int);
 void DrawElementName (ElementTypePtr, int);
 void DrawElementPackage (ElementTypePtr, int);
@@ -67,6 +68,7 @@ void EraseLine (LineTypePtr);
 void EraseArc (ArcTypePtr);
 void EraseText (LayerTypePtr, TextTypePtr);
 void ErasePolygon (PolygonTypePtr);
+void ErasePour (PourTypePtr);
 void EraseElement (ElementTypePtr);
 void EraseElementPinsAndPads (ElementTypePtr);
 void EraseElementName (ElementTypePtr);
diff --git a/src/file.c b/src/file.c
index a61d53f..d44c3bb 100644
--- a/src/file.c
+++ b/src/file.c
@@ -89,7 +89,6 @@
 #include "move.h"
 #include "mymem.h"
 #include "parse_l.h"
-#include "polygon.h"
 #include "rats.h"
 #include "remove.h"
 #include "set.h"
@@ -786,7 +785,7 @@ WriteLayerData (FILE * FP, Cardinal Number, LayerTypePtr layer)
 {
   int n;
   /* write information about non empty layers */
-  if (layer->LineN || layer->ArcN || layer->TextN || layer->PolygonN ||
+  if (layer->LineN || layer->ArcN || layer->TextN || layer->PourN ||
       (layer->Name && *layer->Name))
     {
       fprintf (FP, "Layer(%i ", (int) Number + 1);
@@ -821,18 +820,18 @@ WriteLayerData (FILE * FP, Cardinal Number, LayerTypePtr layer)
 	  PrintQuotedString (FP, EMPTY (text->TextString));
 	  fprintf (FP, " %s]\n", F2S (text, TEXT_TYPE));
 	}
-      for (n = 0; n < layer->PolygonN; n++)
+      for (n = 0; n < layer->PourN; n++)
 	{
-	  PolygonTypePtr polygon = &layer->Polygon[n];
+	  PourTypePtr pour = &layer->Pour[n];
 	  int p, i = 0;
 	  Cardinal hole = 0;
-	  fprintf (FP, "\tPolygon(%s)\n\t(", F2S (polygon, POLYGON_TYPE));
-	  for (p = 0; p < polygon->PointN; p++)
+	  fprintf (FP, "\tPolygon(%s)\n\t(", F2S (pour, POUR_TYPE));
+	  for (p = 0; p < pour->PointN; p++)
 	    {
-	      PointTypePtr point = &polygon->Points[p];
+	      PointTypePtr point = &pour->Points[p];
 
-	      if (hole < polygon->HoleIndexN &&
-		  p == polygon->HoleIndex[hole])
+	      if (hole < pour->HoleIndexN &&
+		  p == pour->HoleIndex[hole])
 		{
 		  if (hole > 0)
 		    fputs ("\n\t\t)", FP);
diff --git a/src/find.c b/src/find.c
index 039bdfa..848edc9 100644
--- a/src/find.c
+++ b/src/find.c
@@ -628,6 +628,7 @@ void
 InitLayoutLookup (void)
 {
   Cardinal i;
+  int polycount;
 
   /* initialize line arc and polygon data */
   for (i = 0; i < max_layer; i++)
@@ -652,12 +653,18 @@ InitLayoutLookup (void)
 
 
       /* allocate memory for polygon list */
-      if (layer->PolygonN)
+      polycount = 0;
+      POUR_LOOP (layer);
+      {
+        polycount += pour->PolygonN;
+      }
+      END_LOOP;
+      if (polycount)
         {
-          PolygonList[i].Data = (void **) MyCalloc (layer->PolygonN,
+          PolygonList[i].Data = (void **) MyCalloc (polycount,
                                                     sizeof (PolygonTypePtr),
                                                     "InitLayoutLookup()");
-          PolygonList[i].Size = layer->PolygonN;
+          PolygonList[i].Size = polycount;
         }
 
       /* clear some struct members */
@@ -799,6 +806,16 @@ LOCtoPVpoly_callback (const BoxType * b, void *cl)
   return 0;
 }
 
+static int
+LOCtoPVpourPoly_callback (const BoxType * b, void *cl)
+{
+  PourTypePtr pour = (PourTypePtr) b;
+  struct pv_info *i = (struct pv_info *) cl;
+
+  return r_search (pour->polygon_tree, (BoxType *) &i->pv,
+                   NULL, LOCtoPVpoly_callback, i);
+}
+
 /* ---------------------------------------------------------------------------
  * checks if a PV is connected to LOs, if it is, the LO is added to
  * the appropriate list and the 'used' flag is set
@@ -841,8 +858,8 @@ LookupLOConnectionsToPVList (bool AndRats)
             return true;
           /* check all polygons */
           if (setjmp (info.env) == 0)
-            r_search (LAYER_PTR (layer)->polygon_tree, (BoxType *) & info.pv,
-                      NULL, LOCtoPVpoly_callback, &info);
+            r_search (LAYER_PTR (layer)->pour_tree, (BoxType *) & info.pv,
+                      NULL, LOCtoPVpourPoly_callback, &info);
           else
             return true;
         }
@@ -1939,15 +1956,13 @@ LookupLOConnectionsToArc (ArcTypePtr Arc, Cardinal LayerGroup)
   /* loop over all layers of the group */
   for (entry = 0; entry < PCB->LayerGroups.Number[LayerGroup]; entry++)
     {
-      Cardinal layer, i;
+      Cardinal layer;
 
       layer = PCB->LayerGroups.Entries[LayerGroup][entry];
 
       /* handle normal layers */
       if (layer < max_layer)
         {
-          PolygonTypePtr polygon;
-
           info.layer = layer;
           /* add arcs */
           if (setjmp (info.env) == 0)
@@ -1963,12 +1978,18 @@ LookupLOConnectionsToArc (ArcTypePtr Arc, Cardinal LayerGroup)
             return true;
 
           /* now check all polygons */
-          i = 0;
-          polygon = PCB->Data->Layer[layer].Polygon;
-          for (; i < PCB->Data->Layer[layer].PolygonN; i++, polygon++)
-            if (!TEST_FLAG (TheFlag, polygon) && IsArcInPolygon (Arc, polygon)
-                && ADD_POLYGON_TO_LIST (layer, polygon))
-              return true;
+          POUR_LOOP (LAYER_PTR (layer));
+          {
+            POURPOLYGON_LOOP (pour);
+            {
+              if (!TEST_FLAG (TheFlag, polygon) &&
+                  IsArcInPolygon (Arc, polygon) &&
+                  ADD_POLYGON_TO_LIST (layer, polygon))
+                return true;
+            }
+            END_LOOP;
+          }
+          END_LOOP;
         }
       else
         {
@@ -2084,8 +2105,6 @@ LookupLOConnectionsToLine (LineTypePtr Line, Cardinal LayerGroup,
       /* handle normal layers */
       if (layer < max_layer)
         {
-          PolygonTypePtr polygon;
-
           info.layer = layer;
           /* add lines */
           if (setjmp (info.env) == 0)
@@ -2102,13 +2121,18 @@ LookupLOConnectionsToLine (LineTypePtr Line, Cardinal LayerGroup,
           /* now check all polygons */
           if (PolysTo)
             {
-              Cardinal i = 0;
-              polygon = PCB->Data->Layer[layer].Polygon;
-              for (; i < PCB->Data->Layer[layer].PolygonN; i++, polygon++)
-                if (!TEST_FLAG
-                    (TheFlag, polygon) && IsLineInPolygon (Line, polygon)
-                    && ADD_POLYGON_TO_LIST (layer, polygon))
-                  return true;
+              POUR_LOOP (LAYER_PTR (layer));
+              {
+                POURPOLYGON_LOOP (pour);
+                {
+                  if (!TEST_FLAG (TheFlag, polygon) &&
+                      IsLineInPolygon (Line, polygon) &&
+                      ADD_POLYGON_TO_LIST (layer, polygon))
+                    return true;
+                }
+                END_LOOP;
+              }
+              END_LOOP;
             }
         }
       else
@@ -2166,7 +2190,6 @@ static bool
 LOTouchesLine (LineTypePtr Line, Cardinal LayerGroup)
 {
   Cardinal entry;
-  Cardinal i;
   struct lo_info info;
 
 
@@ -2183,8 +2206,6 @@ LOTouchesLine (LineTypePtr Line, Cardinal LayerGroup)
       /* handle normal layers */
       if (layer < max_layer)
         {
-          PolygonTypePtr polygon;
-
           /* find the first line that touches coordinates */
 
           if (setjmp (info.env) == 0)
@@ -2199,12 +2220,17 @@ LOTouchesLine (LineTypePtr Line, Cardinal LayerGroup)
             return (true);
 
           /* now check all polygons */
-          i = 0;
-          polygon = PCB->Data->Layer[layer].Polygon;
-          for (; i < PCB->Data->Layer[layer].PolygonN; i++, polygon++)
-            if (!TEST_FLAG (TheFlag, polygon)
-                && IsLineInPolygon (Line, polygon))
-              return (true);
+          POUR_LOOP (LAYER_PTR (layer));
+          {
+            POURPOLYGON_LOOP (pour);
+            {
+              if (!TEST_FLAG (TheFlag, polygon) &&
+                  IsLineInPolygon (Line, polygon))
+                return (true);
+            }
+            END_LOOP;
+          }
+          END_LOOP;
         }
       else
         {
@@ -2260,6 +2286,16 @@ PolygonToRat_callback (const BoxType * b, void *cl)
 }
 
 static int
+PourPolygonToRat_callback (const BoxType * b, void *cl)
+{
+  PourTypePtr pour = (PourTypePtr) b;
+  struct rat_info *i = (struct rat_info *) cl;
+
+  return r_search_pt (pour->polygon_tree, i->Point, 1,
+                      NULL, PolygonToRat_callback, i);
+}
+
+static int
 LOCtoPad_callback (const BoxType * b, void *cl)
 {
   PadTypePtr pad = (PadTypePtr) b;
@@ -2310,8 +2346,8 @@ LookupLOConnectionsToRatEnd (PointTypePtr Point, Cardinal LayerGroup)
           else
             return true;
           if (setjmp (info.env) == 0)
-            r_search_pt (LAYER_PTR (layer)->polygon_tree, Point, 1,
-                      NULL, PolygonToRat_callback, &info);
+            r_search_pt (LAYER_PTR (layer)->pour_tree, Point, 1,
+                      NULL, PourPolygonToRat_callback, &info);
         }
       else
         {
@@ -2375,6 +2411,16 @@ LOCtoPadPoly_callback (const BoxType * b, void *cl)
 }
 
 static int
+LOCtoPadPourPoly_callback (const BoxType * b, void *cl)
+{
+  PourTypePtr pour = (PourTypePtr) b;
+  struct lo_info *i = (struct lo_info *) cl;
+
+  return r_search (pour->polygon_tree, &i->pad.BoundingBox,
+                   NULL, LOCtoPadPoly_callback, i);
+}
+
+static int
 LOCtoPadRat_callback (const BoxType * b, void *cl)
 {
   RatTypePtr rat = (RatTypePtr) b;
@@ -2464,8 +2510,8 @@ LookupLOConnectionsToPad (PadTypePtr Pad, Cardinal LayerGroup)
             return true;
           /* add polygons */
           if (setjmp (info.env) == 0)
-            r_search (LAYER_PTR (layer)->polygon_tree, &info.pad.BoundingBox,
-                      NULL, LOCtoPadPoly_callback, &info);
+            r_search (LAYER_PTR (layer)->pour_tree, &info.pad.BoundingBox,
+                      NULL, LOCtoPadPourPoly_callback, &info);
           else
             return true;
         }
@@ -2575,25 +2621,30 @@ LookupLOConnectionsToPolygon (PolygonTypePtr Polygon, Cardinal LayerGroup)
 /* loop over all layers of the group */
   for (entry = 0; entry < PCB->LayerGroups.Number[LayerGroup]; entry++)
     {
-      Cardinal layer, i;
+      Cardinal layer;
 
       layer = PCB->LayerGroups.Entries[LayerGroup][entry];
 
       /* handle normal layers */
       if (layer < max_layer)
         {
-          PolygonTypePtr polygon;
+          info.layer = layer;
 
           /* check all polygons */
 
-          polygon = PCB->Data->Layer[layer].Polygon;
-          for (i = 0; i < PCB->Data->Layer[layer].PolygonN; i++, polygon++)
-            if (!TEST_FLAG (TheFlag, polygon)
-                && IsPolygonInPolygon (polygon, Polygon)
-                && ADD_POLYGON_TO_LIST (layer, polygon))
-              return true;
+          POUR_LOOP (LAYER_PTR (layer));
+          {
+            POURPOLYGON_LOOP (pour);
+            {
+              if (!TEST_FLAG (TheFlag, polygon) &&
+                  IsPolygonInPolygon (polygon, Polygon) &&
+                  ADD_POLYGON_TO_LIST (layer, polygon))
+                return true;
+            }
+            END_LOOP;
+          }
+          END_LOOP;
 
-          info.layer = layer;
           /* check all lines */
           if (setjmp (info.env) == 0)
             r_search (LAYER_PTR (layer)->line_tree,
@@ -3555,17 +3606,21 @@ ResetFoundLinesAndPolygons (bool AndDraw)
       }
   }
   ENDALL_LOOP;
-  COPPERPOLYGON_LOOP (PCB->Data);
+  COPPERPOUR_LOOP (PCB->Data);
   {
-    if (TEST_FLAG (TheFlag, polygon))
-      {
-        if (AndDraw)
-          AddObjectToFlagUndoList (POLYGON_TYPE, layer, polygon, polygon);
-        CLEAR_FLAG (TheFlag, polygon);
-        if (AndDraw)
-          DrawPolygon (layer, polygon, 0);
-        change = true;
-      }
+    POURPOLYGON_LOOP (pour);
+    {
+      if (TEST_FLAG (TheFlag, polygon))
+        {
+          if (AndDraw)
+            AddObjectToFlagUndoList (POLYGON_TYPE, layer, polygon, polygon);
+          CLEAR_FLAG (TheFlag, polygon);
+          if (AndDraw)
+            DrawPolygon (layer, polygon, 0);
+          change = true;
+        }
+    }
+    END_LOOP;
   }
   ENDALL_LOOP;
   if (change)
diff --git a/src/find.h b/src/find.h
index 5b04980..f93fca1 100644
--- a/src/find.h
+++ b/src/find.h
@@ -42,7 +42,7 @@
 #define LOOKUP_MORE	\
 	(VIA_TYPE | LINE_TYPE | RATLINE_TYPE | POLYGON_TYPE | ARC_TYPE)
 #define SILK_TYPE	\
-	(LINE_TYPE | ARC_TYPE | POLYGON_TYPE)
+	(LINE_TYPE | ARC_TYPE | POUR_TYPE)
 
 bool LineLineIntersect (LineTypePtr, LineTypePtr);
 bool LineArcIntersect (LineTypePtr, ArcTypePtr);
diff --git a/src/flags.c b/src/flags.c
index 60688dd..95b72f6 100644
--- a/src/flags.c
+++ b/src/flags.c
@@ -191,8 +191,9 @@ HID_Flag flags_flag_list[] = {
   {"lockmode", FlagMode, LOCK_MODE},
   {"movemode", FlagMode, MOVE_MODE},
   {"pastebuffermode", FlagMode, PASTEBUFFER_MODE},
-  {"polygonmode", FlagMode, POLYGON_MODE},
-  {"polygonholemode", FlagMode, POLYGONHOLE_MODE},
+//  {"polygonmode", FlagMode, POLYGON_MODE},
+  {"pourmode", FlagMode, POUR_MODE},
+  {"pourholemode", FlagMode, POURHOLE_MODE},
   {"rectanglemode", FlagMode, RECTANGLE_MODE},
   {"removemode", FlagMode, REMOVE_MODE},
   {"rotatemode", FlagMode, ROTATE_MODE},
diff --git a/src/global.h b/src/global.h
index bb78abc..3d5f28f 100644
--- a/src/global.h
+++ b/src/global.h
@@ -251,19 +251,49 @@ typedef struct
   void *Element;
 } TextType, *TextTypePtr;
 
-struct polygon_st			/* holds information about a polygon */
+struct rtree
+{
+  struct rtree_node *root;
+  int size;			/* number of entries in tree */
+};
+
+typedef struct			/* holds information about a polygon */
 {
   ANYOBJECTFIELDS;
-  Cardinal PointN,		/* number of points in polygon */
-    PointMax;			/* max number from malloc() */
-  POLYAREA *Clipped;		/* the clipped region of this polygon */
-  PLINE *NoHoles;		/* the polygon broken into hole-less regions */
-  int NoHolesValid;		/* Is the NoHoles polygon up to date? */
-  PointTypePtr Points;		/* data */
-  Cardinal *HoleIndex;		/* Index of hole data within the Points array */
+
+  Cardinal PointN;		/* number of points in pour outline */
+  Cardinal PointMax;		/* max number from malloc() */
+  PointTypePtr Points;		/* pour outline data */
+
   Cardinal HoleIndexN;		/* number of holes in polygon */
   Cardinal HoleIndexMax;	/* max number from malloc() */
+  Cardinal *HoleIndex;		/* Index of hole data within the Points array */
+
+  Cardinal PolygonN;		/* number of polygons this pour has */
+  Cardinal PolygonMax;		/* max number from malloc() */
+  PolygonTypePtr Polygons;	/* pour polygons */
+
+  rtree_t *polygon_tree;	/* r-tree of child polygons */
+
+} PourType, *PourTypePtr;
 
+struct polygon_st		/* holds information about a polygon */
+{
+  ANYOBJECTFIELDS;
+
+//  Cardinal PointN,		/* number of points in polygon */
+//  Cardinal PointMax;		/* max number from malloc() */
+//  PointTypePtr Points;		/* data */
+
+//  Cardinal HoleIndexN;		/* number of holes in polygon */
+//  Cardinal HoleIndexMax;	/* max number from malloc() */
+//  Cardinal *HoleIndex;		/* Index of hole data within the Points array */
+
+  POLYAREA *Clipped;		/* the clipped region of this polygon */
+  PLINE *NoHoles;		/* the clipped polygon broken into hole-less regions */
+  int NoHolesValid;		/* Is the NoHoles polygon up to date? */
+
+  PourTypePtr ParentPour;	/* The pour which resulted in this polygon */
 };
 
 typedef struct			/* holds information about arcs */
@@ -277,26 +307,25 @@ typedef struct			/* holds information about arcs */
     Delta;
 } ArcType, *ArcTypePtr;
 
-struct rtree
-{
-  struct rtree_node *root;
-  int size;			/* number of entries in tree */
-};
-
 typedef struct			/* holds information about one layer */
 {
   char *Name;			/* layer name */
   Cardinal LineN,		/* number of lines */
     TextN,			/* labels */
-    PolygonN,			/* polygons */
+//    PolygonN,			/* polygons */
+    PourN,			/* poured areas */
     ArcN,			/* and arcs */
     LineMax,			/* max number from malloc() */
-    TextMax, PolygonMax, ArcMax;
+    TextMax,
+//    PolygonMax,
+    PourMax,
+    ArcMax;
   LineTypePtr Line;		/* pointer to additional structures */
   TextTypePtr Text;
-  PolygonTypePtr Polygon;
+//  PolygonTypePtr Polygon;
+  PourTypePtr Pour;
   ArcTypePtr Arc;
-  rtree_t *line_tree, *text_tree, *polygon_tree, *arc_tree;
+  rtree_t *line_tree, *text_tree, *pour_tree, *arc_tree;
   bool On;			/* visible flag */
   char *Color,			/* color */
    *SelectedColor;
@@ -581,7 +610,8 @@ typedef struct			/* holds cursor information */
   bool On;			/* flag for 'is visible' */
   AttachedLineType AttachedLine;	/* data of new lines... */
   AttachedBoxType AttachedBox;
-  PolygonType AttachedPolygon;
+//  PolygonType AttachedPolygon;
+  PourType AttachedPour;
   AttachedObjectType AttachedObject;	/* data of attached objects */
   enum crosshair_shape shape; /* shape of crosshair */
 } CrosshairType, *CrosshairTypePtr;
@@ -696,13 +726,15 @@ typedef struct
   void *(*Line) (LayerTypePtr, LineTypePtr);
   void *(*Text) (LayerTypePtr, TextTypePtr);
   void *(*Polygon) (LayerTypePtr, PolygonTypePtr);
+  void *(*Pour) (LayerTypePtr, PourTypePtr);
   void *(*Via) (PinTypePtr);
   void *(*Element) (ElementTypePtr);
   void *(*ElementName) (ElementTypePtr);
   void *(*Pin) (ElementTypePtr, PinTypePtr);
   void *(*Pad) (ElementTypePtr, PadTypePtr);
   void *(*LinePoint) (LayerTypePtr, LineTypePtr, PointTypePtr);
-  void *(*Point) (LayerTypePtr, PolygonTypePtr, PointTypePtr);
+//  void *(*PolygonPoint) (LayerTypePtr, PolygonTypePtr, PointTypePtr);
+  void *(*PourPoint) (LayerTypePtr, PourTypePtr, PointTypePtr);
   void *(*Arc) (LayerTypePtr, ArcTypePtr);
   void *(*Rat) (RatTypePtr);
 } ObjectFunctionType, *ObjectFunctionTypePtr;
diff --git a/src/gpcb-menu.res b/src/gpcb-menu.res
index e92a59a..01d2dab 100644
--- a/src/gpcb-menu.res
+++ b/src/gpcb-menu.res
@@ -508,8 +508,8 @@ PopupMenus =
        {"Arc" checked=arcmode,1 Mode(Arc) a={"F3" "<Key>F3"}}
        {"Text" checked=textmode,1 Mode(Text) a={"F4" "<Key>F4"}}
        {"Rectangle" checked=rectanglemode,1 Mode(Rectangle) a={"F5" "<Key>F5"}}
-       {"Polygon" checked=polygonmode,1 Mode(Polygon) a={"F6" "<Key>F6"}}
-       {"Polygon Hole" checked=polygonholemode,1 Mode(PolygonHole)}
+       {"Polygon" checked=pourmode,1 Mode(Pour) a={"F6" "<Key>F6"}}
+       {"Polygon Hole" checked=pourholemode,1 Mode(PourHole)}
        {"Buffer" checked=pastebuffermode,1 Mode(PasteBuffer) a={"F7" "<Key>F7"}}
        {"Remove" checked=removemode,1 Mode(Remove) a={"F8" "<Key>F8"}}
        {"Rotate" checked=rotatemode,1 Mode(Rotate) a={"F9" "<Key>F9"}}
diff --git a/src/hid/gcode/gcode.c b/src/hid/gcode/gcode.c
index c3c2e4e..86bac04 100644
--- a/src/hid/gcode/gcode.c
+++ b/src/hid/gcode/gcode.c
@@ -281,7 +281,7 @@ gcode_choose_groups ()
     {
       layer = &PCB->Data->Layer[n];
 
-      if (layer->LineN || layer->TextN || layer->ArcN || layer->PolygonN)
+      if (layer->LineN || layer->TextN || layer->ArcN || layer->PourN)
 	{
 	  /* layer isn't empty */
 
diff --git a/src/hid/gerber/gerber.c b/src/hid/gerber/gerber.c
index 8a46c3c..e235349 100644
--- a/src/hid/gerber/gerber.c
+++ b/src/hid/gerber/gerber.c
@@ -383,7 +383,7 @@ gerber_do_export (HID_Attr_Val * options)
   for (i = 0; i < max_layer; i++)
     {
       LayerType *layer = PCB->Data->Layer + i;
-      if (layer->LineN || layer->TextN || layer->ArcN || layer->PolygonN)
+      if (layer->LineN || layer->TextN || layer->ArcN || layer->PourN)
 	print_group[GetLayerGroupNumberByNumber (i)] = 1;
     }
   print_group[GetLayerGroupNumberByNumber (max_layer)] = 1;
diff --git a/src/hid/gtk/gui-drc-window.c b/src/hid/gtk/gui-drc-window.c
index e2fa201..2726c07 100644
--- a/src/hid/gtk/gui-drc-window.c
+++ b/src/hid/gtk/gui-drc-window.c
@@ -166,15 +166,19 @@ unset_found_flags (int AndDraw)
       }
   }
   ENDALL_LOOP;
-  COPPERPOLYGON_LOOP (PCB->Data);
+  COPPERPOUR_LOOP (PCB->Data);
   {
-    if (TEST_FLAG (flag, polygon))
-      {
-	AddObjectToFlagUndoList (POLYGON_TYPE, layer, polygon, polygon);
-	CLEAR_FLAG (flag, polygon);
-	DrawPolygon (layer, polygon, 0);
-	change = true;
-      }
+    POURPOLYGON_LOOP (pour);
+    {
+      if (TEST_FLAG (flag, polygon))
+        {
+          AddObjectToFlagUndoList (POLYGON_TYPE, layer, polygon, polygon);
+          CLEAR_FLAG (flag, polygon);
+          DrawPolygon (layer, polygon, 0);
+          change = true;
+        }
+    }
+    END_LOOP;
   }
   ENDALL_LOOP;
   if (change)
diff --git a/src/hid/gtk/gui-icons-mode-buttons.data b/src/hid/gtk/gui-icons-mode-buttons.data
index be040f1..432d47f 100644
--- a/src/hid/gtk/gui-icons-mode-buttons.data
+++ b/src/hid/gtk/gui-icons-mode-buttons.data
@@ -252,7 +252,7 @@ static char *pan[] = {
 
 #endif
 /* XPM */
-static char *poly[] = {
+static char *pour[] = {
 /* columns rows colors chars-per-pixel */
 "21 21 4 1",
 "  c black",
@@ -284,7 +284,7 @@ static char *poly[] = {
 };
 
 /* XPM */
-static char * polyhole[] = {
+static char * pourhole[] = {
 "21 21 3 1",
 " 	c None",
 ".	c #6EA5D7",
diff --git a/src/hid/gtk/gui-misc.c b/src/hid/gtk/gui-misc.c
index a607a69..f36c400 100644
--- a/src/hid/gtk/gui-misc.c
+++ b/src/hid/gtk/gui-misc.c
@@ -219,8 +219,8 @@ ghid_mode_cursor (int Mode)
       gport_set_cursor (GDK_LEFT_PTR);
       break;
 
-    case POLYGON_MODE:
-    case POLYGONHOLE_MODE:
+    case POUR_MODE:
+    case POURHOLE_MODE:
       gport_set_cursor (GDK_SB_UP_ARROW);
       break;
 
diff --git a/src/hid/gtk/gui-output-events.c b/src/hid/gtk/gui-output-events.c
index 37c2e48..7f58605 100644
--- a/src/hid/gtk/gui-output-events.c
+++ b/src/hid/gtk/gui-output-events.c
@@ -461,8 +461,8 @@ have_crosshair_attachments (void)
     case VIA_MODE:
       result = TRUE;
       break;
-    case POLYGON_MODE:
-    case POLYGONHOLE_MODE:
+    case POUR_MODE:
+    case POURHOLE_MODE:
       if (Crosshair.AttachedLine.State != STATE_FIRST)
 	result = TRUE;
       break;
diff --git a/src/hid/gtk/gui-top-window.c b/src/hid/gtk/gui-top-window.c
index 26f29b4..dbe0be5 100644
--- a/src/hid/gtk/gui-top-window.c
+++ b/src/hid/gtk/gui-top-window.c
@@ -1984,8 +1984,9 @@ static ModeButton mode_buttons[] = {
   {NULL, NULL, NULL, "arc", ARC_MODE, arc},
   {NULL, NULL, NULL, "text", TEXT_MODE, text},
   {NULL, NULL, NULL, "rectangle", RECTANGLE_MODE, rect},
-  {NULL, NULL, NULL, "polygon", POLYGON_MODE, poly},
-  {NULL, NULL, NULL, "polygonhole", POLYGONHOLE_MODE, polyhole},
+//  {NULL, NULL, NULL, "polygon", POLYGON_MODE, poly},
+  {NULL, NULL, NULL, "pour", POUR_MODE, pour},
+  {NULL, NULL, NULL, "pourhole", POURHOLE_MODE, pourhole},
   {NULL, NULL, NULL, "buffer", PASTEBUFFER_MODE, buf},
   {NULL, NULL, NULL, "remove", REMOVE_MODE, del},
   {NULL, NULL, NULL, "rotate", ROTATE_MODE, rot},
diff --git a/src/hid/nelma/nelma.c b/src/hid/nelma/nelma.c
index 688adce..885299b 100644
--- a/src/hid/nelma/nelma.c
+++ b/src/hid/nelma/nelma.c
@@ -526,7 +526,7 @@ nelma_choose_groups()
 		layer = &PCB->Data->Layer[n];
 
 		if (layer->LineN || layer->TextN || layer->ArcN ||
-		    layer->PolygonN) {
+		    layer->PourN) {
 			/* layer isn't empty */
 
 			/*
diff --git a/src/hid/png/png.c b/src/hid/png/png.c
index 0c292cd..46bd92b 100644
--- a/src/hid/png/png.c
+++ b/src/hid/png/png.c
@@ -333,7 +333,7 @@ png_hid_export_to_file (FILE * the_file, HID_Attr_Val * options)
   for (i = 0; i < max_layer; i++)
     {
       LayerType *layer = PCB->Data->Layer + i;
-      if (layer->LineN || layer->TextN || layer->ArcN || layer->PolygonN)
+      if (layer->LineN || layer->TextN || layer->ArcN || layer->PourN)
 	print_group[GetLayerGroupNumberByNumber (i)] = 1;
     }
   print_group[GetLayerGroupNumberByNumber (max_layer)] = 1;
diff --git a/src/hid/ps/eps.c b/src/hid/ps/eps.c
index d67947d..16e0718 100644
--- a/src/hid/ps/eps.c
+++ b/src/hid/ps/eps.c
@@ -150,7 +150,7 @@ eps_hid_export_to_file (FILE * the_file, HID_Attr_Val * options)
     {
       LayerType *layer = PCB->Data->Layer + i;
       if (layer->On)
-	if (layer->LineN || layer->TextN || layer->ArcN || layer->PolygonN)
+	if (layer->LineN || layer->TextN || layer->ArcN || layer->PourN)
 	  print_group[GetLayerGroupNumberByNumber (i)] = 1;
     }
 
diff --git a/src/hid/ps/ps.c b/src/hid/ps/ps.c
index 2a7a4d7..394f41b 100644
--- a/src/hid/ps/ps.c
+++ b/src/hid/ps/ps.c
@@ -481,7 +481,7 @@ ps_hid_export_to_file (FILE * the_file, HID_Attr_Val * options)
   for (i = 0; i < max_layer; i++)
     {
       LayerType *layer = PCB->Data->Layer + i;
-      if (layer->LineN || layer->TextN || layer->ArcN || layer->PolygonN)
+      if (layer->LineN || layer->TextN || layer->ArcN || layer->PourN)
 	print_group[GetLayerGroupNumberByNumber (i)] = 1;
 
       if (strcmp (layer->Name, "outline") == 0 ||
diff --git a/src/insert.c b/src/insert.c
index 5e62463..19e61f2 100644
--- a/src/insert.c
+++ b/src/insert.c
@@ -46,6 +46,7 @@
 #include "misc.h"
 #include "move.h"
 #include "polygon.h"
+#include "pour.h"
 #include "rtree.h"
 #include "search.h"
 #include "select.h"
@@ -65,7 +66,7 @@ RCSID ("$Id$");
  * some local prototypes
  */
 static void *InsertPointIntoLine (LayerTypePtr, LineTypePtr);
-static void *InsertPointIntoPolygon (LayerTypePtr, PolygonTypePtr);
+static void *InsertPointIntoPour (LayerTypePtr, PourTypePtr);
 static void *InsertPointIntoRat (RatTypePtr);
 
 /* ---------------------------------------------------------------------------
@@ -79,7 +80,8 @@ static bool Forcible;
 static ObjectFunctionType InsertFunctions = {
   InsertPointIntoLine,
   NULL,
-  InsertPointIntoPolygon,
+  NULL,
+  InsertPointIntoPour,
   NULL,
   NULL,
   NULL,
@@ -160,10 +162,10 @@ InsertPointIntoLine (LayerTypePtr Layer, LineTypePtr Line)
 }
 
 /* ---------------------------------------------------------------------------
- * inserts a point into a polygon
+ * inserts a point into a pour
  */
 static void *
-InsertPointIntoPolygon (LayerTypePtr Layer, PolygonTypePtr Polygon)
+InsertPointIntoPour (LayerTypePtr Layer, PourTypePtr Pour)
 {
   PointType save;
   Cardinal n;
@@ -175,40 +177,40 @@ InsertPointIntoPolygon (LayerTypePtr Layer, PolygonTypePtr Polygon)
        * first make sure adding the point is sensible
        */
       line.Thickness = 0;
-      line.Point1 = Polygon->Points[prev_contour_point (Polygon, InsertAt)];
-      line.Point2 = Polygon->Points[InsertAt];
+      line.Point1 = Pour->Points[prev_contour_point (Pour, InsertAt)];
+      line.Point2 = Pour->Points[InsertAt];
       if (IsPointOnLine ((float) InsertX, (float) InsertY, 0.0, &line))
 	return (NULL);
     }
   /*
    * second, shift the points up to make room for the new point
    */
-  ErasePolygon (Polygon);
-  r_delete_entry (Layer->polygon_tree, (BoxTypePtr) Polygon);
-  save = *CreateNewPointInPolygon (Polygon, InsertX, InsertY);
-  for (n = Polygon->PointN - 1; n > InsertAt; n--)
-    Polygon->Points[n] = Polygon->Points[n - 1];
+  ErasePour (Pour);
+  r_delete_entry (Layer->pour_tree, (BoxTypePtr) Pour);
+  save = *CreateNewPointInPour (Pour, InsertX, InsertY);
+  for (n = Pour->PointN - 1; n > InsertAt; n--)
+    Pour->Points[n] = Pour->Points[n - 1];
 
   /* Shift up indices of any holes */
-  for (n = 0; n < Polygon->HoleIndexN; n++)
-    if (Polygon->HoleIndex[n] > InsertAt ||
-	(InsertLast && Polygon->HoleIndex[n] == InsertAt))
-      Polygon->HoleIndex[n]++;
+  for (n = 0; n < Pour->HoleIndexN; n++)
+    if (Pour->HoleIndex[n] > InsertAt ||
+	(InsertLast && Pour->HoleIndex[n] == InsertAt))
+      Pour->HoleIndex[n]++;
 
-  Polygon->Points[InsertAt] = save;
+  Pour->Points[InsertAt] = save;
   SetChangedFlag (true);
-  AddObjectToInsertPointUndoList (POLYGONPOINT_TYPE, Layer, Polygon,
-				  &Polygon->Points[InsertAt]);
+  AddObjectToInsertPointUndoList (POURPOINT_TYPE, Layer, Pour,
+				  &Pour->Points[InsertAt]);
 
-  SetPolygonBoundingBox (Polygon);
-  r_insert_entry (Layer->polygon_tree, (BoxType *) Polygon, 0);
-  InitClip (PCB->Data, Layer, Polygon);
-  if (Forcible || !RemoveExcessPolygonPoints (Layer, Polygon))
+  SetPourBoundingBox (Pour);
+  r_insert_entry (Layer->pour_tree, (BoxType *) Pour, 0);
+  InitPourClip (PCB->Data, Layer, Pour);
+  if (Forcible || !RemoveExcessPourPoints (Layer, Pour))
     {
-      DrawPolygon (Layer, Polygon, 0);
+      DrawPour (Layer, Pour, 0);
       Draw ();
     }
-  return (&Polygon->Points[InsertAt]);
+  return (&Pour->Points[InsertAt]);
 }
 
 /* ---------------------------------------------------------------------------
diff --git a/src/insert.h b/src/insert.h
index 350a0de..67d1b78 100644
--- a/src/insert.h
+++ b/src/insert.h
@@ -33,7 +33,7 @@
 
 #include "global.h"
 
-#define	INSERT_TYPES	(POLYGON_TYPE | LINE_TYPE | RATLINE_TYPE)
+#define	INSERT_TYPES	(POUR_TYPE | LINE_TYPE | RATLINE_TYPE)
 
 /* ---------------------------------------------------------------------------
  * prototypes
diff --git a/src/macro.h b/src/macro.h
index 819d202..f9200b0 100644
--- a/src/macro.h
+++ b/src/macro.h
@@ -391,19 +391,26 @@ extern int mem_any_set (unsigned char *, int);
 	{						\
 		text = &(layer)->Text[n]
 
-#define	POLYGON_LOOP(layer) do {			\
+#define	POUR_LOOP(layer) do {			\
 	Cardinal		n;			\
-	PolygonTypePtr	polygon;			\
-	for (n = (layer)->PolygonN-1; n != -1; n--)	\
+	PourTypePtr	pour;			\
+	for (n = (layer)->PourN-1; n != -1; n--)	\
 	{						\
-		polygon = &(layer)->Polygon[n]
+		pour = &(layer)->Pour[n]
 
-#define	POLYGONPOINT_LOOP(polygon) do	{	\
+#define	POURPOINT_LOOP(pour) do	{	\
 	Cardinal			n;		\
 	PointTypePtr	point;				\
-	for (n = (polygon)->PointN-1; n != -1; n--)	\
+	for (n = (pour)->PointN-1; n != -1; n--)	\
 	{						\
-		point = &(polygon)->Points[n]
+		point = &(pour)->Points[n]
+
+#define	POURPOLYGON_LOOP(pour) do	{	\
+	Cardinal			n;		\
+	PolygonTypePtr	polygon;				\
+	for (n = (pour)->PolygonN-1; n != -1; n--)	\
+	{						\
+		polygon = &(pour)->Polygons[n]
 
 #define ENDALL_LOOP }} while (0);  }} while (0)
 
@@ -429,12 +436,12 @@ extern int mem_any_set (unsigned char *, int);
 	{ \
 		ARC_LOOP(layer)
 
-#define	ALLPOLYGON_LOOP(top)	do {		\
+#define	ALLPOUR_LOOP(top)	do {		\
 	Cardinal		l;			\
 	LayerTypePtr	layer = (top)->Layer;		\
 	for (l = 0; l < max_layer + 2; l++, layer++)	\
 	{ \
-		POLYGON_LOOP(layer)
+		POUR_LOOP(layer)
 
 #define	COPPERLINE_LOOP(top) do	{		\
 	Cardinal		l;			\
@@ -450,12 +457,12 @@ extern int mem_any_set (unsigned char *, int);
 	{ \
 		ARC_LOOP(layer)
 
-#define	COPPERPOLYGON_LOOP(top) do	{		\
+#define	COPPERPOUR_LOOP(top) do	{		\
 	Cardinal		l;			\
 	LayerTypePtr	layer = (top)->Layer;		\
 	for (l = 0; l < max_layer; l++, layer++)	\
 	{ \
-		POLYGON_LOOP(layer)
+		POUR_LOOP(layer)
 
 #define	SILKLINE_LOOP(top) do	{		\
 	Cardinal		l;			\
@@ -473,13 +480,13 @@ extern int mem_any_set (unsigned char *, int);
 	{ \
 		ARC_LOOP(layer)
 
-#define	SILKPOLYGON_LOOP(top) do	{		\
+#define	SILKPOUR_LOOP(top) do	{		\
 	Cardinal		l;			\
 	LayerTypePtr	layer = (top)->Layer;		\
 	layer += max_layer;				\
 	for (l = 0; l < 2; l++, layer++)		\
 	{ \
-		POLYGON_LOOP(layer)
+		POUR_LOOP(layer)
 
 #define	ALLTEXT_LOOP(top)	do {		\
 	Cardinal		l;			\
@@ -512,13 +519,13 @@ extern int mem_any_set (unsigned char *, int);
                 TEXT_LOOP(layer);                                      \
                   if (TEXT_IS_VISIBLE((board), layer, text))
 
-#define	VISIBLEPOLYGON_LOOP(top) do	{	\
+#define	VISIBLEPOUR_LOOP(top) do	{	\
 	Cardinal		l;			\
 	LayerTypePtr	layer = (top)->Layer;		\
 	for (l = 0; l < max_layer + 2; l++, layer++)	\
 	{ \
 		if (layer->On)				\
-			POLYGON_LOOP(layer)
+			POUR_LOOP(layer)
 
 #define POINTER_LOOP(top) do	{	\
 	Cardinal	n;			\
diff --git a/src/mirror.c b/src/mirror.c
index 7ef7d41..1b76e88 100644
--- a/src/mirror.c
+++ b/src/mirror.c
@@ -46,6 +46,7 @@
 #include "mirror.h"
 #include "misc.h"
 #include "polygon.h"
+#include "pour.h"
 #include "search.h"
 #include "select.h"
 #include "set.h"
@@ -78,14 +79,14 @@ MirrorElementCoordinates (DataTypePtr Data, ElementTypePtr Element,
   END_LOOP;
   PIN_LOOP (Element);
   {
-    RestoreToPolygon (Data, PIN_TYPE, Element, pin);
+    RestoreToPours (Data, PIN_TYPE, Element, pin);
     pin->X = SWAP_X (pin->X);
     pin->Y = SWAP_Y (pin->Y) + yoff;
   }
   END_LOOP;
   PAD_LOOP (Element);
   {
-    RestoreToPolygon (Data, PAD_TYPE, Element, pad);
+    RestoreToPours (Data, PAD_TYPE, Element, pad);
     pad->Point1.X = SWAP_X (pad->Point1.X);
     pad->Point1.Y = SWAP_Y (pad->Point1.Y) + yoff;
     pad->Point2.X = SWAP_X (pad->Point2.X);
@@ -115,5 +116,5 @@ MirrorElementCoordinates (DataTypePtr Data, ElementTypePtr Element,
   TOGGLE_FLAG (ONSOLDERFLAG, Element);
   /* this inserts all of the rtree data too */
   SetElementBoundingBox (Data, Element, &PCB->Font);
-  ClearFromPolygon (Data, ELEMENT_TYPE, Element, Element);
+  ClearFromPours (Data, ELEMENT_TYPE, Element, Element);
 }
diff --git a/src/misc.c b/src/misc.c
index dfbb1d7..ada4878 100644
--- a/src/misc.c
+++ b/src/misc.c
@@ -66,6 +66,7 @@
 #include "misc.h"
 #include "move.h"
 #include "polygon.h"
+#include "pour.h"
 #include "remove.h"
 #include "rtree.h"
 #include "rotate.h"
@@ -242,22 +243,35 @@ SetLineBoundingBox (LineTypePtr Line)
 }
 
 /* ---------------------------------------------------------------------------
- * sets the bounding box of a polygons
+ * sets the bounding box of a polygon
  */
 void
 SetPolygonBoundingBox (PolygonTypePtr Polygon)
 {
-  Polygon->BoundingBox.X1 = Polygon->BoundingBox.Y1 = MAX_COORD;
-  Polygon->BoundingBox.X2 = Polygon->BoundingBox.Y2 = 0;
-  POLYGONPOINT_LOOP (Polygon);
+  PLINE *outer = Polygon->Clipped->contours;
+  Polygon->BoundingBox.X1 = outer->xmin;
+  Polygon->BoundingBox.Y1 = outer->ymin;
+  Polygon->BoundingBox.X2 = outer->xmax;
+  Polygon->BoundingBox.Y2 = outer->ymax;
+}
+
+/* ---------------------------------------------------------------------------
+ * sets the bounding box of a pour
+ */
+void
+SetPourBoundingBox (PourTypePtr Pour)
+{
+  Pour->BoundingBox.X1 = Pour->BoundingBox.Y1 = MAX_COORD;
+  Pour->BoundingBox.X2 = Pour->BoundingBox.Y2 = 0;
+  POURPOINT_LOOP (Pour);
   {
-    MAKEMIN (Polygon->BoundingBox.X1, point->X);
-    MAKEMIN (Polygon->BoundingBox.Y1, point->Y);
-    MAKEMAX (Polygon->BoundingBox.X2, point->X);
-    MAKEMAX (Polygon->BoundingBox.Y2, point->Y);
+    MAKEMIN (Pour->BoundingBox.X1, point->X);
+    MAKEMIN (Pour->BoundingBox.Y1, point->Y);
+    MAKEMAX (Pour->BoundingBox.X2, point->X);
+    MAKEMAX (Pour->BoundingBox.Y2, point->Y);
   }
   /* boxes don't include the lower right corner */
-  close_box(&Polygon->BoundingBox);
+  close_box(&Pour->BoundingBox);
   END_LOOP;
 }
 
@@ -499,7 +513,9 @@ IsDataEmpty (DataTypePtr Data)
     hasNoObjects = hasNoObjects &&
       Data->Layer[i].LineN == 0 &&
       Data->Layer[i].ArcN == 0 &&
-      Data->Layer[i].TextN == 0 && Data->Layer[i].PolygonN == 0;
+      Data->Layer[i].TextN == 0 &&
+      Data->Layer[i].PourN == 0;
+
   return (hasNoObjects);
 }
 
@@ -579,13 +595,17 @@ GetDataBoundingBox (DataTypePtr Data)
     box.Y2 = MAX (box.Y2, text->BoundingBox.Y2);
   }
   ENDALL_LOOP;
-  ALLPOLYGON_LOOP (Data);
-  {
-    box.X1 = MIN (box.X1, polygon->BoundingBox.X1);
-    box.Y1 = MIN (box.Y1, polygon->BoundingBox.Y1);
-    box.X2 = MAX (box.X2, polygon->BoundingBox.X2);
-    box.Y2 = MAX (box.Y2, polygon->BoundingBox.Y2);
-  }
+  ALLPOUR_LOOP (Data);
+    {
+      POURPOLYGON_LOOP (pour);
+      {
+        box.X1 = MIN (box.X1, polygon->BoundingBox.X1);
+        box.Y1 = MIN (box.Y1, polygon->BoundingBox.Y1);
+        box.X2 = MAX (box.X2, polygon->BoundingBox.X2);
+        box.Y2 = MAX (box.Y2, polygon->BoundingBox.Y2);
+      }
+      END_LOOP;
+    }
   ENDALL_LOOP;
   return (IsDataEmpty (Data) ? NULL : &box);
 }
@@ -1223,6 +1243,7 @@ GetObjectBoundingBox (int Type, void *Ptr1, void *Ptr2, void *Ptr3)
     case ARC_TYPE:
     case TEXT_TYPE:
     case POLYGON_TYPE:
+    case POUR_TYPE:
     case PAD_TYPE:
     case PIN_TYPE:
     case ELEMENTNAME_TYPE:
@@ -1230,7 +1251,7 @@ GetObjectBoundingBox (int Type, void *Ptr1, void *Ptr2, void *Ptr3)
     case VIA_TYPE:
     case ELEMENT_TYPE:
       return (BoxType *)Ptr1;
-    case POLYGONPOINT_TYPE:
+    case POURPOINT_TYPE:
     case LINEPOINT_TYPE:
       return (BoxType *)Ptr3;
     default:
@@ -1500,14 +1521,14 @@ ChangeArcAngles (LayerTypePtr Layer, ArcTypePtr a,
       new_da = 360;
       new_sa = 0;
     }
-  RestoreToPolygon (PCB->Data, ARC_TYPE, Layer, a);
+  RestoreToPours (PCB->Data, ARC_TYPE, Layer, a);
   r_delete_entry (Layer->arc_tree, (BoxTypePtr) a);
   AddObjectToChangeAnglesUndoList (ARC_TYPE, a, a, a);
   a->StartAngle = new_sa;
   a->Delta = new_da;
   SetArcBoundingBox (a);
   r_insert_entry (Layer->arc_tree, (BoxTypePtr) a, 0);
-  ClearFromPolygon (PCB->Data, ARC_TYPE, Layer, a);
+  ClearFromPours (PCB->Data, ARC_TYPE, Layer, a);
 }
 
 static char *
@@ -1592,13 +1613,8 @@ GetGridLockCoordinates (int type, void *ptr1,
       *x = ((ElementTypePtr) ptr2)->MarkX;
       *y = ((ElementTypePtr) ptr2)->MarkY;
       break;
-    case POLYGON_TYPE:
-      *x = ((PolygonTypePtr) ptr2)->Points[0].X;
-      *y = ((PolygonTypePtr) ptr2)->Points[0].Y;
-      break;
-
     case LINEPOINT_TYPE:
-    case POLYGONPOINT_TYPE:
+    case POURPOINT_TYPE:
       *x = ((PointTypePtr) ptr3)->X;
       *y = ((PointTypePtr) ptr3)->Y;
       break;
diff --git a/src/misc.h b/src/misc.h
index d58e12e..b263efc 100644
--- a/src/misc.h
+++ b/src/misc.h
@@ -42,6 +42,7 @@ void SetPointBoundingBox (PointTypePtr);
 void SetPinBoundingBox (PinTypePtr);
 void SetPadBoundingBox (PadTypePtr);
 void SetPolygonBoundingBox (PolygonTypePtr);
+void SetPourBoundingBox (PourTypePtr);
 void SetElementBoundingBox (DataTypePtr, ElementTypePtr, FontTypePtr);
 bool IsDataEmpty (DataTypePtr);
 BoxTypePtr GetDataBoundingBox (DataTypePtr);
diff --git a/src/move.c b/src/move.c
index cd23253..bf9670e 100644
--- a/src/move.c
+++ b/src/move.c
@@ -48,6 +48,7 @@
 #include "move.h"
 #include "mymem.h"
 #include "polygon.h"
+#include "pour.h"
 #include "rtree.h"
 #include "search.h"
 #include "select.h"
@@ -72,14 +73,14 @@ static void *MoveVia (PinTypePtr);
 static void *MoveLine (LayerTypePtr, LineTypePtr);
 static void *MoveArc (LayerTypePtr, ArcTypePtr);
 static void *MoveText (LayerTypePtr, TextTypePtr);
-static void *MovePolygon (LayerTypePtr, PolygonTypePtr);
+static void *MovePour (LayerTypePtr, PourTypePtr);
 static void *MoveLinePoint (LayerTypePtr, LineTypePtr, PointTypePtr);
-static void *MovePolygonPoint (LayerTypePtr, PolygonTypePtr, PointTypePtr);
+static void *MovePourPoint (LayerTypePtr, PourTypePtr, PointTypePtr);
 static void *MoveLineToLayer (LayerTypePtr, LineTypePtr);
 static void *MoveArcToLayer (LayerTypePtr, ArcTypePtr);
 static void *MoveRatToLayer (RatTypePtr);
 static void *MoveTextToLayer (LayerTypePtr, TextTypePtr);
-static void *MovePolygonToLayer (LayerTypePtr, PolygonTypePtr);
+static void *MovePourToLayer (LayerTypePtr, PourTypePtr);
 
 /* ---------------------------------------------------------------------------
  * some local identifiers
@@ -91,14 +92,15 @@ static bool MoreToCome;
 static ObjectFunctionType MoveFunctions = {
   MoveLine,
   MoveText,
-  MovePolygon,
+  NULL,
+  MovePour,
   MoveVia,
   MoveElement,
   MoveElementName,
   NULL,
   NULL,
   MoveLinePoint,
-  MovePolygonPoint,
+  MovePourPoint,
   MoveArc,
   NULL
 }, MoveToLayerFunctions =
@@ -106,8 +108,17 @@ static ObjectFunctionType MoveFunctions = {
 {
 MoveLineToLayer,
     MoveTextToLayer,
-    MovePolygonToLayer,
-    NULL, NULL, NULL, NULL, NULL, NULL, NULL, MoveArcToLayer, MoveRatToLayer};
+    NULL,
+    MovePourToLayer,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    MoveArcToLayer,
+    MoveRatToLayer};
 
 /* ---------------------------------------------------------------------------
  * moves a element by +-X and +-Y
@@ -128,13 +139,13 @@ MoveElementLowLevel (DataTypePtr Data, ElementTypePtr Element,
     if (Data)
       {
 	r_delete_entry (Data->pin_tree, (BoxType *) pin);
-	RestoreToPolygon (Data, PIN_TYPE, Element, pin);
+	RestoreToPours (Data, PIN_TYPE, Element, pin);
       }
     MOVE_PIN_LOWLEVEL (pin, DX, DY);
     if (Data)
       {
 	r_insert_entry (Data->pin_tree, (BoxType *) pin, 0);
-	ClearFromPolygon (Data, PIN_TYPE, Element, pin);
+	ClearFromPours (Data, PIN_TYPE, Element, pin);
       }
   }
   END_LOOP;
@@ -143,13 +154,13 @@ MoveElementLowLevel (DataTypePtr Data, ElementTypePtr Element,
     if (Data)
       {
 	r_delete_entry (Data->pad_tree, (BoxType *) pad);
-	RestoreToPolygon (Data, PAD_TYPE, Element, pad);
+	RestoreToPours (Data, PAD_TYPE, Element, pad);
       }
     MOVE_PAD_LOWLEVEL (pad, DX, DY);
     if (Data)
       {
 	r_insert_entry (Data->pad_tree, (BoxType *) pad, 0);
-	ClearFromPolygon (Data, PAD_TYPE, Element, pad);
+	ClearFromPours (Data, PAD_TYPE, Element, pad);
       }
   }
   END_LOOP;
@@ -249,12 +260,12 @@ static void *
 MoveVia (PinTypePtr Via)
 {
   r_delete_entry (PCB->Data->via_tree, (BoxTypePtr) Via);
-  RestoreToPolygon (PCB->Data, VIA_TYPE, Via, Via);
+  RestoreToPours (PCB->Data, VIA_TYPE, Via, Via);
   MOVE_VIA_LOWLEVEL (Via, DeltaX, DeltaY);
   if (PCB->ViaOn)
     EraseVia (Via);
   r_insert_entry (PCB->Data->via_tree, (BoxTypePtr) Via, 0);
-  ClearFromPolygon (PCB->Data, VIA_TYPE, Via, Via);
+  ClearFromPours (PCB->Data, VIA_TYPE, Via, Via);
   if (PCB->ViaOn)
     {
       DrawVia (Via, 0);
@@ -271,11 +282,11 @@ MoveLine (LayerTypePtr Layer, LineTypePtr Line)
 {
   if (Layer->On)
     EraseLine (Line);
-  RestoreToPolygon (PCB->Data, LINE_TYPE, Layer, Line);
+  RestoreToPours (PCB->Data, LINE_TYPE, Layer, Line);
   r_delete_entry (Layer->line_tree, (BoxTypePtr) Line);
   MOVE_LINE_LOWLEVEL (Line, DeltaX, DeltaY);
   r_insert_entry (Layer->line_tree, (BoxTypePtr) Line, 0);
-  ClearFromPolygon (PCB->Data, LINE_TYPE, Layer, Line);
+  ClearFromPours (PCB->Data, LINE_TYPE, Layer, Line);
   if (Layer->On)
     {
       DrawLine (Layer, Line, 0);
@@ -290,7 +301,7 @@ MoveLine (LayerTypePtr Layer, LineTypePtr Line)
 static void *
 MoveArc (LayerTypePtr Layer, ArcTypePtr Arc)
 {
-  RestoreToPolygon (PCB->Data, ARC_TYPE, Layer, Arc);
+  RestoreToPours (PCB->Data, ARC_TYPE, Layer, Arc);
   r_delete_entry (Layer->arc_tree, (BoxTypePtr) Arc);
   if (Layer->On)
     {
@@ -304,7 +315,7 @@ MoveArc (LayerTypePtr Layer, ArcTypePtr Arc)
       MOVE_ARC_LOWLEVEL (Arc, DeltaX, DeltaY);
     }
   r_insert_entry (Layer->arc_tree, (BoxTypePtr) Arc, 0);
-  ClearFromPolygon (PCB->Data, ARC_TYPE, Layer, Arc);
+  ClearFromPours (PCB->Data, ARC_TYPE, Layer, Arc);
   return (Arc);
 }
 
@@ -314,7 +325,7 @@ MoveArc (LayerTypePtr Layer, ArcTypePtr Arc)
 static void *
 MoveText (LayerTypePtr Layer, TextTypePtr Text)
 {
-  RestoreToPolygon (PCB->Data, TEXT_TYPE, Layer, Text);
+  RestoreToPours (PCB->Data, TEXT_TYPE, Layer, Text);
   r_delete_entry (Layer->text_tree, (BoxTypePtr) Text);
   if (Layer->On)
     {
@@ -326,45 +337,45 @@ MoveText (LayerTypePtr Layer, TextTypePtr Text)
   else
     MOVE_TEXT_LOWLEVEL (Text, DeltaX, DeltaY);
   r_insert_entry (Layer->text_tree, (BoxTypePtr) Text, 0);
-  ClearFromPolygon (PCB->Data, TEXT_TYPE, Layer, Text);
+  ClearFromPours (PCB->Data, TEXT_TYPE, Layer, Text);
   return (Text);
 }
 
 /* ---------------------------------------------------------------------------
- * low level routine to move a polygon
+ * low level routine to move a pour
  */
 void
-MovePolygonLowLevel (PolygonTypePtr Polygon, LocationType DeltaX,
+MovePourLowLevel (PourTypePtr Pour, LocationType DeltaX,
 		     LocationType DeltaY)
 {
-  POLYGONPOINT_LOOP (Polygon);
+  POURPOINT_LOOP (Pour);
   {
     MOVE (point->X, point->Y, DeltaX, DeltaY);
   }
   END_LOOP;
-  MOVE_BOX_LOWLEVEL (&Polygon->BoundingBox, DeltaX, DeltaY);
+  MOVE_BOX_LOWLEVEL (&Pour->BoundingBox, DeltaX, DeltaY);
 }
 
 /* ---------------------------------------------------------------------------
- * moves a polygon
+ * moves a pour
  */
 static void *
-MovePolygon (LayerTypePtr Layer, PolygonTypePtr Polygon)
+MovePour (LayerTypePtr Layer, PourTypePtr Pour)
 {
   if (Layer->On)
     {
-      ErasePolygon (Polygon);
+      ErasePour (Pour);
     }
-  r_delete_entry (Layer->polygon_tree, (BoxType *) Polygon);
-  MovePolygonLowLevel (Polygon, DeltaX, DeltaY);
-  r_insert_entry (Layer->polygon_tree, (BoxType *) Polygon, 0);
-  InitClip (PCB->Data, Layer, Polygon);
+  r_delete_entry (Layer->pour_tree, (BoxType *) Pour);
+  MovePourLowLevel (Pour, DeltaX, DeltaY);
+  r_insert_entry (Layer->pour_tree, (BoxType *) Pour, 0);
+  InitPourClip (PCB->Data, Layer, Pour);
   if (Layer->On)
     {
-      DrawPolygon (Layer, Polygon, 0);
+      DrawPour (Layer, Pour, 0);
       Draw ();
     }
-  return (Polygon);
+  return (Pour);
 }
 
 /* ---------------------------------------------------------------------------
@@ -377,12 +388,12 @@ MoveLinePoint (LayerTypePtr Layer, LineTypePtr Line, PointTypePtr Point)
     {
       if (Layer->On)
 	EraseLine (Line);
-      RestoreToPolygon (PCB->Data, LINE_TYPE, Layer, Line);
+      RestoreToPours (PCB->Data, LINE_TYPE, Layer, Line);
       r_delete_entry (Layer->line_tree, &Line->BoundingBox);
       MOVE (Point->X, Point->Y, DeltaX, DeltaY);
       SetLineBoundingBox (Line);
       r_insert_entry (Layer->line_tree, &Line->BoundingBox, 0);
-      ClearFromPolygon (PCB->Data, LINE_TYPE, Layer, Line);
+      ClearFromPours (PCB->Data, LINE_TYPE, Layer, Line);
       if (Layer->On)
 	{
 	  DrawLine (Layer, Line, 0);
@@ -408,25 +419,24 @@ MoveLinePoint (LayerTypePtr Layer, LineTypePtr Line, PointTypePtr Point)
 }
 
 /* ---------------------------------------------------------------------------
- * moves a polygon-point
+ * moves a pour-point
  */
 static void *
-MovePolygonPoint (LayerTypePtr Layer, PolygonTypePtr Polygon,
-		  PointTypePtr Point)
+MovePourPoint (LayerTypePtr Layer, PourTypePtr Pour, PointTypePtr Point)
 {
   if (Layer->On)
     {
-      ErasePolygon (Polygon);
+      ErasePour (Pour);
     }
-  r_delete_entry (Layer->polygon_tree, (BoxType *) Polygon);
+  r_delete_entry (Layer->pour_tree, (BoxType *) Pour);
   MOVE (Point->X, Point->Y, DeltaX, DeltaY);
-  SetPolygonBoundingBox (Polygon);
-  r_insert_entry (Layer->polygon_tree, (BoxType *) Polygon, 0);
-  RemoveExcessPolygonPoints (Layer, Polygon);
-  InitClip (PCB->Data, Layer, Polygon);
+  SetPourBoundingBox (Pour);
+  r_insert_entry (Layer->pour_tree, (BoxType *) Pour, 0);
+  RemoveExcessPourPoints (Layer, Pour);
+  InitPourClip (PCB->Data, Layer, Pour);
   if (Layer->On)
     {
-      DrawPolygon (Layer, Polygon, 0);
+      DrawPour (Layer, Pour, 0);
       Draw ();
     }
   return (Point);
@@ -498,11 +508,11 @@ MoveArcToLayer (LayerTypePtr Layer, ArcTypePtr Arc)
   if (((long int) Dest == -1) || Dest == Layer)
     return (Arc);
   AddObjectToMoveToLayerUndoList (ARC_TYPE, Layer, Arc, Arc);
-  RestoreToPolygon (PCB->Data, ARC_TYPE, Layer, Arc);
+  RestoreToPours (PCB->Data, ARC_TYPE, Layer, Arc);
   if (Layer->On)
     EraseArc (Arc);
   new = MoveArcToLayerLowLevel (Layer, Arc, Dest);
-  ClearFromPolygon (PCB->Data, ARC_TYPE, Dest, Arc);
+  ClearFromPours (PCB->Data, ARC_TYPE, Dest, Arc);
   if (Dest->On)
     DrawArc (Dest, new, 0);
   Draw ();
@@ -592,10 +602,10 @@ MoveLineToLayer (LayerTypePtr Layer, LineTypePtr Line)
   AddObjectToMoveToLayerUndoList (LINE_TYPE, Layer, Line, Line);
   if (Layer->On)
     EraseLine (Line);
-  RestoreToPolygon (PCB->Data, LINE_TYPE, Layer, Line);
+  RestoreToPours (PCB->Data, LINE_TYPE, Layer, Line);
   new = MoveLineToLayerLowLevel (Layer, Line, Dest);
   Line = NULL;
-  ClearFromPolygon (PCB->Data, LINE_TYPE, Dest, new);
+  ClearFromPours (PCB->Data, LINE_TYPE, Dest, new);
   if (Dest->On)
     DrawLine (Dest, new, 0);
   Draw ();
@@ -646,7 +656,7 @@ MoveTextToLayerLowLevel (LayerTypePtr Source, TextTypePtr Text,
 {
   TextTypePtr new = GetTextMemory (Destination);
 
-  RestoreToPolygon (PCB->Data, TEXT_TYPE, Source, Text);
+  RestoreToPours (PCB->Data, TEXT_TYPE, Source, Text);
   r_delete_entry (Source->text_tree, (BoxTypePtr) Text);
   /* copy the data and remove it from the former layer */
   *new = *Text;
@@ -664,7 +674,7 @@ MoveTextToLayerLowLevel (LayerTypePtr Source, TextTypePtr Text,
   if (!Destination->text_tree)
     Destination->text_tree = r_create_tree (NULL, 0, 0);
   r_insert_entry (Destination->text_tree, (BoxTypePtr) new, 0);
-  ClearFromPolygon (PCB->Data, TEXT_TYPE, Destination, new);
+  ClearFromPours (PCB->Data, TEXT_TYPE, Destination, new);
   return (new);
 }
 
@@ -697,25 +707,28 @@ MoveTextToLayer (LayerTypePtr Layer, TextTypePtr Text)
 }
 
 /* ---------------------------------------------------------------------------
- * moves a polygon between layers; lowlevel routines
+ * moves a pour between layers; lowlevel routines
  */
 void *
-MovePolygonToLayerLowLevel (LayerTypePtr Source, PolygonTypePtr Polygon,
+MovePourToLayerLowLevel (LayerTypePtr Source, PourTypePtr Pour,
 			    LayerTypePtr Destination)
 {
-  PolygonTypePtr new = GetPolygonMemory (Destination);
+  PourTypePtr new = GetPourMemory (Destination);
+  Cardinal i;
 
-  r_delete_entry (Source->polygon_tree, (BoxType *) Polygon);
+  r_delete_entry (Source->pour_tree, (BoxType *) Pour);
   /* copy the data and remove it from the former layer */
-  *new = *Polygon;
-  *Polygon = Source->Polygon[--Source->PolygonN];
-  r_substitute (Source->polygon_tree,
-		(BoxType *) & Source->Polygon[Source->PolygonN],
-		(BoxType *) Polygon);
-  memset (&Source->Polygon[Source->PolygonN], 0, sizeof (PolygonType));
-  if (!Destination->polygon_tree)
-    Destination->polygon_tree = r_create_tree (NULL, 0, 0);
-  r_insert_entry (Destination->polygon_tree, (BoxType *) new, 0);
+  *new = *Pour;
+  *Pour = Source->Pour[--Source->PourN];
+  r_substitute (Source->pour_tree,
+		(BoxType *) & Source->Pour[Source->PourN],
+		(BoxType *) Pour);
+  for (i = 0; i < Pour->PolygonN; i++)
+    Pour->Polygons[i].ParentPour = Pour;
+  memset (&Source->Pour[Source->PourN], 0, sizeof (PourType));
+  if (!Destination->pour_tree)
+    Destination->pour_tree = r_create_tree (NULL, 0, 0);
+  r_insert_entry (Destination->pour_tree, (BoxType *) new, 0);
   return (new);
 }
 
@@ -745,37 +758,40 @@ mptl_pin_callback (const BoxType *b, void *cl)
 }
 
 /* ---------------------------------------------------------------------------
- * moves a polygon between layers
+ * moves a pour between layers
  */
 static void *
-MovePolygonToLayer (LayerTypePtr Layer, PolygonTypePtr Polygon)
+MovePourToLayer (LayerTypePtr Layer, PourTypePtr Pour)
 {
-  PolygonTypePtr new;
-  struct mptlc d;
+  PourTypePtr new;
+//  struct mptlc d;
 
-  if (TEST_FLAG (LOCKFLAG, Polygon))
+  if (TEST_FLAG (LOCKFLAG, Pour))
     {
       Message (_("Sorry, the object is locked\n"));
       return NULL;
     }
   if (((long int) Dest == -1) || (Layer == Dest))
-    return (Polygon);
-  AddObjectToMoveToLayerUndoList (POLYGON_TYPE, Layer, Polygon, Polygon);
+    return (Pour);
+  AddObjectToMoveToLayerUndoList (POUR_TYPE, Layer, Pour, Pour);
   if (Layer->On)
-    ErasePolygon (Polygon);
-  /* Move all of the thermals with the polygon */
+    ErasePour (Pour);
+#define FIXME Later
+#if 0
+  /* Move all of the thermals with the pour */
   d.snum = GetLayerNumber (PCB->Data, Layer);
   d.dnum = GetLayerNumber (PCB->Data, Dest);
-  d.polygon = Polygon;
+  d.pour = Pour;
   d.type = PIN_TYPE;
-  r_search (PCB->Data->pin_tree, &Polygon->BoundingBox, NULL, mptl_pin_callback, &d);
+  r_search (PCB->Data->pin_tree, &Pour->BoundingBox, NULL, mptl_pin_callback, &d);
   d.type = VIA_TYPE;
-  r_search (PCB->Data->via_tree, &Polygon->BoundingBox, NULL, mptl_pin_callback, &d);
-  new = MovePolygonToLayerLowLevel (Layer, Polygon, Dest);
-  InitClip (PCB->Data, Dest, new);
+  r_search (PCB->Data->via_tree, &Pour->BoundingBox, NULL, mptl_pin_callback, &d);
+#endif
+  new = MovePourToLayerLowLevel (Layer, Pour, Dest);
+  InitPourClip (PCB->Data, Dest, new);
   if (Dest->On)
     {
-      DrawPolygon (Dest, new, 0);
+      DrawPour (Dest, new, 0);
       Draw ();
     }
   return (new);
diff --git a/src/move.h b/src/move.h
index c4a844b..9a65143 100644
--- a/src/move.h
+++ b/src/move.h
@@ -85,15 +85,15 @@
 
 #define	MOVE_TYPES	\
 	(VIA_TYPE | LINE_TYPE | TEXT_TYPE | ELEMENT_TYPE | ELEMENTNAME_TYPE |	\
-	POLYGON_TYPE | POLYGONPOINT_TYPE | LINEPOINT_TYPE | ARC_TYPE)
+	POUR_TYPE | POURPOINT_TYPE | LINEPOINT_TYPE | ARC_TYPE)
 #define	MOVETOLAYER_TYPES	\
-	(LINE_TYPE | TEXT_TYPE | POLYGON_TYPE | RATLINE_TYPE | ARC_TYPE)
+	(LINE_TYPE | TEXT_TYPE | POUR_TYPE | RATLINE_TYPE | ARC_TYPE)
 
 
 /* ---------------------------------------------------------------------------
  * prototypes
  */
-void MovePolygonLowLevel (PolygonTypePtr, LocationType, LocationType);
+void MovePourLowLevel (PourTypePtr, LocationType, LocationType);
 void MoveElementLowLevel (DataTypePtr, ElementTypePtr, LocationType,
 			  LocationType);
 void *MoveObject (int, void *, void *, void *, LocationType, LocationType);
@@ -102,7 +102,6 @@ void *MoveObjectAndRubberband (int, void *, void *, void *,
 			       LocationType, LocationType);
 void *MoveLineToLayerLowLevel (LayerTypePtr, LineTypePtr, LayerTypePtr);
 void *MoveTextToLayerLowLevel (LayerTypePtr, TextTypePtr, LayerTypePtr);
-void *MovePolygonToLayerLowLevel (LayerTypePtr, PolygonTypePtr, LayerTypePtr);
 bool MoveSelectedObjectsToLayer (LayerTypePtr);
 
 /* index is 0..MAX_LAYER-1.  If old_index is -1, a new layer is
diff --git a/src/mymem.c b/src/mymem.c
index bed0f9b..f3acc98 100644
--- a/src/mymem.c
+++ b/src/mymem.c
@@ -408,32 +408,61 @@ GetTextMemory (LayerTypePtr Layer)
 }
 
 /* ---------------------------------------------------------------------------
+ * get next slot for a pour polygon object, allocates memory if necessary
+ */
+PourTypePtr
+GetPourMemory (LayerTypePtr Layer)
+{
+  PourTypePtr pour = Layer->Pour;
+
+  /* realloc new memory if necessary and clear it */
+  if (Layer->PourN >= Layer->PourMax)
+    {
+      Layer->PourMax += STEP_POUR;
+      if (Layer->pour_tree)
+	r_destroy_tree (&Layer->pour_tree);
+      pour = MyRealloc (pour, Layer->PourMax * sizeof (PourType),
+			   "GetPourMemory()");
+      Layer->Pour = pour;
+      memset (pour + Layer->PourN, 0,
+	      STEP_POUR * sizeof (PourType));
+      Layer->pour_tree = r_create_tree (NULL, 0, 0);
+      POUR_LOOP (Layer);
+      {
+	r_insert_entry (Layer->pour_tree, (BoxType *) pour, 0);
+      }
+      END_LOOP;
+    }
+  return (pour + Layer->PourN++);
+}
+
+/* ---------------------------------------------------------------------------
  * get next slot for a polygon object, allocates memory if necessary
  */
 PolygonTypePtr
-GetPolygonMemory (LayerTypePtr Layer)
+GetPolygonMemoryInPour (PourTypePtr Pour)
 {
-  PolygonTypePtr polygon = Layer->Polygon;
+  PolygonTypePtr polygon = Pour->Polygons;
 
   /* realloc new memory if necessary and clear it */
-  if (Layer->PolygonN >= Layer->PolygonMax)
+  if (Pour->PolygonN >= Pour->PolygonMax)
     {
-      Layer->PolygonMax += STEP_POLYGON;
-      if (Layer->polygon_tree)
-	r_destroy_tree (&Layer->polygon_tree);
-      polygon = MyRealloc (polygon, Layer->PolygonMax * sizeof (PolygonType),
-			   "GetPolygonMemory()");
-      Layer->Polygon = polygon;
-      memset (polygon + Layer->PolygonN, 0,
-	      STEP_POLYGON * sizeof (PolygonType));
-      Layer->polygon_tree = r_create_tree (NULL, 0, 0);
-      POLYGON_LOOP (Layer);
+      Pour->PolygonMax += STEP_POLYGON;
+      if (Pour->polygon_tree)
+        r_destroy_tree (&Pour->polygon_tree);
+      polygon = MyRealloc (polygon, Pour->PolygonMax * sizeof (PolygonType),
+                           "GetPolygonMemoryInPour()");
+      Pour->Polygons = polygon;
+      memset (polygon + Pour->PolygonN, 0,
+              STEP_POLYGON * sizeof (PolygonType));
+      Pour->polygon_tree = r_create_tree (NULL, 0, 0);
+      POURPOLYGON_LOOP (Pour);
       {
-	r_insert_entry (Layer->polygon_tree, (BoxType *) polygon, 0);
+        r_insert_entry (Pour->polygon_tree, (BoxType *) polygon, 0);
       }
       END_LOOP;
     }
-  return (polygon + Layer->PolygonN++);
+  return (polygon + Pour->PolygonN++);
 }
 
 /* ---------------------------------------------------------------------------
@@ -443,6 +472,9 @@ GetPolygonMemory (LayerTypePtr Layer)
 PointTypePtr
 GetPointMemoryInPolygon (PolygonTypePtr Polygon)
 {
+  return NULL;
+#warning FIXME Later
+#if 0
   PointTypePtr points = Polygon->Points;
 
   /* realloc new memory if necessary and clear it */
@@ -456,6 +488,29 @@ GetPointMemoryInPolygon (PolygonTypePtr Polygon)
 	      STEP_POLYGONPOINT * sizeof (PointType));
     }
   return (points + Polygon->PointN++);
+#endif
+}
+
+/* ---------------------------------------------------------------------------
+ * gets the next slot for a point in a pour struct, allocates memory
+ * if necessary
+ */
+PointTypePtr
+GetPointMemoryInPour (PourTypePtr Pour)
+{
+  PointTypePtr points = Pour->Points;
+
+  /* realloc new memory if necessary and clear it */
+  if (Pour->PointN >= Pour->PointMax)
+    {
+      Pour->PointMax += STEP_POLYGONPOINT;
+      points = MyRealloc (points, Pour->PointMax * sizeof (PointType),
+			  "GetPointMemoryInPour()");
+      Pour->Points = points;
+      memset (points + Pour->PointN, 0,
+	      STEP_POLYGONPOINT * sizeof (PointType));
+    }
+  return (points + Pour->PointN++);
 }
 
 /* ---------------------------------------------------------------------------
@@ -463,21 +518,21 @@ GetPointMemoryInPolygon (PolygonTypePtr Polygon)
  * if necessary
  */
 Cardinal *
-GetHoleIndexMemoryInPolygon (PolygonTypePtr Polygon)
+GetHoleIndexMemoryInPour (PourTypePtr Pour)
 {
-  Cardinal *holeindex = Polygon->HoleIndex;
+  Cardinal *holeindex = Pour->HoleIndex;
 
   /* realloc new memory if necessary and clear it */
-  if (Polygon->HoleIndexN >= Polygon->HoleIndexMax)
+  if (Pour->HoleIndexN >= Pour->HoleIndexMax)
     {
-      Polygon->HoleIndexMax += STEP_POLYGONHOLEINDEX;
-      holeindex = MyRealloc (holeindex, Polygon->HoleIndexMax * sizeof (int),
-			     "GetHoleIndexMemoryInPolygon()");
-      Polygon->HoleIndex = holeindex;
-      memset (holeindex + Polygon->HoleIndexN, 0,
+      Pour->HoleIndexMax += STEP_POLYGONHOLEINDEX;
+      holeindex = MyRealloc (holeindex, Pour->HoleIndexMax * sizeof (int),
+			     "GetHoleIndexMemoryInPour()");
+      Pour->HoleIndex = holeindex;
+      memset (holeindex + Pour->HoleIndexN, 0,
 	      STEP_POLYGONHOLEINDEX * sizeof (int));
     }
-  return (holeindex + Polygon->HoleIndexN++);
+  return (holeindex + Pour->HoleIndexN++);
 }
 
 /* ---------------------------------------------------------------------------
@@ -755,8 +810,8 @@ FreePolygonMemory (PolygonTypePtr Polygon)
 {
   if (Polygon)
     {
-      MYFREE (Polygon->Points);
-      MYFREE (Polygon->HoleIndex);
+//      MYFREE (Polygon->Points);
+//      MYFREE (Polygon->HoleIndex);
       if (Polygon->Clipped)
 	poly_Free (&Polygon->Clipped);
       poly_FreeContours (&Polygon->NoHoles);
@@ -765,6 +820,27 @@ FreePolygonMemory (PolygonTypePtr Polygon)
 }
 
 /* ---------------------------------------------------------------------------
+ * frees memory used by a pour
+ */
+void
+FreePourMemory (PourTypePtr Pour)
+{
+  if (Pour)
+    {
+      MYFREE (Pour->Points);
+      MYFREE (Pour->HoleIndex);
+#define FIXME Later
+#if 0
+      if (Pour->Clipped)
+	poly_Free (&Pour->Clipped);
+      if (Pour->NoHoles)
+	poly_Free (&Pour->NoHoles);
+#endif
+      memset (Pour, 0, sizeof (PourType));
+    }
+}
+
+/* ---------------------------------------------------------------------------
  * frees memory used by a box list
  */
 void
@@ -948,20 +1024,31 @@ FreeDataMemory (DataTypePtr Data)
 	  MYFREE (layer->Line);
 	  MYFREE (layer->Arc);
 	  MYFREE (layer->Text);
+#warning FIXME Later
+#if 0
 	  POLYGON_LOOP (layer);
 	  {
 	    FreePolygonMemory (polygon);
 	  }
 	  END_LOOP;
-	  MYFREE (layer->Polygon);
+#endif
+//	  MYFREE (layer->Polygon);
+	  POUR_LOOP (layer);
+	  {
+	    FreePourMemory (pour);
+	  }
+	  END_LOOP;
+	  MYFREE (layer->Pour);
 	  if (layer->line_tree)
 	    r_destroy_tree (&layer->line_tree);
 	  if (layer->arc_tree)
 	    r_destroy_tree (&layer->arc_tree);
 	  if (layer->text_tree)
 	    r_destroy_tree (&layer->text_tree);
-	  if (layer->polygon_tree)
-	    r_destroy_tree (&layer->polygon_tree);
+//	  if (layer->polygon_tree)
+//	    r_destroy_tree (&layer->polygon_tree);
+	  if (layer->pour_tree)
+	    r_destroy_tree (&layer->pour_tree);
 	}
 
       if (Data->element_tree)
diff --git a/src/mymem.h b/src/mymem.h
index 81dff7a..bbd7897 100644
--- a/src/mymem.h
+++ b/src/mymem.h
@@ -56,7 +56,8 @@
 #define	STEP_SELECTORENTRY	128
 #define	STEP_REMOVELIST		500
 #define	STEP_UNDOLIST		500
-#define	STEP_POLYGON		10
+#define	STEP_POUR		10
+#define	STEP_POLYGON		100
 #define	STEP_POLYGONPOINT	10
 #define	STEP_POLYGONHOLEINDEX	10
 #define	STEP_LIBRARYMENU	10
@@ -81,9 +82,11 @@ LineTypePtr GetLineMemory (LayerTypePtr);
 ArcTypePtr GetArcMemory (LayerTypePtr);
 RatTypePtr GetRatMemory (DataTypePtr);
 TextTypePtr GetTextMemory (LayerTypePtr);
-PolygonTypePtr GetPolygonMemory (LayerTypePtr);
+PolygonTypePtr GetPolygonMemoryInPour (PourTypePtr);
+PourTypePtr GetPourMemory (LayerTypePtr);
 PointTypePtr GetPointMemoryInPolygon (PolygonTypePtr);
-Cardinal *GetHoleIndexMemoryInPolygon (PolygonTypePtr);
+PointTypePtr GetPointMemoryInPour (PourTypePtr);
+Cardinal *GetHoleIndexMemoryInPour (PourTypePtr);
 ElementTypePtr GetElementMemory (DataTypePtr);
 BoxTypePtr GetBoxMemory (BoxListTypePtr);
 ConnectionTypePtr GetConnectionMemory (NetTypePtr);
@@ -102,6 +105,7 @@ char *MyStrdup (char *s, const char *);
 /* void MyFree (void **); */
 #define MYFREE(x) do { SaveFree(x); (x)=NULL; } while (0)
 void FreePolygonMemory (PolygonTypePtr);
+void FreePourMemory (PourTypePtr);
 void FreeElementMemory (ElementTypePtr);
 void FreePCBMemory (PCBTypePtr);
 void FreeBoxListMemory (BoxListTypePtr);
diff --git a/src/parse_y.y b/src/parse_y.y
index a5b2d23..4d2b236 100644
--- a/src/parse_y.y
+++ b/src/parse_y.y
@@ -52,6 +52,7 @@
 #include "misc.h"
 #include "parse_l.h"
 #include "polygon.h"
+#include "pour.h"
 #include "remove.h"
 #include "rtree.h"
 #include "strflags.h"
@@ -64,7 +65,7 @@
 RCSID("$Id$");
 
 static	LayerTypePtr	Layer;
-static	PolygonTypePtr	Polygon;
+static	PourTypePtr	Pour;
 static	SymbolTypePtr	Symbol;
 static	int		pin_num;
 static	LibraryMenuTypePtr	Menu;
@@ -187,8 +188,8 @@ parsepcb
 			 */
 			PCB = yyPCB;
 			for (i = 0; i < yyData->LayerN+2; i++)
-			  for (j = 0; j < yyData->Layer[i].PolygonN; j++)
-			      InitClip (yyData, &yyData->Layer[i], &yyData->Layer[i].Polygon[j]);
+			  for (j = 0; j < yyData->Layer[i].PourN; j++)
+			      InitPourClip (yyData, &yyData->Layer[i], &yyData->Layer[i].Pour[j]);
 			PCB = pcb_save;
 			}
 			   
@@ -887,7 +888,7 @@ layerdefinition
 			/* x1, y1, x2, y2, flags */
 		| T_RECTANGLE '(' NUMBER NUMBER NUMBER NUMBER NUMBER ')'
 			{
-				CreateNewPolygonFromRectangle(Layer,
+				CreateNewPourFromRectangle(Layer,
 					$3*100, $4*100, ($3+$5)*100, ($4+$6)*100, OldFlags($7));
 			}
 		| text_hi_format
@@ -1122,7 +1123,7 @@ polygon_format
 		: /* flags are passed in */
 		T_POLYGON '(' flags ')' '('
 			{
-				Polygon = CreateNewPolygon(Layer, $3);
+				Pour = CreateNewPour(Layer, $3);
 			}
 		  polygonpoints
 		  polygonholes ')'
@@ -1130,13 +1131,13 @@ polygon_format
 				Cardinal contour, contour_start, contour_end;
 				bool bad_contour_found = false;
 				/* ignore junk */
-				for (contour = 0; contour <= Polygon->HoleIndexN; contour++)
+				for (contour = 0; contour <= Pour->HoleIndexN; contour++)
 				  {
 				    contour_start = (contour == 0) ?
-						      0 : Polygon->HoleIndex[contour - 1];
-				    contour_end = (contour == Polygon->HoleIndexN) ?
-						 Polygon->PointN :
-						 Polygon->HoleIndex[contour];
+						      0 : Pour->HoleIndex[contour - 1];
+				    contour_end = (contour == Pour->HoleIndexN) ?
+						 Pour->PointN :
+						 Pour->HoleIndex[contour];
 				    if (contour_end - contour_start < 3)
 				      bad_contour_found = true;
 				  }
@@ -1145,16 +1146,16 @@ polygon_format
 				  {
 				    Message("WARNING parsing file '%s'\n"
 					    "    line:        %i\n"
-					    "    description: 'ignored polygon (< 3 points in a contour)'\n",
+					    "    description: 'ignored pour (< 3 points in a contour)'\n",
 					    yyfilename, yylineno);
-				    DestroyObject(yyData, POLYGON_TYPE, Layer, Polygon, Polygon);
+				    DestroyObject(yyData, POLYGON_TYPE, Layer, Pour, Pour);
 				  }
 				else
 				  {
-				    SetPolygonBoundingBox (Polygon);
-				    if (!Layer->polygon_tree)
-				      Layer->polygon_tree = r_create_tree (NULL, 0, 0);
-				    r_insert_entry (Layer->polygon_tree, (BoxType *) Polygon, 0);
+				    SetPourBoundingBox (Pour);
+				    if (!Layer->pour_tree)
+				      Layer->pour_tree = r_create_tree (NULL, 0, 0);
+				    r_insert_entry (Layer->pour_tree, (BoxType *) Pour, 0);
 				  }
 			}
 		;
@@ -1168,7 +1169,7 @@ polygonholes
 polygonhole
 		: T_POLYGON_HOLE '('
 			{
-				CreateNewHoleInPolygon (Polygon);
+				CreateNewHoleInPour (Pour);
 			}
 		  polygonpoints ')'
 		;
@@ -1182,11 +1183,11 @@ polygonpoint
 			/* xcoord ycoord */
 		: '(' NUMBER NUMBER ')'
 			{
-				CreateNewPointInPolygon(Polygon, $2*100, $3*100);
+				CreateNewPointInPour(Pour, $2*100, $3*100);
 			}
 		| '[' NUMBER NUMBER ']'
 			{
-				CreateNewPointInPolygon(Polygon, $2, $3);
+				CreateNewPointInPour(Pour, $2, $3);
 			}
 		|
 		;
diff --git a/src/pcb-menu.res b/src/pcb-menu.res
index 1166439..dcf8a8a 100644
--- a/src/pcb-menu.res
+++ b/src/pcb-menu.res
@@ -173,8 +173,8 @@ MainMenu =
    {"Arc" checked=arcmode,1 Mode(Arc) a={"F3" "<Key>F3"}}
    {"Text" checked=textmode,1 Mode(Text) a={"F4" "<Key>F4"}}
    {"Rectangle" checked=rectanglemode,1 Mode(Rectangle) a={"F5" "<Key>F5"}}
-   {"Polygon" checked=polygonmode,1 Mode(Polygon) a={"F6" "<Key>F6"}}
-   {"Polygon Hole" checked=polygonholemode,1 Mode(PolygonHole)}
+   {"Polygon" checked=pourmode,1 Mode(Pour) a={"F6" "<Key>F6"}}
+   {"Polygon Hole" checked=pourholemode,1 Mode(PourHole)}
    {"Buffer" checked=pastebuffermode,1 Mode(PasteBuffer) a={"F7" "<Key>F7"}}
    {"Remove" checked=removemode,1 Mode(Remove) a={"F8" "<Key>F8"}}
    {"Rotate" checked=rotatemode,1 Mode(Rotate) a={"F9" "<Key>F9"}}
diff --git a/src/polygon.c b/src/polygon.c
index 15b3534..ca36271 100644
--- a/src/polygon.c
+++ b/src/polygon.c
@@ -32,6 +32,8 @@
 Here's a brief tour of the data and life of a polygon, courtesy of Ben
 Jackson:
 
+*** FIXME: SOME OF THIS WILL BE OUT DATED BY THE ADDITION OF POURS ****
+
 A PCB PolygonType contains an array of points outlining the polygon.
 This is what is manipulated by the UI and stored in the saved PCB.
 
@@ -109,10 +111,6 @@ RCSID ("$Id$");
 
 #define ROUND(x) ((long)(((x) >= 0 ? (x) + 0.5  : (x) - 0.5)))
 
-#define UNSUBTRACT_BLOAT 10
-#define SUBTRACT_PIN_VIA_BATCH_SIZE 100
-#define SUBTRACT_LINE_BATCH_SIZE 20
-
 /* ---------------------------------------------------------------------------
  * local prototypes
  */
@@ -123,73 +121,6 @@ static double circleVerticies[] = {
   0.98768834059513777, 0.15643446504023087,
 };
 
-Cardinal
-polygon_point_idx (PolygonTypePtr polygon, PointTypePtr point)
-{
-  assert (point >= polygon->Points);
-  assert (point <= polygon->Points + polygon->PointN);
-  return ((char *)point - (char *)polygon->Points) / sizeof (PointType);
-}
-
-/* Find contour number: 0 for outer, 1 for first hole etc.. */
-Cardinal
-polygon_point_contour (PolygonTypePtr polygon, Cardinal point)
-{
-  Cardinal i;
-  Cardinal contour = 0;
-
-  for (i = 0; i < polygon->HoleIndexN; i++)
-    if (point >= polygon->HoleIndex[i])
-      contour = i + 1;
-  return contour;
-}
-
-Cardinal
-next_contour_point (PolygonTypePtr polygon, Cardinal point)
-{
-  Cardinal contour;
-  Cardinal this_contour_start;
-  Cardinal next_contour_start;
-
-  contour = polygon_point_contour (polygon, point);
-
-  this_contour_start = (contour == 0) ? 0 :
-                                        polygon->HoleIndex[contour - 1];
-  next_contour_start =
-    (contour == polygon->HoleIndexN) ? polygon->PointN :
-                                       polygon->HoleIndex[contour];
-
-  /* Wrap back to the start of the contour we're in if we pass the end */
-  if (++point == next_contour_start)
-    point = this_contour_start;
-
-  return point;
-}
-
-Cardinal
-prev_contour_point (PolygonTypePtr polygon, Cardinal point)
-{
-  Cardinal contour;
-  Cardinal prev_contour_end;
-  Cardinal this_contour_end;
-
-  contour = polygon_point_contour (polygon, point);
-
-  prev_contour_end = (contour == 0) ? 0 :
-                                      polygon->HoleIndex[contour - 1];
-  this_contour_end =
-    (contour == polygon->HoleIndexN) ? polygon->PointN - 1:
-                                       polygon->HoleIndex[contour] - 1;
-
-  /* Wrap back to the start of the contour we're in if we pass the end */
-  if (point == prev_contour_end)
-    point = this_contour_end;
-  else
-    point--;
-
-  return point;
-}
-
 static void
 add_noholes_polyarea (PLINE *pline, void *user_data)
 {
@@ -211,6 +142,7 @@ ComputeNoHoles (PolygonType *poly)
   poly->NoHolesValid = 1;
 }
 
+#if 0
 static POLYAREA *
 biggest (POLYAREA * p)
 {
@@ -260,12 +192,14 @@ biggest (POLYAREA * p)
   assert (p->b);
   return p;
 }
+#endif
 
 POLYAREA *
 ContourToPoly (PLINE * contour)
 {
   POLYAREA *p;
   poly_PreContour (contour, TRUE);
+  poly_ChkContour (contour);
   assert (contour->Flags.orient == PLF_DIR);
   if (!(p = poly_Create ()))
     return NULL;
@@ -274,9 +208,12 @@ ContourToPoly (PLINE * contour)
   return p;
 }
 
+#warning FIXME Later
+#if 0
 static POLYAREA *
-original_poly (PolygonType * p)
+original_poly (PourType * p)
 {
+  return NULL;
   PLINE *contour = NULL;
   POLYAREA *np = NULL;
   Cardinal n;
@@ -286,7 +223,7 @@ original_poly (PolygonType * p)
   if ((np = poly_Create ()) == NULL)
     return NULL;
 
-  /* first make initial polygon contour */
+  /* first make initial pour contour */
   for (n = 0; n < p->PointN; n++)
     {
       /* No current contour? Make a new one starting at point */
@@ -334,12 +271,7 @@ original_poly (PolygonType * p)
   }
   return biggest (np);
 }
-
-POLYAREA *
-PolygonToPoly (PolygonType *p)
-{
-  return original_poly (p);
-}
+#endif
 
 POLYAREA *
 RectPoly (LocationType x1, LocationType x2, LocationType y1, LocationType y2)
@@ -713,6 +645,8 @@ SquarePadPoly (PadType * pad, BDimension clear)
   return np;
 }
 
+#warning FIXME Later
+#if 0
 /* clear np1 from the polygon */
 static int
 Subtract (POLYAREA * np1, PolygonType * p, bool fnp)
@@ -746,7 +680,9 @@ Subtract (POLYAREA * np1, PolygonType * p, bool fnp)
       p->NoHoles = NULL;
       return -1;
     }
-  p->Clipped = biggest (merged);
+#warning FIXME Later
+//  p->Clipped = biggest (merged);
+  p->Clipped = merged;
   assert (!p->Clipped || poly_Valid (p->Clipped));
   if (!p->Clipped)
     Message ("Polygon cleared out of existence near (%d, %d)\n",
@@ -754,6 +690,7 @@ Subtract (POLYAREA * np1, PolygonType * p, bool fnp)
              (p->BoundingBox.Y1 + p->BoundingBox.Y2) / 2);
   return 1;
 }
+#endif
 
 /* create a polygon of the pin clearance */
 POLYAREA *
@@ -785,435 +722,14 @@ BoxPolyBloated (BoxType *box, BDimension bloat)
                    box->Y1 - bloat, box->Y2 + bloat);
 }
 
-/* remove the pin clearance from the polygon */
-static int
-SubtractPin (DataType * d, PinType * pin, LayerType * l, PolygonType * p)
-{
-  POLYAREA *np;
-  Cardinal i;
-
-  if (pin->Clearance == 0)
-    return 0;
-  i = GetLayerNumber (d, l);
-  if (TEST_THERM (i, pin))
-    {
-      np = ThermPoly ((PCBTypePtr) (d->pcb), pin, i);
-      if (!np)
-        return 0;
-    }
-  else
-    {
-      np = PinPoly (pin, pin->Thickness, pin->Clearance);
-      if (!np)
-        return -1;
-    }
-  return Subtract (np, p, TRUE);
-}
-
-static int
-SubtractLine (LineType * line, PolygonType * p)
-{
-  POLYAREA *np;
-
-  if (!TEST_FLAG (CLEARLINEFLAG, line))
-    return 0;
-  if (!(np = LinePoly (line, line->Thickness + line->Clearance)))
-    return -1;
-  return Subtract (np, p, true);
-}
-
-static int
-SubtractArc (ArcType * arc, PolygonType * p)
-{
-  POLYAREA *np;
-
-  if (!TEST_FLAG (CLEARLINEFLAG, arc))
-    return 0;
-  if (!(np = ArcPoly (arc, arc->Thickness + arc->Clearance)))
-    return -1;
-  return Subtract (np, p, true);
-}
-
-static int
-SubtractText (TextType * text, PolygonType * p)
-{
-  POLYAREA *np;
-  const BoxType *b = &text->BoundingBox;
-
-  if (!TEST_FLAG (CLEARLINEFLAG, text))
-    return 0;
-  if (!(np = RoundRect (b->X1 + PCB->Bloat, b->X2 - PCB->Bloat,
-                        b->Y1 + PCB->Bloat, b->Y2 - PCB->Bloat, PCB->Bloat)))
-    return -1;
-  return Subtract (np, p, true);
-}
-
-static int
-SubtractPad (PadType * pad, PolygonType * p)
-{
-  POLYAREA *np = NULL;
-
-  if (pad->Clearance == 0)
-    return 0;
-  if (TEST_FLAG (SQUAREFLAG, pad))
-    {
-      if (!
-          (np = SquarePadPoly (pad, pad->Thickness + pad->Clearance)))
-        return -1;
-    }
-  else
-    {
-      if (!
-          (np = LinePoly ((LineType *) pad, pad->Thickness + pad->Clearance)))
-        return -1;
-    }
-  return Subtract (np, p, true);
-}
-
-struct cpInfo
-{
-  const BoxType *other;
-  DataType *data;
-  LayerType *layer;
-  PolygonType *polygon;
-  bool solder;
-  POLYAREA *accumulate;
-  int batch_size;
-  jmp_buf env;
-};
-
-static void
-subtract_accumulated (struct cpInfo *info, PolygonTypePtr polygon)
-{
-  if (info->accumulate == NULL)
-    return;
-  Subtract (info->accumulate, polygon, true);
-  info->accumulate = NULL;
-  info->batch_size = 0;
-}
-
-static int
-pin_sub_callback (const BoxType * b, void *cl)
-{
-  PinTypePtr pin = (PinTypePtr) b;
-  struct cpInfo *info = (struct cpInfo *) cl;
-  PolygonTypePtr polygon;
-  POLYAREA *np;
-  POLYAREA *merged;
-  Cardinal i;
-
-  /* don't subtract the object that was put back! */
-  if (b == info->other)
-    return 0;
-  polygon = info->polygon;
-
-  if (pin->Clearance == 0)
-    return 0;
-  i = GetLayerNumber (info->data, info->layer);
-  if (TEST_THERM (i, pin))
-    {
-      np = ThermPoly ((PCBTypePtr) (info->data->pcb), pin, i);
-      if (!np)
-        return 1;
-    }
-  else
-    {
-      np = PinPoly (pin, pin->Thickness, pin->Clearance);
-      if (!np)
-        longjmp (info->env, 1);
-    }
-
-  poly_Boolean_free (info->accumulate, np, &merged, PBO_UNITE);
-  info->accumulate = merged;
-
-  info->batch_size ++;
-
-  if (info->batch_size == SUBTRACT_PIN_VIA_BATCH_SIZE)
-    subtract_accumulated (info, polygon);
-
-  return 1;
-}
-
-static int
-arc_sub_callback (const BoxType * b, void *cl)
-{
-  ArcTypePtr arc = (ArcTypePtr) b;
-  struct cpInfo *info = (struct cpInfo *) cl;
-  PolygonTypePtr polygon;
-
-  /* don't subtract the object that was put back! */
-  if (b == info->other)
-    return 0;
-  if (!TEST_FLAG (CLEARLINEFLAG, arc))
-    return 0;
-  polygon = info->polygon;
-  if (SubtractArc (arc, polygon) < 0)
-    longjmp (info->env, 1);
-  return 1;
-}
-
-static int
-pad_sub_callback (const BoxType * b, void *cl)
-{
-  PadTypePtr pad = (PadTypePtr) b;
-  struct cpInfo *info = (struct cpInfo *) cl;
-  PolygonTypePtr polygon;
-
-  /* don't subtract the object that was put back! */
-  if (b == info->other)
-    return 0;
-  if (pad->Clearance == 0)
-    return 0;
-  polygon = info->polygon;
-  if (XOR (TEST_FLAG (ONSOLDERFLAG, pad), !info->solder))
-    {
-      if (SubtractPad (pad, polygon) < 0)
-        longjmp (info->env, 1);
-      return 1;
-    }
-  return 0;
-}
-
-static int
-line_sub_callback (const BoxType * b, void *cl)
-{
-  LineTypePtr line = (LineTypePtr) b;
-  struct cpInfo *info = (struct cpInfo *) cl;
-  PolygonTypePtr polygon;
-  POLYAREA *np;
-  POLYAREA *merged;
-
-  /* don't subtract the object that was put back! */
-  if (b == info->other)
-    return 0;
-  if (!TEST_FLAG (CLEARLINEFLAG, line))
-    return 0;
-  polygon = info->polygon;
-
-  if (!(np = LinePoly (line, line->Thickness + line->Clearance)))
-    longjmp (info->env, 1);
-
-  poly_Boolean_free (info->accumulate, np, &merged, PBO_UNITE);
-  info->accumulate = merged;
-  info->batch_size ++;
-
-  if (info->batch_size == SUBTRACT_LINE_BATCH_SIZE)
-    subtract_accumulated (info, polygon);
-
-  return 1;
-}
-
-static int
-text_sub_callback (const BoxType * b, void *cl)
-{
-  TextTypePtr text = (TextTypePtr) b;
-  struct cpInfo *info = (struct cpInfo *) cl;
-  PolygonTypePtr polygon;
-
-  /* don't subtract the object that was put back! */
-  if (b == info->other)
-    return 0;
-  if (!TEST_FLAG (CLEARLINEFLAG, text))
-    return 0;
-  polygon = info->polygon;
-  if (SubtractText (text, polygon) < 0)
-    longjmp (info->env, 1);
-  return 1;
-}
-
-static int
-Group (DataTypePtr Data, Cardinal layer)
-{
-  Cardinal i, j;
-  for (i = 0; i < max_layer; i++)
-    for (j = 0; j < ((PCBType *) (Data->pcb))->LayerGroups.Number[i]; j++)
-      if (layer == ((PCBType *) (Data->pcb))->LayerGroups.Entries[i][j])
-        return i;
-  return i;
-}
-
-static int
-clearPoly (DataTypePtr Data, LayerTypePtr Layer, PolygonType * polygon,
-           const BoxType * here, BDimension expand)
-{
-  int r = 0;
-  BoxType region;
-  struct cpInfo info;
-  Cardinal group;
-
-  if (!TEST_FLAG (CLEARPOLYFLAG, polygon)
-      || GetLayerNumber (Data, Layer) >= max_layer)
-    return 0;
-  group = Group (Data, GetLayerNumber (Data, Layer));
-  info.solder = (group == Group (Data, max_layer + SOLDER_LAYER));
-  info.data = Data;
-  info.other = here;
-  info.layer = Layer;
-  info.polygon = polygon;
-  if (here)
-    region = clip_box (here, &polygon->BoundingBox);
-  else
-    region = polygon->BoundingBox;
-  region = bloat_box (&region, expand);
-
-  if (setjmp (info.env) == 0)
-    {
-      r = 0;
-      info.accumulate = NULL;
-      info.batch_size = 0;
-      if (info.solder || group == Group (Data, max_layer + COMPONENT_LAYER))
-	r += r_search (Data->pad_tree, &region, NULL, pad_sub_callback, &info);
-      GROUP_LOOP (Data, group);
-      {
-        r +=
-          r_search (layer->line_tree, &region, NULL, line_sub_callback,
-                    &info);
-        subtract_accumulated (&info, polygon);
-        r +=
-          r_search (layer->arc_tree, &region, NULL, arc_sub_callback, &info);
-	r +=
-          r_search (layer->text_tree, &region, NULL, text_sub_callback, &info);
-      }
-      END_LOOP;
-      r += r_search (Data->via_tree, &region, NULL, pin_sub_callback, &info);
-      r += r_search (Data->pin_tree, &region, NULL, pin_sub_callback, &info);
-      subtract_accumulated (&info, polygon);
-    }
-  polygon->NoHolesValid = 0;
-  return r;
-}
-
-static int
-Unsubtract (POLYAREA * np1, PolygonType * p)
-{
-  POLYAREA *merged = NULL, *np = np1;
-  POLYAREA *orig_poly, *clipped_np;
-  int x;
-  assert (np);
-  assert (p && p->Clipped);
-
-  orig_poly = original_poly (p);
-
-  x = poly_Boolean_free (np, orig_poly, &clipped_np, PBO_ISECT);
-  if (x != err_ok)
-    {
-      fprintf (stderr, "Error while clipping PBO_ISECT: %d\n", x);
-      poly_Free (&clipped_np);
-      goto fail;
-    }
-
-  x = poly_Boolean_free (p->Clipped, clipped_np, &merged, PBO_UNITE);
-  if (x != err_ok)
-    {
-      fprintf (stderr, "Error while clipping PBO_UNITE: %d\n", x);
-      poly_Free (&merged);
-      goto fail;
-    }
-  p->Clipped = biggest (merged);
-  assert (!p->Clipped || poly_Valid (p->Clipped));
-  return 1;
-
-fail:
-  p->Clipped = NULL;
-  if (p->NoHoles) printf ("Just leaked in Unsubtract\n");
-  p->NoHoles = NULL;
-  return 0;
-}
-
-static int
-UnsubtractPin (PinType * pin, LayerType * l, PolygonType * p)
-{
-  POLYAREA *np;
-
-  /* overlap a bit to prevent gaps from rounding errors */
-  np = BoxPolyBloated (&pin->BoundingBox, UNSUBTRACT_BLOAT);
-
-  if (!np)
-    return 0;
-  if (!Unsubtract (np, p))
-    return 0;
-  clearPoly (PCB->Data, l, p, (const BoxType *) pin, 2 * UNSUBTRACT_BLOAT);
-  return 1;
-}
-
-static int
-UnsubtractArc (ArcType * arc, LayerType * l, PolygonType * p)
-{
-  POLYAREA *np;
-
-  if (!TEST_FLAG (CLEARLINEFLAG, arc))
-    return 0;
-
-  /* overlap a bit to prevent gaps from rounding errors */
-  np = BoxPolyBloated (&arc->BoundingBox, UNSUBTRACT_BLOAT);
-
-  if (!np)
-    return 0;
-  if (!Unsubtract (np, p))
-    return 0;
-  clearPoly (PCB->Data, l, p, (const BoxType *) arc, 2 * UNSUBTRACT_BLOAT);
-  return 1;
-}
-
-static int
-UnsubtractLine (LineType * line, LayerType * l, PolygonType * p)
-{
-  POLYAREA *np;
-
-  if (!TEST_FLAG (CLEARLINEFLAG, line))
-    return 0;
-
-  /* overlap a bit to prevent notches from rounding errors */
-  np = BoxPolyBloated (&line->BoundingBox, UNSUBTRACT_BLOAT);
-
-  if (!np)
-    return 0;
-  if (!Unsubtract (np, p))
-    return 0;
-  clearPoly (PCB->Data, l, p, (const BoxType *) line, 2 * UNSUBTRACT_BLOAT);
-  return 1;
-}
-
-static int
-UnsubtractText (TextType * text, LayerType * l, PolygonType * p)
-{
-  POLYAREA *np;
-
-  if (!TEST_FLAG (CLEARLINEFLAG, text))
-    return 0;
-
-  /* overlap a bit to prevent notches from rounding errors */
-  np = BoxPolyBloated (&text->BoundingBox, UNSUBTRACT_BLOAT);
-
-  if (!np)
-    return -1;
-  if (!Unsubtract (np, p))
-    return 0;
-  clearPoly (PCB->Data, l, p, (const BoxType *) text, 2 * UNSUBTRACT_BLOAT);
-  return 1;
-}
-
-static int
-UnsubtractPad (PadType * pad, LayerType * l, PolygonType * p)
-{
-  POLYAREA *np;
-
-  /* overlap a bit to prevent notches from rounding errors */
-  np = BoxPolyBloated (&pad->BoundingBox, UNSUBTRACT_BLOAT);
-
-  if (!np)
-    return 0;
-  if (!Unsubtract (np, p))
-    return 0;
-  clearPoly (PCB->Data, l, p, (const BoxType *) pad, 2 * UNSUBTRACT_BLOAT);
-  return 1;
-}
-
-static bool inhibit = false;
-
 int
 InitClip (DataTypePtr Data, LayerTypePtr layer, PolygonType * p)
 {
+  /* NOP */
+  printf ("Someone called InitClip, bad someone.\n");
+  return 0;
+#warning FIXME Later
+#if 0
   if (inhibit)
     return 0;
   if (p->Clipped)
@@ -1228,201 +744,7 @@ InitClip (DataTypePtr Data, LayerTypePtr layer, PolygonType * p)
   else
     p->NoHolesValid = 0;
   return 1;
-}
-
-/* --------------------------------------------------------------------------
- * remove redundant polygon points. Any point that lies on the straight
- * line between the points on either side of it is redundant.
- * returns true if any points are removed
- */
-bool
-RemoveExcessPolygonPoints (LayerTypePtr Layer, PolygonTypePtr Polygon)
-{
-  PointTypePtr p;
-  Cardinal n, prev, next;
-  LineType line;
-  bool changed = false;
-
-  if (Undoing ())
-    return (false);
-
-  for (n = 0; n < Polygon->PointN; n++)
-    {
-      prev = prev_contour_point (Polygon, n);
-      next = next_contour_point (Polygon, n);
-      p = &Polygon->Points[n];
-
-      line.Point1 = Polygon->Points[prev];
-      line.Point2 = Polygon->Points[next];
-      line.Thickness = 0;
-      if (IsPointOnLine ((float) p->X, (float) p->Y, 0.0, &line))
-        {
-          RemoveObject (POLYGONPOINT_TYPE, Layer, Polygon, p);
-          changed = true;
-        }
-    }
-  return (changed);
-}
-
-/* ---------------------------------------------------------------------------
- * returns the index of the polygon point which is the end
- * point of the segment with the lowest distance to the passed
- * coordinates
- */
-Cardinal
-GetLowestDistancePolygonPoint (PolygonTypePtr Polygon, LocationType X,
-                               LocationType Y)
-{
-  double mindistance = (double) MAX_COORD * MAX_COORD;
-  PointTypePtr ptr1, ptr2;
-  Cardinal n, result = 0;
-
-  /* we calculate the distance to each segment and choose the
-   * shortest distance. If the closest approach between the
-   * given point and the projected line (i.e. the segment extended)
-   * is not on the segment, then the distance is the distance
-   * to the segment end point.
-   */
-
-  for (n = 0; n < Polygon->PointN; n++)
-    {
-      register double u, dx, dy;
-      ptr1 = &Polygon->Points[prev_contour_point (Polygon, n)];
-      ptr2 = &Polygon->Points[n];
-
-      dx = ptr2->X - ptr1->X;
-      dy = ptr2->Y - ptr1->Y;
-      if (dx != 0.0 || dy != 0.0)
-        {
-          /* projected intersection is at P1 + u(P2 - P1) */
-          u = ((X - ptr1->X) * dx + (Y - ptr1->Y) * dy) / (dx * dx + dy * dy);
-
-          if (u < 0.0)
-            {                   /* ptr1 is closest point */
-              u = SQUARE (X - ptr1->X) + SQUARE (Y - ptr1->Y);
-            }
-          else if (u > 1.0)
-            {                   /* ptr2 is closest point */
-              u = SQUARE (X - ptr2->X) + SQUARE (Y - ptr2->Y);
-            }
-          else
-            {                   /* projected intersection is closest point */
-              u = SQUARE (X - ptr1->X * (1.0 - u) - u * ptr2->X) +
-                SQUARE (Y - ptr1->Y * (1.0 - u) - u * ptr2->Y);
-            }
-          if (u < mindistance)
-            {
-              mindistance = u;
-              result = n;
-            }
-        }
-    }
-  return (result);
-}
-
-/* ---------------------------------------------------------------------------
- * go back to the  previous point of the polygon
- */
-void
-GoToPreviousPoint (void)
-{
-  switch (Crosshair.AttachedPolygon.PointN)
-    {
-      /* do nothing if mode has just been entered */
-    case 0:
-      break;
-
-      /* reset number of points and 'LINE_MODE' state */
-    case 1:
-      Crosshair.AttachedPolygon.PointN = 0;
-      Crosshair.AttachedLine.State = STATE_FIRST;
-      addedLines = 0;
-      break;
-
-      /* back-up one point */
-    default:
-      {
-        PointTypePtr points = Crosshair.AttachedPolygon.Points;
-        Cardinal n = Crosshair.AttachedPolygon.PointN - 2;
-
-        Crosshair.AttachedPolygon.PointN--;
-        Crosshair.AttachedLine.Point1.X = points[n].X;
-        Crosshair.AttachedLine.Point1.Y = points[n].Y;
-        break;
-      }
-    }
-}
-
-/* ---------------------------------------------------------------------------
- * close polygon if possible
- */
-void
-ClosePolygon (void)
-{
-  Cardinal n = Crosshair.AttachedPolygon.PointN;
-
-  /* check number of points */
-  if (n >= 3)
-    {
-      /* if 45 degree lines are what we want do a quick check
-       * if closing the polygon makes sense
-       */
-      if (!TEST_FLAG (ALLDIRECTIONFLAG, PCB))
-        {
-          BDimension dx, dy;
-
-          dx = abs (Crosshair.AttachedPolygon.Points[n - 1].X -
-                    Crosshair.AttachedPolygon.Points[0].X);
-          dy = abs (Crosshair.AttachedPolygon.Points[n - 1].Y -
-                    Crosshair.AttachedPolygon.Points[0].Y);
-          if (!(dx == 0 || dy == 0 || dx == dy))
-            {
-              Message
-                (_
-                 ("Cannot close polygon because 45 degree lines are requested.\n"));
-              return;
-            }
-        }
-      CopyAttachedPolygonToLayer ();
-      Draw ();
-    }
-  else
-    Message (_("A polygon has to have at least 3 points\n"));
-}
-
-/* ---------------------------------------------------------------------------
- * moves the data of the attached (new) polygon to the current layer
- */
-void
-CopyAttachedPolygonToLayer (void)
-{
-  PolygonTypePtr polygon;
-  int saveID;
-
-  /* move data to layer and clear attached struct */
-  polygon = CreateNewPolygon (CURRENT, NoFlags ());
-  saveID = polygon->ID;
-  *polygon = Crosshair.AttachedPolygon;
-  polygon->ID = saveID;
-  SET_FLAG (CLEARPOLYFLAG, polygon);
-  if (TEST_FLAG (NEWFULLPOLYFLAG, PCB))
-    SET_FLAG (FULLPOLYFLAG, polygon);
-  memset (&Crosshair.AttachedPolygon, 0, sizeof (PolygonType));
-  SetPolygonBoundingBox (polygon);
-  if (!CURRENT->polygon_tree)
-    CURRENT->polygon_tree = r_create_tree (NULL, 0, 0);
-  r_insert_entry (CURRENT->polygon_tree, (BoxType *) polygon, 0);
-  InitClip (PCB->Data, CURRENT, polygon);
-  DrawPolygon (CURRENT, polygon, 0);
-  SetChangedFlag (true);
-
-  /* reset state of attached line */
-  Crosshair.AttachedLine.State = STATE_FIRST;
-  addedLines = 0;
-
-  /* add to undo list */
-  AddObjectToCreateUndoList (POLYGON_TYPE, CURRENT, polygon, polygon);
-  IncrementUndoSerialNumber ();
+#endif
 }
 
 /* find polygon holes in range, then call the callback function for
@@ -1466,61 +788,14 @@ struct plow_info
 };
 
 static int
-subtract_plow (DataTypePtr Data, LayerTypePtr Layer, PolygonTypePtr Polygon,
-               int type, void *ptr1, void *ptr2)
+plow_callback_2 (const BoxType * b, void *cl)
 {
-  if (!Polygon->Clipped)
-    return 0;
-  switch (type)
-    {
-    case PIN_TYPE:
-    case VIA_TYPE:
-      SubtractPin (Data, (PinTypePtr) ptr2, Layer, Polygon);
-      Polygon->NoHolesValid = 0;
-      return 1;
-    case LINE_TYPE:
-      SubtractLine ((LineTypePtr) ptr2, Polygon);
-      Polygon->NoHolesValid = 0;
-      return 1;
-    case ARC_TYPE:
-      SubtractArc ((ArcTypePtr) ptr2, Polygon);
-      Polygon->NoHolesValid = 0;
-      return 1;
-    case PAD_TYPE:
-      SubtractPad ((PadTypePtr) ptr2, Polygon);
-      Polygon->NoHolesValid = 0;
-      return 1;
-    case TEXT_TYPE:
-      SubtractText ((TextTypePtr) ptr2, Polygon);
-      Polygon->NoHolesValid = 0;
-      return 1;
-    }
-  return 0;
-}
+  struct plow_info *plow = (struct plow_info *) cl;
+  PolygonTypePtr polygon = (PolygonTypePtr) b;
 
-static int
-add_plow (DataTypePtr Data, LayerTypePtr Layer, PolygonTypePtr Polygon,
-          int type, void *ptr1, void *ptr2)
-{
-  switch (type)
-    {
-    case PIN_TYPE:
-    case VIA_TYPE:
-      UnsubtractPin ((PinTypePtr) ptr2, Layer, Polygon);
-      return 1;
-    case LINE_TYPE:
-      UnsubtractLine ((LineTypePtr) ptr2, Layer, Polygon);
-      return 1;
-    case ARC_TYPE:
-      UnsubtractArc ((ArcTypePtr) ptr2, Layer, Polygon);
-      return 1;
-    case PAD_TYPE:
-      UnsubtractPad ((PadTypePtr) ptr2, Layer, Polygon);
-      return 1;
-    case TEXT_TYPE:
-      UnsubtractText ((TextTypePtr) ptr2, Layer, Polygon);
-      return 1;
-    }
+  if (TEST_FLAG (CLEARPOLYFLAG, polygon))
+    return plow->callback (plow->data, plow->layer, polygon, plow->type,
+                           plow->ptr1, plow->ptr2);
   return 0;
 }
 
@@ -1528,12 +803,10 @@ static int
 plow_callback (const BoxType * b, void *cl)
 {
   struct plow_info *plow = (struct plow_info *) cl;
-  PolygonTypePtr polygon = (PolygonTypePtr) b;
+  PourTypePtr pour = (PourTypePtr) b;
+  BoxType *sb = &((PinTypePtr) plow->ptr2)->BoundingBox;
 
-  if (TEST_FLAG (CLEARPOLYFLAG, polygon))
-    return plow->callback (plow->data, plow->layer, polygon, plow->type,
-                           plow->ptr1, plow->ptr2);
-  return 0;
+  return r_search (pour->polygon_tree, sb, NULL, plow_callback_2, plow);
 }
 
 int
@@ -1560,8 +833,7 @@ PlowsPolygon (DataType * Data, int type, void *ptr1, void *ptr2,
           LAYER_LOOP (Data, max_layer);
           {
             info.layer = layer;
-            r +=
-              r_search (layer->polygon_tree, &sb, NULL, plow_callback, &info);
+            r += r_search (layer->pour_tree, &sb, NULL, plow_callback, &info);
           }
           END_LOOP;
         }
@@ -1571,8 +843,7 @@ PlowsPolygon (DataType * Data, int type, void *ptr1, void *ptr2,
                                                                          ((LayerTypePtr) ptr1))));
           {
             info.layer = layer;
-            r +=
-              r_search (layer->polygon_tree, &sb, NULL, plow_callback, &info);
+            r += r_search (layer->pour_tree, &sb, NULL, plow_callback, &info);
           }
           END_LOOP;
         }
@@ -1590,7 +861,7 @@ PlowsPolygon (DataType * Data, int type, void *ptr1, void *ptr2,
                                                                      ((LayerTypePtr) ptr1))));
       {
         info.layer = layer;
-        r += r_search (layer->polygon_tree, &sb, NULL, plow_callback, &info);
+        r += r_search (layer->pour_tree, &sb, NULL, plow_callback, &info);
       }
       END_LOOP;
       break;
@@ -1604,7 +875,7 @@ PlowsPolygon (DataType * Data, int type, void *ptr1, void *ptr2,
         {
           info.layer = layer;
           r +=
-            r_search (layer->polygon_tree, &sb, NULL, plow_callback, &info);
+            r_search (layer->pour_tree, &sb, NULL, plow_callback, &info);
         }
         END_LOOP;
       }
@@ -1628,23 +899,6 @@ PlowsPolygon (DataType * Data, int type, void *ptr1, void *ptr2,
   return r;
 }
 
-void
-RestoreToPolygon (DataType * Data, int type, void *ptr1, void *ptr2)
-{
-  if (type == POLYGON_TYPE)
-    InitClip (PCB->Data, (LayerTypePtr) ptr1, (PolygonTypePtr) ptr2);
-  else
-    PlowsPolygon (Data, type, ptr1, ptr2, add_plow);
-}
-
-void
-ClearFromPolygon (DataType * Data, int type, void *ptr1, void *ptr2)
-{
-  if (type == POLYGON_TYPE)
-    InitClip (PCB->Data, (LayerTypePtr) ptr1, (PolygonTypePtr) ptr2);
-  else
-    PlowsPolygon (Data, type, ptr1, ptr2, subtract_plow);
-}
 
 bool
 isects (POLYAREA * a, PolygonTypePtr p, bool fr)
@@ -1794,6 +1048,9 @@ NoHolesPolygonDicer (PolygonTypePtr p, const BoxType * clip,
 bool
 MorphPolygon (LayerTypePtr layer, PolygonTypePtr poly)
 {
+  return 0;
+#warning FIXME Later
+#if 0
   POLYAREA *p, *start;
   bool many = false;
   FlagType flags;
@@ -1857,6 +1114,7 @@ MorphPolygon (LayerTypePtr layer, PolygonTypePtr poly)
   inhibit = false;
   IncrementUndoSerialNumber ();
   return many;
+#endif
 }
 
 void debug_pline (PLINE *pl)
@@ -1887,19 +1145,19 @@ debug_polyarea (POLYAREA *p)
 void
 debug_polygon (PolygonType *p)
 {
-  Cardinal i;
+//  Cardinal i;
   POLYAREA *pa;
-  fprintf (stderr, "POLYGON %p  %d pts\n", p, p->PointN);
-  for (i=0; i<p->PointN; i++)
-    fprintf(stderr, "\t%d: %d, %d\n", i, p->Points[i].X, p->Points[i].Y);
-  if (p->HoleIndexN)
-    {
-      fprintf (stderr, "%d holes, starting at indices\n", p->HoleIndexN);
-      for (i=0; i<p->HoleIndexN; i++)
-        fprintf(stderr, "\t%d: %d\n", i, p->HoleIndex[i]);
-    }
-  else
-    fprintf (stderr, "it has no holes\n");
+//  fprintf (stderr, "POLYGON %p  %d pts\n", p, p->PointN);
+//  for (i=0; i<p->PointN; i++)
+//    fprintf(stderr, "\t%d: %d, %d\n", i, p->Points[i].X, p->Points[i].Y);
+//  if (p->HoleIndexN)
+//    {
+//      fprintf (stderr, "%d holes, starting at indices\n", p->HoleIndexN);
+//      for (i=0; i<p->HoleIndexN; i++)
+//        fprintf(stderr, "\t%d: %d\n", i, p->HoleIndex[i]);
+//    }
+//  else
+//    fprintf (stderr, "it has no holes\n");
   pa = p->Clipped;
   while (pa)
     {
@@ -1910,62 +1168,6 @@ debug_polygon (PolygonType *p)
     }
 }
 
-/* Convert a POLYAREA (and all linked POLYAREA) to
- * raw PCB polygons on the given layer.
- */
-void
-PolyToPolygonsOnLayer (DataType *Destination, LayerType *Layer,
-                       POLYAREA *Input, FlagType Flags)
-{
-  PolygonType *Polygon;
-  POLYAREA *pa;
-  PLINE *pline;
-  VNODE *node;
-  bool outer;
-
-  if (Input == NULL)
-    return;
-
-  pa = Input;
-  do
-    {
-      Polygon = CreateNewPolygon (Layer, Flags);
-
-      pline = pa->contours;
-      outer = true;
-
-      do
-        {
-          if (!outer)
-            CreateNewHoleInPolygon (Polygon);
-          outer = false;
-
-          node = &pline->head;
-          do
-            {
-              CreateNewPointInPolygon (Polygon, node->point[0],
-                                                node->point[1]);
-            }
-          while ((node = node->next) != &pline->head);
-
-        }
-      while ((pline = pline->next) != NULL);
-
-      InitClip (Destination, Layer, Polygon);
-      SetPolygonBoundingBox (Polygon);
-      if (!Layer->polygon_tree)
-        Layer->polygon_tree = r_create_tree (NULL, 0, 0);
-      r_insert_entry (Layer->polygon_tree, (BoxType *) Polygon, 0);
-
-      DrawPolygon (Layer, Polygon, 0);
-      /* add to undo list */
-      AddObjectToCreateUndoList (POLYGON_TYPE, Layer, Polygon, Polygon);
-    }
-  while ((pa = pa->f) != Input);
-
-  SetChangedFlag (true);
-}
-
 
 struct clip_outline_info {
   POLYAREA *poly;
diff --git a/src/polygon.h b/src/polygon.h
index 5b3baf6..b8a3202 100644
--- a/src/polygon.h
+++ b/src/polygon.h
@@ -33,32 +33,27 @@
 
 #include "global.h"
 
-Cardinal polygon_point_idx (PolygonTypePtr polygon, PointTypePtr point);
-Cardinal polygon_point_contour (PolygonTypePtr polygon, Cardinal point);
-Cardinal prev_contour_point (PolygonTypePtr polygon, Cardinal point);
-Cardinal next_contour_point (PolygonTypePtr polygon, Cardinal point);
-Cardinal GetLowestDistancePolygonPoint (PolygonTypePtr,
-					LocationType, LocationType);
-bool RemoveExcessPolygonPoints (LayerTypePtr, PolygonTypePtr);
-void GoToPreviousPoint (void);
-void ClosePolygon (void);
-void CopyAttachedPolygonToLayer (void);
 int PolygonHoles (PolygonType *ptr, const BoxType *range,
 		  int (*callback) (PLINE *, void *user_data),
                   void *user_data);
 int PlowsPolygon (DataType *, int, void *, void *,
 		  int (*callback) (DataTypePtr, LayerTypePtr, PolygonTypePtr, int, void *, void *));
 void ComputeNoHoles (PolygonType *poly);
+
 POLYAREA * ContourToPoly (PLINE *);
 POLYAREA * PolygonToPoly (PolygonType *);
 POLYAREA * RectPoly (LocationType x1, LocationType x2, LocationType y1, LocationType y2);
-POLYAREA * CirclePoly(LocationType x, LocationType y, BDimension radius);
 POLYAREA * OctagonPoly(LocationType x, LocationType y, BDimension radius);
-POLYAREA * LinePoly(LineType *l, BDimension thick);
+void frac_circle (PLINE *, LocationType, LocationType, Vector, int);
+POLYAREA * CirclePoly(LocationType x, LocationType y, BDimension radius);
+POLYAREA * RoundRect (LocationType x1, LocationType x2, LocationType y1, LocationType y2, BDimension t);
 POLYAREA * ArcPoly(ArcType *l, BDimension thick);
+POLYAREA * LinePoly(LineType *l, BDimension thick);
+POLYAREA * SquarePadPoly (PadType * pad, BDimension clear);
+
 POLYAREA * PinPoly(PinType *l, BDimension thick, BDimension clear);
 POLYAREA * BoxPolyBloated (BoxType *box, BDimension radius);
-void frac_circle (PLINE *, LocationType, LocationType, Vector, int);
+
 int InitClip(DataType *d, LayerType *l, PolygonType *p);
 void RestoreToPolygon(DataType *, int, void *, void *);
 void ClearFromPolygon(DataType *, int, void *, void *);
@@ -71,6 +66,5 @@ bool isects (POLYAREA *, PolygonTypePtr, bool);
 bool MorphPolygon (LayerTypePtr, PolygonTypePtr);
 void NoHolesPolygonDicer (PolygonType *p, const BoxType *clip,
                           void (*emit) (PLINE *, void *), void *user_data);
-void PolyToPolygonsOnLayer (DataType *, LayerType *, POLYAREA *, FlagType);
 POLYAREA *board_outline_poly ();
 #endif
diff --git a/src/polygon1.c b/src/polygon1.c
index 4a761d5..95c47bb 100644
--- a/src/polygon1.c
+++ b/src/polygon1.c
@@ -938,6 +938,45 @@ intersect (jmp_buf * jb, POLYAREA * b, POLYAREA * a, int add)
 }
 
 static void
+M_POLYAREA_intersect2 (jmp_buf * e, POLYAREA * afst, POLYAREA * bfst, int add)
+{
+  POLYAREA *a = afst, *b = bfst;
+  PLINE *curcA, *curcB;
+  CVCList *the_list = NULL;
+
+  if (a == NULL || b == NULL)
+    error (err_bad_parm);
+  do
+    {
+      do
+	{
+	  if (a->contours->xmax >= b->contours->xmin &&
+	      a->contours->ymax >= b->contours->ymin &&
+	      a->contours->xmin <= b->contours->xmax &&
+	      a->contours->ymin <= b->contours->ymax)
+	    {
+	      if (intersect (e, a, b, add))
+		error (err_no_memory);
+	    }
+	}
+      while ((a = a->f) != afst);
+      for (curcB = b->contours; curcB != NULL; curcB = curcB->next)
+	if (curcB->Flags.status == ISECTED)
+	  if (!(the_list = add_descriptors (curcB, 'B', the_list)))
+	    error (err_no_memory);
+    }
+  while ((b = b->f) != bfst);
+  do
+    {
+      for (curcA = a->contours; curcA != NULL; curcA = curcA->next)
+	if (curcA->Flags.status == ISECTED)
+	  if (!(the_list = add_descriptors (curcA, 'A', the_list)))
+	    error (err_no_memory);
+    }
+  while ((a = a->f) != afst);
+}				/* M_POLYAREA_intersect */
+
+static void
 M_POLYAREA_intersect (jmp_buf * e, POLYAREA * afst, POLYAREA * bfst, int add)
 {
   POLYAREA *a = afst, *b = bfst;
@@ -1188,7 +1227,7 @@ M_POLYAREA_label (POLYAREA * afst, POLYAREA * b, BOOLp touch)
 	      return TRUE;
 	  }
     }
-  while (!touch && (a = a->f) != afst);
+  while ((a = a->f) != afst);
   return FALSE;
 }
 
@@ -2300,7 +2339,8 @@ Touching (POLYAREA * a, POLYAREA * b)
       if (!poly_Valid (b))
 	return -1;
 #endif
-      M_POLYAREA_intersect (&e, a, b, false);
+//      M_POLYAREA_intersect (&e, a, b, false);
+      M_POLYAREA_intersect2 (&e, a, b, false);
 
       if (M_POLYAREA_label (a, b, TRUE))
 	return TRUE;
@@ -3196,15 +3236,19 @@ inside_sector (VNODE * pn, Vector p2)
 BOOLp
 poly_ChkContour (PLINE * a)
 {
-  VNODE *a1, *a2, *hit1, *hit2;
+  VNODE *a1, *a2, *a2_start, *hit1, *hit2;
   Vector i1, i2;
   int icnt;
+  double d1, d2;
+
+#warning FIXME Later: Deliberately disabled this test - seems something strange is going on
+  return FALSE;
 
   assert (a != NULL);
   a1 = &a->head;
   do
     {
-      a2 = a1;
+      a2_start = a2 = a1;
       do
 	{
 	  if (!node_neighbours (a1, a2) &&
@@ -3214,9 +3258,11 @@ poly_ChkContour (PLINE * a)
 	      if (icnt > 1)
 		return TRUE;
 
-	      if (vect_dist2 (i1, a1->point) < EPSILON)
+	      d1 = -1;
+	      d2 = -1;
+	      if ((d1 = vect_dist2 (i1, a1->point)) < EPSILON)
 		hit1 = a1;
-	      else if (vect_dist2 (i1, a1->next->point) < EPSILON)
+	      else if ((d2 = vect_dist2 (i1, a1->next->point)) < EPSILON)
 		hit1 = a1->next;
 	      else
 		hit1 = NULL;
@@ -3260,7 +3306,7 @@ poly_ChkContour (PLINE * a)
 		}
 	    }
 	}
-      while ((a2 = a2->next) != &a->head);
+      while ((a2 = a2->next) != a2_start);
     }
   while ((a1 = a1->next) != &a->head);
   return FALSE;
diff --git a/src/pour.c b/src/pour.c
new file mode 100644
index 0000000..a3efa93
--- /dev/null
+++ b/src/pour.c
@@ -0,0 +1,1438 @@
+/* $Id$ */
+
+/*
+ *                            COPYRIGHT
+ *
+ *  PCB, interactive printed circuit board design
+ *  Copyright (C) 1994,1995,1996 Thomas Nau
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *  Contact addresses for paper mail and Email:
+ *  Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
+ *  Thomas.Nau@xxxxxxxxxxxxx
+ *
+ */
+
+
+/* special pour editing routines
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <assert.h>
+#include <math.h>
+#include <memory.h>
+#include <setjmp.h>
+
+#include "global.h"
+#include "box.h"
+#include "create.h"
+#include "crosshair.h"
+#include "data.h"
+#include "draw.h"
+#include "error.h"
+#include "find.h"
+#include "misc.h"
+#include "move.h"
+#include "polygon.h"
+#include "pour.h"
+#include "remove.h"
+#include "rtree.h"
+#include "search.h"
+#include "set.h"
+#include "thermal.h"
+#include "undo.h"
+
+#ifdef HAVE_LIBDMALLOC
+#include <dmalloc.h>
+#endif
+
+RCSID ("$Id$");
+
+#define ROUND(x) ((long)(((x) >= 0 ? (x) + 0.5  : (x) - 0.5)))
+
+#define UNSUBTRACT_BLOAT 100
+
+/* ---------------------------------------------------------------------------
+ * local prototypes
+ */
+
+
+Cardinal
+pour_point_idx (PourTypePtr pour, PointTypePtr point)
+{
+  assert (point >= pour->Points);
+  assert (point <= pour->Points + pour->PointN);
+  return ((char *)point - (char *)pour->Points) / sizeof (PointType);
+}
+
+/* Find contour number: 0 for outer, 1 for first hole etc.. */
+Cardinal
+pour_point_contour (PourTypePtr pour, Cardinal point)
+{
+  Cardinal i;
+  Cardinal contour = 0;
+
+  for (i = 0; i < pour->HoleIndexN; i++)
+    if (point >= pour->HoleIndex[i])
+      contour = i + 1;
+  return contour;
+}
+
+Cardinal
+next_contour_point (PourTypePtr pour, Cardinal point)
+{
+  Cardinal contour;
+  Cardinal this_contour_start;
+  Cardinal next_contour_start;
+
+  contour = pour_point_contour (pour, point);
+
+  this_contour_start = (contour == 0) ? 0 :
+                                        pour->HoleIndex[contour - 1];
+  next_contour_start =
+    (contour == pour->HoleIndexN) ? pour->PointN :
+                                       pour->HoleIndex[contour];
+
+  /* Wrap back to the start of the contour we're in if we pass the end */
+  if (++point == next_contour_start)
+    point = this_contour_start;
+
+  return point;
+}
+
+Cardinal
+prev_contour_point (PourTypePtr pour, Cardinal point)
+{
+  Cardinal contour;
+  Cardinal prev_contour_end;
+  Cardinal this_contour_end;
+
+  contour = pour_point_contour (pour, point);
+
+  prev_contour_end = (contour == 0) ? 0 :
+                                      pour->HoleIndex[contour - 1];
+  this_contour_end =
+    (contour == pour->HoleIndexN) ? pour->PointN - 1:
+                                       pour->HoleIndex[contour] - 1;
+
+  /* Wrap back to the start of the contour we're in if we pass the end */
+  if (point == prev_contour_end)
+    point = this_contour_end;
+  else
+    point--;
+
+  return point;
+}
+
+
+/* --------------------------------------------------------------------------
+ * remove redundant polygon points. Any point that lies on the straight
+ * line between the points on either side of it is redundant.
+ * returns true if any points are removed
+ */
+bool
+RemoveExcessPourPoints (LayerTypePtr Layer, PourTypePtr Pour)
+{
+  PointTypePtr pt1, pt2, pt3;
+  Cardinal n;
+  LineType line;
+  bool changed = false;
+
+  if (Undoing ())
+    return (false);
+  /* there are always at least three points in a pour */
+  pt1 = &Pour->Points[Pour->PointN - 1];
+  pt2 = &Pour->Points[0];
+  pt3 = &Pour->Points[1];
+  for (n = 0; n < Pour->PointN; n++, pt1++, pt2++, pt3++)
+    {
+      /* wrap around pour */
+      if (n == 1)
+        pt1 = &Pour->Points[0];
+      if (n == Pour->PointN - 1)
+        pt3 = &Pour->Points[0];
+      line.Point1 = *pt1;
+      line.Point2 = *pt3;
+      line.Thickness = 0;
+      if (IsPointOnLine ((float) pt2->X, (float) pt2->Y, 0.0, &line))
+        {
+          RemoveObject (POURPOINT_TYPE, (void *) Layer, (void *) Pour,
+                        (void *) pt2);
+          changed = true;
+        }
+    }
+  return (changed);
+}
+
+/* ---------------------------------------------------------------------------
+ * returns the index of the polygon point which is the end
+ * point of the segment with the lowest distance to the passed
+ * coordinates
+ */
+Cardinal
+GetLowestDistancePourPoint (PourTypePtr Pour, LocationType X,
+                            LocationType Y)
+{
+  double mindistance = (double) MAX_COORD * MAX_COORD;
+  PointTypePtr ptr1 = &Pour->Points[Pour->PointN - 1],
+               ptr2 = &Pour->Points[0];
+  Cardinal n, result = 0;
+
+  /* we calculate the distance to each segment and choose the
+   * shortest distance. If the closest approach between the
+   * given point and the projected line (i.e. the segment extended)
+   * is not on the segment, then the distance is the distance
+   * to the segment end point.
+   */
+
+  for (n = 0; n < Pour->PointN; n++, ptr2++)
+    {
+      register double u, dx, dy;
+      dx = ptr2->X - ptr1->X;
+      dy = ptr2->Y - ptr1->Y;
+      if (dx != 0.0 || dy != 0.0)
+        {
+          /* projected intersection is at P1 + u(P2 - P1) */
+          u = ((X - ptr1->X) * dx + (Y - ptr1->Y) * dy) / (dx * dx + dy * dy);
+
+          if (u < 0.0)
+            {                   /* ptr1 is closest point */
+              u = SQUARE (X - ptr1->X) + SQUARE (Y - ptr1->Y);
+            }
+          else if (u > 1.0)
+            {                   /* ptr2 is closest point */
+              u = SQUARE (X - ptr2->X) + SQUARE (Y - ptr2->Y);
+            }
+          else
+            {                   /* projected intersection is closest point */
+              u = SQUARE (X - ptr1->X * (1.0 - u) - u * ptr2->X) +
+                SQUARE (Y - ptr1->Y * (1.0 - u) - u * ptr2->Y);
+            }
+          if (u < mindistance)
+            {
+              mindistance = u;
+              result = n;
+            }
+        }
+      ptr1 = ptr2;
+    }
+  return (result);
+}
+
+/* ---------------------------------------------------------------------------
+ * go back to the  previous point of the polygon
+ */
+void
+GoToPreviousPourPoint (void)
+{
+  switch (Crosshair.AttachedPour.PointN)
+    {
+      /* do nothing if mode has just been entered */
+    case 0:
+      break;
+
+      /* reset number of points and 'LINE_MODE' state */
+    case 1:
+      Crosshair.AttachedPour.PointN = 0;
+      Crosshair.AttachedLine.State = STATE_FIRST;
+      addedLines = 0;
+      break;
+
+      /* back-up one point */
+    default:
+      {
+        PointTypePtr points = Crosshair.AttachedPour.Points;
+        Cardinal n = Crosshair.AttachedPour.PointN - 2;
+
+        Crosshair.AttachedPour.PointN--;
+        Crosshair.AttachedLine.Point1.X = points[n].X;
+        Crosshair.AttachedLine.Point1.Y = points[n].Y;
+        break;
+      }
+    }
+}
+
+/* ---------------------------------------------------------------------------
+ * close pour if possible
+ */
+void
+ClosePour (void)
+{
+  Cardinal n = Crosshair.AttachedPour.PointN;
+
+  /* check number of points */
+  if (n >= 3)
+    {
+      /* if 45 degree lines are what we want do a quick check
+       * if closing the polygon makes sense
+       */
+      if (!TEST_FLAG (ALLDIRECTIONFLAG, PCB))
+        {
+          BDimension dx, dy;
+
+          dx = abs (Crosshair.AttachedPour.Points[n - 1].X -
+                    Crosshair.AttachedPour.Points[0].X);
+          dy = abs (Crosshair.AttachedPour.Points[n - 1].Y -
+                    Crosshair.AttachedPour.Points[0].Y);
+          if (!(dx == 0 || dy == 0 || dx == dy))
+            {
+              Message
+                (_
+                 ("Cannot close polygon because 45 degree lines are requested.\n"));
+              return;
+            }
+        }
+      CopyAttachedPourToLayer ();
+      Draw ();
+    }
+  else
+    Message (_("A polygon has to have at least 3 points\n"));
+}
+
+/* ---------------------------------------------------------------------------
+ * moves the data of the attached (new) polygon to the current layer
+ */
+void
+CopyAttachedPourToLayer (void)
+{
+  PourTypePtr pour;
+  int saveID;
+
+  /* move data to layer and clear attached struct */
+  pour = CreateNewPour (CURRENT, NoFlags ());
+  saveID = pour->ID;
+  *pour = Crosshair.AttachedPour;
+  pour->ID = saveID;
+  SET_FLAG (CLEARPOLYFLAG, pour);
+  if (TEST_FLAG (NEWFULLPOLYFLAG, PCB))
+    SET_FLAG (FULLPOLYFLAG, pour);
+  memset (&Crosshair.AttachedPour, 0, sizeof (PourType));
+  SetPourBoundingBox (pour);
+  if (!CURRENT->pour_tree)
+    CURRENT->pour_tree = r_create_tree (NULL, 0, 0);
+  r_insert_entry (CURRENT->pour_tree, (BoxType *) pour, 0);
+  InitPourClip (PCB->Data, CURRENT, pour);
+//  DrawPolygon (CURRENT, polygon, 0);
+  DrawPour (CURRENT, pour, 0);
+  SetChangedFlag (true);
+
+  /* reset state of attached line */
+  Crosshair.AttachedLine.State = STATE_FIRST;
+  addedLines = 0;
+
+  /* add to undo list */
+  AddObjectToCreateUndoList (POUR_TYPE, CURRENT, pour, pour);
+  IncrementUndoSerialNumber ();
+}
+
+/*---------------------------------------- END OF NICE GENTLE UI DRIVEN PIECES OF THE POUR CODE --------------*/
+
+/*---------------------------------------- THIS CODE BELOW WILL MURDER SMALL ANIMALS THEN LAUGH --------------*/
+
+/* ---------------------------------------------------------------------------
+ * destroys a polygon from a pour
+ */
+static void *
+DestroyPolygonInPour (PourTypePtr pour, PolygonTypePtr polygon)
+{
+  r_delete_entry (pour->polygon_tree, (BoxTypePtr) polygon);
+
+  FreePolygonMemory (polygon);
+  *polygon = pour->Polygons[ --pour->PolygonN ];
+  r_substitute (pour->polygon_tree,
+                (BoxType *) & pour->Polygons[ pour->PolygonN ],
+                (BoxType *) polygon);
+  memset (&pour->Polygons[ pour->PolygonN ], 0, sizeof (PolygonType));
+  return (NULL);
+}
+
+static int
+subtract_poly (POLYAREA * np1, POLYAREA **pg)
+{
+  POLYAREA *merged = NULL, *np = np1;
+  int x;
+
+  assert (np);
+  assert (pg);
+  assert (*pg);
+
+  if (pg == NULL)
+    {
+      printf ("Hmm, got pg == NULL in subtract_poly\n");
+      poly_Free (&np);
+      return -1;
+    }
+
+  assert (poly_Valid (*pg));
+  assert (poly_Valid (np));
+  x = poly_Boolean_free (*pg, np, &merged, PBO_SUB);
+  if (x != err_ok)
+    {
+      fprintf (stderr, "Error while clipping PBO_SUB: %d\n", x);
+      poly_Free (&merged);
+      *pg = NULL;
+      return -1;
+    }
+
+  assert (!merged || poly_Valid (merged));
+
+  *pg = merged;
+  return 1;
+}
+
+  static int
+unite_poly (POLYAREA * np, POLYAREA ** pg)
+{
+  POLYAREA *merged = NULL;
+  int x;
+  assert (np);
+  assert (pg);
+//  assert (*pg);
+  x = poly_Boolean_free (*pg, np, &merged, PBO_UNITE);
+  if (x != err_ok)
+    {
+      fprintf (stderr, "Error while clipping PBO_UNITE: %d\n", x);
+      poly_Free (&merged);
+      *pg = NULL;
+      return 0;
+    }
+  assert (!merged || poly_Valid (merged));
+  *pg = merged;
+  return 1;
+}
+
+static int
+intersect_poly (POLYAREA * np, POLYAREA ** pg)
+{
+  POLYAREA *merged;
+  int x;
+  assert (np);
+  assert (pg);
+  assert (*pg);
+  x = poly_Boolean_free (*pg, np, &merged, PBO_ISECT);
+  if (x != err_ok)
+    {
+      fprintf (stderr, "Error while clipping PBO_ISECT: %d\n", x);
+      poly_Free (&merged);
+      *pg = NULL;
+      return 0;
+    }
+  assert (!merged || poly_Valid (merged));
+  *pg = merged;
+  return 1;
+}
+
+
+static POLYAREA *
+get_subtract_pin_poly (DataType * d, PinType * pin, LayerType * l, PourType *pour)
+{
+  POLYAREA *np;
+  Cardinal i;
+
+  if (pin->Clearance == 0)
+    return NULL;
+
+  i = GetLayerNumber (d, l);
+  if (TEST_THERM (i, pin))
+    np = ThermPoly ((PCBTypePtr) (d->pcb), pin, i);
+  else
+    np = PinPoly (pin, pin->Thickness, pin->Clearance);
+
+  return np;
+}
+
+static POLYAREA *
+get_subtract_line_poly (LineType *line, PourType *pour)
+{
+  if (!TEST_FLAG (CLEARLINEFLAG, line))
+    return NULL;
+
+  return LinePoly (line, line->Thickness + line->Clearance);
+}
+
+static POLYAREA *
+get_subtract_arc_poly (ArcType * arc, PourType * pour)
+{
+  if (!TEST_FLAG (CLEARLINEFLAG, arc))
+    return NULL;
+
+  return ArcPoly (arc, arc->Thickness + arc->Clearance);
+}
+
+static POLYAREA *
+get_subtract_text_poly (TextType * text, PourType * pour)
+{
+  const BoxType *b = &text->BoundingBox;
+
+  if (!TEST_FLAG (CLEARLINEFLAG, text))
+    return NULL;
+
+  return RoundRect (b->X1 + PCB->Bloat, b->X2 - PCB->Bloat,
+                    b->Y1 + PCB->Bloat, b->Y2 - PCB->Bloat, PCB->Bloat);
+}
+
+static POLYAREA *
+get_subtract_pad_poly (PadType * pad, PourType * pour)
+{
+  POLYAREA *np;
+
+  if (pad->Clearance == 0)
+    return NULL;
+
+  if (TEST_FLAG (SQUAREFLAG, pad))
+    np = SquarePadPoly (pad, pad->Thickness + pad->Clearance);
+  else
+    np = LinePoly ((LineType *) pad, pad->Thickness + pad->Clearance);
+
+  return np;
+}
+
+static POLYAREA *
+get_subtract_polygon_poly (PolygonType * polygon, PourType * pour)
+{
+  POLYAREA *np;
+
+  /* Don't subtract from ourselves! */
+  if (polygon->ParentPour == pour || !TEST_FLAG (CLEARLINEFLAG, polygon))
+    return NULL;
+
+  poly_Copy0 (&np, polygon->Clipped);
+
+  return np;
+}
+
+struct cpInfo
+{
+  const BoxType *other;
+  DataType *data;
+  LayerType *layer;
+  PourType *pour;
+  bool solder;
+  POLYAREA *pg;
+  BoxType *region;
+  jmp_buf env;
+};
+
+static int
+pin_sub_callback (const BoxType * b, void *cl)
+{
+  PinTypePtr pin = (PinTypePtr) b;
+  struct cpInfo *info = (struct cpInfo *) cl;
+  POLYAREA *np;
+
+  /* don't subtract the object that was put back! */
+  if (b == info->other)
+    return 0;
+
+  np = get_subtract_pin_poly (info->data, pin, info->layer, info->pour);
+  if (np == NULL)
+    return 0;
+
+  if (subtract_poly (np, &info->pg) < 0)
+    longjmp (info->env, 1);
+  return 1;
+}
+
+static int
+arc_sub_callback (const BoxType * b, void *cl)
+{
+  ArcTypePtr arc = (ArcTypePtr) b;
+  struct cpInfo *info = (struct cpInfo *) cl;
+  POLYAREA *np;
+
+  /* don't subtract the object that was put back! */
+  if (b == info->other)
+    return 0;
+  if (!TEST_FLAG (CLEARLINEFLAG, arc))
+    return 0;
+
+  np = get_subtract_arc_poly (arc, info->pour);
+  if (np == NULL)
+    return 0;
+
+  if (subtract_poly (np, &info->pg) < 0)
+    longjmp (info->env, 1);
+  return 1;
+}
+
+static int
+pad_sub_callback (const BoxType * b, void *cl)
+{
+  PadTypePtr pad = (PadTypePtr) b;
+  struct cpInfo *info = (struct cpInfo *) cl;
+  POLYAREA *np;
+
+  /* don't subtract the object that was put back! */
+  if (b == info->other)
+    return 0;
+  if (XOR (TEST_FLAG (ONSOLDERFLAG, pad), info->solder))
+    return 0;
+
+  np = get_subtract_pad_poly (pad, info->pour);
+  if (np == NULL)
+    return 0;
+
+  if (subtract_poly (np, &info->pg) < 0)
+    longjmp (info->env, 1);
+  return 1;
+}
+
+static int
+line_sub_callback (const BoxType * b, void *cl)
+{
+  LineTypePtr line = (LineTypePtr) b;
+  struct cpInfo *info = (struct cpInfo *) cl;
+  POLYAREA *np;
+
+  /* don't subtract the object that was put back! */
+  if (b == info->other)
+    return 0;
+  if (!TEST_FLAG (CLEARLINEFLAG, line))
+    return 0;
+
+  np = get_subtract_line_poly (line, info->pour);
+  if (np == NULL)
+    return 0;
+
+  if (subtract_poly (np, &info->pg) < 0)
+    longjmp (info->env, 1);
+  return 1;
+}
+
+
+static int
+text_sub_callback (const BoxType * b, void *cl)
+{
+  TextTypePtr text = (TextTypePtr) b;
+  struct cpInfo *info = (struct cpInfo *) cl;
+  POLYAREA *np;
+
+  /* don't subtract the object that was put back! */
+  if (b == info->other)
+    return 0;
+  if (!TEST_FLAG (CLEARLINEFLAG, text))
+    return 0;
+
+  np = get_subtract_text_poly (text, info->pour);
+  if (np == NULL)
+    return 0;
+
+  if (subtract_poly (np, &info->pg) < 0)
+    longjmp (info->env, 1);
+  return 1;
+}
+
+static int
+poly_sub_callback (const BoxType * b, void *cl)
+{
+  PolygonTypePtr poly = (PolygonTypePtr) b;
+  struct cpInfo *info = (struct cpInfo *) cl;
+  POLYAREA *np;
+
+  /* don't subtract the object that was put back! */
+  if (b == info->other)
+    return 0;
+  if (!TEST_FLAG (CLEARLINEFLAG, poly))
+    return 0;
+
+  np = get_subtract_polygon_poly (poly, info->pour);
+  if (np == NULL)
+    return 0;
+
+  if (subtract_poly (np, &info->pg) < 0)
+    longjmp (info->env, 1);
+  return 1;
+}
+
+static int
+pour_sub_callback (const BoxType * b, void *cl)
+{
+  PourTypePtr pour = (PourTypePtr) b;
+  struct cpInfo *info = (struct cpInfo *) cl;
+  BoxType *region = info->region;
+
+  return r_search (pour->polygon_tree, region, NULL, poly_sub_callback, info);
+
+}
+
+static int
+Group (DataTypePtr Data, Cardinal layer)
+{
+  Cardinal i, j;
+  for (i = 0; i < max_layer; i++)
+    for (j = 0; j < ((PCBType *) (Data->pcb))->LayerGroups.Number[i]; j++)
+      if (layer == ((PCBType *) (Data->pcb))->LayerGroups.Entries[i][j])
+        return i;
+  return i;
+}
+
+/* NB: For convenience, we're passing the defined POLYAREA in here */
+static int
+ClearPour (DataTypePtr Data, LayerTypePtr Layer, PourType * pour,
+           POLYAREA **pg, const BoxType * here, BDimension expand)
+{
+  int r = 0;
+  BoxType region;
+  struct cpInfo info;
+  Cardinal group;
+
+  if (!TEST_FLAG (CLEARPOLYFLAG, pour)
+      || GetLayerNumber (Data, Layer) >= max_layer)
+    return 0;
+  group = Group (Data, GetLayerNumber (Data, Layer));
+  info.solder = (group == Group (Data, max_layer + SOLDER_LAYER));
+  info.data = Data;
+  info.other = here;
+  info.layer = Layer;
+  info.pour = pour;
+  info.pg = *pg;
+  if (here)
+    region = clip_box (here, &pour->BoundingBox);
+  else
+    region = pour->BoundingBox;
+  region = bloat_box (&region, expand);
+  info.region = &region;
+
+  if (setjmp (info.env) == 0)
+    {
+      r  = r_search (Data->via_tree, &region, NULL, pin_sub_callback, &info);
+      r += r_search (Data->pin_tree, &region, NULL, pin_sub_callback, &info);
+      GROUP_LOOP (Data, group);
+      {
+        r += r_search (layer->line_tree, &region, NULL, line_sub_callback, &info);
+        r += r_search (layer->arc_tree,  &region, NULL, arc_sub_callback,  &info);
+        r += r_search (layer->text_tree, &region, NULL, text_sub_callback, &info);
+        r += r_search (layer->pour_tree, &region, NULL, pour_sub_callback, &info);
+      }
+      END_LOOP;
+      if (info.solder || group == Group (Data, max_layer + COMPONENT_LAYER))
+        r += r_search (Data->pad_tree, &region, NULL, pad_sub_callback, &info);
+    }
+
+  *pg = info.pg;
+
+  return r;
+}
+
+static int
+subtract_plow (DataTypePtr Data, LayerTypePtr Layer, PourTypePtr pour,
+              int type, void *ptr1, void *ptr2)
+{
+  POLYAREA *np = NULL, *pg = NULL, *start_pg, *tmp;
+  int count, count_all, count_added;
+
+  switch (type)
+    {
+    case PIN_TYPE:
+    case VIA_TYPE:
+      np = get_subtract_pin_poly (Data, (PinTypePtr) ptr2, Layer, pour);
+      break;
+    case LINE_TYPE:
+      np = get_subtract_line_poly ((LineTypePtr) ptr2, pour);
+      break;
+    case ARC_TYPE:
+      np = get_subtract_arc_poly ((ArcTypePtr) ptr2, pour);
+      break;
+    case PAD_TYPE:
+      np = get_subtract_pad_poly ((PadTypePtr) ptr2, pour);
+      break;
+    case POLYGON_TYPE:
+      np = get_subtract_polygon_poly ((PolygonTypePtr) ptr2, pour);
+      break;
+    case TEXT_TYPE:
+      np = get_subtract_text_poly ((TextTypePtr) ptr2, pour);
+      break;
+    }
+
+  if (np == NULL)
+    {
+      printf ("Didn't get a POLYAREA to subtract, so bailing\n");
+      return 0;
+    }
+
+  assert (poly_Valid (np));
+
+  /* Make pg contain the polygons we're going to fiddle with */
+
+  count = 0;
+  POURPOLYGON_LOOP (pour);
+  {
+    /* Gather up children which are touched by np */
+    if (isects (np, polygon, false))
+      {
+        count++;
+        /* Steal their clipped contours, then delete them */
+        /* Add contour to local list to fiddle about with */
+
+        assert (poly_Valid (polygon->Clipped));
+        if (polygon->Clipped == NULL)
+          {
+            printf ("Got polygon->clipped == NULL!\n");
+            continue;
+          }
+        if (pg == NULL)
+          {
+            pg = polygon->Clipped;
+            polygon->Clipped = NULL;
+          }
+        else
+          {
+            /* Link the _single_ polygon->Clipped into our circular pg list. */
+            polygon->Clipped->f = pg;
+            polygon->Clipped->b = pg->b;
+            pg->b->f = polygon->Clipped;
+            pg->b = polygon->Clipped;
+            polygon->Clipped = NULL;
+          }
+        /* POURPOLYGON_LOOP iterates backwards, so it's OK
+         * to delete the current element we're sitting on */
+        DestroyPolygonInPour (pour, polygon);
+      }
+  }
+  END_LOOP;
+//  printf ("Subtract counted %i touching children, now removed\n", count);
+
+  if (pg == NULL)
+    {
+      printf ("Hmm, got pg == NULL in subtract_plow\n");
+      poly_Free (&np);
+      return -1;
+    }
+
+  assert (poly_Valid (pg));
+
+  /* Perform the subtract operation */
+
+  /* NB: Old *pg is freed inside subtract_poly */
+  subtract_poly (np, &pg);
+
+  if (pg == NULL)
+    {
+      printf ("Poly killed to death by subtracting\n");
+      return -1;
+    }
+
+#if 0
+  count = 0;
+  { POLYAREA *pg_start;
+  pg_start = pg;
+  do {
+    count++;
+  } while ((pg = pg->f) != pg_start);
+  }
+  printf ("After subtract, counted %i polygon pieces\n", count);
+#endif
+
+  count_all = count_added = 0;
+  /* For each piece of the clipped up polygon, create a new child */
+  start_pg = pg;
+  do
+    {
+      PolygonType *poly;
+
+      tmp = pg->f;
+      pg->f = pg;
+      pg->b = pg;
+
+      count_all++;
+//      if (pg->contours->area > PCB->IsleArea)
+      if (1) // Breaks incremental updates otherwise
+        {
+          count_added++;
+          poly = CreateNewPolygonInPour (pour, pour->Flags);
+          poly->Clipped = pg;
+          CLEAR_FLAG (SELECTEDFLAG, poly);
+
+          SetPolygonBoundingBox (poly);
+
+          if (pour->polygon_tree == NULL)
+            pour->polygon_tree = r_create_tree (NULL, 0, 0);
+          r_insert_entry (pour->polygon_tree, (BoxType *) poly, 0);
+        }
+      else
+        {
+          poly_Free (&pg);
+        }
+    }
+  while ((pg = tmp) != start_pg);
+
+  return 0;
+}
+
+static POLYAREA *
+get_unsubtract_pin_poly (PinType * pin, LayerType * l, PourType * pour)
+{
+  /* overlap a bit to prevent gaps from rounding errors */
+  return BoxPolyBloated (&pin->BoundingBox, UNSUBTRACT_BLOAT);
+}
+
+static POLYAREA *
+get_unsubtract_arc_poly (ArcType * arc, LayerType * l, PourType * pour)
+{
+  if (!TEST_FLAG (CLEARLINEFLAG, arc))
+    return NULL;
+
+  /* overlap a bit to prevent gaps from rounding errors */
+  return BoxPolyBloated (&arc->BoundingBox, UNSUBTRACT_BLOAT);
+}
+
+static POLYAREA *
+get_unsubtract_line_poly (LineType * line, LayerType * l, PourType * pour)
+{
+  if (!TEST_FLAG (CLEARLINEFLAG, line))
+    return NULL;
+
+  /* overlap a bit to prevent notches from rounding errors */
+  return BoxPolyBloated (&line->BoundingBox, UNSUBTRACT_BLOAT);
+}
+
+static POLYAREA *
+get_unsubtract_text_poly (TextType * text, LayerType * l, PourType * pour)
+{
+  if (!TEST_FLAG (CLEARLINEFLAG, text))
+    return NULL;
+
+  /* overlap a bit to prevent notches from rounding errors */
+  return BoxPolyBloated (&text->BoundingBox, UNSUBTRACT_BLOAT);
+}
+
+static POLYAREA *
+get_unsubtract_pad_poly (PadType * pad, LayerType * l, PourType * pour)
+{
+  /* overlap a bit to prevent notches from rounding errors */
+  return BoxPolyBloated (&pad->BoundingBox, UNSUBTRACT_BLOAT);
+}
+
+static POLYAREA *
+get_unsubtract_polygon_poly (PolygonType * poly, LayerType * l, PourType * pour)
+{
+  /* Don't subtract from ourselves, or if CLEARLINEFLAG isn't set */
+  if (poly->ParentPour == pour || !TEST_FLAG (CLEARLINEFLAG, poly))
+    return NULL;
+
+  /* overlap a bit to prevent notches from rounding errors */
+  return BoxPolyBloated (&poly->BoundingBox, UNSUBTRACT_BLOAT);
+}
+
+static POLYAREA *
+original_pour_poly (PourType * p)
+{
+  PLINE *contour = NULL;
+  POLYAREA *np = NULL;
+  Cardinal n;
+  Vector v;
+  int hole = 0;
+
+  if ((np = poly_Create ()) == NULL)
+    return NULL;
+
+  /* first make initial pour contour */
+  for (n = 0; n < p->PointN; n++)
+    {
+      /* No current contour? Make a new one starting at point */
+      /*   (or) Add point to existing contour */
+
+      v[0] = p->Points[n].X;
+      v[1] = p->Points[n].Y;
+      if (contour == NULL)
+        {
+          if ((contour = poly_NewContour (v)) == NULL)
+            return NULL;
+        }
+      else
+        {
+          poly_InclVertex (contour->head.prev, poly_CreateNode (v));
+        }
+
+      /* Is current point last in contour? If so process it. */
+      if (n == p->PointN - 1 ||
+          (hole < p->HoleIndexN && n == p->HoleIndex[hole] - 1))
+        {
+          if (contour == NULL)
+            {
+              printf ("How did that escape - did the loop iterate zero times??\n");
+              POURPOINT_LOOP (p);
+                {
+                  printf ("Hello\n");
+                }
+              END_LOOP;
+              return NULL;
+            }
+          poly_PreContour (contour, TRUE);
+
+          /* make sure it is a positive contour (outer) or negative (hole) */
+          if (contour->Flags.orient != (hole ? PLF_INV : PLF_DIR))
+            poly_InvContour (contour);
+          assert (contour->Flags.orient == (hole ? PLF_INV : PLF_DIR));
+
+          poly_InclContour (np, contour);
+          contour = NULL;
+          assert (poly_Valid (np));
+
+          hole++;
+        }
+    }
+  return np;
+}
+
+POLYAREA *
+PourToPoly (PourType *p)
+{
+  return original_pour_poly (p);
+}
+
+static int
+add_plow (DataTypePtr Data, LayerTypePtr Layer, PourTypePtr pour,
+          int type, void *ptr1, void *ptr2)
+{
+  POLYAREA *np = NULL, *pg = NULL, *tmp, *start_pg;
+  POLYAREA *orig_poly;
+  int count, count_all, count_added;
+
+  switch (type)
+    {
+    case PIN_TYPE:
+    case VIA_TYPE:
+      np = get_unsubtract_pin_poly ((PinTypePtr) ptr2, Layer, pour);
+      break;
+    case LINE_TYPE:
+      np = get_unsubtract_line_poly ((LineTypePtr) ptr2, Layer, pour);
+      break;
+    case ARC_TYPE:
+      np = get_unsubtract_arc_poly ((ArcTypePtr) ptr2, Layer, pour);
+      break;
+    case PAD_TYPE:
+      np = get_unsubtract_pad_poly ((PadTypePtr) ptr2, Layer, pour);
+      break;
+    case POLYGON_TYPE:
+      np = get_unsubtract_polygon_poly ((PolygonTypePtr) ptr2, Layer, pour);
+      break;
+    case TEXT_TYPE:
+      np = get_unsubtract_text_poly ((TextTypePtr) ptr2, Layer, pour);
+      break;
+    }
+
+  if (np == NULL)
+    {
+      printf ("Didn't get a POLYAREA to add, so bailing\n");
+      return 0;
+    }
+
+  orig_poly = original_pour_poly (pour);
+  /* NB: orig_poly and old *pg are freed inside intersect_poly() */
+  intersect_poly (orig_poly, &np);
+
+  if (np == NULL)
+    {
+      printf ("POLYAREA to add got clipped away, so bailing\n");
+      return 0;
+    }
+
+  assert (poly_Valid (np));
+
+  /* Make pg contain the polygons we're going to fiddle with */
+
+  count = 0;
+  POURPOLYGON_LOOP (pour);
+  {
+    /* Gather up children which are touched by np */
+    if (isects (np, polygon, false))
+      {
+        count++;
+        /* Steal their clipped contours, then delete them */
+        /* Add contour to local list to fiddle about with */
+
+        assert (poly_Valid (polygon->Clipped));
+        if (polygon->Clipped == NULL)
+          {
+            printf ("Got polygon->clipped == NULL!\n");
+            continue;
+          }
+        if (pg == NULL)
+          {
+            pg = polygon->Clipped;
+            polygon->Clipped = NULL;
+          }
+        else
+          {
+            /* Link the _single_ polygon->Clipped into our circular pg list. */
+            polygon->Clipped->f = pg;
+            polygon->Clipped->b = pg->b;
+            pg->b->f = polygon->Clipped;
+            pg->b = polygon->Clipped;
+            polygon->Clipped = NULL;
+          }
+        /* POURPOLYGON_LOOP iterates backwards, so it's OK
+         * to delete the current element we're sitting on */
+        DestroyPolygonInPour (pour, polygon);
+      }
+  }
+  END_LOOP;
+//  printf ("Unsubtract counted %i touching children, now removed\n", count);
+
+  if (pg == NULL)
+    {
+      printf ("Hmm, got pg == NULL in add_plow\n");
+//      poly_Free (&np);
+//      return -1;
+    }
+
+//  assert (poly_Valid (pg));
+
+  /* Perform the union operation */
+  /* NB: np and old *pg are freed inside union_poly() */
+  unite_poly (np, &pg);
+
+
+#if 0
+  count = 0;
+  { POLYAREA *pg_start;
+  pg_start = pg;
+  do {
+    count++;
+  } while ((pg = pg->f) != pg_start);
+  }
+  printf ("After unsubtract, counted %i polygon pieces\n", count);
+#endif
+
+  ClearPour (PCB->Data, Layer, pour, &pg, (const BoxType *) ptr2, 2 * UNSUBTRACT_BLOAT);
+
+  if (pg == NULL)
+    {
+      printf ("Poly killed to death somehow\n");
+      return -1;
+    }
+
+  /* For each piece of the clipped up polygon, create a new child */
+  count_all = count_added = 0;
+  start_pg = pg;
+  do
+    {
+      PolygonType *poly;
+
+      tmp = pg->f;
+      pg->f = pg;
+      pg->b = pg;
+      count_all++;
+//      if (pg->contours->area > PCB->IsleArea)
+      if (1) // Breaks incremental updates otherwise
+        {
+          count_added++;
+          poly = CreateNewPolygonInPour (pour, pour->Flags);
+          poly->Clipped = pg;
+          CLEAR_FLAG (SELECTEDFLAG, poly);
+
+          SetPolygonBoundingBox (poly);
+
+          if (pour->polygon_tree == NULL)
+            pour->polygon_tree = r_create_tree (NULL, 0, 0);
+          r_insert_entry (pour->polygon_tree, (BoxType *) poly, 0);
+        }
+      else
+        {
+          printf ("Too small\n");
+          poly_Free (&pg);
+        }
+    }
+  while ((pg = tmp) != start_pg);
+
+//  printf ("ClearPour counted %i polygon pieces, and added the biggest %i\n", count_all, count_added);
+
+  return 0;
+}
+
+/* ---------------------------------------------------------------------------------------------------------- */
+
+int
+InitPourClip (DataTypePtr Data, LayerTypePtr layer, PourType * pour)
+{
+  POLYAREA *pg, *tmp, *start_pg;
+  int count_all, count_added;
+
+  /* Free any children we might have */
+  if (pour->PolygonN)
+    {
+      POURPOLYGON_LOOP (pour);
+      {
+        /* POURPOLYGON_LOOP iterates backwards, so it's OK
+         * to delete the current element we're sitting on */
+        DestroyPolygonInPour (pour, polygon);
+      }
+      END_LOOP;
+    }
+
+  pg = original_pour_poly (pour);
+  if (!pg)
+    {
+      printf ("Clipping returned NULL - can that be good?\n");
+      return 0;
+    }
+  if (!pg->contours)
+    {
+      printf ("Clipping returned NULL contours - can that be good?\n");
+      printf ("Pour was %ld, %p\n", pour->ID, pour);
+      return 0;
+    }
+//  assert (poly_Valid (clipped));
+  if (TEST_FLAG (CLEARPOLYFLAG, pour))
+    {
+      /* Clip the pour against anything we can find in this layer */
+      ClearPour (Data, layer, pour, &pg, NULL, UNSUBTRACT_BLOAT);
+    }
+
+  if (pg == NULL)
+    {
+      printf ("Got pg == NULL for some reason\n");
+      return 0;
+    }
+
+  if (pg->contours == NULL)
+    {
+      printf ("Got pg->contours == NULL for some reason\n");
+      printf ("Pour was %ld, %p\n", pour->ID, pour);
+      return 0;
+    }
+
+  count_all = count_added = 0;
+  /* For each piece of the clipped up polygon, create a new child */
+  start_pg = pg;
+  do
+    {
+      PolygonType *poly;
+
+      tmp = pg->f;
+      pg->f = pg;
+      pg->b = pg;
+
+      count_all++;
+//      if (pg->contours->area > PCB->IsleArea)
+      if (1) // Breaks incremental updates otherwise
+        {
+          count_added++;
+          poly = CreateNewPolygonInPour (pour, pour->Flags);
+          poly->Clipped = pg;
+          CLEAR_FLAG (SELECTEDFLAG, poly);
+
+          SetPolygonBoundingBox (poly);
+
+          if (pour->polygon_tree == NULL)
+            pour->polygon_tree = r_create_tree (NULL, 0, 0);
+          r_insert_entry (pour->polygon_tree, (BoxType *) poly, 0);
+        }
+      else
+        {
+          poly_Free (&pg);
+        }
+    }
+  while ((pg = tmp) != start_pg);
+
+  return 1;
+}
+
+struct plow_info
+{
+  int type;
+  void *ptr1, *ptr2;
+  LayerTypePtr layer;
+  DataTypePtr data;
+  int (*callback) (DataTypePtr, LayerTypePtr,
+                   PourTypePtr, int, void *, void *);
+};
+
+static int
+plow_callback (const BoxType * b, void *cl)
+{
+  struct plow_info *plow = (struct plow_info *) cl;
+  PourTypePtr pour = (PourTypePtr) b;
+
+  if (TEST_FLAG (CLEARPOLYFLAG, pour))
+    return plow->callback (plow->data, plow->layer, pour,
+                           plow->type, plow->ptr1, plow->ptr2);
+  return 0;
+}
+
+int
+PlowPours (DataType * Data, int type, void *ptr1, void *ptr2,
+           int (*call_back) (DataTypePtr data, LayerTypePtr lay,
+                             PourTypePtr poly, int type,
+                             void *ptr1, void *ptr2))
+{
+  BoxType sb = ((PinTypePtr) ptr2)->BoundingBox;
+  int r = 0;
+  struct plow_info info;
+
+  info.type = type;
+  info.ptr1 = ptr1;
+  info.ptr2 = ptr2;
+  info.data = Data;
+  info.callback = call_back;
+  switch (type)
+    {
+    case PIN_TYPE:
+    case VIA_TYPE:
+      if (type == PIN_TYPE || ptr1 == ptr2 || ptr1 == NULL)
+        {
+          LAYER_LOOP (Data, max_layer);
+          {
+            info.layer = layer;
+            r += r_search (layer->pour_tree, &sb, NULL, plow_callback, &info);
+          }
+          END_LOOP;
+        }
+      else
+        {
+          int layer_no = GetLayerNumber (Data, ((LayerTypePtr) ptr1));
+          int group_no = GetLayerGroupNumberByNumber (layer_no);
+          GROUP_LOOP (Data, group_no);
+          {
+            info.layer = layer;
+            r += r_search (layer->pour_tree, &sb, NULL, plow_callback, &info);
+          }
+          END_LOOP;
+        }
+      break;
+    case LINE_TYPE:
+    case ARC_TYPE:
+    case TEXT_TYPE:
+    case POLYGON_TYPE:
+      /* the cast works equally well for lines and arcs */
+      if (!TEST_FLAG (CLEARLINEFLAG, (LineTypePtr) ptr2))
+        return 0;
+      /* silk doesn't plow */
+      if (GetLayerNumber (Data, ptr1) >= max_layer)
+        return 0;
+      GROUP_LOOP (Data, GetLayerGroupNumberByNumber (GetLayerNumber (Data,
+                                                                     ((LayerTypePtr) ptr1))));
+      {
+        info.layer = layer;
+        r += r_search (layer->pour_tree, &sb, NULL, plow_callback, &info);
+      }
+      END_LOOP;
+      break;
+    case PAD_TYPE:
+      {
+        Cardinal group = TEST_FLAG (ONSOLDERFLAG,
+                                    (PadType *) ptr2) ? SOLDER_LAYER :
+          COMPONENT_LAYER;
+        group = GetLayerGroupNumberByNumber (max_layer + group);
+        GROUP_LOOP (Data, group);
+        {
+          info.layer = layer;
+          r += r_search (layer->pour_tree, &sb, NULL, plow_callback, &info);
+        }
+        END_LOOP;
+      }
+      break;
+
+    case ELEMENT_TYPE:
+      {
+        PIN_LOOP ((ElementType *) ptr1);
+        {
+          PlowPours (Data, PIN_TYPE, ptr1, pin, call_back);
+        }
+        END_LOOP;
+        PAD_LOOP ((ElementType *) ptr1);
+        {
+          PlowPours (Data, PAD_TYPE, ptr1, pad, call_back);
+        }
+        END_LOOP;
+      }
+      break;
+    }
+  return r;
+}
+
+void
+RestoreToPours (DataType * Data, int type, void *ptr1, void *ptr2)
+{
+  if (type == POUR_TYPE)
+    {
+#warning FIXME Later: Why do we need to do this?
+//      printf ("Calling InitPourClip from RestoreToPour\n");
+      InitPourClip (PCB->Data, (LayerTypePtr) ptr1, (PourTypePtr) ptr2);
+    }
+  PlowPours (Data, type, ptr1, ptr2, add_plow);
+}
+
+void
+ClearFromPours (DataType * Data, int type, void *ptr1, void *ptr2)
+{
+  if (type == POUR_TYPE)
+    {
+#warning FIXME Later: Why do we need to do this?
+//      printf ("Calling InitPourClip from ClearFromPour\n");
+      InitPourClip (PCB->Data, (LayerTypePtr) ptr1, (PourTypePtr) ptr2);
+    }
+  PlowPours (Data, type, ptr1, ptr2, subtract_plow);
+}
+
+/* Convert a POLYAREA (and all linked POLYAREA) to
+ * raw PCB pours on the given layer.
+ */
+void
+PolyToPoursOnLayer (DataType *Destination, LayerType *Layer,
+                    POLYAREA *Input, FlagType Flags)
+{
+  PourType *Pour;
+  POLYAREA *pa;
+  PLINE *pline;
+  VNODE *node;
+  bool outer;
+
+  if (Input == NULL)
+    return;
+
+  pa = Input;
+  do
+    {
+      Pour = CreateNewPour (Layer, Flags);
+
+      pline = pa->contours;
+      outer = true;
+
+      do
+        {
+          if (!outer)
+            CreateNewHoleInPour (Pour);
+          outer = false;
+
+          node = &pline->head;
+          do
+            {
+              CreateNewPointInPour (Pour, node->point[0], node->point[1]);
+            }
+          while ((node = node->next) != &pline->head);
+
+        }
+      while ((pline = pline->next) != NULL);
+
+      SetPourBoundingBox (Pour);
+      if (!Layer->pour_tree)
+        Layer->pour_tree = r_create_tree (NULL, 0, 0);
+      r_insert_entry (Layer->pour_tree, (BoxType *) Pour, 0);
+
+      InitPourClip (Destination, Layer, Pour);
+      DrawPour (Layer, Pour, 0);
+      /* add to undo list */
+      AddObjectToCreateUndoList (POLYGON_TYPE, Layer, Pour, Pour);
+    }
+  while ((pa = pa->f) != Input);
+
+  SetChangedFlag (true);
+}
diff --git a/src/pour.h b/src/pour.h
new file mode 100644
index 0000000..4711da7
--- /dev/null
+++ b/src/pour.h
@@ -0,0 +1,54 @@
+/*
+ *                            COPYRIGHT
+ *
+ *  PCB, interactive printed circuit board design
+ *  Copyright (C) 1994,1995,1996 Thomas Nau
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *  Contact addresses for paper mail and Email:
+ *  Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
+ *  Thomas.Nau@xxxxxxxxxxxxx
+ *
+ *  RCS: $Id$
+ */
+
+/* prototypes for pour editing routines
+ */
+
+#ifndef	__POUR_INCLUDED__
+#define	__POUR_INCLUDED__
+
+#include "global.h"
+
+Cardinal pour_point_idx (PourTypePtr, PointTypePtr);
+Cardinal pour_point_contour (PourTypePtr, Cardinal);
+Cardinal prev_contour_point (PourTypePtr, Cardinal);
+Cardinal next_contour_point (PourTypePtr, Cardinal);
+Cardinal GetLowestDistancePourPoint (PourTypePtr,
+					LocationType, LocationType);
+bool RemoveExcessPourPoints (LayerTypePtr, PourTypePtr);
+void GoToPreviousPourPoint (void);
+void ClosePour (void);
+void CopyAttachedPourToLayer (void);
+
+int InitPourClip(DataType *d, LayerType *l, PourType *p);
+void RestoreToPours(DataType *, int, void *, void *);
+void ClearFromPours(DataType *, int, void *, void *);
+
+POLYAREA * PourToPoly (PourType *);
+void PolyToPoursOnLayer (DataType *, LayerType *, POLYAREA *, FlagType);
+
+#endif /* __POUR_INCLUDED__ */
diff --git a/src/puller.c b/src/puller.c
index 848d394..db123b1 100644
--- a/src/puller.c
+++ b/src/puller.c
@@ -1704,6 +1704,8 @@ gp_text_cb (const BoxType *b, void *cb)
   return 0;
 }
 
+#warning FIXME Later: Really want to geometry of the clipped polygons
+#if 0
 static int
 gp_poly_cb (const BoxType *b, void *cb)
 {
@@ -1713,6 +1715,18 @@ gp_poly_cb (const BoxType *b, void *cb)
     gp_point (p->Points[i].X, p->Points[i].Y, 0, 0);
   return 0;
 }
+#endif
+
+#warning FIXME Later: Really want to geometry of the clipped polygons
+static int
+gp_pour_cb (const BoxType *b, void *cb)
+{
+  int i;
+  const PourTypePtr p = (PourTypePtr) b;
+  for (i=0; i<p->PointN; i++)
+    gp_point (p->Points[i].X, p->Points[i].Y, 0, 0);
+  return 0;
+}
 
 static int
 gp_pin_cb (const BoxType *b, void *cb)
@@ -2238,7 +2252,7 @@ maybe_pull_1 (LineTypePtr line)
   r_search(CURRENT->line_tree, &box, NULL, gp_line_cb, 0);
   r_search(CURRENT->arc_tree, &box, NULL, gp_arc_cb, 0);
   r_search(CURRENT->text_tree, &box, NULL, gp_text_cb, 0);
-  r_search(CURRENT->polygon_tree, &box, NULL, gp_poly_cb, 0);
+  r_search(CURRENT->pour_tree, &box, NULL, gp_pour_cb, 0);
   r_search(PCB->Data->pin_tree, &box, NULL, gp_pin_cb, 0);
   r_search(PCB->Data->via_tree, &box, NULL, gp_pin_cb, 0);
   r_search(PCB->Data->pad_tree, &box, NULL, gp_pad_cb, 0);
diff --git a/src/rats.c b/src/rats.c
index 29e9831..d986a26 100644
--- a/src/rats.c
+++ b/src/rats.c
@@ -513,20 +513,24 @@ GatherSubnets (NetListTypePtr Netl, bool NoWarn, bool AndRats)
       }
       ENDALL_LOOP;
       /* add polygons so the auto-router can see them as targets */
-      ALLPOLYGON_LOOP (PCB->Data);
+      ALLPOUR_LOOP (PCB->Data);
       {
-	if (TEST_FLAG (DRCFLAG, polygon))
-	  {
-	    conn = GetConnectionMemory (a);
-	    /* make point on a vertex */
-	    conn->X = polygon->Clipped->contours->head.point[0];
-	    conn->Y = polygon->Clipped->contours->head.point[1];
-	    conn->type = POLYGON_TYPE;
-	    conn->ptr1 = layer;
-	    conn->ptr2 = polygon;
-	    conn->group = GetLayerGroupNumberByPointer (layer);
-	    conn->menu = NULL;	/* agnostic view of where it belongs */
-	  }
+        POURPOLYGON_LOOP (pour);
+        {
+          if (TEST_FLAG (DRCFLAG, polygon))
+            {
+              conn = GetConnectionMemory (a);
+              /* make point on a vertex */
+              conn->X = polygon->Clipped->contours->head.point[0];
+              conn->Y = polygon->Clipped->contours->head.point[1];
+              conn->type = POLYGON_TYPE;
+              conn->ptr1 = layer;
+              conn->ptr2 = polygon;
+              conn->group = GetLayerGroupNumberByPointer (layer);
+              conn->menu = NULL;	/* agnostic view of where it belongs */
+            }
+        }
+        END_LOOP;
       }
       ENDALL_LOOP;
       VIA_LOOP (PCB->Data);
diff --git a/src/remove.c b/src/remove.c
index 98b9ade..d124284 100644
--- a/src/remove.c
+++ b/src/remove.c
@@ -45,7 +45,8 @@
 #include "misc.h"
 #include "move.h"
 #include "mymem.h"
-#include "polygon.h"
+//#include "polygon.h"
+#include "pour.h"
 #include "rats.h"
 #include "remove.h"
 #include "rtree.h"
@@ -69,13 +70,13 @@ static void *DestroyRat (RatTypePtr);
 static void *DestroyLine (LayerTypePtr, LineTypePtr);
 static void *DestroyArc (LayerTypePtr, ArcTypePtr);
 static void *DestroyText (LayerTypePtr, TextTypePtr);
-static void *DestroyPolygon (LayerTypePtr, PolygonTypePtr);
+static void *DestroyPour (LayerTypePtr, PourTypePtr);
 static void *DestroyElement (ElementTypePtr);
 static void *RemoveVia (PinTypePtr);
 static void *RemoveRat (RatTypePtr);
-static void *DestroyPolygonPoint (LayerTypePtr, PolygonTypePtr, PointTypePtr);
-static void *RemovePolygonContour (LayerTypePtr, PolygonTypePtr, Cardinal);
-static void *RemovePolygonPoint (LayerTypePtr, PolygonTypePtr, PointTypePtr);
+static void *DestroyPourPoint (LayerTypePtr, PourTypePtr, PointTypePtr);
+static void *RemovePourContour (LayerTypePtr, PourTypePtr, Cardinal);
+static void *RemovePourPoint (LayerTypePtr, PourTypePtr, PointTypePtr);
 static void *RemoveLinePoint (LayerTypePtr, LineTypePtr, PointTypePtr);
 
 /* ---------------------------------------------------------------------------
@@ -84,28 +85,30 @@ static void *RemoveLinePoint (LayerTypePtr, LineTypePtr, PointTypePtr);
 static ObjectFunctionType RemoveFunctions = {
   RemoveLine,
   RemoveText,
-  RemovePolygon,
+  NULL,
+  RemovePour,
   RemoveVia,
   RemoveElement,
   NULL,
   NULL,
   NULL,
   RemoveLinePoint,
-  RemovePolygonPoint,
+  RemovePourPoint,
   RemoveArc,
   RemoveRat
 };
 static ObjectFunctionType DestroyFunctions = {
   DestroyLine,
   DestroyText,
-  DestroyPolygon,
+  NULL, //DestroyPolygon,
+  DestroyPour,
   DestroyVia,
   DestroyElement,
   NULL,
   NULL,
   NULL,
   NULL,
-  DestroyPolygonPoint,
+  DestroyPourPoint,
   DestroyArc,
   DestroyRat
 };
@@ -179,62 +182,66 @@ DestroyArc (LayerTypePtr Layer, ArcTypePtr Arc)
 }
 
 /* ---------------------------------------------------------------------------
- * destroys a polygon from a layer
+ * destroys a pour from a layer
  */
 static void *
-DestroyPolygon (LayerTypePtr Layer, PolygonTypePtr Polygon)
+DestroyPour (LayerTypePtr Layer, PourTypePtr Pour)
 {
-  r_delete_entry (Layer->polygon_tree, (BoxTypePtr) Polygon);
-  FreePolygonMemory (Polygon);
-  if (Polygon != &Layer->Polygon[--Layer->PolygonN])
+  Cardinal i;
+
+  r_delete_entry (Layer->pour_tree, (BoxTypePtr) Pour);
+  FreePourMemory (Pour);
+  if (Pour != &Layer->Pour[--Layer->PourN])
     {
-      *Polygon = Layer->Polygon[Layer->PolygonN];
-      r_substitute (Layer->polygon_tree,
-		    (BoxType *) & Layer->Polygon[Layer->PolygonN],
-		    (BoxType *) Polygon);
+      *Pour = Layer->Pour[Layer->PourN];
+      r_substitute (Layer->pour_tree,
+                    (BoxType *) & Layer->Pour[Layer->PourN],
+                    (BoxType *) Pour);
+      for (i = 0; i < Pour->PolygonN; i++)
+        Pour->Polygons[i].ParentPour = Pour;
     }
-  memset (&Layer->Polygon[Layer->PolygonN], 0, sizeof (PolygonType));
+  memset (&Layer->Pour[Layer->PourN], 0, sizeof (PourType));
   return (NULL);
 }
 
 /* ---------------------------------------------------------------------------
- * removes a polygon-point from a polygon and destroys the data
+ * removes a pour-point from a pour and destroys the data
  */
 static void *
-DestroyPolygonPoint (LayerTypePtr Layer,
-		     PolygonTypePtr Polygon, PointTypePtr Point)
+DestroyPourPoint (LayerTypePtr Layer,
+                  PourTypePtr Pour, PointTypePtr Point)
 {
   Cardinal point_idx;
   Cardinal i;
   Cardinal contour;
   Cardinal contour_start, contour_end, contour_points;
 
-  point_idx = polygon_point_idx (Polygon, Point);
-  contour = polygon_point_contour (Polygon, point_idx);
-  contour_start = (contour == 0) ? 0 : Polygon->HoleIndex[contour - 1];
-  contour_end = (contour == Polygon->HoleIndexN) ? Polygon->PointN :
-                                                   Polygon->HoleIndex[contour];
+  point_idx = pour_point_idx (Pour, Point);
+  contour = pour_point_contour (Pour, point_idx);
+  contour_start = (contour == 0) ? 0 : Pour->HoleIndex[contour - 1];
+  contour_end = (contour == Pour->HoleIndexN) ? Pour->PointN :
+                                                Pour->HoleIndex[contour];
   contour_points = contour_end - contour_start;
 
   if (contour_points <= 3)
-    return RemovePolygonContour (Layer, Polygon, contour);
+    return RemovePourContour (Layer, Pour, contour);
 
-  r_delete_entry (Layer->polygon_tree, (BoxType *) Polygon);
+  r_delete_entry (Layer->pour_tree, (BoxType *) Pour);
 
   /* remove point from list, keep point order */
-  for (i = point_idx; i < Polygon->PointN - 1; i++)
-    Polygon->Points[i] = Polygon->Points[i + 1];
-  Polygon->PointN--;
+  for (i = point_idx; i < Pour->PointN - 1; i++)
+    Pour->Points[i] = Pour->Points[i + 1];
+  Pour->PointN--;
 
   /* Shift down indices of any holes */
-  for (i = 0; i < Polygon->HoleIndexN; i++)
-    if (Polygon->HoleIndex[i] > point_idx)
-      Polygon->HoleIndex[i]--;
-
-  SetPolygonBoundingBox (Polygon);
-  r_insert_entry (Layer->polygon_tree, (BoxType *) Polygon, 0);
-  InitClip (PCB->Data, Layer, Polygon);
-  return (Polygon);
+  for (i = 0; i < Pour->HoleIndexN; i++)
+    if (Pour->HoleIndex[i] > point_idx)
+      Pour->HoleIndex[i]--;
+
+  SetPourBoundingBox (Pour);
+  r_insert_entry (Layer->pour_tree, (BoxType *) Pour, 0);
+  InitPourClip (PCB->Data, Layer, Pour);
+  return (Pour);
 }
 
 /* ---------------------------------------------------------------------------
@@ -481,67 +488,67 @@ RemoveText (LayerTypePtr Layer, TextTypePtr Text)
 }
 
 /* ---------------------------------------------------------------------------
- * removes a polygon from a layer
+ * removes a pour from a layer
  */
 void *
-RemovePolygon (LayerTypePtr Layer, PolygonTypePtr Polygon)
+RemovePour (LayerTypePtr Layer, PourTypePtr Pour)
 {
   /* erase from screen */
   if (Layer->On)
     {
-      ErasePolygon (Polygon);
+      ErasePour (Pour);
       if (!Bulk)
 	Draw ();
     }
-  MoveObjectToRemoveUndoList (POLYGON_TYPE, Layer, Polygon, Polygon);
+  MoveObjectToRemoveUndoList (POUR_TYPE, Layer, Pour, Pour);
   return (NULL);
 }
 
 /* ---------------------------------------------------------------------------
- * removes a contour from a polygon.
- * If removing the outer contour, it removes the whole polygon.
+ * removes a contour from a pour.
+ * If removing the outer contour, it removes the whole pour.
  */
 static void *
-RemovePolygonContour (LayerTypePtr Layer,
-                      PolygonTypePtr Polygon,
-                      Cardinal contour)
+RemovePourContour (LayerTypePtr Layer,
+                   PourTypePtr Pour,
+                   Cardinal contour)
 {
   Cardinal contour_start, contour_end, contour_points;
   Cardinal i;
 
   if (contour == 0)
-    return RemovePolygon (Layer, Polygon);
+    return RemovePour (Layer, Pour);
 
   if (Layer->On)
     {
-      ErasePolygon (Polygon);
+      ErasePour (Pour);
       if (!Bulk)
         Draw ();
     }
 
-  /* Copy the polygon to the undo list */
-  AddObjectToRemoveContourUndoList (POLYGON_TYPE, Layer, Polygon);
+  /* Copy the pour to the undo list */
+  AddObjectToRemoveContourUndoList (POUR_TYPE, Layer, Pour);
 
-  contour_start = (contour == 0) ? 0 : Polygon->HoleIndex[contour - 1];
-  contour_end = (contour == Polygon->HoleIndexN) ? Polygon->PointN :
-                                                   Polygon->HoleIndex[contour];
+  contour_start = (contour == 0) ? 0 : Pour->HoleIndex[contour - 1];
+  contour_end = (contour == Pour->HoleIndexN) ? Pour->PointN :
+                                                Pour->HoleIndex[contour];
   contour_points = contour_end - contour_start;
 
   /* remove points from list, keep point order */
-  for (i = contour_start; i < Polygon->PointN - contour_points; i++)
-    Polygon->Points[i] = Polygon->Points[i + contour_points];
-  Polygon->PointN -= contour_points;
+  for (i = contour_start; i < Pour->PointN - contour_points; i++)
+    Pour->Points[i] = Pour->Points[i + contour_points];
+  Pour->PointN -= contour_points;
 
   /* remove hole from list and shift down remaining indices */
-  for (i = contour; i < Polygon->HoleIndexN; i++)
-    Polygon->HoleIndex[i - 1] = Polygon->HoleIndex[i] - contour_points;
-  Polygon->HoleIndexN--;
+  for (i = contour; i < Pour->HoleIndexN; i++)
+    Pour->HoleIndex[i - 1] = Pour->HoleIndex[i] - contour_points;
+  Pour->HoleIndexN--;
 
-  InitClip (PCB->Data, Layer, Polygon);
-  /* redraw polygon if necessary */
+  InitPourClip (PCB->Data, Layer, Pour);
+  /* redraw pour if necessary */
   if (Layer->On)
     {
-      DrawPolygon (Layer, Polygon, 0);
+      DrawPour (Layer, Pour, 0);
       if (!Bulk)
         Draw ();
     }
@@ -549,53 +556,53 @@ RemovePolygonContour (LayerTypePtr Layer,
 }
 
 /* ---------------------------------------------------------------------------
- * removes a polygon-point from a polygon
+ * removes a pour-point from a pour
  */
 static void *
-RemovePolygonPoint (LayerTypePtr Layer,
-		    PolygonTypePtr Polygon, PointTypePtr Point)
+RemovePourPoint (LayerTypePtr Layer,
+                 PourTypePtr Pour, PointTypePtr Point)
 {
   Cardinal point_idx;
   Cardinal i;
   Cardinal contour;
   Cardinal contour_start, contour_end, contour_points;
 
-  point_idx = polygon_point_idx (Polygon, Point);
-  contour = polygon_point_contour (Polygon, point_idx);
-  contour_start = (contour == 0) ? 0 : Polygon->HoleIndex[contour - 1];
-  contour_end = (contour == Polygon->HoleIndexN) ? Polygon->PointN :
-                                                   Polygon->HoleIndex[contour];
+  point_idx = pour_point_idx (Pour, Point);
+  contour = pour_point_contour (Pour, point_idx);
+  contour_start = (contour == 0) ? 0 : Pour->HoleIndex[contour - 1];
+  contour_end = (contour == Pour->HoleIndexN) ? Pour->PointN :
+                                                Pour->HoleIndex[contour];
   contour_points = contour_end - contour_start;
 
   if (contour_points <= 3)
-    return RemovePolygonContour (Layer, Polygon, contour);
+    return RemovePourContour (Layer, Pour, contour);
 
   if (Layer->On)
-    ErasePolygon (Polygon);
+    ErasePour (Pour);
 
-  /* insert the polygon-point into the undo list */
-  AddObjectToRemovePointUndoList (POLYGONPOINT_TYPE, Layer, Polygon, point_idx);
-  r_delete_entry (Layer->polygon_tree, (BoxType *) Polygon);
+  /* insert the pour-point into the undo list */
+  AddObjectToRemovePointUndoList (POURPOINT_TYPE, Layer, Pour, point_idx);
+  r_delete_entry (Layer->pour_tree, (BoxType *) Pour);
 
   /* remove point from list, keep point order */
-  for (i = point_idx; i < Polygon->PointN - 1; i++)
-    Polygon->Points[i] = Polygon->Points[i + 1];
-  Polygon->PointN--;
+  for (i = point_idx; i < Pour->PointN - 1; i++)
+    Pour->Points[i] = Pour->Points[i + 1];
+  Pour->PointN--;
 
   /* Shift down indices of any holes */
-  for (i = 0; i < Polygon->HoleIndexN; i++)
-    if (Polygon->HoleIndex[i] > point_idx)
-      Polygon->HoleIndex[i]--;
+  for (i = 0; i < Pour->HoleIndexN; i++)
+    if (Pour->HoleIndex[i] > point_idx)
+      Pour->HoleIndex[i]--;
 
-  SetPolygonBoundingBox (Polygon);
-  r_insert_entry (Layer->polygon_tree, (BoxType *) Polygon, 0);
-  RemoveExcessPolygonPoints (Layer, Polygon);
-  InitClip (PCB->Data, Layer, Polygon);
+  SetPourBoundingBox (Pour);
+  r_insert_entry (Layer->pour_tree, (BoxType *) Pour, 0);
+  RemoveExcessPourPoints (Layer, Pour);
+  InitPourClip (PCB->Data, Layer, Pour);
 
-  /* redraw polygon if necessary */
+  /* redraw pour if necessary */
   if (Layer->On)
     {
-      DrawPolygon (Layer, Polygon, 0);
+      DrawPour (Layer, Pour, 0);
       if (!Bulk)
 	Draw ();
     }
diff --git a/src/remove.h b/src/remove.h
index 9fd4625..07e158b 100644
--- a/src/remove.h
+++ b/src/remove.h
@@ -38,11 +38,11 @@
  */
 #define REMOVE_TYPES            \
 	(VIA_TYPE | LINEPOINT_TYPE | LINE_TYPE | TEXT_TYPE | ELEMENT_TYPE |	\
-	POLYGONPOINT_TYPE | POLYGON_TYPE | RATLINE_TYPE | ARC_TYPE)
+	POURPOINT_TYPE | POUR_TYPE | RATLINE_TYPE | ARC_TYPE)
 
 void *RemoveLine (LayerTypePtr, LineTypePtr);
 void *RemoveArc (LayerTypePtr, ArcTypePtr);
-void *RemovePolygon (LayerTypePtr, PolygonTypePtr);
+void *RemovePour (LayerTypePtr, PourTypePtr);
 void *RemoveText (LayerTypePtr, TextTypePtr);
 void *RemoveElement (ElementTypePtr);
 void ClearRemoveList (void);
diff --git a/src/report.c b/src/report.c
index dc01153..306c8d9 100644
--- a/src/report.c
+++ b/src/report.c
@@ -330,12 +330,43 @@ ReportDialog (int argc, char **argv, int x, int y)
 		 flags_to_string (Polygon->Flags, POLYGON_TYPE),
 		 Polygon->BoundingBox.X1, Polygon->BoundingBox.Y1,
 		 Polygon->BoundingBox.X2, Polygon->BoundingBox.Y2,
+     0, 0,
+#warning FIXME Later
+#if 0
 		 Polygon->PointN, Polygon->PointMax - Polygon->PointN,
 		 Polygon->HoleIndexN,
+#endif
 		 GetLayerNumber (PCB->Data, (LayerTypePtr) ptr1),
 		 TEST_FLAG (LOCKFLAG, Polygon) ? "It is LOCKED\n" : "");
 	break;
       }
+    case POUR_TYPE:
+      {
+	PourTypePtr Pour;
+#ifndef NDEBUG
+	if (gui->shift_is_pressed ())
+	  {
+	    LayerTypePtr layer = (LayerTypePtr) ptr1;
+	    __r_dump_tree (layer->pour_tree->root, 0);
+	    return;
+	  }
+#endif
+	Pour = (PourTypePtr) ptr2;
+
+	sprintf (&report[0], "POUR ID# %ld   Flags:%s\n"
+		 "Its bounding box is (%d,%d) (%d,%d)\n"
+		 "It has %d points and could store %d more\n"
+		 "without using more memory.\n"
+		 "It resides on layer %d\n"
+		 "%s", Pour->ID,
+		 flags_to_string (Pour->Flags, POUR_TYPE),
+		 Pour->BoundingBox.X1, Pour->BoundingBox.Y1,
+		 Pour->BoundingBox.X2, Pour->BoundingBox.Y2,
+		 Pour->PointN, Pour->PointMax - Pour->PointN,
+		 GetLayerNumber (PCB->Data, (LayerTypePtr) ptr1),
+		 TEST_FLAG (LOCKFLAG, Pour) ? "It is LOCKED\n" : "");
+	break;
+      }
     case PAD_TYPE:
       {
 	int len, dx, dy, mgap;
@@ -466,14 +497,14 @@ ReportDialog (int argc, char **argv, int x, int y)
 	break;
       }
     case LINEPOINT_TYPE:
-    case POLYGONPOINT_TYPE:
+    case POURPOINT_TYPE:
       {
 	PointTypePtr point = (PointTypePtr) ptr2;
 	sprintf (&report[0], "POINT ID# %ld. Points don't have flags.\n"
 		 "Located at (X,Y) = (%d,%d)\n"
 		 "It belongs to a %s on layer %d\n", point->ID,
 		 point->X, point->Y,
-		 (type == LINEPOINT_TYPE) ? "line" : "polygon",
+		 (type == LINEPOINT_TYPE) ? "line" : "pour",
 		 GetLayerNumber (PCB->Data, (LayerTypePtr) ptr1));
 	break;
       }
diff --git a/src/report.h b/src/report.h
index 7abbb79..39ce0ca 100644
--- a/src/report.h
+++ b/src/report.h
@@ -31,8 +31,8 @@
 #include "global.h"
 
 #define REPORT_TYPES \
-	(VIA_TYPE | LINE_TYPE | TEXT_TYPE | POLYGON_TYPE | ELEMENT_TYPE | \
+	(VIA_TYPE | LINE_TYPE | TEXT_TYPE | POUR_TYPE | ELEMENT_TYPE | \
 	 RATLINE_TYPE | PIN_TYPE | PAD_TYPE | ELEMENTNAME_TYPE | ARC_TYPE \
-	 | POLYGONPOINT_TYPE | LINEPOINT_TYPE)
+	 | POURPOINT_TYPE | LINEPOINT_TYPE)
 
 #endif
diff --git a/src/rotate.c b/src/rotate.c
index 9e19581..229e705 100644
--- a/src/rotate.c
+++ b/src/rotate.c
@@ -44,6 +44,7 @@
 #include "error.h"
 #include "misc.h"
 #include "polygon.h"
+#include "pour.h"
 #include "rotate.h"
 #include "rtree.h"
 #include "rubberband.h"
@@ -81,6 +82,7 @@ static ObjectFunctionType RotateFunctions = {
   RotateText,
   NULL,
   NULL,
+  NULL,
   RotateElement,
   RotateElementName,
   NULL,
@@ -158,18 +160,18 @@ RotateTextLowLevel (TextTypePtr Text, LocationType X, LocationType Y,
 }
 
 /* ---------------------------------------------------------------------------
- * rotates a polygon in 90 degree steps
+ * rotates a pour in 90 degree steps
  */
 void
-RotatePolygonLowLevel (PolygonTypePtr Polygon,
+RotatePourLowLevel (PourTypePtr Pour,
 		       LocationType X, LocationType Y, BYTE Number)
 {
-  POLYGONPOINT_LOOP (Polygon);
+  POURPOINT_LOOP (Pour);
   {
     ROTATE (point->X, point->Y, X, Y, Number);
   }
   END_LOOP;
-  RotateBoxLowLevel (&Polygon->BoundingBox, X, Y, Number);
+  RotateBoxLowLevel (&Pour->BoundingBox, X, Y, Number);
 }
 
 /* ---------------------------------------------------------------------------
@@ -179,11 +181,11 @@ static void *
 RotateText (LayerTypePtr Layer, TextTypePtr Text)
 {
   EraseText (Layer, Text);
-  RestoreToPolygon (PCB->Data, TEXT_TYPE, Layer, Text);
+  RestoreToPours (PCB->Data, TEXT_TYPE, Layer, Text);
   r_delete_entry (Layer->text_tree, (BoxTypePtr) Text);
   RotateTextLowLevel (Text, CenterX, CenterY, Number);
   r_insert_entry (Layer->text_tree, (BoxTypePtr) Text, 0);
-  ClearFromPolygon (PCB->Data, TEXT_TYPE, Layer, Text);
+  ClearFromPours (PCB->Data, TEXT_TYPE, Layer, Text);
   DrawText (Layer, Text, 0);
   Draw ();
   return (Text);
@@ -241,7 +243,7 @@ RotateElementLowLevel (DataTypePtr Data, ElementTypePtr Element,
     /* pre-delete the pins from the pin-tree before their coordinates change */
     if (Data)
       r_delete_entry (Data->pin_tree, (BoxType *) pin);
-    RestoreToPolygon (Data, PIN_TYPE, Element, pin);
+    RestoreToPours (Data, PIN_TYPE, Element, pin);
     ROTATE_PIN_LOWLEVEL (pin, X, Y, Number);
   }
   END_LOOP;
@@ -250,7 +252,7 @@ RotateElementLowLevel (DataTypePtr Data, ElementTypePtr Element,
     /* pre-delete the pads before their coordinates change */
     if (Data)
       r_delete_entry (Data->pad_tree, (BoxType *) pad);
-    RestoreToPolygon (Data, PAD_TYPE, Element, pad);
+    RestoreToPours (Data, PAD_TYPE, Element, pad);
     ROTATE_PAD_LOWLEVEL (pad, X, Y, Number);
   }
   END_LOOP;
@@ -262,7 +264,7 @@ RotateElementLowLevel (DataTypePtr Data, ElementTypePtr Element,
   ROTATE (Element->MarkX, Element->MarkY, X, Y, Number);
   /* SetElementBoundingBox reenters the rtree data */
   SetElementBoundingBox (Data, Element, &PCB->Font);
-  ClearFromPolygon (Data, ELEMENT_TYPE, Element, Element);
+  ClearFromPours (Data, ELEMENT_TYPE, Element, Element);
 }
 
 /* ---------------------------------------------------------------------------
@@ -274,7 +276,7 @@ RotateLinePoint (LayerTypePtr Layer, LineTypePtr Line, PointTypePtr Point)
   EraseLine (Line);
   if (Layer)
     {
-      RestoreToPolygon (PCB->Data, LINE_TYPE, Layer, Line);
+      RestoreToPours (PCB->Data, LINE_TYPE, Layer, Line);
       r_delete_entry (Layer->line_tree, (BoxTypePtr) Line);
     }
   else
@@ -284,7 +286,7 @@ RotateLinePoint (LayerTypePtr Layer, LineTypePtr Line, PointTypePtr Point)
   if (Layer)
     {
       r_insert_entry (Layer->line_tree, (BoxTypePtr) Line, 0);
-      ClearFromPolygon (PCB->Data, LINE_TYPE, Layer, Line);
+      ClearFromPours (PCB->Data, LINE_TYPE, Layer, Line);
       DrawLine (Layer, Line, 0);
     }
   else
@@ -388,7 +390,7 @@ RotateObject (int Type, void *Ptr1, void *Ptr2, void *Ptr3,
       EraseLine (ptr->Line);
       if (ptr->Layer)
 	{
-	  RestoreToPolygon (PCB->Data, LINE_TYPE, ptr->Layer, ptr->Line);
+	  RestoreToPours (PCB->Data, LINE_TYPE, ptr->Layer, ptr->Line);
 	  r_delete_entry (ptr->Layer->line_tree, (BoxType *) ptr->Line);
 	}
       else
@@ -398,7 +400,7 @@ RotateObject (int Type, void *Ptr1, void *Ptr2, void *Ptr3,
       if (ptr->Layer)
 	{
 	  r_insert_entry (ptr->Layer->line_tree, (BoxType *) ptr->Line, 0);
-	  ClearFromPolygon (PCB->Data, LINE_TYPE, ptr->Layer, ptr->Line);
+	  ClearFromPours (PCB->Data, LINE_TYPE, ptr->Layer, ptr->Line);
 	  DrawLine (ptr->Layer, ptr->Line, 0);
 	}
       else
diff --git a/src/rotate.h b/src/rotate.h
index f032fcb..8ad4f60 100644
--- a/src/rotate.h
+++ b/src/rotate.h
@@ -64,7 +64,7 @@ void RotateLineLowLevel (LineTypePtr, LocationType, LocationType, BYTE);
 void RotateArcLowLevel (ArcTypePtr, LocationType, LocationType, BYTE);
 void RotateBoxLowLevel (BoxTypePtr, LocationType, LocationType, BYTE);
 void RotateTextLowLevel (TextTypePtr, LocationType, LocationType, BYTE);
-void RotatePolygonLowLevel (PolygonTypePtr, LocationType, LocationType, BYTE);
+void RotatePourLowLevel (PourTypePtr, LocationType, LocationType, BYTE);
 void RotateElementLowLevel (DataTypePtr, ElementTypePtr, LocationType,
 			    LocationType, BYTE);
 void *RotateObject (int, void *, void *, void *, LocationType, LocationType,
diff --git a/src/search.c b/src/search.c
index c05a4b4..200cc89 100644
--- a/src/search.c
+++ b/src/search.c
@@ -80,6 +80,8 @@ static bool SearchTextByLocation (int, LayerTypePtr *, TextTypePtr *,
 				     TextTypePtr *);
 static bool SearchPolygonByLocation (int, LayerTypePtr *, PolygonTypePtr *,
 					PolygonTypePtr *);
+static bool SearchPourByLocation (int, LayerTypePtr *, PourTypePtr *,
+				  PourTypePtr *);
 static bool SearchPinByLocation (int, ElementTypePtr *, PinTypePtr *,
 				    PinTypePtr *);
 static bool SearchPadByLocation (int, ElementTypePtr *, PadTypePtr *,
@@ -91,8 +93,8 @@ static bool SearchElementNameByLocation (int, ElementTypePtr *,
 					    bool);
 static bool SearchLinePointByLocation (int, LayerTypePtr *, LineTypePtr *,
 					  PointTypePtr *);
-static bool SearchPointByLocation (int, LayerTypePtr *, PolygonTypePtr *,
-				      PointTypePtr *);
+static bool SearchPourPointByLocation (int, LayerTypePtr *, PourTypePtr *,
+				       PointTypePtr *);
 static bool SearchElementByLocation (int, ElementTypePtr *,
 					ElementTypePtr *, ElementTypePtr *,
 					bool);
@@ -105,6 +107,7 @@ struct ans_info
   void **ptr1, **ptr2, **ptr3;
   bool BackToo;
   float area;
+  BoxType *search_box;
   jmp_buf env;
   int locked;			/* This will be zero or LOCKFLAG */
 };
@@ -419,6 +422,14 @@ polygon_callback (const BoxType * box, void *cl)
   return 0;
 }
 
+static int
+pour_polygon_callback (const BoxType * box, void *cl)
+{
+  PourTypePtr pour = (PourTypePtr) box;
+  struct ans_info *i = (struct ans_info *) cl;
+
+  return r_search (pour->polygon_tree, &SearchBox, NULL, polygon_callback, i);
+}
 
 /* ---------------------------------------------------------------------------
  * searches a polygon on the SearchLayer 
@@ -436,13 +447,59 @@ SearchPolygonByLocation (int locked, LayerTypePtr * Layer,
 
   if (setjmp (info.env) == 0)
     {
-      r_search (SearchLayer->polygon_tree, &SearchBox, NULL, polygon_callback,
+      r_search (SearchLayer->pour_tree, &SearchBox, NULL, pour_polygon_callback,
 		&info);
       return false;
     }
   return (true);
 }
 
+#warning FIXME Later: For now, can only select a pour if you're hitting its child polygons
+#if 0
+static int
+pour_callback (const BoxType * box, void *cl)
+{
+  PourTypePtr pour = (PourTypePtr) box;
+  struct ans_info *i = (struct ans_info *) cl;
+
+  if (TEST_FLAG (i->locked, pour))
+    return 0;
+
+  if (IsPointInPour (PosX, PosY, SearchRadius, pour))
+    {
+      *i->ptr2 = *i->ptr3 = pour;
+      longjmp (i->env, 1);
+    }
+  return 0;
+}
+#endif
+
+/* ---------------------------------------------------------------------------
+ * searches a pour on the SearchLayer 
+ */
+static bool
+SearchPourByLocation (int locked, LayerTypePtr * Layer,
+                      PourTypePtr * Pour, PourTypePtr * Dummy)
+{
+  struct ans_info info;
+
+  *Layer = SearchLayer;
+  info.ptr2 = (void **) Pour;
+  info.ptr3 = (void **) Dummy;
+  info.locked = (locked & LOCKED_TYPE) ? 0 : LOCKFLAG;
+
+#warning FIXME Later: For now, can only select a pour if you're hitting its child polygons
+  if (setjmp (info.env) == 0)
+    {
+      r_search (SearchLayer->pour_tree, &SearchBox, NULL, pour_polygon_callback, &info);
+      return false;
+    }
+
+  /* Make sure we return the pour, not the polygon */
+  *info.ptr2 = *info.ptr3 = ((PolygonTypePtr)*info.ptr2)->ParentPour;
+  return (true);
+}
+
 static int
 linepoint_callback (const BoxType * b, void *cl)
 {
@@ -498,27 +555,27 @@ SearchLinePointByLocation (int locked, LayerTypePtr * Layer,
 }
 
 /* ---------------------------------------------------------------------------
- * searches a polygon-point on all layers that are switched on
+ * searches a pour-point on all layers that are switched on
  * in layerstack order
  */
 static bool
-SearchPointByLocation (int locked, LayerTypePtr * Layer,
-		       PolygonTypePtr * Polygon, PointTypePtr * Point)
+SearchPourPointByLocation (int locked, LayerTypePtr * Layer,
+		       PourTypePtr * Pour, PointTypePtr * Point)
 {
   float d, least;
   bool found = false;
 
-  least = SQUARE (SearchRadius + MAX_POLYGON_POINT_DISTANCE);
+  least = SQUARE (SearchRadius + MAX_POUR_POINT_DISTANCE);
   *Layer = SearchLayer;
-  POLYGON_LOOP (*Layer);
+  POUR_LOOP (*Layer);
   {
-    POLYGONPOINT_LOOP (polygon);
+    POURPOINT_LOOP (pour);
     {
       d = SQUARE (point->X - PosX) + SQUARE (point->Y - PosY);
       if (d < least)
 	{
 	  least = d;
-	  *Polygon = polygon;
+	  *Pour = pour;
 	  *Point = point;
 	  found = true;
 	}
@@ -1176,7 +1233,7 @@ SearchObjectByLocation (int Type,
     }
   if (TEST_FLAG (THINDRAWFLAG, PCB) || TEST_FLAG (THINDRAWPOLYFLAG, PCB))
     {
-      Type &= ~POLYGON_TYPE;
+      Type &= ~(POLYGON_TYPE | POUR_TYPE);
     }
 
   if (Type & RATLINE_TYPE && PCB->RatOn &&
@@ -1241,12 +1298,12 @@ SearchObjectByLocation (int Type,
       if (SearchLayer->On)
 	{
 	  if ((HigherAvail & (PIN_TYPE | PAD_TYPE)) == 0 &&
-	      Type & POLYGONPOINT_TYPE &&
-	      SearchPointByLocation (locked,
-				     (LayerTypePtr *) Result1,
-				     (PolygonTypePtr *) Result2,
-				     (PointTypePtr *) Result3))
-	    return (POLYGONPOINT_TYPE);
+	      Type & POURPOINT_TYPE &&
+	      SearchPourPointByLocation (locked,
+					 (LayerTypePtr *) Result1,
+					 (PourTypePtr *) Result2,
+					 (PointTypePtr *) Result3))
+	    return (POURPOINT_TYPE);
 
 	  if ((HigherAvail & (PIN_TYPE | PAD_TYPE)) == 0 &&
 	      Type & LINEPOINT_TYPE &&
@@ -1297,6 +1354,27 @@ SearchObjectByLocation (int Type,
 	      else
 		return (POLYGON_TYPE);
 	    }
+
+	  if (Type & POUR_TYPE &&
+	      SearchPourByLocation (locked,
+				    (LayerTypePtr *) Result1,
+				    (PourTypePtr *) Result2,
+				    (PourTypePtr *) Result3))
+	    {
+	      if (HigherAvail)
+		{
+		  BoxTypePtr box =
+		    &(*(PourTypePtr *) Result2)->BoundingBox;
+		  float area =
+		    (float) (box->X2 - box->X1) * (float) (box->X2 - box->X1);
+		  if (HigherBound < area)
+		    break;
+		  else
+		    return (POUR_TYPE);
+		}
+	      else
+		return (POUR_TYPE);
+	    }
 	}
     }
   /* return any previously found objects */
@@ -1428,31 +1506,47 @@ SearchObjectByID (DataTypePtr Base,
       ENDALL_LOOP;
     }
 
-  if (type == POLYGON_TYPE || type == POLYGONPOINT_TYPE)
+  if (type == POUR_TYPE || type == POURPOINT_TYPE || type == POLYGON_TYPE)
     {
-      ALLPOLYGON_LOOP (Base);
+      ALLPOUR_LOOP (Base);
       {
-	if (polygon->ID == ID)
+	if (pour->ID == ID)
 	  {
 	    *Result1 = (void *) layer;
-	    *Result2 = *Result3 = (void *) polygon;
-	    return (POLYGON_TYPE);
+	    *Result2 = *Result3 = (void *) pour;
+	    return (POUR_TYPE);
 	  }
-	if (type == POLYGONPOINT_TYPE)
-	  POLYGONPOINT_LOOP (polygon);
-	{
-	  if (point->ID == ID)
-	    {
-	      *Result1 = (void *) layer;
-	      *Result2 = (void *) polygon;
-	      *Result3 = (void *) point;
-	      return (POLYGONPOINT_TYPE);
-	    }
-	}
-	END_LOOP;
+	if (type == POURPOINT_TYPE)
+          {
+            POURPOINT_LOOP (pour);
+            {
+              if (point->ID == ID)
+                {
+                  *Result1 = (void *) layer;
+                  *Result2 = (void *) pour;
+                  *Result3 = (void *) point;
+                  return (POURPOINT_TYPE);
+                }
+            }
+            END_LOOP;
+          }
+        else if (type == POLYGON_TYPE)
+          {
+            POURPOLYGON_LOOP (pour);
+            {
+              if (polygon->ID == ID)
+                {
+                  *Result1 = (void *) layer;
+                  *Result2 = *Result3 = (void *) polygon;
+                  return (POLYGON_TYPE);
+                }
+            }
+            END_LOOP;
+          }
       }
       ENDALL_LOOP;
     }
+
   if (type == VIA_TYPE)
     {
       VIA_LOOP (Base);
diff --git a/src/search.h b/src/search.h
index add5661..25d8103 100644
--- a/src/search.h
+++ b/src/search.h
@@ -59,8 +59,13 @@
 #define	TEXT_IN_BOX(t,b)	\
 	(BOX_IN_BOX(&((t)->BoundingBox), (b)))
 
+#if 0 // NOT USED
 #define	POLYGON_IN_BOX(p,b)	\
 	(BOX_IN_BOX(&((p)->BoundingBox), (b)))
+#endif
+
+#define	POUR_IN_BOX(p,b)	\
+	(BOX_IN_BOX(&((p)->BoundingBox), (b)))
 
 #define	ELEMENT_IN_BOX(e,b)	\
 	(BOX_IN_BOX(&((e)->BoundingBox), (b)))
diff --git a/src/select.c b/src/select.c
index aa65f36..9467931 100644
--- a/src/select.c
+++ b/src/select.c
@@ -182,6 +182,7 @@ SelectObject (void)
 	break;
       }
 
+#if 0
     case POLYGON_TYPE:
       {
 	PolygonType *poly = (PolygonTypePtr) ptr2;
@@ -193,6 +194,19 @@ SelectObject (void)
 	/* changing memory order no longer effects draw order */
 	break;
       }
+#endif
+
+    case POUR_TYPE:
+      {
+	PourType *pour = (PourTypePtr) ptr2;
+
+	layer = (LayerTypePtr) ptr1;
+	AddObjectToFlagUndoList (POUR_TYPE, ptr1, ptr2, ptr2);
+	TOGGLE_FLAG (SELECTEDFLAG, pour);
+	DrawPour (layer, pour, 0);
+	/* changing memory order no longer effects draw order */
+	break;
+      }
 
     case PIN_TYPE:
       AddObjectToFlagUndoList (PIN_TYPE, ptr1, ptr2, ptr2);
@@ -351,8 +365,20 @@ SelectBlock (BoxTypePtr Box, bool Flag)
 	}
     }
     END_LOOP;
-    POLYGON_LOOP (layer);
+    POUR_LOOP (layer);
     {
+#warning FIXME Later: Do we want to be able to select the polygon pieces?
+      if (POUR_IN_BOX (pour, Box)
+	  && !TEST_FLAG (LOCKFLAG, pour)
+	  && TEST_FLAG (SELECTEDFLAG, pour) != Flag)
+	{
+	  AddObjectToFlagUndoList (POUR_TYPE, layer, pour, pour);
+	  ASSIGN_FLAG (SELECTEDFLAG, Flag, pour);
+	  if (layer->On)
+	    DrawPour (layer, pour, 0);
+	  changed = true;
+	}
+#if 0
       if (POLYGON_IN_BOX (polygon, Box)
 	  && !TEST_FLAG (LOCKFLAG, polygon)
 	  && TEST_FLAG (SELECTEDFLAG, polygon) != Flag)
@@ -363,6 +389,7 @@ SelectBlock (BoxTypePtr Box, bool Flag)
 	    DrawPolygon (layer, polygon, 0);
 	  changed = true;
 	}
+#endif
     }
     END_LOOP;
   }
@@ -523,9 +550,14 @@ ObjectOperation (ObjectFunctionTypePtr F,
 	return (F->Polygon ((LayerTypePtr) Ptr1, (PolygonTypePtr) Ptr2));
       break;
 
-    case POLYGONPOINT_TYPE:
-      if (F->Point)
-	return (F->Point ((LayerTypePtr) Ptr1, (PolygonTypePtr) Ptr2,
+    case POUR_TYPE:
+      if (F->Pour)
+	return (F->Pour ((LayerTypePtr) Ptr1, (PourTypePtr) Ptr2));
+      break;
+
+    case POURPOINT_TYPE:
+      if (F->PourPoint)
+	return (F->PourPoint ((LayerTypePtr) Ptr1, (PourTypePtr) Ptr2,
 			  (PointTypePtr) Ptr3));
       break;
 
@@ -624,21 +656,44 @@ SelectedOperation (ObjectFunctionTypePtr F, bool Reset, int type)
   }
   ENDALL_LOOP;
 
+#if 0
   /* check polygons */
   if (type & POLYGON_TYPE && F->Polygon)
-    VISIBLEPOLYGON_LOOP (PCB->Data);
-  {
-    if (TEST_FLAG (SELECTEDFLAG, polygon))
+    VISIBLEPOUR_LOOP (PCB->Data);
+    {
+      POURPOLYGON_LOOP (pour);
       {
-	if (Reset)
-	  {
-	    AddObjectToFlagUndoList (POLYGON_TYPE, layer, polygon, polygon);
-	    CLEAR_FLAG (SELECTEDFLAG, polygon);
-	  }
-	F->Polygon (layer, polygon);
-	changed = true;
+        if (TEST_FLAG (SELECTEDFLAG, polygon))
+          {
+            if (Reset)
+              {
+                AddObjectToFlagUndoList (POLYGON_TYPE, layer, polygon, polygon);
+                CLEAR_FLAG (SELECTEDFLAG, polygon);
+              }
+            F->Polygon (layer, polygon);
+            changed = true;
+          }
       }
-  }
+      END_LOOP;
+    }
+  ENDALL_LOOP;
+#endif
+
+  /* check pours */
+  if (type & POUR_TYPE && F->Pour)
+    VISIBLEPOUR_LOOP (PCB->Data);
+    {
+      if (TEST_FLAG (SELECTEDFLAG, pour))
+        {
+          if (Reset)
+            {
+              AddObjectToFlagUndoList (POUR_TYPE, layer, pour, pour);
+              CLEAR_FLAG (SELECTEDFLAG, pour);
+            }
+          F->Pour (layer, pour);
+          changed = true;
+        }
+    }
   ENDALL_LOOP;
 
   /* elements silkscreen */
@@ -800,17 +855,23 @@ SelectConnection (bool Flag)
       }
   }
   ENDALL_LOOP;
-  VISIBLEPOLYGON_LOOP (PCB->Data);
+#if 0
+  VISIBLEPOUR_LOOP (PCB->Data);
   {
-    if (TEST_FLAG (FOUNDFLAG, polygon) && !TEST_FLAG (LOCKFLAG, polygon))
-      {
-	AddObjectToFlagUndoList (POLYGON_TYPE, layer, polygon, polygon);
-	ASSIGN_FLAG (SELECTEDFLAG, Flag, polygon);
-	DrawPolygon (layer, polygon, 0);
-	changed = true;
-      }
+    POURPOLYGON_LOOP (pour);
+    {
+      if (TEST_FLAG (FOUNDFLAG, polygon) && !TEST_FLAG (LOCKFLAG, polygon))
+        {
+          AddObjectToFlagUndoList (POLYGON_TYPE, layer, polygon, polygon);
+          ASSIGN_FLAG (SELECTEDFLAG, Flag, polygon);
+          DrawPolygon (layer, polygon, 0);
+          changed = true;
+        }
+    }
+    END_LOOP;
   }
   ENDALL_LOOP;
+#endif
 
   if (PCB->PinOn && PCB->ElementOn)
     {
diff --git a/src/select.h b/src/select.h
index e24ab82..36de895 100644
--- a/src/select.h
+++ b/src/select.h
@@ -34,7 +34,7 @@
 #include "global.h"
 
 #define SELECT_TYPES	\
-	(VIA_TYPE | LINE_TYPE | TEXT_TYPE | POLYGON_TYPE | ELEMENT_TYPE |	\
+	(VIA_TYPE | LINE_TYPE | TEXT_TYPE | POUR_TYPE | ELEMENT_TYPE |	\
 	 PIN_TYPE | PAD_TYPE | ELEMENTNAME_TYPE | RATLINE_TYPE | ARC_TYPE)
 
 void SelectPin (LibraryEntryTypePtr entry, bool toggle);
diff --git a/src/set.c b/src/set.c
index 7a41f73..4f2e591 100644
--- a/src/set.c
+++ b/src/set.c
@@ -248,12 +248,12 @@ SetMode (int Mode)
   addedLines = 0;
   Crosshair.AttachedObject.Type = NO_TYPE;
   Crosshair.AttachedObject.State = STATE_FIRST;
-  Crosshair.AttachedPolygon.PointN = 0;
+  Crosshair.AttachedPour.PointN = 0;
   if (PCB->RatDraw)
     {
       if (Mode == ARC_MODE || Mode == RECTANGLE_MODE ||
-	  Mode == VIA_MODE || Mode == POLYGON_MODE ||
-	  Mode == POLYGONHOLE_MODE ||
+	  Mode == VIA_MODE || Mode == POUR_MODE ||
+	  Mode == POURHOLE_MODE ||
 	  Mode == TEXT_MODE || Mode == INSERTPOINT_MODE ||
 	  Mode == THERMAL_MODE)
 	{
diff --git a/src/strflags.c b/src/strflags.c
index ac1fdcc..26a2405 100644
--- a/src/strflags.c
+++ b/src/strflags.c
@@ -95,7 +95,7 @@ static FlagBitsType object_flagbits[] = {
   { HOLEFLAG, N ("hole"), PIN_TYPES },
   { RATFLAG, N ("rat"), RATLINE_TYPE },
   { PININPOLYFLAG, N ("pininpoly"), PIN_TYPES | PAD_TYPE },
-  { CLEARPOLYFLAG, N ("clearpoly"), POLYGON_TYPE },
+  { CLEARPOLYFLAG, N ("clearpoly"), POUR_TYPE },
   { HIDENAMEFLAG, N ("hidename"), ELEMENT_TYPE },
   { DISPLAYNAMEFLAG, N ("showname"), ELEMENT_TYPE },
   { CLEARLINEFLAG, N ("clearline"), LINE_TYPE | ARC_TYPE | TEXT_TYPE },
@@ -110,7 +110,7 @@ static FlagBitsType object_flagbits[] = {
   { DRCFLAG, N ("drc"), ALL_TYPES },
   { LOCKFLAG, N ("lock"), ALL_TYPES },
   { EDGE2FLAG, N ("edge2"), ALL_TYPES },
-  { FULLPOLYFLAG, N ("fullpoly"), POLYGON_TYPE},
+  { FULLPOLYFLAG, N ("fullpoly"), POUR_TYPE},
   { NOPASTEFLAG, N ("nopaste"), PAD_TYPE }
 };
 
diff --git a/src/undo.c b/src/undo.c
index 68ea8ff..2dacee3 100644
--- a/src/undo.c
+++ b/src/undo.c
@@ -62,6 +62,7 @@
 #include "move.h"
 #include "mymem.h"
 #include "polygon.h"
+#include "pour.h"
 #include "remove.h"
 #include "rotate.h"
 #include "rtree.h"
@@ -127,7 +128,7 @@ typedef struct			/* information about poly clear/restore */
   bool Clear;		/* true was clear, false was restore */
   LayerTypePtr Layer;
 }
-ClearPolyType, *ClearPolyTypePtr;
+ClearPourType, *ClearPourTypePtr;
 
 typedef struct			/* information about netlist lib changes */
 {
@@ -152,7 +153,7 @@ typedef struct			/* holds information about an operation */
     FlagType Flags;
     BDimension Size;
     LayerChangeType LayerChange;
-    ClearPolyType ClearPoly;
+    ClearPourType ClearPour;
     NetlistChangeType NetlistChange;
     long int CopyID;
   }
@@ -196,7 +197,7 @@ static bool UndoChange2ndSize (UndoListTypePtr);
 static bool UndoChangeAngles (UndoListTypePtr);
 static bool UndoChangeClearSize (UndoListTypePtr);
 static bool UndoChangeMaskSize (UndoListTypePtr);
-static bool UndoClearPoly (UndoListTypePtr);
+static bool UndoClearPour (UndoListTypePtr);
 static int PerformUndo (UndoListTypePtr);
 
 /* ---------------------------------------------------------------------------
@@ -272,7 +273,7 @@ GetUndoSlot (int CommandType, int ID, int Kind)
 static void
 DrawRecoveredObject (int Type, void *Ptr1, void *Ptr2, void *Ptr3)
 {
-  if (Type & (LINE_TYPE | TEXT_TYPE | POLYGON_TYPE | ARC_TYPE))
+  if (Type & (LINE_TYPE | TEXT_TYPE | POLYGON_TYPE | POUR_TYPE | ARC_TYPE))
     {
       LayerTypePtr layer;
 
@@ -314,7 +315,7 @@ UndoRotate (UndoListTypePtr Entry)
  * returns true if anything has been recovered
  */
 static bool
-UndoClearPoly (UndoListTypePtr Entry)
+UndoClearPour (UndoListTypePtr Entry)
 {
   void *ptr1, *ptr2, *ptr3;
   int type;
@@ -323,11 +324,11 @@ UndoClearPoly (UndoListTypePtr Entry)
     SearchObjectByID (PCB->Data, &ptr1, &ptr2, &ptr3, Entry->ID, Entry->Kind);
   if (type != NO_TYPE)
     {
-      if (Entry->Data.ClearPoly.Clear)
-	RestoreToPolygon (PCB->Data, type, Entry->Data.ClearPoly.Layer, ptr3);
+      if (Entry->Data.ClearPour.Clear)
+	RestoreToPours (PCB->Data, type, Entry->Data.ClearPour.Layer, ptr3);
       else
-	ClearFromPolygon (PCB->Data, type, Entry->Data.ClearPoly.Layer, ptr3);
-      Entry->Data.ClearPoly.Clear = !Entry->Data.ClearPoly.Clear;
+	ClearFromPours (PCB->Data, type, Entry->Data.ClearPour.Layer, ptr3);
+      Entry->Data.ClearPour.Clear = !Entry->Data.ClearPour.Clear;
       return true;
     }
   return false;
@@ -440,11 +441,11 @@ UndoChangeClearSize (UndoListTypePtr Entry)
       if (TEST_FLAG (LOCKFLAG, (LineTypePtr) ptr2))
 	return (false);
       swap = ((PinTypePtr) ptr2)->Clearance;
-      RestoreToPolygon (PCB->Data, type, ptr1, ptr2);
+      RestoreToPours (PCB->Data, type, ptr1, ptr2);
       if (andDraw)
 	EraseObject (type, ptr1, ptr2);
       ((PinTypePtr) ptr2)->Clearance = Entry->Data.Size;
-      ClearFromPolygon (PCB->Data, type, ptr1, ptr2);
+      ClearFromPours (PCB->Data, type, ptr1, ptr2);
       Entry->Data.Size = swap;
       if (andDraw)
 	DrawObject (type, ptr1, ptr2, 0);
@@ -508,12 +509,12 @@ UndoChangeSize (UndoListTypePtr Entry)
       /* Wow! can any object be treated as a pin type for size change?? */
       /* pins, vias, lines, and arcs can. Text can't but it has it's own mechanism */
       swap = ((PinTypePtr) ptr2)->Thickness;
-      RestoreToPolygon (PCB->Data, type, ptr1, ptr2);
+      RestoreToPours (PCB->Data, type, ptr1, ptr2);
       if (andDraw)
 	EraseObject (type, ptr1, ptr2);
       ((PinTypePtr) ptr2)->Thickness = Entry->Data.Size;
       Entry->Data.Size = swap;
-      ClearFromPolygon (PCB->Data, type, ptr1, ptr2);
+      ClearFromPours (PCB->Data, type, ptr1, ptr2);
       if (andDraw)
 	DrawObject (type, ptr1, ptr2, 0);
       return (true);
@@ -714,37 +715,37 @@ static bool
 UndoRemovePoint (UndoListTypePtr Entry)
 {
   LayerTypePtr layer;
-  PolygonTypePtr polygon;
+  PourTypePtr pour;
   void *ptr3;
   int type;
 
   /* lookup entry (polygon not point was saved) by it's ID */
-  assert (Entry->Kind == POLYGON_TYPE);
+  assert (Entry->Kind == POUR_TYPE);
   type =
-    SearchObjectByID (PCB->Data, (void *) &layer, (void *) &polygon, &ptr3,
+    SearchObjectByID (PCB->Data, (void *) &layer, (void *) &pour, &ptr3,
 		      Entry->ID, Entry->Kind);
   switch (type)
     {
-    case POLYGON_TYPE:		/* restore the removed point */
+    case POUR_TYPE:		/* restore the removed point */
       {
-	if (TEST_FLAG (LOCKFLAG, polygon))
+	if (TEST_FLAG (LOCKFLAG, pour))
 	  return (false);
 	/* recover the point */
 	if (andDraw && layer->On)
-	  ErasePolygon (polygon);
-	InsertPointIntoObject (POLYGON_TYPE, layer, polygon,
+	  ErasePour (pour);
+	InsertPointIntoObject (POUR_TYPE, layer, pour,
 			       &Entry->Data.RemovedPoint.Index,
 			       Entry->Data.RemovedPoint.X,
 			       Entry->Data.RemovedPoint.Y, true,
 			       Entry->Data.RemovedPoint.last_in_contour);
 
-	polygon->Points[Entry->Data.RemovedPoint.Index].ID =
+	pour->Points[Entry->Data.RemovedPoint.Index].ID =
 	  Entry->Data.RemovedPoint.ID;
 	if (andDraw && layer->On)
-	  DrawPolygon (layer, polygon, 0);
+	  DrawPour (layer, pour, 0);
 	Entry->Type = UNDO_INSERT_POINT;
 	Entry->ID = Entry->Data.RemovedPoint.ID;
-	Entry->Kind = POLYGONPOINT_TYPE;
+	Entry->Kind = POURPOINT_TYPE;
 	return (true);
       }
 
@@ -754,56 +755,56 @@ UndoRemovePoint (UndoListTypePtr Entry)
 }
 
 /* ---------------------------------------------------------------------------
- * recovers an inserted polygon point
+ * recovers an inserted pour point
  * returns true on success
  */
 static bool
 UndoInsertPoint (UndoListTypePtr Entry)
 {
   LayerTypePtr layer;
-  PolygonTypePtr polygon;
+  PourTypePtr pour;
   PointTypePtr pnt;
   int type;
   Cardinal point_idx;
   Cardinal hole;
   bool last_in_contour = false;
 
-  assert (Entry->Kind == POLYGONPOINT_TYPE);
+  assert (Entry->Kind == POURPOINT_TYPE);
   /* lookup entry by it's ID */
   type =
-    SearchObjectByID (PCB->Data, (void *) &layer, (void *) &polygon,
+    SearchObjectByID (PCB->Data, (void *) &layer, (void *) &pour,
 		      (void *) &pnt, Entry->ID, Entry->Kind);
   switch (type)
     {
-    case POLYGONPOINT_TYPE:	/* removes an inserted polygon point */
+    case POURPOINT_TYPE:	/* removes an inserted pour point */
       {
-	if (TEST_FLAG (LOCKFLAG, polygon))
+	if (TEST_FLAG (LOCKFLAG, pour))
 	  return (false);
 	if (andDraw && layer->On)
-	  ErasePolygon (polygon);
+	  ErasePour (pour);
 
 	/* Check whether this point was at the end of its contour.
 	 * If so, we need to flag as such when re-adding the point
 	 * so it goes back in the correct place
 	 */
-	point_idx = polygon_point_idx (polygon, pnt);
-	for (hole = 0; hole < polygon->HoleIndexN; hole++)
-	  if (point_idx == polygon->HoleIndex[hole] - 1)
+	point_idx = pour_point_idx (pour, pnt);
+	for (hole = 0; hole < pour->HoleIndexN; hole++)
+	  if (point_idx == pour->HoleIndex[hole] - 1)
 	    last_in_contour = true;
-	if (point_idx == polygon->PointN - 1)
+	if (point_idx == pour->PointN - 1)
 	  last_in_contour = true;
 	Entry->Data.RemovedPoint.last_in_contour = last_in_contour;
 
 	Entry->Data.RemovedPoint.X = pnt->X;
 	Entry->Data.RemovedPoint.Y = pnt->Y;
 	Entry->Data.RemovedPoint.ID = pnt->ID;
-	Entry->ID = polygon->ID;
-	Entry->Kind = POLYGON_TYPE;
+	Entry->ID = pour->ID;
+	Entry->Kind = POUR_TYPE;
 	Entry->Type = UNDO_REMOVE_POINT;
 	Entry->Data.RemovedPoint.Index = point_idx;
-	DestroyObject (PCB->Data, POLYGONPOINT_TYPE, layer, polygon, pnt);
+	DestroyObject (PCB->Data, POURPOINT_TYPE, layer, pour, pnt);
 	if (andDraw && layer->On)
-	  DrawPolygon (layer, polygon, 0);
+	  DrawPour (layer, pour, 0);
 	return (true);
       }
 
@@ -847,8 +848,8 @@ UndoSwapCopiedObject (UndoListTypePtr Entry)
     DrawRecoveredObject (Entry->Kind, ptr1, ptr2, ptr3);
 
   obj = MoveObjectToBuffer (PCB->Data, RemoveList, type, ptr1, ptr2, ptr3);
-  if (Entry->Kind == POLYGON_TYPE)
-    InitClip (PCB->Data, ptr1b, (PolygonType *)obj);
+  if (Entry->Kind == POUR_TYPE)
+    InitPourClip (PCB->Data, ptr1b, (PourType *)obj);
   return (true);
 }
 
@@ -859,7 +860,7 @@ UndoSwapCopiedObject (UndoListTypePtr Entry)
 static bool
 UndoRemoveContour (UndoListTypePtr Entry)
 {
-  assert (Entry->Kind == POLYGON_TYPE);
+  assert (Entry->Kind == POUR_TYPE);
   return UndoSwapCopiedObject (Entry);
 }
 
@@ -870,7 +871,7 @@ UndoRemoveContour (UndoListTypePtr Entry)
 static bool
 UndoInsertContour (UndoListTypePtr Entry)
 {
-  assert (Entry->Kind == POLYGON_TYPE);
+  assert (Entry->Kind == POUR_TYPE);
   return UndoSwapCopiedObject (Entry);
 }
 
@@ -1061,7 +1062,7 @@ PerformUndo (UndoListTypePtr ptr)
       break;
 
     case UNDO_CLEAR:
-      if (UndoClearPoly (ptr))
+      if (UndoClearPour (ptr))
 	return (UNDO_CLEAR);
       break;
 
@@ -1233,7 +1234,7 @@ ClearUndoList (bool Force)
  * adds an object to the list of clearpoly objects
  */
 void
-AddObjectToClearPolyUndoList (int Type, void *Ptr1, void *Ptr2, void *Ptr3,
+AddObjectToClearPourUndoList (int Type, void *Ptr1, void *Ptr2, void *Ptr3,
 			      bool clear)
 {
   UndoListTypePtr undo;
@@ -1241,8 +1242,8 @@ AddObjectToClearPolyUndoList (int Type, void *Ptr1, void *Ptr2, void *Ptr3,
   if (!Locked)
     {
       undo = GetUndoSlot (UNDO_CLEAR, OBJECT_ID (Ptr3), Type);
-      undo->Data.ClearPoly.Clear = clear;
-      undo->Data.ClearPoly.Layer = (LayerTypePtr) Ptr1;
+      undo->Data.ClearPour.Clear = clear;
+      undo->Data.ClearPour.Layer = (LayerTypePtr) Ptr1;
     }
 }
 
@@ -1308,7 +1309,7 @@ AddObjectToRemovePointUndoList (int Type,
 				void *Ptr1, void *Ptr2, Cardinal index)
 {
   UndoListTypePtr undo;
-  PolygonTypePtr polygon = (PolygonTypePtr) Ptr2;
+  PourTypePtr pour = (PourTypePtr) Ptr2;
   Cardinal hole;
   bool last_in_contour = false;
 
@@ -1316,27 +1317,27 @@ AddObjectToRemovePointUndoList (int Type,
     {
       switch (Type)
 	{
-	case POLYGONPOINT_TYPE:
+	case POURPOINT_TYPE:
 	  {
 	    /* save the ID of the parent object; else it will be
 	     * impossible to recover the point
 	     */
 	    undo =
-	      GetUndoSlot (UNDO_REMOVE_POINT, OBJECT_ID (polygon),
-			   POLYGON_TYPE);
-	    undo->Data.RemovedPoint.X = polygon->Points[index].X;
-	    undo->Data.RemovedPoint.Y = polygon->Points[index].Y;
-	    undo->Data.RemovedPoint.ID = polygon->Points[index].ID;
+	      GetUndoSlot (UNDO_REMOVE_POINT, OBJECT_ID (pour),
+			   POUR_TYPE);
+	    undo->Data.RemovedPoint.X = pour->Points[index].X;
+	    undo->Data.RemovedPoint.Y = pour->Points[index].Y;
+	    undo->Data.RemovedPoint.ID = pour->Points[index].ID;
 	    undo->Data.RemovedPoint.Index = index;
 
 	    /* Check whether this point was at the end of its contour.
 	     * If so, we need to flag as such when re-adding the point
 	     * so it goes back in the correct place
 	     */
-	    for (hole = 0; hole < polygon->HoleIndexN; hole++)
-	      if (index == polygon->HoleIndex[hole] - 1)
+	    for (hole = 0; hole < pour->HoleIndexN; hole++)
+	      if (index == pour->HoleIndex[hole] - 1)
 		last_in_contour = true;
-	    if (index == polygon->PointN - 1)
+	    if (index == pour->PointN - 1)
 	      last_in_contour = true;
 	    undo->Data.RemovedPoint.last_in_contour = last_in_contour;
 	  }
@@ -1380,9 +1381,9 @@ CopyObjectToUndoList (int undo_type, int Type, void *Ptr1, void *Ptr2, void *Ptr
  */
 void
 AddObjectToRemoveContourUndoList (int Type,
-				  LayerType *Layer, PolygonType *Polygon)
+				  LayerType *Layer, PourType *Pour)
 {
-  CopyObjectToUndoList (UNDO_REMOVE_CONTOUR, Type, Layer, Polygon, NULL);
+  CopyObjectToUndoList (UNDO_REMOVE_CONTOUR, Type, Layer, Pour, NULL);
 }
 
 /* ---------------------------------------------------------------------------
@@ -1455,7 +1456,7 @@ AddObjectToCreateUndoList (int Type, void *Ptr1, void *Ptr2, void *Ptr3)
 
   if (!Locked)
     undo = GetUndoSlot (UNDO_CREATE, OBJECT_ID (Ptr3), Type);
-  ClearFromPolygon (PCB->Data, Type, Ptr1, Ptr2);
+  ClearFromPours (PCB->Data, Type, Ptr1, Ptr2);
 }
 
 /* ---------------------------------------------------------------------------
diff --git a/src/undo.h b/src/undo.h
index 0a4601f..b3c04d0 100644
--- a/src/undo.h
+++ b/src/undo.h
@@ -47,7 +47,7 @@ void ClearUndoList (bool);
 void MoveObjectToRemoveUndoList (int, void *, void *, void *);
 void AddObjectToRemovePointUndoList (int, void *, void *, Cardinal);
 void AddObjectToInsertPointUndoList (int, void *, void *, void *);
-void AddObjectToRemoveContourUndoList (int, LayerType *, PolygonType *);
+void AddObjectToRemoveContourUndoList (int, LayerType *, PourType *);
 void AddObjectToInsertContourUndoList (int, LayerType *, PolygonType *);
 void AddObjectToMoveUndoList (int, void *, void *, void *,
 			      LocationType, LocationType);
@@ -63,7 +63,7 @@ void AddObjectTo2ndSizeUndoList (int, void *, void *, void *);
 void AddObjectToClearSizeUndoList (int, void *, void *, void *);
 void AddObjectToMaskSizeUndoList (int, void *, void *, void *);
 void AddObjectToChangeAnglesUndoList (int, void *, void *, void *);
-void AddObjectToClearPolyUndoList (int, void *, void *, void *, bool);
+void AddObjectToClearPourUndoList (int, void *, void *, void *, bool);
 void AddLayerChangeToUndoList (int, int);
 void AddNetlistLibToUndoList (LibraryTypePtr);
 void LockUndo (void);

commit 4aed6d529217fcde9078026f100237b39249f390
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    Workaround crash where contour is passed as NULL to poly_PreContour

diff --git a/src/polygon.c b/src/polygon.c
index 1a3d319..15b3534 100644
--- a/src/polygon.c
+++ b/src/polygon.c
@@ -308,6 +308,16 @@ original_poly (PolygonType * p)
       if (n == p->PointN - 1 ||
           (hole < p->HoleIndexN && n == p->HoleIndex[hole] - 1))
         {
+          if (contour == NULL)
+            {
+              printf ("How did that escape - did the loop iterate zero times??\n");
+              POLYGONPOINT_LOOP (p);
+                {
+                  printf ("Hello\n");
+                }
+              END_LOOP;
+              return NULL;
+            }
           poly_PreContour (contour, TRUE);
 
           /* make sure it is a positive contour (outer) or negative (hole) */

commit 193adfc2ca0d6365d4fa881c3870b88a1509d98b
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    Fix mesa crash on startup
    
    I'm not sure why it crashed, but it seems that providing a realize
    handler which fiddles with the GL context solves it. I've also
    removed a number of superfluous gtk_widget_realize() and an un-warraned
    gtk_widget_show_all()

diff --git a/src/hid/gtk/gui-top-window.c b/src/hid/gtk/gui-top-window.c
index a3898cb..26f29b4 100644
--- a/src/hid/gtk/gui-top-window.c
+++ b/src/hid/gtk/gui-top-window.c
@@ -2145,7 +2145,21 @@ destroy_chart_cb (GtkWidget * widget, GHidPort * port)
   gtk_main_quit ();
 }
 
+static void
+ghid_port_drawing_realize_cb (GtkWidget *widget, gpointer data)
+{
+  GdkGLContext *glcontext = gtk_widget_get_gl_context (widget);
+  GdkGLDrawable *gldrawable = gtk_widget_get_gl_drawable (widget);
+
+  /*** OpenGL BEGIN ***/
+  if (!gdk_gl_drawable_gl_begin (gldrawable, glcontext))
+    return;
 
+  gdk_gl_drawable_gl_end (gldrawable);
+  /*** OpenGL END ***/
+
+  return;
+}
 
 /* 
  * Create the top_window contents.  The config settings should be loaded
@@ -2368,6 +2382,9 @@ ghid_build_pcb_top_window (void)
      |  the user does a command entry.
    */
 
+  g_signal_connect (G_OBJECT (gport->drawing_area), "realize",
+		    G_CALLBACK (ghid_port_drawing_realize_cb),
+		    port);
   g_signal_connect (G_OBJECT (gport->drawing_area), "expose_event",
 		    G_CALLBACK (ghid_port_drawing_area_expose_event_cb),
 		    port);
@@ -2403,10 +2420,6 @@ ghid_build_pcb_top_window (void)
   ghidgui->creating = FALSE;
 
   gtk_widget_show_all (gport->top_window);
-  gtk_widget_realize (vbox_main);
-  gtk_widget_realize (hbox_middle);
-  gtk_widget_realize (viewport);
-  gtk_widget_realize (gport->drawing_area);
   gdk_window_set_back_pixmap (gport->drawing_area->window, NULL, FALSE);
 
   ghid_route_style_temp_buttons_hide ();
@@ -2734,8 +2747,6 @@ ghid_parse_arguments (int *argc, char ***argv)
   if (Settings.AutoPlace)
     gtk_widget_set_uposition (GTK_WIDGET (window), 10, 10);
 
-  gtk_widget_realize (gport->top_window);
-  gtk_widget_show_all (gport->top_window);
   ghidgui->creating = TRUE;
 }
 

commit 2d553c21045125dafb33137ae21adf4d5efc9314
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    Don't make GUI drawing calls to erase objects
    
    Changing the colour here is unnecessary (as drawing is deferred).
    Delete the gui->set_color() calls, and additionally, comment out
    all real-time drawing frmo the autorouter. This hasn't been ported
    to be compatible with the GL code, which requires specific setup
    and teardown around drawing.

diff --git a/src/autoroute.c b/src/autoroute.c
index 7fb7443..3361f79 100644
--- a/src/autoroute.c
+++ b/src/autoroute.c
@@ -1421,9 +1421,11 @@ bloat_routebox (routebox_t * rb)
 void
 fillbox (const BoxType * b)
 {
+#if 0
   LayerTypePtr SLayer = LAYER_PTR (0);
   gui->set_color (Output.fgGC, SLayer->Color);
   gui->fill_rect (Output.fgGC, b->X1, b->Y1, b->X2, b->Y2);
+#endif
 }
 
 /* makes a line on the solder layer silk surrounding the box */
@@ -1437,7 +1439,7 @@ showbox (BoxType b, Dimension thickness, int group)
   if (showboxen != -1 && showboxen != group)
     return;
 
-
+#if 0
   gui->set_line_width (Output.fgGC, thickness);
   gui->set_line_cap (Output.fgGC, Trace_Cap);
   gui->set_color (Output.fgGC, SLayer->Color);
@@ -1447,6 +1449,7 @@ showbox (BoxType b, Dimension thickness, int group)
   gui->draw_line (Output.fgGC, b.X1, b.Y1, b.X1, b.Y2);
   gui->draw_line (Output.fgGC, b.X2, b.Y1, b.X2, b.Y2);
   gui->use_mask (HID_FLUSH_DRAW_Q);
+#endif
 
 #if 1
   if (b.Y1 == b.Y2 || b.X1 == b.X2)
@@ -1491,6 +1494,7 @@ showedge (edge_t * e)
 {
   BoxType *b = (BoxType *) e->rb;
 
+#if 0
   gui->set_line_cap (Output.fgGC, Trace_Cap);
   gui->set_line_width (Output.fgGC, 1);
   gui->set_color (Output.fgGC, Settings.MaskColor);
@@ -1512,6 +1516,7 @@ showedge (edge_t * e)
     default:
       break;
     }
+#endif
 }
 #endif
 
@@ -1545,9 +1550,11 @@ EraseRouteBox (routebox_t * rb)
       X2 = rb->box.X2 - thick / 2;
     }
 
+#if 0
   gui->set_line_width (ar_gc, thick);
   gui->set_color (ar_gc, Settings.BackgroundColor);
   gui->draw_line (ar_gc, X1, Y1, X2, Y2);
+#endif
 }
 
 /* return a "parent" of this edge which immediately precedes it in the route.*/
@@ -3235,11 +3242,13 @@ RD_DrawVia (routedata_t * rd, LocationType X, LocationType Y,
       r_insert_entry (rd->layergrouptree[rb->group], &rb->box, 1);
       rb->flags.homeless = 0;	/* not homeless anymore */
 
+#if 0
       if (TEST_FLAG (LIVEROUTEFLAG, PCB))
 	{
 	  gui->set_color (ar_gc, PCB->ViaColor);
 	  gui->fill_circle (ar_gc, X, Y, radius);
 	}
+#endif
     }
 }
 static void
@@ -3327,6 +3336,7 @@ RD_DrawLine (routedata_t * rd,
   /* and add it to the r-tree! */
   r_insert_entry (rd->layergrouptree[rb->group], &rb->box, 1);
 
+#if 0
   if (TEST_FLAG (LIVEROUTEFLAG, PCB))
     {
       LayerTypePtr layp = LAYER_PTR (PCB->LayerGroups.Entries[rb->group][0]);
@@ -3335,6 +3345,7 @@ RD_DrawLine (routedata_t * rd,
       gui->set_color (ar_gc, layp->Color);
       gui->draw_line (ar_gc, qX1, qY1, qX2, qY2);
     }
+#endif
 
   /* and to the via space structures */
   if (AutoRouteParameters.use_vias)
@@ -3650,8 +3661,10 @@ TracePath (routedata_t * rd, routebox_t * path, const routebox_t * target,
   while (!path->flags.source);
   /* flush the line queue */
   RD_DrawLine (rd, -1, 0, 0, 0, 0, 0, NULL, false, false);
+#if 0
   if (TEST_FLAG (LIVEROUTEFLAG, PCB))
     gui->use_mask (HID_FLUSH_DRAW_Q);
+#endif
 }
 
 /* create a fake "edge" used to defer via site searching. */
@@ -3950,8 +3963,8 @@ __show_tree (const BoxType * b, void *cl)
 static void
 show_tree (rtree_t * tree, int even_odd)
 {
-  r_search (tree, NULL, NULL, __show_tree, (void *) even_odd);
-  gui->use_mask (HID_FLUSH_DRAW_Q);
+//  r_search (tree, NULL, NULL, __show_tree, (void *) even_odd);
+//  gui->use_mask (HID_FLUSH_DRAW_Q);
 }
 
 #endif
@@ -4730,8 +4743,8 @@ RouteAll (routedata_t * rd)
 		    }
 		}
 	      END_LOOP;
-	      if (TEST_FLAG (LIVEROUTEFLAG, PCB))
-		gui->use_mask (HID_FLUSH_DRAW_Q);
+//	      if (TEST_FLAG (LIVEROUTEFLAG, PCB))
+//		gui->use_mask (HID_FLUSH_DRAW_Q);
 	      /* reset to original connectivity */
 	      if (rip)
 		{
@@ -5089,16 +5102,20 @@ AutoRoute (bool selected)
 
   total_wire_length = 0;
   total_via_count = 0;
+#if 0
   if (TEST_FLAG (LIVEROUTEFLAG, PCB))
     {
       gui->use_mask (HID_LIVE_DRAWING);
     }
+#endif
 
+#if 0
   if (ar_gc == 0)
     {
       ar_gc = gui->make_gc ();
       gui->set_line_cap (ar_gc, Round_Cap);
     }
+#endif
 
   for (i = 0; i < NUM_STYLES; i++)
     {
@@ -5258,10 +5275,12 @@ donerouting:
   Message ("Total added wire length = %f inches, %d vias added\n",
 	   total_wire_length / 1.e5, total_via_count);
   DestroyRouteData (&rd);
+#if 0
   if (TEST_FLAG (LIVEROUTEFLAG, PCB))
     {
       gui->use_mask (HID_LIVE_DRAWING_OFF);
     }
+#endif
   if (changed)
     {
       SaveUndoSerialNumber ();
diff --git a/src/draw.c b/src/draw.c
index 602b499..a27c0dc 100644
--- a/src/draw.c
+++ b/src/draw.c
@@ -2126,7 +2126,6 @@ void
 EraseVia (PinTypePtr Via)
 {
   Erasing++;
-  gui->set_color (Output.fgGC, Settings.BackgroundColor);
   DrawPinOrViaLowLevel (Via, false);
   if (TEST_FLAG (DISPLAYNAMEFLAG, Via))
     DrawPinOrViaNameLowLevel (Via);
@@ -2140,7 +2139,6 @@ void
 EraseRat (RatTypePtr Rat)
 {
   Erasing++;
-  gui->set_color (Output.fgGC, Settings.BackgroundColor);
   if (TEST_FLAG(VIAFLAG, Rat))
     {
       int w = Rat->Thickness;
@@ -2165,7 +2163,6 @@ void
 EraseViaName (PinTypePtr Via)
 {
   Erasing++;
-  gui->set_color (Output.fgGC, Settings.BackgroundColor);
   DrawPinOrViaNameLowLevel (Via);
   Erasing--;
 }
@@ -2177,7 +2174,6 @@ void
 ErasePad (PadTypePtr Pad)
 {
   Erasing++;
-  gui->set_color (Output.fgGC, Settings.BackgroundColor);
   DrawPadLowLevel (Output.fgGC, Pad, false, false);
   if (TEST_FLAG (DISPLAYNAMEFLAG, Pad))
     DrawPadNameLowLevel (Pad);
@@ -2191,7 +2187,6 @@ void
 ErasePadName (PadTypePtr Pad)
 {
   Erasing++;
-  gui->set_color (Output.fgGC, Settings.BackgroundColor);
   DrawPadNameLowLevel (Pad);
   Erasing--;
 }
@@ -2203,7 +2198,6 @@ void
 ErasePin (PinTypePtr Pin)
 {
   Erasing++;
-  gui->set_color (Output.fgGC, Settings.BackgroundColor);
   DrawPinOrViaLowLevel (Pin, false);
   if (TEST_FLAG (DISPLAYNAMEFLAG, Pin))
     DrawPinOrViaNameLowLevel (Pin);
@@ -2217,7 +2211,6 @@ void
 ErasePinName (PinTypePtr Pin)
 {
   Erasing++;
-  gui->set_color (Output.fgGC, Settings.BackgroundColor);
   DrawPinOrViaNameLowLevel (Pin);
   Erasing--;
 }
@@ -2229,7 +2222,6 @@ void
 EraseLine (LineTypePtr Line)
 {
   Erasing++;
-  gui->set_color (Output.fgGC, Settings.BackgroundColor);
   DrawLineLowLevel (Line, false);
   Erasing--;
 }
@@ -2243,7 +2235,6 @@ EraseArc (ArcTypePtr Arc)
   if (!Arc->Thickness)
     return;
   Erasing++;
-  gui->set_color (Output.fgGC, Settings.BackgroundColor);
   DrawArcLowLevel (Arc);
   Erasing--;
 }
@@ -2256,7 +2247,6 @@ EraseText (LayerTypePtr Layer, TextTypePtr Text)
 {
   int min_silk_line;
   Erasing++;
-  gui->set_color (Output.fgGC, Settings.BackgroundColor);
   if (Layer == & PCB->Data->SILKLAYER
       || Layer == & PCB->Data->BACKSILKLAYER)
     min_silk_line = PCB->minSlk;
@@ -2273,7 +2263,6 @@ void
 ErasePolygon (PolygonTypePtr Polygon)
 {
   Erasing++;
-  gui->set_color (Output.fgGC, Settings.BackgroundColor);
   DrawPolygonLowLevel (Polygon);
   Erasing--;
 }
@@ -2285,8 +2274,6 @@ void
 EraseElement (ElementTypePtr Element)
 {
   Erasing++;
-  /* set color and draw lines, arcs, text and pins */
-  gui->set_color (Output.fgGC, Settings.BackgroundColor);
   ELEMENTLINE_LOOP (Element);
   {
     DrawLineLowLevel (line, false);
@@ -2310,7 +2297,6 @@ void
 EraseElementPinsAndPads (ElementTypePtr Element)
 {
   Erasing++;
-  gui->set_color (Output.fgGC, Settings.BackgroundColor);
   PIN_LOOP (Element);
   {
     DrawPinOrViaLowLevel (pin, false);
@@ -2337,7 +2323,6 @@ EraseElementName (ElementTypePtr Element)
   if (TEST_FLAG (HIDENAMEFLAG, Element))
     return;
   Erasing++;
-  gui->set_color (Output.fgGC, Settings.BackgroundColor);
   DrawTextLowLevel (&ELEMENT_TEXT (PCB, Element), PCB->minSlk);
   Erasing--;
 }

commit 8b162eca5ba77e4b9f06436a9fa7f9311532a61d
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    Debug GL calls out of context

diff --git a/src/hid/gtk/gui-output-events.c b/src/hid/gtk/gui-output-events.c
index 322e37d..37c2e48 100644
--- a/src/hid/gtk/gui-output-events.c
+++ b/src/hid/gtk/gui-output-events.c
@@ -73,6 +73,7 @@ static GLfloat last_modelview_matrix[4][4] = {{1.0, 0.0, 0.0, 0.0},
                                               {0.0, 0.0, 0.0, 1.0}};
 static int global_view_2d = 1;
 
+static bool check_gl_drawing_ok_hack = false;
 
 /* Set to true if cursor is currently in viewport. This is a hack to prevent
  * Crosshair stack corruption due to unmatching window enter / leave events */
@@ -596,6 +597,9 @@ ghid_show_crosshair (gboolean show)
   static GdkColor cross_color;
   extern float global_depth;
 
+  if (!check_gl_drawing_ok_hack)
+    return;
+
   if (gport->x_crosshair < 0 || ghidgui->creating) {// || !gport->has_entered) {
     printf ("Returning\n");
     return;
@@ -1732,6 +1736,8 @@ ghid_port_drawing_area_expose_event_cb (GtkWidget * widget,
 
   hidgl_init ();
 
+  check_gl_drawing_ok_hack = true;
+
   /* If we don't have any stencil bits available,
      we can't use the hidgl polygon drawing routine */
   /* TODO: We could use the GLU tessellator though */
@@ -1954,6 +1960,8 @@ ghid_port_drawing_area_expose_event_cb (GtkWidget * widget,
   else
     glFlush ();
 
+  check_gl_drawing_ok_hack = false;
+
   /* end drawing to current GL-context */
   gdk_gl_drawable_gl_end (pGlDrawable);
 

commit 2e09009091271e4efa7a3496a637e79427d714ac
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    Allow zero clearance pads and pins to touch polygons
    
    This was already supported for vias, lets be consistent.

diff --git a/src/change.c b/src/change.c
index 5546f1f..0c55c69 100644
--- a/src/change.c
+++ b/src/change.c
@@ -532,7 +532,13 @@ ChangePinClearSize (ElementTypePtr Element, PinTypePtr Pin)
 
   if (TEST_FLAG (LOCKFLAG, Pin))
     return (NULL);
-  value = MIN (MAX_LINESIZE, MAX (value, PCB->Bloat * 2 + 2));
+  value = MIN (MAX_LINESIZE, value);
+  if (value < 0)
+    value = 0;
+  if (Delta < 0 && value < PCB->Bloat * 2)
+    value = 0;
+  if ((Delta > 0 || Absolute) && value < PCB->Bloat * 2)
+    value = PCB->Bloat * 2 + 2;
   if (Pin->Clearance == value)
     return NULL;
   RestoreToPolygon (PCB->Data, PIN_TYPE, Element, Pin);
@@ -587,21 +593,25 @@ ChangePadClearSize (ElementTypePtr Element, PadTypePtr Pad)
 
   if (TEST_FLAG (LOCKFLAG, Pad))
     return (NULL);
-  value = MIN (MAX_LINESIZE, MAX (value, PCB->Bloat * 2 + 2));
-  if (value <= MAX_PADSIZE && value >= MIN_PADSIZE && value != Pad->Clearance)
-    {
-      AddObjectToClearSizeUndoList (PAD_TYPE, Element, Pad, Pad);
-      RestoreToPolygon (PCB->Data, PAD_TYPE, Element, Pad);
-      ErasePad (Pad);
-      r_delete_entry (PCB->Data->pad_tree, &Pad->BoundingBox);
-      Pad->Clearance = value;
-      /* SetElementBB updates all associated rtrees */
-      SetElementBoundingBox (PCB->Data, Element, &PCB->Font);
-      ClearFromPolygon (PCB->Data, PAD_TYPE, Element, Pad);
-      DrawPad (Pad, 0);
-      return (Pad);
-    }
-  return (NULL);
+  value = MIN (MAX_LINESIZE, value);
+  if (value < 0)
+    value = 0;
+  if (Delta < 0 && value < PCB->Bloat * 2)
+    value = 0;
+  if ((Delta > 0 || Absolute) && value < PCB->Bloat * 2)
+    value = PCB->Bloat * 2 + 2;
+  if (value == Pad->Clearance)
+    return NULL;
+  AddObjectToClearSizeUndoList (PAD_TYPE, Element, Pad, Pad);
+  RestoreToPolygon (PCB->Data, PAD_TYPE, Element, Pad);
+  ErasePad (Pad);
+  r_delete_entry (PCB->Data->pad_tree, &Pad->BoundingBox);
+  Pad->Clearance = value;
+  /* SetElementBB updates all associated rtrees */
+  SetElementBoundingBox (PCB->Data, Element, &PCB->Font);
+  ClearFromPolygon (PCB->Data, PAD_TYPE, Element, Pad);
+  DrawPad (Pad, 0);
+  return Pad;
 }
 
 /* ---------------------------------------------------------------------------
diff --git a/src/find.c b/src/find.c
index 593be70..039bdfa 100644
--- a/src/find.c
+++ b/src/find.c
@@ -3844,7 +3844,7 @@ drc_callback (DataTypePtr data, LayerTypePtr layer, PolygonTypePtr polygon,
         }
       break;
     case PAD_TYPE:
-      if (pad->Clearance < 2 * PCB->Bloat)
+      if (pad->Clearance && pad->Clearance < 2 * PCB->Bloat)
 	if (IsPadInPolygon(pad,polygon))
 	  {
 	    AddObjectToFlagUndoList (type, ptr1, ptr2, ptr2);
@@ -3854,7 +3854,7 @@ drc_callback (DataTypePtr data, LayerTypePtr layer, PolygonTypePtr polygon,
 	  }
       break;
     case PIN_TYPE:
-      if (pin->Clearance < 2 * PCB->Bloat)
+      if (pin->Clearance && pin->Clearance < 2 * PCB->Bloat)
         {
           AddObjectToFlagUndoList (type, ptr1, ptr2, ptr2);
           SET_FLAG (TheFlag, pin);

commit 911388136478f1a12eb0cd7338ce165a8c12fc88
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    Board outline polygon generation
    
    FIXME: Make this work with the GL masking polygon drawing routines, rather
           than relying on the dicer.

diff --git a/src/hid/gtk/gui-output-events.c b/src/hid/gtk/gui-output-events.c
index f6e7758..322e37d 100644
--- a/src/hid/gtk/gui-output-events.c
+++ b/src/hid/gtk/gui-output-events.c
@@ -45,6 +45,7 @@
 #include "draw.h"
 #include "error.h"
 #include "misc.h"
+#include "polygon.h"
 #include "set.h"
 #include "find.h"
 #include "search.h"
@@ -1310,6 +1311,7 @@ DrawMask (BoxType * screen)
 {
   struct pin_info info;
   int thin = TEST_FLAG(THINDRAWFLAG, PCB) || TEST_FLAG(THINDRAWPOLYFLAG, PCB);
+  PolygonType polygon;
 
   OutputType *out = &Output;
 
@@ -1338,7 +1340,17 @@ DrawMask (BoxType * screen)
   gui->use_mask (HID_MASK_AFTER);
   gui->set_color (out->fgGC, PCB->MaskColor);
   ghid_global_alpha_mult (out->fgGC, thin ? 0.35 : 1.0);
-  gui->fill_rect (out->fgGC, 0, 0, PCB->MaxWidth, PCB->MaxHeight);
+
+  polygon.Clipped = board_outline_poly ();
+  polygon.NoHoles = NULL;
+  polygon.NoHolesValid = 0;
+  SET_FLAG (FULLPOLYFLAG, &polygon);
+  common_fill_pcb_polygon (out->fgGC, &polygon, screen);
+  poly_Free (&polygon.Clipped);
+  poly_FreeContours (&polygon.NoHoles);
+  /* THE GL fill_pcb_polygon doesn't work whilst masking */
+//  gui->fill_pcb_polygon (out->fgGC, &polygon, screen);
+//  gui->fill_rect (out->fgGC, 0, 0, PCB->MaxWidth, PCB->MaxHeight);
   ghid_global_alpha_mult (out->fgGC, 1.0);
 
   gui->use_mask (HID_MASK_OFF);
diff --git a/src/polygon.c b/src/polygon.c
index eac9390..1a3d319 100644
--- a/src/polygon.c
+++ b/src/polygon.c
@@ -81,6 +81,7 @@ dicer output is used for HIDs which cannot render things with holes
 #include <math.h>
 #include <memory.h>
 #include <setjmp.h>
+#include <glib.h>
 
 #include "global.h"
 #include "box.h"
@@ -1954,3 +1955,172 @@ PolyToPolygonsOnLayer (DataType *Destination, LayerType *Layer,
 
   SetChangedFlag (true);
 }
+
+
+struct clip_outline_info {
+  POLYAREA *poly;
+};
+
+#define ROUTER_THICKNESS 1000
+//#define ROUTER_THICKNESS 10
+
+static int
+arc_outline_callback (const BoxType * b, void *cl)
+{
+  ArcTypePtr arc = (ArcTypePtr)b;
+  struct clip_outline_info *info = cl;
+  POLYAREA *np, *res;
+
+  if (!(np = ArcPoly (arc, ROUTER_THICKNESS)))
+    return 0;
+
+  poly_Boolean_free (info->poly, np, &res, PBO_SUB);
+  info->poly = res;
+
+  return 1;
+}
+
+static int
+line_outline_callback (const BoxType * b, void *cl)
+{
+  LineTypePtr line = (LineTypePtr)b;
+  struct clip_outline_info *info = cl;
+  POLYAREA *np, *res;
+
+  if (!(np = LinePoly (line, ROUTER_THICKNESS)))
+    return 0;
+
+  poly_Boolean_free (info->poly, np, &res, PBO_SUB);
+  info->poly = res;
+
+  return 1;
+}
+
+static void
+delete_piece_cb (gpointer data, gpointer userdata)
+{
+  POLYAREA *piece = data;
+  POLYAREA **res = userdata;
+
+  /* If this item was the start of the list, advance that pointer */
+  if (*res == piece)
+    *res = (*res)->f;
+
+  /* But reset it to NULL if it wraps around and hits us again */
+  if (*res == piece)
+    *res = NULL;
+
+  piece->b->f = piece->f;
+  piece->f->b = piece->b;
+  piece->f = piece->b = piece;
+
+  poly_Free (&piece);
+}
+
+POLYAREA *board_outline_poly ()
+{
+  int i;
+  int count;
+  int found_outline = 0;
+  LayerTypePtr Layer = NULL;
+  BoxType region;
+  struct clip_outline_info info;
+  POLYAREA *whole_world;
+  POLYAREA *clipped;
+  POLYAREA *piece;
+  POLYAREA *check;
+  GList *pieces_to_delete = NULL;
+
+#define BLOAT_WORLD 1000
+
+  whole_world = RectPoly (-BLOAT_WORLD, BLOAT_WORLD + PCB->MaxWidth,
+                          -BLOAT_WORLD, BLOAT_WORLD + PCB->MaxHeight);
+
+  for (i = 0; i < max_layer; i++)
+    {
+      Layer = PCB->Data->Layer + i;
+
+      if (strcasecmp (Layer->Name, "outline") == 0 ||
+          strcasecmp (Layer->Name, "route") == 0)
+        {
+          found_outline = 1;
+          break;
+        }
+    }
+
+  if (!found_outline) {
+    printf ("Didn't find outline\n");
+    return whole_world;
+  }
+
+  /* Do stuff to turn the outline layer into a polygon */
+
+  /* Ideally, we just want to look at centre-lines, but that is hard!
+   *
+   * Lets add all lines, arcs etc.. together to form a polygon comprising
+   * the bits we presume a router would remove.
+   *
+   * Then we need to subtract that from some notional "infinite" plane
+   * polygon, leaving the remaining pieces.
+   *
+   * OR.. we could just look at the holes in the resulting polygon?
+   *
+   * Given these holes, we need to know which are inside and outside.
+   *   _____________
+   *  / ___________ \
+   *  ||           ||
+   *  ||   //=\\   ||
+   *  ||   || ||   ||
+   *  ||   \\=//   ||
+   *  ||___________||
+   *  \_____________/
+   */
+
+  info.poly = whole_world;
+
+  region.X1 = 0;
+  region.Y1 = 0;
+  region.X2 = PCB->MaxWidth;
+  region.Y2 = PCB->MaxHeight;
+
+  r_search (Layer->line_tree, &region, NULL, line_outline_callback, &info);
+  r_search (Layer->arc_tree,  &region, NULL, arc_outline_callback, &info);
+
+  clipped = info.poly;
+
+  /* Now we just need to work out which pieces of polygon are inside
+     and outside the board! */
+
+  /* If there is only one piece, return that */
+  if (clipped->f == clipped)
+    return clipped;
+
+  /* WARNING: This next check is O(n^2), where n is the number of clipped
+   *          pieces, hopefully the outline layer isn't too complex!
+   */
+
+  piece = clipped;
+  do { /* LOOP OVER POLYGON PIECES */
+
+    if (piece->contours == NULL)
+      printf ("WTF?\n");
+
+    count = 0;
+    check = clipped;
+    do { /* LOOP OVER POLYGON PIECES */
+      if (check == piece)
+        continue;
+      if (poly_ContourInContour (check->contours, piece->contours))
+        count ++;
+    } while ((check = check->f) != clipped);
+
+    /* If the piece is inside an odd number of others, delete it */
+    if ((count & 1) == 0)
+      pieces_to_delete = g_list_prepend (pieces_to_delete, piece);
+
+  } while ((piece = piece->f) != clipped);
+
+  g_list_foreach (pieces_to_delete, delete_piece_cb, &clipped);
+
+  return clipped;
+}
diff --git a/src/polygon.h b/src/polygon.h
index e29f67f..5b3baf6 100644
--- a/src/polygon.h
+++ b/src/polygon.h
@@ -72,4 +72,5 @@ bool MorphPolygon (LayerTypePtr, PolygonTypePtr);
 void NoHolesPolygonDicer (PolygonType *p, const BoxType *clip,
                           void (*emit) (PLINE *, void *), void *user_data);
 void PolyToPolygonsOnLayer (DataType *, LayerType *, POLYAREA *, FlagType);
+POLYAREA *board_outline_poly ();
 #endif

commit 7bb66d19ddb72f6f17eb1295d6723d00729a71c8
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    Fixup depth for layers and element marks

diff --git a/src/hid/gtk/gtkhid-main.c b/src/hid/gtk/gtkhid-main.c
index 89e21d0..3b96103 100644
--- a/src/hid/gtk/gtkhid-main.c
+++ b/src/hid/gtk/gtkhid-main.c
@@ -359,7 +359,7 @@ int compute_depth (int group)
   if (group >= 0 && group < max_layer) {
     newgroup = group;
 
-    depth = (max_depth - newgroup * 10) * 200 / gport->zoom;
+    depth = (max_depth - (newgroup - min_phys_group) * 10) * 200 / gport->zoom;
   } else if (SL_TYPE (idx) == SL_MASK) {
     if (SL_SIDE (idx) == SL_TOP_SIDE) {
       depth = (max_depth + 3) * 200 / gport->zoom;
diff --git a/src/hid/gtk/gui-output-events.c b/src/hid/gtk/gui-output-events.c
index 7ebc25f..f6e7758 100644
--- a/src/hid/gtk/gui-output-events.c
+++ b/src/hid/gtk/gui-output-events.c
@@ -1670,12 +1670,14 @@ ghid_draw_everything (BoxTypePtr drawn_area)
     gui->set_layer (NULL, SL (FINISHED, 0), 0);
   }
   /* Draw top silkscreen */
-  if (gui->set_layer ("topsilk", SL (SILK, TOP), 0)) {
+  if (!Settings.ShowSolderSide &&
+      gui->set_layer ("topsilk", SL (SILK, TOP), 0)) {
     DrawSilk (0, COMPONENT_LAYER, drawn_area);
     gui->set_layer (NULL, SL (FINISHED, 0), 0);
   }
 
-  if (gui->set_layer ("bottomsilk", SL (SILK, BOTTOM), 0)) {
+  if (Settings.ShowSolderSide &&
+      gui->set_layer ("bottomsilk", SL (SILK, BOTTOM), 0)) {
     DrawSilk (1, SOLDER_LAYER, drawn_area);
     gui->set_layer (NULL, SL (FINISHED, 0), 0);
   }
@@ -1843,13 +1845,6 @@ ghid_port_drawing_area_expose_event_cb (GtkWidget * widget,
              gport->bg_color.green / 65535.,
              gport->bg_color.blue / 65535.);
 
-  glBegin (GL_QUADS);
-  glVertex3i (eleft,  etop,    -50);
-  glVertex3i (eright, etop,    -50);
-  glVertex3i (eright, ebottom, -50);
-  glVertex3i (eleft,  ebottom, -50);
-  glEnd ();
-
   /* TODO: Background image */
 
   hidgl_init_triangle_array (&buffer);
@@ -1870,6 +1865,37 @@ ghid_port_drawing_area_expose_event_cb (GtkWidget * widget,
                 ghid_flip_y ? gport->view_y0 - PCB->MaxHeight :
                              -gport->view_y0, 0);
 
+  if (global_view_2d) {
+    glBegin (GL_QUADS);
+    glVertex3i (0,             0,              0);
+    glVertex3i (PCB->MaxWidth, 0,              0);
+    glVertex3i (PCB->MaxWidth, PCB->MaxHeight, 0);
+    glVertex3i (0,             PCB->MaxHeight, 0);
+    glEnd ();
+  } else {
+    int solder_group;
+    int component_group;
+    int min_phys_group;
+    int max_phys_group;
+    int i;
+
+    solder_group = GetLayerGroupNumberByNumber (max_layer + SOLDER_LAYER);
+    component_group = GetLayerGroupNumberByNumber (max_layer + COMPONENT_LAYER);
+
+    min_phys_group = MIN (solder_group, component_group);
+    max_phys_group = MAX (solder_group, component_group);
+
+    glBegin (GL_QUADS);
+    for (i = min_phys_group; i <= max_phys_group; i++) {
+      int depth = compute_depth (i);
+      glVertex3i (0,             0,              depth);
+      glVertex3i (PCB->MaxWidth, 0,              depth);
+      glVertex3i (PCB->MaxWidth, PCB->MaxHeight, depth);
+      glVertex3i (0,             PCB->MaxHeight, depth);
+    }
+    glEnd ();
+  }
+
   // hid_expose_callback (&ghid_hid, &region, 0);
   ghid_draw_everything (&region);
 

commit 06a432e7d509472c95fa0287de2c7d3f33c3933c
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    Layer fixes
    
    ** SHOULD MERGE SOME OF THIS COMMIT DOWN INTO OTHER PATCHES? **
    
    Fix mask display in 3D (Allow both side masks to display at once)
    Fix rendering depths for silk and mask layers

diff --git a/src/hid/gtk/gtkhid-main.c b/src/hid/gtk/gtkhid-main.c
index 6002b9a..89e21d0 100644
--- a/src/hid/gtk/gtkhid-main.c
+++ b/src/hid/gtk/gtkhid-main.c
@@ -337,36 +337,47 @@ int compute_depth (int group)
 {
   static int last_depth_computed = 0;
 
+  int solder_group;
+  int component_group;
+  int min_phys_group;
+  int max_phys_group;
+  int max_depth;
   int depth = last_depth_computed;
   int newgroup;
   int idx = (group >= 0
              && group <
              max_layer) ? PCB->LayerGroups.Entries[group][0] : group;
 
+  solder_group = GetLayerGroupNumberByNumber (max_layer + SOLDER_LAYER);
+  component_group = GetLayerGroupNumberByNumber (max_layer + COMPONENT_LAYER);
+
+  min_phys_group = MIN (solder_group, component_group);
+  max_phys_group = MAX (solder_group, component_group);
+
+  max_depth = (1 + max_phys_group - min_phys_group) * 10;
+
   if (group >= 0 && group < max_layer) {
     newgroup = group;
-#if 0
-    /* Re-ordering doesn't work, since we also need to adjust the rendering order */
-    if (group == 1)
-      newgroup = max_layer - 1;
-    else if (group > 1)
-      newgroup = group - 1;
-#endif
-    depth = ((max_layer - newgroup) * 10) * 200 / gport->zoom;
+
+    depth = (max_depth - newgroup * 10) * 200 / gport->zoom;
   } else if (SL_TYPE (idx) == SL_MASK) {
-    if (SL_SIDE (idx) == SL_TOP_SIDE && !Settings.ShowSolderSide) {
-      depth = (max_layer * 10 + 3) * 200 / gport->zoom;
+    if (SL_SIDE (idx) == SL_TOP_SIDE) {
+      depth = (max_depth + 3) * 200 / gport->zoom;
     } else {
       depth = (10 - 3) * 200 / gport->zoom;
     }
   } else if (SL_TYPE (idx) == SL_SILK) {
-    if (SL_SIDE (idx) == SL_TOP_SIDE && !Settings.ShowSolderSide) {
-      depth = (max_layer * 10 + 5) * 200 / gport->zoom;
+    if (SL_SIDE (idx) == SL_TOP_SIDE) {
+      depth = (max_depth + 5) * 200 / gport->zoom;
     } else {
       depth = (10 - 5) * 200 / gport->zoom;
     }
   } else if (SL_TYPE (idx) == SL_INVISIBLE) {
-    depth = (10 - 3) * 200 / gport->zoom;
+    if (Settings.ShowSolderSide) {
+      depth = (max_depth + 5) * 200 / gport->zoom;
+    } else {
+      depth = (10 - 5) * 200 / gport->zoom;
+    }
   }
 
   last_depth_computed = depth;
diff --git a/src/hid/gtk/gui-output-events.c b/src/hid/gtk/gui-output-events.c
index ae4bc48..7ebc25f 100644
--- a/src/hid/gtk/gui-output-events.c
+++ b/src/hid/gtk/gui-output-events.c
@@ -1354,8 +1354,8 @@ DrawLayerGroup (int group, const BoxType * screen)
   int n_entries = PCB->LayerGroups.Number[group];
   Cardinal *layers = PCB->LayerGroups.Entries[group];
   int first_run = 1;
-  int component = GetLayerGroupNumberByNumber (max_layer + COMPONENT_LAYER);
-  int solder    = GetLayerGroupNumberByNumber (max_layer + SOLDER_LAYER);
+  int component_group = GetLayerGroupNumberByNumber (max_layer + COMPONENT_LAYER);
+  int solder_group    = GetLayerGroupNumberByNumber (max_layer + SOLDER_LAYER);
 
   if (!gui->set_layer (0, group, 0)) {
     gui->set_layer (NULL, SL (FINISHED, 0), 0);
@@ -1417,12 +1417,12 @@ DrawLayerGroup (int group, const BoxType * screen)
       if (!global_view_2d && rv) {
         if (PCB->PinOn) r_search (PCB->Data->pin_tree, screen, NULL, pin_inlayer_callback, Layer);
         if (PCB->ViaOn) r_search (PCB->Data->via_tree, screen, NULL, via_inlayer_callback, Layer);
-        if ((layernum == component && !SWAP_IDENT) ||
-            (layernum == solder    &&  SWAP_IDENT))
+        if ((group == component_group && !SWAP_IDENT) ||
+            (group == solder_group    &&  SWAP_IDENT))
           if (PCB->PinOn)
             r_search (PCB->Data->pad_tree, screen, NULL, pad_callback, Layer);
-        if ((layernum == solder    && !SWAP_IDENT) ||
-            (layernum == component &&  SWAP_IDENT))
+        if ((group == solder_group    && !SWAP_IDENT) ||
+            (group == component_group &&  SWAP_IDENT))
           if (PCB->PinOn)
             r_search (PCB->Data->pad_tree, screen, NULL, backPad_callback, Layer);
       }
@@ -1508,6 +1508,10 @@ ghid_draw_everything (BoxTypePtr drawn_area)
   struct cyl_info cyl_info;
   int reverse_layers;
   int save_show_solder;
+  int solder_group;
+  int component_group;
+  int min_phys_group;
+  int max_phys_group;
 
   extern char *current_color;
   extern bool Gathering;
@@ -1531,36 +1535,71 @@ ghid_draw_everything (BoxTypePtr drawn_area)
   if (!global_view_2d && save_show_solder)
     reverse_layers = !reverse_layers;
 
+  PCB->Data->SILKLAYER.Color = PCB->ElementColor;
+  PCB->Data->BACKSILKLAYER.Color = PCB->InvisibleObjectsColor;
+
+  solder_group = GetLayerGroupNumberByNumber (max_layer + SOLDER_LAYER);
+  component_group = GetLayerGroupNumberByNumber (max_layer + COMPONENT_LAYER);
+
+  min_phys_group = MIN (solder_group, component_group);
+  max_phys_group = MAX (solder_group, component_group);
+
   memset (do_group, 0, sizeof (do_group));
   for (ngroups = 0, i = 0; i < max_layer; i++) {
-    LayerType *l;
     int group;
     int orderi;
 
     orderi = reverse_layers ? max_layer - i - 1 : i;
 
     // Draw in numerical order when in 3D view
-    l = global_view_2d ? LAYER_ON_STACK (i) : LAYER_PTR (orderi);
-    group = GetLayerGroupNumberByNumber (global_view_2d ? LayerStack[i] : orderi);
+    group = global_view_2d ? GetLayerGroupNumberByNumber (LayerStack[i]) : orderi;
 
-    if (/*l->On && */!do_group[group]) {
+    if (!do_group[group]) {
       do_group[group] = 1;
       drawn_groups[ngroups++] = group;
     }
   }
 
+
   /*
    * first draw all 'invisible' stuff
    */
   if (!TEST_FLAG (CHECKPLANESFLAG, PCB) &&
       gui->set_layer ("invisible", SL (INVISIBLE, 0), 0)) {
-    if (global_view_2d)
-      r_search (PCB->Data->pad_tree, drawn_area, NULL, backPad_callback, NULL);
     if (PCB->ElementOn) {
-      r_search (PCB->Data->element_tree, drawn_area, NULL, backE_callback, NULL);
       r_search (PCB->Data->name_tree[NAME_INDEX (PCB)], drawn_area, NULL, backN_callback, NULL);
       DrawLayer (&(PCB->Data->BACKSILKLAYER), drawn_area);
     }
+#if 1
+    if (!global_view_2d) {
+      /* Draw the solder mask if turned on */
+      if (gui->set_layer ("soldermask", SL (MASK, BOTTOM), 0)) {
+        int save_swap = SWAP_IDENT;
+        gui->set_layer (NULL, SL (FINISHED, 0), 0);
+        gui->set_layer ("componentmask", SL (MASK, TOP), 0);
+        //^__ HACK, THE GUI DOESNT WANT US TO DRAW THIS!
+        SWAP_IDENT = 0;
+        DrawMask (drawn_area);
+        SWAP_IDENT = save_swap;
+        gui->set_layer (NULL, SL (FINISHED, 0), 0);
+      }
+      if (gui->set_layer ("componentmask", SL (MASK, TOP), 0)) {
+        int save_swap = SWAP_IDENT;
+        gui->set_layer (NULL, SL (FINISHED, 0), 0);
+        gui->set_layer ("soldermask", SL (MASK, BOTTOM), 0);
+        //^__ HACK, THE GUI DOESNT WANT US TO DRAW THIS!
+        SWAP_IDENT = 1;
+        DrawMask (drawn_area);
+        SWAP_IDENT = save_swap;
+        gui->set_layer (NULL, SL (FINISHED, 0), 0);
+      }
+      gui->set_layer ("invisible", SL (INVISIBLE, 0), 0);
+    }
+#endif
+    if (global_view_2d)
+      r_search (PCB->Data->pad_tree, drawn_area, NULL, backPad_callback, NULL);
+    if (PCB->ElementOn)
+      r_search (PCB->Data->element_tree, drawn_area, NULL, backE_callback, NULL);
     gui->set_layer (NULL, SL (FINISHED, 0), 0);
   }
 
@@ -1569,7 +1608,11 @@ ghid_draw_everything (BoxTypePtr drawn_area)
     DrawLayerGroup (drawn_groups [i], drawn_area);
 
 #if 1
-    if (!global_view_2d && i > 0) {
+    if (!global_view_2d && i > 0 &&
+        drawn_groups[i] >= min_phys_group &&
+        drawn_groups[i] <= max_phys_group &&
+        drawn_groups[i - 1] >= min_phys_group &&
+        drawn_groups[i - 1] <= max_phys_group) {
       cyl_info.from_layer = drawn_groups[i];
       cyl_info.to_layer = drawn_groups[i - 1];
       cyl_info.scale = gport->zoom;

commit eee43264a941ef1084a8888ec31325d6a37bae6c
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    Add routines to render just a single contour
    
    Use them rather than the GLU tessellator

diff --git a/src/hid/common/hidgl.c b/src/hid/common/hidgl.c
index 360aa83..6931651 100644
--- a/src/hid/common/hidgl.c
+++ b/src/hid/common/hidgl.c
@@ -585,27 +585,7 @@ hidgl_fill_polygon (int n_coords, int *x, int *y)
   free (vertices);
 }
 
-void tesselate_contour (GLUtesselator *tobj, VNODE *vnode, GLdouble *vertices)
-{
-  VNODE *vn = vnode;
-  int offset = 0;
-
-  gluTessBeginPolygon (tobj, NULL);
-  gluTessBeginContour (tobj);
-  do {
-    vertices [0 + offset] = vn->point[0];
-    vertices [1 + offset] = vn->point[1];
-    vertices [2 + offset] = 0.;
-    gluTessVertex (tobj, &vertices [offset], &vertices [offset]);
-    offset += 3;
-  } while ((vn = vn->next) != vnode);
-  gluTessEndContour (tobj);
-  gluTessEndPolygon (tobj);
-}
-
 struct do_hole_info {
-  GLUtesselator *tobj;
-  GLdouble *vertices;
   double scale;
 };
 
@@ -614,6 +594,7 @@ do_hole (const BoxType *b, void *cl)
 {
   struct do_hole_info *info = cl;
   PLINE *curc = (PLINE *) b;
+  cairo_traps_t traps;
 
   /* Ignore the outer contour - we draw it first explicitly*/
   if (curc->Flags.orient == PLF_DIR) {
@@ -632,7 +613,10 @@ do_hole (const BoxType *b, void *cl)
     }
   }
 
-  tesselate_contour (info->tobj, &curc->head, info->vertices);
+  _cairo_traps_init (&traps);
+  bo_contour_to_traps (curc, &traps);
+  _cairo_traps_fini (&traps);
+
   return 1;
 }
 
@@ -644,18 +628,10 @@ static int assigned_bits = 0;
 void
 hidgl_fill_pcb_polygon (PolygonType *poly, const BoxType *clip_box, double scale)
 {
-  int vertex_count = 0;
-  PLINE *contour;
   struct do_hole_info info;
   int stencil_bit;
   cairo_traps_t traps;
 
-  _cairo_traps_init (&traps);
-  bo_poly_to_traps (poly->Clipped, &traps);
-  _cairo_traps_fini (&traps);
-
-  return;
-
   info.scale = scale;
   global_scale = scale;
 
@@ -675,19 +651,6 @@ hidgl_fill_pcb_polygon (PolygonType *poly, const BoxType *clip_box, double scale
   /* Flush out any existing geoemtry to be rendered */
   hidgl_flush_triangles (&buffer);
 
-  /* Walk the polygon structure, counting vertices */
-  /* This gives an upper bound on the amount of storage required */
-  for (contour = poly->Clipped->contours;
-       contour != NULL; contour = contour->next)
-    vertex_count = MAX (vertex_count, contour->Count);
-
-  info.vertices = malloc (sizeof(GLdouble) * vertex_count * 3);
-  info.tobj = gluNewTess ();
-  gluTessCallback(info.tobj, GLU_TESS_BEGIN, myBegin);
-  gluTessCallback(info.tobj, GLU_TESS_VERTEX, myVertex);
-  gluTessCallback(info.tobj, GLU_TESS_COMBINE, myCombine);
-  gluTessCallback(info.tobj, GLU_TESS_ERROR, myError);
-
   glPushAttrib (GL_STENCIL_BUFFER_BIT);                   // Save the write mask etc.. for final restore
   glPushAttrib (GL_STENCIL_BUFFER_BIT |                   // Resave the stencil write-mask etc.., and
                 GL_COLOR_BUFFER_BIT);                     // the colour buffer write mask etc.. for part way restore
@@ -716,17 +679,15 @@ hidgl_fill_pcb_polygon (PolygonType *poly, const BoxType *clip_box, double scale
                                                               // any bits permitted by the stencil writemask
 
   /* Draw the polygon outer */
-  tesselate_contour (info.tobj, &poly->Clipped->contours->head, info.vertices);
+  _cairo_traps_init (&traps);
+  bo_contour_to_traps (poly->Clipped->contours, &traps);
+  _cairo_traps_fini (&traps);
   hidgl_flush_triangles (&buffer);
 
   /* Unassign our stencil buffer bit */
   hidgl_return_stencil_bit (stencil_bit);
 
   glPopAttrib ();                                             // Restore the stencil buffer write-mask etc..
-
-  gluDeleteTess (info.tobj);
-  myFreeCombined ();
-  free (info.vertices);
 }
 
 void

commit fe8e6a53ff8a0028360888f7927108ca7ffa498b
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    Remove unused intersection routines from cairo-bentley-ottman.c
    
    Our polygons are (supposed to be) free from intersections!

diff --git a/src/cairo/cairo-bentley-ottmann.c b/src/cairo/cairo-bentley-ottmann.c
index 778d69c..fcc0e66 100644
--- a/src/cairo/cairo-bentley-ottmann.c
+++ b/src/cairo/cairo-bentley-ottmann.c
@@ -59,16 +59,6 @@
 
 typedef cairo_point_t cairo_bo_point32_t;
 
-typedef struct _cairo_bo_intersect_ordinate {
-    int32_t ordinate;
-    enum { EXACT, INEXACT } exactness;
-} cairo_bo_intersect_ordinate_t;
-
-typedef struct _cairo_bo_intersect_point {
-    cairo_bo_intersect_ordinate_t x;
-    cairo_bo_intersect_ordinate_t y;
-} cairo_bo_intersect_point_t;
-
 typedef struct _cairo_bo_edge cairo_bo_edge_t;
 typedef struct _cairo_bo_trap cairo_bo_trap_t;
 
@@ -94,7 +84,6 @@ struct _cairo_bo_edge {
 
 typedef enum {
     CAIRO_BO_EVENT_TYPE_STOP,
-    CAIRO_BO_EVENT_TYPE_INTERSECTION,
     CAIRO_BO_EVENT_TYPE_START
 } cairo_bo_event_type_t;
 
@@ -136,75 +125,6 @@ typedef struct _cairo_bo_sweep_line {
     cairo_bo_edge_t *current_edge;
 } cairo_bo_sweep_line_t;
 
-#if DEBUG_TRAPS
-static void
-dump_traps (cairo_traps_t *traps, const char *filename)
-{
-    FILE *file;
-    int n;
-
-    if (getenv ("CAIRO_DEBUG_TRAPS") == NULL)
-        return;
-
-    if (traps->has_limits) {
-        printf ("%s: limits=(%d, %d, %d, %d)\n",
-                filename,
-                traps->limits.p1.x, traps->limits.p1.y,
-                traps->limits.p2.x, traps->limits.p2.y);
-    }
-    printf ("%s: extents=(%d, %d, %d, %d)\n",
-            filename,
-            traps->extents.p1.x, traps->extents.p1.y,
-            traps->extents.p2.x, traps->extents.p2.y);
-
-    file = fopen (filename, "a");
-    if (file != NULL) {
-        for (n = 0; n < traps->num_traps; n++) {
-            fprintf (file, "%d %d L:(%d, %d), (%d, %d) R:(%d, %d), (%d, %d)\n",
-                     traps->traps[n].top,
-                     traps->traps[n].bottom,
-                     traps->traps[n].left.p1.x,
-                     traps->traps[n].left.p1.y,
-                     traps->traps[n].left.p2.x,
-                     traps->traps[n].left.p2.y,
-                     traps->traps[n].right.p1.x,
-                     traps->traps[n].right.p1.y,
-                     traps->traps[n].right.p2.x,
-                     traps->traps[n].right.p2.y);
-        }
-        fprintf (file, "\n");
-        fclose (file);
-    }
-}
-
-static void
-dump_edges (cairo_bo_start_event_t *events,
-            int num_edges,
-            const char *filename)
-{
-    FILE *file;
-    int n;
-
-    if (getenv ("CAIRO_DEBUG_TRAPS") == NULL)
-        return;
-
-    file = fopen (filename, "a");
-    if (file != NULL) {
-        for (n = 0; n < num_edges; n++) {
-            fprintf (file, "(%d, %d), (%d, %d) %d %d %d\n",
-                     events[n].edge.edge.line.p1.x,
-                     events[n].edge.edge.line.p1.y,
-                     events[n].edge.edge.line.p2.x,
-                     events[n].edge.edge.line.p2.y,
-                     events[n].edge.edge.top,
-                     events[n].edge.edge.bottom,
-                     events[n].edge.edge.dir);
-        }
-        fprintf (file, "\n");
-        fclose (file);
-    }
-}
-#endif
 
 static cairo_fixed_t
 _line_compute_intersection_x_for_y (const cairo_line_t *line,
@@ -612,262 +532,6 @@ det64x32_128 (cairo_int64_t a, int32_t       b,
                               _cairo_int64x32_128_mul (c, b));
 }
 
-/* Compute the intersection of two lines as defined by two edges. The
- * result is provided as a coordinate pair of 128-bit integers.
- *
- * Returns %CAIRO_BO_STATUS_INTERSECTION if there is an intersection or
- * %CAIRO_BO_STATUS_PARALLEL if the two lines are exactly parallel.
- */
-static cairo_bool_t
-intersect_lines (cairo_bo_edge_t                *a,
-                 cairo_bo_edge_t                *b,
-                 cairo_bo_intersect_point_t        *intersection)
-{
-    cairo_int64_t a_det, b_det;
-
-    /* XXX: We're assuming here that dx and dy will still fit in 32
-     * bits. That's not true in general as there could be overflow. We
-     * should prevent that before the tessellation algorithm begins.
-     * What we're doing to mitigate this is to perform clamping in
-     * cairo_bo_tessellate_polygon().
-     */
-    int32_t dx1 = a->edge.line.p1.x - a->edge.line.p2.x;
-    int32_t dy1 = a->edge.line.p1.y - a->edge.line.p2.y;
-
-    int32_t dx2 = b->edge.line.p1.x - b->edge.line.p2.x;
-    int32_t dy2 = b->edge.line.p1.y - b->edge.line.p2.y;
-
-    cairo_int64_t den_det;
-    cairo_int64_t R;
-    cairo_quorem64_t qr;
-
-    den_det = det32_64 (dx1, dy1, dx2, dy2);
-
-     /* Q: Can we determine that the lines do not intersect (within range)
-      * much more cheaply than computing the intersection point i.e. by
-      * avoiding the division?
-      *
-      *   X = ax + t * adx = bx + s * bdx;
-      *   Y = ay + t * ady = by + s * bdy;
-      *   â?´ t * (ady*bdx - bdy*adx) = bdx * (by - ay) + bdy * (ax - bx)
-      *   => t * L = R
-      *
-      * Therefore we can reject any intersection (under the criteria for
-      * valid intersection events) if:
-      *   L^R < 0 => t < 0, or
-      *   L<R => t > 1
-      *
-      * (where top/bottom must at least extend to the line endpoints).
-      *
-      * A similar substitution can be performed for s, yielding:
-      *   s * (ady*bdx - bdy*adx) = ady * (ax - bx) - adx * (ay - by)
-      */
-    R = det32_64 (dx2, dy2,
-                  b->edge.line.p1.x - a->edge.line.p1.x,
-                  b->edge.line.p1.y - a->edge.line.p1.y);
-    if (_cairo_int64_negative (den_det)) {
-        if (_cairo_int64_ge (den_det, R))
-            return FALSE;
-    } else {
-        if (_cairo_int64_le (den_det, R))
-            return FALSE;
-    }
-
-    R = det32_64 (dy1, dx1,
-                  a->edge.line.p1.y - b->edge.line.p1.y,
-                  a->edge.line.p1.x - b->edge.line.p1.x);
-    if (_cairo_int64_negative (den_det)) {
-        if (_cairo_int64_ge (den_det, R))
-            return FALSE;
-    } else {
-        if (_cairo_int64_le (den_det, R))
-            return FALSE;
-    }
-
-    /* We now know that the two lines should intersect within range. */
-
-    a_det = det32_64 (a->edge.line.p1.x, a->edge.line.p1.y,
-                      a->edge.line.p2.x, a->edge.line.p2.y);
-    b_det = det32_64 (b->edge.line.p1.x, b->edge.line.p1.y,
-                      b->edge.line.p2.x, b->edge.line.p2.y);
-
-    /* x = det (a_det, dx1, b_det, dx2) / den_det */
-    qr = _cairo_int_96by64_32x64_divrem (det64x32_128 (a_det, dx1,
-                                                       b_det, dx2),
-                                         den_det);
-    if (_cairo_int64_eq (qr.rem, den_det))
-        return FALSE;
-#if 0
-    intersection->x.exactness = _cairo_int64_is_zero (qr.rem) ? EXACT : INEXACT;
-#else
-    intersection->x.exactness = EXACT;
-    if (! _cairo_int64_is_zero (qr.rem)) {
-        if (_cairo_int64_negative (den_det) ^ _cairo_int64_negative (qr.rem))
-            qr.rem = _cairo_int64_negate (qr.rem);
-        qr.rem = _cairo_int64_mul (qr.rem, _cairo_int32_to_int64 (2));
-        if (_cairo_int64_ge (qr.rem, den_det)) {
-            qr.quo = _cairo_int64_add (qr.quo,
-                                       _cairo_int32_to_int64 (_cairo_int64_negative (qr.quo) ? -1 : 1));
-        } else
-            intersection->x.exactness = INEXACT;
-    }
-#endif
-    intersection->x.ordinate = _cairo_int64_to_int32 (qr.quo);
-
-    /* y = det (a_det, dy1, b_det, dy2) / den_det */
-    qr = _cairo_int_96by64_32x64_divrem (det64x32_128 (a_det, dy1,
-                                                       b_det, dy2),
-                                         den_det);
-    if (_cairo_int64_eq (qr.rem, den_det))
-        return FALSE;
-#if 0
-    intersection->y.exactness = _cairo_int64_is_zero (qr.rem) ? EXACT : INEXACT;
-#else
-    intersection->y.exactness = EXACT;
-    if (! _cairo_int64_is_zero (qr.rem)) {
-        if (_cairo_int64_negative (den_det) ^ _cairo_int64_negative (qr.rem))
-            qr.rem = _cairo_int64_negate (qr.rem);
-        qr.rem = _cairo_int64_mul (qr.rem, _cairo_int32_to_int64 (2));
-        if (_cairo_int64_ge (qr.rem, den_det)) {
-            qr.quo = _cairo_int64_add (qr.quo,
-                                       _cairo_int32_to_int64 (_cairo_int64_negative (qr.quo) ? -1 : 1));
-        } else
-            intersection->y.exactness = INEXACT;
-    }
-#endif
-    intersection->y.ordinate = _cairo_int64_to_int32 (qr.quo);
-
-    return TRUE;
-}
-
-static int
-_cairo_bo_intersect_ordinate_32_compare (cairo_bo_intersect_ordinate_t        a,
-                                         int32_t                        b)
-{
-    /* First compare the quotient */
-    if (a.ordinate > b)
-        return +1;
-    if (a.ordinate < b)
-        return -1;
-    /* With quotient identical, if remainder is 0 then compare equal */
-    /* Otherwise, the non-zero remainder makes a > b */
-    return INEXACT == a.exactness;
-}
-
-/* Does the given edge contain the given point. The point must already
- * be known to be contained within the line determined by the edge,
- * (most likely the point results from an intersection of this edge
- * with another).
- *
- * If we had exact arithmetic, then this function would simply be a
- * matter of examining whether the y value of the point lies within
- * the range of y values of the edge. But since intersection points
- * are not exact due to being rounded to the nearest integer within
- * the available precision, we must also examine the x value of the
- * point.
- *
- * The definition of "contains" here is that the given intersection
- * point will be seen by the sweep line after the start event for the
- * given edge and before the stop event for the edge. See the comments
- * in the implementation for more details.
- */
-static cairo_bool_t
-_cairo_bo_edge_contains_intersect_point (cairo_bo_edge_t                *edge,
-                                         cairo_bo_intersect_point_t        *point)
-{
-    int cmp_top, cmp_bottom;
-
-    /* XXX: When running the actual algorithm, we don't actually need to
-     * compare against edge->top at all here, since any intersection above
-     * top is eliminated early via a slope comparison. We're leaving these
-     * here for now only for the sake of the quadratic-time intersection
-     * finder which needs them.
-     */
-
-    cmp_top = _cairo_bo_intersect_ordinate_32_compare (point->y,
-                                                       edge->edge.top);
-    cmp_bottom = _cairo_bo_intersect_ordinate_32_compare (point->y,
-                                                          edge->edge.bottom);
-
-    if (cmp_top < 0 || cmp_bottom > 0)
-    {
-        return FALSE;
-    }
-
-    if (cmp_top > 0 && cmp_bottom < 0)
-    {
-        return TRUE;
-    }
-
-    /* At this stage, the point lies on the same y value as either
-     * edge->top or edge->bottom, so we have to examine the x value in
-     * order to properly determine containment. */
-
-    /* If the y value of the point is the same as the y value of the
-     * top of the edge, then the x value of the point must be greater
-     * to be considered as inside the edge. Similarly, if the y value
-     * of the point is the same as the y value of the bottom of the
-     * edge, then the x value of the point must be less to be
-     * considered as inside. */
-
-    if (cmp_top == 0) {
-        cairo_fixed_t top_x;
-
-        top_x = _line_compute_intersection_x_for_y (&edge->edge.line,
-                                                    edge->edge.top);
-        return _cairo_bo_intersect_ordinate_32_compare (point->x, top_x) > 0;
-    } else { /* cmp_bottom == 0 */
-        cairo_fixed_t bot_x;
-
-        bot_x = _line_compute_intersection_x_for_y (&edge->edge.line,
-                                                    edge->edge.bottom);
-        return _cairo_bo_intersect_ordinate_32_compare (point->x, bot_x) < 0;
-    }
-}
-
-/* Compute the intersection of two edges. The result is provided as a
- * coordinate pair of 128-bit integers.
- *
- * Returns %CAIRO_BO_STATUS_INTERSECTION if there is an intersection
- * that is within both edges, %CAIRO_BO_STATUS_NO_INTERSECTION if the
- * intersection of the lines defined by the edges occurs outside of
- * one or both edges, and %CAIRO_BO_STATUS_PARALLEL if the two edges
- * are exactly parallel.
- *
- * Note that when determining if a candidate intersection is "inside"
- * an edge, we consider both the infinitesimal shortening and the
- * infinitesimal tilt rules described by John Hobby. Specifically, if
- * the intersection is exactly the same as an edge point, it is
- * effectively outside (no intersection is returned). Also, if the
- * intersection point has the same
- */
-static cairo_bool_t
-_cairo_bo_edge_intersect (cairo_bo_edge_t        *a,
-                          cairo_bo_edge_t        *b,
-                          cairo_bo_point32_t        *intersection)
-{
-    cairo_bo_intersect_point_t quorem;
-
-    if (! intersect_lines (a, b, &quorem))
-        return FALSE;
-
-    if (! _cairo_bo_edge_contains_intersect_point (a, &quorem))
-        return FALSE;
-
-    if (! _cairo_bo_edge_contains_intersect_point (b, &quorem))
-        return FALSE;
-
-    /* Now that we've correctly compared the intersection point and
-     * determined that it lies within the edge, then we know that we
-     * no longer need any more bits of storage for the intersection
-     * than we do for our edge coordinates. We also no longer need the
-     * remainder from the division. */
-    intersection->x = quorem.x.ordinate;
-    intersection->y = quorem.y.ordinate;
-
-    return TRUE;
-}
-
 static inline int
 cairo_bo_event_compare (const cairo_bo_event_t *a,
                         const cairo_bo_event_t *b)
@@ -1080,33 +744,6 @@ _cairo_bo_event_queue_fini (cairo_bo_event_queue_t *event_queue)
     _cairo_freepool_fini (&event_queue->pool);
 }
 
-static inline cairo_status_t
-_cairo_bo_event_queue_insert_if_intersect_below_current_y (cairo_bo_event_queue_t        *event_queue,
-                                                           cairo_bo_edge_t        *left,
-                                                           cairo_bo_edge_t *right)
-{
-    cairo_bo_point32_t intersection;
-
-    if (_line_equal (&left->edge.line, &right->edge.line))
-        return CAIRO_STATUS_SUCCESS;
-
-    /* The names "left" and "right" here are correct descriptions of
-     * the order of the two edges within the active edge list. So if a
-     * slope comparison also puts left less than right, then we know
-     * that the intersection of these two segments has already
-     * occurred before the current sweep line position. */
-    if (_slope_compare (left, right) <= 0)
-        return CAIRO_STATUS_SUCCESS;
-
-    if (! _cairo_bo_edge_intersect (left, right, &intersection))
-        return CAIRO_STATUS_SUCCESS;
-
-    return _cairo_bo_event_queue_insert (event_queue,
-                                         CAIRO_BO_EVENT_TYPE_INTERSECTION,
-                                         left, right,
-                                         &intersection);
-}
-
 static void
 _cairo_bo_sweep_line_init (cairo_bo_sweep_line_t *sweep_line)
 {
@@ -1192,26 +829,6 @@ _cairo_bo_sweep_line_delete (cairo_bo_sweep_line_t        *sweep_line,
         sweep_line->current_edge = edge->prev ? edge->prev : edge->next;
 }
 
-static void
-_cairo_bo_sweep_line_swap (cairo_bo_sweep_line_t        *sweep_line,
-                           cairo_bo_edge_t                *left,
-                           cairo_bo_edge_t                *right)
-{
-    if (left->prev != NULL)
-        left->prev->next = right;
-    else
-        sweep_line->head = right;
-
-    if (right->next != NULL)
-        right->next->prev = left;
-
-    left->next = right->next;
-    right->next = left;
-
-    right->prev = left->prev;
-    left->prev = right;
-}
-
 #if DEBUG_PRINT_STATE
 static void
 _cairo_bo_edge_print (cairo_bo_edge_t *edge)
@@ -1231,16 +848,9 @@ _cairo_bo_event_print (cairo_bo_event_t *event)
     case CAIRO_BO_EVENT_TYPE_STOP:
         printf ("Stop: ");
         break;
-    case CAIRO_BO_EVENT_TYPE_INTERSECTION:
-        printf ("Intersection: ");
-        break;
     }
     printf ("(%d, %d)\t", event->point.x, event->point.y);
     _cairo_bo_edge_print (((cairo_bo_queue_event_t *)event)->e1);
-    if (event->type == CAIRO_BO_EVENT_TYPE_INTERSECTION) {
-        printf (" X ");
-        _cairo_bo_edge_print (((cairo_bo_queue_event_t *)event)->e2);
-    }
     printf ("\n");
 }
 
@@ -1542,7 +1152,7 @@ _cairo_bentley_ottmann_tessellate_bo_edges (cairo_bo_event_t   **start_events,
     cairo_bo_sweep_line_t sweep_line;
     cairo_bo_event_t *event;
     cairo_bo_edge_t *left, *right;
-    cairo_bo_edge_t *e1, *e2;
+    cairo_bo_edge_t *e1;
 
 #if DEBUG_EVENTS
     {
@@ -1633,18 +1243,6 @@ _cairo_bentley_ottmann_tessellate_bo_edges (cairo_bo_event_t   **start_events,
             left = e1->prev;
             right = e1->next;
 
-            if (left != NULL) {
-                status = _cairo_bo_event_queue_insert_if_intersect_below_current_y (&event_queue, left, e1);
-                if (unlikely (status))
-                    goto unwind;
-            }
-
-            if (right != NULL) {
-                status = _cairo_bo_event_queue_insert_if_intersect_below_current_y (&event_queue, e1, right);
-                if (unlikely (status))
-                    goto unwind;
-            }
-
             break;
 
         case CAIRO_BO_EVENT_TYPE_STOP:
@@ -1665,47 +1263,8 @@ _cairo_bentley_ottmann_tessellate_bo_edges (cairo_bo_event_t   **start_events,
                 e1->prev = NULL;
             }
 
-            if (left != NULL && right != NULL) {
-                status = _cairo_bo_event_queue_insert_if_intersect_below_current_y (&event_queue, left, right);
-                if (unlikely (status))
-                    goto unwind;
-            }
-
-            break;
-
-        case CAIRO_BO_EVENT_TYPE_INTERSECTION:
             break;
-            printf ("Intersection event\n");
-            e1 = ((cairo_bo_queue_event_t *) event)->e1;
-            e2 = ((cairo_bo_queue_event_t *) event)->e2;
-            _cairo_bo_event_queue_delete (&event_queue, event);
 
-            /* skip this intersection if its edges are not adjacent */
-            if (e2 != e1->next)
-                break;
-
-            intersection_count++;
-
-            left = e1->prev;
-            right = e2->next;
-
-            _cairo_bo_sweep_line_swap (&sweep_line, e1, e2);
-
-            /* after the swap e2 is left of e1 */
-
-            if (left != NULL) {
-                status = _cairo_bo_event_queue_insert_if_intersect_below_current_y (&event_queue, left, e2);
-                if (unlikely (status))
-                    goto unwind;
-            }
-
-            if (right != NULL) {
-                status = _cairo_bo_event_queue_insert_if_intersect_below_current_y (&event_queue, e1, right);
-                if (unlikely (status))
-                    goto unwind;
-            }
-
-            break;
         }
     }
 

commit 880d3643711b332899e36fe7b3b9c0eeae3bc4af
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    Bentley-Ottann test implementation

diff --git a/configure.ac b/configure.ac
index 863e2ee..7628e9d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -7,6 +7,8 @@ AM_INIT_AUTOMAKE([1.9])
 AC_GNU_SOURCE
 AM_CONFIG_HEADER([config.h])
 
+m4_include(configure.ac.system)	dnl checks for system functions, headers, libs
+
 ##########################################################################
 #
 # Try to figure out if we are building from git sources.
diff --git a/configure.ac.system b/configure.ac.system
new file mode 100644
index 0000000..3f6ab7e
--- /dev/null
+++ b/configure.ac.system
@@ -0,0 +1,164 @@
+dnl
+dnl Non-failing checks for functions, headers, libraries, etc go here
+dnl
+
+dnl ====================================================================
+dnl Feature checks
+dnl ====================================================================
+
+AM_CONDITIONAL(CROSS_COMPILING, test "x$cross_compiling" = "xyes")
+CAIRO_BIGENDIAN
+AC_ARG_ENABLE(atomic,
+	      [AS_HELP_STRING([--disable-atomic],
+			      [disable use of native atomic operations])],
+	      [use_atomic=$enableval], [use_atomic=yes])
+AS_IF([test "x$use_atomic" = "xyes"], [
+  CAIRO_CHECK_NATIVE_ATOMIC_PRIMITIVES
+  CAIRO_CHECK_ATOMIC_OP_NEEDS_MEMORY_BARRIER
+])
+AC_CHECK_SIZEOF(void *)
+AC_CHECK_SIZEOF(int)
+AC_CHECK_SIZEOF(long)
+AC_CHECK_SIZEOF(long long)
+AC_CHECK_SIZEOF(size_t)
+
+AC_MSG_CHECKING([for native Win32])
+case "$host" in
+  *-*-mingw*)
+    cairo_os_win32=yes
+    ;;
+  *)
+    cairo_os_win32=no
+    ;;
+esac
+AC_MSG_RESULT([$cairo_os_win32])
+AM_CONDITIONAL(OS_WIN32, test "$cairo_os_win32" = "yes")
+
+AC_MSG_CHECKING([for Sun Solaris (non-POSIX ctime_r)])
+case "$host" in
+    *-*-solaris*)
+	CFLAGS="$CFLAGS -D_POSIX_PTHREAD_SEMANTICS"
+	solaris_posix_pthread=yes
+	;;
+    *)
+	solaris_posix_pthread=no
+	;;
+esac
+AC_MSG_RESULT([$solaris_posix_pthread])
+
+dnl ====================================================================
+dnl Library checks
+dnl ====================================================================
+
+AC_CHECK_LIBM
+LIBS="$LIBS $LIBM"
+
+AC_CHECK_LIB(rt, sched_yield, [RT_LIBS=-lrt], [RT_LIBS=])
+CAIROPERF_LIBS=$RT_LIBS
+AC_SUBST(CAIROPERF_LIBS)
+
+has_shm_open=
+AC_CHECK_LIB(rt, shm_open, [
+	     SHM_LIBS=-lrt
+	     has_shm_open=yes
+	     ], [SHM_LIBS=])
+AM_CONDITIONAL(HAVE_SHM, test "x$has_shm_open" = "xyes")
+AC_SUBST(SHM_LIBS)
+
+AC_CHECK_LIB(socket, connect, [SOCKET_LIBS=-lsocket], [SOCKET_LIBS=])
+CAIROBOILERPLATE_LIBS=$SOCKET_LIBS
+AC_SUBST(CAIROBOILERPLATE_LIBS)
+
+dnl ====================================================================
+dnl Header/function checks
+dnl ====================================================================
+
+dnl check if we have a __builtin_return_address for the cairo-trace
+dnl utility.
+AC_MSG_CHECKING([for __builtin_return_address(0)])
+AC_TRY_COMPILE([],[__builtin_return_address(0);],
+		[have_builtin_return_address=yes],
+		[have_builtin_return_address=no])
+AC_MSG_RESULT($have_builtin_return_address)
+if test "x$have_builtin_return_address" = "xyes"; then
+    AC_DEFINE(HAVE_BUILTIN_RETURN_ADDRESS, 1,
+	[Define to 1 if your compiler supports the __builtin_return_address() intrinsic.])
+fi
+
+dnl Checks for precise integer types
+AC_CHECK_HEADERS([stdint.h inttypes.h sys/int_types.h])
+AC_CHECK_TYPES([uint64_t, uint128_t, __uint128_t])
+
+dnl Check for socket support for any2ppm daemon
+AC_CHECK_HEADERS([fcntl.h unistd.h signal.h sys/stat.h sys/socket.h sys/poll.h sys/un.h])
+
+dnl Check for infinite loops
+AC_CHECK_FUNCS([alarm])
+
+dnl check for CPU affinity support
+AC_CHECK_HEADERS([sched.h], [AC_CHECK_FUNCS([sched_getaffinity])])
+
+dnl check for mmap support
+AC_CHECK_HEADERS([sys/mman.h], [AC_CHECK_FUNCS([mmap])])
+
+dnl check for clock_gettime() support
+save_LIBS="$LIBS"
+LIBS="$LIBS $RT_LIBS"
+AC_CHECK_HEADERS([time.h], [AC_CHECK_FUNCS([clock_gettime])])
+LIBS="$save_LIBS"
+
+dnl check for GNU-extensions to fenv
+AC_CHECK_HEADER(fenv.h,
+	[AC_CHECK_FUNCS(feenableexcept fedisableexcept feclearexcept)])
+
+dnl check for misc headers and functions
+AC_CHECK_HEADERS([libgen.h byteswap.h signal.h setjmp.h fenv.h])
+AC_CHECK_FUNCS([vasnprintf link ctime_r drand48 flockfile ffs])
+
+dnl check for win32 headers (this detects mingw as well)
+AC_CHECK_HEADERS([windows.h], have_windows=yes, have_windows=no)
+
+
+dnl Possible headers for mkdir
+AC_CHECK_HEADERS([sys/stat.h io.h])
+AC_CHECK_FUNC(mkdir,
+	      [AC_MSG_CHECKING([mkdir variant])
+	      mkdir_variant="unknown"
+	      save_CFLAGS="$CFLAGS"
+	      CFLAGS=$WARN_CFLAGS
+	      AC_TRY_COMPILE([
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#ifdef HAVE_IO_H
+#include <io.h>
+#endif
+		      ],
+		      [mkdir ("hello.world", 0777)],
+		      mkdir_variant="mkdir(path, mode)",
+		      [AC_TRY_COMPILE([
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#ifdef HAVE_IO_H
+#include <io.h>
+#endif
+			      ],
+			      [mkdir ("hello.world")],
+			      mkdir_variant="mkdir(path)")])
+	      AC_MSG_RESULT([$mkdir_variant])
+	      CFLAGS="$save_CFLAGS"
+	      if test "x$mkdir_variant" = "xmkdir(path, mode)"; then
+		  AC_DEFINE(HAVE_MKDIR, 2,
+			    [Define to non-zero if your system has mkdir, and to 2 if your version of mkdir requires a mode parameter])
+	      else
+		  AC_DEFINE(HAVE_MKDIR, 1,
+			    [Define to non-zero if your system has mkdir, and to 2 if your version of mkdir requires a mode parameter])
+	      fi])
+
+dnl ===========================================================================
+dnl
+dnl Test for the tools required for building one big test binary
+dnl
+
+AC_CHECK_FUNCS(fork waitpid raise)
diff --git a/src/Makefile.am b/src/Makefile.am
index 2ce0991..b709c27 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -38,6 +38,22 @@ PCB_SRCS = \
 	box.h \
 	buffer.c \
 	buffer.h \
+	cairo/cairo-minimal.h \
+	cairo/cairoint-minimal.h \
+	cairo/cairo-bentley-ottmann.c \
+	cairo/cairo-combsort-private.h \
+	cairo/cairo-compiler-private.h \
+	cairo/cairo-fixed-private.h \
+	cairo/cairo-fixed-type-private.h \
+	cairo/cairo-freelist.c \
+	cairo/cairo-freelist-private.h \
+	cairo/cairo-malloc-private.h \
+	cairo/cairo-traps.c \
+	cairo/cairo-traps-private.h \
+	cairo/cairo-types-private.h \
+	cairo/cairo-wideint.c \
+	cairo/cairo-wideint-private.h \
+	cairo/cairo-wideint-type-private.h \
 	change.c \
 	change.h \
 	clip.c \
@@ -131,6 +147,7 @@ PCB_SRCS = \
 	set.h \
 	strflags.c \
 	strflags.h \
+	sweep.h \
 	thermal.c \
 	thermal.h \
 	undo.c \
diff --git a/src/cairo/cairo-bentley-ottmann.c b/src/cairo/cairo-bentley-ottmann.c
new file mode 100644
index 0000000..778d69c
--- /dev/null
+++ b/src/cairo/cairo-bentley-ottmann.c
@@ -0,0 +1,2010 @@
+/*
+ * Copyright © 2004 Carl Worth
+ * Copyright © 2006 Red Hat, Inc.
+ * Copyright © 2008 Chris Wilson
+ * Copyright © 2009 Peter Clifton
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is Carl Worth
+ *
+ * Contributor(s):
+ *        Carl D. Worth <cworth@xxxxxxxxxx>
+ *        Chris Wilson <chris@xxxxxxxxxxxxxxxxxx>
+ *        Peter Clifton <pcjc2@xxxxxxxxx> (Adaptation to PCB use)
+ */
+
+/* Provide definitions for standalone compilation */
+#include "cairoint-minimal.h"
+#include "cairo-malloc-private.h"
+#include "cairo-traps-private.h"
+#include "cairo-fixed-private.h"
+#include "cairo-freelist-private.h"
+#include "cairo-combsort-private.h"
+
+#include <glib.h>
+
+#include "polygon.h"
+#include <GL/gl.h>
+#include "hid/common/hidgl.h"
+
+#define _cairo_error(x) (x)
+
+#define DEBUG_PRINT_STATE 0
+#define DEBUG_EVENTS 0
+#define DEBUG_TRAPS 0
+
+typedef cairo_point_t cairo_bo_point32_t;
+
+typedef struct _cairo_bo_intersect_ordinate {
+    int32_t ordinate;
+    enum { EXACT, INEXACT } exactness;
+} cairo_bo_intersect_ordinate_t;
+
+typedef struct _cairo_bo_intersect_point {
+    cairo_bo_intersect_ordinate_t x;
+    cairo_bo_intersect_ordinate_t y;
+} cairo_bo_intersect_point_t;
+
+typedef struct _cairo_bo_edge cairo_bo_edge_t;
+typedef struct _cairo_bo_trap cairo_bo_trap_t;
+
+/* A deferred trapezoid of an edge */
+struct _cairo_bo_trap {
+    cairo_bo_edge_t *right;
+    int32_t top;
+};
+
+struct _cairo_bo_edge {
+    cairo_edge_t edge;
+    cairo_bo_edge_t *prev;
+    cairo_bo_edge_t *next;
+    cairo_bo_trap_t deferred_trap;
+};
+
+/* the parent is always given by index/2 */
+#define PQ_PARENT_INDEX(i) ((i) >> 1)
+#define PQ_FIRST_ENTRY 1
+
+/* left and right children are index * 2 and (index * 2) +1 respectively */
+#define PQ_LEFT_CHILD_INDEX(i) ((i) << 1)
+
+typedef enum {
+    CAIRO_BO_EVENT_TYPE_STOP,
+    CAIRO_BO_EVENT_TYPE_INTERSECTION,
+    CAIRO_BO_EVENT_TYPE_START
+} cairo_bo_event_type_t;
+
+typedef struct _cairo_bo_event {
+    cairo_bo_event_type_t type;
+    cairo_point_t point;
+} cairo_bo_event_t;
+
+typedef struct _cairo_bo_start_event {
+    cairo_bo_event_type_t type;
+    cairo_point_t point;
+    cairo_bo_edge_t edge;
+} cairo_bo_start_event_t;
+
+typedef struct _cairo_bo_queue_event {
+    cairo_bo_event_type_t type;
+    cairo_point_t point;
+    cairo_bo_edge_t *e1;
+    cairo_bo_edge_t *e2;
+} cairo_bo_queue_event_t;
+
+typedef struct _pqueue {
+    int size, max_size;
+
+    cairo_bo_event_t **elements;
+    cairo_bo_event_t *elements_embedded[1024];
+} pqueue_t;
+
+typedef struct _cairo_bo_event_queue {
+    cairo_freepool_t pool;
+    pqueue_t pqueue;
+    cairo_bo_event_t **start_events;
+} cairo_bo_event_queue_t;
+
+typedef struct _cairo_bo_sweep_line {
+    cairo_bo_edge_t *head;
+    cairo_bo_edge_t *stopped;
+    int32_t current_y;
+    cairo_bo_edge_t *current_edge;
+} cairo_bo_sweep_line_t;
+
+#if DEBUG_TRAPS
+static void
+dump_traps (cairo_traps_t *traps, const char *filename)
+{
+    FILE *file;
+    int n;
+
+    if (getenv ("CAIRO_DEBUG_TRAPS") == NULL)
+        return;
+
+    if (traps->has_limits) {
+        printf ("%s: limits=(%d, %d, %d, %d)\n",
+                filename,
+                traps->limits.p1.x, traps->limits.p1.y,
+                traps->limits.p2.x, traps->limits.p2.y);
+    }
+    printf ("%s: extents=(%d, %d, %d, %d)\n",
+            filename,
+            traps->extents.p1.x, traps->extents.p1.y,
+            traps->extents.p2.x, traps->extents.p2.y);
+
+    file = fopen (filename, "a");
+    if (file != NULL) {
+        for (n = 0; n < traps->num_traps; n++) {
+            fprintf (file, "%d %d L:(%d, %d), (%d, %d) R:(%d, %d), (%d, %d)\n",
+                     traps->traps[n].top,
+                     traps->traps[n].bottom,
+                     traps->traps[n].left.p1.x,
+                     traps->traps[n].left.p1.y,
+                     traps->traps[n].left.p2.x,
+                     traps->traps[n].left.p2.y,
+                     traps->traps[n].right.p1.x,
+                     traps->traps[n].right.p1.y,
+                     traps->traps[n].right.p2.x,
+                     traps->traps[n].right.p2.y);
+        }
+        fprintf (file, "\n");
+        fclose (file);
+    }
+}
+
+static void
+dump_edges (cairo_bo_start_event_t *events,
+            int num_edges,
+            const char *filename)
+{
+    FILE *file;
+    int n;
+
+    if (getenv ("CAIRO_DEBUG_TRAPS") == NULL)
+        return;
+
+    file = fopen (filename, "a");
+    if (file != NULL) {
+        for (n = 0; n < num_edges; n++) {
+            fprintf (file, "(%d, %d), (%d, %d) %d %d %d\n",
+                     events[n].edge.edge.line.p1.x,
+                     events[n].edge.edge.line.p1.y,
+                     events[n].edge.edge.line.p2.x,
+                     events[n].edge.edge.line.p2.y,
+                     events[n].edge.edge.top,
+                     events[n].edge.edge.bottom,
+                     events[n].edge.edge.dir);
+        }
+        fprintf (file, "\n");
+        fclose (file);
+    }
+}
+#endif
+
+static cairo_fixed_t
+_line_compute_intersection_x_for_y (const cairo_line_t *line,
+                                    cairo_fixed_t y)
+{
+    cairo_fixed_t x, dy;
+
+    if (y == line->p1.y)
+        return line->p1.x;
+    if (y == line->p2.y)
+        return line->p2.x;
+
+    x = line->p1.x;
+    dy = line->p2.y - line->p1.y;
+    if (dy != 0) {
+        x += _cairo_fixed_mul_div_floor (y - line->p1.y,
+                                         line->p2.x - line->p1.x,
+                                         dy);
+    }
+
+    return x;
+}
+
+static inline int
+_cairo_bo_point32_compare (cairo_bo_point32_t const *a,
+                           cairo_bo_point32_t const *b)
+{
+    int cmp;
+
+    cmp = a->y - b->y;
+    if (cmp)
+        return cmp;
+
+    return a->x - b->x;
+}
+
+/* Compare the slope of a to the slope of b, returning 1, 0, -1 if the
+ * slope a is respectively greater than, equal to, or less than the
+ * slope of b.
+ *
+ * For each edge, consider the direction vector formed from:
+ *
+ *        top -> bottom
+ *
+ * which is:
+ *
+ *        (dx, dy) = (line.p2.x - line.p1.x, line.p2.y - line.p1.y)
+ *
+ * We then define the slope of each edge as dx/dy, (which is the
+ * inverse of the slope typically used in math instruction). We never
+ * compute a slope directly as the value approaches infinity, but we
+ * can derive a slope comparison without division as follows, (where
+ * the ? represents our compare operator).
+ *
+ * 1.           slope(a) ? slope(b)
+ * 2.            adx/ady ? bdx/bdy
+ * 3.        (adx * bdy) ? (bdx * ady)
+ *
+ * Note that from step 2 to step 3 there is no change needed in the
+ * sign of the result since both ady and bdy are guaranteed to be
+ * greater than or equal to 0.
+ *
+ * When using this slope comparison to sort edges, some care is needed
+ * when interpreting the results. Since the slope compare operates on
+ * distance vectors from top to bottom it gives a correct left to
+ * right sort for edges that have a common top point, (such as two
+ * edges with start events at the same location). On the other hand,
+ * the sense of the result will be exactly reversed for two edges that
+ * have a common stop point.
+ */
+static inline int
+_slope_compare (const cairo_bo_edge_t *a,
+                const cairo_bo_edge_t *b)
+{
+    /* XXX: We're assuming here that dx and dy will still fit in 32
+     * bits. That's not true in general as there could be overflow. We
+     * should prevent that before the tessellation algorithm
+     * begins.
+     */
+    int32_t adx = a->edge.line.p2.x - a->edge.line.p1.x;
+    int32_t bdx = b->edge.line.p2.x - b->edge.line.p1.x;
+
+    /* Since the dy's are all positive by construction we can fast
+     * path several common cases.
+     */
+
+    /* First check for vertical lines. */
+    if (adx == 0)
+        return -bdx;
+    if (bdx == 0)
+        return adx;
+
+    /* Then where the two edges point in different directions wrt x. */
+    if ((adx ^ bdx) < 0)
+        return adx;
+
+    /* Finally we actually need to do the general comparison. */
+    {
+        int32_t ady = a->edge.line.p2.y - a->edge.line.p1.y;
+        int32_t bdy = b->edge.line.p2.y - b->edge.line.p1.y;
+        cairo_int64_t adx_bdy = _cairo_int32x32_64_mul (adx, bdy);
+        cairo_int64_t bdx_ady = _cairo_int32x32_64_mul (bdx, ady);
+
+        return _cairo_int64_cmp (adx_bdy, bdx_ady);
+    }
+}
+
+/*
+ * We need to compare the x-coordinates of a pair of lines for a particular y,
+ * without loss of precision.
+ *
+ * The x-coordinate along an edge for a given y is:
+ *   X = A_x + (Y - A_y) * A_dx / A_dy
+ *
+ * So the inequality we wish to test is:
+ *   A_x + (Y - A_y) * A_dx / A_dy â?? B_x + (Y - B_y) * B_dx / B_dy,
+ * where â?? is our inequality operator.
+ *
+ * By construction, we know that A_dy and B_dy (and (Y - A_y), (Y - B_y)) are
+ * all positive, so we can rearrange it thus without causing a sign change:
+ *   A_dy * B_dy * (A_x - B_x) â?? (Y - B_y) * B_dx * A_dy
+ *                                 - (Y - A_y) * A_dx * B_dy
+ *
+ * Given the assumption that all the deltas fit within 32 bits, we can compute
+ * this comparison directly using 128 bit arithmetic. For certain, but common,
+ * input we can reduce this down to a single 32 bit compare by inspecting the
+ * deltas.
+ *
+ * (And put the burden of the work on developing fast 128 bit ops, which are
+ * required throughout the tessellator.)
+ *
+ * See the similar discussion for _slope_compare().
+ */
+static int
+edges_compare_x_for_y_general (const cairo_bo_edge_t *a,
+                               const cairo_bo_edge_t *b,
+                               int32_t y)
+{
+    /* XXX: We're assuming here that dx and dy will still fit in 32
+     * bits. That's not true in general as there could be overflow. We
+     * should prevent that before the tessellation algorithm
+     * begins.
+     */
+    int32_t dx;
+    int32_t adx, ady;
+    int32_t bdx, bdy;
+    enum {
+       HAVE_NONE    = 0x0,
+       HAVE_DX      = 0x1,
+       HAVE_ADX     = 0x2,
+       HAVE_DX_ADX  = HAVE_DX | HAVE_ADX,
+       HAVE_BDX     = 0x4,
+       HAVE_DX_BDX  = HAVE_DX | HAVE_BDX,
+       HAVE_ADX_BDX = HAVE_ADX | HAVE_BDX,
+       HAVE_ALL     = HAVE_DX | HAVE_ADX | HAVE_BDX
+    } have_dx_adx_bdx = HAVE_ALL;
+
+    /* don't bother solving for abscissa if the edges' bounding boxes
+     * can be used to order them. */
+    {
+           int32_t amin, amax;
+           int32_t bmin, bmax;
+           if (a->edge.line.p1.x < a->edge.line.p2.x) {
+                   amin = a->edge.line.p1.x;
+                   amax = a->edge.line.p2.x;
+           } else {
+                   amin = a->edge.line.p2.x;
+                   amax = a->edge.line.p1.x;
+           }
+           if (b->edge.line.p1.x < b->edge.line.p2.x) {
+                   bmin = b->edge.line.p1.x;
+                   bmax = b->edge.line.p2.x;
+           } else {
+                   bmin = b->edge.line.p2.x;
+                   bmax = b->edge.line.p1.x;
+           }
+           if (amax < bmin) return -1;
+           if (amin > bmax) return +1;
+    }
+
+    ady = a->edge.line.p2.y - a->edge.line.p1.y;
+    adx = a->edge.line.p2.x - a->edge.line.p1.x;
+    if (adx == 0)
+        have_dx_adx_bdx &= ~HAVE_ADX;
+
+    bdy = b->edge.line.p2.y - b->edge.line.p1.y;
+    bdx = b->edge.line.p2.x - b->edge.line.p1.x;
+    if (bdx == 0)
+        have_dx_adx_bdx &= ~HAVE_BDX;
+
+    dx = a->edge.line.p1.x - b->edge.line.p1.x;
+    if (dx == 0)
+        have_dx_adx_bdx &= ~HAVE_DX;
+
+#define L _cairo_int64x32_128_mul (_cairo_int32x32_64_mul (ady, bdy), dx)
+#define A _cairo_int64x32_128_mul (_cairo_int32x32_64_mul (adx, bdy), y - a->edge.line.p1.y)
+#define B _cairo_int64x32_128_mul (_cairo_int32x32_64_mul (bdx, ady), y - b->edge.line.p1.y)
+    switch (have_dx_adx_bdx) {
+    default:
+    case HAVE_NONE:
+        return 0;
+    case HAVE_DX:
+        /* A_dy * B_dy * (A_x - B_x) â?? 0 */
+        return dx; /* ady * bdy is positive definite */
+    case HAVE_ADX:
+        /* 0 â??  - (Y - A_y) * A_dx * B_dy */
+        return adx; /* bdy * (y - a->top.y) is positive definite */
+    case HAVE_BDX:
+        /* 0 â?? (Y - B_y) * B_dx * A_dy */
+        return -bdx; /* ady * (y - b->top.y) is positive definite */
+    case HAVE_ADX_BDX:
+        /*  0 â?? (Y - B_y) * B_dx * A_dy - (Y - A_y) * A_dx * B_dy */
+        if ((adx ^ bdx) < 0) {
+            return adx;
+        } else if (a->edge.line.p1.y == b->edge.line.p1.y) { /* common origin */
+            cairo_int64_t adx_bdy, bdx_ady;
+
+            /* â?´ A_dx * B_dy â?? B_dx * A_dy */
+
+            adx_bdy = _cairo_int32x32_64_mul (adx, bdy);
+            bdx_ady = _cairo_int32x32_64_mul (bdx, ady);
+
+            return _cairo_int64_cmp (adx_bdy, bdx_ady);
+        } else
+            return _cairo_int128_cmp (A, B);
+    case HAVE_DX_ADX:
+        /* A_dy * (A_x - B_x) â?? - (Y - A_y) * A_dx */
+        if ((-adx ^ dx) < 0) {
+            return dx;
+        } else {
+            cairo_int64_t ady_dx, dy_adx;
+
+            ady_dx = _cairo_int32x32_64_mul (ady, dx);
+            dy_adx = _cairo_int32x32_64_mul (a->edge.line.p1.y - y, adx);
+
+            return _cairo_int64_cmp (ady_dx, dy_adx);
+        }
+    case HAVE_DX_BDX:
+        /* B_dy * (A_x - B_x) â?? (Y - B_y) * B_dx */
+        if ((bdx ^ dx) < 0) {
+            return dx;
+        } else {
+            cairo_int64_t bdy_dx, dy_bdx;
+
+            bdy_dx = _cairo_int32x32_64_mul (bdy, dx);
+            dy_bdx = _cairo_int32x32_64_mul (y - b->edge.line.p1.y, bdx);
+
+            return _cairo_int64_cmp (bdy_dx, dy_bdx);
+        }
+    case HAVE_ALL:
+        /* XXX try comparing (a->edge.line.p2.x - b->edge.line.p2.x) et al */
+        return _cairo_int128_cmp (L, _cairo_int128_sub (B, A));
+    }
+#undef B
+#undef A
+#undef L
+}
+
+/*
+ * We need to compare the x-coordinate of a line for a particular y wrt to a
+ * given x, without loss of precision.
+ *
+ * The x-coordinate along an edge for a given y is:
+ *   X = A_x + (Y - A_y) * A_dx / A_dy
+ *
+ * So the inequality we wish to test is:
+ *   A_x + (Y - A_y) * A_dx / A_dy â?? X
+ * where â?? is our inequality operator.
+ *
+ * By construction, we know that A_dy (and (Y - A_y)) are
+ * all positive, so we can rearrange it thus without causing a sign change:
+ *   (Y - A_y) * A_dx â?? (X - A_x) * A_dy
+ *
+ * Given the assumption that all the deltas fit within 32 bits, we can compute
+ * this comparison directly using 64 bit arithmetic.
+ *
+ * See the similar discussion for _slope_compare() and
+ * edges_compare_x_for_y_general().
+ */
+static int
+edge_compare_for_y_against_x (const cairo_bo_edge_t *a,
+                              int32_t y,
+                              int32_t x)
+{
+    int32_t adx, ady;
+    int32_t dx, dy;
+    cairo_int64_t L, R;
+
+    if (x < a->edge.line.p1.x && x < a->edge.line.p2.x)
+        return 1;
+    if (x > a->edge.line.p1.x && x > a->edge.line.p2.x)
+        return -1;
+
+    adx = a->edge.line.p2.x - a->edge.line.p1.x;
+    dx = x - a->edge.line.p1.x;
+
+    if (adx == 0)
+        return -dx;
+    if (dx == 0 || (adx ^ dx) < 0)
+        return adx;
+
+    dy = y - a->edge.line.p1.y;
+    ady = a->edge.line.p2.y - a->edge.line.p1.y;
+
+    L = _cairo_int32x32_64_mul (dy, adx);
+    R = _cairo_int32x32_64_mul (dx, ady);
+
+    return _cairo_int64_cmp (L, R);
+}
+
+static int
+edges_compare_x_for_y (const cairo_bo_edge_t *a,
+                       const cairo_bo_edge_t *b,
+                       int32_t y)
+{
+    /* If the sweep-line is currently on an end-point of a line,
+     * then we know its precise x value (and considering that we often need to
+     * compare events at end-points, this happens frequently enough to warrant
+     * special casing).
+     */
+    enum {
+       HAVE_NEITHER = 0x0,
+       HAVE_AX      = 0x1,
+       HAVE_BX      = 0x2,
+       HAVE_BOTH    = HAVE_AX | HAVE_BX
+    } have_ax_bx = HAVE_BOTH;
+    int32_t ax, bx;
+
+    if (y == a->edge.line.p1.y)
+        ax = a->edge.line.p1.x;
+    else if (y == a->edge.line.p2.y)
+        ax = a->edge.line.p2.x;
+    else
+        have_ax_bx &= ~HAVE_AX;
+
+    if (y == b->edge.line.p1.y)
+        bx = b->edge.line.p1.x;
+    else if (y == b->edge.line.p2.y)
+        bx = b->edge.line.p2.x;
+    else
+        have_ax_bx &= ~HAVE_BX;
+
+    switch (have_ax_bx) {
+    default:
+    case HAVE_NEITHER:
+        return edges_compare_x_for_y_general (a, b, y);
+    case HAVE_AX:
+        return -edge_compare_for_y_against_x (b, y, ax);
+    case HAVE_BX:
+        return edge_compare_for_y_against_x (a, y, bx);
+    case HAVE_BOTH:
+        return ax - bx;
+    }
+}
+
+static inline int
+_line_equal (const cairo_line_t *a, const cairo_line_t *b)
+{
+    return a->p1.x == b->p1.x && a->p1.y == b->p1.y &&
+           a->p2.x == b->p2.x && a->p2.y == b->p2.y;
+}
+
+static int
+_cairo_bo_sweep_line_compare_edges (cairo_bo_sweep_line_t        *sweep_line,
+                                    const cairo_bo_edge_t        *a,
+                                    const cairo_bo_edge_t        *b)
+{
+    int cmp;
+
+    /* compare the edges if not identical */
+    if (! _line_equal (&a->edge.line, &b->edge.line)) {
+        cmp = edges_compare_x_for_y (a, b, sweep_line->current_y);
+        if (cmp)
+            return cmp;
+
+        /* The two edges intersect exactly at y, so fall back on slope
+         * comparison. We know that this compare_edges function will be
+         * called only when starting a new edge, (not when stopping an
+         * edge), so we don't have to worry about conditionally inverting
+         * the sense of _slope_compare. */
+        cmp = _slope_compare (a, b);
+        if (cmp)
+            return cmp;
+    }
+
+    /* We've got two collinear edges now. */
+    return b->edge.bottom - a->edge.bottom;
+}
+
+static inline cairo_int64_t
+det32_64 (int32_t a, int32_t b,
+          int32_t c, int32_t d)
+{
+    /* det = a * d - b * c */
+    return _cairo_int64_sub (_cairo_int32x32_64_mul (a, d),
+                             _cairo_int32x32_64_mul (b, c));
+}
+
+static inline cairo_int128_t
+det64x32_128 (cairo_int64_t a, int32_t       b,
+              cairo_int64_t c, int32_t       d)
+{
+    /* det = a * d - b * c */
+    return _cairo_int128_sub (_cairo_int64x32_128_mul (a, d),
+                              _cairo_int64x32_128_mul (c, b));
+}
+
+/* Compute the intersection of two lines as defined by two edges. The
+ * result is provided as a coordinate pair of 128-bit integers.
+ *
+ * Returns %CAIRO_BO_STATUS_INTERSECTION if there is an intersection or
+ * %CAIRO_BO_STATUS_PARALLEL if the two lines are exactly parallel.
+ */
+static cairo_bool_t
+intersect_lines (cairo_bo_edge_t                *a,
+                 cairo_bo_edge_t                *b,
+                 cairo_bo_intersect_point_t        *intersection)
+{
+    cairo_int64_t a_det, b_det;
+
+    /* XXX: We're assuming here that dx and dy will still fit in 32
+     * bits. That's not true in general as there could be overflow. We
+     * should prevent that before the tessellation algorithm begins.
+     * What we're doing to mitigate this is to perform clamping in
+     * cairo_bo_tessellate_polygon().
+     */
+    int32_t dx1 = a->edge.line.p1.x - a->edge.line.p2.x;
+    int32_t dy1 = a->edge.line.p1.y - a->edge.line.p2.y;
+
+    int32_t dx2 = b->edge.line.p1.x - b->edge.line.p2.x;
+    int32_t dy2 = b->edge.line.p1.y - b->edge.line.p2.y;
+
+    cairo_int64_t den_det;
+    cairo_int64_t R;
+    cairo_quorem64_t qr;
+
+    den_det = det32_64 (dx1, dy1, dx2, dy2);
+
+     /* Q: Can we determine that the lines do not intersect (within range)
+      * much more cheaply than computing the intersection point i.e. by
+      * avoiding the division?
+      *
+      *   X = ax + t * adx = bx + s * bdx;
+      *   Y = ay + t * ady = by + s * bdy;
+      *   â?´ t * (ady*bdx - bdy*adx) = bdx * (by - ay) + bdy * (ax - bx)
+      *   => t * L = R
+      *
+      * Therefore we can reject any intersection (under the criteria for
+      * valid intersection events) if:
+      *   L^R < 0 => t < 0, or
+      *   L<R => t > 1
+      *
+      * (where top/bottom must at least extend to the line endpoints).
+      *
+      * A similar substitution can be performed for s, yielding:
+      *   s * (ady*bdx - bdy*adx) = ady * (ax - bx) - adx * (ay - by)
+      */
+    R = det32_64 (dx2, dy2,
+                  b->edge.line.p1.x - a->edge.line.p1.x,
+                  b->edge.line.p1.y - a->edge.line.p1.y);
+    if (_cairo_int64_negative (den_det)) {
+        if (_cairo_int64_ge (den_det, R))
+            return FALSE;
+    } else {
+        if (_cairo_int64_le (den_det, R))
+            return FALSE;
+    }
+
+    R = det32_64 (dy1, dx1,
+                  a->edge.line.p1.y - b->edge.line.p1.y,
+                  a->edge.line.p1.x - b->edge.line.p1.x);
+    if (_cairo_int64_negative (den_det)) {
+        if (_cairo_int64_ge (den_det, R))
+            return FALSE;
+    } else {
+        if (_cairo_int64_le (den_det, R))
+            return FALSE;
+    }
+
+    /* We now know that the two lines should intersect within range. */
+
+    a_det = det32_64 (a->edge.line.p1.x, a->edge.line.p1.y,
+                      a->edge.line.p2.x, a->edge.line.p2.y);
+    b_det = det32_64 (b->edge.line.p1.x, b->edge.line.p1.y,
+                      b->edge.line.p2.x, b->edge.line.p2.y);
+
+    /* x = det (a_det, dx1, b_det, dx2) / den_det */
+    qr = _cairo_int_96by64_32x64_divrem (det64x32_128 (a_det, dx1,
+                                                       b_det, dx2),
+                                         den_det);
+    if (_cairo_int64_eq (qr.rem, den_det))
+        return FALSE;
+#if 0
+    intersection->x.exactness = _cairo_int64_is_zero (qr.rem) ? EXACT : INEXACT;
+#else
+    intersection->x.exactness = EXACT;
+    if (! _cairo_int64_is_zero (qr.rem)) {
+        if (_cairo_int64_negative (den_det) ^ _cairo_int64_negative (qr.rem))
+            qr.rem = _cairo_int64_negate (qr.rem);
+        qr.rem = _cairo_int64_mul (qr.rem, _cairo_int32_to_int64 (2));
+        if (_cairo_int64_ge (qr.rem, den_det)) {
+            qr.quo = _cairo_int64_add (qr.quo,
+                                       _cairo_int32_to_int64 (_cairo_int64_negative (qr.quo) ? -1 : 1));
+        } else
+            intersection->x.exactness = INEXACT;
+    }
+#endif
+    intersection->x.ordinate = _cairo_int64_to_int32 (qr.quo);
+
+    /* y = det (a_det, dy1, b_det, dy2) / den_det */
+    qr = _cairo_int_96by64_32x64_divrem (det64x32_128 (a_det, dy1,
+                                                       b_det, dy2),
+                                         den_det);
+    if (_cairo_int64_eq (qr.rem, den_det))
+        return FALSE;
+#if 0
+    intersection->y.exactness = _cairo_int64_is_zero (qr.rem) ? EXACT : INEXACT;
+#else
+    intersection->y.exactness = EXACT;
+    if (! _cairo_int64_is_zero (qr.rem)) {
+        if (_cairo_int64_negative (den_det) ^ _cairo_int64_negative (qr.rem))
+            qr.rem = _cairo_int64_negate (qr.rem);
+        qr.rem = _cairo_int64_mul (qr.rem, _cairo_int32_to_int64 (2));
+        if (_cairo_int64_ge (qr.rem, den_det)) {
+            qr.quo = _cairo_int64_add (qr.quo,
+                                       _cairo_int32_to_int64 (_cairo_int64_negative (qr.quo) ? -1 : 1));
+        } else
+            intersection->y.exactness = INEXACT;
+    }
+#endif
+    intersection->y.ordinate = _cairo_int64_to_int32 (qr.quo);
+
+    return TRUE;
+}
+
+static int
+_cairo_bo_intersect_ordinate_32_compare (cairo_bo_intersect_ordinate_t        a,
+                                         int32_t                        b)
+{
+    /* First compare the quotient */
+    if (a.ordinate > b)
+        return +1;
+    if (a.ordinate < b)
+        return -1;
+    /* With quotient identical, if remainder is 0 then compare equal */
+    /* Otherwise, the non-zero remainder makes a > b */
+    return INEXACT == a.exactness;
+}
+
+/* Does the given edge contain the given point. The point must already
+ * be known to be contained within the line determined by the edge,
+ * (most likely the point results from an intersection of this edge
+ * with another).
+ *
+ * If we had exact arithmetic, then this function would simply be a
+ * matter of examining whether the y value of the point lies within
+ * the range of y values of the edge. But since intersection points
+ * are not exact due to being rounded to the nearest integer within
+ * the available precision, we must also examine the x value of the
+ * point.
+ *
+ * The definition of "contains" here is that the given intersection
+ * point will be seen by the sweep line after the start event for the
+ * given edge and before the stop event for the edge. See the comments
+ * in the implementation for more details.
+ */
+static cairo_bool_t
+_cairo_bo_edge_contains_intersect_point (cairo_bo_edge_t                *edge,
+                                         cairo_bo_intersect_point_t        *point)
+{
+    int cmp_top, cmp_bottom;
+
+    /* XXX: When running the actual algorithm, we don't actually need to
+     * compare against edge->top at all here, since any intersection above
+     * top is eliminated early via a slope comparison. We're leaving these
+     * here for now only for the sake of the quadratic-time intersection
+     * finder which needs them.
+     */
+
+    cmp_top = _cairo_bo_intersect_ordinate_32_compare (point->y,
+                                                       edge->edge.top);
+    cmp_bottom = _cairo_bo_intersect_ordinate_32_compare (point->y,
+                                                          edge->edge.bottom);
+
+    if (cmp_top < 0 || cmp_bottom > 0)
+    {
+        return FALSE;
+    }
+
+    if (cmp_top > 0 && cmp_bottom < 0)
+    {
+        return TRUE;
+    }
+
+    /* At this stage, the point lies on the same y value as either
+     * edge->top or edge->bottom, so we have to examine the x value in
+     * order to properly determine containment. */
+
+    /* If the y value of the point is the same as the y value of the
+     * top of the edge, then the x value of the point must be greater
+     * to be considered as inside the edge. Similarly, if the y value
+     * of the point is the same as the y value of the bottom of the
+     * edge, then the x value of the point must be less to be
+     * considered as inside. */
+
+    if (cmp_top == 0) {
+        cairo_fixed_t top_x;
+
+        top_x = _line_compute_intersection_x_for_y (&edge->edge.line,
+                                                    edge->edge.top);
+        return _cairo_bo_intersect_ordinate_32_compare (point->x, top_x) > 0;
+    } else { /* cmp_bottom == 0 */
+        cairo_fixed_t bot_x;
+
+        bot_x = _line_compute_intersection_x_for_y (&edge->edge.line,
+                                                    edge->edge.bottom);
+        return _cairo_bo_intersect_ordinate_32_compare (point->x, bot_x) < 0;
+    }
+}
+
+/* Compute the intersection of two edges. The result is provided as a
+ * coordinate pair of 128-bit integers.
+ *
+ * Returns %CAIRO_BO_STATUS_INTERSECTION if there is an intersection
+ * that is within both edges, %CAIRO_BO_STATUS_NO_INTERSECTION if the
+ * intersection of the lines defined by the edges occurs outside of
+ * one or both edges, and %CAIRO_BO_STATUS_PARALLEL if the two edges
+ * are exactly parallel.
+ *
+ * Note that when determining if a candidate intersection is "inside"
+ * an edge, we consider both the infinitesimal shortening and the
+ * infinitesimal tilt rules described by John Hobby. Specifically, if
+ * the intersection is exactly the same as an edge point, it is
+ * effectively outside (no intersection is returned). Also, if the
+ * intersection point has the same
+ */
+static cairo_bool_t
+_cairo_bo_edge_intersect (cairo_bo_edge_t        *a,
+                          cairo_bo_edge_t        *b,
+                          cairo_bo_point32_t        *intersection)
+{
+    cairo_bo_intersect_point_t quorem;
+
+    if (! intersect_lines (a, b, &quorem))
+        return FALSE;
+
+    if (! _cairo_bo_edge_contains_intersect_point (a, &quorem))
+        return FALSE;
+
+    if (! _cairo_bo_edge_contains_intersect_point (b, &quorem))
+        return FALSE;
+
+    /* Now that we've correctly compared the intersection point and
+     * determined that it lies within the edge, then we know that we
+     * no longer need any more bits of storage for the intersection
+     * than we do for our edge coordinates. We also no longer need the
+     * remainder from the division. */
+    intersection->x = quorem.x.ordinate;
+    intersection->y = quorem.y.ordinate;
+
+    return TRUE;
+}
+
+static inline int
+cairo_bo_event_compare (const cairo_bo_event_t *a,
+                        const cairo_bo_event_t *b)
+{
+    int cmp;
+
+    cmp = _cairo_bo_point32_compare (&a->point, &b->point);
+    if (cmp)
+        return cmp;
+
+    cmp = a->type - b->type;
+    if (cmp)
+        return cmp;
+
+    return a - b;
+}
+
+static inline void
+_pqueue_init (pqueue_t *pq)
+{
+    pq->max_size = ARRAY_LENGTH (pq->elements_embedded);
+    pq->size = 0;
+
+    pq->elements = pq->elements_embedded;
+}
+
+static inline void
+_pqueue_fini (pqueue_t *pq)
+{
+    if (pq->elements != pq->elements_embedded)
+        free (pq->elements);
+}
+
+static cairo_status_t
+_pqueue_grow (pqueue_t *pq)
+{
+    cairo_bo_event_t **new_elements;
+    pq->max_size *= 2;
+
+    if (pq->elements == pq->elements_embedded) {
+        new_elements = _cairo_malloc_ab (pq->max_size,
+                                         sizeof (cairo_bo_event_t *));
+        if (unlikely (new_elements == NULL))
+            return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+        memcpy (new_elements, pq->elements_embedded,
+                sizeof (pq->elements_embedded));
+    } else {
+        new_elements = _cairo_realloc_ab (pq->elements,
+                                          pq->max_size,
+                                          sizeof (cairo_bo_event_t *));
+        if (unlikely (new_elements == NULL))
+            return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+    }
+
+    pq->elements = new_elements;
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static inline cairo_status_t
+_pqueue_push (pqueue_t *pq, cairo_bo_event_t *event)
+{
+    cairo_bo_event_t **elements;
+    int i, parent;
+
+    if (unlikely (pq->size + 1 == pq->max_size)) {
+        cairo_status_t status;
+
+        status = _pqueue_grow (pq);
+        if (unlikely (status))
+            return status;
+    }
+
+    elements = pq->elements;
+
+    for (i = ++pq->size;
+         i != PQ_FIRST_ENTRY &&
+         cairo_bo_event_compare (event,
+                                 elements[parent = PQ_PARENT_INDEX (i)]) < 0;
+         i = parent)
+    {
+        elements[i] = elements[parent];
+    }
+
+    elements[i] = event;
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static inline void
+_pqueue_pop (pqueue_t *pq)
+{
+    cairo_bo_event_t **elements = pq->elements;
+    cairo_bo_event_t *tail;
+    int child, i;
+
+    tail = elements[pq->size--];
+    if (pq->size == 0) {
+        elements[PQ_FIRST_ENTRY] = NULL;
+        return;
+    }
+
+    for (i = PQ_FIRST_ENTRY;
+         (child = PQ_LEFT_CHILD_INDEX (i)) <= pq->size;
+         i = child)
+    {
+        if (child != pq->size &&
+            cairo_bo_event_compare (elements[child+1],
+                                    elements[child]) < 0)
+        {
+            child++;
+        }
+
+        if (cairo_bo_event_compare (elements[child], tail) >= 0)
+            break;
+
+        elements[i] = elements[child];
+    }
+    elements[i] = tail;
+}
+
+static inline cairo_status_t
+_cairo_bo_event_queue_insert (cairo_bo_event_queue_t        *queue,
+                              cairo_bo_event_type_t         type,
+                              cairo_bo_edge_t                *e1,
+                              cairo_bo_edge_t                *e2,
+                              const cairo_point_t         *point)
+{
+    cairo_bo_queue_event_t *event;
+
+    event = _cairo_freepool_alloc (&queue->pool);
+    if (unlikely (event == NULL))
+        return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+    event->type = type;
+    event->e1 = e1;
+    event->e2 = e2;
+    event->point = *point;
+
+    return _pqueue_push (&queue->pqueue, (cairo_bo_event_t *) event);
+}
+
+static void
+_cairo_bo_event_queue_delete (cairo_bo_event_queue_t *queue,
+                              cairo_bo_event_t             *event)
+{
+    _cairo_freepool_free (&queue->pool, event);
+}
+
+static cairo_bo_event_t *
+_cairo_bo_event_dequeue (cairo_bo_event_queue_t *event_queue)
+{
+    cairo_bo_event_t *event, *cmp;
+
+    event = event_queue->pqueue.elements[PQ_FIRST_ENTRY];
+    cmp = *event_queue->start_events;
+    if (event == NULL ||
+        (cmp != NULL && cairo_bo_event_compare (cmp, event) < 0))
+    {
+        event = cmp;
+        event_queue->start_events++;
+    }
+    else
+    {
+        _pqueue_pop (&event_queue->pqueue);
+    }
+
+    return event;
+}
+
+CAIRO_COMBSORT_DECLARE (_cairo_bo_event_queue_sort,
+                        cairo_bo_event_t *,
+                        cairo_bo_event_compare)
+
+static void
+_cairo_bo_event_queue_init (cairo_bo_event_queue_t         *event_queue,
+                            cairo_bo_event_t                **start_events,
+                            int                                  num_events)
+{
+    _cairo_bo_event_queue_sort (start_events, num_events);
+    start_events[num_events] = NULL;
+
+    event_queue->start_events = start_events;
+
+    _cairo_freepool_init (&event_queue->pool,
+                          sizeof (cairo_bo_queue_event_t));
+    _pqueue_init (&event_queue->pqueue);
+    event_queue->pqueue.elements[PQ_FIRST_ENTRY] = NULL;
+}
+
+static cairo_status_t
+_cairo_bo_event_queue_insert_stop (cairo_bo_event_queue_t        *event_queue,
+                                   cairo_bo_edge_t                *edge)
+{
+    cairo_bo_point32_t point;
+
+    point.y = edge->edge.bottom;
+    point.x = _line_compute_intersection_x_for_y (&edge->edge.line,
+                                                  point.y);
+    return _cairo_bo_event_queue_insert (event_queue,
+                                         CAIRO_BO_EVENT_TYPE_STOP,
+                                         edge, NULL,
+                                         &point);
+}
+
+static void
+_cairo_bo_event_queue_fini (cairo_bo_event_queue_t *event_queue)
+{
+    _pqueue_fini (&event_queue->pqueue);
+    _cairo_freepool_fini (&event_queue->pool);
+}
+
+static inline cairo_status_t
+_cairo_bo_event_queue_insert_if_intersect_below_current_y (cairo_bo_event_queue_t        *event_queue,
+                                                           cairo_bo_edge_t        *left,
+                                                           cairo_bo_edge_t *right)
+{
+    cairo_bo_point32_t intersection;
+
+    if (_line_equal (&left->edge.line, &right->edge.line))
+        return CAIRO_STATUS_SUCCESS;
+
+    /* The names "left" and "right" here are correct descriptions of
+     * the order of the two edges within the active edge list. So if a
+     * slope comparison also puts left less than right, then we know
+     * that the intersection of these two segments has already
+     * occurred before the current sweep line position. */
+    if (_slope_compare (left, right) <= 0)
+        return CAIRO_STATUS_SUCCESS;
+
+    if (! _cairo_bo_edge_intersect (left, right, &intersection))
+        return CAIRO_STATUS_SUCCESS;
+
+    return _cairo_bo_event_queue_insert (event_queue,
+                                         CAIRO_BO_EVENT_TYPE_INTERSECTION,
+                                         left, right,
+                                         &intersection);
+}
+
+static void
+_cairo_bo_sweep_line_init (cairo_bo_sweep_line_t *sweep_line)
+{
+    sweep_line->head = NULL;
+    sweep_line->stopped = NULL;
+    sweep_line->current_y = INT32_MIN;
+    sweep_line->current_edge = NULL;
+}
+
+static cairo_status_t
+_cairo_bo_sweep_line_insert (cairo_bo_sweep_line_t        *sweep_line,
+                             cairo_bo_edge_t                *edge)
+{
+    if (sweep_line->current_edge != NULL) {
+        cairo_bo_edge_t *prev, *next;
+        int cmp;
+
+        cmp = _cairo_bo_sweep_line_compare_edges (sweep_line,
+                                                  sweep_line->current_edge,
+                                                  edge);
+        if (cmp < 0) {
+            prev = sweep_line->current_edge;
+            next = prev->next;
+            while (next != NULL &&
+                   _cairo_bo_sweep_line_compare_edges (sweep_line,
+                                                       next, edge) < 0)
+            {
+                prev = next, next = prev->next;
+            }
+
+            prev->next = edge;
+            edge->prev = prev;
+            edge->next = next;
+            if (next != NULL)
+                next->prev = edge;
+        } else if (cmp > 0) {
+            next = sweep_line->current_edge;
+            prev = next->prev;
+            while (prev != NULL &&
+                   _cairo_bo_sweep_line_compare_edges (sweep_line,
+                                                       prev, edge) > 0)
+            {
+                next = prev, prev = next->prev;
+            }
+
+            next->prev = edge;
+            edge->next = next;
+            edge->prev = prev;
+            if (prev != NULL)
+                prev->next = edge;
+            else
+                sweep_line->head = edge;
+        } else {
+            prev = sweep_line->current_edge;
+            edge->prev = prev;
+            edge->next = prev->next;
+            if (prev->next != NULL)
+                prev->next->prev = edge;
+            prev->next = edge;
+        }
+    } else {
+        sweep_line->head = edge;
+    }
+
+    sweep_line->current_edge = edge;
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+_cairo_bo_sweep_line_delete (cairo_bo_sweep_line_t        *sweep_line,
+                             cairo_bo_edge_t        *edge)
+{
+    if (edge->prev != NULL)
+        edge->prev->next = edge->next;
+    else
+        sweep_line->head = edge->next;
+
+    if (edge->next != NULL)
+        edge->next->prev = edge->prev;
+
+    if (sweep_line->current_edge == edge)
+        sweep_line->current_edge = edge->prev ? edge->prev : edge->next;
+}
+
+static void
+_cairo_bo_sweep_line_swap (cairo_bo_sweep_line_t        *sweep_line,
+                           cairo_bo_edge_t                *left,
+                           cairo_bo_edge_t                *right)
+{
+    if (left->prev != NULL)
+        left->prev->next = right;
+    else
+        sweep_line->head = right;
+
+    if (right->next != NULL)
+        right->next->prev = left;
+
+    left->next = right->next;
+    right->next = left;
+
+    right->prev = left->prev;
+    left->prev = right;
+}
+
+#if DEBUG_PRINT_STATE
+static void
+_cairo_bo_edge_print (cairo_bo_edge_t *edge)
+{
+    printf ("(%d, %d)-(%d, %d)",
+            edge->edge.line.p1.x, edge->edge.line.p1.y,
+            edge->edge.line.p2.x, edge->edge.line.p2.y);
+}
+
+static void
+_cairo_bo_event_print (cairo_bo_event_t *event)
+{
+    switch (event->type) {
+    case CAIRO_BO_EVENT_TYPE_START:
+        printf ("Start: ");
+        break;
+    case CAIRO_BO_EVENT_TYPE_STOP:
+        printf ("Stop: ");
+        break;
+    case CAIRO_BO_EVENT_TYPE_INTERSECTION:
+        printf ("Intersection: ");
+        break;
+    }
+    printf ("(%d, %d)\t", event->point.x, event->point.y);
+    _cairo_bo_edge_print (((cairo_bo_queue_event_t *)event)->e1);
+    if (event->type == CAIRO_BO_EVENT_TYPE_INTERSECTION) {
+        printf (" X ");
+        _cairo_bo_edge_print (((cairo_bo_queue_event_t *)event)->e2);
+    }
+    printf ("\n");
+}
+
+static void
+_cairo_bo_event_queue_print (cairo_bo_event_queue_t *event_queue)
+{
+    /* XXX: fixme to print the start/stop array too. */
+    printf ("Event queue:\n");
+}
+
+static void
+_cairo_bo_sweep_line_print (cairo_bo_sweep_line_t *sweep_line)
+{
+    cairo_bool_t first = TRUE;
+    cairo_bo_edge_t *edge;
+
+    printf ("Sweep line from edge list: ");
+    first = TRUE;
+    for (edge = sweep_line->head;
+         edge;
+         edge = edge->next)
+    {
+        if (!first)
+            printf (", ");
+        _cairo_bo_edge_print (edge);
+        first = FALSE;
+    }
+    printf ("\n");
+}
+
+static void
+print_state (const char                        *msg,
+             cairo_bo_event_t                *event,
+             cairo_bo_event_queue_t        *event_queue,
+             cairo_bo_sweep_line_t        *sweep_line)
+{
+    printf ("%s ", msg);
+    _cairo_bo_event_print (event);
+    _cairo_bo_event_queue_print (event_queue);
+    _cairo_bo_sweep_line_print (sweep_line);
+    printf ("\n");
+}
+#endif
+
+#if DEBUG_EVENTS
+static void CAIRO_PRINTF_FORMAT (1, 2)
+event_log (const char *fmt, ...)
+{
+    FILE *file;
+
+    if (getenv ("CAIRO_DEBUG_EVENTS") == NULL)
+        return;
+
+    file = fopen ("bo-events.txt", "a");
+    if (file != NULL) {
+        va_list ap;
+
+        va_start (ap, fmt);
+        vfprintf (file, fmt, ap);
+        va_end (ap);
+
+        fclose (file);
+    }
+}
+#endif
+
+static inline cairo_bool_t
+edges_colinear (const cairo_bo_edge_t *a, const cairo_bo_edge_t *b)
+{
+    if (_line_equal (&a->edge.line, &b->edge.line))
+        return TRUE;
+
+    if (_slope_compare (a, b))
+        return FALSE;
+
+    /* The choice of y is not truly arbitrary since we must guarantee that it
+     * is greater than the start of either line.
+     */
+    if (a->edge.line.p1.y == b->edge.line.p1.y) {
+        return a->edge.line.p1.x == b->edge.line.p1.x;
+    } else if (a->edge.line.p1.y < b->edge.line.p1.y) {
+        return edge_compare_for_y_against_x (b,
+                                             a->edge.line.p1.y,
+                                             a->edge.line.p1.x) == 0;
+    } else {
+        return edge_compare_for_y_against_x (a,
+                                             b->edge.line.p1.y,
+                                             b->edge.line.p1.x) == 0;
+    }
+}
+
+/* Adds the trapezoid, if any, of the left edge to the #cairo_traps_t */
+static cairo_status_t
+_cairo_bo_edge_end_trap (cairo_bo_edge_t        *left,
+                         int32_t                 bot,
+                         cairo_traps_t          *traps)
+{
+    cairo_bo_trap_t *trap = &left->deferred_trap;
+
+    /* Only emit (trivial) non-degenerate trapezoids with positive height. */
+    if (likely (trap->top < bot)) {
+        _cairo_traps_add_trap (traps,
+                               trap->top, bot,
+                               &left->edge.line, &trap->right->edge.line);
+
+#if DEBUG_PRINT_STATE
+        printf ("Deferred trap: left=(%d, %d)-(%d,%d) "
+                "right=(%d,%d)-(%d,%d) top=%d, bot=%d\n",
+                left->edge.line.p1.x, left->edge.line.p1.y,
+                left->edge.line.p2.x, left->edge.line.p2.y,
+                trap->right->edge.line.p1.x, trap->right->edge.line.p1.y,
+                trap->right->edge.line.p2.x, trap->right->edge.line.p2.y,
+                trap->top, bot);
+#endif
+#if DEBUG_EVENTS
+        event_log ("end trap: %lu %lu %d %d\n",
+                   (long) left,
+                   (long) trap->right,
+                   trap->top,
+                   bot);
+#endif
+    }
+
+    trap->right = NULL;
+
+//    return _cairo_traps_status (traps);
+    return 0;
+}
+
+
+/* Start a new trapezoid at the given top y coordinate, whose edges
+ * are `edge' and `edge->next'. If `edge' already has a trapezoid,
+ * then either add it to the traps in `traps', if the trapezoid's
+ * right edge differs from `edge->next', or do nothing if the new
+ * trapezoid would be a continuation of the existing one. */
+static inline cairo_status_t
+_cairo_bo_edge_start_or_continue_trap (cairo_bo_edge_t        *left,
+                                       cairo_bo_edge_t  *right,
+                                       int               top,
+                                       cairo_traps_t        *traps)
+{
+    cairo_status_t status;
+    if (left->deferred_trap.right == right) {
+        return CAIRO_STATUS_SUCCESS;
+    }
+
+    if (left->deferred_trap.right != NULL) {
+        if (right != NULL && edges_colinear (left->deferred_trap.right, right))
+        {
+            /* continuation on right, so just swap edges */
+            left->deferred_trap.right = right;
+            return CAIRO_STATUS_SUCCESS;
+        }
+
+        status = _cairo_bo_edge_end_trap (left, top, traps);
+        if (unlikely (status))
+            return status;
+    }
+
+    if (right != NULL && ! edges_colinear (left, right)) {
+        left->deferred_trap.top = top;
+        left->deferred_trap.right = right;
+
+#if DEBUG_EVENTS
+        event_log ("begin trap: %lu %lu %d\n",
+                   (long) left,
+                   (long) right,
+                   top);
+#endif
+    }
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static inline cairo_status_t
+_active_edges_to_traps (cairo_bo_edge_t		*left,
+			int32_t			 top,
+			cairo_fill_rule_t	 fill_rule,
+			cairo_traps_t	        *traps)
+{
+    cairo_bo_edge_t *right;
+    cairo_status_t status;
+
+#if DEBUG_PRINT_STATE
+    printf ("Processing active edges for %d\n", top);
+#endif
+
+    if (fill_rule == CAIRO_FILL_RULE_WINDING) {
+	while (left != NULL) {
+	    int in_out;
+
+	    /* Greedily search for the closing edge, so that we generate the
+	     * maximal span width with the minimal number of trapezoids.
+	     */
+	    in_out = left->edge.dir;
+
+	    /* Check if there is a co-linear edge with an existing trap */
+	    right = left->next;
+	    if (left->deferred_trap.right == NULL) {
+		while (right != NULL && right->deferred_trap.right == NULL)
+		    right = right->next;
+
+		if (right != NULL && edges_colinear (left, right)) {
+		    /* continuation on left */
+		    left->deferred_trap = right->deferred_trap;
+		    right->deferred_trap.right = NULL;
+		}
+	    }
+
+	    /* End all subsumed traps */
+	    right = left->next;
+	    while (right != NULL) {
+		if (right->deferred_trap.right != NULL) {
+		    status = _cairo_bo_edge_end_trap (right, top, traps);
+		    if (unlikely (status))
+			return status;
+		}
+
+		in_out += right->edge.dir;
+		if (in_out == 0) {
+		    cairo_bo_edge_t *next;
+		    cairo_bool_t skip = FALSE;
+
+		    /* skip co-linear edges */
+		    next = right->next;
+		    if (next != NULL)
+			skip = edges_colinear (right, next);
+
+		    if (! skip)
+			break;
+		}
+
+		right = right->next;
+	    }
+
+	    status = _cairo_bo_edge_start_or_continue_trap (left, right,
+							    top, traps);
+	    if (unlikely (status))
+		return status;
+
+	    left = right;
+	    if (left != NULL)
+		left = left->next;
+	}
+    } else {
+	while (left != NULL) {
+	    int in_out = 0;
+
+	    right = left->next;
+	    while (right != NULL) {
+		if (right->deferred_trap.right != NULL) {
+		    status = _cairo_bo_edge_end_trap (right, top, traps);
+		    if (unlikely (status))
+			return status;
+		}
+
+		if ((in_out++ & 1) == 0) {
+		    cairo_bo_edge_t *next;
+		    cairo_bool_t skip = FALSE;
+
+		    /* skip co-linear edges */
+		    next = right->next;
+		    if (next != NULL)
+			skip = edges_colinear (right, next);
+
+		    if (! skip)
+			break;
+		}
+
+		right = right->next;
+	    }
+
+	    status = _cairo_bo_edge_start_or_continue_trap (left, right,
+							    top, traps);
+	    if (unlikely (status))
+		return status;
+
+	    left = right;
+	    if (left != NULL)
+		left = left->next;
+	}
+    }
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+/* Execute a single pass of the Bentley-Ottmann algorithm on edges,
+ * generating trapezoids according to the fill_rule and appending them
+ * to traps. */
+static cairo_status_t
+_cairo_bentley_ottmann_tessellate_bo_edges (cairo_bo_event_t   **start_events,
+                                            int                  num_events,
+                                            cairo_traps_t       *traps,
+                                            int                 *num_intersections)
+{
+    cairo_status_t status = CAIRO_STATUS_SUCCESS; /* silence compiler */
+    int intersection_count = 0;
+    cairo_bo_event_queue_t event_queue;
+    cairo_bo_sweep_line_t sweep_line;
+    cairo_bo_event_t *event;
+    cairo_bo_edge_t *left, *right;
+    cairo_bo_edge_t *e1, *e2;
+
+#if DEBUG_EVENTS
+    {
+        int i;
+
+        for (i = 0; i < num_events; i++) {
+            cairo_bo_start_event_t *event =
+                ((cairo_bo_start_event_t **) start_events)[i];
+            event_log ("edge: %lu (%d, %d) (%d, %d) (%d, %d) %d\n",
+//                       (long) &events[i].edge,
+                       (long) 666,
+                       event->edge.edge.line.p1.x,
+                       event->edge.edge.line.p1.y,
+                       event->edge.edge.line.p2.x,
+                       event->edge.edge.line.p2.y,
+                       event->edge.edge.top,
+                       event->edge.edge.bottom,
+                       event->edge.edge.dir);
+        }
+    }
+#endif
+
+    _cairo_bo_event_queue_init (&event_queue, start_events, num_events);
+    _cairo_bo_sweep_line_init (&sweep_line);
+
+    while ((event = _cairo_bo_event_dequeue (&event_queue))) {
+        if (event->point.y != sweep_line.current_y) {
+            for (e1 = sweep_line.stopped; e1; e1 = e1->next) {
+                if (e1->deferred_trap.right != NULL) {
+                    status = _cairo_bo_edge_end_trap (e1,
+                                                      e1->edge.bottom,
+                                                      traps);
+                    if (unlikely (status))
+                        goto unwind;
+                }
+            }
+            sweep_line.stopped = NULL;
+
+            status = _active_edges_to_traps (sweep_line.head,
+                                             sweep_line.current_y,
+//                                             CAIRO_FILL_RULE_WINDING,
+                                             CAIRO_FILL_RULE_EVEN_ODD,
+                                             traps);
+            if (unlikely (status))
+                goto unwind;
+
+            sweep_line.current_y = event->point.y;
+        }
+
+#if DEBUG_EVENTS
+        event_log ("event: %d (%ld, %ld) %lu, %lu\n",
+                   event->type,
+                   (long) event->point.x,
+                   (long) event->point.y,
+                   (long) ((cairo_bo_queue_event_t *)event)->e1,
+                   (long) ((cairo_bo_queue_event_t *)event)->e2);
+#endif
+
+        switch (event->type) {
+        case CAIRO_BO_EVENT_TYPE_START:
+            e1 = &((cairo_bo_start_event_t *) event)->edge;
+
+            status = _cairo_bo_sweep_line_insert (&sweep_line, e1);
+            if (unlikely (status))
+                goto unwind;
+
+            status = _cairo_bo_event_queue_insert_stop (&event_queue, e1);
+            if (unlikely (status))
+                goto unwind;
+
+            /* check to see if this is a continuation of a stopped edge */
+            /* XXX change to an infinitesimal lengthening rule */
+            for (left = sweep_line.stopped; left; left = left->next) {
+                if (e1->edge.top <= left->edge.bottom &&
+                    edges_colinear (e1, left))
+                {
+                    e1->deferred_trap = left->deferred_trap;
+                    if (left->prev != NULL)
+                        left->prev = left->next;
+                    else
+                        sweep_line.stopped = left->next;
+                    if (left->next != NULL)
+                        left->next->prev = left->prev;
+                    break;
+                }
+            }
+
+            left = e1->prev;
+            right = e1->next;
+
+            if (left != NULL) {
+                status = _cairo_bo_event_queue_insert_if_intersect_below_current_y (&event_queue, left, e1);
+                if (unlikely (status))
+                    goto unwind;
+            }
+
+            if (right != NULL) {
+                status = _cairo_bo_event_queue_insert_if_intersect_below_current_y (&event_queue, e1, right);
+                if (unlikely (status))
+                    goto unwind;
+            }
+
+            break;
+
+        case CAIRO_BO_EVENT_TYPE_STOP:
+            e1 = ((cairo_bo_queue_event_t *) event)->e1;
+            _cairo_bo_event_queue_delete (&event_queue, event);
+
+            left = e1->prev;
+            right = e1->next;
+
+            _cairo_bo_sweep_line_delete (&sweep_line, e1);
+
+            /* first, check to see if we have a continuation via a fresh edge */
+            if (e1->deferred_trap.right != NULL) {
+                e1->next = sweep_line.stopped;
+                if (sweep_line.stopped != NULL)
+                    sweep_line.stopped->prev = e1;
+                sweep_line.stopped = e1;
+                e1->prev = NULL;
+            }
+
+            if (left != NULL && right != NULL) {
+                status = _cairo_bo_event_queue_insert_if_intersect_below_current_y (&event_queue, left, right);
+                if (unlikely (status))
+                    goto unwind;
+            }
+
+            break;
+
+        case CAIRO_BO_EVENT_TYPE_INTERSECTION:
+            break;
+            printf ("Intersection event\n");
+            e1 = ((cairo_bo_queue_event_t *) event)->e1;
+            e2 = ((cairo_bo_queue_event_t *) event)->e2;
+            _cairo_bo_event_queue_delete (&event_queue, event);
+
+            /* skip this intersection if its edges are not adjacent */
+            if (e2 != e1->next)
+                break;
+
+            intersection_count++;
+
+            left = e1->prev;
+            right = e2->next;
+
+            _cairo_bo_sweep_line_swap (&sweep_line, e1, e2);
+
+            /* after the swap e2 is left of e1 */
+
+            if (left != NULL) {
+                status = _cairo_bo_event_queue_insert_if_intersect_below_current_y (&event_queue, left, e2);
+                if (unlikely (status))
+                    goto unwind;
+            }
+
+            if (right != NULL) {
+                status = _cairo_bo_event_queue_insert_if_intersect_below_current_y (&event_queue, e1, right);
+                if (unlikely (status))
+                    goto unwind;
+            }
+
+            break;
+        }
+    }
+
+    *num_intersections = intersection_count;
+    for (e1 = sweep_line.stopped; e1; e1 = e1->next) {
+        if (e1->deferred_trap.right != NULL) {
+            status = _cairo_bo_edge_end_trap (e1, e1->edge.bottom, traps);
+            if (unlikely (status))
+                break;
+        }
+    }
+ unwind:
+    _cairo_bo_event_queue_fini (&event_queue);
+
+#if DEBUG_EVENTS
+    event_log ("\n");
+#endif
+
+    return status;
+}
+
+static void
+contour_to_start_events (PLINE                   *contour,
+                         cairo_bo_start_event_t  *events,
+                         cairo_bo_event_t       **event_ptrs,
+                         int                     *counter,
+                         int                      outer_contour)
+{
+    int i = *counter;
+    VNODE *bv;
+
+    /* Loop over nodes, adding edges */
+    bv = &contour->head;
+    do {
+      int x1, y1, x2, y2;
+      cairo_edge_t cairo_edge;
+      /* Node is between bv->point[0,1] and bv->next->point[0,1] */
+
+      if (bv->point[1] == bv->next->point[1]) {
+          if (bv->point[0] < bv->next->point[0]) {
+            x1 = bv->point[0];
+            y1 = bv->point[1];
+            x2 = bv->next->point[0];
+            y2 = bv->next->point[1];
+          } else {
+            x1 = bv->next->point[0];
+            y1 = bv->next->point[1];
+            x2 = bv->point[0];
+            y2 = bv->point[1];
+          }
+      } else if (bv->point[1] < bv->next->point[1]) {
+        x1 = bv->point[0];
+        y1 = bv->point[1];
+        x2 = bv->next->point[0];
+        y2 = bv->next->point[1];
+      } else {
+        x1 = bv->next->point[0];
+        y1 = bv->next->point[1];
+        x2 = bv->point[0];
+        y2 = bv->point[1];
+      }
+
+      cairo_edge.line.p1.x = x1;
+      cairo_edge.line.p1.y = y1;
+      cairo_edge.line.p2.x = x2;
+      cairo_edge.line.p2.y = y2;
+      cairo_edge.top = y1;
+      cairo_edge.bottom = y2;
+      cairo_edge.dir = outer_contour ? 1 : -1;
+
+      event_ptrs[i] = (cairo_bo_event_t *) &events[i];
+
+      events[i].type = CAIRO_BO_EVENT_TYPE_START;
+      events[i].point.y = cairo_edge.line.p1.y;
+      events[i].point.x = cairo_edge.line.p1.x;
+
+      events[i].edge.edge = cairo_edge;
+      events[i].edge.deferred_trap.right = NULL;
+      events[i].edge.prev = NULL;
+      events[i].edge.next = NULL;
+      i++;
+
+    } while ((bv = bv->next) != &contour->head);
+
+    *counter = i;
+}
+
+
+static void
+poly_area_to_start_events (POLYAREA                *poly,
+                           cairo_bo_start_event_t  *events,
+                           cairo_bo_event_t       **event_ptrs,
+                           int                     *counter)
+{
+    int i = *counter;
+    PLINE *contour;
+    POLYAREA *pa;
+    int outer_contour;
+
+    pa = poly;
+    do {
+      /* Loop over contours */
+      outer_contour = 1;
+      for (contour = pa->contours; contour != NULL; contour = contour->next) {
+        contour_to_start_events (contour, events, event_ptrs,
+                                 counter, outer_contour);
+        outer_contour = 0;
+      }
+
+    } while ((pa = pa->f) != poly);
+
+    *counter = i;
+}
+
+
+cairo_status_t
+bo_poly_to_traps (POLYAREA *poly, cairo_traps_t *traps)
+{
+  int intersections;
+  cairo_status_t status;
+  cairo_bo_start_event_t stack_events[CAIRO_STACK_ARRAY_LENGTH (cairo_bo_start_event_t)];
+  cairo_bo_start_event_t *events;
+  cairo_bo_event_t *stack_event_ptrs[ARRAY_LENGTH (stack_events) + 1];
+  cairo_bo_event_t **event_ptrs;
+  int num_events = 0;
+  int i;
+  int n;
+  POLYAREA *pa;
+  PLINE *contour;
+
+  pa = poly;
+  do {
+    for (contour = pa->contours; contour != NULL; contour = contour->next)
+      num_events += contour->Count;
+    /* FIXME: Remove horizontal edges? */
+  } while ((pa = pa->f) != poly);
+
+  if (unlikely (0 == num_events))
+      return CAIRO_STATUS_SUCCESS;
+
+  events = stack_events;
+  event_ptrs = stack_event_ptrs;
+  if (num_events > ARRAY_LENGTH (stack_events)) {
+      events = _cairo_malloc_ab_plus_c (num_events,
+                                        sizeof (cairo_bo_start_event_t) +
+                                        sizeof (cairo_bo_event_t *),
+                                        sizeof (cairo_bo_event_t *));
+      if (unlikely (events == NULL))
+          return CAIRO_STATUS_NO_MEMORY;
+
+      event_ptrs = (cairo_bo_event_t **) (events + num_events);
+  }
+
+  i = 0;
+
+  poly_area_to_start_events (poly, events, event_ptrs, &i);
+
+  /* XXX: This would be the convenient place to throw in multiple
+   * passes of the Bentley-Ottmann algorithm. It would merely
+   * require storing the results of each pass into a temporary
+   * cairo_traps_t. */
+  status = _cairo_bentley_ottmann_tessellate_bo_edges (event_ptrs,
+                                                       num_events,
+                                                       traps,
+                                                       &intersections);
+
+  for (n = 0; n < traps->num_traps; n++) {
+    int x1, y1, x2, y2, x3, y3, x4, y4;
+
+    x1 = _line_compute_intersection_x_for_y (&traps->traps[n].left, traps->traps[n].top);
+    y1 = traps->traps[n].top;
+    x2 = _line_compute_intersection_x_for_y (&traps->traps[n].right, traps->traps[n].top);
+    y2 = traps->traps[n].top;
+    x3 = _line_compute_intersection_x_for_y (&traps->traps[n].right, traps->traps[n].bottom);
+    y3 = traps->traps[n].bottom;
+    x4 = _line_compute_intersection_x_for_y (&traps->traps[n].left, traps->traps[n].bottom);
+    y4 = traps->traps[n].bottom;
+
+#if 1
+    if (x1 == x2) {
+      hidgl_ensure_triangle_space (&buffer, 1);
+      hidgl_add_triangle (&buffer, x1, y1, x3, y3, x4, y4);
+    } else if (x3 == x4) {
+      hidgl_ensure_triangle_space (&buffer, 1);
+      hidgl_add_triangle (&buffer, x1, y1, x2, y2, x3, y3);
+    } else {
+      hidgl_ensure_triangle_space (&buffer, 2);
+      hidgl_add_triangle (&buffer, x1, y1, x2, y2, x3, y3);
+      hidgl_add_triangle (&buffer, x3, y3, x4, y4, x1, y1);
+    }
+#else
+    glBegin (GL_LINES);
+    glVertex2i (x1, y1); glVertex2i (x2, y2);
+    glVertex2i (x2, y2); glVertex2i (x3, y3);
+     glVertex2i (x3, y3); glVertex2i (x1, y1);
+    glVertex2i (x3, y3); glVertex2i (x4, y4);
+    glVertex2i (x4, y4); glVertex2i (x1, y1);
+     glVertex2i (x1, y1); glVertex2i (x3, y3);
+    glEnd ();
+#endif
+  }
+
+#if DEBUG_TRAPS
+  dump_traps (traps, "bo-polygon-out.txt");
+#endif
+
+  if (events != stack_events)
+      free (events);
+
+  return CAIRO_STATUS_SUCCESS;
+}
+
+
+cairo_status_t
+bo_contour_to_traps (PLINE *contour, cairo_traps_t *traps)
+{
+  int intersections;
+  cairo_status_t status;
+  cairo_bo_start_event_t stack_events[CAIRO_STACK_ARRAY_LENGTH (cairo_bo_start_event_t)];
+  cairo_bo_start_event_t *events;
+  cairo_bo_event_t *stack_event_ptrs[ARRAY_LENGTH (stack_events) + 1];
+  cairo_bo_event_t **event_ptrs;
+  int num_events = 0;
+  int i;
+  int n;
+
+  num_events = contour->Count;
+
+  if (unlikely (0 == num_events))
+      return CAIRO_STATUS_SUCCESS;
+
+  events = stack_events;
+  event_ptrs = stack_event_ptrs;
+  if (num_events > ARRAY_LENGTH (stack_events)) {
+      events = _cairo_malloc_ab_plus_c (num_events,
+                                        sizeof (cairo_bo_start_event_t) +
+                                        sizeof (cairo_bo_event_t *),
+                                        sizeof (cairo_bo_event_t *));
+      if (unlikely (events == NULL))
+          return CAIRO_STATUS_NO_MEMORY;
+
+      event_ptrs = (cairo_bo_event_t **) (events + num_events);
+  }
+
+  i = 0;
+
+  contour_to_start_events (contour, events, event_ptrs, &i, 1);
+
+  /* XXX: This would be the convenient place to throw in multiple
+   * passes of the Bentley-Ottmann algorithm. It would merely
+   * require storing the results of each pass into a temporary
+   * cairo_traps_t. */
+  status = _cairo_bentley_ottmann_tessellate_bo_edges (event_ptrs,
+                                                       num_events,
+                                                       traps,
+                                                       &intersections);
+
+  for (n = 0; n < traps->num_traps; n++) {
+    int x1, y1, x2, y2, x3, y3, x4, y4;
+
+    x1 = _line_compute_intersection_x_for_y (&traps->traps[n].left, traps->traps[n].top);
+    y1 = traps->traps[n].top;
+    x2 = _line_compute_intersection_x_for_y (&traps->traps[n].right, traps->traps[n].top);
+    y2 = traps->traps[n].top;
+    x3 = _line_compute_intersection_x_for_y (&traps->traps[n].right, traps->traps[n].bottom);
+    y3 = traps->traps[n].bottom;
+    x4 = _line_compute_intersection_x_for_y (&traps->traps[n].left, traps->traps[n].bottom);
+    y4 = traps->traps[n].bottom;
+
+#if 1
+    if (x1 == x2) {
+      hidgl_ensure_triangle_space (&buffer, 1);
+      hidgl_add_triangle (&buffer, x1, y1, x3, y3, x4, y4);
+    } else if (x3 == x4) {
+      hidgl_ensure_triangle_space (&buffer, 1);
+      hidgl_add_triangle (&buffer, x1, y1, x2, y2, x3, y3);
+    } else {
+      hidgl_ensure_triangle_space (&buffer, 2);
+      hidgl_add_triangle (&buffer, x1, y1, x2, y2, x3, y3);
+      hidgl_add_triangle (&buffer, x3, y3, x4, y4, x1, y1);
+    }
+#else
+    glBegin (GL_LINES);
+    glVertex2i (x1, y1); glVertex2i (x2, y2);
+    glVertex2i (x2, y2); glVertex2i (x3, y3);
+     glVertex2i (x3, y3); glVertex2i (x1, y1);
+    glVertex2i (x3, y3); glVertex2i (x4, y4);
+    glVertex2i (x4, y4); glVertex2i (x1, y1);
+     glVertex2i (x1, y1); glVertex2i (x3, y3);
+    glEnd ();
+#endif
+  }
+
+#if DEBUG_TRAPS
+  dump_traps (traps, "bo-polygon-out.txt");
+#endif
+
+  if (events != stack_events)
+      free (events);
+
+  return CAIRO_STATUS_SUCCESS;
+}
diff --git a/src/cairo/cairo-combsort-private.h b/src/cairo/cairo-combsort-private.h
new file mode 100644
index 0000000..ce31257
--- /dev/null
+++ b/src/cairo/cairo-combsort-private.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright © 2008 Chris Wilson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is Chris Wilson
+ *
+ * Contributor(s):
+ *	Chris Wilson <chris@xxxxxxxxxxxxxxxxxx>
+ */
+
+/* This fragment implements a comb sort (specifically combsort11) */
+#ifndef _HAVE_CAIRO_COMBSORT_NEWGAP
+#define _HAVE_CAIRO_COMBSORT_NEWGAP
+static inline unsigned int
+_cairo_combsort_newgap (unsigned int gap)
+{
+  gap = 10 * gap / 13;
+  if (gap == 9 || gap == 10)
+    gap = 11;
+  if (gap < 1)
+    gap = 1;
+  return gap;
+}
+#endif
+
+#define CAIRO_COMBSORT_DECLARE(NAME, TYPE, CMP) \
+static void \
+NAME (TYPE *base, unsigned int nmemb) \
+{ \
+  unsigned int gap = nmemb; \
+  unsigned int i, j; \
+  int swapped; \
+  do { \
+      gap = _cairo_combsort_newgap (gap); \
+      swapped = gap > 1; \
+      for (i = 0; i < nmemb-gap ; i++) { \
+	  j = i + gap; \
+	  if (CMP (base[i], base[j]) > 0 ) { \
+	      TYPE tmp; \
+	      tmp = base[i]; \
+	      base[i] = base[j]; \
+	      base[j] = tmp; \
+	      swapped = 1; \
+	  } \
+      } \
+  } while (swapped); \
+}
diff --git a/src/cairo/cairo-compiler-private.h b/src/cairo/cairo-compiler-private.h
new file mode 100644
index 0000000..9fe8e9b
--- /dev/null
+++ b/src/cairo/cairo-compiler-private.h
@@ -0,0 +1,203 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2002 University of Southern California
+ * Copyright © 2005 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is University of Southern
+ * California.
+ *
+ * Contributor(s):
+ *	Carl D. Worth <cworth@xxxxxxxxxx>
+ */
+
+#ifndef CAIRO_COMPILER_PRIVATE_H
+#define CAIRO_COMPILER_PRIVATE_H
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#if __GNUC__ >= 3 && defined(__ELF__) && !defined(__sun)
+# define slim_hidden_proto(name)		slim_hidden_proto1(name, slim_hidden_int_name(name)) cairo_private
+# define slim_hidden_proto_no_warn(name)	slim_hidden_proto1(name, slim_hidden_int_name(name)) cairo_private_no_warn
+# define slim_hidden_def(name)			slim_hidden_def1(name, slim_hidden_int_name(name))
+# define slim_hidden_int_name(name) INT_##name
+# define slim_hidden_proto1(name, internal)				\
+  extern __typeof (name) name						\
+	__asm__ (slim_hidden_asmname (internal))
+# define slim_hidden_def1(name, internal)				\
+  extern __typeof (name) EXT_##name __asm__(slim_hidden_asmname(name))	\
+	__attribute__((__alias__(slim_hidden_asmname(internal))))
+# define slim_hidden_ulp		slim_hidden_ulp1(__USER_LABEL_PREFIX__)
+# define slim_hidden_ulp1(x)		slim_hidden_ulp2(x)
+# define slim_hidden_ulp2(x)		#x
+# define slim_hidden_asmname(name)	slim_hidden_asmname1(name)
+# define slim_hidden_asmname1(name)	slim_hidden_ulp #name
+#else
+# define slim_hidden_proto(name)		int _cairo_dummy_prototype(void)
+# define slim_hidden_proto_no_warn(name)	int _cairo_dummy_prototype(void)
+# define slim_hidden_def(name)			int _cairo_dummy_prototype(void)
+#endif
+
+#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 4)
+#define CAIRO_PRINTF_FORMAT(fmt_index, va_index) \
+	__attribute__((__format__(__printf__, fmt_index, va_index)))
+#else
+#define CAIRO_PRINTF_FORMAT(fmt_index, va_index)
+#endif
+
+/* slim_internal.h */
+#define CAIRO_HAS_HIDDEN_SYMBOLS 1
+#if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)) && defined(__ELF__) && !defined(__sun)
+#define cairo_private_no_warn	__attribute__((__visibility__("hidden")))
+#elif defined(__SUNPRO_C) && (__SUNPRO_C >= 0x550)
+#define cairo_private_no_warn	__hidden
+#else /* not gcc >= 3.3 and not Sun Studio >= 8 */
+#define cairo_private_no_warn
+#undef CAIRO_HAS_HIDDEN_SYMBOLS
+#endif
+
+#ifndef WARN_UNUSED_RESULT
+#define WARN_UNUSED_RESULT
+#endif
+/* Add attribute(warn_unused_result) if supported */
+#define cairo_warn	    WARN_UNUSED_RESULT
+#define cairo_private	    cairo_private_no_warn cairo_warn
+
+/* This macro allow us to deprecate a function by providing an alias
+   for the old function name to the new function name. With this
+   macro, binary compatibility is preserved. The macro only works on
+   some platforms --- tough.
+
+   Meanwhile, new definitions in the public header file break the
+   source code so that it will no longer link against the old
+   symbols. Instead it will give a descriptive error message
+   indicating that the old function has been deprecated by the new
+   function.
+*/
+#if __GNUC__ >= 2 && defined(__ELF__)
+# define CAIRO_FUNCTION_ALIAS(old, new)		\
+	extern __typeof (new) old		\
+	__asm__ ("" #old)			\
+	__attribute__((__alias__("" #new)))
+#else
+# define CAIRO_FUNCTION_ALIAS(old, new)
+#endif
+
+/*
+ * Cairo uses the following function attributes in order to improve the
+ * generated code (effectively by manual inter-procedural analysis).
+ *
+ *   'cairo_pure': The function is only allowed to read from its arguments
+ *                 and global memory (i.e. following a pointer argument or
+ *                 accessing a shared variable). The return value should
+ *                 only depend on its arguments, and for an identical set of
+ *                 arguments should return the same value.
+ *
+ *   'cairo_const': The function is only allowed to read from its arguments.
+ *                  It is not allowed to access global memory. The return
+ *                  value should only depend its arguments, and for an
+ *                  identical set of arguments should return the same value.
+ *                  This is currently the most strict function attribute.
+ *
+ * Both these function attributes allow gcc to perform CSE and
+ * constant-folding, with 'cairo_const 'also guaranteeing that pointer contents
+ * do not change across the function call.
+ */
+#if __GNUC__ >= 3
+#define cairo_pure __attribute__((pure))
+#define cairo_const __attribute__((const))
+#else
+#define cairo_pure
+#define cairo_const
+#endif
+
+#if defined(__GNUC__) && (__GNUC__ > 2) && defined(__OPTIMIZE__)
+#define _CAIRO_BOOLEAN_EXPR(expr)                   \
+ __extension__ ({                               \
+   int _cairo_boolean_var_;                         \
+   if (expr)                                    \
+      _cairo_boolean_var_ = 1;                      \
+   else                                         \
+      _cairo_boolean_var_ = 0;                      \
+   _cairo_boolean_var_;                             \
+})
+#define likely(expr) (__builtin_expect (_CAIRO_BOOLEAN_EXPR(expr), 1))
+#define unlikely(expr) (__builtin_expect (_CAIRO_BOOLEAN_EXPR(expr), 0))
+#else
+#define likely(expr) (expr)
+#define unlikely(expr) (expr)
+#endif
+
+#ifndef __GNUC__
+#undef __attribute__
+#define __attribute__(x)
+#endif
+
+#if (defined(__WIN32__) && !defined(__WINE__)) || defined(_MSC_VER)
+#define snprintf _snprintf
+#define popen _popen
+#define pclose _pclose
+#define hypot _hypot
+#endif
+
+#ifdef _MSC_VER
+#undef inline
+#define inline __inline
+#endif
+
+#if defined(_MSC_VER) && defined(_M_IX86)
+/* When compiling with /Gy and /OPT:ICF identical functions will be folded in together.
+   The CAIRO_ENSURE_UNIQUE macro ensures that a function is always unique and
+   will never be folded into another one. Something like this might eventually
+   be needed for GCC but it seems fine for now. */
+#define CAIRO_ENSURE_UNIQUE                       \
+    do {                                          \
+	char func[] = __FUNCTION__;               \
+	char file[] = __FILE__;                   \
+	__asm {                                   \
+	    __asm jmp __internal_skip_line_no     \
+	    __asm _emit (__LINE__ & 0xff)         \
+	    __asm _emit ((__LINE__>>8) & 0xff)    \
+	    __asm _emit ((__LINE__>>16) & 0xff)   \
+	    __asm _emit ((__LINE__>>24) & 0xff)   \
+	    __asm lea eax, func                   \
+	    __asm lea eax, file                   \
+	    __asm __internal_skip_line_no:        \
+	};                                        \
+    } while (0)
+#else
+#define CAIRO_ENSURE_UNIQUE    do { } while (0)
+#endif
+
+#ifdef __STRICT_ANSI__
+#undef inline
+#define inline __inline__
+#endif
+
+#endif
diff --git a/src/cairo/cairo-fixed-private.h b/src/cairo/cairo-fixed-private.h
new file mode 100644
index 0000000..e3add4a
--- /dev/null
+++ b/src/cairo/cairo-fixed-private.h
@@ -0,0 +1,290 @@
+/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
+/* Cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2007 Mozilla Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is Mozilla Corporation
+ *
+ * Contributor(s):
+ *	Vladimir Vukicevic <vladimir@xxxxxxxxx>
+ */
+
+#ifndef CAIRO_FIXED_PRIVATE_H
+#define CAIRO_FIXED_PRIVATE_H
+
+#include "cairo-fixed-type-private.h"
+
+#include "cairo-wideint-private.h"
+
+/* Implementation */
+
+#if (CAIRO_FIXED_BITS != 32)
+# error CAIRO_FIXED_BITS must be 32, and the type must be a 32-bit type.
+# error To remove this limitation, you will have to fix the tesselator.
+#endif
+
+#define CAIRO_FIXED_ONE        ((cairo_fixed_t)(1 << CAIRO_FIXED_FRAC_BITS))
+#define CAIRO_FIXED_ONE_DOUBLE ((double)(1 << CAIRO_FIXED_FRAC_BITS))
+#define CAIRO_FIXED_EPSILON    ((cairo_fixed_t)(1))
+
+#define CAIRO_FIXED_FRAC_MASK  (((cairo_fixed_unsigned_t)(-1)) >> (CAIRO_FIXED_BITS - CAIRO_FIXED_FRAC_BITS))
+#define CAIRO_FIXED_WHOLE_MASK (~CAIRO_FIXED_FRAC_MASK)
+
+static inline cairo_fixed_t
+_cairo_fixed_from_int (int i)
+{
+    return i << CAIRO_FIXED_FRAC_BITS;
+}
+
+/* This is the "magic number" approach to converting a double into fixed
+ * point as described here:
+ *
+ * http://www.stereopsis.com/sree/fpu2006.html (an overview)
+ * http://www.d6.com/users/checker/pdfs/gdmfp.pdf (in detail)
+ *
+ * The basic idea is to add a large enough number to the double that the
+ * literal floating point is moved up to the extent that it forces the
+ * double's value to be shifted down to the bottom of the mantissa (to make
+ * room for the large number being added in). Since the mantissa is, at a
+ * given moment in time, a fixed point integer itself, one can convert a
+ * float to various fixed point representations by moving around the point
+ * of a floating point number through arithmetic operations. This behavior
+ * is reliable on most modern platforms as it is mandated by the IEEE-754
+ * standard for floating point arithmetic.
+ *
+ * For our purposes, a "magic number" must be carefully selected that is
+ * both large enough to produce the desired point-shifting effect, and also
+ * has no lower bits in its representation that would interfere with our
+ * value at the bottom of the mantissa. The magic number is calculated as
+ * follows:
+ *
+ *          (2 ^ (MANTISSA_SIZE - FRACTIONAL_SIZE)) * 1.5
+ *
+ * where in our case:
+ *  - MANTISSA_SIZE for 64-bit doubles is 52
+ *  - FRACTIONAL_SIZE for 16.16 fixed point is 16
+ *
+ * Although this approach provides a very large speedup of this function
+ * on a wide-array of systems, it does come with two caveats:
+ *
+ * 1) It uses banker's rounding as opposed to arithmetic rounding.
+ * 2) It doesn't function properly if the FPU is in single-precision
+ *    mode.
+ */
+
+/* The 16.16 number must always be available */
+#define CAIRO_MAGIC_NUMBER_FIXED_16_16 (103079215104.0)
+
+#if CAIRO_FIXED_BITS <= 32
+#define CAIRO_MAGIC_NUMBER_FIXED ((1LL << (52 - CAIRO_FIXED_FRAC_BITS)) * 1.5)
+
+/* For 32-bit fixed point numbers */
+static inline cairo_fixed_t
+_cairo_fixed_from_double (double d)
+{
+    union {
+        double d;
+        int32_t i[2];
+    } u;
+
+    u.d = d + CAIRO_MAGIC_NUMBER_FIXED;
+#ifdef FLOAT_WORDS_BIGENDIAN
+    return u.i[1];
+#else
+    return u.i[0];
+#endif
+}
+
+#else
+# error Please define a magic number for your fixed point type!
+# error See cairo-fixed-private.h for details.
+#endif
+
+static inline cairo_fixed_t
+_cairo_fixed_from_26_6 (uint32_t i)
+{
+#if CAIRO_FIXED_FRAC_BITS > 6
+    return i << (CAIRO_FIXED_FRAC_BITS - 6);
+#else
+    return i >> (6 - CAIRO_FIXED_FRAC_BITS);
+#endif
+}
+
+static inline double
+_cairo_fixed_to_double (cairo_fixed_t f)
+{
+    return ((double) f) / CAIRO_FIXED_ONE_DOUBLE;
+}
+
+static inline int
+_cairo_fixed_is_integer (cairo_fixed_t f)
+{
+    return (f & CAIRO_FIXED_FRAC_MASK) == 0;
+}
+
+static inline int
+_cairo_fixed_integer_part (cairo_fixed_t f)
+{
+    return f >> CAIRO_FIXED_FRAC_BITS;
+}
+
+static inline int
+_cairo_fixed_integer_floor (cairo_fixed_t f)
+{
+    if (f >= 0)
+        return f >> CAIRO_FIXED_FRAC_BITS;
+    else
+        return -((-f - 1) >> CAIRO_FIXED_FRAC_BITS) - 1;
+}
+
+static inline int
+_cairo_fixed_integer_ceil (cairo_fixed_t f)
+{
+    if (f > 0)
+	return ((f - 1)>>CAIRO_FIXED_FRAC_BITS) + 1;
+    else
+	return - (-f >> CAIRO_FIXED_FRAC_BITS);
+}
+
+/* A bunch of explicit 16.16 operators; we need these
+ * to interface with pixman and other backends that require
+ * 16.16 fixed point types.
+ */
+static inline cairo_fixed_16_16_t
+_cairo_fixed_to_16_16 (cairo_fixed_t f)
+{
+#if (CAIRO_FIXED_FRAC_BITS == 16) && (CAIRO_FIXED_BITS == 32)
+    return f;
+#elif CAIRO_FIXED_FRAC_BITS > 16
+    /* We're just dropping the low bits, so we won't ever got over/underflow here */
+    return f >> (CAIRO_FIXED_FRAC_BITS - 16);
+#else
+    cairo_fixed_16_16_t x;
+
+    /* Handle overflow/underflow by clamping to the lowest/highest
+     * value representable as 16.16
+     */
+    if ((f >> CAIRO_FIXED_FRAC_BITS) < INT16_MIN) {
+	x = INT32_MIN;
+    } else if ((f >> CAIRO_FIXED_FRAC_BITS) > INT16_MAX) {
+	x = INT32_MAX;
+    } else {
+	x = f << (16 - CAIRO_FIXED_FRAC_BITS);
+    }
+
+    return x;
+#endif
+}
+
+static inline cairo_fixed_16_16_t
+_cairo_fixed_16_16_from_double (double d)
+{
+    union {
+        double d;
+        int32_t i[2];
+    } u;
+
+    u.d = d + CAIRO_MAGIC_NUMBER_FIXED_16_16;
+#ifdef FLOAT_WORDS_BIGENDIAN
+    return u.i[1];
+#else
+    return u.i[0];
+#endif
+}
+
+#if CAIRO_FIXED_BITS == 32
+
+static inline cairo_fixed_t
+_cairo_fixed_mul (cairo_fixed_t a, cairo_fixed_t b)
+{
+    cairo_int64_t temp = _cairo_int32x32_64_mul (a, b);
+    return _cairo_int64_to_int32(_cairo_int64_rsl (temp, CAIRO_FIXED_FRAC_BITS));
+}
+
+/* computes round (a * b / c) */
+static inline cairo_fixed_t
+_cairo_fixed_mul_div (cairo_fixed_t a, cairo_fixed_t b, cairo_fixed_t c)
+{
+    cairo_int64_t ab  = _cairo_int32x32_64_mul (a, b);
+    cairo_int64_t c64 = _cairo_int32_to_int64 (c);
+    return _cairo_int64_to_int32 (_cairo_int64_divrem (ab, c64).quo);
+}
+
+/* computes floor (a * b / c) */
+static inline cairo_fixed_t
+_cairo_fixed_mul_div_floor (cairo_fixed_t a, cairo_fixed_t b, cairo_fixed_t c)
+{
+    return _cairo_int64_32_div (_cairo_int32x32_64_mul (a, b), c);
+}
+
+
+static inline cairo_fixed_t
+_cairo_edge_compute_intersection_y_for_x (const cairo_point_t *p1,
+					  const cairo_point_t *p2,
+					  cairo_fixed_t x)
+{
+    cairo_fixed_t y, dx;
+
+    if (x == p1->x)
+	return p1->y;
+    if (x == p2->x)
+	return p2->y;
+
+    y = p1->y;
+    dx = p2->x - p1->x;
+    if (dx != 0)
+	y += _cairo_fixed_mul_div_floor (x - p1->x, p2->y - p1->y, dx);
+
+    return y;
+}
+
+static inline cairo_fixed_t
+_cairo_edge_compute_intersection_x_for_y (const cairo_point_t *p1,
+					  const cairo_point_t *p2,
+					  cairo_fixed_t y)
+{
+    cairo_fixed_t x, dy;
+
+    if (y == p1->y)
+	return p1->x;
+    if (y == p2->y)
+	return p2->x;
+
+    x = p1->x;
+    dy = p2->y - p1->y;
+    if (dy != 0)
+	x += _cairo_fixed_mul_div_floor (y - p1->y, p2->x - p1->x, dy);
+
+    return x;
+}
+
+#else
+# error Please define multiplication and other operands for your fixed-point type size
+#endif
+
+#endif /* CAIRO_FIXED_PRIVATE_H */
diff --git a/src/cairo/cairo-fixed-type-private.h b/src/cairo/cairo-fixed-type-private.h
new file mode 100644
index 0000000..730ed3e
--- /dev/null
+++ b/src/cairo/cairo-fixed-type-private.h
@@ -0,0 +1,75 @@
+/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
+/* Cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2007 Mozilla Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is Mozilla Corporation
+ *
+ * Contributor(s):
+ *	Vladimir Vukicevic <vladimir@xxxxxxxxx>
+ */
+
+#ifndef CAIRO_FIXED_TYPE_PRIVATE_H
+#define CAIRO_FIXED_TYPE_PRIVATE_H
+
+#include "cairo-wideint-type-private.h"
+
+/*
+ * Fixed-point configuration
+ */
+
+typedef int32_t		cairo_fixed_16_16_t;
+typedef cairo_int64_t	cairo_fixed_32_32_t;
+typedef cairo_int64_t	cairo_fixed_48_16_t;
+typedef cairo_int128_t	cairo_fixed_64_64_t;
+typedef cairo_int128_t	cairo_fixed_96_32_t;
+
+/* Eventually, we should allow changing this, but I think
+ * there are some assumptions in the tesselator about the
+ * size of a fixed type.  For now, it must be 32.
+ */
+#define CAIRO_FIXED_BITS	32
+
+/* The number of fractional bits.  Changing this involves
+ * making sure that you compute a double-to-fixed magic number.
+ * (see below).
+ */
+#define CAIRO_FIXED_FRAC_BITS	8
+
+/* A signed type %CAIRO_FIXED_BITS in size; the main fixed point type */
+typedef int32_t cairo_fixed_t;
+
+/* An unsigned type of the same size as #cairo_fixed_t */
+typedef uint32_t cairo_fixed_unsigned_t;
+
+typedef struct _cairo_point {
+    cairo_fixed_t x;
+    cairo_fixed_t y;
+} cairo_point_t;
+
+#endif /* CAIRO_FIXED_TYPE_PRIVATE_H */
diff --git a/src/cairo/cairo-freelist-private.h b/src/cairo/cairo-freelist-private.h
new file mode 100644
index 0000000..5be22b1
--- /dev/null
+++ b/src/cairo/cairo-freelist-private.h
@@ -0,0 +1,150 @@
+/*
+ * Copyright © 2006 Joonas Pihlaja
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  The copyright holders make no representations
+ * about the suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+#ifndef CAIRO_FREELIST_H
+#define CAIRO_FREELIST_H
+
+#include "cairo-types-private.h"
+#include "cairo-compiler-private.h"
+
+/* for stand-alone compilation*/
+#ifndef VG
+#define VG(x)
+#endif
+
+#ifndef NULL
+#define NULL (void *) 0
+#endif
+
+typedef struct _cairo_freelist_node cairo_freelist_node_t;
+struct _cairo_freelist_node {
+    cairo_freelist_node_t *next;
+};
+
+typedef struct _cairo_freelist {
+    cairo_freelist_node_t *first_free_node;
+    unsigned nodesize;
+} cairo_freelist_t;
+
+typedef struct _cairo_freelist_pool cairo_freelist_pool_t;
+struct _cairo_freelist_pool {
+    cairo_freelist_pool_t *next;
+    unsigned size, rem;
+    uint8_t *data;
+};
+
+typedef struct _cairo_freepool {
+    cairo_freelist_node_t *first_free_node;
+    cairo_freelist_pool_t *pools;
+    unsigned nodesize;
+    cairo_freelist_pool_t embedded_pool;
+    uint8_t embedded_data[1000];
+} cairo_freepool_t;
+
+
+/* Initialise a freelist that will be responsible for allocating
+ * nodes of size nodesize. */
+cairo_private void
+_cairo_freelist_init (cairo_freelist_t *freelist, unsigned nodesize);
+
+/* Deallocate any nodes in the freelist. */
+cairo_private void
+_cairo_freelist_fini (cairo_freelist_t *freelist);
+
+/* Allocate a new node from the freelist.  If the freelist contains no
+ * nodes, a new one will be allocated using malloc().  The caller is
+ * responsible for calling _cairo_freelist_free() or free() on the
+ * returned node.  Returns %NULL on memory allocation error. */
+cairo_private void *
+_cairo_freelist_alloc (cairo_freelist_t *freelist);
+
+/* Allocate a new node from the freelist.  If the freelist contains no
+ * nodes, a new one will be allocated using calloc().  The caller is
+ * responsible for calling _cairo_freelist_free() or free() on the
+ * returned node.  Returns %NULL on memory allocation error. */
+cairo_private void *
+_cairo_freelist_calloc (cairo_freelist_t *freelist);
+
+/* Return a node to the freelist. This does not deallocate the memory,
+ * but makes it available for later reuse by
+ * _cairo_freelist_alloc(). */
+cairo_private void
+_cairo_freelist_free (cairo_freelist_t *freelist, void *node);
+
+
+cairo_private void
+_cairo_freepool_init (cairo_freepool_t *freepool, unsigned nodesize);
+
+cairo_private void
+_cairo_freepool_fini (cairo_freepool_t *freepool);
+
+cairo_private void *
+_cairo_freepool_alloc_from_new_pool (cairo_freepool_t *freepool);
+
+static inline void *
+_cairo_freepool_alloc_from_pool (cairo_freepool_t *freepool)
+{
+    cairo_freelist_pool_t *pool;
+    uint8_t *ptr;
+
+    pool = freepool->pools;
+    if (unlikely (freepool->nodesize > pool->rem))
+	return _cairo_freepool_alloc_from_new_pool (freepool);
+
+    ptr = pool->data;
+    pool->data += freepool->nodesize;
+    pool->rem -= freepool->nodesize;
+    VG (VALGRIND_MAKE_MEM_UNDEFINED (ptr, freepool->nodesize));
+    return ptr;
+}
+
+static inline void *
+_cairo_freepool_alloc (cairo_freepool_t *freepool)
+{
+    cairo_freelist_node_t *node;
+
+    node = freepool->first_free_node;
+    if (unlikely (node == NULL))
+	return _cairo_freepool_alloc_from_pool (freepool);
+
+    VG (VALGRIND_MAKE_MEM_DEFINED (node, sizeof (node->next)));
+    freepool->first_free_node = node->next;
+    VG (VALGRIND_MAKE_MEM_UNDEFINED (node, freepool->nodesize));
+
+    return node;
+}
+
+cairo_private cairo_status_t
+_cairo_freepool_alloc_array (cairo_freepool_t *freepool,
+			     int count,
+			     void **array);
+
+static inline void
+_cairo_freepool_free (cairo_freepool_t *freepool, void *ptr)
+{
+    cairo_freelist_node_t *node = ptr;
+
+    node->next = freepool->first_free_node;
+    freepool->first_free_node = node;
+    VG (VALGRIND_MAKE_MEM_NOACCESS (node, freepool->nodesize));
+}
+
+#endif /* CAIRO_FREELIST_H */
diff --git a/src/cairo/cairo-freelist.c b/src/cairo/cairo-freelist.c
new file mode 100644
index 0000000..6ea5c17
--- /dev/null
+++ b/src/cairo/cairo-freelist.c
@@ -0,0 +1,176 @@
+/*
+ * Copyright © 2006 Joonas Pihlaja
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  The copyright holders make no representations
+ * about the suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "cairo-freelist-private.h"
+
+#define _cairo_error(x) (x)
+
+void
+_cairo_freelist_init (cairo_freelist_t *freelist, unsigned nodesize)
+{
+    memset (freelist, 0, sizeof (cairo_freelist_t));
+    freelist->nodesize = nodesize;
+}
+
+void
+_cairo_freelist_fini (cairo_freelist_t *freelist)
+{
+    cairo_freelist_node_t *node = freelist->first_free_node;
+    while (node) {
+	cairo_freelist_node_t *next;
+
+	VG (VALGRIND_MAKE_MEM_DEFINED (node, sizeof (node->next)));
+	next = node->next;
+
+	free (node);
+	node = next;
+    }
+}
+
+void *
+_cairo_freelist_alloc (cairo_freelist_t *freelist)
+{
+    if (freelist->first_free_node) {
+	cairo_freelist_node_t *node;
+
+	node = freelist->first_free_node;
+	VG (VALGRIND_MAKE_MEM_DEFINED (node, sizeof (node->next)));
+	freelist->first_free_node = node->next;
+	VG (VALGRIND_MAKE_MEM_UNDEFINED (node, freelist->nodesize));
+
+	return node;
+    }
+
+    return malloc (freelist->nodesize);
+}
+
+void *
+_cairo_freelist_calloc (cairo_freelist_t *freelist)
+{
+    void *node = _cairo_freelist_alloc (freelist);
+    if (node)
+	memset (node, 0, freelist->nodesize);
+    return node;
+}
+
+void
+_cairo_freelist_free (cairo_freelist_t *freelist, void *voidnode)
+{
+    cairo_freelist_node_t *node = voidnode;
+    if (node) {
+	node->next = freelist->first_free_node;
+	freelist->first_free_node = node;
+	VG (VALGRIND_MAKE_MEM_NOACCESS (node, freelist->nodesize));
+    }
+}
+
+
+void
+_cairo_freepool_init (cairo_freepool_t *freepool, unsigned nodesize)
+{
+    freepool->first_free_node = NULL;
+    freepool->pools = &freepool->embedded_pool;
+    freepool->nodesize = nodesize;
+
+    freepool->embedded_pool.next = NULL;
+    freepool->embedded_pool.size = sizeof (freepool->embedded_data);
+    freepool->embedded_pool.rem = sizeof (freepool->embedded_data);
+    freepool->embedded_pool.data = freepool->embedded_data;
+
+    VG (VALGRIND_MAKE_MEM_NOACCESS (freepool->embedded_data,
+				    sizeof (freepool->embedded_data)));
+}
+
+void
+_cairo_freepool_fini (cairo_freepool_t *freepool)
+{
+    cairo_freelist_pool_t *pool = freepool->pools;
+    while (pool != &freepool->embedded_pool) {
+	cairo_freelist_pool_t *next = pool->next;
+	free (pool);
+	pool = next;
+    }
+    VG (VALGRIND_MAKE_MEM_NOACCESS (freepool, sizeof (freepool)));
+}
+
+void *
+_cairo_freepool_alloc_from_new_pool (cairo_freepool_t *freepool)
+{
+    cairo_freelist_pool_t *pool;
+    int poolsize;
+
+    if (freepool->pools != &freepool->embedded_pool)
+	poolsize = 2 * freepool->pools->size;
+    else
+	poolsize = (128 * freepool->nodesize + 8191) & -8192;
+    pool = malloc (sizeof (cairo_freelist_pool_t) + poolsize);
+    if (unlikely (pool == NULL))
+	return pool;
+
+    pool->next = freepool->pools;
+    freepool->pools = pool;
+
+    pool->size = poolsize;
+    pool->rem = poolsize - freepool->nodesize;
+    pool->data = (uint8_t *) (pool + 1) + freepool->nodesize;
+
+    VG (VALGRIND_MAKE_MEM_NOACCESS (pool->data, poolsize));
+    VG (VALGRIND_MAKE_MEM_UNDEFINED (pool->data, freepool->nodesize));
+
+    return pool + 1;
+}
+
+cairo_status_t
+_cairo_freepool_alloc_array (cairo_freepool_t *freepool,
+			     int count,
+			     void **array)
+{
+    int i;
+
+    for (i = 0; i < count; i++) {
+	cairo_freelist_node_t *node;
+
+	node = freepool->first_free_node;
+	if (likely (node != NULL)) {
+	    VG (VALGRIND_MAKE_MEM_DEFINED (node, sizeof (node->next)));
+	    freepool->first_free_node = node->next;
+	    VG (VALGRIND_MAKE_MEM_UNDEFINED (node, freepool->nodesize));
+	} else {
+	    node = _cairo_freepool_alloc_from_pool (freepool);
+	    if (unlikely (node == NULL))
+		goto CLEANUP;
+	}
+
+	array[i] = node;
+    }
+
+    return CAIRO_STATUS_SUCCESS;
+
+  CLEANUP:
+    while (i--)
+	_cairo_freepool_free (freepool, array[i]);
+
+    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+}
diff --git a/src/cairo/cairo-malloc-private.h b/src/cairo/cairo-malloc-private.h
new file mode 100644
index 0000000..d812058
--- /dev/null
+++ b/src/cairo/cairo-malloc-private.h
@@ -0,0 +1,148 @@
+/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
+/* Cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2007 Mozilla Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is Mozilla Corporation
+ *
+ * Contributor(s):
+ *	Vladimir Vukicevic <vladimir@xxxxxxxxx>
+ */
+
+#ifndef CAIRO_MALLOC_PRIVATE_H
+#define CAIRO_MALLOC_PRIVATE_H
+
+#include "cairo-wideint-private.h"
+
+#if HAVE_MEMFAULT
+#include <memfault.h>
+#define CAIRO_INJECT_FAULT() MEMFAULT_INJECT_FAULT()
+#else
+#define CAIRO_INJECT_FAULT() 0
+#endif
+
+/**
+ * _cairo_malloc:
+ * @size: size in bytes
+ *
+ * Allocate @size memory using malloc().
+ * The memory should be freed using free().
+ * malloc is skipped, if 0 bytes are requested, and %NULL will be returned.
+ *
+ * Return value: A pointer to the newly allocated memory, or %NULL in
+ * case of malloc() failure or size is 0.
+ */
+
+#define _cairo_malloc(size) \
+   ((size) ? malloc((unsigned) (size)) : NULL)
+
+/**
+ * _cairo_malloc_ab:
+ * @n: number of elements to allocate
+ * @size: size of each element
+ *
+ * Allocates @n*@size memory using _cairo_malloc(), taking care to not
+ * overflow when doing the multiplication.  Behaves much like
+ * calloc(), except that the returned memory is not set to zero.
+ * The memory should be freed using free().
+ *
+ * @size should be a constant so that the compiler can optimize
+ * out a constant division.
+ *
+ * Return value: A pointer to the newly allocated memory, or %NULL in
+ * case of malloc() failure or overflow.
+ */
+
+#define _cairo_malloc_ab(a, size) \
+  ((size) && (unsigned) (a) >= INT32_MAX / (unsigned) (size) ? NULL : \
+   _cairo_malloc((unsigned) (a) * (unsigned) (size)))
+
+/**
+ * _cairo_realloc_ab:
+ * @ptr: original pointer to block of memory to be resized
+ * @n: number of elements to allocate
+ * @size: size of each element
+ *
+ * Reallocates @ptr a block of @n*@size memory using realloc(), taking
+ * care to not overflow when doing the multiplication.  The memory
+ * should be freed using free().
+ *
+ * @size should be a constant so that the compiler can optimize
+ * out a constant division.
+ *
+ * Return value: A pointer to the newly allocated memory, or %NULL in
+ * case of realloc() failure or overflow (whereupon the original block
+ * of memory * is left untouched).
+ */
+
+#define _cairo_realloc_ab(ptr, a, size) \
+  ((size) && (unsigned) (a) >= INT32_MAX / (unsigned) (size) ? NULL : \
+   realloc(ptr, (unsigned) (a) * (unsigned) (size)))
+
+/**
+ * _cairo_malloc_abc:
+ * @n: first factor of number of elements to allocate
+ * @b: second factor of number of elements to allocate
+ * @size: size of each element
+ *
+ * Allocates @n*@b*@size memory using _cairo_malloc(), taking care to not
+ * overflow when doing the multiplication.  Behaves like
+ * _cairo_malloc_ab().  The memory should be freed using free().
+ *
+ * @size should be a constant so that the compiler can optimize
+ * out a constant division.
+ *
+ * Return value: A pointer to the newly allocated memory, or %NULL in
+ * case of malloc() failure or overflow.
+ */
+
+#define _cairo_malloc_abc(a, b, size) \
+  ((b) && (unsigned) (a) >= INT32_MAX / (unsigned) (b) ? NULL : \
+   (size) && (unsigned) ((a)*(b)) >= INT32_MAX / (unsigned) (size) ? NULL : \
+   _cairo_malloc((unsigned) (a) * (unsigned) (b) * (unsigned) (size)))
+
+/**
+ * _cairo_malloc_ab_plus_c:
+ * @n: number of elements to allocate
+ * @size: size of each element
+ * @k: additional size to allocate
+ *
+ * Allocates @n*@ksize+@k memory using _cairo_malloc(), taking care to not
+ * overflow when doing the arithmetic.  Behaves like
+ * _cairo_malloc_ab().  The memory should be freed using free().
+ *
+ * Return value: A pointer to the newly allocated memory, or %NULL in
+ * case of malloc() failure or overflow.
+ */
+
+#define _cairo_malloc_ab_plus_c(n, size, k) \
+  ((size) && (unsigned) (n) >= INT32_MAX / (unsigned) (size) ? NULL : \
+   (unsigned) (k) >= INT32_MAX - (unsigned) (n) * (unsigned) (size) ? NULL : \
+   _cairo_malloc((unsigned) (n) * (unsigned) (size) + (unsigned) (k)))
+
+#endif /* CAIRO_MALLOC_PRIVATE_H */
diff --git a/src/cairo/cairo-minimal.h b/src/cairo/cairo-minimal.h
new file mode 100644
index 0000000..9028299
--- /dev/null
+++ b/src/cairo/cairo-minimal.h
@@ -0,0 +1,208 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2002 University of Southern California
+ * Copyright © 2005 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is University of Southern
+ * California.
+ *
+ * Contributor(s):
+ *	Carl D. Worth <cworth@xxxxxxxxxx>
+ */
+
+#ifndef _CAIRO_MINIMAL_H_
+#define _CAIRO_MINIMAL_H_
+
+#ifdef  __cplusplus
+# define CAIRO_BEGIN_DECLS  extern "C" {
+# define CAIRO_END_DECLS    }
+#else
+# define CAIRO_BEGIN_DECLS
+# define CAIRO_END_DECLS
+#endif
+
+#ifndef cairo_public
+# define cairo_public
+#endif
+
+CAIRO_BEGIN_DECLS
+
+/**
+ * cairo_bool_t:
+ *
+ * #cairo_bool_t is used for boolean values. Returns of type
+ * #cairo_bool_t will always be either 0 or 1, but testing against
+ * these values explicitly is not encouraged; just use the
+ * value as a boolean condition.
+ *
+ * <informalexample><programlisting>
+ *  if (cairo_in_stroke (cr, x, y)) {
+ *      /<!-- -->* do something *<!-- -->/
+ *  }
+ * </programlisting></informalexample>
+ **/
+typedef int cairo_bool_t;
+
+
+/**
+ * cairo_status_t:
+ * @CAIRO_STATUS_SUCCESS: no error has occurred
+ * @CAIRO_STATUS_NO_MEMORY: out of memory
+ * @CAIRO_STATUS_INVALID_RESTORE: cairo_restore() called without matching cairo_save()
+ * @CAIRO_STATUS_INVALID_POP_GROUP: no saved group to pop, i.e. cairo_pop_group() without matching cairo_push_group()
+ * @CAIRO_STATUS_NO_CURRENT_POINT: no current point defined
+ * @CAIRO_STATUS_INVALID_MATRIX: invalid matrix (not invertible)
+ * @CAIRO_STATUS_INVALID_STATUS: invalid value for an input #cairo_status_t
+ * @CAIRO_STATUS_NULL_POINTER: %NULL pointer
+ * @CAIRO_STATUS_INVALID_STRING: input string not valid UTF-8
+ * @CAIRO_STATUS_INVALID_PATH_DATA: input path data not valid
+ * @CAIRO_STATUS_READ_ERROR: error while reading from input stream
+ * @CAIRO_STATUS_WRITE_ERROR: error while writing to output stream
+ * @CAIRO_STATUS_SURFACE_FINISHED: target surface has been finished
+ * @CAIRO_STATUS_SURFACE_TYPE_MISMATCH: the surface type is not appropriate for the operation
+ * @CAIRO_STATUS_PATTERN_TYPE_MISMATCH: the pattern type is not appropriate for the operation
+ * @CAIRO_STATUS_INVALID_CONTENT: invalid value for an input #cairo_content_t
+ * @CAIRO_STATUS_INVALID_FORMAT: invalid value for an input #cairo_format_t
+ * @CAIRO_STATUS_INVALID_VISUAL: invalid value for an input Visual*
+ * @CAIRO_STATUS_FILE_NOT_FOUND: file not found
+ * @CAIRO_STATUS_INVALID_DASH: invalid value for a dash setting
+ * @CAIRO_STATUS_INVALID_DSC_COMMENT: invalid value for a DSC comment (Since 1.2)
+ * @CAIRO_STATUS_INVALID_INDEX: invalid index passed to getter (Since 1.4)
+ * @CAIRO_STATUS_CLIP_NOT_REPRESENTABLE: clip region not representable in desired format (Since 1.4)
+ * @CAIRO_STATUS_TEMP_FILE_ERROR: error creating or writing to a temporary file (Since 1.6)
+ * @CAIRO_STATUS_INVALID_STRIDE: invalid value for stride (Since 1.6)
+ * @CAIRO_STATUS_FONT_TYPE_MISMATCH: the font type is not appropriate for the operation (Since 1.8)
+ * @CAIRO_STATUS_USER_FONT_IMMUTABLE: the user-font is immutable (Since 1.8)
+ * @CAIRO_STATUS_USER_FONT_ERROR: error occurred in a user-font callback function (Since 1.8)
+ * @CAIRO_STATUS_NEGATIVE_COUNT: negative number used where it is not allowed (Since 1.8)
+ * @CAIRO_STATUS_INVALID_CLUSTERS: input clusters do not represent the accompanying text and glyph array (Since 1.8)
+ * @CAIRO_STATUS_INVALID_SLANT: invalid value for an input #cairo_font_slant_t (Since 1.8)
+ * @CAIRO_STATUS_INVALID_WEIGHT: invalid value for an input #cairo_font_weight_t (Since 1.8)
+ * @CAIRO_STATUS_INVALID_SIZE: invalid value (typically too big) for the size of the input (surface, pattern, etc.) (Since 1.10)
+ * @CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED: user-font method not implemented (Since 1.10)
+ * @CAIRO_STATUS_LAST_STATUS: this is a special value indicating the number of
+ *   status values defined in this enumeration.  When using this value, note
+ *   that the version of cairo at run-time may have additional status values
+ *   defined than the value of this symbol at compile-time. (Since 1.10)
+ *
+ * #cairo_status_t is used to indicate errors that can occur when
+ * using Cairo. In some cases it is returned directly by functions.
+ * but when using #cairo_t, the last error, if any, is stored in
+ * the context and can be retrieved with cairo_status().
+ *
+ * New entries may be added in future versions.  Use cairo_status_to_string()
+ * to get a human-readable representation of an error message.
+ **/
+typedef enum _cairo_status {
+    CAIRO_STATUS_SUCCESS = 0,
+
+    CAIRO_STATUS_NO_MEMORY,
+    CAIRO_STATUS_INVALID_RESTORE,
+    CAIRO_STATUS_INVALID_POP_GROUP,
+    CAIRO_STATUS_NO_CURRENT_POINT,
+    CAIRO_STATUS_INVALID_MATRIX,
+    CAIRO_STATUS_INVALID_STATUS,
+    CAIRO_STATUS_NULL_POINTER,
+    CAIRO_STATUS_INVALID_STRING,
+    CAIRO_STATUS_INVALID_PATH_DATA,
+    CAIRO_STATUS_READ_ERROR,
+    CAIRO_STATUS_WRITE_ERROR,
+    CAIRO_STATUS_SURFACE_FINISHED,
+    CAIRO_STATUS_SURFACE_TYPE_MISMATCH,
+    CAIRO_STATUS_PATTERN_TYPE_MISMATCH,
+    CAIRO_STATUS_INVALID_CONTENT,
+    CAIRO_STATUS_INVALID_FORMAT,
+    CAIRO_STATUS_INVALID_VISUAL,
+    CAIRO_STATUS_FILE_NOT_FOUND,
+    CAIRO_STATUS_INVALID_DASH,
+    CAIRO_STATUS_INVALID_DSC_COMMENT,
+    CAIRO_STATUS_INVALID_INDEX,
+    CAIRO_STATUS_CLIP_NOT_REPRESENTABLE,
+    CAIRO_STATUS_TEMP_FILE_ERROR,
+    CAIRO_STATUS_INVALID_STRIDE,
+    CAIRO_STATUS_FONT_TYPE_MISMATCH,
+    CAIRO_STATUS_USER_FONT_IMMUTABLE,
+    CAIRO_STATUS_USER_FONT_ERROR,
+    CAIRO_STATUS_NEGATIVE_COUNT,
+    CAIRO_STATUS_INVALID_CLUSTERS,
+    CAIRO_STATUS_INVALID_SLANT,
+    CAIRO_STATUS_INVALID_WEIGHT,
+    CAIRO_STATUS_INVALID_SIZE,
+    CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED,
+
+    CAIRO_STATUS_LAST_STATUS
+} cairo_status_t;
+
+/**
+ * cairo_fill_rule_t:
+ * @CAIRO_FILL_RULE_WINDING: If the path crosses the ray from
+ * left-to-right, counts +1. If the path crosses the ray
+ * from right to left, counts -1. (Left and right are determined
+ * from the perspective of looking along the ray from the starting
+ * point.) If the total count is non-zero, the point will be filled.
+ * @CAIRO_FILL_RULE_EVEN_ODD: Counts the total number of
+ * intersections, without regard to the orientation of the contour. If
+ * the total number of intersections is odd, the point will be
+ * filled.
+ *
+ * #cairo_fill_rule_t is used to select how paths are filled. For both
+ * fill rules, whether or not a point is included in the fill is
+ * determined by taking a ray from that point to infinity and looking
+ * at intersections with the path. The ray can be in any direction,
+ * as long as it doesn't pass through the end point of a segment
+ * or have a tricky intersection such as intersecting tangent to the path.
+ * (Note that filling is not actually implemented in this way. This
+ * is just a description of the rule that is applied.)
+ *
+ * The default fill rule is %CAIRO_FILL_RULE_WINDING.
+ *
+ * New entries may be added in future versions.
+ **/
+typedef enum _cairo_fill_rule {
+    CAIRO_FILL_RULE_WINDING,
+    CAIRO_FILL_RULE_EVEN_ODD
+} cairo_fill_rule_t;
+
+/* Region functions */
+
+typedef struct _cairo_region cairo_region_t;
+
+typedef struct _cairo_rectangle_int {
+    int x, y;
+    int width, height;
+} cairo_rectangle_int_t;
+
+typedef enum _cairo_region_overlap {
+    CAIRO_REGION_OVERLAP_IN,		/* completely inside region */
+    CAIRO_REGION_OVERLAP_OUT,		/* completely outside region */
+    CAIRO_REGION_OVERLAP_PART		/* partly inside region */
+} cairo_region_overlap_t;
+
+CAIRO_END_DECLS
+
+#endif /* _CAIRO_MINIMAL_H_ */
diff --git a/src/cairo/cairo-traps-private.h b/src/cairo/cairo-traps-private.h
new file mode 100644
index 0000000..ac26aee
--- /dev/null
+++ b/src/cairo/cairo-traps-private.h
@@ -0,0 +1,152 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2002 University of Southern California
+ * Copyright © 2005 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is University of Southern
+ * California.
+ *
+ * Contributor(s):
+ *	Carl D. Worth <cworth@xxxxxxxxxx>
+ */
+
+/*
+ * These definitions are solely for use by the implementation of cairo
+ * and constitute no kind of standard.  If you need any of these
+ * functions, please drop me a note.  Either the library needs new
+ * functionality, or there's a way to do what you need using the
+ * existing published interfaces. cworth@xxxxxxxxxx
+ */
+
+#ifndef _CAIRO_TRAPS_PRIVATE_H_
+#define _CAIRO_TRAPS_PRIVATE_H_
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "cairo-types-private.h"
+
+typedef struct _cairo_traps {
+    cairo_status_t status;
+
+    const cairo_box_t *limits;
+    int num_limits;
+
+    unsigned int maybe_region : 1; /* hint: 0 implies that it cannot be */
+    unsigned int has_intersections : 1;
+    unsigned int is_rectilinear : 1;
+    unsigned int is_rectangular : 1;
+
+    int num_traps;
+    int traps_size;
+    cairo_trapezoid_t *traps;
+    cairo_trapezoid_t  traps_embedded[16];
+} cairo_traps_t;
+
+
+/* cairo-traps.c */
+cairo_private void
+_cairo_traps_init (cairo_traps_t *traps);
+
+cairo_private void
+_cairo_traps_limit (cairo_traps_t	*traps,
+		    const cairo_box_t	*boxes,
+		    int			 num_boxes);
+
+cairo_private cairo_status_t
+_cairo_traps_init_boxes (cairo_traps_t	    *traps,
+			 const cairo_box_t    *boxes,
+			 int		     num_boxes);
+
+cairo_private void
+_cairo_traps_clear (cairo_traps_t *traps);
+
+cairo_private void
+_cairo_traps_fini (cairo_traps_t *traps);
+
+#define _cairo_traps_status(T) (T)->status
+
+cairo_private void
+_cairo_traps_translate (cairo_traps_t *traps, int x, int y);
+
+cairo_private cairo_status_t
+_cairo_traps_tessellate_rectangle (cairo_traps_t *traps,
+				   const cairo_point_t *top_left,
+				   const cairo_point_t *bottom_right);
+
+cairo_private void
+_cairo_traps_add_trap (cairo_traps_t *traps,
+		       cairo_fixed_t top, cairo_fixed_t bottom,
+		       cairo_line_t *left, cairo_line_t *right);
+
+cairo_private cairo_status_t
+_cairo_bentley_ottmann_tessellate_rectilinear_polygon (cairo_traps_t	 *traps,
+						       const cairo_polygon_t *polygon,
+						       cairo_fill_rule_t	  fill_rule);
+
+cairo_private cairo_status_t
+_cairo_bentley_ottmann_tessellate_polygon (cairo_traps_t         *traps,
+					   const cairo_polygon_t *polygon);
+
+cairo_private cairo_status_t
+_cairo_bentley_ottmann_tessellate_traps (cairo_traps_t *traps,
+					 cairo_fill_rule_t fill_rule);
+
+cairo_private cairo_status_t
+_cairo_bentley_ottmann_tessellate_rectangular_traps (cairo_traps_t *traps,
+						     cairo_fill_rule_t fill_rule);
+
+cairo_private cairo_status_t
+_cairo_bentley_ottmann_tessellate_rectilinear_traps (cairo_traps_t *traps,
+						     cairo_fill_rule_t fill_rule);
+
+cairo_private int
+_cairo_traps_contain (const cairo_traps_t *traps,
+		      double x, double y);
+
+cairo_private void
+_cairo_traps_extents (const cairo_traps_t *traps,
+		      cairo_box_t         *extents);
+
+cairo_private cairo_int_status_t
+_cairo_traps_extract_region (cairo_traps_t  *traps,
+			     cairo_region_t **region);
+
+cairo_private cairo_status_t
+_cairo_traps_path (const cairo_traps_t *traps,
+		   cairo_path_fixed_t  *path);
+
+cairo_private void
+_cairo_trapezoid_array_translate_and_scale (cairo_trapezoid_t *offset_traps,
+					    cairo_trapezoid_t *src_traps,
+					    int num_traps,
+					    double tx, double ty,
+					    double sx, double sy);
+
+#endif
diff --git a/src/cairo/cairo-traps.c b/src/cairo/cairo-traps.c
new file mode 100644
index 0000000..089f3c6
--- /dev/null
+++ b/src/cairo/cairo-traps.c
@@ -0,0 +1,438 @@
+/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
+/*
+ * Copyright © 2002 Keith Packard
+ * Copyright © 2007 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is Keith Packard
+ *
+ * Contributor(s):
+ *	Keith R. Packard <keithp@xxxxxxxxxx>
+ *	Carl D. Worth <cworth@xxxxxxxxxx>
+ *
+ * 2002-07-15: Converted from XRenderCompositeDoublePoly to #cairo_trap_t. Carl D. Worth
+ */
+
+#include "cairoint-minimal.h"
+#include "cairo-malloc-private.h"
+#include "cairo-traps-private.h"
+#include "cairo-fixed-private.h"
+
+#define _cairo_error(x) (x)
+
+/* private functions */
+
+void
+_cairo_traps_init (cairo_traps_t *traps)
+{
+    VG (VALGRIND_MAKE_MEM_UNDEFINED (traps, sizeof (cairo_traps_t)));
+
+    traps->status = CAIRO_STATUS_SUCCESS;
+
+    traps->maybe_region = 1;
+    traps->is_rectilinear = 0;
+    traps->is_rectangular = 0;
+
+    traps->num_traps = 0;
+
+    traps->traps_size = ARRAY_LENGTH (traps->traps_embedded);
+    traps->traps = traps->traps_embedded;
+
+    traps->num_limits = 0;
+    traps->has_intersections = FALSE;
+}
+
+void
+_cairo_traps_limit (cairo_traps_t	*traps,
+		    const cairo_box_t	*limits,
+		    int			 num_limits)
+{
+    traps->limits = limits;
+    traps->num_limits = num_limits;
+}
+
+void
+_cairo_traps_clear (cairo_traps_t *traps)
+{
+    traps->status = CAIRO_STATUS_SUCCESS;
+
+    traps->maybe_region = 1;
+    traps->is_rectilinear = 0;
+    traps->is_rectangular = 0;
+
+    traps->num_traps = 0;
+    traps->has_intersections = FALSE;
+}
+
+void
+_cairo_traps_fini (cairo_traps_t *traps)
+{
+    if (traps->traps != traps->traps_embedded)
+	free (traps->traps);
+
+    VG (VALGRIND_MAKE_MEM_NOACCESS (traps, sizeof (cairo_traps_t)));
+}
+
+/* make room for at least one more trap */
+static cairo_bool_t
+_cairo_traps_grow (cairo_traps_t *traps)
+{
+    cairo_trapezoid_t *new_traps;
+    int new_size = 4 * traps->traps_size;
+
+    if (traps->traps == traps->traps_embedded) {
+	new_traps = _cairo_malloc_ab (new_size, sizeof (cairo_trapezoid_t));
+	if (new_traps != NULL)
+	    memcpy (new_traps, traps->traps, sizeof (traps->traps_embedded));
+    } else {
+	new_traps = _cairo_realloc_ab (traps->traps,
+	                               new_size, sizeof (cairo_trapezoid_t));
+    }
+
+    if (unlikely (new_traps == NULL)) {
+	traps->status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+	return FALSE;
+    }
+
+    traps->traps = new_traps;
+    traps->traps_size = new_size;
+    return TRUE;
+}
+
+void
+_cairo_traps_add_trap (cairo_traps_t *traps,
+		       cairo_fixed_t top, cairo_fixed_t bottom,
+		       cairo_line_t *left, cairo_line_t *right)
+{
+    cairo_trapezoid_t *trap;
+
+    if (unlikely (traps->num_traps == traps->traps_size)) {
+	if (unlikely (! _cairo_traps_grow (traps)))
+	    return;
+    }
+
+    trap = &traps->traps[traps->num_traps++];
+    trap->top = top;
+    trap->bottom = bottom;
+    trap->left = *left;
+    trap->right = *right;
+}
+
+/**
+ * _cairo_traps_init_box:
+ * @traps: a #cairo_traps_t
+ * @box: an array box that will each be converted to a single trapezoid
+ *       to store in @traps.
+ *
+ * Initializes a #cairo_traps_t to contain an array of rectangular
+ * trapezoids.
+ **/
+cairo_status_t
+_cairo_traps_init_boxes (cairo_traps_t	    *traps,
+		         const cairo_box_t  *boxes,
+			 int		     num_boxes)
+{
+    cairo_trapezoid_t *trap;
+
+    _cairo_traps_init (traps);
+
+    while (traps->traps_size < num_boxes) {
+	if (unlikely (! _cairo_traps_grow (traps))) {
+	    _cairo_traps_fini (traps);
+	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+	}
+    }
+
+    traps->num_traps = num_boxes;
+    traps->is_rectilinear = TRUE;
+    traps->is_rectangular = TRUE;
+
+    trap = &traps->traps[0];
+    while (num_boxes--) {
+	trap->top    = boxes->p1.y;
+	trap->bottom = boxes->p2.y;
+
+	trap->left.p1   = boxes->p1;
+	trap->left.p2.x = boxes->p1.x;
+	trap->left.p2.y = boxes->p2.y;
+
+	trap->right.p1.x = boxes->p2.x;
+	trap->right.p1.y = boxes->p1.y;
+	trap->right.p2   = boxes->p2;
+
+	if (traps->maybe_region) {
+	    traps->maybe_region  = _cairo_fixed_is_integer (boxes->p1.x) &&
+		                   _cairo_fixed_is_integer (boxes->p1.y) &&
+		                   _cairo_fixed_is_integer (boxes->p2.x) &&
+		                   _cairo_fixed_is_integer (boxes->p2.y);
+	}
+
+	trap++, boxes++;
+    }
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+cairo_status_t
+_cairo_traps_tessellate_rectangle (cairo_traps_t *traps,
+				   const cairo_point_t *top_left,
+				   const cairo_point_t *bottom_right)
+{
+    cairo_line_t left;
+    cairo_line_t right;
+    cairo_fixed_t top, bottom;
+
+    if (top_left->y == bottom_right->y)
+	return CAIRO_STATUS_SUCCESS;
+
+    if (top_left->x == bottom_right->x)
+	return CAIRO_STATUS_SUCCESS;
+
+     left.p1.x =  left.p2.x = top_left->x;
+     left.p1.y = right.p1.y = top_left->y;
+    right.p1.x = right.p2.x = bottom_right->x;
+     left.p2.y = right.p2.y = bottom_right->y;
+
+     top = top_left->y;
+     bottom = bottom_right->y;
+
+    if (traps->num_limits) {
+	cairo_bool_t reversed;
+	int n;
+
+	/* support counter-clockwise winding for rectangular tessellation */
+	reversed = top_left->x > bottom_right->x;
+	if (reversed) {
+	    right.p1.x = right.p2.x = top_left->x;
+	    left.p1.x = left.p2.x = bottom_right->x;
+	}
+
+	for (n = 0; n < traps->num_limits; n++) {
+	    const cairo_box_t *limits = &traps->limits[n];
+	    cairo_line_t _left, _right;
+	    cairo_fixed_t _top, _bottom;
+
+	    if (top >= limits->p2.y)
+		continue;
+	    if (bottom <= limits->p1.y)
+		continue;
+
+	    /* Trivially reject if trapezoid is entirely to the right or
+	     * to the left of the limits. */
+	    if (left.p1.x >= limits->p2.x)
+		continue;
+	    if (right.p1.x <= limits->p1.x)
+		continue;
+
+	    /* Otherwise, clip the trapezoid to the limits. */
+	    _top = top;
+	    if (_top < limits->p1.y)
+		_top = limits->p1.y;
+
+	    _bottom = bottom;
+	    if (_bottom > limits->p2.y)
+		_bottom = limits->p2.y;
+
+	    if (_bottom <= _top)
+		continue;
+
+	    _left = left;
+	    if (_left.p1.x < limits->p1.x) {
+		_left.p1.x = limits->p1.x;
+		_left.p1.y = limits->p1.y;
+		_left.p2.x = limits->p1.x;
+		_left.p2.y = limits->p2.y;
+	    }
+
+	    _right = right;
+	    if (_right.p1.x > limits->p2.x) {
+		_right.p1.x = limits->p2.x;
+		_right.p1.y = limits->p1.y;
+		_right.p2.x = limits->p2.x;
+		_right.p2.y = limits->p2.y;
+	    }
+
+	    if (left.p1.x >= right.p1.x)
+		continue;
+
+	    if (reversed)
+		_cairo_traps_add_trap (traps, _top, _bottom, &_right, &_left);
+	    else
+		_cairo_traps_add_trap (traps, _top, _bottom, &_left, &_right);
+	}
+    } else {
+	_cairo_traps_add_trap (traps, top, bottom, &left, &right);
+    }
+
+    return traps->status;
+}
+
+void
+_cairo_traps_translate (cairo_traps_t *traps, int x, int y)
+{
+    cairo_fixed_t xoff, yoff;
+    cairo_trapezoid_t *t;
+    int i;
+
+    /* Ugh. The cairo_composite/(Render) interface doesn't allow
+       an offset for the trapezoids. Need to manually shift all
+       the coordinates to align with the offset origin of the
+       intermediate surface. */
+
+    xoff = _cairo_fixed_from_int (x);
+    yoff = _cairo_fixed_from_int (y);
+
+    for (i = 0, t = traps->traps; i < traps->num_traps; i++, t++) {
+	t->top += yoff;
+	t->bottom += yoff;
+	t->left.p1.x += xoff;
+	t->left.p1.y += yoff;
+	t->left.p2.x += xoff;
+	t->left.p2.y += yoff;
+	t->right.p1.x += xoff;
+	t->right.p1.y += yoff;
+	t->right.p2.x += xoff;
+	t->right.p2.y += yoff;
+    }
+}
+
+void
+_cairo_trapezoid_array_translate_and_scale (cairo_trapezoid_t *offset_traps,
+                                            cairo_trapezoid_t *src_traps,
+                                            int num_traps,
+                                            double tx, double ty,
+                                            double sx, double sy)
+{
+    int i;
+    cairo_fixed_t xoff = _cairo_fixed_from_double (tx);
+    cairo_fixed_t yoff = _cairo_fixed_from_double (ty);
+
+    if (sx == 1.0 && sy == 1.0) {
+        for (i = 0; i < num_traps; i++) {
+            offset_traps[i].top = src_traps[i].top + yoff;
+            offset_traps[i].bottom = src_traps[i].bottom + yoff;
+            offset_traps[i].left.p1.x = src_traps[i].left.p1.x + xoff;
+            offset_traps[i].left.p1.y = src_traps[i].left.p1.y + yoff;
+            offset_traps[i].left.p2.x = src_traps[i].left.p2.x + xoff;
+            offset_traps[i].left.p2.y = src_traps[i].left.p2.y + yoff;
+            offset_traps[i].right.p1.x = src_traps[i].right.p1.x + xoff;
+            offset_traps[i].right.p1.y = src_traps[i].right.p1.y + yoff;
+            offset_traps[i].right.p2.x = src_traps[i].right.p2.x + xoff;
+            offset_traps[i].right.p2.y = src_traps[i].right.p2.y + yoff;
+        }
+    } else {
+        cairo_fixed_t xsc = _cairo_fixed_from_double (sx);
+        cairo_fixed_t ysc = _cairo_fixed_from_double (sy);
+
+        for (i = 0; i < num_traps; i++) {
+            offset_traps[i].top = _cairo_fixed_mul (src_traps[i].top + yoff, ysc);
+            offset_traps[i].bottom = _cairo_fixed_mul (src_traps[i].bottom + yoff, ysc);
+            offset_traps[i].left.p1.x = _cairo_fixed_mul (src_traps[i].left.p1.x + xoff, xsc);
+            offset_traps[i].left.p1.y = _cairo_fixed_mul (src_traps[i].left.p1.y + yoff, ysc);
+            offset_traps[i].left.p2.x = _cairo_fixed_mul (src_traps[i].left.p2.x + xoff, xsc);
+            offset_traps[i].left.p2.y = _cairo_fixed_mul (src_traps[i].left.p2.y + yoff, ysc);
+            offset_traps[i].right.p1.x = _cairo_fixed_mul (src_traps[i].right.p1.x + xoff, xsc);
+            offset_traps[i].right.p1.y = _cairo_fixed_mul (src_traps[i].right.p1.y + yoff, ysc);
+            offset_traps[i].right.p2.x = _cairo_fixed_mul (src_traps[i].right.p2.x + xoff, xsc);
+            offset_traps[i].right.p2.y = _cairo_fixed_mul (src_traps[i].right.p2.y + yoff, ysc);
+        }
+    }
+}
+
+static cairo_fixed_t
+_line_compute_intersection_x_for_y (const cairo_line_t *line,
+				    cairo_fixed_t y)
+{
+    return _cairo_edge_compute_intersection_x_for_y (&line->p1, &line->p2, y);
+}
+
+void
+_cairo_traps_extents (const cairo_traps_t *traps,
+		      cairo_box_t *extents)
+{
+    int i;
+
+    if (traps->num_traps == 0) {
+	extents->p1.x = extents->p1.y = 0;
+	extents->p2.x = extents->p2.y = 0;
+	return;
+    }
+
+    extents->p1.x = extents->p1.y = INT32_MAX;
+    extents->p2.x = extents->p2.y = INT32_MIN;
+
+    for (i = 0; i < traps->num_traps; i++) {
+	const cairo_trapezoid_t *trap =  &traps->traps[i];
+
+	if (trap->top < extents->p1.y)
+	    extents->p1.y = trap->top;
+	if (trap->bottom > extents->p2.y)
+	    extents->p2.y = trap->bottom;
+
+	if (trap->left.p1.x < extents->p1.x) {
+	    cairo_fixed_t x = trap->left.p1.x;
+	    if (trap->top != trap->left.p1.y) {
+		x = _line_compute_intersection_x_for_y (&trap->left,
+							trap->top);
+		if (x < extents->p1.x)
+		    extents->p1.x = x;
+	    } else
+		extents->p1.x = x;
+	}
+	if (trap->left.p2.x < extents->p1.x) {
+	    cairo_fixed_t x = trap->left.p2.x;
+	    if (trap->bottom != trap->left.p2.y) {
+		x = _line_compute_intersection_x_for_y (&trap->left,
+							trap->bottom);
+		if (x < extents->p1.x)
+		    extents->p1.x = x;
+	    } else
+		extents->p1.x = x;
+	}
+
+	if (trap->right.p1.x > extents->p2.x) {
+	    cairo_fixed_t x = trap->right.p1.x;
+	    if (trap->top != trap->right.p1.y) {
+		x = _line_compute_intersection_x_for_y (&trap->right,
+							trap->top);
+		if (x > extents->p2.x)
+		    extents->p2.x = x;
+	    } else
+		extents->p2.x = x;
+	}
+	if (trap->right.p2.x > extents->p2.x) {
+	    cairo_fixed_t x = trap->right.p2.x;
+	    if (trap->bottom != trap->right.p2.y) {
+		x = _line_compute_intersection_x_for_y (&trap->right,
+							trap->bottom);
+		if (x > extents->p2.x)
+		    extents->p2.x = x;
+	    } else
+		extents->p2.x = x;
+	}
+    }
+}
diff --git a/src/cairo/cairo-types-private.h b/src/cairo/cairo-types-private.h
new file mode 100644
index 0000000..44c29b9
--- /dev/null
+++ b/src/cairo/cairo-types-private.h
@@ -0,0 +1,206 @@
+/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2002 University of Southern California
+ * Copyright © 2005 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is University of Southern
+ * California.
+ *
+ * Contributor(s):
+ *	Carl D. Worth <cworth@xxxxxxxxxx>
+ */
+
+#ifndef CAIRO_TYPES_PRIVATE_H
+#define CAIRO_TYPES_PRIVATE_H
+
+#include "cairo-minimal.h"
+#include "cairo-fixed-type-private.h"
+#include "cairo-compiler-private.h"
+
+typedef struct _cairo_array cairo_array_t;
+typedef struct _cairo_backend cairo_backend_t;
+typedef struct _cairo_cache cairo_cache_t;
+typedef struct _cairo_clip cairo_clip_t;
+typedef struct _cairo_clip_path cairo_clip_path_t;
+typedef struct _cairo_gstate cairo_gstate_t;
+typedef struct _cairo_hash_entry cairo_hash_entry_t;
+typedef struct _cairo_hash_table cairo_hash_table_t;
+typedef struct _cairo_path_fixed cairo_path_fixed_t;
+
+typedef cairo_array_t cairo_user_data_array_t;
+
+/**
+ * cairo_hash_entry_t:
+ *
+ * A #cairo_hash_entry_t contains both a key and a value for
+ * #cairo_hash_table_t. User-derived types for #cairo_hash_entry_t must
+ * be type-compatible with this structure (eg. they must have an
+ * unsigned long as the first parameter. The easiest way to get this
+ * is to use:
+ *
+ * 	typedef _my_entry {
+ *	    cairo_hash_entry_t base;
+ *	    ... Remainder of key and value fields here ..
+ *	} my_entry_t;
+ *
+ * which then allows a pointer to my_entry_t to be passed to any of
+ * the #cairo_hash_table_t functions as follows without requiring a cast:
+ *
+ *	_cairo_hash_table_insert (hash_table, &my_entry->base);
+ *
+ * IMPORTANT: The caller is reponsible for initializing
+ * my_entry->base.hash with a hash code derived from the key. The
+ * essential property of the hash code is that keys_equal must never
+ * return %TRUE for two keys that have different hashes. The best hash
+ * code will reduce the frequency of two keys with the same code for
+ * which keys_equal returns %FALSE.
+ *
+ * Which parts of the entry make up the "key" and which part make up
+ * the value are entirely up to the caller, (as determined by the
+ * computation going into base.hash as well as the keys_equal
+ * function). A few of the #cairo_hash_table_t functions accept an entry
+ * which will be used exclusively as a "key", (indicated by a
+ * parameter name of key). In these cases, the value-related fields of
+ * the entry need not be initialized if so desired.
+ **/
+struct _cairo_hash_entry {
+    unsigned long hash;
+};
+
+struct _cairo_array {
+    unsigned int size;
+    unsigned int num_elements;
+    unsigned int element_size;
+    char **elements;
+
+    cairo_bool_t is_snapshot;
+};
+
+/* Sure wish C had a real enum type so that this would be distinct
+ * from #cairo_status_t. Oh well, without that, I'll use this bogus 100
+ * offset.  We want to keep it fit in int8_t as the compiler may choose
+ * that for #cairo_status_t */
+typedef enum _cairo_int_status {
+    CAIRO_INT_STATUS_UNSUPPORTED = 100,
+    CAIRO_INT_STATUS_DEGENERATE,
+    CAIRO_INT_STATUS_NOTHING_TO_DO,
+    CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY,
+    CAIRO_INT_STATUS_IMAGE_FALLBACK,
+    CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN,
+
+    CAIRO_INT_STATUS_LAST_STATUS
+} cairo_int_status_t;
+
+typedef struct _cairo_slope {
+    cairo_fixed_t dx;
+    cairo_fixed_t dy;
+} cairo_slope_t, cairo_distance_t;
+
+typedef struct _cairo_point_double {
+    double x;
+    double y;
+} cairo_point_double_t;
+
+typedef struct _cairo_distance_double {
+    double dx;
+    double dy;
+} cairo_distance_double_t;
+
+typedef struct _cairo_line {
+    cairo_point_t p1;
+    cairo_point_t p2;
+} cairo_line_t, cairo_box_t;
+
+typedef struct _cairo_trapezoid {
+    cairo_fixed_t top, bottom;
+    cairo_line_t left, right;
+} cairo_trapezoid_t;
+
+typedef struct _cairo_point_int {
+    int x, y;
+} cairo_point_int_t;
+
+#define CAIRO_RECT_INT_MIN (INT_MIN >> CAIRO_FIXED_FRAC_BITS)
+#define CAIRO_RECT_INT_MAX (INT_MAX >> CAIRO_FIXED_FRAC_BITS)
+
+/* Rectangles that take part in a composite operation.
+ *
+ * This defines four translations that define which pixels of the
+ * source pattern, mask, clip and destination surface take part in a
+ * general composite operation.  The idea is that the pixels at
+ *
+ *	(i,j)+(src.x, src.y) of the source,
+ *      (i,j)+(mask.x, mask.y) of the mask,
+ *      (i,j)+(clip.x, clip.y) of the clip and
+ *      (i,j)+(dst.x, dst.y) of the destination
+ *
+ * all combine together to form the result at (i,j)+(dst.x,dst.y),
+ * for i,j ranging in [0,width) and [0,height) respectively.
+ */
+typedef struct _cairo_composite_rectangles {
+        cairo_point_int_t src;
+        cairo_point_int_t mask;
+        cairo_point_int_t clip;
+        cairo_point_int_t dst;
+        int width;
+        int height;
+} cairo_composite_rectangles_t;
+
+typedef struct _cairo_edge {
+    cairo_line_t line;
+    int top, bottom;
+    int dir;
+} cairo_edge_t;
+
+typedef struct _cairo_polygon {
+    cairo_status_t status;
+
+    cairo_point_t first_point;
+    cairo_point_t last_point;
+    cairo_point_t current_point;
+    cairo_slope_t current_edge;
+    cairo_bool_t has_current_point;
+    cairo_bool_t has_current_edge;
+
+    cairo_box_t extents;
+    cairo_box_t limit;
+    const cairo_box_t *limits;
+    int num_limits;
+
+    int num_edges;
+    int edges_size;
+    cairo_edge_t *edges;
+    cairo_edge_t  edges_embedded[32];
+} cairo_polygon_t;
+
+typedef cairo_warn cairo_status_t
+(*cairo_spline_add_point_func_t) (void *closure,
+				  const cairo_point_t *point);
+
+#endif /* CAIRO_TYPES_PRIVATE_H */
diff --git a/src/cairo/cairo-wideint-private.h b/src/cairo/cairo-wideint-private.h
new file mode 100644
index 0000000..303dab1
--- /dev/null
+++ b/src/cairo/cairo-wideint-private.h
@@ -0,0 +1,329 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2004 Keith Packard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is Keith Packard
+ *
+ * Contributor(s):
+ *	Keith R. Packard <keithp@xxxxxxxxxx>
+ *
+ */
+
+#ifndef CAIRO_WIDEINT_H
+#define CAIRO_WIDEINT_H
+
+#include "cairo-wideint-type-private.h"
+
+#include "cairo-compiler-private.h"
+
+/*
+ * 64-bit datatypes.  Two separate implementations, one using
+ * built-in 64-bit signed/unsigned types another implemented
+ * as a pair of 32-bit ints
+ */
+
+#define I cairo_private cairo_const
+
+#if !HAVE_UINT64_T
+
+cairo_uquorem64_t I
+_cairo_uint64_divrem (cairo_uint64_t num, cairo_uint64_t den);
+
+cairo_uint64_t I	_cairo_uint32_to_uint64 (uint32_t i);
+#define			_cairo_uint64_to_uint32(a)  ((a).lo)
+cairo_uint64_t I	_cairo_uint64_add (cairo_uint64_t a, cairo_uint64_t b);
+cairo_uint64_t I	_cairo_uint64_sub (cairo_uint64_t a, cairo_uint64_t b);
+cairo_uint64_t I	_cairo_uint64_mul (cairo_uint64_t a, cairo_uint64_t b);
+cairo_uint64_t I	_cairo_uint32x32_64_mul (uint32_t a, uint32_t b);
+cairo_uint64_t I	_cairo_uint64_lsl (cairo_uint64_t a, int shift);
+cairo_uint64_t I	_cairo_uint64_rsl (cairo_uint64_t a, int shift);
+cairo_uint64_t I	_cairo_uint64_rsa (cairo_uint64_t a, int shift);
+int	       I	_cairo_uint64_lt (cairo_uint64_t a, cairo_uint64_t b);
+int	       I	_cairo_uint64_cmp (cairo_uint64_t a, cairo_uint64_t b);
+int	       I	_cairo_uint64_eq (cairo_uint64_t a, cairo_uint64_t b);
+cairo_uint64_t I	_cairo_uint64_negate (cairo_uint64_t a);
+#define			_cairo_uint64_is_zero(a) ((a).hi == 0 && (a).lo == 0)
+#define			_cairo_uint64_negative(a)   (((int32_t) ((a).hi)) < 0)
+cairo_uint64_t I	_cairo_uint64_not (cairo_uint64_t a);
+
+#define			_cairo_uint64_to_int64(i)   (i)
+#define			_cairo_int64_to_uint64(i)   (i)
+
+cairo_int64_t  I	_cairo_int32_to_int64(int32_t i);
+#define			_cairo_int64_to_int32(a)    ((int32_t) _cairo_uint64_to_uint32(a))
+#define			_cairo_int64_add(a,b)	    _cairo_uint64_add (a,b)
+#define			_cairo_int64_sub(a,b)	    _cairo_uint64_sub (a,b)
+#define			_cairo_int64_mul(a,b)	    _cairo_uint64_mul (a,b)
+cairo_int64_t  I	_cairo_int32x32_64_mul (int32_t a, int32_t b);
+int	       I	_cairo_int64_lt (cairo_int64_t a, cairo_int64_t b);
+int	       I	_cairo_int64_cmp (cairo_int64_t a, cairo_int64_t b);
+#define			_cairo_int64_is_zero(a)	    _cairo_uint64_is_zero (a)
+#define			_cairo_int64_eq(a,b)	    _cairo_uint64_eq (a,b)
+#define			_cairo_int64_lsl(a,b)	    _cairo_uint64_lsl (a,b)
+#define			_cairo_int64_rsl(a,b)	    _cairo_uint64_rsl (a,b)
+#define			_cairo_int64_rsa(a,b)	    _cairo_uint64_rsa (a,b)
+#define			_cairo_int64_negate(a)	    _cairo_uint64_negate(a)
+#define			_cairo_int64_negative(a)    (((int32_t) ((a).hi)) < 0)
+#define			_cairo_int64_not(a)	    _cairo_uint64_not(a)
+
+#else
+
+static inline cairo_uquorem64_t
+_cairo_uint64_divrem (cairo_uint64_t num, cairo_uint64_t den)
+{
+    cairo_uquorem64_t	qr;
+
+    qr.quo = num / den;
+    qr.rem = num % den;
+    return qr;
+}
+
+#define			_cairo_uint32_to_uint64(i)  ((uint64_t) (i))
+#define			_cairo_uint64_to_uint32(i)  ((uint32_t) (i))
+#define			_cairo_uint64_add(a,b)	    ((a) + (b))
+#define			_cairo_uint64_sub(a,b)	    ((a) - (b))
+#define			_cairo_uint64_mul(a,b)	    ((a) * (b))
+#define			_cairo_uint32x32_64_mul(a,b)	((uint64_t) (a) * (b))
+#define			_cairo_uint64_lsl(a,b)	    ((a) << (b))
+#define			_cairo_uint64_rsl(a,b)	    ((uint64_t) (a) >> (b))
+#define			_cairo_uint64_rsa(a,b)	    ((uint64_t) ((int64_t) (a) >> (b)))
+#define			_cairo_uint64_lt(a,b)	    ((a) < (b))
+#define                 _cairo_uint64_cmp(a,b)       ((a) == (b) ? 0 : (a) < (b) ? -1 : 1)
+#define			_cairo_uint64_is_zero(a)    ((a) == 0)
+#define			_cairo_uint64_eq(a,b)	    ((a) == (b))
+#define			_cairo_uint64_negate(a)	    ((uint64_t) -((int64_t) (a)))
+#define			_cairo_uint64_negative(a)   ((int64_t) (a) < 0)
+#define			_cairo_uint64_not(a)	    (~(a))
+
+#define			_cairo_uint64_to_int64(i)   ((int64_t) (i))
+#define			_cairo_int64_to_uint64(i)   ((uint64_t) (i))
+
+#define			_cairo_int32_to_int64(i)    ((int64_t) (i))
+#define			_cairo_int64_to_int32(i)    ((int32_t) (i))
+#define			_cairo_int64_add(a,b)	    ((a) + (b))
+#define			_cairo_int64_sub(a,b)	    ((a) - (b))
+#define			_cairo_int64_mul(a,b)	    ((a) * (b))
+#define			_cairo_int32x32_64_mul(a,b) ((int64_t) (a) * (b))
+#define			_cairo_int64_lt(a,b)	    ((a) < (b))
+#define                 _cairo_int64_cmp(a,b)       ((a) == (b) ? 0 : (a) < (b) ? -1 : 1)
+#define			_cairo_int64_is_zero(a)     ((a) == 0)
+#define			_cairo_int64_eq(a,b)	    ((a) == (b))
+#define			_cairo_int64_lsl(a,b)	    ((a) << (b))
+#define			_cairo_int64_rsl(a,b)	    ((int64_t) ((uint64_t) (a) >> (b)))
+#define			_cairo_int64_rsa(a,b)	    ((int64_t) (a) >> (b))
+#define			_cairo_int64_negate(a)	    (-(a))
+#define			_cairo_int64_negative(a)    ((a) < 0)
+#define			_cairo_int64_not(a)	    (~(a))
+
+#endif
+
+/*
+ * 64-bit comparisions derived from lt or eq
+ */
+#define			_cairo_uint64_le(a,b)	    (!_cairo_uint64_gt(a,b))
+#define			_cairo_uint64_ne(a,b)	    (!_cairo_uint64_eq(a,b))
+#define			_cairo_uint64_ge(a,b)	    (!_cairo_uint64_lt(a,b))
+#define			_cairo_uint64_gt(a,b)	    _cairo_uint64_lt(b,a)
+
+#define			_cairo_int64_le(a,b)	    (!_cairo_int64_gt(a,b))
+#define			_cairo_int64_ne(a,b)	    (!_cairo_int64_eq(a,b))
+#define			_cairo_int64_ge(a,b)	    (!_cairo_int64_lt(a,b))
+#define			_cairo_int64_gt(a,b)	    _cairo_int64_lt(b,a)
+
+/*
+ * As the C implementation always computes both, create
+ * a function which returns both for the 'native' type as well
+ */
+
+static inline cairo_quorem64_t
+_cairo_int64_divrem (cairo_int64_t num, cairo_int64_t den)
+{
+    int			num_neg = _cairo_int64_negative (num);
+    int			den_neg = _cairo_int64_negative (den);
+    cairo_uquorem64_t	uqr;
+    cairo_quorem64_t	qr;
+
+    if (num_neg)
+	num = _cairo_int64_negate (num);
+    if (den_neg)
+	den = _cairo_int64_negate (den);
+    uqr = _cairo_uint64_divrem (num, den);
+    if (num_neg)
+	qr.rem = _cairo_int64_negate (uqr.rem);
+    else
+	qr.rem = uqr.rem;
+    if (num_neg != den_neg)
+	qr.quo = (cairo_int64_t) _cairo_int64_negate (uqr.quo);
+    else
+	qr.quo = (cairo_int64_t) uqr.quo;
+    return qr;
+}
+
+#if 0
+static inline int32_t
+_cairo_int64_32_div (cairo_int64_t num, int32_t den)
+{
+    return num / den;
+}
+#endif
+
+static inline int32_t
+_cairo_int64_32_div (cairo_int64_t num, int32_t den)
+{
+  cairo_quorem64_t quorem;
+  cairo_int64_t den64;
+
+  den64 = _cairo_int32_to_int64 (den);
+  quorem = _cairo_int64_divrem (num, den64);
+
+  return _cairo_int64_to_int32 (quorem.quo);
+}
+
+/*
+ * 128-bit datatypes.  Again, provide two implementations in
+ * case the machine has a native 128-bit datatype.  GCC supports int128_t
+ * on ia64
+ */
+
+#if !HAVE_UINT128_T
+
+cairo_uint128_t I	_cairo_uint32_to_uint128 (uint32_t i);
+cairo_uint128_t I	_cairo_uint64_to_uint128 (cairo_uint64_t i);
+#define			_cairo_uint128_to_uint64(a)	((a).lo)
+#define			_cairo_uint128_to_uint32(a)	_cairo_uint64_to_uint32(_cairo_uint128_to_uint64(a))
+cairo_uint128_t I	_cairo_uint128_add (cairo_uint128_t a, cairo_uint128_t b);
+cairo_uint128_t I	_cairo_uint128_sub (cairo_uint128_t a, cairo_uint128_t b);
+cairo_uint128_t I	_cairo_uint128_mul (cairo_uint128_t a, cairo_uint128_t b);
+cairo_uint128_t I	_cairo_uint64x64_128_mul (cairo_uint64_t a, cairo_uint64_t b);
+cairo_uint128_t I	_cairo_uint128_lsl (cairo_uint128_t a, int shift);
+cairo_uint128_t I	_cairo_uint128_rsl (cairo_uint128_t a, int shift);
+cairo_uint128_t I	_cairo_uint128_rsa (cairo_uint128_t a, int shift);
+int	        I	_cairo_uint128_lt (cairo_uint128_t a, cairo_uint128_t b);
+int	        I	_cairo_uint128_cmp (cairo_uint128_t a, cairo_uint128_t b);
+int	        I	_cairo_uint128_eq (cairo_uint128_t a, cairo_uint128_t b);
+#define			_cairo_uint128_is_zero(a) (_cairo_uint64_is_zero ((a).hi) && _cairo_uint64_is_zero ((a).lo))
+cairo_uint128_t I	_cairo_uint128_negate (cairo_uint128_t a);
+#define			_cairo_uint128_negative(a)  (_cairo_uint64_negative(a.hi))
+cairo_uint128_t I	_cairo_uint128_not (cairo_uint128_t a);
+
+#define			_cairo_uint128_to_int128(i)	(i)
+#define			_cairo_int128_to_uint128(i)	(i)
+
+cairo_int128_t  I	_cairo_int32_to_int128 (int32_t i);
+cairo_int128_t  I	_cairo_int64_to_int128 (cairo_int64_t i);
+#define			_cairo_int128_to_int64(a)   ((cairo_int64_t) (a).lo)
+#define			_cairo_int128_to_int32(a)   _cairo_int64_to_int32(_cairo_int128_to_int64(a))
+#define			_cairo_int128_add(a,b)	    _cairo_uint128_add(a,b)
+#define			_cairo_int128_sub(a,b)	    _cairo_uint128_sub(a,b)
+#define			_cairo_int128_mul(a,b)	    _cairo_uint128_mul(a,b)
+cairo_int128_t I _cairo_int64x64_128_mul (cairo_int64_t a, cairo_int64_t b);
+#define                 _cairo_int64x32_128_mul(a, b) _cairo_int64x64_128_mul(a, _cairo_int32_to_int64(b))
+#define			_cairo_int128_lsl(a,b)	    _cairo_uint128_lsl(a,b)
+#define			_cairo_int128_rsl(a,b)	    _cairo_uint128_rsl(a,b)
+#define			_cairo_int128_rsa(a,b)	    _cairo_uint128_rsa(a,b)
+int 	        I	_cairo_int128_lt (cairo_int128_t a, cairo_int128_t b);
+int	        I	_cairo_int128_cmp (cairo_int128_t a, cairo_int128_t b);
+#define			_cairo_int128_is_zero(a)    _cairo_uint128_is_zero (a)
+#define			_cairo_int128_eq(a,b)	    _cairo_uint128_eq (a,b)
+#define			_cairo_int128_negate(a)	    _cairo_uint128_negate(a)
+#define			_cairo_int128_negative(a)   (_cairo_uint128_negative(a))
+#define			_cairo_int128_not(a)	    _cairo_uint128_not(a)
+
+#else	/* !HAVE_UINT128_T */
+
+#define			_cairo_uint32_to_uint128(i) ((uint128_t) (i))
+#define			_cairo_uint64_to_uint128(i) ((uint128_t) (i))
+#define			_cairo_uint128_to_uint64(i) ((uint64_t) (i))
+#define			_cairo_uint128_to_uint32(i) ((uint32_t) (i))
+#define			_cairo_uint128_add(a,b)	    ((a) + (b))
+#define			_cairo_uint128_sub(a,b)	    ((a) - (b))
+#define			_cairo_uint128_mul(a,b)	    ((a) * (b))
+#define			_cairo_uint64x64_128_mul(a,b)	((uint128_t) (a) * (b))
+#define			_cairo_uint128_lsl(a,b)	    ((a) << (b))
+#define			_cairo_uint128_rsl(a,b)	    ((uint128_t) (a) >> (b))
+#define			_cairo_uint128_rsa(a,b)	    ((uint128_t) ((int128_t) (a) >> (b)))
+#define			_cairo_uint128_lt(a,b)	    ((a) < (b))
+#define			_cairo_uint128_cmp(a,b)	    ((a) == (b) ? 0 : (a) < (b) ? -1 : 1)
+#define			_cairo_uint128_is_zero(a)   ((a) == 0)
+#define			_cairo_uint128_eq(a,b)	    ((a) == (b))
+#define			_cairo_uint128_negate(a)    ((uint128_t) -((int128_t) (a)))
+#define			_cairo_uint128_negative(a)  ((int128_t) (a) < 0)
+#define			_cairo_uint128_not(a)	    (~(a))
+
+#define			_cairo_uint128_to_int128(i) ((int128_t) (i))
+#define			_cairo_int128_to_uint128(i) ((uint128_t) (i))
+
+#define			_cairo_int32_to_int128(i)   ((int128_t) (i))
+#define			_cairo_int64_to_int128(i)   ((int128_t) (i))
+#define			_cairo_int128_to_int64(i)   ((int64_t) (i))
+#define			_cairo_int128_to_int32(i)   ((int32_t) (i))
+#define			_cairo_int128_add(a,b)	    ((a) + (b))
+#define			_cairo_int128_sub(a,b)	    ((a) - (b))
+#define			_cairo_int128_mul(a,b)	    ((a) * (b))
+#define			_cairo_int64x64_128_mul(a,b) ((int128_t) (a) * (b))
+#define                 _cairo_int64x32_128_mul(a, b) _cairo_int64x64_128_mul(a, _cairo_int32_to_int64(b))
+#define			_cairo_int128_lt(a,b)	    ((a) < (b))
+#define			_cairo_int128_cmp(a,b)	    ((a) == (b) ? 0 : (a) < (b) ? -1 : 1)
+#define			_cairo_int128_is_zero(a)    ((a) == 0)
+#define			_cairo_int128_eq(a,b)	    ((a) == (b))
+#define			_cairo_int128_lsl(a,b)	    ((a) << (b))
+#define			_cairo_int128_rsl(a,b)	    ((int128_t) ((uint128_t) (a) >> (b)))
+#define			_cairo_int128_rsa(a,b)	    ((int128_t) (a) >> (b))
+#define			_cairo_int128_negate(a)	    (-(a))
+#define			_cairo_int128_negative(a)   ((a) < 0)
+#define			_cairo_int128_not(a)	    (~(a))
+
+#endif	/* HAVE_UINT128_T */
+
+cairo_uquorem128_t I
+_cairo_uint128_divrem (cairo_uint128_t num, cairo_uint128_t den);
+
+cairo_quorem128_t I
+_cairo_int128_divrem (cairo_int128_t num, cairo_int128_t den);
+
+cairo_uquorem64_t I
+_cairo_uint_96by64_32x64_divrem (cairo_uint128_t num,
+				 cairo_uint64_t  den);
+
+cairo_quorem64_t I
+_cairo_int_96by64_32x64_divrem (cairo_int128_t num,
+				cairo_int64_t  den);
+
+#define			_cairo_uint128_le(a,b)	    (!_cairo_uint128_gt(a,b))
+#define			_cairo_uint128_ne(a,b)	    (!_cairo_uint128_eq(a,b))
+#define			_cairo_uint128_ge(a,b)	    (!_cairo_uint128_lt(a,b))
+#define			_cairo_uint128_gt(a,b)	    _cairo_uint128_lt(b,a)
+
+#define			_cairo_int128_le(a,b)	    (!_cairo_int128_gt(a,b))
+#define			_cairo_int128_ne(a,b)	    (!_cairo_int128_eq(a,b))
+#define			_cairo_int128_ge(a,b)	    (!_cairo_int128_lt(a,b))
+#define			_cairo_int128_gt(a,b)	    _cairo_int128_lt(b,a)
+
+#undef I
+
+#endif /* CAIRO_WIDEINT_H */
diff --git a/src/cairo/cairo-wideint-type-private.h b/src/cairo/cairo-wideint-type-private.h
new file mode 100644
index 0000000..e18f48e
--- /dev/null
+++ b/src/cairo/cairo-wideint-type-private.h
@@ -0,0 +1,153 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2004 Keith Packard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is Keith Packard
+ *
+ * Contributor(s):
+ *	Keith R. Packard <keithp@xxxxxxxxxx>
+ *
+ */
+
+#ifndef CAIRO_WIDEINT_TYPE_H
+#define CAIRO_WIDEINT_TYPE_H
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#if   HAVE_STDINT_H
+# include <stdint.h>
+#elif HAVE_INTTYPES_H
+# include <inttypes.h>
+#elif HAVE_SYS_INT_TYPES_H
+# include <sys/int_types.h>
+#elif defined(_MSC_VER)
+  typedef __int8 int8_t;
+  typedef unsigned __int8 uint8_t;
+  typedef __int16 int16_t;
+  typedef unsigned __int16 uint16_t;
+  typedef __int32 int32_t;
+  typedef unsigned __int32 uint32_t;
+  typedef __int64 int64_t;
+  typedef unsigned __int64 uint64_t;
+# ifndef HAVE_UINT64_T
+#  define HAVE_UINT64_T 1
+# endif
+#else
+#error Cannot find definitions for fixed-width integral types (uint8_t, uint32_t, etc.)
+#endif
+
+#ifndef INT16_MIN
+# define INT16_MIN	(-32767-1)
+#endif
+#ifndef INT16_MAX
+# define INT16_MAX	(32767)
+#endif
+#ifndef UINT16_MAX
+# define UINT16_MAX	(65535)
+#endif
+#ifndef INT32_MIN
+# define INT32_MIN	(-2147483647-1)
+#endif
+#ifndef INT32_MAX
+# define INT32_MAX	(2147483647)
+#endif
+
+#if HAVE_BYTESWAP_H
+# include <byteswap.h>
+#endif
+#ifndef bswap_16
+# define bswap_16(p) \
+	(((((uint16_t)(p)) & 0x00ff) << 8) | \
+	  (((uint16_t)(p))           >> 8));
+#endif
+#ifndef bswap_32
+# define bswap_32(p) \
+         (((((uint32_t)(p)) & 0x000000ff) << 24) | \
+	  ((((uint32_t)(p)) & 0x0000ff00) << 8)  | \
+	  ((((uint32_t)(p)) & 0x00ff0000) >> 8)  | \
+	  ((((uint32_t)(p)))              >> 24));
+#endif
+
+
+#if !HAVE_UINT64_T
+
+typedef struct _cairo_uint64 {
+    uint32_t	lo, hi;
+} cairo_uint64_t, cairo_int64_t;
+
+#else
+
+typedef uint64_t    cairo_uint64_t;
+typedef int64_t	    cairo_int64_t;
+
+#endif
+
+typedef struct _cairo_uquorem64 {
+    cairo_uint64_t	quo;
+    cairo_uint64_t	rem;
+} cairo_uquorem64_t;
+
+typedef struct _cairo_quorem64 {
+    cairo_int64_t	quo;
+    cairo_int64_t	rem;
+} cairo_quorem64_t;
+
+/* gcc has a non-standard name. */
+#if HAVE___UINT128_T && !HAVE_UINT128_T
+typedef __uint128_t uint128_t;
+typedef __int128_t int128_t;
+#define HAVE_UINT128_T 1
+#endif
+
+#if !HAVE_UINT128_T
+
+typedef struct cairo_uint128 {
+    cairo_uint64_t	lo, hi;
+} cairo_uint128_t, cairo_int128_t;
+
+#else
+
+typedef uint128_t	cairo_uint128_t;
+typedef int128_t	cairo_int128_t;
+
+#endif
+
+typedef struct _cairo_uquorem128 {
+    cairo_uint128_t	quo;
+    cairo_uint128_t	rem;
+} cairo_uquorem128_t;
+
+typedef struct _cairo_quorem128 {
+    cairo_int128_t	quo;
+    cairo_int128_t	rem;
+} cairo_quorem128_t;
+
+
+#endif /* CAIRO_WIDEINT_H */
diff --git a/src/cairo/cairo-wideint.c b/src/cairo/cairo-wideint.c
new file mode 100644
index 0000000..823ebca
--- /dev/null
+++ b/src/cairo/cairo-wideint.c
@@ -0,0 +1,819 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2004 Keith Packard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is Keith Packard
+ *
+ * Contributor(s):
+ *	Keith R. Packard <keithp@xxxxxxxxxx>
+ */
+
+#include "cairo-wideint-private.h"
+
+#if HAVE_UINT64_T
+
+#define uint64_lo32(i)	((i) & 0xffffffff)
+#define uint64_hi32(i)	((i) >> 32)
+#define uint64_lo(i)	((i) & 0xffffffff)
+#define uint64_hi(i)	((i) >> 32)
+#define uint64_shift32(i)   ((i) << 32)
+#define uint64_carry32	(((uint64_t) 1) << 32)
+
+#define _cairo_uint32s_to_uint64(h,l) ((uint64_t) (h) << 32 | (l))
+
+#else
+
+#define uint64_lo32(i)	((i).lo)
+#define uint64_hi32(i)	((i).hi)
+
+static cairo_uint64_t
+uint64_lo (cairo_uint64_t i)
+{
+    cairo_uint64_t  s;
+
+    s.lo = i.lo;
+    s.hi = 0;
+    return s;
+}
+
+static cairo_uint64_t
+uint64_hi (cairo_uint64_t i)
+{
+    cairo_uint64_t  s;
+
+    s.lo = i.hi;
+    s.hi = 0;
+    return s;
+}
+
+static cairo_uint64_t
+uint64_shift32 (cairo_uint64_t i)
+{
+    cairo_uint64_t  s;
+
+    s.lo = 0;
+    s.hi = i.lo;
+    return s;
+}
+
+static const cairo_uint64_t uint64_carry32 = { 0, 1 };
+
+cairo_uint64_t
+_cairo_uint32_to_uint64 (uint32_t i)
+{
+    cairo_uint64_t	q;
+
+    q.lo = i;
+    q.hi = 0;
+    return q;
+}
+
+cairo_int64_t
+_cairo_int32_to_int64 (int32_t i)
+{
+    cairo_uint64_t	q;
+
+    q.lo = i;
+    q.hi = i < 0 ? -1 : 0;
+    return q;
+}
+
+static cairo_uint64_t
+_cairo_uint32s_to_uint64 (uint32_t h, uint32_t l)
+{
+    cairo_uint64_t	q;
+
+    q.lo = l;
+    q.hi = h;
+    return q;
+}
+
+cairo_uint64_t
+_cairo_uint64_add (cairo_uint64_t a, cairo_uint64_t b)
+{
+    cairo_uint64_t	s;
+
+    s.hi = a.hi + b.hi;
+    s.lo = a.lo + b.lo;
+    if (s.lo < a.lo)
+	s.hi++;
+    return s;
+}
+
+cairo_uint64_t
+_cairo_uint64_sub (cairo_uint64_t a, cairo_uint64_t b)
+{
+    cairo_uint64_t	s;
+
+    s.hi = a.hi - b.hi;
+    s.lo = a.lo - b.lo;
+    if (s.lo > a.lo)
+	s.hi--;
+    return s;
+}
+
+#define uint32_lo(i)	((i) & 0xffff)
+#define uint32_hi(i)	((i) >> 16)
+#define uint32_carry16	((1) << 16)
+
+cairo_uint64_t
+_cairo_uint32x32_64_mul (uint32_t a, uint32_t b)
+{
+    cairo_uint64_t  s;
+
+    uint16_t	ah, al, bh, bl;
+    uint32_t	r0, r1, r2, r3;
+
+    al = uint32_lo (a);
+    ah = uint32_hi (a);
+    bl = uint32_lo (b);
+    bh = uint32_hi (b);
+
+    r0 = (uint32_t) al * bl;
+    r1 = (uint32_t) al * bh;
+    r2 = (uint32_t) ah * bl;
+    r3 = (uint32_t) ah * bh;
+
+    r1 += uint32_hi(r0);    /* no carry possible */
+    r1 += r2;		    /* but this can carry */
+    if (r1 < r2)	    /* check */
+	r3 += uint32_carry16;
+
+    s.hi = r3 + uint32_hi(r1);
+    s.lo = (uint32_lo (r1) << 16) + uint32_lo (r0);
+    return s;
+}
+
+cairo_int64_t
+_cairo_int32x32_64_mul (int32_t a, int32_t b)
+{
+    cairo_int64_t s;
+    s = _cairo_uint32x32_64_mul ((uint32_t) a, (uint32_t) b);
+    if (a < 0)
+	s.hi -= b;
+    if (b < 0)
+	s.hi -= a;
+    return s;
+}
+
+cairo_uint64_t
+_cairo_uint64_mul (cairo_uint64_t a, cairo_uint64_t b)
+{
+    cairo_uint64_t	s;
+
+    s = _cairo_uint32x32_64_mul (a.lo, b.lo);
+    s.hi += a.lo * b.hi + a.hi * b.lo;
+    return s;
+}
+
+cairo_uint64_t
+_cairo_uint64_lsl (cairo_uint64_t a, int shift)
+{
+    if (shift >= 32)
+    {
+	a.hi = a.lo;
+	a.lo = 0;
+	shift -= 32;
+    }
+    if (shift)
+    {
+	a.hi = a.hi << shift | a.lo >> (32 - shift);
+	a.lo = a.lo << shift;
+    }
+    return a;
+}
+
+cairo_uint64_t
+_cairo_uint64_rsl (cairo_uint64_t a, int shift)
+{
+    if (shift >= 32)
+    {
+	a.lo = a.hi;
+	a.hi = 0;
+	shift -= 32;
+    }
+    if (shift)
+    {
+	a.lo = a.lo >> shift | a.hi << (32 - shift);
+	a.hi = a.hi >> shift;
+    }
+    return a;
+}
+
+#define _cairo_uint32_rsa(a,n)	((uint32_t) (((int32_t) (a)) >> (n)))
+
+cairo_int64_t
+_cairo_uint64_rsa (cairo_int64_t a, int shift)
+{
+    if (shift >= 32)
+    {
+	a.lo = a.hi;
+	a.hi = _cairo_uint32_rsa (a.hi, 31);
+	shift -= 32;
+    }
+    if (shift)
+    {
+	a.lo = a.lo >> shift | a.hi << (32 - shift);
+	a.hi = _cairo_uint32_rsa (a.hi, shift);
+    }
+    return a;
+}
+
+int
+_cairo_uint64_lt (cairo_uint64_t a, cairo_uint64_t b)
+{
+    return (a.hi < b.hi ||
+	    (a.hi == b.hi && a.lo < b.lo));
+}
+
+int
+_cairo_uint64_eq (cairo_uint64_t a, cairo_uint64_t b)
+{
+    return a.hi == b.hi && a.lo == b.lo;
+}
+
+int
+_cairo_int64_lt (cairo_int64_t a, cairo_int64_t b)
+{
+    if (_cairo_int64_negative (a) && !_cairo_int64_negative (b))
+	return 1;
+    if (!_cairo_int64_negative (a) && _cairo_int64_negative (b))
+	return 0;
+    return _cairo_uint64_lt (a, b);
+}
+
+int
+_cairo_uint64_cmp (cairo_uint64_t a, cairo_uint64_t b)
+{
+    if (a.hi < b.hi)
+	return -1;
+    else if (a.hi > b.hi)
+	return 1;
+    else if (a.lo < b.lo)
+	return -1;
+    else if (a.lo > b.lo)
+	return 1;
+    else
+	return 0;
+}
+
+int
+_cairo_int64_cmp (cairo_int64_t a, cairo_int64_t b)
+{
+    if (_cairo_int64_negative (a) && !_cairo_int64_negative (b))
+	return -1;
+    if (!_cairo_int64_negative (a) && _cairo_int64_negative (b))
+	return 1;
+
+    return _cairo_uint64_cmp (a, b);
+}
+
+cairo_uint64_t
+_cairo_uint64_not (cairo_uint64_t a)
+{
+    a.lo = ~a.lo;
+    a.hi = ~a.hi;
+    return a;
+}
+
+cairo_uint64_t
+_cairo_uint64_negate (cairo_uint64_t a)
+{
+    a.lo = ~a.lo;
+    a.hi = ~a.hi;
+    if (++a.lo == 0)
+	++a.hi;
+    return a;
+}
+
+/*
+ * Simple bit-at-a-time divide.
+ */
+cairo_uquorem64_t
+_cairo_uint64_divrem (cairo_uint64_t num, cairo_uint64_t den)
+{
+    cairo_uquorem64_t	qr;
+    cairo_uint64_t	bit;
+    cairo_uint64_t	quo;
+
+    bit = _cairo_uint32_to_uint64 (1);
+
+    /* normalize to make den >= num, but not overflow */
+    while (_cairo_uint64_lt (den, num) && (den.hi & 0x80000000) == 0)
+    {
+	bit = _cairo_uint64_lsl (bit, 1);
+	den = _cairo_uint64_lsl (den, 1);
+    }
+    quo = _cairo_uint32_to_uint64 (0);
+
+    /* generate quotient, one bit at a time */
+    while (bit.hi | bit.lo)
+    {
+	if (_cairo_uint64_le (den, num))
+	{
+	    num = _cairo_uint64_sub (num, den);
+	    quo = _cairo_uint64_add (quo, bit);
+	}
+	bit = _cairo_uint64_rsl (bit, 1);
+	den = _cairo_uint64_rsl (den, 1);
+    }
+    qr.quo = quo;
+    qr.rem = num;
+    return qr;
+}
+
+#endif /* !HAVE_UINT64_T */
+
+#if HAVE_UINT128_T
+cairo_uquorem128_t
+_cairo_uint128_divrem (cairo_uint128_t num, cairo_uint128_t den)
+{
+    cairo_uquorem128_t	qr;
+
+    qr.quo = num / den;
+    qr.rem = num % den;
+    return qr;
+}
+
+#else
+
+cairo_uint128_t
+_cairo_uint32_to_uint128 (uint32_t i)
+{
+    cairo_uint128_t	q;
+
+    q.lo = _cairo_uint32_to_uint64 (i);
+    q.hi = _cairo_uint32_to_uint64 (0);
+    return q;
+}
+
+cairo_int128_t
+_cairo_int32_to_int128 (int32_t i)
+{
+    cairo_int128_t	q;
+
+    q.lo = _cairo_int32_to_int64 (i);
+    q.hi = _cairo_int32_to_int64 (i < 0 ? -1 : 0);
+    return q;
+}
+
+cairo_uint128_t
+_cairo_uint64_to_uint128 (cairo_uint64_t i)
+{
+    cairo_uint128_t	q;
+
+    q.lo = i;
+    q.hi = _cairo_uint32_to_uint64 (0);
+    return q;
+}
+
+cairo_int128_t
+_cairo_int64_to_int128 (cairo_int64_t i)
+{
+    cairo_int128_t	q;
+
+    q.lo = i;
+    q.hi = _cairo_int32_to_int64 (_cairo_int64_negative(i) ? -1 : 0);
+    return q;
+}
+
+cairo_uint128_t
+_cairo_uint128_add (cairo_uint128_t a, cairo_uint128_t b)
+{
+    cairo_uint128_t	s;
+
+    s.hi = _cairo_uint64_add (a.hi, b.hi);
+    s.lo = _cairo_uint64_add (a.lo, b.lo);
+    if (_cairo_uint64_lt (s.lo, a.lo))
+	s.hi = _cairo_uint64_add (s.hi, _cairo_uint32_to_uint64 (1));
+    return s;
+}
+
+cairo_uint128_t
+_cairo_uint128_sub (cairo_uint128_t a, cairo_uint128_t b)
+{
+    cairo_uint128_t	s;
+
+    s.hi = _cairo_uint64_sub (a.hi, b.hi);
+    s.lo = _cairo_uint64_sub (a.lo, b.lo);
+    if (_cairo_uint64_gt (s.lo, a.lo))
+	s.hi = _cairo_uint64_sub (s.hi, _cairo_uint32_to_uint64(1));
+    return s;
+}
+
+cairo_uint128_t
+_cairo_uint64x64_128_mul (cairo_uint64_t a, cairo_uint64_t b)
+{
+    cairo_uint128_t	s;
+    uint32_t		ah, al, bh, bl;
+    cairo_uint64_t	r0, r1, r2, r3;
+
+    al = uint64_lo32 (a);
+    ah = uint64_hi32 (a);
+    bl = uint64_lo32 (b);
+    bh = uint64_hi32 (b);
+
+    r0 = _cairo_uint32x32_64_mul (al, bl);
+    r1 = _cairo_uint32x32_64_mul (al, bh);
+    r2 = _cairo_uint32x32_64_mul (ah, bl);
+    r3 = _cairo_uint32x32_64_mul (ah, bh);
+
+    r1 = _cairo_uint64_add (r1, uint64_hi (r0));    /* no carry possible */
+    r1 = _cairo_uint64_add (r1, r2);	    	    /* but this can carry */
+    if (_cairo_uint64_lt (r1, r2))		    /* check */
+	r3 = _cairo_uint64_add (r3, uint64_carry32);
+
+    s.hi = _cairo_uint64_add (r3, uint64_hi(r1));
+    s.lo = _cairo_uint64_add (uint64_shift32 (r1),
+				uint64_lo (r0));
+    return s;
+}
+
+cairo_int128_t
+_cairo_int64x64_128_mul (cairo_int64_t a, cairo_int64_t b)
+{
+    cairo_int128_t  s;
+    s = _cairo_uint64x64_128_mul (_cairo_int64_to_uint64(a),
+				  _cairo_int64_to_uint64(b));
+    if (_cairo_int64_negative (a))
+	s.hi = _cairo_uint64_sub (s.hi,
+				  _cairo_int64_to_uint64 (b));
+    if (_cairo_int64_negative (b))
+	s.hi = _cairo_uint64_sub (s.hi,
+				  _cairo_int64_to_uint64 (a));
+    return s;
+}
+
+cairo_uint128_t
+_cairo_uint128_mul (cairo_uint128_t a, cairo_uint128_t b)
+{
+    cairo_uint128_t	s;
+
+    s = _cairo_uint64x64_128_mul (a.lo, b.lo);
+    s.hi = _cairo_uint64_add (s.hi,
+				_cairo_uint64_mul (a.lo, b.hi));
+    s.hi = _cairo_uint64_add (s.hi,
+				_cairo_uint64_mul (a.hi, b.lo));
+    return s;
+}
+
+cairo_uint128_t
+_cairo_uint128_lsl (cairo_uint128_t a, int shift)
+{
+    if (shift >= 64)
+    {
+	a.hi = a.lo;
+	a.lo = _cairo_uint32_to_uint64 (0);
+	shift -= 64;
+    }
+    if (shift)
+    {
+	a.hi = _cairo_uint64_add (_cairo_uint64_lsl (a.hi, shift),
+				    _cairo_uint64_rsl (a.lo, (64 - shift)));
+	a.lo = _cairo_uint64_lsl (a.lo, shift);
+    }
+    return a;
+}
+
+cairo_uint128_t
+_cairo_uint128_rsl (cairo_uint128_t a, int shift)
+{
+    if (shift >= 64)
+    {
+	a.lo = a.hi;
+	a.hi = _cairo_uint32_to_uint64 (0);
+	shift -= 64;
+    }
+    if (shift)
+    {
+	a.lo = _cairo_uint64_add (_cairo_uint64_rsl (a.lo, shift),
+				    _cairo_uint64_lsl (a.hi, (64 - shift)));
+	a.hi = _cairo_uint64_rsl (a.hi, shift);
+    }
+    return a;
+}
+
+cairo_uint128_t
+_cairo_uint128_rsa (cairo_int128_t a, int shift)
+{
+    if (shift >= 64)
+    {
+	a.lo = a.hi;
+	a.hi = _cairo_uint64_rsa (a.hi, 64-1);
+	shift -= 64;
+    }
+    if (shift)
+    {
+	a.lo = _cairo_uint64_add (_cairo_uint64_rsl (a.lo, shift),
+				    _cairo_uint64_lsl (a.hi, (64 - shift)));
+	a.hi = _cairo_uint64_rsa (a.hi, shift);
+    }
+    return a;
+}
+
+int
+_cairo_uint128_lt (cairo_uint128_t a, cairo_uint128_t b)
+{
+    return (_cairo_uint64_lt (a.hi, b.hi) ||
+	    (_cairo_uint64_eq (a.hi, b.hi) &&
+	     _cairo_uint64_lt (a.lo, b.lo)));
+}
+
+int
+_cairo_int128_lt (cairo_int128_t a, cairo_int128_t b)
+{
+    if (_cairo_int128_negative (a) && !_cairo_int128_negative (b))
+	return 1;
+    if (!_cairo_int128_negative (a) && _cairo_int128_negative (b))
+	return 0;
+    return _cairo_uint128_lt (a, b);
+}
+
+int
+_cairo_uint128_cmp (cairo_uint128_t a, cairo_uint128_t b)
+{
+    int cmp;
+
+    cmp = _cairo_uint64_cmp (a.hi, b.hi);
+    if (cmp)
+	return cmp;
+    return _cairo_uint64_cmp (a.lo, b.lo);
+}
+
+int
+_cairo_int128_cmp (cairo_int128_t a, cairo_int128_t b)
+{
+    if (_cairo_int128_negative (a) && !_cairo_int128_negative (b))
+	return -1;
+    if (!_cairo_int128_negative (a) && _cairo_int128_negative (b))
+	return 1;
+
+    return _cairo_uint128_cmp (a, b);
+}
+
+int
+_cairo_uint128_eq (cairo_uint128_t a, cairo_uint128_t b)
+{
+    return (_cairo_uint64_eq (a.hi, b.hi) &&
+	    _cairo_uint64_eq (a.lo, b.lo));
+}
+
+#if HAVE_UINT64_T
+#define _cairo_msbset64(q)  (q & ((uint64_t) 1 << 63))
+#else
+#define _cairo_msbset64(q)  (q.hi & ((uint32_t) 1 << 31))
+#endif
+
+cairo_uquorem128_t
+_cairo_uint128_divrem (cairo_uint128_t num, cairo_uint128_t den)
+{
+    cairo_uquorem128_t	qr;
+    cairo_uint128_t	bit;
+    cairo_uint128_t	quo;
+
+    bit = _cairo_uint32_to_uint128 (1);
+
+    /* normalize to make den >= num, but not overflow */
+    while (_cairo_uint128_lt (den, num) && !_cairo_msbset64(den.hi))
+    {
+	bit = _cairo_uint128_lsl (bit, 1);
+	den = _cairo_uint128_lsl (den, 1);
+    }
+    quo = _cairo_uint32_to_uint128 (0);
+
+    /* generate quotient, one bit at a time */
+    while (_cairo_uint128_ne (bit, _cairo_uint32_to_uint128(0)))
+    {
+	if (_cairo_uint128_le (den, num))
+	{
+	    num = _cairo_uint128_sub (num, den);
+	    quo = _cairo_uint128_add (quo, bit);
+	}
+	bit = _cairo_uint128_rsl (bit, 1);
+	den = _cairo_uint128_rsl (den, 1);
+    }
+    qr.quo = quo;
+    qr.rem = num;
+    return qr;
+}
+
+cairo_int128_t
+_cairo_int128_negate (cairo_int128_t a)
+{
+    a.lo = _cairo_uint64_not (a.lo);
+    a.hi = _cairo_uint64_not (a.hi);
+    return _cairo_uint128_add (a, _cairo_uint32_to_uint128 (1));
+}
+
+cairo_int128_t
+_cairo_int128_not (cairo_int128_t a)
+{
+    a.lo = _cairo_uint64_not (a.lo);
+    a.hi = _cairo_uint64_not (a.hi);
+    return a;
+}
+
+#endif /* !HAVE_UINT128_T */
+
+cairo_quorem128_t
+_cairo_int128_divrem (cairo_int128_t num, cairo_int128_t den)
+{
+    int			num_neg = _cairo_int128_negative (num);
+    int			den_neg = _cairo_int128_negative (den);
+    cairo_uquorem128_t	uqr;
+    cairo_quorem128_t	qr;
+
+    if (num_neg)
+	num = _cairo_int128_negate (num);
+    if (den_neg)
+	den = _cairo_int128_negate (den);
+    uqr = _cairo_uint128_divrem (num, den);
+    if (num_neg)
+	qr.rem = _cairo_int128_negate (uqr.rem);
+    else
+	qr.rem = uqr.rem;
+    if (num_neg != den_neg)
+	qr.quo = _cairo_int128_negate (uqr.quo);
+    else
+	qr.quo = uqr.quo;
+    return qr;
+}
+
+/**
+ * _cairo_uint_96by64_32x64_divrem:
+ *
+ * Compute a 32 bit quotient and 64 bit remainder of a 96 bit unsigned
+ * dividend and 64 bit divisor.  If the quotient doesn't fit into 32
+ * bits then the returned remainder is equal to the divisor, and the
+ * quotient is the largest representable 64 bit integer.  It is an
+ * error to call this function with the high 32 bits of @num being
+ * non-zero. */
+cairo_uquorem64_t
+_cairo_uint_96by64_32x64_divrem (cairo_uint128_t num,
+				 cairo_uint64_t den)
+{
+    cairo_uquorem64_t result;
+    cairo_uint64_t B = _cairo_uint32s_to_uint64 (1, 0);
+
+    /* These are the high 64 bits of the *96* bit numerator.  We're
+     * going to represent the numerator as xB + y, where x is a 64,
+     * and y is a 32 bit number. */
+    cairo_uint64_t x = _cairo_uint128_to_uint64 (_cairo_uint128_rsl(num, 32));
+
+    /* Initialise the result to indicate overflow. */
+    result.quo = _cairo_uint32s_to_uint64 (-1U, -1U);
+    result.rem = den;
+
+    /* Don't bother if the quotient is going to overflow. */
+    if (_cairo_uint64_ge (x, den)) {
+	return /* overflow */ result;
+    }
+
+    if (_cairo_uint64_lt (x, B)) {
+	/* When the final quotient is known to fit in 32 bits, then
+	 * num < 2^64 if and only if den < 2^32. */
+	return _cairo_uint64_divrem (_cairo_uint128_to_uint64 (num), den);
+    }
+    else {
+	/* Denominator is >= 2^32. the numerator is >= 2^64, and the
+	 * division won't overflow: need two divrems.  Write the
+	 * numerator and denominator as
+	 *
+	 *	num = xB + y		x : 64 bits, y : 32 bits
+	 *	den = uB + v		u, v : 32 bits
+	 */
+	uint32_t y = _cairo_uint128_to_uint32 (num);
+	uint32_t u = uint64_hi32 (den);
+	uint32_t v = _cairo_uint64_to_uint32 (den);
+
+	/* Compute a lower bound approximate quotient of num/den
+	 * from x/(u+1).  Then we have
+	 *
+	 * x	= q(u+1) + r	; q : 32 bits, r <= u : 32 bits.
+	 *
+	 * xB + y	= q(u+1)B	+ (rB+y)
+	 *		= q(uB + B + v - v) + (rB+y)
+	 *		= q(uB + v)	+ qB - qv + (rB+y)
+	 *		= q(uB + v)	+ q(B-v) + (rB+y)
+	 *
+	 * The true quotient of num/den then is q plus the
+	 * contribution of q(B-v) + (rB+y).  The main contribution
+	 * comes from the term q(B-v), with the term (rB+y) only
+	 * contributing at most one part.
+	 *
+	 * The term q(B-v) must fit into 64 bits, since q fits into 32
+	 * bits on account of being a lower bound to the true
+	 * quotient, and as B-v <= 2^32, we may safely use a single
+	 * 64/64 bit division to find its contribution. */
+
+	cairo_uquorem64_t quorem;
+	cairo_uint64_t remainder; /* will contain final remainder */
+	uint32_t quotient;	/* will contain final quotient. */
+	uint32_t q;
+	uint32_t r;
+
+	/* Approximate quotient by dividing the high 64 bits of num by
+	 * u+1. Watch out for overflow of u+1. */
+	if (u+1) {
+	    quorem = _cairo_uint64_divrem (x, _cairo_uint32_to_uint64 (u+1));
+	    q = _cairo_uint64_to_uint32 (quorem.quo);
+	    r = _cairo_uint64_to_uint32 (quorem.rem);
+	}
+	else {
+	    q = uint64_hi32 (x);
+	    r = _cairo_uint64_to_uint32 (x);
+	}
+	quotient = q;
+
+	/* Add the main term's contribution to quotient.  Note B-v =
+	 * -v as an uint32 (unless v = 0) */
+	if (v)
+	    quorem = _cairo_uint64_divrem (_cairo_uint32x32_64_mul (q, -v), den);
+	else
+	    quorem = _cairo_uint64_divrem (_cairo_uint32s_to_uint64 (q, 0), den);
+	quotient += _cairo_uint64_to_uint32 (quorem.quo);
+
+	/* Add the contribution of the subterm and start computing the
+	 * true remainder. */
+	remainder = _cairo_uint32s_to_uint64 (r, y);
+	if (_cairo_uint64_ge (remainder, den)) {
+	    remainder = _cairo_uint64_sub (remainder, den);
+	    quotient++;
+	}
+
+	/* Add the contribution of the main term's remainder. The
+	 * funky test here checks that remainder + main_rem >= den,
+	 * taking into account overflow of the addition. */
+	remainder = _cairo_uint64_add (remainder, quorem.rem);
+	if (_cairo_uint64_ge (remainder, den) ||
+	    _cairo_uint64_lt (remainder, quorem.rem))
+	{
+	    remainder = _cairo_uint64_sub (remainder, den);
+	    quotient++;
+	}
+
+	result.quo = _cairo_uint32_to_uint64 (quotient);
+	result.rem = remainder;
+    }
+    return result;
+}
+
+cairo_quorem64_t
+_cairo_int_96by64_32x64_divrem (cairo_int128_t num, cairo_int64_t den)
+{
+    int			num_neg = _cairo_int128_negative (num);
+    int			den_neg = _cairo_int64_negative (den);
+    cairo_uint64_t	nonneg_den;
+    cairo_uquorem64_t	uqr;
+    cairo_quorem64_t	qr;
+
+    if (num_neg)
+	num = _cairo_int128_negate (num);
+    if (den_neg)
+	nonneg_den = _cairo_int64_negate (den);
+    else
+	nonneg_den = den;
+
+    uqr = _cairo_uint_96by64_32x64_divrem (num, nonneg_den);
+    if (_cairo_uint64_eq (uqr.rem, nonneg_den)) {
+	/* bail on overflow. */
+	qr.quo = _cairo_uint32s_to_uint64 (0x7FFFFFFF, -1U);;
+	qr.rem = den;
+	return qr;
+    }
+
+    if (num_neg)
+	qr.rem = _cairo_int64_negate (uqr.rem);
+    else
+	qr.rem = uqr.rem;
+    if (num_neg != den_neg)
+	qr.quo = _cairo_int64_negate (uqr.quo);
+    else
+	qr.quo = uqr.quo;
+    return qr;
+}
diff --git a/src/cairo/cairoint-minimal.h b/src/cairo/cairoint-minimal.h
new file mode 100644
index 0000000..4b6d20b
--- /dev/null
+++ b/src/cairo/cairoint-minimal.h
@@ -0,0 +1,146 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2002 University of Southern California
+ * Copyright © 2005 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is University of Southern
+ * California.
+ *
+ * Contributor(s):
+ *	Carl D. Worth <cworth@xxxxxxxxxx>
+ */
+
+/*
+ * These definitions are solely for use by the implementation of cairo
+ * and constitute no kind of standard.  If you need any of these
+ * functions, please drop me a note.  Either the library needs new
+ * functionality, or there's a way to do what you need using the
+ * existing published interfaces. cworth@xxxxxxxxxx
+ */
+
+#ifndef _CAIROINT_H_
+#define _CAIROINT_H_
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef _MSC_VER
+#define cairo_public __declspec(dllexport)
+#endif
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stddef.h>
+
+#ifdef _MSC_VER
+#define _USE_MATH_DEFINES
+#endif
+#include <math.h>
+#include <limits.h>
+#include <stdio.h>
+
+#include "cairo-minimal.h"
+
+#include "cairo-compiler-private.h"
+
+CAIRO_BEGIN_DECLS
+
+#if _WIN32 && !_WIN32_WCE /* Permissions on WinCE? No worries! */
+cairo_private FILE *
+_cairo_win32_tmpfile (void);
+#define tmpfile() _cairo_win32_tmpfile()
+#endif
+
+#undef MIN
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+
+#undef MAX
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+#ifndef M_SQRT2
+#define M_SQRT2 1.41421356237309504880
+#endif
+
+#ifndef M_SQRT1_2
+#define M_SQRT1_2 0.707106781186547524400844362104849039
+#endif
+
+#undef  ARRAY_LENGTH
+#define ARRAY_LENGTH(__array) ((int) (sizeof (__array) / sizeof (__array[0])))
+
+#undef STRINGIFY
+#undef STRINGIFY_ARG
+#define STRINGIFY(macro_or_string)    STRINGIFY_ARG (macro_or_string)
+#define STRINGIFY_ARG(contents)       #contents
+
+#if defined (__GNUC__)
+#define cairo_container_of(ptr, type, member) ({ \
+    const __typeof__ (((type *) 0)->member) *mptr__ = (ptr); \
+    (type *) ((char *) mptr__ - offsetof (type, member)); \
+})
+#else
+#define cairo_container_of(ptr, type, member) \
+    (type *)((char *) (ptr) - (char *) &((type *)0)->member)
+#endif
+
+
+/* Size in bytes of buffer to use off the stack per functions.
+ * Mostly used by text functions.  For larger allocations, they'll
+ * malloc(). */
+#ifndef CAIRO_STACK_BUFFER_SIZE
+#define CAIRO_STACK_BUFFER_SIZE (512 * sizeof (int))
+#endif
+
+#define CAIRO_STACK_ARRAY_LENGTH(T) (CAIRO_STACK_BUFFER_SIZE / sizeof(T))
+
+
+#include "cairo-types-private.h"
+
+#if HAVE_VALGRIND
+# include <memcheck.h>
+# define VG(x) x
+#else
+# define VG(x)
+#endif
+
+#endif
diff --git a/src/hid/common/hidgl.c b/src/hid/common/hidgl.c
index cb53763..360aa83 100644
--- a/src/hid/common/hidgl.c
+++ b/src/hid/common/hidgl.c
@@ -37,7 +37,7 @@
 #include "hid.h"
 #include "hidgl.h"
 #include "rtree.h"
-
+#include "sweep.h"
 
 #ifdef HAVE_LIBDMALLOC
 #include <dmalloc.h>
@@ -648,6 +648,13 @@ hidgl_fill_pcb_polygon (PolygonType *poly, const BoxType *clip_box, double scale
   PLINE *contour;
   struct do_hole_info info;
   int stencil_bit;
+  cairo_traps_t traps;
+
+  _cairo_traps_init (&traps);
+  bo_poly_to_traps (poly->Clipped, &traps);
+  _cairo_traps_fini (&traps);
+
+  return;
 
   info.scale = scale;
   global_scale = scale;
diff --git a/src/sweep.h b/src/sweep.h
new file mode 100644
index 0000000..257664f
--- /dev/null
+++ b/src/sweep.h
@@ -0,0 +1,4 @@
+#include "cairo/cairo-traps-private.h"
+
+cairo_status_t bo_poly_to_traps (POLYAREA *poly, cairo_traps_t *traps);
+cairo_status_t bo_contour_to_traps (PLINE *contour, cairo_traps_t *traps);

commit a76a26a2362b1a6ad5a8d8841d942f483bb16f20
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    Play with display lists

diff --git a/src/hid/gtk/gui-output-events.c b/src/hid/gtk/gui-output-events.c
index 211e3e6..ae4bc48 100644
--- a/src/hid/gtk/gui-output-events.c
+++ b/src/hid/gtk/gui-output-events.c
@@ -1650,13 +1650,13 @@ ghid_draw_everything (BoxTypePtr drawn_area)
   Settings.ShowSolderSide = save_show_solder;
 }
 
-static int one_shot = 1;
-
 #define Z_NEAR 3.0
 gboolean
 ghid_port_drawing_area_expose_event_cb (GtkWidget * widget,
 					GdkEventExpose * ev, GHidPort * port)
 {
+  static int one_shot = 1;
+  static int display_list;
   BoxType region;
   int eleft, eright, etop, ebottom;
   extern HID ghid_hid;
@@ -1710,6 +1710,13 @@ ghid_port_drawing_area_expose_event_cb (GtkWidget * widget,
   glTranslatef (-widget->allocation.width / 2., -widget->allocation.height / 2., 0);
   glGetFloatv (GL_MODELVIEW_MATRIX, (GLfloat *)last_modelview_matrix);
 
+#if 0
+  if (one_shot) {
+
+    display_list = glGenLists(1);
+    glNewList (display_list, GL_COMPILE);
+#endif
+
   glEnable (GL_STENCIL_TEST);
   glClearColor (gport->offlimits_color.red / 65535.,
                 gport->offlimits_color.green / 65535.,
@@ -1847,6 +1854,15 @@ ghid_port_drawing_area_expose_event_cb (GtkWidget * widget,
   hidgl_flush_triangles (&buffer);
   glPopMatrix ();
 
+#if 0
+    glEndList ();
+    one_shot = 0;
+  } else {
+    /* Second and subsequent times */
+    glCallList (display_list);
+  }
+#endif
+
   ghid_show_crosshair (TRUE);
 
   hidgl_flush_triangles (&buffer);

commit 802d52c2c9ad48781f1e6662cacb60fe20f64157
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    Playing with stack rendering

diff --git a/src/hid/gtk/gui-output-events.c b/src/hid/gtk/gui-output-events.c
index 82dc295..211e3e6 100644
--- a/src/hid/gtk/gui-output-events.c
+++ b/src/hid/gtk/gui-output-events.c
@@ -1058,7 +1058,17 @@ SetPVColor_inlayer (PinTypePtr Pin, LayerTypePtr Layer, int Type)
   else if (TEST_FLAG (FOUNDFLAG, Pin))
     color = PCB->ConnectedColor;
   else
-    color = Layer->Color;
+    {
+      int component_group = GetLayerGroupNumberByNumber (max_layer + COMPONENT_LAYER);
+      int solder_group    = GetLayerGroupNumberByNumber (max_layer + SOLDER_LAYER);
+      int this_group      = GetLayerGroupNumberByPointer (Layer);
+
+      if (this_group == component_group || this_group == solder_group)
+        color = (SWAP_IDENT == (this_group == solder_group))
+                  ? PCB->ViaColor : PCB->InvisibleObjectsColor;
+      else
+        color = Layer->Color;
+    }
 
   gui->set_color (Output.fgGC, color);
 }
@@ -1344,6 +1354,8 @@ DrawLayerGroup (int group, const BoxType * screen)
   int n_entries = PCB->LayerGroups.Number[group];
   Cardinal *layers = PCB->LayerGroups.Entries[group];
   int first_run = 1;
+  int component = GetLayerGroupNumberByNumber (max_layer + COMPONENT_LAYER);
+  int solder    = GetLayerGroupNumberByNumber (max_layer + SOLDER_LAYER);
 
   if (!gui->set_layer (0, group, 0)) {
     gui->set_layer (NULL, SL (FINISHED, 0), 0);
@@ -1401,10 +1413,18 @@ DrawLayerGroup (int group, const BoxType * screen)
         }
       }
 
-      /* Draw pins and vias on this layer */
+      /* Draw pins, vias and pads on this layer */
       if (!global_view_2d && rv) {
         if (PCB->PinOn) r_search (PCB->Data->pin_tree, screen, NULL, pin_inlayer_callback, Layer);
         if (PCB->ViaOn) r_search (PCB->Data->via_tree, screen, NULL, via_inlayer_callback, Layer);
+        if ((layernum == component && !SWAP_IDENT) ||
+            (layernum == solder    &&  SWAP_IDENT))
+          if (PCB->PinOn)
+            r_search (PCB->Data->pad_tree, screen, NULL, pad_callback, Layer);
+        if ((layernum == solder    && !SWAP_IDENT) ||
+            (layernum == component &&  SWAP_IDENT))
+          if (PCB->PinOn)
+            r_search (PCB->Data->pad_tree, screen, NULL, backPad_callback, Layer);
       }
 
       if (TEST_FLAG (CHECKPLANESFLAG, PCB))
@@ -1534,7 +1554,8 @@ ghid_draw_everything (BoxTypePtr drawn_area)
    */
   if (!TEST_FLAG (CHECKPLANESFLAG, PCB) &&
       gui->set_layer ("invisible", SL (INVISIBLE, 0), 0)) {
-    r_search (PCB->Data->pad_tree, drawn_area, NULL, backPad_callback, NULL);
+    if (global_view_2d)
+      r_search (PCB->Data->pad_tree, drawn_area, NULL, backPad_callback, NULL);
     if (PCB->ElementOn) {
       r_search (PCB->Data->element_tree, drawn_area, NULL, backE_callback, NULL);
       r_search (PCB->Data->name_tree[NAME_INDEX (PCB)], drawn_area, NULL, backN_callback, NULL);
@@ -1572,20 +1593,21 @@ ghid_draw_everything (BoxTypePtr drawn_area)
     gui->set_layer ("bottomsilk", SL (SILK, BOTTOM), 0);
 //  gui->set_layer (NULL, SL (FINISHED, 0), 0);
 
-#if 1
-  /* Mask out drilled holes */
-  hidgl_flush_triangles (&buffer);
-  glPushAttrib (GL_COLOR_BUFFER_BIT);
-  glColorMask (0, 0, 0, 0);
-  if (PCB->PinOn) r_search (PCB->Data->pin_tree, drawn_area, NULL, hole_callback, NULL);
-  if (PCB->ViaOn) r_search (PCB->Data->via_tree, drawn_area, NULL, hole_callback, NULL);
-  hidgl_flush_triangles (&buffer);
-  glPopAttrib ();
-
-  if (PCB->PinOn) r_search (PCB->Data->pad_tree, drawn_area, NULL, pad_callback, NULL);
-  if (PCB->PinOn) r_search (PCB->Data->pin_tree, drawn_area, NULL, pin_callback, NULL);
-  if (PCB->ViaOn) r_search (PCB->Data->via_tree, drawn_area, NULL, via_callback, NULL);
-#endif
+  if (global_view_2d)
+    {
+      /* Mask out drilled holes */
+      hidgl_flush_triangles (&buffer);
+      glPushAttrib (GL_COLOR_BUFFER_BIT);
+      glColorMask (0, 0, 0, 0);
+      if (PCB->PinOn) r_search (PCB->Data->pin_tree, drawn_area, NULL, hole_callback, NULL);
+      if (PCB->ViaOn) r_search (PCB->Data->via_tree, drawn_area, NULL, hole_callback, NULL);
+      hidgl_flush_triangles (&buffer);
+      glPopAttrib ();
+
+      if (PCB->PinOn) r_search (PCB->Data->pad_tree, drawn_area, NULL, pad_callback, NULL);
+      if (PCB->PinOn) r_search (PCB->Data->pin_tree, drawn_area, NULL, pin_callback, NULL);
+      if (PCB->ViaOn) r_search (PCB->Data->via_tree, drawn_area, NULL, via_callback, NULL);
+    }
 
   gui->set_layer (NULL, SL (FINISHED, 0), 0);
 

commit 5118760e196039dad5eded4c1624254660963c9c
Author: Bert Timmerman <bert.timmerman@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    From 22f4d1dd450f218172b8ee0edf9a2aaef6c20f2f Mon Sep 17 00:00:00 2001
    Subject: [PATCH] Additional defines for a 3D joystick for (older) linux versions which do not have these defines in <linux/input.h>

diff --git a/src/hid/gtk/snavi.c b/src/hid/gtk/snavi.c
index 6dd1b5f..618be32 100644
--- a/src/hid/gtk/snavi.c
+++ b/src/hid/gtk/snavi.c
@@ -21,6 +21,19 @@
 
 #include <linux/types.h>
 #include <linux/input.h>
+/*
+Additional defines for a 3D joystick for (older) linux versions which do not
+have these defines in <linux/input.h>
+*/
+#ifndef REL_RX
+#define REL_RX                  0x03
+#endif
+#ifndef REL_RY
+#define REL_RY                  0x04
+#endif
+#ifndef REL_RZ
+#define REL_RZ                  0x05
+#endif
 
 #include <glib.h>
 

commit 1ad90700d1900a90c4537bb51889c3979dd47c9e
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    Silly space navigator interface to allow funky views

diff --git a/src/Makefile.am b/src/Makefile.am
index f21c807..2ce0991 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -280,7 +280,9 @@ LIBGTK_SRCS = \
 	hid/gtk/gui-top-window.c \
 	hid/gtk/gui-trackball.c \
 	hid/gtk/gui-trackball.h \
-	hid/gtk/gui-utils.c
+	hid/gtk/gui-utils.c \
+	hid/gtk/snavi.c \
+	hid/gtk/snavi.h
 libgtk_a_SOURCES = ${LIBGTK_SRCS} hid/gtk/gtk_lists.h
 
 hid/gtk/gtk_lists.h : ${LIBGTK_SRCS} Makefile
diff --git a/src/hid/gtk/gui-output-events.c b/src/hid/gtk/gui-output-events.c
index 88cf644..82dc295 100644
--- a/src/hid/gtk/gui-output-events.c
+++ b/src/hid/gtk/gui-output-events.c
@@ -50,6 +50,8 @@
 #include "search.h"
 #include "rats.h"
 #include "rtree.h"
+#include "snavi.h"
+#include "gui-trackball.h"
 
 #ifdef HAVE_LIBDMALLOC
 #include <dmalloc.h>
@@ -2039,6 +2041,8 @@ ghid_port_window_enter_cb (GtkWidget * widget,
       /* Make sure drawing area has keyboard focus when we are in it.
        */
       gtk_widget_grab_focus (out->drawing_area);
+      if (ghidgui->snavi)
+        snavi_set_led (ghidgui->snavi, TRUE);
     }
   ghidgui->in_popup = FALSE;
 
@@ -2146,6 +2150,8 @@ ghid_port_window_leave_cb (GtkWidget * widget,
 	    }
 	  g_idle_add (ghid_pan_idle_cb, NULL);
 	}
+      else if (ghidgui->snavi)
+        snavi_set_led (ghidgui->snavi, FALSE);
     }
 
   if(cursor_in_viewport)
@@ -2194,3 +2200,29 @@ ghid_port_window_mouse_scroll_cb (GtkWidget * widget,
 
   return TRUE;
 }
+
+void ndof_pan_cb (int dx, int dy, int dz, gpointer data)
+{
+  if (dx || dy)
+    ghid_port_ranges_pan (-gport->zoom * 5 * dx,
+                          -gport->zoom * 5 * dy, TRUE);
+  if (dz)
+    ghid_port_ranges_zoom (gport->zoom * (1.0 - (dz / 100.0)));
+}
+
+void ndof_roll_cb (int dx, int dy, int dz, gpointer data)
+{
+  ghid_trackball_external_rotate (GHID_TRACKBALL (gport->trackball),
+                                  dy / 100., dx / 100., dz / 100.);
+}
+
+void ndof_done_cb (gpointer data)
+{
+}
+
+void ndof_button_cb (int button, int value, gpointer data)
+{
+  if (value == 1)
+    hid_actionl ("SwapSides", (button == 0) ? "V" : "H", NULL);
+}
+
diff --git a/src/hid/gtk/gui-top-window.c b/src/hid/gtk/gui-top-window.c
index 038ba6c..a3898cb 100644
--- a/src/hid/gtk/gui-top-window.c
+++ b/src/hid/gtk/gui-top-window.c
@@ -123,6 +123,7 @@ a zoom in/out.
 #include "gui-icons-mode-buttons.data"
 #include "gui-icons-misc.data"
 #include "gui-trackball.h"
+#include "snavi.h"
 
 #ifdef HAVE_LIBDMALLOC
 #include <dmalloc.h>
@@ -2267,6 +2268,7 @@ ghid_build_pcb_top_window (void)
   make_layer_buttons(vbox, port);
 
   trackball = ghid_trackball_new ();
+  gport->trackball = trackball;
   g_signal_connect (trackball, "rotation-changed",
                     G_CALLBACK (ghid_port_rotate), NULL);
   g_signal_connect (trackball, "view-2d-changed",
@@ -2751,6 +2753,12 @@ ghid_do_export (HID_Attr_Val * options)
   if (stdin_listen)
     ghid_create_listener ();
 
+  ghidgui->snavi = setup_snavi (ndof_pan_cb,
+                                ndof_roll_cb,
+                                ndof_done_cb,
+                                ndof_button_cb,
+                                NULL);
+
   ghid_notify_gui_is_up ();
 
   gtk_main ();
diff --git a/src/hid/gtk/gui-trackball.c b/src/hid/gtk/gui-trackball.c
index 26440bb..33b8c81 100644
--- a/src/hid/gtk/gui-trackball.c
+++ b/src/hid/gtk/gui-trackball.c
@@ -99,6 +99,38 @@ button_release_cb (GtkWidget *widget, GdkEventButton *ev, gpointer userdata)
 }
 
 
+void
+ghid_trackball_external_rotate (GhidTrackball *ball, float dx, float dy, float dz)
+{
+  float axis[3];
+  float quart[4];
+#if 0
+  float quart_accum[4];
+
+  axis[0] = 1.; axis[1] = 0.; axis[2] = 0.;
+  axis_to_quat (axis, dx, quart_accum);
+
+  axis[0] = 0.; axis[1] = 1.; axis[2] = 0.;
+  axis_to_quat (axis, dy, quart);
+  add_quats (quart, quart_accum, quart_accum);
+
+  axis[0] = 0.; axis[1] = 0.; axis[2] = 1.;
+  axis_to_quat (axis, dz, quart);
+  add_quats (quart, quart_accum, quart_accum);
+
+  add_quats (quart_accum, ball->quart1, ball->quart1);
+#endif
+
+  if (dx == 0. && dy == 0. && dz == 0.) return;
+
+  axis[0] = dx; axis[1] = dy; axis[2] = dz;
+  axis_to_quat (axis, sqrt (dx * dx + dy * dy + dz * dz), quart);
+  add_quats (quart, ball->quart1, ball->quart1);
+
+  g_signal_emit (ball, ghid_trackball_signals[ROTATION_CHANGED], 0, ball->quart1);
+}
+
+
 static gboolean
 motion_notify_cb (GtkWidget *widget, GdkEventMotion *ev, gpointer userdata)
 {
diff --git a/src/hid/gtk/gui-trackball.h b/src/hid/gtk/gui-trackball.h
index d6bd03c..3af647e 100644
--- a/src/hid/gtk/gui-trackball.h
+++ b/src/hid/gtk/gui-trackball.h
@@ -65,6 +65,7 @@ struct _GhidTrackball
 
 GType ghid_trackball_get_type (void);
 
+void ghid_trackball_external_rotate (GhidTrackball *ball, float dx, float dy, float dz);
 GtkWidget *ghid_trackball_new (void);
 
 #endif /* __GHID_TRACKBALL_H__ */
diff --git a/src/hid/gtk/gui.h b/src/hid/gtk/gui.h
index 38f2148..af281b3 100644
--- a/src/hid/gtk/gui.h
+++ b/src/hid/gtk/gui.h
@@ -159,6 +159,8 @@ typedef struct
     library_window_width,
     library_window_height,
     netlist_window_height, history_size, settings_mode, auto_pan_speed;
+
+  GIOChannel *snavi;
 }
 GhidGui;
 
@@ -171,6 +173,7 @@ typedef struct
 {
   GtkWidget *top_window,	/* toplevel widget              */
    *drawing_area;		/* and its drawing area */
+  GtkWidget *trackball;
   GdkPixmap *pixmap, *mask;
   GdkDrawable *drawable;	/* Current drawable for drawing routines */
   gint width, height;
@@ -336,6 +339,10 @@ gint ghid_port_drawing_area_configure_event_cb (GtkWidget * widget,
 						GdkEventConfigure * ev,
 						GHidPort * out);
 
+void ndof_pan_cb (int dx, int dy, int dz, gpointer data);
+void ndof_roll_cb (int dx, int dy, int dz, gpointer data);
+void ndof_done_cb (gpointer data);
+void ndof_button_cb (int button, int value, gpointer data);
 
 /* gui-dialog.c function prototypes.
 */
diff --git a/src/hid/gtk/snavi.c b/src/hid/gtk/snavi.c
new file mode 100644
index 0000000..6dd1b5f
--- /dev/null
+++ b/src/hid/gtk/snavi.c
@@ -0,0 +1,174 @@
+/*
+ * spacenavi.c - a proof-of-concept hack to access the
+ * 3dconnexion space navigator
+ *
+ * Written by Simon Budig, placed in the public domain.
+ * it helps to read http://www.frogmouth.net/hid-doco/linux-hid.html .
+ *
+ * Adapted to control pcb by Peter Clifton
+ *
+ * For the LED to work a patch to the linux kernel is needed:
+ *   http://www.home.unix-ag.org/simon/files/spacenavigator-hid.patch
+ *
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+
+#include <linux/types.h>
+#include <linux/input.h>
+
+#include <glib.h>
+
+#define test_bit(bit, array)  (array [bit / 8] & (1 << (bit % 8)))
+
+static void (*update_pan_cb)(int, int, int, gpointer);
+static void (*update_roll_cb)(int, int, int, gpointer);
+static void (*update_done_cb)(gpointer);
+static void (*button_cb)(int, int, gpointer);
+static gpointer cb_userdata;
+
+int snavi_set_led (GIOChannel *snavi, int led_state)
+{
+  struct input_event event;
+  GError      *error = NULL;
+  gsize        bytes_written;
+
+  event.type  = EV_LED;
+  event.code  = LED_MISC;
+  event.value = led_state;
+
+  g_io_channel_seek_position (snavi, 0, G_SEEK_END, &error);
+  if (error) {
+    g_printerr ("Error: %s\n", error->message);
+    /* FIXME: FREE THE ERROR??? */
+    return FALSE;
+  }
+
+  g_io_channel_write_chars (snavi,
+                            (gchar *) &event,
+                            sizeof (struct input_event),
+                            &bytes_written,
+                            &error);
+
+  if (error) {
+    g_printerr ("Error: %s\n", error->message);
+    /* FIXME: FREE THE ERROR??? */
+    return FALSE;
+  }
+
+  g_io_channel_flush (snavi, &error);
+
+  if (error) {
+    g_printerr ("Error: %s\n", error->message);
+    /* FIXME: FREE THE ERROR??? */
+    return FALSE;
+  }
+
+  return bytes_written < sizeof (struct input_event);
+}
+
+
+#define BAND 5
+
+gboolean snavi_event (GIOChannel   *source,
+                      GIOCondition  condition,
+                      gpointer      data)
+{
+  static gint axes[6] = { 0, 0, 0, 0, 0, 0 };
+  static gint buttons[2] = { 0, 0 };
+  int i = 0;
+
+  struct       input_event event;
+  GError      *error = NULL;
+  gsize        bytes_read;
+
+  g_io_channel_read_chars (source,
+                           (gchar *) &event,
+                           sizeof (struct input_event),
+                           &bytes_read,
+                           &error);
+
+  if (error)
+    {
+      g_printerr ("%s\n", error->message);
+      return FALSE;
+    }
+
+  switch (event.type)
+    {
+      case EV_REL:
+        if (event.code <= REL_RZ)
+          axes[event.code - REL_X] = event.value;
+        break;
+
+      case EV_KEY:
+        if (event.code >= BTN_0 && event.code <= BTN_1)
+          buttons[event.code - BTN_0] = event.value;
+
+          button_cb (event.code - BTN_0, event.value, cb_userdata);
+        break;
+
+      case EV_SYN:
+        /*
+         * if multiple axes change simultaneously the linux
+         * input system sends multiple EV_REL events.
+         * EV_SYN indicates that all changes have been reported.
+         */
+
+        /* Deadband */
+        for (i = 0; i < 6; i++) {
+          if (axes[i] > -BAND &&
+              axes[i] < BAND)
+            axes[i] = 0;
+        }
+
+        update_pan_cb (axes[0] / 100.0,
+                       axes[2] / 100.0,
+                       axes[1] / 100.0, cb_userdata);
+        update_roll_cb (axes[5] / 100.0,
+                        axes[3] / 100.0,
+                        axes[4] / 100.0, cb_userdata);
+        update_done_cb (cb_userdata);
+
+        axes[0] = axes[1] = axes[2] = axes[3] = axes[4] = axes[5] = 0;
+        break;
+
+      default:
+        break;
+    }
+
+
+  return TRUE;
+}
+
+
+GIOChannel *
+setup_snavi (void (*update_pan)(int, int, int, gpointer),
+             void (*update_roll)(int, int, int, gpointer),
+             void (*update_done)(gpointer),
+             void (*button)(int, int, gpointer),
+             gpointer data)
+{
+  int event_id;
+  GIOChannel *snavi;
+
+  update_pan_cb = update_pan;
+  update_roll_cb = update_roll;
+  update_done_cb = update_done;
+  button_cb = button;
+  cb_userdata = data;
+
+  snavi = g_io_channel_new_file ("/dev/input/spacenavigator", "r+", NULL);
+  if (snavi)
+    {
+      g_io_channel_set_encoding (snavi, NULL, NULL);
+      event_id = g_io_add_watch (snavi, G_IO_IN, snavi_event, NULL);
+    }
+
+  return snavi;
+}
diff --git a/src/hid/gtk/snavi.h b/src/hid/gtk/snavi.h
new file mode 100644
index 0000000..9b5011c
--- /dev/null
+++ b/src/hid/gtk/snavi.h
@@ -0,0 +1,6 @@
+GIOChannel *setup_snavi(void (*update_pan)(int dx, int dy, int dz, gpointer data),
+                        void (*update_roll)(int dx, int dy, int dz, gpointer data),
+                        void (*update_done)(gpointer data),
+                        void (*button)(int button, int value, gpointer data),
+                        gpointer data);
+void snavi_set_led (GIOChannel *snavi, int value);

commit 2ffaef15bdf630c0c10db23c17d6ce3cb1b157fe
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    Major re-write to drawing routines

diff --git a/src/draw.c b/src/draw.c
index c713965..602b499 100644
--- a/src/draw.c
+++ b/src/draw.c
@@ -76,7 +76,7 @@ FloatPolyType, *FloatPolyTypePtr;
  * some local identifiers
  */
 static BoxType Block;
-static bool Gathering = true;
+/* static */ bool Gathering = true;
 static int Erasing = false;
 
 static int doing_pinout = false;
@@ -90,27 +90,27 @@ static void Redraw (bool, BoxTypePtr);
 static void DrawEverything (BoxTypePtr);
 static void DrawTop (const BoxType *);
 static int DrawLayerGroup (int, const BoxType *);
-static void DrawPinOrViaLowLevel (PinTypePtr, bool);
+/* static */ void DrawPinOrViaLowLevel (PinTypePtr, bool);
 static void ClearOnlyPin (PinTypePtr, bool);
-static void DrawPlainPin (PinTypePtr, bool);
-static void DrawPlainVia (PinTypePtr, bool);
+/* static */ void DrawPlainPin (PinTypePtr, bool);
+/* static */ void DrawPlainVia (PinTypePtr, bool);
 static void DrawPinOrViaNameLowLevel (PinTypePtr);
 static void DrawPadLowLevel (hidGC, PadTypePtr, bool, bool);
 static void DrawPadNameLowLevel (PadTypePtr);
 static void DrawLineLowLevel (LineTypePtr, bool);
-static void DrawRegularText (LayerTypePtr, TextTypePtr, int);
+/* static */ void DrawRegularText (LayerTypePtr, TextTypePtr, int);
 static void DrawPolygonLowLevel (PolygonTypePtr);
 static void DrawArcLowLevel (ArcTypePtr);
 static void DrawElementPackageLowLevel (ElementTypePtr Element, int);
 static void DrawPlainPolygon (LayerTypePtr Layer, PolygonTypePtr Polygon);
 static void AddPart (void *);
 static void SetPVColor (PinTypePtr, int);
-static void DrawEMark (ElementTypePtr, LocationType, LocationType, bool);
+/* static */ void DrawEMark (ElementTypePtr, LocationType, LocationType, bool);
 static void ClearPad (PadTypePtr, bool);
-static void DrawHole (PinTypePtr);
+/* static */ void DrawHole (PinTypePtr);
 static void DrawMask (BoxType *);
-static void DrawRats (BoxType *);
-static void DrawSilk (int, int, const BoxType *);
+/* static */ void DrawRats (BoxType *);
+/* static */ void DrawSilk (int, int, const BoxType *);
 static int pin_callback (const BoxType * b, void *cl);
 static int pad_callback (const BoxType * b, void *cl);
 
@@ -591,7 +591,7 @@ DrawEverything (BoxTypePtr drawn_area)
     }
 }
 
-static void
+/* static */ void
 DrawEMark (ElementTypePtr e, LocationType X, LocationType Y,
 	   bool invisible)
 {
@@ -679,7 +679,7 @@ struct pin_info
   LayerTypePtr Layer;
 };
 
-static int
+/* static */ int
 clearPin_callback (const BoxType * b, void *cl)
 {
   PinTypePtr pin = (PinTypePtr) b;
@@ -697,7 +697,7 @@ poly_callback (const BoxType * b, void *cl)
   return 1;
 }
 
-static int
+/* static */ int
 clearPad_callback (const BoxType * b, void *cl)
 {
   PadTypePtr pad = (PadTypePtr) b;
@@ -710,7 +710,7 @@ clearPad_callback (const BoxType * b, void *cl)
  * Draws silk layer.
  */
 
-static void
+/* static */ void
 DrawSilk (int new_swap, int layer, const BoxType * drawn_area)
 {
 #if 0
@@ -817,7 +817,7 @@ DrawMask (BoxType * screen)
 #endif
 }
 
-static void
+/* static */ void
 DrawRats (BoxTypePtr drawn_area)
 {
   /*
@@ -952,7 +952,7 @@ DrawLayerGroup (int group, const BoxType * screen)
  *         \       /
  *          2 --- 1
   */
-static void
+/* static */ void
 DrawSpecialPolygon (hidGC DrawGC,
 		    LocationType X, LocationType Y, int Thickness,
 		    int thin_draw)
@@ -1016,7 +1016,7 @@ DrawSpecialPolygon (hidGC DrawGC,
 /* ---------------------------------------------------------------------------
  * lowlevel drawing routine for pins and vias
  */
-static void
+/* static */ void
 DrawPinOrViaLowLevel (PinTypePtr Ptr, bool drawHole)
 {
   if (Gathering)
@@ -1100,7 +1100,7 @@ DrawPinOrViaLowLevel (PinTypePtr Ptr, bool drawHole)
 /**************************************************************
  * draw pin/via hole
  */
-static void
+/* static */ void
 DrawHole (PinTypePtr Ptr)
 {
   if (TEST_FLAG (THINDRAWFLAG, PCB))
@@ -1715,7 +1715,7 @@ DrawVia (PinTypePtr Via, int unused)
 /* ---------------------------------------------------------------------------
  * draw a via without dealing with polygon clearance 
  */
-static void
+/* static */ void
 DrawPlainVia (PinTypePtr Via, bool holeToo)
 {
   if (!Gathering)
@@ -1760,7 +1760,7 @@ DrawPin (PinTypePtr Pin, int unused)
 /* ---------------------------------------------------------------------------
  * draw a pin without clearing around polygons 
  */
-static void
+/* static */ void
 DrawPlainPin (PinTypePtr Pin, bool holeToo)
 {
   if (!Gathering)
@@ -1950,7 +1950,7 @@ DrawText (LayerTypePtr Layer, TextTypePtr Text, int unused)
 /* ---------------------------------------------------------------------------
  * draws text on a layer
  */
-static void
+/* static */ void
 DrawRegularText (LayerTypePtr Layer, TextTypePtr Text, int unused)
 {
   int min_silk_line;
diff --git a/src/draw.h b/src/draw.h
index c0e23a3..077c575 100644
--- a/src/draw.h
+++ b/src/draw.h
@@ -74,6 +74,19 @@ void EraseObject (int, void *, void *);
 void LoadBackgroundImage (char *);
 void UpdateAll (void);
 
+/* TEMPORARY */
+void DrawPinOrViaLowLevel (PinTypePtr, bool);
+void DrawPlainPin (PinTypePtr, bool);
+void DrawPlainVia (PinTypePtr, bool);
+void DrawRegularText (LayerTypePtr, TextTypePtr, int);
+void DrawEMark (ElementTypePtr, LocationType, LocationType, bool);
+void DrawHole (PinTypePtr);
+void DrawRats (BoxType *);
+void DrawSilk (int, int, const BoxType *);
+void DrawSpecialPolygon (hidGC DrawGC, LocationType X, LocationType Y, int Thickness, int thin_draw);
+
+/* TEMPORARY */
+
 /*GdkDrawable *draw_get_current_drawable(void);*/
 
 #endif
diff --git a/src/hid/gtk/gtkhid-gl.c b/src/hid/gtk/gtkhid-gl.c
index 87daf19..8705cd4 100644
--- a/src/hid/gtk/gtkhid-gl.c
+++ b/src/hid/gtk/gtkhid-gl.c
@@ -313,9 +313,9 @@ typedef struct
   double blue;
 } ColorCache;
 
-static char *current_color = NULL;
-static double global_alpha_mult = 1.0;
-static int alpha_changed = 0;
+/* static */ char *current_color = NULL;
+/* static */ double global_alpha_mult = 1.0;
+/* static */ int alpha_changed = 0;
 
 void
 ghid_set_color (hidGC gc, const char *name)
diff --git a/src/hid/gtk/gtkhid-main.c b/src/hid/gtk/gtkhid-main.c
index 7b01d27..6002b9a 100644
--- a/src/hid/gtk/gtkhid-main.c
+++ b/src/hid/gtk/gtkhid-main.c
@@ -333,68 +333,89 @@ ghid_invalidate_all ()
   gdk_window_invalidate_rect (gport->drawing_area->window, NULL, 1);
 }
 
+int compute_depth (int group)
+{
+  static int last_depth_computed = 0;
+
+  int depth = last_depth_computed;
+  int newgroup;
+  int idx = (group >= 0
+             && group <
+             max_layer) ? PCB->LayerGroups.Entries[group][0] : group;
+
+  if (group >= 0 && group < max_layer) {
+    newgroup = group;
+#if 0
+    /* Re-ordering doesn't work, since we also need to adjust the rendering order */
+    if (group == 1)
+      newgroup = max_layer - 1;
+    else if (group > 1)
+      newgroup = group - 1;
+#endif
+    depth = ((max_layer - newgroup) * 10) * 200 / gport->zoom;
+  } else if (SL_TYPE (idx) == SL_MASK) {
+    if (SL_SIDE (idx) == SL_TOP_SIDE && !Settings.ShowSolderSide) {
+      depth = (max_layer * 10 + 3) * 200 / gport->zoom;
+    } else {
+      depth = (10 - 3) * 200 / gport->zoom;
+    }
+  } else if (SL_TYPE (idx) == SL_SILK) {
+    if (SL_SIDE (idx) == SL_TOP_SIDE && !Settings.ShowSolderSide) {
+      depth = (max_layer * 10 + 5) * 200 / gport->zoom;
+    } else {
+      depth = (10 - 5) * 200 / gport->zoom;
+    }
+  } else if (SL_TYPE (idx) == SL_INVISIBLE) {
+    depth = (10 - 3) * 200 / gport->zoom;
+  }
+
+  last_depth_computed = depth;
+  return depth;
+}
+
 int
 ghid_set_layer (const char *name, int group, int empty)
 {
   static int stencil_bit = 0;
-  int idx = (group >= 0
-	     && group <
-	     max_layer) ? PCB->LayerGroups.Entries[group][0] : group;
+  int idx = (group >= 0 && group < max_layer) ?
+              PCB->LayerGroups.Entries[group][0] : group;
 
-#define SUBCOMPOSITE_LAYERS
-#ifdef SUBCOMPOSITE_LAYERS
   /* Flush out any existing geoemtry to be rendered */
   hidgl_flush_triangles (&buffer);
 
-  if (group >= 0 && group < max_layer) {
-    hidgl_set_depth ((max_layer - group) * 10);
+  hidgl_set_depth (compute_depth (group));
+
+  glEnable (GL_STENCIL_TEST);                   // Enable Stencil test
+  glStencilOp (GL_KEEP, GL_KEEP, GL_REPLACE);   // Stencil pass => replace stencil value (with 1)
+  hidgl_return_stencil_bit (stencil_bit);       // Relinquish any bitplane we previously used
+  if (SL_TYPE (idx) != SL_FINISHED) {
+    stencil_bit = hidgl_assign_clear_stencil_bit();       // Get a new (clean) bitplane to stencil with
+    glStencilMask (stencil_bit);                          // Only write to our subcompositing stencil bitplane
+    glStencilFunc (GL_GREATER, stencil_bit, stencil_bit); // Pass stencil test if our assigned bit is clear
   } else {
-    if (SL_TYPE (idx) == SL_SILK) {
-      if (SL_SIDE (idx) == SL_TOP_SIDE && !Settings.ShowSolderSide) {
-        hidgl_set_depth (max_layer * 10 + 3);
-      } else {
-        hidgl_set_depth (10 - 3);
-      }
-    }
+    stencil_bit = 0;
+    glStencilMask (0);
+    glStencilFunc (GL_ALWAYS, 0, 0);  // Always pass stencil test
   }
 
-  glEnable (GL_STENCIL_TEST);                // Enable Stencil test
-  glStencilOp (GL_KEEP, GL_KEEP, GL_REPLACE); // Stencil pass => replace stencil value (with 1)
-  /* Reset stencil buffer so we can paint anywhere */
-  hidgl_return_stencil_bit (stencil_bit);               // Relinquish any bitplane we previously used
-  if (SL_TYPE (idx) != SL_FINISHED)
-    {
-      stencil_bit = hidgl_assign_clear_stencil_bit();       // Get a new (clean) bitplane to stencil with
-      glStencilFunc (GL_GREATER, stencil_bit, stencil_bit); // Pass stencil test if our assigned bit is clear
-      glStencilMask (stencil_bit);                          // Only write to our subcompositing stencil bitplane
-    }
-  else
-    {
-#endif
-      stencil_bit = 0;
-      glStencilMask (0);
-      glStencilFunc (GL_ALWAYS, 0, 0);  // Always pass stencil test
-#ifdef SUBCOMPOSITE_LAYERS
-    }
-#endif
-
   if (idx >= 0 && idx < max_layer + 2) {
     gport->trans_lines = TRUE;
-    return /*pinout ? 1 : */ PCB->Data->Layer[idx].On;
+    return PCB->Data->Layer[idx].On;
   }
+
   if (idx < 0)
     {
       switch (SL_TYPE (idx))
 	{
 	case SL_INVISIBLE:
-	  return /* pinout ? 0 : */ PCB->InvisibleObjectsOn;
+	  return PCB->InvisibleObjectsOn;
 	case SL_MASK:
-	  if (SL_MYSIDE (idx) /*&& !pinout */ )
+	  if (SL_MYSIDE (idx))
 	    return TEST_FLAG (SHOWMASKFLAG, PCB);
 	  return 0;
 	case SL_SILK:
 	  gport->trans_lines = TRUE;
-	  if (SL_MYSIDE (idx) /*|| pinout */ )
+	  if (SL_MYSIDE (idx))
 	    return PCB->ElementOn;
 	  return 0;
 	case SL_ASSY:
@@ -408,6 +429,7 @@ ghid_set_layer (const char *name, int group, int empty)
 	  return PCB->RatOn;
 	}
     }
+
   return 0;
 }
 
diff --git a/src/hid/gtk/gui-output-events.c b/src/hid/gtk/gui-output-events.c
index fabe334..88cf644 100644
--- a/src/hid/gtk/gui-output-events.c
+++ b/src/hid/gtk/gui-output-events.c
@@ -49,6 +49,7 @@
 #include "find.h"
 #include "search.h"
 #include "rats.h"
+#include "rtree.h"
 
 #ifdef HAVE_LIBDMALLOC
 #include <dmalloc.h>
@@ -962,7 +963,14 @@ ghid_screen_update (void)
 #endif
 }
 
-void DrawAttached (Boolean);
+void DrawAttached (bool);
+
+struct pin_info
+{
+  bool arg;
+  LayerTypePtr Layer;
+  const BoxType *drawn_area;
+};
 
 void
 ghid_view_2d (void *ball, gboolean view_2d, gpointer userdata)
@@ -994,6 +1002,631 @@ ghid_port_rotate (void *ball, float *quarternion, gpointer userdata)
   ghid_invalidate_all ();
 }
 
+static int
+backE_callback (const BoxType * b, void *cl)
+{
+  ElementTypePtr element = (ElementTypePtr) b;
+
+  if (!FRONT (element))
+    {
+      DrawElementPackage (element, 0);
+    }
+  return 1;
+}
+
+static int
+backN_callback (const BoxType * b, void *cl)
+{
+  TextTypePtr text = (TextTypePtr) b;
+  ElementTypePtr element = (ElementTypePtr) text->Element;
+
+  if (!FRONT (element) && !TEST_FLAG (HIDENAMEFLAG, element))
+    DrawElementName (element, 0);
+  return 0;
+}
+
+static int
+backPad_callback (const BoxType * b, void *cl)
+{
+  PadTypePtr pad = (PadTypePtr) b;
+
+  if (!FRONT (pad))
+    DrawPad (pad, 0);
+  return 1;
+}
+
+static int
+EMark_callback (const BoxType * b, void *cl)
+{
+  ElementTypePtr element = (ElementTypePtr) b;
+
+  DrawEMark (element, element->MarkX, element->MarkY, !FRONT (element));
+  return 1;
+}
+
+static void
+SetPVColor_inlayer (PinTypePtr Pin, LayerTypePtr Layer, int Type)
+{
+  char *color;
+
+  if (TEST_FLAG (WARNFLAG, Pin))
+    color = PCB->WarnColor;
+  else if (TEST_FLAG (SELECTEDFLAG, Pin))
+    color = (Type == VIA_TYPE) ? PCB->ViaSelectedColor : PCB->PinSelectedColor;
+  else if (TEST_FLAG (FOUNDFLAG, Pin))
+    color = PCB->ConnectedColor;
+  else
+    color = Layer->Color;
+
+  gui->set_color (Output.fgGC, color);
+}
+
+
+static int
+pin_inlayer_callback (const BoxType * b, void *cl)
+{
+  SetPVColor_inlayer ((PinTypePtr) b, cl, PIN_TYPE);
+  DrawPinOrViaLowLevel ((PinTypePtr) b, false);
+  return 1;
+}
+
+static int
+via_inlayer_callback (const BoxType * b, void *cl)
+{
+  SetPVColor_inlayer ((PinTypePtr) b, cl, VIA_TYPE);
+  DrawPinOrViaLowLevel ((PinTypePtr) b, false);
+  return 1;
+}
+
+static int
+pin_callback (const BoxType * b, void *cl)
+{
+  DrawPlainPin ((PinTypePtr) b, false);
+  return 1;
+}
+
+static int
+pad_callback (const BoxType * b, void *cl)
+{
+  PadTypePtr pad = (PadTypePtr) b;
+  if (FRONT (pad))
+    DrawPad (pad, 0);
+  return 1;
+}
+
+
+static int
+hole_callback (const BoxType * b, void *cl)
+{
+#if 0
+  PinTypePtr pin = (PinTypePtr) b;
+  int plated = cl ? *(int *) cl : -1;
+
+  switch (plated)
+    {
+    case -1:
+      break;
+    case 0:
+      if (!TEST_FLAG (HOLEFLAG, pin))
+	return 1;
+      break;
+    case 1:
+      if (TEST_FLAG (HOLEFLAG, pin))
+	return 1;
+      break;
+    }
+#endif
+  DrawHole ((PinTypePtr) b);
+  return 1;
+}
+
+static int
+via_callback (const BoxType * b, void *cl)
+{
+  PinTypePtr via = (PinTypePtr) b;
+  DrawPlainVia (via, false);
+  return 1;
+}
+
+static int
+line_callback (const BoxType * b, void *cl)
+{
+  DrawLine ((LayerTypePtr) cl, (LineTypePtr) b, 0);
+  return 1;
+}
+
+static int
+arc_callback (const BoxType * b, void *cl)
+{
+  DrawArc ((LayerTypePtr) cl, (ArcTypePtr) b, 0);
+  return 1;
+}
+
+static int
+text_callback (const BoxType * b, void *cl)
+{
+  DrawRegularText ((LayerTypePtr) cl, (TextTypePtr) b, 0);
+  return 1;
+}
+
+static void
+DrawPlainPolygon (LayerTypePtr Layer, PolygonTypePtr Polygon, const BoxType *drawn_area)
+{
+  static char *color;
+
+  if (!Polygon->Clipped)
+    return;
+
+  if (TEST_FLAG (SELECTEDFLAG, Polygon))
+    color = Layer->SelectedColor;
+  else if (TEST_FLAG (FOUNDFLAG, Polygon))
+    color = PCB->ConnectedColor;
+  else
+    color = Layer->Color;
+  gui->set_color (Output.fgGC, color);
+
+  if (gui->thindraw_pcb_polygon != NULL &&
+      (TEST_FLAG (THINDRAWFLAG, PCB) ||
+       TEST_FLAG (THINDRAWPOLYFLAG, PCB)))
+    gui->thindraw_pcb_polygon (Output.fgGC, Polygon, drawn_area);
+  else
+    gui->fill_pcb_polygon (Output.fgGC, Polygon, drawn_area);
+
+  /* If checking planes, thin-draw any pieces which have been clipped away */
+  if (gui->thindraw_pcb_polygon != NULL &&
+      TEST_FLAG (CHECKPLANESFLAG, PCB) &&
+      !TEST_FLAG (FULLPOLYFLAG, Polygon))
+    {
+      PolygonType poly = *Polygon;
+
+      for (poly.Clipped = Polygon->Clipped->f;
+           poly.Clipped != Polygon->Clipped;
+           poly.Clipped = poly.Clipped->f)
+        gui->thindraw_pcb_polygon (Output.fgGC, &poly, drawn_area);
+    }
+}
+
+static int
+poly_callback (const BoxType * b, void *cl)
+{
+  struct pin_info *i = (struct pin_info *) cl;
+
+  DrawPlainPolygon (i->Layer, (PolygonTypePtr) b, i->drawn_area);
+  return 1;
+}
+
+static void
+DrawPadLowLevelSolid (hidGC gc, PadTypePtr Pad, bool clear, bool mask)
+{
+  int w = clear ? (mask ? Pad->Mask : Pad->Thickness + Pad->Clearance)
+		: Pad->Thickness;
+
+  if (Pad->Point1.X == Pad->Point2.X &&
+      Pad->Point1.Y == Pad->Point2.Y)
+    {
+      if (TEST_FLAG (SQUAREFLAG, Pad))
+        {
+          int l, r, t, b;
+          l = Pad->Point1.X - w / 2;
+          b = Pad->Point1.Y - w / 2;
+          r = l + w;
+          t = b + w;
+          gui->fill_rect (gc, l, b, r, t);
+        }
+      else
+        {
+          gui->fill_circle (gc, Pad->Point1.X, Pad->Point1.Y, w / 2);
+        }
+    }
+  else
+    {
+      gui->set_line_cap (gc,
+                         TEST_FLAG (SQUAREFLAG,
+                                    Pad) ? Square_Cap : Round_Cap);
+      gui->set_line_width (gc, w);
+
+      gui->draw_line (gc,
+                      Pad->Point1.X, Pad->Point1.Y,
+                      Pad->Point2.X, Pad->Point2.Y);
+    }
+}
+
+static void
+ClearPadSolid (PadTypePtr Pad, bool mask)
+{
+  DrawPadLowLevelSolid(Output.pmGC, Pad, true, mask);
+}
+
+static void
+ClearOnlyPinSolid (PinTypePtr Pin, bool mask)
+{
+  BDimension half =
+    (mask ? Pin->Mask / 2 : (Pin->Thickness + Pin->Clearance) / 2);
+
+  if (!mask && TEST_FLAG (HOLEFLAG, Pin))
+    return;
+  if (half == 0)
+    return;
+  if (!mask && Pin->Clearance <= 0)
+    return;
+
+  /* Clear the area around the pin */
+  if (TEST_FLAG (SQUAREFLAG, Pin))
+    {
+      int l, r, t, b;
+      l = Pin->X - half;
+      b = Pin->Y - half;
+      r = l + half * 2;
+      t = b + half * 2;
+      gui->fill_rect (Output.pmGC, l, b, r, t);
+    }
+  else if (TEST_FLAG (OCTAGONFLAG, Pin))
+    {
+      DrawSpecialPolygon (Output.pmGC, Pin->X, Pin->Y, half * 2, false);
+    }
+  else
+    {
+      gui->fill_circle (Output.pmGC, Pin->X, Pin->Y, half);
+    }
+}
+
+static int
+clearPin_callback_solid (const BoxType * b, void *cl)
+{
+  PinTypePtr pin = (PinTypePtr) b;
+  struct pin_info *i = (struct pin_info *) cl;
+  if (i->arg)
+    ClearOnlyPinSolid (pin, true);
+  return 1;
+}
+
+static int
+clearPad_callback_solid (const BoxType * b, void *cl)
+{
+  PadTypePtr pad = (PadTypePtr) b;
+  if (!XOR (TEST_FLAG (ONSOLDERFLAG, pad), SWAP_IDENT))
+    ClearPadSolid (pad, true);
+  return 1;
+}
+
+int clearPin_callback (const BoxType * b, void *cl);
+int clearPad_callback (const BoxType * b, void *cl);
+
+
+static void
+DrawMask (BoxType * screen)
+{
+  struct pin_info info;
+  int thin = TEST_FLAG(THINDRAWFLAG, PCB) || TEST_FLAG(THINDRAWPOLYFLAG, PCB);
+
+  OutputType *out = &Output;
+
+  info.arg = true;
+  info.drawn_area = screen;
+
+  if (thin)
+    {
+      gui->set_line_width (Output.pmGC, 0);
+      gui->set_color (Output.pmGC, PCB->MaskColor);
+      r_search (PCB->Data->pin_tree, screen, NULL, clearPin_callback, &info);
+      r_search (PCB->Data->via_tree, screen, NULL, clearPin_callback, &info);
+      r_search (PCB->Data->pad_tree, screen, NULL, clearPad_callback, &info);
+      gui->set_color (Output.pmGC, "erase");
+    }
+
+  gui->use_mask (HID_MASK_BEFORE);
+  gui->set_color (out->fgGC, PCB->MaskColor);
+  gui->fill_rect (out->fgGC, 0, 0, PCB->MaxWidth, PCB->MaxHeight);
+
+  gui->use_mask (HID_MASK_CLEAR);
+  r_search (PCB->Data->pin_tree, screen, NULL, clearPin_callback_solid, &info);
+  r_search (PCB->Data->via_tree, screen, NULL, clearPin_callback_solid, &info);
+  r_search (PCB->Data->pad_tree, screen, NULL, clearPad_callback_solid, &info);
+
+  gui->use_mask (HID_MASK_AFTER);
+  gui->set_color (out->fgGC, PCB->MaskColor);
+  ghid_global_alpha_mult (out->fgGC, thin ? 0.35 : 1.0);
+  gui->fill_rect (out->fgGC, 0, 0, PCB->MaxWidth, PCB->MaxHeight);
+  ghid_global_alpha_mult (out->fgGC, 1.0);
+
+  gui->use_mask (HID_MASK_OFF);
+}
+
+static int
+DrawLayerGroup (int group, const BoxType * screen)
+{
+  int i, rv = 1;
+  int layernum;
+  struct pin_info info;
+  LayerTypePtr Layer;
+  int n_entries = PCB->LayerGroups.Number[group];
+  Cardinal *layers = PCB->LayerGroups.Entries[group];
+  int first_run = 1;
+
+  if (!gui->set_layer (0, group, 0)) {
+    gui->set_layer (NULL, SL (FINISHED, 0), 0);
+    return 0;
+  }
+
+  /* HACK: Subcomposite each layer in a layer group separately */
+  for (i = n_entries - 1; i >= 0; i--) {
+    layernum = layers[i];
+    Layer = PCB->Data->Layer + layers[i];
+
+    if (strcasecmp (Layer->Name, "outline") == 0 ||
+        strcasecmp (Layer->Name, "route") == 0)
+      rv = 0;
+
+    if (layernum < max_layer /*&& Layer->On*/) {
+
+      if (!first_run)
+        gui->set_layer (0, group, 0);
+
+      first_run = 0;
+
+      if (rv) {
+        /* Mask out drilled holes on this layer */
+        hidgl_flush_triangles (&buffer);
+        glPushAttrib (GL_COLOR_BUFFER_BIT);
+        glColorMask (0, 0, 0, 0);
+        gui->set_color (Output.bgGC, PCB->MaskColor);
+        if (PCB->PinOn) r_search (PCB->Data->pin_tree, screen, NULL, hole_callback, NULL);
+        if (PCB->ViaOn) r_search (PCB->Data->via_tree, screen, NULL, hole_callback, NULL);
+        hidgl_flush_triangles (&buffer);
+        glPopAttrib ();
+      }
+
+      /* draw all polygons on this layer */
+      if (Layer->PolygonN) {
+        info.Layer = Layer;
+        info.drawn_area = screen;
+        r_search (Layer->polygon_tree, screen, NULL, poly_callback, &info);
+
+        /* HACK: Subcomposite polygons separately from other layer primitives */
+        /* Reset the compositing */
+        gui->set_layer (NULL, SL (FINISHED, 0), 0);
+        gui->set_layer (0, group, 0);
+
+        if (rv) {
+          hidgl_flush_triangles (&buffer);
+          glPushAttrib (GL_COLOR_BUFFER_BIT);
+          glColorMask (0, 0, 0, 0);
+          /* Mask out drilled holes on this layer */
+          if (PCB->PinOn) r_search (PCB->Data->pin_tree, screen, NULL, hole_callback, NULL);
+          if (PCB->ViaOn) r_search (PCB->Data->via_tree, screen, NULL, hole_callback, NULL);
+          hidgl_flush_triangles (&buffer);
+          glPopAttrib ();
+        }
+      }
+
+      /* Draw pins and vias on this layer */
+      if (!global_view_2d && rv) {
+        if (PCB->PinOn) r_search (PCB->Data->pin_tree, screen, NULL, pin_inlayer_callback, Layer);
+        if (PCB->ViaOn) r_search (PCB->Data->via_tree, screen, NULL, via_inlayer_callback, Layer);
+      }
+
+      if (TEST_FLAG (CHECKPLANESFLAG, PCB))
+        continue;
+
+      r_search (Layer->line_tree, screen, NULL, line_callback, Layer);
+      r_search (Layer->arc_tree, screen, NULL, arc_callback, Layer);
+      r_search (Layer->text_tree, screen, NULL, text_callback, Layer);
+    }
+  }
+
+  gui->set_layer (NULL, SL (FINISHED, 0), 0);
+
+  return (n_entries > 1);
+}
+
+extern int compute_depth (int group);
+
+static void
+DrawDrillChannel (int vx, int vy, int vr, int from_layer, int to_layer, double scale)
+{
+#define PIXELS_PER_CIRCLINE 5.
+#define MIN_FACES_PER_CYL 6
+#define MAX_FACES_PER_CYL 360
+  float radius = vr;
+  float x1, y1;
+  float x2, y2;
+  float z1, z2;
+  int i;
+  int slices;
+
+  slices = M_PI * 2 * vr / scale / PIXELS_PER_CIRCLINE;
+
+  if (slices < MIN_FACES_PER_CYL)
+    slices = MIN_FACES_PER_CYL;
+
+  if (slices > MAX_FACES_PER_CYL)
+    slices = MAX_FACES_PER_CYL;
+
+  z1 = compute_depth (from_layer);
+  z2 = compute_depth (to_layer);
+
+  x1 = vx + vr;
+  y1 = vy;
+
+  hidgl_ensure_triangle_space (&buffer, 2 * slices);
+  for (i = 0; i < slices; i++)
+    {
+      x2 = radius * cosf (((float)(i + 1)) * 2. * M_PI / (float)slices) + vx;
+      y2 = radius * sinf (((float)(i + 1)) * 2. * M_PI / (float)slices) + vy;
+      hidgl_add_triangle_3D (&buffer, x1, y1, z1,  x2, y2, z1,  x1, y1, z2);
+      hidgl_add_triangle_3D (&buffer, x2, y2, z1,  x1, y1, z2,  x2, y2, z2);
+      x1 = x2;
+      y1 = y2;
+    }
+}
+
+struct cyl_info {
+  int from_layer;
+  int to_layer;
+  double scale;
+};
+
+static int
+hole_cyl_callback (const BoxType * b, void *cl)
+{
+  PinTypePtr Pin = (PinTypePtr) b;
+  struct cyl_info *info = cl;
+  DrawDrillChannel (Pin->X, Pin->Y, Pin->DrillingHole / 2, info->from_layer, info->to_layer, info->scale);
+  return 0;
+}
+
+void
+ghid_draw_everything (BoxTypePtr drawn_area)
+{
+  int i, ngroups;
+  /* This is the list of layer groups we will draw.  */
+  int do_group[MAX_LAYER];
+  /* This is the reverse of the order in which we draw them.  */
+  int drawn_groups[MAX_LAYER];
+  struct cyl_info cyl_info;
+  int reverse_layers;
+  int save_show_solder;
+
+  extern char *current_color;
+  extern bool Gathering;
+
+  current_color = NULL;
+  Gathering = false;
+
+  /* Test direction of rendering */
+  /* Look at sign of eye coordinate system z-coord when projecting a
+     world vector along +ve Z axis, (0, 0, 1). */
+  /* FIXME: This isn't strictly correct, as I've ignored the matrix
+            elements for homogeneous coordinates. */
+  /* NB: last_modelview_matrix is transposed in memory! */
+  reverse_layers = (last_modelview_matrix[2][2] < 0);
+
+  save_show_solder = Settings.ShowSolderSide;
+
+  if (reverse_layers)
+    Settings.ShowSolderSide = !Settings.ShowSolderSide;
+
+  if (!global_view_2d && save_show_solder)
+    reverse_layers = !reverse_layers;
+
+  memset (do_group, 0, sizeof (do_group));
+  for (ngroups = 0, i = 0; i < max_layer; i++) {
+    LayerType *l;
+    int group;
+    int orderi;
+
+    orderi = reverse_layers ? max_layer - i - 1 : i;
+
+    // Draw in numerical order when in 3D view
+    l = global_view_2d ? LAYER_ON_STACK (i) : LAYER_PTR (orderi);
+    group = GetLayerGroupNumberByNumber (global_view_2d ? LayerStack[i] : orderi);
+
+    if (/*l->On && */!do_group[group]) {
+      do_group[group] = 1;
+      drawn_groups[ngroups++] = group;
+    }
+  }
+
+  /*
+   * first draw all 'invisible' stuff
+   */
+  if (!TEST_FLAG (CHECKPLANESFLAG, PCB) &&
+      gui->set_layer ("invisible", SL (INVISIBLE, 0), 0)) {
+    r_search (PCB->Data->pad_tree, drawn_area, NULL, backPad_callback, NULL);
+    if (PCB->ElementOn) {
+      r_search (PCB->Data->element_tree, drawn_area, NULL, backE_callback, NULL);
+      r_search (PCB->Data->name_tree[NAME_INDEX (PCB)], drawn_area, NULL, backN_callback, NULL);
+      DrawLayer (&(PCB->Data->BACKSILKLAYER), drawn_area);
+    }
+    gui->set_layer (NULL, SL (FINISHED, 0), 0);
+  }
+
+  /* draw all layers in layerstack order */
+  for (i = ngroups - 1; i >= 0; i--) {
+    DrawLayerGroup (drawn_groups [i], drawn_area);
+
+#if 1
+    if (!global_view_2d && i > 0) {
+      cyl_info.from_layer = drawn_groups[i];
+      cyl_info.to_layer = drawn_groups[i - 1];
+      cyl_info.scale = gport->zoom;
+//      gui->set_color (Output.fgGC, PCB->MaskColor);
+      gui->set_color (Output.fgGC, "drill");
+      ghid_global_alpha_mult (Output.fgGC, 0.75);
+      if (PCB->PinOn) r_search (PCB->Data->pin_tree, drawn_area, NULL, hole_cyl_callback, &cyl_info);
+      if (PCB->ViaOn) r_search (PCB->Data->via_tree, drawn_area, NULL, hole_cyl_callback, &cyl_info);
+      ghid_global_alpha_mult (Output.fgGC, 1.0);
+    }
+#endif
+  }
+
+  if (TEST_FLAG (CHECKPLANESFLAG, PCB))
+    return;
+
+  /* Draw pins, pads, vias below silk */
+  if (!Settings.ShowSolderSide)
+    gui->set_layer ("topsilk", SL (SILK, TOP), 0);
+  else
+    gui->set_layer ("bottomsilk", SL (SILK, BOTTOM), 0);
+//  gui->set_layer (NULL, SL (FINISHED, 0), 0);
+
+#if 1
+  /* Mask out drilled holes */
+  hidgl_flush_triangles (&buffer);
+  glPushAttrib (GL_COLOR_BUFFER_BIT);
+  glColorMask (0, 0, 0, 0);
+  if (PCB->PinOn) r_search (PCB->Data->pin_tree, drawn_area, NULL, hole_callback, NULL);
+  if (PCB->ViaOn) r_search (PCB->Data->via_tree, drawn_area, NULL, hole_callback, NULL);
+  hidgl_flush_triangles (&buffer);
+  glPopAttrib ();
+
+  if (PCB->PinOn) r_search (PCB->Data->pad_tree, drawn_area, NULL, pad_callback, NULL);
+  if (PCB->PinOn) r_search (PCB->Data->pin_tree, drawn_area, NULL, pin_callback, NULL);
+  if (PCB->ViaOn) r_search (PCB->Data->via_tree, drawn_area, NULL, via_callback, NULL);
+#endif
+
+  gui->set_layer (NULL, SL (FINISHED, 0), 0);
+
+  /* Draw the solder mask if turned on */
+  if (gui->set_layer ("componentmask", SL (MASK, TOP), 0)) {
+    int save_swap = SWAP_IDENT;
+    SWAP_IDENT = 0;
+    DrawMask (drawn_area);
+    SWAP_IDENT = save_swap;
+    gui->set_layer (NULL, SL (FINISHED, 0), 0);
+  }
+  if (gui->set_layer ("soldermask", SL (MASK, BOTTOM), 0)) {
+    int save_swap = SWAP_IDENT;
+    SWAP_IDENT = 1;
+    DrawMask (drawn_area);
+    SWAP_IDENT = save_swap;
+    gui->set_layer (NULL, SL (FINISHED, 0), 0);
+  }
+  /* Draw top silkscreen */
+  if (gui->set_layer ("topsilk", SL (SILK, TOP), 0)) {
+    DrawSilk (0, COMPONENT_LAYER, drawn_area);
+    gui->set_layer (NULL, SL (FINISHED, 0), 0);
+  }
+
+  if (gui->set_layer ("bottomsilk", SL (SILK, BOTTOM), 0)) {
+    DrawSilk (1, SOLDER_LAYER, drawn_area);
+    gui->set_layer (NULL, SL (FINISHED, 0), 0);
+  }
+
+  /* Draw element Marks */
+  if (PCB->PinOn)
+    r_search (PCB->Data->element_tree, drawn_area, NULL, EMark_callback, NULL);
+
+  /* Draw rat lines on top */
+  if (PCB->RatOn && gui->set_layer ("rats", SL (RATS, 0), 0))
+    DrawRats(drawn_area);
+
+  Gathering = true;
+
+  Settings.ShowSolderSide = save_show_solder;
+}
+
+static int one_shot = 1;
 
 #define Z_NEAR 3.0
 gboolean
@@ -1069,8 +1702,8 @@ ghid_port_drawing_area_expose_event_cb (GtkWidget * widget,
   glStencilFunc (GL_ALWAYS, 0, 0);
 
   /* Test the 8 corners of a cube spanning the event */
-  min_depth = -50; /* FIXME */
-  max_depth =  0;  /* FIXME */
+  min_depth = -50 + compute_depth (0);         /* FIXME */
+  max_depth =  50 + compute_depth (max_layer); /* FIXME */
 
   ghid_unproject_to_z_plane (ev->area.x,
                              ev->area.y,
@@ -1163,7 +1796,8 @@ ghid_port_drawing_area_expose_event_cb (GtkWidget * widget,
                 ghid_flip_y ? gport->view_y0 - PCB->MaxHeight :
                              -gport->view_y0, 0);
 
-  hid_expose_callback (&ghid_hid, &region, 0);
+  // hid_expose_callback (&ghid_hid, &region, 0);
+  ghid_draw_everything (&region);
 
   hidgl_flush_triangles (&buffer);
   glPopMatrix ();
@@ -1202,6 +1836,8 @@ ghid_port_drawing_area_expose_event_cb (GtkWidget * widget,
   /* end drawing to current GL-context */
   gdk_gl_drawable_gl_end (pGlDrawable);
 
+  one_shot = 0;
+
   return FALSE;
 }
 
diff --git a/src/hid/gtk/gui.h b/src/hid/gtk/gui.h
index e676b43..38f2148 100644
--- a/src/hid/gtk/gui.h
+++ b/src/hid/gtk/gui.h
@@ -542,6 +542,7 @@ void ghid_fill_rect (hidGC gc, int x1, int y1, int x2, int y2);
 /* gtkhid-main.c */
 
 void ghid_invalidate_all ();
+void ghid_global_alpha_mult (hidGC gc, double alpha_mult);
 void ghid_invalidate_current_gc ();
 void ghid_get_coords (const char *msg, int *x, int *y);
 gint PCBChanged (int argc, char **argv, int x, int y);

commit fa86f244887fca50ad7487b377fecf64b0c44bb1
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    Fix grid extents in 3D view

diff --git a/src/hid/gtk/gtkhid-gl.c b/src/hid/gtk/gtkhid-gl.c
index ae58cbb..87daf19 100644
--- a/src/hid/gtk/gtkhid-gl.c
+++ b/src/hid/gtk/gtkhid-gl.c
@@ -62,7 +62,7 @@ ghid_make_gc (void)
 }
 
 void
-ghid_draw_grid ()
+ghid_draw_grid (BoxTypePtr drawn_area)
 {
   static GLfloat *points = 0;
   static int npoints = 0;
@@ -91,10 +91,10 @@ ghid_draw_grid ()
              gport->grid_color.green / 65535.,
              gport->grid_color.blue / 65535.);
 
-  x1 = GRIDFIT_X (SIDE_X (gport->view_x0), PCB->Grid);
-  y1 = GRIDFIT_Y (SIDE_Y (gport->view_y0), PCB->Grid);
-  x2 = GRIDFIT_X (SIDE_X (gport->view_x0 + gport->view_width - 1), PCB->Grid);
-  y2 = GRIDFIT_Y (SIDE_Y (gport->view_y0 + gport->view_height - 1), PCB->Grid);
+  x1 = GRIDFIT_X (MAX (0, drawn_area->X1), PCB->Grid);
+  y1 = GRIDFIT_Y (MAX (0, drawn_area->Y1), PCB->Grid);
+  x2 = GRIDFIT_X (MIN (PCB->MaxWidth, drawn_area->X2), PCB->Grid);
+  y2 = GRIDFIT_Y (MIN (PCB->MaxHeight, drawn_area->Y2), PCB->Grid);
   if (x1 > x2)
     {
       int tmp = x1;
diff --git a/src/hid/gtk/gui-output-events.c b/src/hid/gtk/gui-output-events.c
index 3295f23..fabe334 100644
--- a/src/hid/gtk/gui-output-events.c
+++ b/src/hid/gtk/gui-output-events.c
@@ -1173,7 +1173,7 @@ ghid_port_drawing_area_expose_event_cb (GtkWidget * widget,
   gui->set_layer (NULL, GetLayerGroupNumberByNumber (INDEXOFCURRENT), 0);
   gui->set_layer (NULL, SL_FINISHED, 0);
 
-  ghid_draw_grid ();
+  ghid_draw_grid (&region);
 
   hidgl_init_triangle_array (&buffer);
   ghid_invalidate_current_gc ();
diff --git a/src/hid/gtk/gui.h b/src/hid/gtk/gui.h
index dad9dea..e676b43 100644
--- a/src/hid/gtk/gui.h
+++ b/src/hid/gtk/gui.h
@@ -517,7 +517,8 @@ GdkPixmap *ghid_render_pixmap (int cx,
 /* gtkhid-gdk.c OR gtkhid-gl.c */
 hidGC ghid_make_gc (void);
 void ghid_destroy_gc (hidGC);
-void ghid_draw_grid (void);
+//void ghid_draw_grid (void);                /* FIXME: GDK AND GL DIFFERENT */
+void ghid_draw_grid (BoxTypePtr drawn_area); /* FIXME: GDK AND GL DIFFERENT */
 void ghid_draw_bg_image (void);
 void ghid_use_mask (int use_it);
 void ghid_set_color (hidGC gc, const char *name);

commit 701effca7fe31d6ab3a778e8cac6f9d39b35f06f
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    Shiny 3D eye-candy
    
    Experiments in progress - don't expect this to work yet!

diff --git a/src/hid/gtk/gtkhid-gl.c b/src/hid/gtk/gtkhid-gl.c
index 6b1e306..ae58cbb 100644
--- a/src/hid/gtk/gtkhid-gl.c
+++ b/src/hid/gtk/gtkhid-gl.c
@@ -68,6 +68,7 @@ ghid_draw_grid ()
   static int npoints = 0;
   int x1, y1, x2, y2, n, i;
   double x, y;
+  extern float global_depth;
 
   if (!Settings.DrawGrid)
     return;
@@ -119,23 +120,24 @@ ghid_draw_grid ()
     {
       npoints = n + 10;
       points =
-	MyRealloc (points, npoints * 2 * sizeof (GLfloat), "gtk_draw_grid");
+	MyRealloc (points, npoints * 3 * sizeof (GLfloat), "gtk_draw_grid");
     }
 
   glEnableClientState (GL_VERTEX_ARRAY);
-  glVertexPointer (2, GL_FLOAT, 0, points);
+  glVertexPointer (3, GL_FLOAT, 0, points);
 
   n = 0;
   for (x = x1; x <= x2; x += PCB->Grid)
     {
-      points[2 * n] = Vx (x);
+      points[3 * n] = Vx (x);
+      points[3 * n + 2] = global_depth;
       n++;
     }
   for (y = y1; y <= y2; y += PCB->Grid)
     {
       int vy = Vy (y);
       for (i = 0; i < n; i++)
-	points[2 * i + 1] = vy;
+	points[3 * i + 1] = vy;
       glDrawArrays (GL_POINTS, 0, n);
     }
 
diff --git a/src/hid/gtk/gtkhid-main.c b/src/hid/gtk/gtkhid-main.c
index e2bc158..7b01d27 100644
--- a/src/hid/gtk/gtkhid-main.c
+++ b/src/hid/gtk/gtkhid-main.c
@@ -346,6 +346,18 @@ ghid_set_layer (const char *name, int group, int empty)
   /* Flush out any existing geoemtry to be rendered */
   hidgl_flush_triangles (&buffer);
 
+  if (group >= 0 && group < max_layer) {
+    hidgl_set_depth ((max_layer - group) * 10);
+  } else {
+    if (SL_TYPE (idx) == SL_SILK) {
+      if (SL_SIDE (idx) == SL_TOP_SIDE && !Settings.ShowSolderSide) {
+        hidgl_set_depth (max_layer * 10 + 3);
+      } else {
+        hidgl_set_depth (10 - 3);
+      }
+    }
+  }
+
   glEnable (GL_STENCIL_TEST);                // Enable Stencil test
   glStencilOp (GL_KEEP, GL_KEEP, GL_REPLACE); // Stencil pass => replace stencil value (with 1)
   /* Reset stencil buffer so we can paint anywhere */
diff --git a/src/hid/gtk/gui-output-events.c b/src/hid/gtk/gui-output-events.c
index 1929d45..3295f23 100644
--- a/src/hid/gtk/gui-output-events.c
+++ b/src/hid/gtk/gui-output-events.c
@@ -483,16 +483,16 @@ have_crosshair_attachments (void)
 #define VCD		8
 
 static void
-draw_right_cross (gint x, gint y)
+draw_right_cross (gint x, gint y, gint z)
 {
-  glVertex2i (x, 0);
-  glVertex2i (x, gport->height);
-  glVertex2i (0, y);
-  glVertex2i (gport->width, y);
+  glVertex3i (x, 0, z);
+  glVertex3i (x, gport->height, z);
+  glVertex3i (0, y, z);
+  glVertex3i (gport->width, y, z);
 }
 
 static void
-draw_slanted_cross (gint x, gint y)
+draw_slanted_cross (gint x, gint y, gint z)
 {
   gint x0, y0, x1, y1;
 
@@ -504,8 +504,8 @@ draw_slanted_cross (gint x, gint y)
   y0 = MAX(0, MIN (y0, gport->height));
   y1 = y - x;
   y1 = MAX(0, MIN (y1, gport->height));
-  glVertex2i (x0, y0);
-  glVertex2i (x1, y1);
+  glVertex3i (x0, y0, z);
+  glVertex3i (x1, y1, z);
 
   x0 = x - (gport->height - y);
   x0 = MAX(0, MIN (x0, gport->width));
@@ -515,12 +515,12 @@ draw_slanted_cross (gint x, gint y)
   y0 = MAX(0, MIN (y0, gport->height));
   y1 = y - (gport->width - x);
   y1 = MAX(0, MIN (y1, gport->height));
-  glVertex2i (x0, y0);
-  glVertex2i (x1, y1);
+  glVertex3i (x0, y0, z);
+  glVertex3i (x1, y1, z);
 }
 
 static void
-draw_dozen_cross (gint x, gint y)
+draw_dozen_cross (gint x, gint y, gint z)
 {
   gint x0, y0, x1, y1;
   gdouble tan60 = sqrt (3);
@@ -533,8 +533,8 @@ draw_dozen_cross (gint x, gint y)
   y0 = MAX(0, MIN (y0, gport->height));
   y1 = y - x * tan60;
   y1 = MAX(0, MIN (y1, gport->height));
-  glVertex2i (x0, y0);
-  glVertex2i (x1, y1);
+  glVertex3i (x0, y0, z);
+  glVertex3i (x1, y1, z);
 
   x0 = x + (gport->height - y) * tan60;
   x0 = MAX(0, MIN (x0, gport->width));
@@ -544,8 +544,8 @@ draw_dozen_cross (gint x, gint y)
   y0 = MAX(0, MIN (y0, gport->height));
   y1 = y - x / tan60;
   y1 = MAX(0, MIN (y1, gport->height));
-  glVertex2i (x0, y0);
-  glVertex2i (x1, y1);
+  glVertex3i (x0, y0, z);
+  glVertex3i (x1, y1, z);
 
   x0 = x - (gport->height - y) / tan60;
   x0 = MAX(0, MIN (x0, gport->width));
@@ -555,8 +555,8 @@ draw_dozen_cross (gint x, gint y)
   y0 = MAX(0, MIN (y0, gport->height));
   y1 = y - (gport->width - x) * tan60;
   y1 = MAX(0, MIN (y1, gport->height));
-  glVertex2i (x0, y0);
-  glVertex2i (x1, y1);
+  glVertex3i (x0, y0, z);
+  glVertex3i (x1, y1, z);
 
   x0 = x - (gport->height - y) * tan60;
   x0 = MAX(0, MIN (x0, gport->width));
@@ -566,30 +566,31 @@ draw_dozen_cross (gint x, gint y)
   y0 = MAX(0, MIN (y0, gport->height));
   y1 = y - (gport->width - x) / tan60;
   y1 = MAX(0, MIN (y1, gport->height));
-  glVertex2i (x0, y0);
-  glVertex2i (x1, y1);
+  glVertex3i (x0, y0, z);
+  glVertex3i (x1, y1, z);
 }
 
 static void
-draw_crosshair (gint x, gint y)
+draw_crosshair (gint x, gint y, gint z)
 {
   static enum crosshair_shape prev = Basic_Crosshair_Shape;
 
-  draw_right_cross (x, y);
+  draw_right_cross (x, y, z);
   if (prev == Union_Jack_Crosshair_Shape)
-    draw_slanted_cross (x, y);
+    draw_slanted_cross (x, y, z);
   if (prev == Dozen_Crosshair_Shape)
-    draw_dozen_cross (x, y);
+    draw_dozen_cross (x, y, z);
   prev = Crosshair.shape;
 }
 
 void
 ghid_show_crosshair (gboolean show)
 {
-  gint x, y;
-  static gint x_prev = -1, y_prev = -1;
+  gint x, y, z;
+  static gint x_prev = -1, y_prev = -1, z_prev = -1;
   static int done_once = 0;
   static GdkColor cross_color;
+  extern float global_depth;
 
   if (gport->x_crosshair < 0 || ghidgui->creating) {// || !gport->has_entered) {
     printf ("Returning\n");
@@ -604,6 +605,7 @@ ghid_show_crosshair (gboolean show)
     }
   x = DRAW_X (gport->x_crosshair);
   y = DRAW_Y (gport->y_crosshair);
+  z = global_depth;
 
   glEnable (GL_COLOR_LOGIC_OP);
   glLogicOp (GL_XOR);
@@ -619,13 +621,13 @@ ghid_show_crosshair (gboolean show)
 #if 1
   if (x_prev >= 0)
     {
-      draw_crosshair (x_prev, y_prev);
+      draw_crosshair (x_prev, y_prev, z_prev);
     }
 #endif
 
   if (x >= 0 && show)
     {
-      draw_crosshair (x, y);
+      draw_crosshair (x, y, z);
     }
 
   glEnd ();
@@ -637,43 +639,43 @@ ghid_show_crosshair (gboolean show)
 #if 1
       if (x_prev >= 0)
         {
-          glVertex2i (0,                  y_prev - VCD);
-          glVertex2i (0,                  y_prev - VCD + VCW);
-          glVertex2i (VCD,                y_prev - VCD + VCW);
-          glVertex2i (VCD,                y_prev - VCD);
-          glVertex2i (gport->width,       y_prev - VCD);
-          glVertex2i (gport->width,       y_prev - VCD + VCW);
-          glVertex2i (gport->width - VCD, y_prev - VCD + VCW);
-          glVertex2i (gport->width - VCD, y_prev - VCD);
-          glVertex2i (x_prev - VCD,       0);
-          glVertex2i (x_prev - VCD,       VCD);
-          glVertex2i (x_prev - VCD + VCW, VCD);
-          glVertex2i (x_prev - VCD + VCW, 0);
-          glVertex2i (x_prev - VCD,       gport->height - VCD);
-          glVertex2i (x_prev - VCD,       gport->height);
-          glVertex2i (x_prev - VCD + VCW, gport->height);
-          glVertex2i (x_prev - VCD + VCW, gport->height - VCD);
+          glVertex3i (0,                  y_prev - VCD,        z_prev);
+          glVertex3i (0,                  y_prev - VCD + VCW,  z_prev);
+          glVertex3i (VCD,                y_prev - VCD + VCW,  z_prev);
+          glVertex3i (VCD,                y_prev - VCD,        z_prev);
+          glVertex3i (gport->width,       y_prev - VCD,        z_prev);
+          glVertex3i (gport->width,       y_prev - VCD + VCW,  z_prev);
+          glVertex3i (gport->width - VCD, y_prev - VCD + VCW,  z_prev);
+          glVertex3i (gport->width - VCD, y_prev - VCD,        z_prev);
+          glVertex3i (x_prev - VCD,       0,                   z_prev);
+          glVertex3i (x_prev - VCD,       VCD,                 z_prev);
+          glVertex3i (x_prev - VCD + VCW, VCD,                 z_prev);
+          glVertex3i (x_prev - VCD + VCW, 0,                   z_prev);
+          glVertex3i (x_prev - VCD,       gport->height - VCD, z_prev);
+          glVertex3i (x_prev - VCD,       gport->height,       z_prev);
+          glVertex3i (x_prev - VCD + VCW, gport->height,       z_prev);
+          glVertex3i (x_prev - VCD + VCW, gport->height - VCD, z_prev);
         }
 #endif
 
       if (x >= 0 && show)
         {
-          glVertex2i (0,                  y - VCD);
-          glVertex2i (0,                  y - VCD + VCW);
-          glVertex2i (VCD,                y - VCD + VCW);
-          glVertex2i (VCD,                y - VCD);
-          glVertex2i (gport->width,       y - VCD);
-          glVertex2i (gport->width,       y - VCD + VCW);
-          glVertex2i (gport->width - VCD, y - VCD + VCW);
-          glVertex2i (gport->width - VCD, y - VCD);
-          glVertex2i (x - VCD,            0);
-          glVertex2i (x - VCD,            VCD);
-          glVertex2i (x - VCD + VCW,      VCD);
-          glVertex2i (x - VCD + VCW,      0);
-          glVertex2i (x - VCD,            gport->height - VCD);
-          glVertex2i (x - VCD,            gport->height);
-          glVertex2i (x - VCD + VCW,      gport->height);
-          glVertex2i (x - VCD + VCW,      gport->height - VCD);
+          glVertex3i (0,                  y - VCD,             z);
+          glVertex3i (0,                  y - VCD + VCW,       z);
+          glVertex3i (VCD,                y - VCD + VCW,       z);
+          glVertex3i (VCD,                y - VCD,             z);
+          glVertex3i (gport->width,       y - VCD,             z);
+          glVertex3i (gport->width,       y - VCD + VCW,       z);
+          glVertex3i (gport->width - VCD, y - VCD + VCW,       z);
+          glVertex3i (gport->width - VCD, y - VCD,             z);
+          glVertex3i (x - VCD,            0,                   z);
+          glVertex3i (x - VCD,            VCD,                 z);
+          glVertex3i (x - VCD + VCW,      VCD,                 z);
+          glVertex3i (x - VCD + VCW,      0,                   z);
+          glVertex3i (x - VCD,            gport->height - VCD, z);
+          glVertex3i (x - VCD,            gport->height,       z);
+          glVertex3i (x - VCD + VCW,      gport->height,       z);
+          glVertex3i (x - VCD + VCW,      gport->height - VCD, z);
         }
 
       glEnd ();
@@ -683,9 +685,10 @@ ghid_show_crosshair (gboolean show)
     {
       x_prev = x;
       y_prev = y;
+      z_prev = z;
     }
   else
-    x_prev = y_prev = -1;
+    x_prev = y_prev = z_prev = -1;
 
   glDisable (GL_COLOR_LOGIC_OP);
 }
@@ -1165,6 +1168,11 @@ ghid_port_drawing_area_expose_event_cb (GtkWidget * widget,
   hidgl_flush_triangles (&buffer);
   glPopMatrix ();
 
+  /* Just prod the drawing code so the current depth gets set to
+     the right value for the layer we are editing */
+  gui->set_layer (NULL, GetLayerGroupNumberByNumber (INDEXOFCURRENT), 0);
+  gui->set_layer (NULL, SL_FINISHED, 0);
+
   ghid_draw_grid ();
 
   hidgl_init_triangle_array (&buffer);

commit 60aa80d5720b54939f37a225eba66aed1a483ec2
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    Add support for depth to triangle rendering routines.
    
    Nasty global depth_state variable should be replaced!

diff --git a/src/hid/common/hidgl.c b/src/hid/common/hidgl.c
index faf27c7..cb53763 100644
--- a/src/hid/common/hidgl.c
+++ b/src/hid/common/hidgl.c
@@ -46,6 +46,7 @@
 RCSID ("$Id: $");
 
 triangle_buffer buffer;
+float global_depth = 0;
 
 #if 0
 triangle_array *
@@ -59,7 +60,7 @@ void
 hidgl_init_triangle_array (triangle_buffer *buffer)
 {
   glEnableClientState (GL_VERTEX_ARRAY);
-  glVertexPointer (2, GL_FLOAT, 0, buffer->triangle_array);
+  glVertexPointer (3, GL_FLOAT, 0, buffer->triangle_array);
   buffer->triangle_count = 0;
   buffer->coord_comp_count = 0;
 }
@@ -377,10 +378,10 @@ void
 hidgl_draw_rect (int x1, int y1, int x2, int y2)
 {
   glBegin (GL_LINE_LOOP);
-  glVertex2f (x1, y1);
-  glVertex2f (x1, y2);
-  glVertex2f (x2, y2);
-  glVertex2f (x2, y1);
+  glVertex3f (x1, y1, global_depth);
+  glVertex3f (x1, y2, global_depth);
+  glVertex3f (x2, y2, global_depth);
+  glVertex3f (x2, y1, global_depth);
   glEnd ();
 }
 
@@ -814,6 +815,12 @@ hidgl_reset_stencil_usage (void)
   dirty_bits = 0;
 }
 
+void
+hidgl_set_depth (float depth)
+{
+  global_depth = depth;
+}
+
 
 /* ---------------------------------------------------------------------- */
 
diff --git a/src/hid/common/hidgl.h b/src/hid/common/hidgl.h
index b956a65..aa2985e 100644
--- a/src/hid/common/hidgl.h
+++ b/src/hid/common/hidgl.h
@@ -25,32 +25,47 @@
 
 #define TRIANGLE_ARRAY_SIZE 5461
 typedef struct {
-  GLfloat triangle_array [2 * 3 * TRIANGLE_ARRAY_SIZE];
+  GLfloat triangle_array [3 * 3 * TRIANGLE_ARRAY_SIZE];
   unsigned int triangle_count;
   unsigned int coord_comp_count;
 } triangle_buffer;
 
 extern triangle_buffer buffer;
+extern float global_depth;
 
 void hidgl_init_triangle_array (triangle_buffer *buffer);
 void hidgl_flush_triangles (triangle_buffer *buffer);
 void hidgl_ensure_triangle_space (triangle_buffer *buffer, int count);
 
 static inline void
-hidgl_add_triangle (triangle_buffer *buffer,
-                    GLfloat x1, GLfloat y1,
-                    GLfloat x2, GLfloat y2,
-                    GLfloat x3, GLfloat y3)
+hidgl_add_triangle_3D (triangle_buffer *buffer,
+                       GLfloat x1, GLfloat y1, GLfloat z1,
+                       GLfloat x2, GLfloat y2, GLfloat z2,
+                       GLfloat x3, GLfloat y3, GLfloat z3)
 {
   buffer->triangle_array [buffer->coord_comp_count++] = x1;
   buffer->triangle_array [buffer->coord_comp_count++] = y1;
+  buffer->triangle_array [buffer->coord_comp_count++] = z1;
   buffer->triangle_array [buffer->coord_comp_count++] = x2;
   buffer->triangle_array [buffer->coord_comp_count++] = y2;
+  buffer->triangle_array [buffer->coord_comp_count++] = z2;
   buffer->triangle_array [buffer->coord_comp_count++] = x3;
   buffer->triangle_array [buffer->coord_comp_count++] = y3;
+  buffer->triangle_array [buffer->coord_comp_count++] = z3;
   buffer->triangle_count++;
 }
 
+static inline void
+hidgl_add_triangle (triangle_buffer *buffer,
+                    GLfloat x1, GLfloat y1,
+                    GLfloat x2, GLfloat y2,
+                    GLfloat x3, GLfloat y3)
+{
+  hidgl_add_triangle_3D (buffer, x1, y1, global_depth,
+                                 x2, y2, global_depth,
+                                 x3, y3, global_depth);
+}
+
 // void draw_grid ()
 void hidgl_draw_line (int cap, double width, int x1, int y1, int x2, int y2, double scale);
 void hidgl_draw_arc (double width, int vx, int vy, int vrx, int vry, int start_angle, int delta_angle, double scale);
@@ -65,5 +80,6 @@ int hidgl_stencil_bits (void);
 int hidgl_assign_clear_stencil_bit (void);
 void hidgl_return_stencil_bit (int bit);
 void hidgl_reset_stencil_usage (void);
+void hidgl_set_depth (float depth);
 
 #endif /* __HIDGL_INCLUDED__  */
diff --git a/src/hid/gtk/gui-output-events.c b/src/hid/gtk/gui-output-events.c
index 4693e5d..1929d45 100644
--- a/src/hid/gtk/gui-output-events.c
+++ b/src/hid/gtk/gui-output-events.c
@@ -422,7 +422,7 @@ ghid_note_event_location (GdkEventButton * ev)
     }
 
   /* Unproject event_x and event_y to world coordinates of the plane we are on */
-  ghid_unproject_to_z_plane (event_x, event_y, 0,
+  ghid_unproject_to_z_plane (event_x, event_y, global_depth,
                              &event_x, &event_y);
 
   gport->view_x = event_x * gport->zoom + gport->view_x0;

commit 454639bf87001fd157269185fad73c3faf00196b
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    Use trackball to allow rotation of 3D view

diff --git a/src/hid/gtk/gui-output-events.c b/src/hid/gtk/gui-output-events.c
index db1fb31..4693e5d 100644
--- a/src/hid/gtk/gui-output-events.c
+++ b/src/hid/gtk/gui-output-events.c
@@ -36,6 +36,7 @@
 #include "gtkhid.h"
 #include "hid/common/hid_resource.h"
 #include "hid/common/draw_helpers.h"
+#include "hid/common/trackball.h"
 
 #include <gdk/gdkkeysyms.h>
 
@@ -58,6 +59,16 @@
 RCSID ("$Id$");
 
 static gint x_pan_speed, y_pan_speed;
+static GLfloat view_matrix[4][4] = {{1.0, 0.0, 0.0, 0.0},
+                                    {0.0, 1.0, 0.0, 0.0},
+                                    {0.0, 0.0, 1.0, 0.0},
+                                    {0.0, 0.0, 0.0, 1.0}};
+static GLfloat last_modelview_matrix[4][4] = {{1.0, 0.0, 0.0, 0.0},
+                                              {0.0, 1.0, 0.0, 0.0},
+                                              {0.0, 0.0, 1.0, 0.0},
+                                              {0.0, 0.0, 0.0, 1.0}};
+static int global_view_2d = 1;
+
 
 /* Set to true if cursor is currently in viewport. This is a hack to prevent
  * Crosshair stack corruption due to unmatching window enter / leave events */
@@ -229,6 +240,169 @@ ghid_get_coords (const char *msg, int *x, int *y)
     }
 }
 
+static float
+determinant_2x2 (float m[2][2])
+{
+  float det;
+  det = m[0][0] * m[1][1] -
+        m[0][1] * m[1][0];
+  return det;
+}
+
+#if 0
+static float
+determinant_4x4 (float m[4][4])
+{
+  float det;
+  det = m[0][3] * m[1][2] * m[2][1] * m[3][0]-m[0][2] * m[1][3] * m[2][1] * m[3][0] -
+        m[0][3] * m[1][1] * m[2][2] * m[3][0]+m[0][1] * m[1][3] * m[2][2] * m[3][0] +
+        m[0][2] * m[1][1] * m[2][3] * m[3][0]-m[0][1] * m[1][2] * m[2][3] * m[3][0] -
+        m[0][3] * m[1][2] * m[2][0] * m[3][1]+m[0][2] * m[1][3] * m[2][0] * m[3][1] +
+        m[0][3] * m[1][0] * m[2][2] * m[3][1]-m[0][0] * m[1][3] * m[2][2] * m[3][1] -
+        m[0][2] * m[1][0] * m[2][3] * m[3][1]+m[0][0] * m[1][2] * m[2][3] * m[3][1] +
+        m[0][3] * m[1][1] * m[2][0] * m[3][2]-m[0][1] * m[1][3] * m[2][0] * m[3][2] -
+        m[0][3] * m[1][0] * m[2][1] * m[3][2]+m[0][0] * m[1][3] * m[2][1] * m[3][2] +
+        m[0][1] * m[1][0] * m[2][3] * m[3][2]-m[0][0] * m[1][1] * m[2][3] * m[3][2] -
+        m[0][2] * m[1][1] * m[2][0] * m[3][3]+m[0][1] * m[1][2] * m[2][0] * m[3][3] +
+        m[0][2] * m[1][0] * m[2][1] * m[3][3]-m[0][0] * m[1][2] * m[2][1] * m[3][3] -
+        m[0][1] * m[1][0] * m[2][2] * m[3][3]+m[0][0] * m[1][1] * m[2][2] * m[3][3];
+   return det;
+}
+#endif
+
+static void
+invert_2x2 (float m[2][2], float out[2][2])
+{
+  float scale = 1 / determinant_2x2 (m);
+  out[0][0] =  m[1][1] * scale;
+  out[0][1] = -m[0][1] * scale;
+  out[1][0] = -m[1][0] * scale;
+  out[1][1] =  m[0][0] * scale;
+}
+
+#if 0
+static void
+invert_4x4 (float m[4][4], float out[4][4])
+{
+  float scale = 1 / determinant_4x4 (m);
+
+  out[0][0] = (m[1][2] * m[2][3] * m[3][1] - m[1][3] * m[2][2] * m[3][1] +
+               m[1][3] * m[2][1] * m[3][2] - m[1][1] * m[2][3] * m[3][2] -
+               m[1][2] * m[2][1] * m[3][3] + m[1][1] * m[2][2] * m[3][3]) * scale;
+  out[0][1] = (m[0][3] * m[2][2] * m[3][1] - m[0][2] * m[2][3] * m[3][1] -
+               m[0][3] * m[2][1] * m[3][2] + m[0][1] * m[2][3] * m[3][2] +
+               m[0][2] * m[2][1] * m[3][3] - m[0][1] * m[2][2] * m[3][3]) * scale;
+  out[0][2] = (m[0][2] * m[1][3] * m[3][1] - m[0][3] * m[1][2] * m[3][1] +
+               m[0][3] * m[1][1] * m[3][2] - m[0][1] * m[1][3] * m[3][2] -
+               m[0][2] * m[1][1] * m[3][3] + m[0][1] * m[1][2] * m[3][3]) * scale;
+  out[0][3] = (m[0][3] * m[1][2] * m[2][1] - m[0][2] * m[1][3] * m[2][1] -
+               m[0][3] * m[1][1] * m[2][2] + m[0][1] * m[1][3] * m[2][2] +
+               m[0][2] * m[1][1] * m[2][3] - m[0][1] * m[1][2] * m[2][3]) * scale;
+  out[1][0] = (m[1][3] * m[2][2] * m[3][0] - m[1][2] * m[2][3] * m[3][0] -
+               m[1][3] * m[2][0] * m[3][2] + m[1][0] * m[2][3] * m[3][2] +
+               m[1][2] * m[2][0] * m[3][3] - m[1][0] * m[2][2] * m[3][3]) * scale;
+  out[1][1] = (m[0][2] * m[2][3] * m[3][0] - m[0][3] * m[2][2] * m[3][0] +
+               m[0][3] * m[2][0] * m[3][2] - m[0][0] * m[2][3] * m[3][2] -
+               m[0][2] * m[2][0] * m[3][3] + m[0][0] * m[2][2] * m[3][3]) * scale;
+  out[1][2] = (m[0][3] * m[1][2] * m[3][0] - m[0][2] * m[1][3] * m[3][0] -
+               m[0][3] * m[1][0] * m[3][2] + m[0][0] * m[1][3] * m[3][2] +
+               m[0][2] * m[1][0] * m[3][3] - m[0][0] * m[1][2] * m[3][3]) * scale;
+  out[1][3] = (m[0][2] * m[1][3] * m[2][0] - m[0][3] * m[1][2] * m[2][0] +
+               m[0][3] * m[1][0] * m[2][2] - m[0][0] * m[1][3] * m[2][2] -
+               m[0][2] * m[1][0] * m[2][3] + m[0][0] * m[1][2] * m[2][3]) * scale;
+  out[2][0] = (m[1][1] * m[2][3] * m[3][0] - m[1][3] * m[2][1] * m[3][0] +
+               m[1][3] * m[2][0] * m[3][1] - m[1][0] * m[2][3] * m[3][1] -
+               m[1][1] * m[2][0] * m[3][3] + m[1][0] * m[2][1] * m[3][3]) * scale;
+  out[2][1] = (m[0][3] * m[2][1] * m[3][0] - m[0][1] * m[2][3] * m[3][0] -
+               m[0][3] * m[2][0] * m[3][1] + m[0][0] * m[2][3] * m[3][1] +
+               m[0][1] * m[2][0] * m[3][3] - m[0][0] * m[2][1] * m[3][3]) * scale;
+  out[2][2] = (m[0][1] * m[1][3] * m[3][0] - m[0][3] * m[1][1] * m[3][0] +
+               m[0][3] * m[1][0] * m[3][1] - m[0][0] * m[1][3] * m[3][1] -
+               m[0][1] * m[1][0] * m[3][3] + m[0][0] * m[1][1] * m[3][3]) * scale;
+  out[2][3] = (m[0][3] * m[1][1] * m[2][0] - m[0][1] * m[1][3] * m[2][0] -
+               m[0][3] * m[1][0] * m[2][1] + m[0][0] * m[1][3] * m[2][1] +
+               m[0][1] * m[1][0] * m[2][3] - m[0][0] * m[1][1] * m[2][3]) * scale;
+  out[3][0] = (m[1][2] * m[2][1] * m[3][0] - m[1][1] * m[2][2] * m[3][0] -
+               m[1][2] * m[2][0] * m[3][1] + m[1][0] * m[2][2] * m[3][1] +
+               m[1][1] * m[2][0] * m[3][2] - m[1][0] * m[2][1] * m[3][2]) * scale;
+  out[3][1] = (m[0][1] * m[2][2] * m[3][0] - m[0][2] * m[2][1] * m[3][0] +
+               m[0][2] * m[2][0] * m[3][1] - m[0][0] * m[2][2] * m[3][1] -
+               m[0][1] * m[2][0] * m[3][2] + m[0][0] * m[2][1] * m[3][2]) * scale;
+  out[3][2] = (m[0][2] * m[1][1] * m[3][0] - m[0][1] * m[1][2] * m[3][0] -
+               m[0][2] * m[1][0] * m[3][1] + m[0][0] * m[1][2] * m[3][1] +
+               m[0][1] * m[1][0] * m[3][2] - m[0][0] * m[1][1] * m[3][2]) * scale;
+  out[3][3] = (m[0][1] * m[1][2] * m[2][0] - m[0][2] * m[1][1] * m[2][0] +
+               m[0][2] * m[1][0] * m[2][1] - m[0][0] * m[1][2] * m[2][1] -
+               m[0][1] * m[1][0] * m[2][2] + m[0][0] * m[1][1] * m[2][2]) * scale;
+}
+#endif
+
+
+void
+ghid_unproject_to_z_plane (int ex, int ey, int vz, int *vx, int *vy)
+{
+  float mat[2][2];
+  float inv_mat[2][2];
+  float x, y;
+
+  /*
+    ex = view_matrix[0][0] * vx +
+         view_matrix[0][1] * vy +
+         view_matrix[0][2] * vz +
+         view_matrix[0][3] * 1;
+    ey = view_matrix[1][0] * vx +
+         view_matrix[1][1] * vy +
+         view_matrix[1][2] * vz +
+         view_matrix[1][3] * 1;
+    UNKNOWN ez = view_matrix[2][0] * vx +
+                 view_matrix[2][1] * vy +
+                 view_matrix[2][2] * vz +
+                 view_matrix[2][3] * 1;
+
+    ex - view_matrix[0][3] * 1
+       - view_matrix[0][2] * vz
+      = view_matrix[0][0] * vx +
+        view_matrix[0][1] * vy;
+
+    ey - view_matrix[1][3] * 1
+       - view_matrix[1][2] * vz
+      = view_matrix[1][0] * vx +
+        view_matrix[1][1] * vy;
+  */
+
+  /* NB: last_modelview_matrix is transposed in memory! */
+  x = (float)ex - last_modelview_matrix[3][0] * 1
+                - last_modelview_matrix[2][0] * vz;
+
+  y = (float)ey - last_modelview_matrix[3][1] * 1
+                - last_modelview_matrix[2][1] * vz;
+
+  /*
+    x = view_matrix[0][0] * vx +
+        view_matrix[0][1] * vy;
+
+    y = view_matrix[1][0] * vx +
+        view_matrix[1][1] * vy;
+
+    [view_matrix[0][0] view_matrix[0][1]] [vx] = [x]
+    [view_matrix[1][0] view_matrix[1][1]] [vy]   [y]
+  */
+
+  mat[0][0] = last_modelview_matrix[0][0];
+  mat[0][1] = last_modelview_matrix[1][0];
+  mat[1][0] = last_modelview_matrix[0][1];
+  mat[1][1] = last_modelview_matrix[1][1];
+
+//    if (determinant_2x2 (mat) < 0.00001)
+//      printf ("Determinant is quite small\n");
+
+  invert_2x2 (mat, inv_mat);
+
+  *vx = (int)(inv_mat[0][0] * x + inv_mat[0][1] * y);
+  *vy = (int)(inv_mat[1][0] * x + inv_mat[1][1] * y);
+}
+
+
 gboolean
 ghid_note_event_location (GdkEventButton * ev)
 {
@@ -246,6 +420,11 @@ ghid_note_event_location (GdkEventButton * ev)
       event_x = ev->x;
       event_y = ev->y;
     }
+
+  /* Unproject event_x and event_y to world coordinates of the plane we are on */
+  ghid_unproject_to_z_plane (event_x, event_y, 0,
+                             &event_x, &event_y);
+
   gport->view_x = event_x * gport->zoom + gport->view_x0;
   gport->view_y = event_y * gport->zoom + gport->view_y0;
 
@@ -782,6 +961,37 @@ ghid_screen_update (void)
 
 void DrawAttached (Boolean);
 
+void
+ghid_view_2d (void *ball, gboolean view_2d, gpointer userdata)
+{
+  global_view_2d = view_2d;
+  ghid_invalidate_all ();
+}
+
+void
+ghid_port_rotate (void *ball, float *quarternion, gpointer userdata)
+{
+#ifdef DEBUG_ROTATE
+  int row, column;
+#endif
+
+  build_rotmatrix (view_matrix, quarternion);
+
+#ifdef DEBUG_ROTATE
+  for (row = 0; row < 4; row++) {
+    printf ("[ %f", view_matrix[row][0]);
+    for (column = 1; column < 4; column++) {
+      printf (",\t%f", view_matrix[row][column]);
+    }
+    printf ("\t]\n");
+  }
+  printf ("\n");
+#endif
+
+  ghid_invalidate_all ();
+}
+
+
 #define Z_NEAR 3.0
 gboolean
 ghid_port_drawing_area_expose_event_cb (GtkWidget * widget,
@@ -792,6 +1002,11 @@ ghid_port_drawing_area_expose_event_cb (GtkWidget * widget,
   extern HID ghid_hid;
   GdkGLContext* pGlContext = gtk_widget_get_gl_context (widget);
   GdkGLDrawable* pGlDrawable = gtk_widget_get_gl_drawable (widget);
+  int min_x, min_y;
+  int max_x, max_y;
+  int new_x, new_y;
+  int min_depth;
+  int max_depth;
 
   /* make GL-context "current" */
   if (!gdk_gl_drawable_gl_begin (pGlDrawable, pGlContext)) {
@@ -826,10 +1041,14 @@ ghid_port_drawing_area_expose_event_cb (GtkWidget * widget,
 
   glMatrixMode (GL_PROJECTION);
   glLoadIdentity ();
-  glOrtho (0, widget->allocation.width, widget->allocation.height, 0, 0, 100);
+  glOrtho (0, widget->allocation.width, widget->allocation.height, 0, -100000, 100000);
   glMatrixMode (GL_MODELVIEW);
   glLoadIdentity ();
-  glTranslatef (0.0f, 0.0f, -Z_NEAR);
+
+  glTranslatef (widget->allocation.width / 2., widget->allocation.height / 2., 0);
+  glMultMatrixf ((GLfloat *)view_matrix);
+  glTranslatef (-widget->allocation.width / 2., -widget->allocation.height / 2., 0);
+  glGetFloatv (GL_MODELVIEW_MATRIX, (GLfloat *)last_modelview_matrix);
 
   glEnable (GL_STENCIL_TEST);
   glClearColor (gport->offlimits_color.red / 65535.,
@@ -846,10 +1065,66 @@ ghid_port_drawing_area_expose_event_cb (GtkWidget * widget,
   glDisable (GL_STENCIL_TEST);
   glStencilFunc (GL_ALWAYS, 0, 0);
 
-  region.X1 = MIN (Px (ev->area.x), Px (ev->area.x + ev->area.width + 1));
-  region.X2 = MAX (Px (ev->area.x), Px (ev->area.x + ev->area.width + 1));
-  region.Y1 = MIN (Py (ev->area.y), Py (ev->area.y + ev->area.height + 1));
-  region.Y2 = MAX (Py (ev->area.y), Py (ev->area.y + ev->area.height + 1));
+  /* Test the 8 corners of a cube spanning the event */
+  min_depth = -50; /* FIXME */
+  max_depth =  0;  /* FIXME */
+
+  ghid_unproject_to_z_plane (ev->area.x,
+                             ev->area.y,
+                             min_depth, &new_x, &new_y);
+  max_x = min_x = new_x;
+  max_y = min_y = new_y;
+
+  ghid_unproject_to_z_plane (ev->area.x,
+                             ev->area.y,
+                             max_depth, &new_x, &new_y);
+  min_x = MIN (min_x, new_x);  max_x = MAX (max_x, new_x);
+  min_y = MIN (min_y, new_y);  max_y = MAX (max_y, new_y);
+
+  /* */
+  ghid_unproject_to_z_plane (ev->area.x + ev->area.width,
+                             ev->area.y,
+                             min_depth, &new_x, &new_y);
+  min_x = MIN (min_x, new_x);  max_x = MAX (max_x, new_x);
+  min_y = MIN (min_y, new_y);  max_y = MAX (max_y, new_y);
+
+  ghid_unproject_to_z_plane (ev->area.x + ev->area.width, ev->area.y,
+                             max_depth, &new_x, &new_y);
+  min_x = MIN (min_x, new_x);  max_x = MAX (max_x, new_x);
+  min_y = MIN (min_y, new_y);  max_y = MAX (max_y, new_y);
+
+  /* */
+  ghid_unproject_to_z_plane (ev->area.x + ev->area.width,
+                             ev->area.y + ev->area.height,
+                             min_depth, &new_x, &new_y);
+  min_x = MIN (min_x, new_x);  max_x = MAX (max_x, new_x);
+  min_y = MIN (min_y, new_y);  max_y = MAX (max_y, new_y);
+
+  ghid_unproject_to_z_plane (ev->area.x + ev->area.width,
+                             ev->area.y + ev->area.height,
+                             max_depth, &new_x, &new_y);
+  min_x = MIN (min_x, new_x);  max_x = MAX (max_x, new_x);
+  min_y = MIN (min_y, new_y);  max_y = MAX (max_y, new_y);
+
+  /* */
+  ghid_unproject_to_z_plane (ev->area.x,
+                             ev->area.y + ev->area.height,
+                             min_depth,
+                             &new_x, &new_y);
+  min_x = MIN (min_x, new_x);  max_x = MAX (max_x, new_x);
+  min_y = MIN (min_y, new_y);  max_y = MAX (max_y, new_y);
+
+  ghid_unproject_to_z_plane (ev->area.x,
+                             ev->area.y + ev->area.height,
+                             max_depth,
+                             &new_x, &new_y);
+  min_x = MIN (min_x, new_x);  max_x = MAX (max_x, new_x);
+  min_y = MIN (min_y, new_y);  max_y = MAX (max_y, new_y);
+
+  region.X1 = MIN (Px (min_x), Px (max_x + 1));
+  region.X2 = MAX (Px (min_x), Px (max_x + 1));
+  region.Y1 = MIN (Py (min_y), Py (max_y + 1));
+  region.Y2 = MAX (Py (min_y), Py (max_y + 1));
 
   eleft = Vx (0);  eright  = Vx (PCB->MaxWidth);
   etop  = Vy (0);  ebottom = Vy (PCB->MaxHeight);
@@ -859,10 +1134,10 @@ ghid_port_drawing_area_expose_event_cb (GtkWidget * widget,
              gport->bg_color.blue / 65535.);
 
   glBegin (GL_QUADS);
-  glVertex3i (eleft,  etop,    0);
-  glVertex3i (eright, etop,    0);
-  glVertex3i (eright, ebottom, 0);
-  glVertex3i (eleft,  ebottom, 0);
+  glVertex3i (eleft,  etop,    -50);
+  glVertex3i (eright, etop,    -50);
+  glVertex3i (eright, ebottom, -50);
+  glVertex3i (eleft,  ebottom, -50);
   glEnd ();
 
   /* TODO: Background image */
@@ -884,7 +1159,9 @@ ghid_port_drawing_area_expose_event_cb (GtkWidget * widget,
                              -gport->view_x0,
                 ghid_flip_y ? gport->view_y0 - PCB->MaxHeight :
                              -gport->view_y0, 0);
+
   hid_expose_callback (&ghid_hid, &region, 0);
+
   hidgl_flush_triangles (&buffer);
   glPopMatrix ();
 
@@ -908,6 +1185,7 @@ ghid_port_drawing_area_expose_event_cb (GtkWidget * widget,
 
   hidgl_flush_triangles (&buffer);
 
+
   if (gdk_gl_drawable_is_double_buffered (pGlDrawable))
     gdk_gl_drawable_swap_buffers (pGlDrawable);
   else
diff --git a/src/hid/gtk/gui-pinout-preview.c b/src/hid/gtk/gui-pinout-preview.c
index 8a4a11c..89a3563 100644
--- a/src/hid/gtk/gui-pinout-preview.c
+++ b/src/hid/gtk/gui-pinout-preview.c
@@ -208,7 +208,7 @@ ghid_pinout_preview_expose (GtkWidget * widget, GdkEventExpose * ev)
 
   glMatrixMode (GL_PROJECTION);
   glLoadIdentity ();
-  glOrtho (0, widget->allocation.width, widget->allocation.height, 0, 0, 100);
+  glOrtho (0, widget->allocation.width, widget->allocation.height, 0, -100000, 100000);
   glMatrixMode (GL_MODELVIEW);
   glLoadIdentity ();
   glTranslatef (0.0f, 0.0f, -Z_NEAR);
diff --git a/src/hid/gtk/gui-render-pixmap.c b/src/hid/gtk/gui-render-pixmap.c
index faa09fe..15412ea 100644
--- a/src/hid/gtk/gui-render-pixmap.c
+++ b/src/hid/gtk/gui-render-pixmap.c
@@ -105,7 +105,7 @@ ghid_render_pixmap (int cx, int cy, double zoom, int width, int height, int dept
 
   glMatrixMode (GL_PROJECTION);
   glLoadIdentity ();
-  glOrtho (0, width, height, 0, 0, 100);
+  glOrtho (0, width, height, 0, -100000, 100000);
   glMatrixMode (GL_MODELVIEW);
   glLoadIdentity ();
   glTranslatef (0.0f, 0.0f, -Z_NEAR);
diff --git a/src/hid/gtk/gui-top-window.c b/src/hid/gtk/gui-top-window.c
index 70f82a3..038ba6c 100644
--- a/src/hid/gtk/gui-top-window.c
+++ b/src/hid/gtk/gui-top-window.c
@@ -122,6 +122,7 @@ a zoom in/out.
 
 #include "gui-icons-mode-buttons.data"
 #include "gui-icons-misc.data"
+#include "gui-trackball.h"
 
 #ifdef HAVE_LIBDMALLOC
 #include <dmalloc.h>
@@ -2156,6 +2157,7 @@ ghid_build_pcb_top_window (void)
   GtkWidget *vbox_main, *vbox_left, *hbox_middle, *hbox = NULL;
   GtkWidget *viewport, *ebox, *vbox, *frame;
   GtkWidget *label;
+  GtkWidget *trackball;
   GHidPort *port = &ghid_port;
   gchar *s;
   GtkWidget *scrolled;
@@ -2264,6 +2266,13 @@ ghid_build_pcb_top_window (void)
       GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
   make_layer_buttons(vbox, port);
 
+  trackball = ghid_trackball_new ();
+  g_signal_connect (trackball, "rotation-changed",
+                    G_CALLBACK (ghid_port_rotate), NULL);
+  g_signal_connect (trackball, "view-2d-changed",
+                    G_CALLBACK (ghid_view_2d), NULL);
+  gtk_box_pack_start (GTK_BOX (vbox_left), trackball, FALSE, FALSE, 0);
+
   vbox = gtk_vbox_new(FALSE, 0);
   gtk_box_pack_start(GTK_BOX(vbox_left), vbox, FALSE, FALSE, 0);
   ghidgui->mode_buttons0_frame_vbox = vbox;
diff --git a/src/hid/gtk/gui.h b/src/hid/gtk/gui.h
index 4dd32a3..dad9dea 100644
--- a/src/hid/gtk/gui.h
+++ b/src/hid/gtk/gui.h
@@ -326,6 +326,8 @@ gint ghid_port_window_motion_cb (GtkWidget * widget,
 gint ghid_port_window_mouse_scroll_cb (GtkWidget * widget,
 				       GdkEventScroll * ev, GHidPort * out);
 
+void ghid_port_rotate (void *ball, float *quarternion, gpointer userdata);
+void ghid_view_2d (void *ball, gboolean view_2d, gpointer userdata);
 
 gint ghid_port_drawing_area_expose_event_cb (GtkWidget * widget,
 					     GdkEventExpose * ev,

commit b846ecafd19c062bc9e85a8d425c024d49fe32cc
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    Add virtual trackball code

diff --git a/po/POTFILES.in b/po/POTFILES.in
index 9ef4db5..8db0918 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -32,6 +32,7 @@ src/hid/gtk/gui-misc.c
 src/hid/gtk/gui-netlist-window.c
 src/hid/gtk/gui-top-window.c
 src/hid/ps/ps.c
+src/hid/gtk/gui-trackball.c
 src/main.c
 src/misc.c
 src/move.c
diff --git a/src/Makefile.am b/src/Makefile.am
index f66cca7..f21c807 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -165,7 +165,10 @@ LIBGTK_GL_SRCS= \
 
 GL_SRCS= \
 	hid/common/hidgl.c \
-	hid/common/hidgl.h
+	hid/common/hidgl.h \
+	hid/common/trackball.c \
+	hid/common/trackball.h
+
 
 BUILT_SOURCES = \
 	core_lists.h \
@@ -275,6 +278,8 @@ LIBGTK_SRCS = \
 	hid/gtk/gui-pinout-window.c \
 	hid/gtk/gui-render-pixmap.c \
 	hid/gtk/gui-top-window.c \
+	hid/gtk/gui-trackball.c \
+	hid/gtk/gui-trackball.h \
 	hid/gtk/gui-utils.c
 libgtk_a_SOURCES = ${LIBGTK_SRCS} hid/gtk/gtk_lists.h
 
diff --git a/src/hid/common/trackball.c b/src/hid/common/trackball.c
new file mode 100644
index 0000000..c4b8501
--- /dev/null
+++ b/src/hid/common/trackball.c
@@ -0,0 +1,324 @@
+/*
+ * (c) Copyright 1993, 1994, Silicon Graphics, Inc.
+ * ALL RIGHTS RESERVED
+ * Permission to use, copy, modify, and distribute this software for
+ * any purpose and without fee is hereby granted, provided that the above
+ * copyright notice appear in all copies and that both the copyright notice
+ * and this permission notice appear in supporting documentation, and that
+ * the name of Silicon Graphics, Inc. not be used in advertising
+ * or publicity pertaining to distribution of the software without specific,
+ * written prior permission.
+ *
+ * THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS"
+ * AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR
+ * FITNESS FOR A PARTICULAR PURPOSE.  IN NO EVENT SHALL SILICON
+ * GRAPHICS, INC.  BE LIABLE TO YOU OR ANYONE ELSE FOR ANY DIRECT,
+ * SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY
+ * KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING WITHOUT LIMITATION,
+ * LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, OR THE CLAIMS OF
+ * THIRD PARTIES, WHETHER OR NOT SILICON GRAPHICS, INC.  HAS BEEN
+ * ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, ARISING OUT OF OR IN PAD_CONNECTION WITH THE
+ * POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * US Government Users Restricted Rights
+ * Use, duplication, or disclosure by the Government is subject to
+ * restrictions set forth in FAR 52.227.19(c)(2) or subparagraph
+ * (c)(1)(ii) of the Rights in Technical Data and Computer Software
+ * clause at DFARS 252.227-7013 and/or in similar or successor
+ * clauses in the FAR or the DOD or NASA FAR Supplement.
+ * Unpublished-- rights reserved under the copyright laws of the
+ * United States.  Contractor/manufacturer is Silicon Graphics,
+ * Inc., 2011 N.  Shoreline Blvd., Mountain View, CA 94039-7311.
+ *
+ * OpenGL(TM) is a trademark of Silicon Graphics, Inc.
+ */
+/*
+ * Trackball code:
+ *
+ * Implementation of a virtual trackball.
+ * Implemented by Gavin Bell, lots of ideas from Thant Tessman and
+ *   the August '88 issue of Siggraph's "Computer Graphics," pp. 121-129.
+ *
+ * Vector manip code:
+ *
+ * Original code from:
+ * David M. Ciemiewicz, Mark Grossman, Henry Moreton, and Paul Haeberli
+ *
+ * Much mucking with by:
+ * Gavin Bell
+ */
+#include <math.h>
+#include "trackball.h"
+
+/*
+ * This size should really be based on the distance from the center of
+ * rotation to the point on the object underneath the mouse.  That
+ * point would then track the mouse as closely as possible.  This is a
+ * simple example, though, so that is left as an Exercise for the
+ * Programmer.
+ */
+#define TRACKBALLSIZE  (0.8f)
+
+/*
+ * Local function prototypes (not defined in trackball.h)
+ */
+static float tb_project_to_sphere(float, float, float);
+static void normalize_quat(float [4]);
+
+void
+vzero(float *v)
+{
+    v[0] = 0.0;
+    v[1] = 0.0;
+    v[2] = 0.0;
+}
+
+void
+vset(float *v, float x, float y, float z)
+{
+    v[0] = x;
+    v[1] = y;
+    v[2] = z;
+}
+
+void
+vsub(const float *src1, const float *src2, float *dst)
+{
+    dst[0] = src1[0] - src2[0];
+    dst[1] = src1[1] - src2[1];
+    dst[2] = src1[2] - src2[2];
+}
+
+void
+vcopy(const float *v1, float *v2)
+{
+    register int i;
+    for (i = 0 ; i < 3 ; i++)
+        v2[i] = v1[i];
+}
+
+void
+vcross(const float *v1, const float *v2, float *cross)
+{
+    float temp[3];
+
+    temp[0] = (v1[1] * v2[2]) - (v1[2] * v2[1]);
+    temp[1] = (v1[2] * v2[0]) - (v1[0] * v2[2]);
+    temp[2] = (v1[0] * v2[1]) - (v1[1] * v2[0]);
+    vcopy(temp, cross);
+}
+
+float
+vlength(const float *v)
+{
+    return (float) sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
+}
+
+void
+vscale(float *v, float div)
+{
+    v[0] *= div;
+    v[1] *= div;
+    v[2] *= div;
+}
+
+void
+vnormal(float *v)
+{
+    vscale(v, 1.0f/vlength(v));
+}
+
+float
+vdot(const float *v1, const float *v2)
+{
+    return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2];
+}
+
+void
+vadd(const float *src1, const float *src2, float *dst)
+{
+    dst[0] = src1[0] + src2[0];
+    dst[1] = src1[1] + src2[1];
+    dst[2] = src1[2] + src2[2];
+}
+
+/*
+ * Ok, simulate a track-ball.  Project the points onto the virtual
+ * trackball, then figure out the axis of rotation, which is the cross
+ * product of P1 P2 and O P1 (O is the center of the ball, 0,0,0)
+ * Note:  This is a deformed trackball-- is a trackball in the center,
+ * but is deformed into a hyperbolic sheet of rotation away from the
+ * center.  This particular function was chosen after trying out
+ * several variations.
+ *
+ * It is assumed that the arguments to this routine are in the range
+ * (-1.0 ... 1.0)
+ */
+void
+trackball(float q[4], float p1x, float p1y, float p2x, float p2y)
+{
+    float a[3]; /* Axis of rotation */
+    float phi;  /* how much to rotate about axis */
+    float p1[3], p2[3], d[3];
+    float t;
+
+    if (p1x == p2x && p1y == p2y) {
+        /* Zero rotation */
+        vzero(q);
+        q[3] = 1.0;
+        return;
+    }
+
+    /*
+     * First, figure out z-coordinates for projection of P1 and P2 to
+     * deformed sphere
+     */
+    vset(p1, p1x, p1y, tb_project_to_sphere(TRACKBALLSIZE, p1x, p1y));
+    vset(p2, p2x, p2y, tb_project_to_sphere(TRACKBALLSIZE, p2x, p2y));
+
+    /*
+     *  Now, we want the cross product of P1 and P2
+     */
+    vcross(p2,p1,a);
+
+    /*
+     *  Figure out how much to rotate around that axis.
+     */
+    vsub(p1, p2, d);
+    t = vlength(d) / (2.0f*TRACKBALLSIZE);
+
+    /*
+     * Avoid problems with out-of-control values...
+     */
+    if (t > 1.0) t = 1.0;
+    if (t < -1.0) t = -1.0;
+    phi = 2.0f * (float) asin(t);
+
+    axis_to_quat(a,phi,q);
+}
+
+/*
+ *  Given an axis and angle, compute quaternion.
+ */
+void
+axis_to_quat(float a[3], float phi, float q[4])
+{
+    vnormal(a);
+    vcopy(a, q);
+    vscale(q, (float) sin(phi/2.0));
+    q[3] = (float) cos(phi/2.0);
+}
+
+/*
+ * Project an x,y pair onto a sphere of radius r OR a hyperbolic sheet
+ * if we are away from the center of the sphere.
+ */
+static float
+tb_project_to_sphere(float r, float x, float y)
+{
+    float d, t, z;
+
+    d = (float) sqrt(x*x + y*y);
+    if (d < r * 0.70710678118654752440) {    /* Inside sphere */
+        z = (float) sqrt(r*r - d*d);
+    } else {           /* On hyperbola */
+        t = r / 1.41421356237309504880f;
+        z = t*t / d;
+    }
+    return z;
+}
+
+/*
+ * Given two rotations, e1 and e2, expressed as quaternion rotations,
+ * figure out the equivalent single rotation and stuff it into dest.
+ *
+ * This routine also normalizes the result every RENORMCOUNT times it is
+ * called, to keep error from creeping in.
+ *
+ * NOTE: This routine is written so that q1 or q2 may be the same
+ * as dest (or each other).
+ */
+
+#define RENORMCOUNT 97
+
+void
+add_quats(float q1[4], float q2[4], float dest[4])
+{
+    static int count=0;
+    float t1[4], t2[4], t3[4];
+    float tf[4];
+
+    vcopy(q1,t1);
+    vscale(t1,q2[3]);
+
+    vcopy(q2,t2);
+    vscale(t2,q1[3]);
+
+    vcross(q2,q1,t3);
+    vadd(t1,t2,tf);
+    vadd(t3,tf,tf);
+    tf[3] = q1[3] * q2[3] - vdot(q1,q2);
+
+    dest[0] = tf[0];
+    dest[1] = tf[1];
+    dest[2] = tf[2];
+    dest[3] = tf[3];
+
+    if (++count > RENORMCOUNT) {
+        count = 0;
+        normalize_quat(dest);
+    }
+}
+
+/*
+ * Quaternions always obey:  a^2 + b^2 + c^2 + d^2 = 1.0
+ * If they don't add up to 1.0, dividing by their magnitued will
+ * renormalize them.
+ *
+ * Note: See the following for more information on quaternions:
+ *
+ * - Shoemake, K., Animating rotation with quaternion curves, Computer
+ *   Graphics 19, No 3 (Proc. SIGGRAPH'85), 245-254, 1985.
+ * - Pletinckx, D., Quaternion calculus as a basic tool in computer
+ *   graphics, The Visual Computer 5, 2-13, 1989.
+ */
+static void
+normalize_quat(float q[4])
+{
+    int i;
+    float mag;
+
+    mag = (q[0]*q[0] + q[1]*q[1] + q[2]*q[2] + q[3]*q[3]);
+    for (i = 0; i < 4; i++) q[i] /= mag;
+}
+
+/*
+ * Build a rotation matrix, given a quaternion rotation.
+ *
+ */
+void
+build_rotmatrix(float m[4][4], float q[4])
+{
+    m[0][0] = 1.0f - 2.0f * (q[1] * q[1] + q[2] * q[2]);
+    m[0][1] = 2.0f * (q[0] * q[1] - q[2] * q[3]);
+    m[0][2] = 2.0f * (q[2] * q[0] + q[1] * q[3]);
+    m[0][3] = 0.0f;
+
+    m[1][0] = 2.0f * (q[0] * q[1] + q[2] * q[3]);
+    m[1][1]= 1.0f - 2.0f * (q[2] * q[2] + q[0] * q[0]);
+    m[1][2] = 2.0f * (q[1] * q[2] - q[0] * q[3]);
+    m[1][3] = 0.0f;
+
+    m[2][0] = 2.0f * (q[2] * q[0] - q[1] * q[3]);
+    m[2][1] = 2.0f * (q[1] * q[2] + q[0] * q[3]);
+    m[2][2] = 1.0f - 2.0f * (q[1] * q[1] + q[0] * q[0]);
+    m[2][3] = 0.0f;
+
+    m[3][0] = 0.0f;
+    m[3][1] = 0.0f;
+    m[3][2] = 0.0f;
+    m[3][3] = 1.0f;
+}
+
diff --git a/src/hid/common/trackball.h b/src/hid/common/trackball.h
new file mode 100644
index 0000000..ed0c267
--- /dev/null
+++ b/src/hid/common/trackball.h
@@ -0,0 +1,78 @@
+/*
+ * (c) Copyright 1993, 1994, Silicon Graphics, Inc.
+ * ALL RIGHTS RESERVED
+ * Permission to use, copy, modify, and distribute this software for
+ * any purpose and without fee is hereby granted, provided that the above
+ * copyright notice appear in all copies and that both the copyright notice
+ * and this permission notice appear in supporting documentation, and that
+ * the name of Silicon Graphics, Inc. not be used in advertising
+ * or publicity pertaining to distribution of the software without specific,
+ * written prior permission.
+ *
+ * THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS"
+ * AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR
+ * FITNESS FOR A PARTICULAR PURPOSE.  IN NO EVENT SHALL SILICON
+ * GRAPHICS, INC.  BE LIABLE TO YOU OR ANYONE ELSE FOR ANY DIRECT,
+ * SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY
+ * KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING WITHOUT LIMITATION,
+ * LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, OR THE CLAIMS OF
+ * THIRD PARTIES, WHETHER OR NOT SILICON GRAPHICS, INC.  HAS BEEN
+ * ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, ARISING OUT OF OR IN PAD_CONNECTION WITH THE
+ * POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * US Government Users Restricted Rights
+ * Use, duplication, or disclosure by the Government is subject to
+ * restrictions set forth in FAR 52.227.19(c)(2) or subparagraph
+ * (c)(1)(ii) of the Rights in Technical Data and Computer Software
+ * clause at DFARS 252.227-7013 and/or in similar or successor
+ * clauses in the FAR or the DOD or NASA FAR Supplement.
+ * Unpublished-- rights reserved under the copyright laws of the
+ * United States.  Contractor/manufacturer is Silicon Graphics,
+ * Inc., 2011 N.  Shoreline Blvd., Mountain View, CA 94039-7311.
+ *
+ * OpenGL(TM) is a trademark of Silicon Graphics, Inc.
+ */
+/*
+ * trackball.h
+ * A virtual trackball implementation
+ * Written by Gavin Bell for Silicon Graphics, November 1988.
+ */
+
+/*
+ * Pass the x and y coordinates of the last and current positions of
+ * the mouse, scaled so they are from (-1.0 ... 1.0).
+ *
+ * The resulting rotation is returned as a quaternion rotation in the
+ * first paramater.
+ */
+void
+trackball(float q[4], float p1x, float p1y, float p2x, float p2y);
+
+/*
+ * Given two quaternions, add them together to get a third quaternion.
+ * Adding quaternions to get a compound rotation is analagous to adding
+ * translations to get a compound translation.  When incrementally
+ * adding rotations, the first argument here should be the new
+ * rotation, the second and third the total rotation (which will be
+ * over-written with the resulting new total rotation).
+ */
+void
+add_quats(float *q1, float *q2, float *dest);
+
+/*
+ * A useful function, builds a rotation matrix in Matrix based on
+ * given quaternion.
+ */
+void
+build_rotmatrix(float m[4][4], float q[4]);
+
+/*
+ * This function computes a quaternion based on an axis (defined by
+ * the given vector) and an angle about which to rotate.  The angle is
+ * expressed in radians.  The result is put into the third argument.
+ */
+void
+axis_to_quat(float a[3], float phi, float q[4]);
+
diff --git a/src/hid/gtk/gui-trackball.c b/src/hid/gtk/gui-trackball.c
new file mode 100644
index 0000000..26440bb
--- /dev/null
+++ b/src/hid/gtk/gui-trackball.c
@@ -0,0 +1,391 @@
+/* $Id$ */
+
+/*
+ *                            COPYRIGHT
+ *
+ *  PCB, interactive printed circuit board design
+ *  Copyright (C) 2009 PCB Contributors (See ChangeLog for details)
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *  Contact addresses for paper mail and Email:
+ *  Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
+ *  Thomas.Nau@xxxxxxxxxxxxx
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "global.h"
+
+#include "gui.h"
+
+#include "copy.h"
+#include "data.h"
+#include "draw.h"
+#include "mymem.h"
+#include "move.h"
+#include "rotate.h"
+#include "hid/common/trackball.h"
+#include "gui-trackball.h"
+
+#ifdef HAVE_LIBDMALLOC
+#include <dmalloc.h>
+#endif
+
+RCSID ("$Id$");
+
+enum {
+  ROTATION_CHANGED,
+  VIEW_2D_CHANGED,
+  LAST_SIGNAL
+};
+
+
+static guint ghid_trackball_signals[ LAST_SIGNAL ] = { 0 };
+static GObjectClass *ghid_trackball_parent_class = NULL;
+
+
+static gboolean
+button_press_cb (GtkWidget *widget, GdkEventButton *ev, gpointer userdata)
+{
+  GhidTrackball *ball = GHID_TRACKBALL (userdata);
+  float axis[3];
+
+  ball->x1 = 2. * ev->x / widget->allocation.width - 1.;
+  ball->y1 = 2. * ev->y / widget->allocation.height - 1.;
+
+  ball->dragging = TRUE;
+
+  /* If we were in 2D view before, reset the rotation of the trackball */
+  if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (ball->view_2d)))
+    {
+      axis[0] = 1.; axis[1] = 0.; axis[2] = 0.;
+      axis_to_quat (axis, 0, ball->quart1);
+      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ball->view_2d), FALSE);
+    }
+
+  return TRUE;
+}
+
+
+static gboolean
+button_release_cb (GtkWidget *widget, GdkEventButton *ev, gpointer userdata)
+{
+  GhidTrackball *ball = GHID_TRACKBALL (userdata);
+
+  ball->quart1[0] = ball->quart2[0];
+  ball->quart1[1] = ball->quart2[1];
+  ball->quart1[2] = ball->quart2[2];
+  ball->quart1[3] = ball->quart2[3];
+
+  ball->dragging = FALSE;
+
+  return TRUE;
+}
+
+
+static gboolean
+motion_notify_cb (GtkWidget *widget, GdkEventMotion *ev, gpointer userdata)
+{
+  GhidTrackball *ball = GHID_TRACKBALL (userdata);
+  double x1, y1;
+  double x2, y2;
+  float q[4];
+
+  if (!ball->dragging)
+    return TRUE;
+
+  x1 = ball->x1;
+  y1 = ball->y1;
+
+  x2 = 2. * ev->x / widget->allocation.width - 1.;
+  y2 = 2. * ev->y / widget->allocation.height - 1.;
+
+  /* Trackball computation */
+  trackball (q, x1, y1, x2, y2);
+  add_quats (q, ball->quart1, ball->quart2);
+
+  g_signal_emit (ball, ghid_trackball_signals[ROTATION_CHANGED], 0,
+                 ball->quart2);
+
+  return TRUE;
+}
+
+static gboolean
+ghid_trackball_expose (GtkWidget * widget, GdkEventExpose * ev)
+{
+  gdk_draw_arc (widget->window,
+                widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
+                TRUE,
+                0, 0, widget->allocation.width, widget->allocation.height,
+                0, 64 * 360);
+  return TRUE;
+}
+
+static gboolean
+view_2d_toggled_cb (GtkToggleButton *toggle, gpointer userdata)
+{
+  GhidTrackball *ball = GHID_TRACKBALL (userdata);
+  float axis[3];
+  float quart[4];
+  gboolean view_2d;
+
+  view_2d = gtk_toggle_button_get_active (toggle);
+  if (view_2d)
+    {
+      axis[0] = 1.; axis[1] = 0.; axis[2] = 0.;
+      axis_to_quat (axis, 0, quart);
+
+      g_signal_emit (ball, ghid_trackball_signals[ROTATION_CHANGED], 0, quart);
+    }
+  else
+    g_signal_emit (ball, ghid_trackball_signals[ROTATION_CHANGED], 0, ball->quart1);
+
+  g_signal_emit (ball, ghid_trackball_signals[VIEW_2D_CHANGED], 0, view_2d);
+
+  return TRUE;
+}
+/*! \brief GObject constructor
+ *
+ *  \par Function Description
+ *  Chain up and construct the object, then setup the
+ *  necessary state for our widget now it is constructed.
+ *
+ *  \param [in] type                    The GType of object to be constructed
+ *  \param [in] n_construct_properties  Number of construct properties
+ *  \param [in] contruct_params         The construct properties
+ *
+ *  \returns The GObject having just been constructed.
+ */
+static GObject *
+ghid_trackball_constructor (GType type,
+                            guint n_construct_properties,
+                            GObjectConstructParam *construct_properties)
+{
+  GhidTrackball *ball;
+  float axis[3];
+
+  /* chain up to constructor of parent class */
+  ball = GHID_TRACKBALL (G_OBJECT_CLASS (ghid_trackball_parent_class)->
+    constructor (type, n_construct_properties, construct_properties));
+
+  gtk_widget_set_size_request (GTK_WIDGET (ball), 120, 120);
+
+  ball->view_2d = gtk_toggle_button_new_with_label (_("2D View"));
+  gtk_box_pack_start (GTK_BOX (ball), ball->view_2d, FALSE, FALSE, 0);
+  gtk_widget_show (ball->view_2d);
+  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ball->view_2d), TRUE);
+
+  ball->drawing_area = gtk_drawing_area_new ();
+  gtk_box_pack_start (GTK_BOX (ball), ball->drawing_area, TRUE, TRUE, 0);
+  gtk_widget_show (ball->drawing_area);
+
+  axis[0] = 1.; axis[1] = 0.; axis[2] = 0.;
+  axis_to_quat (axis, 0, ball->quart1);
+  axis_to_quat (axis, 0, ball->quart2);
+
+  g_signal_connect (ball->view_2d, "toggled",
+                    G_CALLBACK (view_2d_toggled_cb), ball);
+
+  g_signal_connect (ball->drawing_area, "expose-event",
+                    G_CALLBACK (ghid_trackball_expose), ball);
+  g_signal_connect (ball->drawing_area, "button-press-event",
+                    G_CALLBACK (button_press_cb), ball);
+  g_signal_connect (ball->drawing_area, "button-release-event",
+                    G_CALLBACK (button_release_cb), ball);
+  g_signal_connect (ball->drawing_area, "motion-notify-event",
+                    G_CALLBACK (motion_notify_cb), ball);
+
+  gtk_widget_add_events (ball->drawing_area, GDK_BUTTON_PRESS_MASK   |
+                                             GDK_BUTTON_RELEASE_MASK |
+                                             GDK_POINTER_MOTION_MASK);
+
+  return G_OBJECT (ball);
+}
+
+
+
+/*! \brief GObject finalise handler
+ *
+ *  \par Function Description
+ *  Just before the GhidTrackball GObject is finalized, free our
+ *  allocated data, and then chain up to the parent's finalize handler.
+ *
+ *  \param [in] widget  The GObject being finalized.
+ */
+static void
+ghid_trackball_finalize (GObject * object)
+{
+//  GhidTrackball *pinout = GHID_TRACKBALL (object);
+
+  G_OBJECT_CLASS (ghid_trackball_parent_class)->finalize (object);
+}
+
+
+/*! \brief GObject property setter function
+ *
+ *  \par Function Description
+ *  Setter function for GhidTrackball's GObject properties,
+ *  "settings-name" and "toplevel".
+ *
+ *  \param [in]  object       The GObject whose properties we are setting
+ *  \param [in]  property_id  The numeric id. under which the property was
+ *                            registered with g_object_class_install_property()
+ *  \param [in]  value        The GValue the property is being set from
+ *  \param [in]  pspec        A GParamSpec describing the property being set
+ */
+static void
+ghid_trackball_set_property (GObject * object, guint property_id,
+				  const GValue * value, GParamSpec * pspec)
+{
+//  GhidTrackball *pinout = GHID_TRACKBALL (object);
+
+  switch (property_id)
+    {
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+    }
+}
+
+
+/*! \brief GObject property getter function
+ *
+ *  \par Function Description
+ *  Getter function for GhidTrackball's GObject properties,
+ *  "settings-name" and "toplevel".
+ *
+ *  \param [in]  object       The GObject whose properties we are getting
+ *  \param [in]  property_id  The numeric id. under which the property was
+ *                            registered with g_object_class_install_property()
+ *  \param [out] value        The GValue in which to return the value of the property
+ *  \param [in]  pspec        A GParamSpec describing the property being got
+ */
+static void
+ghid_trackball_get_property (GObject * object, guint property_id,
+				  GValue * value, GParamSpec * pspec)
+{
+  switch (property_id)
+    {
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+    }
+
+}
+
+
+/*! \brief GType class initialiser for GhidTrackball
+ *
+ *  \par Function Description
+ *  GType class initialiser for GhidTrackball. We override our parent
+ *  virtual class methods as needed and register our GObject properties.
+ *
+ *  \param [in]  klass       The GhidTrackballClass we are initialising
+ */
+static void
+ghid_trackball_class_init (GhidTrackballClass * klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+  gobject_class->constructor  = ghid_trackball_constructor;
+  gobject_class->finalize     = ghid_trackball_finalize;
+  gobject_class->set_property = ghid_trackball_set_property;
+  gobject_class->get_property = ghid_trackball_get_property;
+
+  ghid_trackball_parent_class = g_type_class_peek_parent (klass);
+
+  ghid_trackball_signals[ROTATION_CHANGED] =
+    g_signal_new ("rotation-changed",
+                  G_OBJECT_CLASS_TYPE( gobject_class ),
+                  G_SIGNAL_RUN_FIRST,     /*signal_flags */
+                  G_STRUCT_OFFSET( GhidTrackballClass, rotation_changed ),
+                  NULL, /* accumulator */
+                  NULL, /* accu_data */
+                  g_cclosure_marshal_VOID__POINTER,
+                  G_TYPE_NONE,
+                  1,    /* n_params */
+                  G_TYPE_POINTER
+                 );
+
+  ghid_trackball_signals[VIEW_2D_CHANGED] =
+    g_signal_new ("view-2d-changed",
+                  G_OBJECT_CLASS_TYPE( gobject_class ),
+                  G_SIGNAL_RUN_FIRST,     /*signal_flags */
+                  G_STRUCT_OFFSET( GhidTrackballClass, view_2d_changed ),
+                  NULL, /* accumulator */
+                  NULL, /* accu_data */
+                  g_cclosure_marshal_VOID__BOOLEAN,
+                  G_TYPE_NONE,
+                  1,    /* n_params */
+                  G_TYPE_BOOLEAN
+                 );
+}
+
+
+/*! \brief Function to retrieve GhidTrackball's GType identifier.
+ *
+ *  \par Function Description
+ *  Function to retrieve GhidTrackball's GType identifier.
+ *  Upon first call, this registers the GhidTrackball in the GType system.
+ *  Subsequently it returns the saved value from its first execution.
+ *
+ *  \return the GType identifier associated with GhidTrackball.
+ */
+GType
+ghid_trackball_get_type ()
+{
+  static GType ghid_trackball_type = 0;
+
+  if (!ghid_trackball_type)
+    {
+      static const GTypeInfo ghid_trackball_info = {
+	sizeof (GhidTrackballClass),
+	NULL,			/* base_init */
+	NULL,			/* base_finalize */
+	(GClassInitFunc) ghid_trackball_class_init,
+	NULL,			/* class_finalize */
+	NULL,			/* class_data */
+	sizeof (GhidTrackball),
+	0,			/* n_preallocs */
+	NULL,			/* instance_init */
+      };
+
+      ghid_trackball_type =
+	g_type_register_static (GTK_TYPE_VBOX, "GhidTrackball",
+				&ghid_trackball_info, 0);
+    }
+
+  return ghid_trackball_type;
+}
+
+
+/*! \brief Convenience function to create a new pinout preview
+ *
+ *  \par Function Description
+ *  Convenience function which creates a GhidTrackball.
+ *
+ *  \return  The GhidTrackball created.
+ */
+GtkWidget *
+ghid_trackball_new (void)
+{
+  GhidTrackball *ball;
+
+  ball = g_object_new (GHID_TYPE_TRACKBALL, NULL);
+
+  return GTK_WIDGET (ball);
+}
diff --git a/src/hid/gtk/gui-trackball.h b/src/hid/gtk/gui-trackball.h
new file mode 100644
index 0000000..d6bd03c
--- /dev/null
+++ b/src/hid/gtk/gui-trackball.h
@@ -0,0 +1,70 @@
+/* $Id$ */
+
+/*
+ *                            COPYRIGHT
+ *
+ *  PCB, interactive printed circuit board design
+ *  Copyright (C) 2009  PCB Contributors (see ChangeLog for details)
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *  Contact addresses for paper mail and Email:
+ *  Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
+ *  Thomas.Nau@xxxxxxxxxxxxx
+ *
+ */
+
+#ifndef __GHID_TRACKBALL_H__
+#define __GHID_TRACKBALL_H__
+
+
+#define GHID_TYPE_TRACKBALL           (ghid_trackball_get_type())
+#define GHID_TRACKBALL(obj)           (G_TYPE_CHECK_INSTANCE_CAST ((obj), GHID_TYPE_TRACKBALL, GhidTrackball))
+#define GHID_TRACKBALL_CLASS(klass)   (G_TYPE_CHECK_CLASS_CAST ((klass),  GHID_TYPE_TRACKBALL, GhidTrackballClass))
+#define GHID_IS_TRACKBALL(obj)        (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GHID_TYPE_TRACKBALL))
+#define GHID_TRACKBALL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),  GHID_TYPE_TRACKBALL, GhidTrackballClass))
+
+typedef struct _GhidTrackballClass GhidTrackballClass;
+typedef struct _GhidTrackball GhidTrackball;
+
+
+struct _GhidTrackballClass
+{
+  GtkVBoxClass parent_class;
+
+  void (*rotation_changed) (GhidTrackball *ball, gpointer rotation, gpointer user_data);
+  void (*view_2d_changed) (GhidTrackball *ball, gboolean view_2d, gpointer user_data);
+};
+
+struct _GhidTrackball
+{
+  GtkVBox parent_instance;
+
+  GtkWidget *drawing_area;
+  GtkWidget *view_2d;
+
+  gboolean dragging;
+  gdouble x1, y1;
+
+  float quart1[4];
+  float quart2[4];
+};
+
+
+GType ghid_trackball_get_type (void);
+
+GtkWidget *ghid_trackball_new (void);
+
+#endif /* __GHID_TRACKBALL_H__ */

commit 0296d3e1d08407747605103f0b99dcbeb168a331
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    Hack to make pretty translucent polygons in thindraw-poly mode
    
    TODO: Perhaps need some way to configure this.. it might be nice in
    non-thindraw mode too. If people want thin-draw to gain extra speed,
    rather than have it actually slower (due to fill + outline), then a
    way to turn it off would also be useful.

diff --git a/src/hid/gtk/gtkhid-gl.c b/src/hid/gtk/gtkhid-gl.c
index fec839e..6b1e306 100644
--- a/src/hid/gtk/gtkhid-gl.c
+++ b/src/hid/gtk/gtkhid-gl.c
@@ -311,25 +311,30 @@ typedef struct
   double blue;
 } ColorCache;
 
+static char *current_color = NULL;
+static double global_alpha_mult = 1.0;
+static int alpha_changed = 0;
+
 void
 ghid_set_color (hidGC gc, const char *name)
 {
   static void *cache = NULL;
-  static char *old_name = NULL;
   hidval cval;
   ColorCache *cc;
   double alpha_mult = 1.0;
   double r, g, b, a;
   a = 1.0;
 
-  if (old_name != NULL)
+  if (!alpha_changed && current_color != NULL)
     {
-      if (strcmp (name, old_name) == 0)
+      if (strcmp (name, current_color) == 0)
         return;
-      free (old_name);
+      free (current_color);
     }
 
-  old_name = strdup (name);
+  alpha_changed = 0;
+
+  current_color = strdup (name);
 
   if (name == NULL)
     {
@@ -403,6 +408,7 @@ ghid_set_color (hidGC gc, const char *name)
     }
   if (1) {
     double maxi, mult;
+    alpha_mult *= global_alpha_mult;
     if (gport->trans_lines)
       a = a * alpha_mult;
     maxi = r;
@@ -424,6 +430,16 @@ ghid_set_color (hidGC gc, const char *name)
 }
 
 void
+ghid_global_alpha_mult (hidGC gc, double alpha_mult)
+{
+  if (alpha_mult != global_alpha_mult) {
+    global_alpha_mult = alpha_mult;
+    alpha_changed = 1;
+    ghid_set_color (gc, current_color);
+  }
+}
+
+void
 ghid_set_line_cap (hidGC gc, EndCapStyle style)
 {
   gc->cap = style;
@@ -535,6 +551,15 @@ ghid_fill_pcb_polygon (hidGC gc, PolygonType *poly, const BoxType *clip_box)
 }
 
 void
+ghid_thindraw_pcb_polygon (hidGC gc, PolygonType *poly, const BoxType *clip_box)
+{
+  common_thindraw_pcb_polygon (gc, poly, clip_box);
+  ghid_global_alpha_mult (gc, 0.25);
+  ghid_fill_pcb_polygon (gc, poly, clip_box);
+  ghid_global_alpha_mult (gc, 1.0);
+}
+
+void
 ghid_fill_rect (hidGC gc, int x1, int y1, int x2, int y2)
 {
   USE_GC (gc);
diff --git a/src/hid/gtk/gtkhid-main.c b/src/hid/gtk/gtkhid-main.c
index 668da46..e2bc158 100644
--- a/src/hid/gtk/gtkhid-main.c
+++ b/src/hid/gtk/gtkhid-main.c
@@ -1134,7 +1134,7 @@ HID ghid_hid = {
   ghid_fill_circle,
   ghid_fill_polygon,
   ghid_fill_pcb_polygon,
-  common_thindraw_pcb_polygon,
+  ghid_thindraw_pcb_polygon,
   ghid_fill_rect,
 
   ghid_calibrate,
diff --git a/src/hid/gtk/gui.h b/src/hid/gtk/gui.h
index 4342f3f..4dd32a3 100644
--- a/src/hid/gtk/gui.h
+++ b/src/hid/gtk/gui.h
@@ -532,6 +532,8 @@ void ghid_fill_circle (hidGC gc, int cx, int cy, int radius);
 void ghid_fill_polygon (hidGC gc, int n_coords, int *x, int *y);
 void ghid_fill_pcb_polygon (hidGC gc, PolygonType *poly,
                             const BoxType *clip_box); /* GL ONLY */
+void ghid_thindraw_pcb_polygon (hidGC gc, PolygonType *poly,
+                                const BoxType *clip_box); /* GL ONLY */
 void ghid_fill_rect (hidGC gc, int x1, int y1, int x2, int y2);
 
 /* gtkhid-main.c */

commit 0366b21ab674253f0567013bfe618429f028e3df
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    Use tags on circular contours to render them faster

diff --git a/src/hid/common/hidgl.c b/src/hid/common/hidgl.c
index c2efdd4..faf27c7 100644
--- a/src/hid/common/hidgl.c
+++ b/src/hid/common/hidgl.c
@@ -605,6 +605,7 @@ void tesselate_contour (GLUtesselator *tobj, VNODE *vnode, GLdouble *vertices)
 struct do_hole_info {
   GLUtesselator *tobj;
   GLdouble *vertices;
+  double scale;
 };
 
 static int
@@ -617,6 +618,19 @@ do_hole (const BoxType *b, void *cl)
   if (curc->Flags.orient == PLF_DIR) {
     return 0;
   }
+
+  /* If the contour is round, and hidgl_fill_circle would use
+   * less slices than we have vertices to draw it, then call
+   * hidgl_fill_circle to draw this contour.
+   */
+  if (curc->is_round) {
+    double slices = calc_slices (curc->radius / info->scale, 2 * M_PI);
+    if (slices < curc->Count) {
+      hidgl_fill_circle (curc->cx, curc->cy, curc->radius, info->scale);
+      return 1;
+    }
+  }
+
   tesselate_contour (info->tobj, &curc->head, info->vertices);
   return 1;
 }
@@ -634,6 +648,7 @@ hidgl_fill_pcb_polygon (PolygonType *poly, const BoxType *clip_box, double scale
   struct do_hole_info info;
   int stencil_bit;
 
+  info.scale = scale;
   global_scale = scale;
 
   if (poly->Clipped == NULL)

commit fd1833e21b0b93851dce69218160d2d22a0cc97e
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    Work in progress on subcompositing / stencil buffers
    
    If we have many stencil buffer bits, we may as well use all of them before
    resorting to a costly clear and re-using the same bit-planes over.

diff --git a/src/draw.c b/src/draw.c
index 1bbbaa1..c713965 100644
--- a/src/draw.c
+++ b/src/draw.c
@@ -420,6 +420,7 @@ DrawEverything (BoxTypePtr drawn_area)
 		    backN_callback, NULL);
 	  DrawLayer (&(PCB->Data->BACKSILKLAYER), drawn_area);
 	}
+      gui->set_layer (NULL, SL (FINISHED, 0), 0);
     }
 
   /* draw all layers in layerstack order */
@@ -458,6 +459,7 @@ DrawEverything (BoxTypePtr drawn_area)
 			    &plated);
 		}
 	    }
+	  gui->set_layer (NULL, SL (FINISHED, 0), 0);
 	}
     }
   if (TEST_FLAG (CHECKPLANESFLAG, PCB) && gui->gui)
@@ -498,6 +500,7 @@ DrawEverything (BoxTypePtr drawn_area)
       SWAP_IDENT = 0;
       DrawMask (drawn_area);
       SWAP_IDENT = save_swap;
+      gui->set_layer (NULL, SL (FINISHED, 0), 0);
     }
   if (gui->set_layer ("soldermask", SL (MASK, BOTTOM), 0))
     {
@@ -505,12 +508,21 @@ DrawEverything (BoxTypePtr drawn_area)
       SWAP_IDENT = 1;
       DrawMask (drawn_area);
       SWAP_IDENT = save_swap;
+      gui->set_layer (NULL, SL (FINISHED, 0), 0);
     }
   /* Draw top silkscreen */
   if (gui->set_layer ("topsilk", SL (SILK, TOP), 0))
-    DrawSilk (0, COMPONENT_LAYER, drawn_area);
+    {
+      DrawSilk (0, COMPONENT_LAYER, drawn_area);
+      gui->set_layer (NULL, SL (FINISHED, 0), 0);
+    }
+
   if (gui->set_layer ("bottomsilk", SL (SILK, BOTTOM), 0))
-    DrawSilk (1, SOLDER_LAYER, drawn_area);
+    {
+      DrawSilk (1, SOLDER_LAYER, drawn_area);
+      gui->set_layer (NULL, SL (FINISHED, 0), 0);
+    }
+
   if (gui->gui)
     {
       /* Draw element Marks */
@@ -553,19 +565,30 @@ DrawEverything (BoxTypePtr drawn_area)
 		DrawPadLowLevel (Output.fgGC, pad, false, false);
 	  }
 	  ENDALL_LOOP;
+	  gui->set_layer (NULL, SL (FINISHED, 0), 0);
 	}
     }
 
   doing_assy = true;
   if (gui->set_layer ("topassembly", SL (ASSY, TOP), 0))
-    PrintAssembly (drawn_area, component, 0);
+    {
+      PrintAssembly (drawn_area, component, 0);
+      gui->set_layer (NULL, SL (FINISHED, 0), 0);
+    }
 
   if (gui->set_layer ("bottomassembly", SL (ASSY, BOTTOM), 0))
-    PrintAssembly (drawn_area, solder, 1);
+    {
+      PrintAssembly (drawn_area, solder, 1);
+      gui->set_layer (NULL, SL (FINISHED, 0), 0);
+    }
+
   doing_assy = false;
 
   if (gui->set_layer ("fab", SL (FAB, 0), 0))
-    PrintFab ();
+    {
+      PrintFab ();
+      gui->set_layer (NULL, SL (FINISHED, 0), 0);
+    }
 }
 
 static void
@@ -873,7 +896,8 @@ DrawLayerGroup (int group, const BoxType * screen)
   Cardinal *layers = PCB->LayerGroups.Entries[group];
 
   clip_box = screen;
-  for (i = n_entries - 1; i >= 0; i--)
+  for (i = n_entries - 1; i >= 0;
+      i--, gui->set_layer (0, group, 0)) /* HACK: Subcomposite each layer in a layer group separately */
     {
       layernum = layers[i];
       Layer = PCB->Data->Layer + layers[i];
@@ -890,6 +914,10 @@ DrawLayerGroup (int group, const BoxType * screen)
 	      r_search (Layer->polygon_tree, screen, NULL, poly_callback,
 			&info);
 	      info.arg = false;
+
+	      /* HACK: Subcomposite polygons separately from other layer primitives */
+	      /* Reset the compositing */
+	      gui->set_layer (0, group, 0);
 	    }
 
 	  if (TEST_FLAG (CHECKPLANESFLAG, PCB))
diff --git a/src/hid.h b/src/hid.h
index dd34b8e..073dbae 100644
--- a/src/hid.h
+++ b/src/hid.h
@@ -205,6 +205,7 @@ extern "C"
 #define SL_FAB		0x0070
 #define SL_ASSY		0x0080
 #define SL_RATS		0x0090
+#define SL_FINISHED	0x00A0
 /* Callers should use this.  */
 #define SL(type,side) (~0xfff | SL_##type | SL_##side##_SIDE)
 
diff --git a/src/hid/common/hidgl.c b/src/hid/common/hidgl.c
index 4594c63..c2efdd4 100644
--- a/src/hid/common/hidgl.c
+++ b/src/hid/common/hidgl.c
@@ -584,28 +584,27 @@ hidgl_fill_polygon (int n_coords, int *x, int *y)
   free (vertices);
 }
 
-void tesselate_contour (GLUtesselator *tobj, VNODE *vnode,
-                        GLdouble *vertices, int *i)
+void tesselate_contour (GLUtesselator *tobj, VNODE *vnode, GLdouble *vertices)
 {
   VNODE *vn = vnode;
-  int offset = *i * 3;
+  int offset = 0;
 
+  gluTessBeginPolygon (tobj, NULL);
   gluTessBeginContour (tobj);
   do {
     vertices [0 + offset] = vn->point[0];
     vertices [1 + offset] = vn->point[1];
     vertices [2 + offset] = 0.;
     gluTessVertex (tobj, &vertices [offset], &vertices [offset]);
-    (*i)++;
     offset += 3;
   } while ((vn = vn->next) != vnode);
   gluTessEndContour (tobj);
+  gluTessEndPolygon (tobj);
 }
 
 struct do_hole_info {
   GLUtesselator *tobj;
   GLdouble *vertices;
-  int *i;
 };
 
 static int
@@ -618,74 +617,89 @@ do_hole (const BoxType *b, void *cl)
   if (curc->Flags.orient == PLF_DIR) {
     return 0;
   }
-  gluTessBeginPolygon (info->tobj, NULL);
-  tesselate_contour (info->tobj, &curc->head, info->vertices, info->i);
-  gluTessEndPolygon (info->tobj);
+  tesselate_contour (info->tobj, &curc->head, info->vertices);
   return 1;
 }
 
+static GLint stencil_bits;
+static int dirty_bits = 0;
+static int assigned_bits = 0;
+
+/* FIXME: JUST DRAWS THE FIRST PIECE.. TODO: SUPPORT FOR FULLPOLY POLYGONS */
 void
 hidgl_fill_pcb_polygon (PolygonType *poly, const BoxType *clip_box, double scale)
 {
-  int i, cc;
   int vertex_count = 0;
   PLINE *contour;
   struct do_hole_info info;
-
+  int stencil_bit;
 
   global_scale = scale;
 
-  if (poly->Clipped == NULL) {
-    fprintf (stderr, "hidgl_fill_pcb_polygon: poly->Clipped == NULL\n");
-    return;
-  }
+  if (poly->Clipped == NULL)
+    {
+      fprintf (stderr, "hidgl_fill_pcb_polygon: poly->Clipped == NULL\n");
+      return;
+    }
 
-  /* TODO: Just draw our triangles, no need to flush the buffer */
+  stencil_bit = hidgl_assign_clear_stencil_bit ();
+  if (!stencil_bit)
+    {
+      printf ("hidgl_fill_pcb_polygon: No free stencil bits, aborting polygon\n");
+      return;
+    }
+
+  /* Flush out any existing geoemtry to be rendered */
   hidgl_flush_triangles (&buffer);
 
-  /* JUST DRAW THE FIRST PIECE */
   /* Walk the polygon structure, counting vertices */
   /* This gives an upper bound on the amount of storage required */
   for (contour = poly->Clipped->contours;
        contour != NULL; contour = contour->next)
-    vertex_count += contour->Count;
+    vertex_count = MAX (vertex_count, contour->Count);
 
   info.vertices = malloc (sizeof(GLdouble) * vertex_count * 3);
   info.tobj = gluNewTess ();
-  info.i = &i;
   gluTessCallback(info.tobj, GLU_TESS_BEGIN, myBegin);
   gluTessCallback(info.tobj, GLU_TESS_VERTEX, myVertex);
   gluTessCallback(info.tobj, GLU_TESS_COMBINE, myCombine);
   gluTessCallback(info.tobj, GLU_TESS_ERROR, myError);
 
-  glClearStencil (0);
-  glClear (GL_STENCIL_BUFFER_BIT);
-  glColorMask (0, 0, 0, 0);                   // Disable writting in color buffer
-  glEnable (GL_STENCIL_TEST);
-
-  i = 0;
-  cc = 1;
+  glPushAttrib (GL_STENCIL_BUFFER_BIT);                   // Save the write mask etc.. for final restore
+  glPushAttrib (GL_STENCIL_BUFFER_BIT |                   // Resave the stencil write-mask etc.., and
+                GL_COLOR_BUFFER_BIT);                     // the colour buffer write mask etc.. for part way restore
+  glStencilMask (stencil_bit);                            // Only write to our stencil bit
+  glStencilFunc (GL_ALWAYS, stencil_bit, stencil_bit);    // Always pass stencil test, ref value is our bit
+  glColorMask (0, 0, 0, 0);                               // Disable writting in color buffer
 
-  /* Drawing operations set the stencil buffer to '1' */
-  glStencilFunc (GL_ALWAYS, 1, 1);            // Test always passes, value written 1
-  glStencilOp (GL_KEEP, GL_KEEP, GL_REPLACE); // Stencil pass => replace stencil value (with 1)
+  /* It will already be setup like this (so avoid prodding the state-machine):
+   * glStencilOp (GL_KEEP, GL_KEEP, GL_REPLACE); // Stencil pass => replace stencil value
+   */
+  /* Drawing operations now set our reference bit in the stencil buffer */
 
   r_search (poly->Clipped->contour_tree, clip_box, NULL, do_hole, &info);
   hidgl_flush_triangles (&buffer);
 
-  /* Drawing operations as masked to areas where the stencil buffer is '1' */
-  glColorMask (1, 1, 1, 1);                   // Enable drawing of r, g, b & a
-  glStencilFunc (GL_EQUAL, 0, 1);             // Draw only where stencil buffer is 0
-  glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP);    // Stencil buffer read only
+  /* Drawing operations as masked to areas where the stencil buffer is '0' */
+
+  glPopAttrib ();                                             // Restore the colour and stencil buffer write-mask etc..
+
+  glStencilOp (GL_KEEP, GL_KEEP, GL_INVERT); // This allows us to toggle the bit on the subcompositing bitplane
+                                             // If the stencil test has passed, we know that bit is 0, so we're
+                                             // effectively just setting it to 1.
+  glStencilFunc (GL_GEQUAL, 0, assigned_bits);
+//  glStencilFunc (GL_GREATER, assigned_bits, assigned_bits);   // Pass stencil test if all assigned bits clear,
+                                                              // reference is all assigned bits so we set
+                                                              // any bits permitted by the stencil writemask
 
   /* Draw the polygon outer */
-  gluTessBeginPolygon (info.tobj, NULL);
-  tesselate_contour (info.tobj, &poly->Clipped->contours->head, info.vertices, &i);
-  gluTessEndPolygon (info.tobj);
+  tesselate_contour (info.tobj, &poly->Clipped->contours->head, info.vertices);
   hidgl_flush_triangles (&buffer);
 
-  glClear (GL_STENCIL_BUFFER_BIT);
-  glDisable (GL_STENCIL_TEST);                // Disable Stencil test
+  /* Unassign our stencil buffer bit */
+  hidgl_return_stencil_bit (stencil_bit);
+
+  glPopAttrib ();                                             // Restore the stencil buffer write-mask etc..
 
   gluDeleteTess (info.tobj);
   myFreeCombined ();
@@ -700,6 +714,92 @@ hidgl_fill_rect (int x1, int y1, int x2, int y2)
   hidgl_add_triangle (&buffer, x2, y1, x2, y2, x1, y1);
 }
 
+void
+hidgl_init (void)
+{
+  glGetIntegerv (GL_STENCIL_BITS, &stencil_bits);
+
+  if (stencil_bits == 0)
+    {
+      printf ("No stencil bits available.\n"
+              "Cannot mask polygon holes or subcomposite layers\n");
+      /* TODO: Flag this to the HID so it can revert to the dicer? */
+    }
+  else if (stencil_bits == 1)
+    {
+      printf ("Only one stencil bitplane avilable\n"
+              "Cannot use stencil buffer to sub-composite layers.\n");
+      /* Do we need to disable that somewhere? */
+    }
+}
+
+int
+hidgl_stencil_bits (void)
+{
+  return stencil_bits;
+}
+
+static void
+hidgl_clean_unassigned_stencil (void)
+{
+  glPushAttrib (GL_STENCIL_BUFFER_BIT);
+  glStencilMask (~assigned_bits);
+  glClearStencil (0);
+  glClear (GL_STENCIL_BUFFER_BIT);
+  glPopAttrib ();
+}
+
+int
+hidgl_assign_clear_stencil_bit (void)
+{
+  int stencil_bitmask = (1 << stencil_bits) - 1;
+  int test;
+  int first_dirty = 0;
+
+  if (assigned_bits == stencil_bitmask)
+    {
+      printf ("No more stencil bits available, total of %i already assigned\n",
+              stencil_bits);
+      return 0;
+    }
+
+  /* Look for a bitplane we don't have to clear */
+  for (test = 1; test & stencil_bitmask; test <<= 1)
+    {
+      if (!(test & dirty_bits))
+        {
+          assigned_bits |= test;
+          dirty_bits |= test;
+          return test;
+        }
+      else if (!first_dirty && !(test & assigned_bits))
+        {
+          first_dirty = test;
+        }
+    }
+
+  /* Didn't find any non dirty planes. Clear those dirty ones which aren't in use */
+  hidgl_clean_unassigned_stencil ();
+  assigned_bits |= first_dirty;
+  dirty_bits = assigned_bits;
+
+  return first_dirty;
+}
+
+void
+hidgl_return_stencil_bit (int bit)
+{
+  assigned_bits &= ~bit;
+}
+
+void
+hidgl_reset_stencil_usage (void)
+{
+  assigned_bits = 0;
+  dirty_bits = 0;
+}
+
+
 /* ---------------------------------------------------------------------- */
 
 #endif /* DISABLE EVERYTHING! */
diff --git a/src/hid/common/hidgl.h b/src/hid/common/hidgl.h
index bb1383c..b956a65 100644
--- a/src/hid/common/hidgl.h
+++ b/src/hid/common/hidgl.h
@@ -60,5 +60,10 @@ void hidgl_fill_polygon (int n_coords, int *x, int *y);
 void hidgl_fill_pcb_polygon (PolygonType *poly, const BoxType *clip_box, double scale);
 void hidgl_fill_rect (int x1, int y1, int x2, int y2);
 
+void hidgl_init (void);
+int hidgl_stencil_bits (void);
+int hidgl_assign_clear_stencil_bit (void);
+void hidgl_return_stencil_bit (int bit);
+void hidgl_reset_stencil_usage (void);
 
 #endif /* __HIDGL_INCLUDED__  */
diff --git a/src/hid/gerber/gerber.c b/src/hid/gerber/gerber.c
index fa908ce..8a46c3c 100644
--- a/src/hid/gerber/gerber.c
+++ b/src/hid/gerber/gerber.c
@@ -455,6 +455,9 @@ gerber_set_layer (const char *name, int group, int empty)
 	     && group <
 	     max_layer) ? PCB->LayerGroups.Entries[group][0] : group;
 
+  if (SL_TYPE (idx) == SL_FINISHED)
+    return 0;
+
   if (name == 0)
     name = PCB->Data->Layer[idx].Name;
 
diff --git a/src/hid/gtk/gtkhid-gl.c b/src/hid/gtk/gtkhid-gl.c
index 430059b..fec839e 100644
--- a/src/hid/gtk/gtkhid-gl.c
+++ b/src/hid/gtk/gtkhid-gl.c
@@ -215,6 +215,7 @@ ghid_draw_bg_image (void)
 void
 ghid_use_mask (int use_it)
 {
+  static int stencil_bit = 0;
 
   /* THE FOLLOWING IS COMPLETE ABUSE OF THIS MASK RENDERING API... NOT IMPLEMENTED */
   if (use_it == HID_LIVE_DRAWING ||
@@ -226,6 +227,7 @@ ghid_use_mask (int use_it)
   if (use_it == cur_mask)
     return;
 
+  /* Flush out any existing geoemtry to be rendered */
   hidgl_flush_triangles (&buffer);
 
   switch (use_it)
@@ -234,25 +236,28 @@ ghid_use_mask (int use_it)
       /* Write '1' to the stencil buffer where the solder-mask is drawn. */
       glColorMask (0, 0, 0, 0);                   // Disable writting in color buffer
       glEnable (GL_STENCIL_TEST);                 // Enable Stencil test
-      glStencilFunc (GL_ALWAYS, 1, 1);            // Test always passes, value written 1
+      stencil_bit = hidgl_assign_clear_stencil_bit();       // Get a new (clean) bitplane to stencil with
+      glStencilFunc (GL_ALWAYS, stencil_bit, stencil_bit);  // Always pass stencil test, write stencil_bit
+      glStencilMask (stencil_bit);                          // Only write to our subcompositing stencil bitplane
       glStencilOp (GL_KEEP, GL_KEEP, GL_REPLACE); // Stencil pass => replace stencil value (with 1)
       break;
 
     case HID_MASK_CLEAR:
       /* Drawing operations clear the stencil buffer to '0' */
-      glStencilFunc (GL_ALWAYS, 0, 1);            // Test always passes, value written 0
+      glStencilFunc (GL_ALWAYS, 0, stencil_bit);  // Always pass stencil test, write 0
       glStencilOp (GL_KEEP, GL_KEEP, GL_REPLACE); // Stencil pass => replace stencil value (with 0)
       break;
 
     case HID_MASK_AFTER:
       /* Drawing operations as masked to areas where the stencil buffer is '1' */
       glColorMask (1, 1, 1, 1);                   // Enable drawing of r, g, b & a
-      glStencilFunc (GL_EQUAL, 1, 1);             // Draw only where stencil buffer is 1
+      glStencilFunc (GL_LEQUAL, stencil_bit, stencil_bit);   // Draw only where our bit of the stencil buffer is set
       glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP);    // Stencil buffer read only
       break;
 
     case HID_MASK_OFF:
       /* Disable stenciling */
+      hidgl_return_stencil_bit (stencil_bit);               // Relinquish any bitplane we previously used
       glDisable (GL_STENCIL_TEST);                // Disable Stencil test
       break;
     }
diff --git a/src/hid/gtk/gtkhid-main.c b/src/hid/gtk/gtkhid-main.c
index aae34fc..668da46 100644
--- a/src/hid/gtk/gtkhid-main.c
+++ b/src/hid/gtk/gtkhid-main.c
@@ -333,14 +333,39 @@ ghid_invalidate_all ()
   gdk_window_invalidate_rect (gport->drawing_area->window, NULL, 1);
 }
 
-
 int
 ghid_set_layer (const char *name, int group, int empty)
 {
+  static int stencil_bit = 0;
   int idx = (group >= 0
 	     && group <
 	     max_layer) ? PCB->LayerGroups.Entries[group][0] : group;
 
+#define SUBCOMPOSITE_LAYERS
+#ifdef SUBCOMPOSITE_LAYERS
+  /* Flush out any existing geoemtry to be rendered */
+  hidgl_flush_triangles (&buffer);
+
+  glEnable (GL_STENCIL_TEST);                // Enable Stencil test
+  glStencilOp (GL_KEEP, GL_KEEP, GL_REPLACE); // Stencil pass => replace stencil value (with 1)
+  /* Reset stencil buffer so we can paint anywhere */
+  hidgl_return_stencil_bit (stencil_bit);               // Relinquish any bitplane we previously used
+  if (SL_TYPE (idx) != SL_FINISHED)
+    {
+      stencil_bit = hidgl_assign_clear_stencil_bit();       // Get a new (clean) bitplane to stencil with
+      glStencilFunc (GL_GREATER, stencil_bit, stencil_bit); // Pass stencil test if our assigned bit is clear
+      glStencilMask (stencil_bit);                          // Only write to our subcompositing stencil bitplane
+    }
+  else
+    {
+#endif
+      stencil_bit = 0;
+      glStencilMask (0);
+      glStencilFunc (GL_ALWAYS, 0, 0);  // Always pass stencil test
+#ifdef SUBCOMPOSITE_LAYERS
+    }
+#endif
+
   if (idx >= 0 && idx < max_layer + 2) {
     gport->trans_lines = TRUE;
     return /*pinout ? 1 : */ PCB->Data->Layer[idx].On;
@@ -356,8 +381,7 @@ ghid_set_layer (const char *name, int group, int empty)
 	    return TEST_FLAG (SHOWMASKFLAG, PCB);
 	  return 0;
 	case SL_SILK:
-//          gport->trans_lines = TRUE;
-          gport->trans_lines = FALSE;
+	  gport->trans_lines = TRUE;
 	  if (SL_MYSIDE (idx) /*|| pinout */ )
 	    return PCB->ElementOn;
 	  return 0;
diff --git a/src/hid/gtk/gui-output-events.c b/src/hid/gtk/gui-output-events.c
index 76de7af..db1fb31 100644
--- a/src/hid/gtk/gui-output-events.c
+++ b/src/hid/gtk/gui-output-events.c
@@ -35,6 +35,7 @@
 #include "gui.h"
 #include "gtkhid.h"
 #include "hid/common/hid_resource.h"
+#include "hid/common/draw_helpers.h"
 
 #include <gdk/gdkkeysyms.h>
 
@@ -797,6 +798,17 @@ ghid_port_drawing_area_expose_event_cb (GtkWidget * widget,
     return FALSE;
   }
 
+  hidgl_init ();
+
+  /* If we don't have any stencil bits available,
+     we can't use the hidgl polygon drawing routine */
+  /* TODO: We could use the GLU tessellator though */
+  if (hidgl_stencil_bits() == 0)
+    {
+      ghid_hid.fill_pcb_polygon = common_fill_pcb_polygon;
+      ghid_hid.poly_dicer = 1;
+    }
+
   ghid_show_crosshair (FALSE);
 
   glEnable (GL_BLEND);
@@ -819,12 +831,20 @@ ghid_port_drawing_area_expose_event_cb (GtkWidget * widget,
   glLoadIdentity ();
   glTranslatef (0.0f, 0.0f, -Z_NEAR);
 
+  glEnable (GL_STENCIL_TEST);
   glClearColor (gport->offlimits_color.red / 65535.,
                 gport->offlimits_color.green / 65535.,
                 gport->offlimits_color.blue / 65535.,
                 1.);
 
+  glStencilMask (~0);
+  glClearStencil (0);
   glClear (GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
+  hidgl_reset_stencil_usage ();
+
+  /* Disable the stencil test until we need it - otherwise it gets dirty */
+  glDisable (GL_STENCIL_TEST);
+  glStencilFunc (GL_ALWAYS, 0, 0);
 
   region.X1 = MIN (Px (ev->area.x), Px (ev->area.x + ev->area.width + 1));
   region.X2 = MAX (Px (ev->area.x), Px (ev->area.x + ev->area.width + 1));
@@ -850,6 +870,12 @@ ghid_port_drawing_area_expose_event_cb (GtkWidget * widget,
   hidgl_init_triangle_array (&buffer);
   ghid_invalidate_current_gc ();
 
+  /* Setup stenciling */
+  /* Drawing operations set the stencil buffer to '1' */
+  glStencilOp (GL_KEEP, GL_KEEP, GL_REPLACE); // Stencil pass => replace stencil value (with 1)
+  /* Drawing operations as masked to areas where the stencil buffer is '0' */
+//  glStencilFunc (GL_GREATER, 1, 1);             // Draw only where stencil buffer is 0
+
   glPushMatrix ();
   glScalef ((ghid_flip_x ? -1. : 1.) / gport->zoom,
             (ghid_flip_y ? -1. : 1.) / gport->zoom,
diff --git a/src/hid/gtk/gui-pinout-preview.c b/src/hid/gtk/gui-pinout-preview.c
index b9d57da..8a4a11c 100644
--- a/src/hid/gtk/gui-pinout-preview.c
+++ b/src/hid/gtk/gui-pinout-preview.c
@@ -217,9 +217,12 @@ ghid_pinout_preview_expose (GtkWidget * widget, GdkEventExpose * ev)
                 gport->bg_color.green / 65535.,
                 gport->bg_color.blue / 65535.,
                 1.);
-
+  glStencilMask (~0);
+  glClearStencil (0);
   glClear (GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
 
+  hidgl_reset_stencil_usage ();
+
   /* call the drawing routine */
   hidgl_init_triangle_array (&buffer);
   ghid_invalidate_current_gc ();
diff --git a/src/hid/gtk/gui-render-pixmap.c b/src/hid/gtk/gui-render-pixmap.c
index 4caddf2..faa09fe 100644
--- a/src/hid/gtk/gui-render-pixmap.c
+++ b/src/hid/gtk/gui-render-pixmap.c
@@ -116,6 +116,7 @@ ghid_render_pixmap (int cx, int cy, double zoom, int width, int height, int dept
                 1.);
   glClearStencil (0);
   glClear (GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
+  hidgl_reset_stencil_usage ();
 
   /* call the drawing routine */
   hidgl_init_triangle_array (&buffer);
diff --git a/src/hid/gtk/gui-top-window.c b/src/hid/gtk/gui-top-window.c
index 197e886..70f82a3 100644
--- a/src/hid/gtk/gui-top-window.c
+++ b/src/hid/gtk/gui-top-window.c
@@ -2683,6 +2683,7 @@ ghid_parse_arguments (int *argc, char ***argv)
   gport->zoom = 300.0;
   pixel_slop = 300;
 
+#ifdef ENABLE_GL
   /* setup GL-context */
   gport->glconfig = gdk_gl_config_new_by_mode (GDK_GL_MODE_RGBA    |
                                                GDK_GL_MODE_STENCIL |
@@ -2692,6 +2693,7 @@ ghid_parse_arguments (int *argc, char ***argv)
     printf("Could not setup GL-context!\n");
     return; /* Should we abort? */
   }
+#endif
 
   ghid_config_files_read (argc, argv);
 
diff --git a/src/hid/nelma/nelma.c b/src/hid/nelma/nelma.c
index 68d7d5b..688adce 100644
--- a/src/hid/nelma/nelma.c
+++ b/src/hid/nelma/nelma.c
@@ -704,6 +704,10 @@ nelma_set_layer(const char *name, int group, int empty)
 	int             idx = (group >= 0 && group < max_layer) ?
 	PCB->LayerGroups.Entries[group][0] : group;
 
+	if (SL_TYPE (idx) == SL_FINISHED) {
+		return 0;
+	}
+
 	if (name == 0) {
 		name = PCB->Data->Layer[idx].Name;
 	}
diff --git a/src/hid/png/png.c b/src/hid/png/png.c
index d5d6617..0c292cd 100644
--- a/src/hid/png/png.c
+++ b/src/hid/png/png.c
@@ -890,6 +890,10 @@ png_set_layer (const char *name, int group, int empty)
   int idx = (group >= 0
 	     && group <
 	     max_layer) ? PCB->LayerGroups.Entries[group][0] : group;
+
+  if (SL_TYPE (idx) == SL_FINISHED)
+    return 0;
+
   if (name == 0)
     name = PCB->Data->Layer[idx].Name;
 
diff --git a/src/hid/ps/eps.c b/src/hid/ps/eps.c
index 0c9345b..d67947d 100644
--- a/src/hid/ps/eps.c
+++ b/src/hid/ps/eps.c
@@ -313,6 +313,10 @@ eps_set_layer (const char *name, int group, int empty)
   int idx = (group >= 0
 	     && group <
 	     max_layer) ? PCB->LayerGroups.Entries[group][0] : group;
+
+  if (SL_TYPE (idx) == SL_FINISHED)
+    return 0;
+
   if (name == 0)
     name = PCB->Data->Layer[idx].Name;
 
diff --git a/src/hid/ps/ps.c b/src/hid/ps/ps.c
index 7b42b5f..2a7a4d7 100644
--- a/src/hid/ps/ps.c
+++ b/src/hid/ps/ps.c
@@ -636,6 +636,10 @@ ps_set_layer (const char *name, int group, int empty)
   int idx = (group >= 0
 	     && group <
 	     max_layer) ? PCB->LayerGroups.Entries[group][0] : group;
+
+  if (SL_TYPE (idx) == SL_FINISHED)
+    return 0;
+
   if (name == 0)
     name = PCB->Data->Layer[idx].Name;
 

commit efed4d20f64ddf37ad80e563ddb9710b2eef8535
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    Add raw polygons support for the GTK HID, bypassing the no-holes dicer
    
    Uses the OpenGL stencil buffer to make drawing polygons with holes faster.
    
    1. Turn Stenciling on, updates to colour buffer off
    2. Clear stencil buffer to 0
    3. Paint polygon holes, setting those areas of the stencil buffer to 1
    4. Switch on stencil test (== 0), turn on updates to colour buffer
    5. Paint outer polygon through areas of the stencil buffer still 0
    6. Clear stencil buffer, switch off stencilling.
    
    ** BUGS? **
    
    Probably throws up if the function is used whilst drawing the mask,
    since that uses stenciling as well, and they don't know to co-operate.
    
    For now, we don't use polygons on the mask, so its not a a problem (?).
    (OR do we.. for some pins?)

diff --git a/src/hid/common/hidgl.c b/src/hid/common/hidgl.c
index b0a5049..4594c63 100644
--- a/src/hid/common/hidgl.c
+++ b/src/hid/common/hidgl.c
@@ -36,6 +36,7 @@
 
 #include "hid.h"
 #include "hidgl.h"
+#include "rtree.h"
 
 
 #ifdef HAVE_LIBDMALLOC
@@ -478,6 +479,8 @@ myBegin (GLenum type)
   triangle_comp_idx = 0;
 }
 
+static double global_scale;
+
 static void
 myVertex (GLdouble *vertex_data)
 {
@@ -494,11 +497,23 @@ myVertex (GLdouble *vertex_data)
         }
       else
         {
+#if 1
           hidgl_ensure_triangle_space (&buffer, 1);
           hidgl_add_triangle (&buffer,
                               triangle_vertices [0], triangle_vertices [1],
                               triangle_vertices [2], triangle_vertices [3],
                               vertex_data [0], vertex_data [1]);
+#else
+          hidgl_draw_line (Square_Cap, global_scale,
+                           triangle_vertices [0], triangle_vertices [1],
+                           triangle_vertices [2], triangle_vertices [3], global_scale);
+          hidgl_draw_line (Square_Cap, global_scale,
+                           triangle_vertices [2], triangle_vertices [3],
+                           vertex_data [0],       vertex_data [1],       global_scale);
+          hidgl_draw_line (Square_Cap, global_scale,
+                           vertex_data [0],       vertex_data [1],
+                           triangle_vertices [0], triangle_vertices [1], global_scale);
+#endif
 
           if (tessVertexType == GL_TRIANGLE_STRIP)
             {
@@ -569,6 +584,114 @@ hidgl_fill_polygon (int n_coords, int *x, int *y)
   free (vertices);
 }
 
+void tesselate_contour (GLUtesselator *tobj, VNODE *vnode,
+                        GLdouble *vertices, int *i)
+{
+  VNODE *vn = vnode;
+  int offset = *i * 3;
+
+  gluTessBeginContour (tobj);
+  do {
+    vertices [0 + offset] = vn->point[0];
+    vertices [1 + offset] = vn->point[1];
+    vertices [2 + offset] = 0.;
+    gluTessVertex (tobj, &vertices [offset], &vertices [offset]);
+    (*i)++;
+    offset += 3;
+  } while ((vn = vn->next) != vnode);
+  gluTessEndContour (tobj);
+}
+
+struct do_hole_info {
+  GLUtesselator *tobj;
+  GLdouble *vertices;
+  int *i;
+};
+
+static int
+do_hole (const BoxType *b, void *cl)
+{
+  struct do_hole_info *info = cl;
+  PLINE *curc = (PLINE *) b;
+
+  /* Ignore the outer contour - we draw it first explicitly*/
+  if (curc->Flags.orient == PLF_DIR) {
+    return 0;
+  }
+  gluTessBeginPolygon (info->tobj, NULL);
+  tesselate_contour (info->tobj, &curc->head, info->vertices, info->i);
+  gluTessEndPolygon (info->tobj);
+  return 1;
+}
+
+void
+hidgl_fill_pcb_polygon (PolygonType *poly, const BoxType *clip_box, double scale)
+{
+  int i, cc;
+  int vertex_count = 0;
+  PLINE *contour;
+  struct do_hole_info info;
+
+
+  global_scale = scale;
+
+  if (poly->Clipped == NULL) {
+    fprintf (stderr, "hidgl_fill_pcb_polygon: poly->Clipped == NULL\n");
+    return;
+  }
+
+  /* TODO: Just draw our triangles, no need to flush the buffer */
+  hidgl_flush_triangles (&buffer);
+
+  /* JUST DRAW THE FIRST PIECE */
+  /* Walk the polygon structure, counting vertices */
+  /* This gives an upper bound on the amount of storage required */
+  for (contour = poly->Clipped->contours;
+       contour != NULL; contour = contour->next)
+    vertex_count += contour->Count;
+
+  info.vertices = malloc (sizeof(GLdouble) * vertex_count * 3);
+  info.tobj = gluNewTess ();
+  info.i = &i;
+  gluTessCallback(info.tobj, GLU_TESS_BEGIN, myBegin);
+  gluTessCallback(info.tobj, GLU_TESS_VERTEX, myVertex);
+  gluTessCallback(info.tobj, GLU_TESS_COMBINE, myCombine);
+  gluTessCallback(info.tobj, GLU_TESS_ERROR, myError);
+
+  glClearStencil (0);
+  glClear (GL_STENCIL_BUFFER_BIT);
+  glColorMask (0, 0, 0, 0);                   // Disable writting in color buffer
+  glEnable (GL_STENCIL_TEST);
+
+  i = 0;
+  cc = 1;
+
+  /* Drawing operations set the stencil buffer to '1' */
+  glStencilFunc (GL_ALWAYS, 1, 1);            // Test always passes, value written 1
+  glStencilOp (GL_KEEP, GL_KEEP, GL_REPLACE); // Stencil pass => replace stencil value (with 1)
+
+  r_search (poly->Clipped->contour_tree, clip_box, NULL, do_hole, &info);
+  hidgl_flush_triangles (&buffer);
+
+  /* Drawing operations as masked to areas where the stencil buffer is '1' */
+  glColorMask (1, 1, 1, 1);                   // Enable drawing of r, g, b & a
+  glStencilFunc (GL_EQUAL, 0, 1);             // Draw only where stencil buffer is 0
+  glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP);    // Stencil buffer read only
+
+  /* Draw the polygon outer */
+  gluTessBeginPolygon (info.tobj, NULL);
+  tesselate_contour (info.tobj, &poly->Clipped->contours->head, info.vertices, &i);
+  gluTessEndPolygon (info.tobj);
+  hidgl_flush_triangles (&buffer);
+
+  glClear (GL_STENCIL_BUFFER_BIT);
+  glDisable (GL_STENCIL_TEST);                // Disable Stencil test
+
+  gluDeleteTess (info.tobj);
+  myFreeCombined ();
+  free (info.vertices);
+}
+
 void
 hidgl_fill_rect (int x1, int y1, int x2, int y2)
 {
diff --git a/src/hid/common/hidgl.h b/src/hid/common/hidgl.h
index 73d9a34..bb1383c 100644
--- a/src/hid/common/hidgl.h
+++ b/src/hid/common/hidgl.h
@@ -57,6 +57,7 @@ void hidgl_draw_arc (double width, int vx, int vy, int vrx, int vry, int start_a
 void hidgl_draw_rect (int x1, int y1, int x2, int y2);
 void hidgl_fill_circle (int vx, int vy, int vr, double scale);
 void hidgl_fill_polygon (int n_coords, int *x, int *y);
+void hidgl_fill_pcb_polygon (PolygonType *poly, const BoxType *clip_box, double scale);
 void hidgl_fill_rect (int x1, int y1, int x2, int y2);
 
 
diff --git a/src/hid/gtk/gtkhid-gl.c b/src/hid/gtk/gtkhid-gl.c
index 3e41c35..430059b 100644
--- a/src/hid/gtk/gtkhid-gl.c
+++ b/src/hid/gtk/gtkhid-gl.c
@@ -522,6 +522,14 @@ ghid_fill_polygon (hidGC gc, int n_coords, int *x, int *y)
 }
 
 void
+ghid_fill_pcb_polygon (hidGC gc, PolygonType *poly, const BoxType *clip_box)
+{
+  USE_GC (gc);
+
+  hidgl_fill_pcb_polygon (poly, clip_box, gport->zoom);
+}
+
+void
 ghid_fill_rect (hidGC gc, int x1, int y1, int x2, int y2)
 {
   USE_GC (gc);
diff --git a/src/hid/gtk/gtkhid-main.c b/src/hid/gtk/gtkhid-main.c
index 31fa88a..aae34fc 100644
--- a/src/hid/gtk/gtkhid-main.c
+++ b/src/hid/gtk/gtkhid-main.c
@@ -1109,7 +1109,7 @@ HID ghid_hid = {
   ghid_draw_rect,
   ghid_fill_circle,
   ghid_fill_polygon,
-  common_fill_pcb_polygon,
+  ghid_fill_pcb_polygon,
   common_thindraw_pcb_polygon,
   ghid_fill_rect,
 
diff --git a/src/hid/gtk/gui.h b/src/hid/gtk/gui.h
index 2ebed06..4342f3f 100644
--- a/src/hid/gtk/gui.h
+++ b/src/hid/gtk/gui.h
@@ -530,6 +530,8 @@ void ghid_draw_arc (hidGC gc, int cx, int cy, int xradius, int yradius,
 void ghid_draw_rect (hidGC gc, int x1, int y1, int x2, int y2);
 void ghid_fill_circle (hidGC gc, int cx, int cy, int radius);
 void ghid_fill_polygon (hidGC gc, int n_coords, int *x, int *y);
+void ghid_fill_pcb_polygon (hidGC gc, PolygonType *poly,
+                            const BoxType *clip_box); /* GL ONLY */
 void ghid_fill_rect (hidGC gc, int x1, int y1, int x2, int y2);
 
 /* gtkhid-main.c */

commit 275346d1b0a54347bd52ec364982a133f161700e
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    Cure crosshair lagging on screen
    
    FIXME: SHOULD NOT RE-WRITE THE GTK HID

diff --git a/src/hid/gtk/gui-output-events.c b/src/hid/gtk/gui-output-events.c
index 4942fc0..76de7af 100644
--- a/src/hid/gtk/gui-output-events.c
+++ b/src/hid/gtk/gui-output-events.c
@@ -1022,6 +1022,7 @@ ghid_port_window_motion_cb (GtkWidget * widget,
   gdouble dx, dy;
   static gint x_prev = -1, y_prev = -1;
   gboolean moved;
+#if 0
   GdkGLContext* pGlContext = gtk_widget_get_gl_context (widget);
   GdkGLDrawable* pGlDrawable = gtk_widget_get_gl_drawable (widget);
 
@@ -1030,11 +1031,15 @@ ghid_port_window_motion_cb (GtkWidget * widget,
     printf ("GL THingy returned\n");
     return FALSE;
   }
+#endif
 
   if (out->panning)
     {
+/* Not sure this really matters, since we're using invalidate to get a redraw */
+#if 1
       if (gtk_events_pending ())
 	return FALSE;
+#endif
       dx = gport->zoom * (x_prev - ev->x);
       dy = gport->zoom * (y_prev - ev->y);
       if (x_prev > 0)
@@ -1050,10 +1055,11 @@ ghid_port_window_motion_cb (GtkWidget * widget,
   queue_tooltip_update (out);
 #endif
 
-  ghid_show_crosshair (TRUE);
-  if (moved && have_crosshair_attachments ())
+//  ghid_show_crosshair (TRUE);
+  if (moved) // && have_crosshair_attachments ())
     ghid_draw_area_update (gport, NULL);
 
+#if 0
   if (gdk_gl_drawable_is_double_buffered (pGlDrawable))
     gdk_gl_drawable_swap_buffers (pGlDrawable);
   else
@@ -1061,6 +1067,8 @@ ghid_port_window_motion_cb (GtkWidget * widget,
 
   /* end drawing to current GL-context */
   gdk_gl_drawable_gl_end (pGlDrawable);
+#endif
+
   return FALSE;
 }
 

commit c1ecaf676017a12d1d7c278af53d600a2c9f8e1b
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    Drop in PCB+GL code + various mess. Needs splitting up?
    
    Credits:
    
      Algorithm to calculate number of segments to use in circular
      curve approximation suggested by DJ Delorie.
    
    FIXME: SHOULD NOT RE-WRITE THE GTK HID!

diff --git a/src/Makefile.am b/src/Makefile.am
index e719268..f66cca7 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -150,13 +150,23 @@ PCB_SRCS = \
 	hid/common/hid_resource.h \
 	hid/hidint.h 
 
-EXTRA_pcb_SOURCES = ${DBUS_SRCS} toporouter.c toporouter.h
+EXTRA_pcb_SOURCES = ${DBUS_SRCS} ${GL_SRCS} toporouter.c toporouter.h
 DBUS_SRCS= \
 	dbus-pcbmain.c \
 	dbus-pcbmain.h \
 	dbus.h \
 	dbus.c
 
+LIBGTK_GDK_SRCS= \
+	hid/gtk/gtkhid-gdk.c
+
+LIBGTK_GL_SRCS= \
+	hid/gtk/gtkhid-gl.c
+
+GL_SRCS= \
+	hid/common/hidgl.c \
+	hid/common/hidgl.h
+
 BUILT_SOURCES = \
 	core_lists.h \
 	gpcb-menu.h \
@@ -244,7 +254,6 @@ LIBGTK_SRCS = \
 	dolists.h \
 	hid/hidint.h \
 	hid/gtk/gtkhid-main.c \
-	hid/gtk/gtkhid-gdk.c \
 	hid/gtk/gtkhid.h \
 	hid/gtk/gui.h \
 	hid/gtk/gui-command-window.c \
@@ -289,6 +298,14 @@ BUILT_SOURCES+=	dbus-introspect.h
 
 endif
 
+# If we are building with GL support, we need some extra files
+if USE_GL
+PCB_SRCS+=	${GL_SRCS}
+LIBGTK_SRCS+=	${LIBGTK_GL_SRCS}
+else
+LIBGTK_SRCS+=	${LIBGTK_GDK_SRCS}
+endif
+
 # If we are building on win32, then compile in some icons for the
 # desktop and application toolbar
 if WIN32
diff --git a/src/crosshair.c b/src/crosshair.c
index d54fad7..ac22277 100644
--- a/src/crosshair.c
+++ b/src/crosshair.c
@@ -85,7 +85,7 @@ static void XORDrawMoveOrCopyObject (void);
 static void XORDrawAttachedLine (LocationType, LocationType, LocationType,
 				 LocationType, BDimension);
 static void XORDrawAttachedArc (BDimension);
-static void DrawAttached (bool);
+/*static*/ void DrawAttached (bool);
 
 /* ---------------------------------------------------------------------------
  * creates a tmp polygon with coordinates converted to screen system
@@ -566,7 +566,7 @@ XORDrawMoveOrCopyObject (void)
 /* ---------------------------------------------------------------------------
  * draws additional stuff that follows the crosshair
  */
-static void
+/*static*/ void
 DrawAttached (bool BlockToo)
 {
   BDimension s;
@@ -738,7 +738,7 @@ HideCrosshair (bool BlockToo)
   CrosshairStack[CrosshairStackLocation] = Crosshair.On;
   CrosshairStackLocation++;
 
-  CrosshairOff (BlockToo);
+//  CrosshairOff (BlockToo);
 }
 
 /* ---------------------------------------------------------------------------
@@ -758,11 +758,11 @@ RestoreCrosshair (bool BlockToo)
 
   if (CrosshairStack[CrosshairStackLocation])
     {
-      CrosshairOn (BlockToo);
+//      CrosshairOn (BlockToo);
     }
   else
     {
-      CrosshairOff (BlockToo);
+//      CrosshairOff (BlockToo);
     }
 }
 
diff --git a/src/hid/common/hidgl.c b/src/hid/common/hidgl.c
new file mode 100644
index 0000000..b0a5049
--- /dev/null
+++ b/src/hid/common/hidgl.c
@@ -0,0 +1,583 @@
+/* $Id: */
+
+#if 1 /* DISABLE EVERYTHING! */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#include <math.h>
+#include <time.h>
+#include <assert.h>
+
+/* The Linux OpenGL ABI 1.0 spec requires that we define
+ * GL_GLEXT_PROTOTYPES before including gl.h or glx.h for extensions
+ * in order to get prototypes:
+ *   http://www.opengl.org/registry/ABI/
+ */
+#define GL_GLEXT_PROTOTYPES 1
+#include <GL/gl.h>
+#include <GL/glu.h>
+
+#include "action.h"
+#include "crosshair.h"
+#include "data.h"
+#include "draw.h"
+#include "error.h"
+#include "global.h"
+#include "mymem.h"
+#include "draw.h"
+#include "clip.h"
+
+#include "hid.h"
+#include "hidgl.h"
+
+
+#ifdef HAVE_LIBDMALLOC
+#include <dmalloc.h>
+#endif
+
+RCSID ("$Id: $");
+
+triangle_buffer buffer;
+
+#if 0
+triangle_array *
+hidgl_new_triangle_array (void)
+{
+  return malloc (sizeof (triangle_buffer));
+}
+#endif
+
+void
+hidgl_init_triangle_array (triangle_buffer *buffer)
+{
+  glEnableClientState (GL_VERTEX_ARRAY);
+  glVertexPointer (2, GL_FLOAT, 0, buffer->triangle_array);
+  buffer->triangle_count = 0;
+  buffer->coord_comp_count = 0;
+}
+
+void
+hidgl_flush_triangles (triangle_buffer *buffer)
+{
+  if (buffer->triangle_count == 0)
+    return;
+
+  glDrawArrays (GL_TRIANGLES, 0, buffer->triangle_count * 3);
+  buffer->triangle_count = 0;
+  buffer->coord_comp_count = 0;
+}
+
+void
+hidgl_ensure_triangle_space (triangle_buffer *buffer, int count)
+{
+  if (count > TRIANGLE_ARRAY_SIZE)
+    {
+      fprintf (stderr, "Not enough space in vertex buffer\n");
+      fprintf (stderr, "Requested %i triangles, %i available\n",
+                       count, TRIANGLE_ARRAY_SIZE);
+      exit (1);
+    }
+  if (count > TRIANGLE_ARRAY_SIZE - buffer->triangle_count)
+    hidgl_flush_triangles (buffer);
+}
+
+//static int cur_mask = -1;
+
+
+/* ------------------------------------------------------------ */
+#if 0
+/*static*/ void
+draw_grid ()
+{
+  static GLfloat *points = 0;
+  static int npoints = 0;
+  int x1, y1, x2, y2, n, i;
+  double x, y;
+
+  if (!Settings.DrawGrid)
+    return;
+  if (Vz (PCB->Grid) < MIN_GRID_DISTANCE)
+    return;
+
+  if (gdk_color_parse (Settings.GridColor, &gport->grid_color))
+    {
+      gport->grid_color.red ^= gport->bg_color.red;
+      gport->grid_color.green ^= gport->bg_color.green;
+      gport->grid_color.blue ^= gport->bg_color.blue;
+    }
+
+  hidgl_flush_triangles ();
+
+  glEnable (GL_COLOR_LOGIC_OP);
+  glLogicOp (GL_XOR);
+
+  glColor3f (gport->grid_color.red / 65535.,
+             gport->grid_color.green / 65535.,
+             gport->grid_color.blue / 65535.);
+
+  x1 = GRIDFIT_X (SIDE_X (gport->view_x0), PCB->Grid);
+  y1 = GRIDFIT_Y (SIDE_Y (gport->view_y0), PCB->Grid);
+  x2 = GRIDFIT_X (SIDE_X (gport->view_x0 + gport->view_width - 1), PCB->Grid);
+  y2 = GRIDFIT_Y (SIDE_Y (gport->view_y0 + gport->view_height - 1), PCB->Grid);
+  if (x1 > x2)
+    {
+      int tmp = x1;
+      x1 = x2;
+      x2 = tmp;
+    }
+  if (y1 > y2)
+    {
+      int tmp = y1;
+      y1 = y2;
+      y2 = tmp;
+    }
+  if (Vx (x1) < 0)
+    x1 += PCB->Grid;
+  if (Vy (y1) < 0)
+    y1 += PCB->Grid;
+  if (Vx (x2) >= gport->width)
+    x2 -= PCB->Grid;
+  if (Vy (y2) >= gport->height)
+    y2 -= PCB->Grid;
+  n = (int) ((x2 - x1) / PCB->Grid + 0.5) + 1;
+  if (n > npoints)
+    {
+      npoints = n + 10;
+      points =
+        MyRealloc (points, npoints * 2 * sizeof (GLfloat), "gtk_draw_grid");
+    }
+
+  glEnableClientState (GL_VERTEX_ARRAY);
+  glVertexPointer (2, GL_FLOAT, 0, points);
+
+  n = 0;
+  for (x = x1; x <= x2; x += PCB->Grid)
+    {
+      points[2 * n] = Vx (x);
+      n++;
+    }
+  for (y = y1; y <= y2; y += PCB->Grid)
+    {
+      int vy = Vy (y);
+      for (i = 0; i < n; i++)
+        points[2 * i + 1] = vy;
+      glDrawArrays (GL_POINTS, 0, n);
+    }
+
+  glDisableClientState (GL_VERTEX_ARRAY);
+  glDisable (GL_COLOR_LOGIC_OP);
+}
+
+#endif
+/* ------------------------------------------------------------ */
+
+#define MAX_PIXELS_ARC_TO_CHORD 0.5
+#define MIN_SLICES 6
+int calc_slices (float pix_radius, float sweep_angle)
+{
+  float slices;
+
+  if (pix_radius <= MAX_PIXELS_ARC_TO_CHORD)
+    return MIN_SLICES;
+
+  slices = sweep_angle / acosf (1 - MAX_PIXELS_ARC_TO_CHORD / pix_radius) / 2.;
+  return (int)ceilf (slices);
+}
+
+#define MIN_TRIANGLES_PER_CAP 3
+#define MAX_TRIANGLES_PER_CAP 90
+static void draw_cap (double width, int x, int y, double angle, double scale)
+{
+  float last_capx, last_capy;
+  float capx, capy;
+  float radius = width / 2.;
+  int slices = calc_slices (radius / scale, M_PI);
+  int i;
+
+  if (slices < MIN_TRIANGLES_PER_CAP)
+    slices = MIN_TRIANGLES_PER_CAP;
+
+  if (slices > MAX_TRIANGLES_PER_CAP)
+    slices = MAX_TRIANGLES_PER_CAP;
+
+  hidgl_ensure_triangle_space (&buffer, slices);
+
+  last_capx =  radius * cosf (angle * M_PI / 180.) + x;
+  last_capy = -radius * sinf (angle * M_PI / 180.) + y;
+  for (i = 0; i < slices; i++) {
+    capx =  radius * cosf (angle * M_PI / 180. + ((float)(i + 1)) * M_PI / (float)slices) + x;
+    capy = -radius * sinf (angle * M_PI / 180. + ((float)(i + 1)) * M_PI / (float)slices) + y;
+    hidgl_add_triangle (&buffer, last_capx, last_capy, capx, capy, x, y);
+    last_capx = capx;
+    last_capy = capy;
+  }
+}
+
+void
+hidgl_draw_line (int cap, double width, int x1, int y1, int x2, int y2, double scale)
+{
+  double angle;
+  float deltax, deltay, length;
+  float wdx, wdy;
+  int circular_caps = 0;
+  int hairline = 0;
+
+  if (width == 0.0)
+    hairline = 1;
+
+  if (width < scale)
+    width = scale;
+
+  deltax = x2 - x1;
+  deltay = y2 - y1;
+
+  length = sqrt (deltax * deltax + deltay * deltay);
+
+  if (length == 0) {
+    /* Assume the orientation of the line is horizontal */
+    angle = 0;
+    wdx = -width / 2.;
+    wdy = 0;
+    length = 1.;
+    deltax = 1.;
+    deltay = 0.;
+  } else {
+    wdy = deltax * width / 2. / length;
+    wdx = -deltay * width / 2. / length;
+
+    if (deltay == 0.)
+      angle = (deltax < 0) ? 270. : 90.;
+    else
+      angle = 180. / M_PI * atanl (deltax / deltay);
+
+    if (deltay < 0)
+      angle += 180.;
+  }
+
+  switch (cap) {
+    case Trace_Cap:
+    case Round_Cap:
+      circular_caps = 1;
+      break;
+
+    case Square_Cap:
+    case Beveled_Cap:
+      x1 -= deltax * width / 2. / length;
+      y1 -= deltay * width / 2. / length;
+      x2 += deltax * width / 2. / length;
+      y2 += deltay * width / 2. / length;
+      break;
+  }
+
+  hidgl_ensure_triangle_space (&buffer, 2);
+  hidgl_add_triangle (&buffer, x1 - wdx, y1 - wdy,
+                               x2 - wdx, y2 - wdy,
+                               x2 + wdx, y2 + wdy);
+  hidgl_add_triangle (&buffer, x1 - wdx, y1 - wdy,
+                               x2 + wdx, y2 + wdy,
+                               x1 + wdx, y1 + wdy);
+
+  /* Don't bother capping hairlines */
+  if (circular_caps && !hairline)
+    {
+      draw_cap (width, x1, y1, angle, scale);
+      draw_cap (width, x2, y2, angle + 180., scale);
+    }
+}
+
+#define MIN_SLICES_PER_ARC 6
+#define MAX_SLICES_PER_ARC 360
+void
+hidgl_draw_arc (double width, int x, int y, int rx, int ry,
+                int start_angle, int delta_angle, double scale)
+{
+  float last_inner_x, last_inner_y;
+  float last_outer_x, last_outer_y;
+  float inner_x, inner_y;
+  float outer_x, outer_y;
+  float inner_r;
+  float outer_r;
+  float cos_ang, sin_ang;
+  float start_angle_rad;
+  float delta_angle_rad;
+  float angle_incr_rad;
+  int slices;
+  int i;
+  int hairline = 0;
+
+  if (width == 0.0)
+    hairline = 1;
+
+  if (width < scale)
+    width = scale;
+
+  inner_r = rx - width / 2.;
+  outer_r = rx + width / 2.;
+
+  if (delta_angle < 0) {
+    start_angle += delta_angle;
+    delta_angle = - delta_angle;
+  }
+
+  start_angle_rad = start_angle * M_PI / 180.;
+  delta_angle_rad = delta_angle * M_PI / 180.;
+
+  slices = calc_slices ((rx + width / 2.) / scale, delta_angle_rad);
+
+  if (slices < MIN_SLICES_PER_ARC)
+    slices = MIN_SLICES_PER_ARC;
+
+  if (slices > MAX_SLICES_PER_ARC)
+    slices = MAX_SLICES_PER_ARC;
+
+  hidgl_ensure_triangle_space (&buffer, 2 * slices);
+
+  angle_incr_rad = delta_angle_rad / (float)slices;
+
+  cos_ang = cosf (start_angle_rad);
+  sin_ang = sinf (start_angle_rad);
+  last_inner_x = -inner_r * cos_ang + x;  last_inner_y = inner_r * sin_ang + y;
+  last_outer_x = -outer_r * cos_ang + x;  last_outer_y = outer_r * sin_ang + y;
+  for (i = 1; i <= slices; i++) {
+    cos_ang = cosf (start_angle_rad + ((float)(i)) * angle_incr_rad);
+    sin_ang = sinf (start_angle_rad + ((float)(i)) * angle_incr_rad);
+    inner_x = -inner_r * cos_ang + x;  inner_y = inner_r * sin_ang + y;
+    outer_x = -outer_r * cos_ang + x;  outer_y = outer_r * sin_ang + y;
+    hidgl_add_triangle (&buffer, last_inner_x, last_inner_y,
+                                 last_outer_x, last_outer_y,
+                                 outer_x, outer_y);
+    hidgl_add_triangle (&buffer, last_inner_x, last_inner_y,
+                                 inner_x, inner_y,
+                                 outer_x, outer_y);
+    last_inner_x = inner_x;  last_inner_y = inner_y;
+    last_outer_x = outer_x;  last_outer_y = outer_y;
+  }
+
+  /* Don't bother capping hairlines */
+  if (hairline)
+    return;
+
+  draw_cap (width, x + rx * -cosf (start_angle_rad),
+                   y + rx *  sinf (start_angle_rad),
+                   start_angle, scale);
+  draw_cap (width, x + rx * -cosf (start_angle_rad + delta_angle_rad),
+                   y + rx *  sinf (start_angle_rad + delta_angle_rad),
+                   start_angle + delta_angle + 180., scale);
+}
+
+void
+hidgl_draw_rect (int x1, int y1, int x2, int y2)
+{
+  glBegin (GL_LINE_LOOP);
+  glVertex2f (x1, y1);
+  glVertex2f (x1, y2);
+  glVertex2f (x2, y2);
+  glVertex2f (x2, y1);
+  glEnd ();
+}
+
+
+void
+hidgl_fill_circle (int vx, int vy, int vr, double scale)
+{
+#define MIN_TRIANGLES_PER_CIRCLE 6
+#define MAX_TRIANGLES_PER_CIRCLE 360
+  float last_x, last_y;
+  float radius = vr;
+  int slices;
+  int i;
+
+  slices = calc_slices (vr / scale, 2 * M_PI);
+
+  if (slices < MIN_TRIANGLES_PER_CIRCLE)
+    slices = MIN_TRIANGLES_PER_CIRCLE;
+
+  if (slices > MAX_TRIANGLES_PER_CIRCLE)
+    slices = MAX_TRIANGLES_PER_CIRCLE;
+
+  hidgl_ensure_triangle_space (&buffer, slices);
+
+  last_x = vx + vr;
+  last_y = vy;
+
+  for (i = 0; i < slices; i++) {
+    float x, y;
+    x = radius * cosf (((float)(i + 1)) * 2. * M_PI / (float)slices) + vx;
+    y = radius * sinf (((float)(i + 1)) * 2. * M_PI / (float)slices) + vy;
+    hidgl_add_triangle (&buffer, vx, vy, last_x, last_y, x, y);
+    last_x = x;
+    last_y = y;
+  }
+}
+
+#define MAX_COMBINED_MALLOCS 2500
+static void *combined_to_free [MAX_COMBINED_MALLOCS];
+static int combined_num_to_free = 0;
+
+static GLenum tessVertexType;
+static int stashed_vertices;
+static int triangle_comp_idx;
+
+
+static void
+myError (GLenum errno)
+{
+  printf ("gluTess error: %s\n", gluErrorString (errno));
+}
+
+static void
+myFreeCombined ()
+{
+  while (combined_num_to_free)
+    free (combined_to_free [-- combined_num_to_free]);
+}
+
+static void
+myCombine ( GLdouble coords[3], void *vertex_data[4], GLfloat weight[4], void **dataOut )
+{
+#define MAX_COMBINED_VERTICES 2500
+  static GLdouble combined_vertices [3 * MAX_COMBINED_VERTICES];
+  static int num_combined_vertices = 0;
+
+  GLdouble *new_vertex;
+
+  if (num_combined_vertices < MAX_COMBINED_VERTICES)
+    {
+      new_vertex = &combined_vertices [3 * num_combined_vertices];
+      num_combined_vertices ++;
+    }
+  else
+    {
+      new_vertex = malloc (3 * sizeof (GLdouble));
+
+      if (combined_num_to_free < MAX_COMBINED_MALLOCS)
+        combined_to_free [combined_num_to_free ++] = new_vertex;
+      else
+        printf ("myCombine leaking %i bytes of memory\n", 3 * sizeof (GLdouble));
+    }
+
+  new_vertex[0] = coords[0];
+  new_vertex[1] = coords[1];
+  new_vertex[2] = coords[2];
+
+  *dataOut = new_vertex;
+}
+
+static void
+myBegin (GLenum type)
+{
+  tessVertexType = type;
+  stashed_vertices = 0;
+  triangle_comp_idx = 0;
+}
+
+static void
+myVertex (GLdouble *vertex_data)
+{
+  static GLfloat triangle_vertices [2 * 3];
+
+  if (tessVertexType == GL_TRIANGLE_STRIP ||
+      tessVertexType == GL_TRIANGLE_FAN)
+    {
+      if (stashed_vertices < 2)
+        {
+          triangle_vertices [triangle_comp_idx ++] = vertex_data [0];
+          triangle_vertices [triangle_comp_idx ++] = vertex_data [1];
+          stashed_vertices ++;
+        }
+      else
+        {
+          hidgl_ensure_triangle_space (&buffer, 1);
+          hidgl_add_triangle (&buffer,
+                              triangle_vertices [0], triangle_vertices [1],
+                              triangle_vertices [2], triangle_vertices [3],
+                              vertex_data [0], vertex_data [1]);
+
+          if (tessVertexType == GL_TRIANGLE_STRIP)
+            {
+              /* STRIP saves the last two vertices for re-use in the next triangle */
+              triangle_vertices [0] = triangle_vertices [2];
+              triangle_vertices [1] = triangle_vertices [3];
+            }
+          /* Both FAN and STRIP save the last vertex for re-use in the next triangle */
+          triangle_vertices [2] = vertex_data [0];
+          triangle_vertices [3] = vertex_data [1];
+        }
+    }
+  else if (tessVertexType == GL_TRIANGLES)
+    {
+      triangle_vertices [triangle_comp_idx ++] = vertex_data [0];
+      triangle_vertices [triangle_comp_idx ++] = vertex_data [1];
+      stashed_vertices ++;
+      if (stashed_vertices == 3)
+        {
+          hidgl_ensure_triangle_space (&buffer, 1);
+          hidgl_add_triangle (&buffer,
+                              triangle_vertices [0], triangle_vertices [1],
+                              triangle_vertices [2], triangle_vertices [3],
+                              triangle_vertices [4], triangle_vertices [5]);
+          triangle_comp_idx = 0;
+          stashed_vertices = 0;
+        }
+    }
+  else
+    printf ("Vertex recieved with unknown type\n");
+}
+
+void
+hidgl_fill_polygon (int n_coords, int *x, int *y)
+{
+  int i;
+  GLUtesselator *tobj;
+  GLdouble *vertices;
+
+//  return;
+
+  assert (n_coords > 0);
+
+  vertices = malloc (sizeof(GLdouble) * n_coords * 3);
+
+  tobj = gluNewTess ();
+  gluTessCallback(tobj, GLU_TESS_BEGIN, myBegin);
+  gluTessCallback(tobj, GLU_TESS_VERTEX, myVertex);
+  gluTessCallback(tobj, GLU_TESS_COMBINE, myCombine);
+  gluTessCallback(tobj, GLU_TESS_ERROR, myError);
+
+  gluTessBeginPolygon (tobj, NULL);
+  gluTessBeginContour (tobj);
+
+  for (i = 0; i < n_coords; i++)
+    {
+      vertices [0 + i * 3] = x[i];
+      vertices [1 + i * 3] = y[i];
+      vertices [2 + i * 3] = 0.;
+      gluTessVertex (tobj, &vertices [i * 3], &vertices [i * 3]);
+    }
+
+  gluTessEndContour (tobj);
+  gluTessEndPolygon (tobj);
+  gluDeleteTess (tobj);
+
+  myFreeCombined ();
+  free (vertices);
+}
+
+void
+hidgl_fill_rect (int x1, int y1, int x2, int y2)
+{
+  hidgl_ensure_triangle_space (&buffer, 2);
+  hidgl_add_triangle (&buffer, x1, y1, x1, y2, x2, y2);
+  hidgl_add_triangle (&buffer, x2, y1, x2, y2, x1, y1);
+}
+
+/* ---------------------------------------------------------------------- */
+
+#endif /* DISABLE EVERYTHING! */
+
diff --git a/src/hid/common/hidgl.h b/src/hid/common/hidgl.h
new file mode 100644
index 0000000..73d9a34
--- /dev/null
+++ b/src/hid/common/hidgl.h
@@ -0,0 +1,63 @@
+/*
+ *                            COPYRIGHT
+ *
+ *  PCB, interactive printed circuit board design
+ *  Copyright (C) 2009 PCB Contributors (See ChangeLog for details).
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef __HIDGL_INCLUDED__
+#define __HIDGL_INCLUDED__
+
+#define TRIANGLE_ARRAY_SIZE 5461
+typedef struct {
+  GLfloat triangle_array [2 * 3 * TRIANGLE_ARRAY_SIZE];
+  unsigned int triangle_count;
+  unsigned int coord_comp_count;
+} triangle_buffer;
+
+extern triangle_buffer buffer;
+
+void hidgl_init_triangle_array (triangle_buffer *buffer);
+void hidgl_flush_triangles (triangle_buffer *buffer);
+void hidgl_ensure_triangle_space (triangle_buffer *buffer, int count);
+
+static inline void
+hidgl_add_triangle (triangle_buffer *buffer,
+                    GLfloat x1, GLfloat y1,
+                    GLfloat x2, GLfloat y2,
+                    GLfloat x3, GLfloat y3)
+{
+  buffer->triangle_array [buffer->coord_comp_count++] = x1;
+  buffer->triangle_array [buffer->coord_comp_count++] = y1;
+  buffer->triangle_array [buffer->coord_comp_count++] = x2;
+  buffer->triangle_array [buffer->coord_comp_count++] = y2;
+  buffer->triangle_array [buffer->coord_comp_count++] = x3;
+  buffer->triangle_array [buffer->coord_comp_count++] = y3;
+  buffer->triangle_count++;
+}
+
+// void draw_grid ()
+void hidgl_draw_line (int cap, double width, int x1, int y1, int x2, int y2, double scale);
+void hidgl_draw_arc (double width, int vx, int vy, int vrx, int vry, int start_angle, int delta_angle, double scale);
+void hidgl_draw_rect (int x1, int y1, int x2, int y2);
+void hidgl_fill_circle (int vx, int vy, int vr, double scale);
+void hidgl_fill_polygon (int n_coords, int *x, int *y);
+void hidgl_fill_rect (int x1, int y1, int x2, int y2);
+
+
+#endif /* __HIDGL_INCLUDED__  */
diff --git a/src/hid/gtk/gtkhid-gl.c b/src/hid/gtk/gtkhid-gl.c
new file mode 100644
index 0000000..3e41c35
--- /dev/null
+++ b/src/hid/gtk/gtkhid-gl.c
@@ -0,0 +1,530 @@
+/* $Id$ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+
+#include "crosshair.h"
+#include "clip.h"
+#include "../hidint.h"
+#include "gui.h"
+
+#ifdef HAVE_LIBDMALLOC
+#include <dmalloc.h>
+#endif
+
+
+RCSID ("$Id$");
+
+
+extern HID ghid_hid;
+extern int ghid_gui_is_up;
+
+static hidGC current_gc = NULL;
+
+/* Sets gport->u_gc to the "right" GC to use (wrt mask or window)
+*/
+#define USE_GC(gc) if (!use_gc(gc)) return
+
+static int cur_mask = -1;
+
+
+typedef struct hid_gc_struct
+{
+  HID *me_pointer;
+
+  gchar *colorname;
+  gint width;
+  gint cap, join;
+  gchar xor;
+  gchar erase;
+}
+hid_gc_struct;
+
+
+void
+ghid_destroy_gc (hidGC gc)
+{
+  g_free (gc);
+}
+
+hidGC
+ghid_make_gc (void)
+{
+  hidGC rv;
+
+  rv = g_new0 (hid_gc_struct, 1);
+  rv->me_pointer = &ghid_hid;
+  rv->colorname = Settings.BackgroundColor;
+  return rv;
+}
+
+void
+ghid_draw_grid ()
+{
+  static GLfloat *points = 0;
+  static int npoints = 0;
+  int x1, y1, x2, y2, n, i;
+  double x, y;
+
+  if (!Settings.DrawGrid)
+    return;
+  if (Vz (PCB->Grid) < MIN_GRID_DISTANCE)
+    return;
+
+  if (gdk_color_parse (Settings.GridColor, &gport->grid_color))
+    {
+      gport->grid_color.red ^= gport->bg_color.red;
+      gport->grid_color.green ^= gport->bg_color.green;
+      gport->grid_color.blue ^= gport->bg_color.blue;
+    }
+
+  hidgl_flush_triangles (&buffer);
+
+  glEnable (GL_COLOR_LOGIC_OP);
+  glLogicOp (GL_XOR);
+
+  glColor3f (gport->grid_color.red / 65535.,
+             gport->grid_color.green / 65535.,
+             gport->grid_color.blue / 65535.);
+
+  x1 = GRIDFIT_X (SIDE_X (gport->view_x0), PCB->Grid);
+  y1 = GRIDFIT_Y (SIDE_Y (gport->view_y0), PCB->Grid);
+  x2 = GRIDFIT_X (SIDE_X (gport->view_x0 + gport->view_width - 1), PCB->Grid);
+  y2 = GRIDFIT_Y (SIDE_Y (gport->view_y0 + gport->view_height - 1), PCB->Grid);
+  if (x1 > x2)
+    {
+      int tmp = x1;
+      x1 = x2;
+      x2 = tmp;
+    }
+  if (y1 > y2)
+    {
+      int tmp = y1;
+      y1 = y2;
+      y2 = tmp;
+    }
+  if (Vx (x1) < 0)
+    x1 += PCB->Grid;
+  if (Vy (y1) < 0)
+    y1 += PCB->Grid;
+  if (Vx (x2) >= gport->width)
+    x2 -= PCB->Grid;
+  if (Vy (y2) >= gport->height)
+    y2 -= PCB->Grid;
+  n = (int) ((x2 - x1) / PCB->Grid + 0.5) + 1;
+  if (n > npoints)
+    {
+      npoints = n + 10;
+      points =
+	MyRealloc (points, npoints * 2 * sizeof (GLfloat), "gtk_draw_grid");
+    }
+
+  glEnableClientState (GL_VERTEX_ARRAY);
+  glVertexPointer (2, GL_FLOAT, 0, points);
+
+  n = 0;
+  for (x = x1; x <= x2; x += PCB->Grid)
+    {
+      points[2 * n] = Vx (x);
+      n++;
+    }
+  for (y = y1; y <= y2; y += PCB->Grid)
+    {
+      int vy = Vy (y);
+      for (i = 0; i < n; i++)
+	points[2 * i + 1] = vy;
+      glDrawArrays (GL_POINTS, 0, n);
+    }
+
+  glDisableClientState (GL_VERTEX_ARRAY);
+  glDisable (GL_COLOR_LOGIC_OP);
+}
+
+#if 0
+void
+ghid_draw_bg_image (void)
+{
+  static GdkPixbuf *pixbuf = NULL;
+  static gint vw_scaled, vh_scaled, x_cached, y_cached;
+  GdkInterpType interp_type;
+  gint x, y, vw, vh, w, h, w_src, h_src;
+  int bits_per_sample;
+  gboolean has_alpha;
+
+  if (!ghidgui->bg_pixbuf)
+    return;
+
+  w = PCB->MaxWidth / gport->zoom;
+  h = PCB->MaxHeight / gport->zoom;
+  x = gport->view_x0 / gport->zoom;
+  y = gport->view_y0 / gport->zoom;
+  vw = gport->view_width / gport->zoom;
+  vh = gport->view_height / gport->zoom;
+
+  if (pixbuf == NULL || vw_scaled != vw || vh_scaled != vh)
+    {
+      if (pixbuf != NULL)
+        g_object_unref(G_OBJECT(pixbuf));
+
+      bits_per_sample = gdk_pixbuf_get_bits_per_sample(ghidgui->bg_pixbuf);
+      has_alpha = gdk_pixbuf_get_has_alpha (ghidgui->bg_pixbuf);
+      pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB,
+                              has_alpha,
+                              bits_per_sample,
+                              vw, vh);
+    }
+
+  if (pixbuf == NULL)
+    return;
+
+  if (vw_scaled != vw || vh_scaled != vh ||
+       x_cached != x  ||  y_cached != y)
+    {
+      w_src = gdk_pixbuf_get_width(ghidgui->bg_pixbuf);
+      h_src = gdk_pixbuf_get_height(ghidgui->bg_pixbuf);
+
+      if (w > w_src && h > h_src)
+        interp_type = GDK_INTERP_NEAREST;
+      else
+        interp_type = GDK_INTERP_BILINEAR;
+
+      gdk_pixbuf_scale(ghidgui->bg_pixbuf, pixbuf,
+                       0, 0, vw, vh,
+                       (double) -x,
+                       (double) -y,
+                       (double) w / w_src,
+                       (double) h / h_src,
+                       interp_type);
+
+      x_cached = x;
+      y_cached = y;
+      vw_scaled = vw;
+      vh_scaled = vh;
+    }
+
+  if (pixbuf != NULL)
+    gdk_draw_pixbuf(gport->drawable, gport->bg_gc, pixbuf,
+                    0, 0, 0, 0, vw, vh, GDK_RGB_DITHER_NORMAL, 0, 0);
+}
+#endif
+
+
+void
+ghid_use_mask (int use_it)
+{
+
+  /* THE FOLLOWING IS COMPLETE ABUSE OF THIS MASK RENDERING API... NOT IMPLEMENTED */
+  if (use_it == HID_LIVE_DRAWING ||
+      use_it == HID_LIVE_DRAWING_OFF ||
+      use_it == HID_FLUSH_DRAW_Q) {
+    return;
+  }
+
+  if (use_it == cur_mask)
+    return;
+
+  hidgl_flush_triangles (&buffer);
+
+  switch (use_it)
+    {
+    case HID_MASK_BEFORE:
+      /* Write '1' to the stencil buffer where the solder-mask is drawn. */
+      glColorMask (0, 0, 0, 0);                   // Disable writting in color buffer
+      glEnable (GL_STENCIL_TEST);                 // Enable Stencil test
+      glStencilFunc (GL_ALWAYS, 1, 1);            // Test always passes, value written 1
+      glStencilOp (GL_KEEP, GL_KEEP, GL_REPLACE); // Stencil pass => replace stencil value (with 1)
+      break;
+
+    case HID_MASK_CLEAR:
+      /* Drawing operations clear the stencil buffer to '0' */
+      glStencilFunc (GL_ALWAYS, 0, 1);            // Test always passes, value written 0
+      glStencilOp (GL_KEEP, GL_KEEP, GL_REPLACE); // Stencil pass => replace stencil value (with 0)
+      break;
+
+    case HID_MASK_AFTER:
+      /* Drawing operations as masked to areas where the stencil buffer is '1' */
+      glColorMask (1, 1, 1, 1);                   // Enable drawing of r, g, b & a
+      glStencilFunc (GL_EQUAL, 1, 1);             // Draw only where stencil buffer is 1
+      glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP);    // Stencil buffer read only
+      break;
+
+    case HID_MASK_OFF:
+      /* Disable stenciling */
+      glDisable (GL_STENCIL_TEST);                // Disable Stencil test
+      break;
+    }
+  cur_mask = use_it;
+}
+
+
+  /* Config helper functions for when the user changes color preferences.
+     |  set_special colors used in the gtkhid.
+   */
+static void
+set_special_grid_color (void)
+{
+  if (!gport->colormap)
+    return;
+  gport->grid_color.red ^= gport->bg_color.red;
+  gport->grid_color.green ^= gport->bg_color.green;
+  gport->grid_color.blue ^= gport->bg_color.blue;
+//  gdk_color_alloc (gport->colormap, &gport->grid_color);
+}
+
+void
+ghid_set_special_colors (HID_Attribute * ha)
+{
+  if (!ha->name || !ha->value)
+    return;
+  if (!strcmp (ha->name, "background-color"))
+    {
+      ghid_map_color_string (*(char **) ha->value, &gport->bg_color);
+      set_special_grid_color ();
+    }
+  else if (!strcmp (ha->name, "off-limit-color"))
+  {
+      ghid_map_color_string (*(char **) ha->value, &gport->offlimits_color);
+    }
+  else if (!strcmp (ha->name, "grid-color"))
+    {
+      ghid_map_color_string (*(char **) ha->value, &gport->grid_color);
+      set_special_grid_color ();
+    }
+}
+
+typedef struct
+{
+  int color_set;
+  GdkColor color;
+  int xor_set;
+  GdkColor xor_color;
+  double red;
+  double green;
+  double blue;
+} ColorCache;
+
+void
+ghid_set_color (hidGC gc, const char *name)
+{
+  static void *cache = NULL;
+  static char *old_name = NULL;
+  hidval cval;
+  ColorCache *cc;
+  double alpha_mult = 1.0;
+  double r, g, b, a;
+  a = 1.0;
+
+  if (old_name != NULL)
+    {
+      if (strcmp (name, old_name) == 0)
+        return;
+      free (old_name);
+    }
+
+  old_name = strdup (name);
+
+  if (name == NULL)
+    {
+      fprintf (stderr, "%s():  name = NULL, setting to magenta\n",
+               __FUNCTION__);
+      name = "magenta";
+    }
+
+  gc->colorname = (char *) name;
+
+  if (gport->colormap == 0)
+    gport->colormap = gtk_widget_get_colormap (gport->top_window);
+  if (strcmp (name, "erase") == 0)
+    {
+      gc->erase = 1;
+      r = gport->bg_color.red   / 65535.;
+      g = gport->bg_color.green / 65535.;
+      b = gport->bg_color.blue  / 65535.;
+    }
+  else if (strcmp (name, "drill") == 0)
+    {
+      gc->erase = 0;
+      alpha_mult = 0.85;
+      r = gport->offlimits_color.red   / 65535.;
+      g = gport->offlimits_color.green / 65535.;
+      b = gport->offlimits_color.blue  / 65535.;
+    }
+  else
+    {
+      alpha_mult = 0.7;
+      if (hid_cache_color (0, name, &cval, &cache))
+        cc = (ColorCache *) cval.ptr;
+      else
+        {
+          cc = (ColorCache *) malloc (sizeof (ColorCache));
+          memset (cc, 0, sizeof (*cc));
+          cval.ptr = cc;
+          hid_cache_color (1, name, &cval, &cache);
+        }
+
+      if (!cc->color_set)
+        {
+          if (gdk_color_parse (name, &cc->color))
+            gdk_color_alloc (gport->colormap, &cc->color);
+          else
+            gdk_color_white (gport->colormap, &cc->color);
+          cc->red   = cc->color.red   / 65535.;
+          cc->green = cc->color.green / 65535.;
+          cc->blue  = cc->color.blue  / 65535.;
+          cc->color_set = 1;
+        }
+      if (gc->xor)
+        {
+          if (!cc->xor_set)
+            {
+              cc->xor_color.red = cc->color.red ^ gport->bg_color.red;
+              cc->xor_color.green = cc->color.green ^ gport->bg_color.green;
+              cc->xor_color.blue = cc->color.blue ^ gport->bg_color.blue;
+              gdk_color_alloc (gport->colormap, &cc->xor_color);
+              cc->red   = cc->color.red   / 65535.;
+              cc->green = cc->color.green / 65535.;
+              cc->blue  = cc->color.blue  / 65535.;
+              cc->xor_set = 1;
+            }
+        }
+      r = cc->red;
+      g = cc->green;
+      b = cc->blue;
+
+      gc->erase = 0;
+    }
+  if (1) {
+    double maxi, mult;
+    if (gport->trans_lines)
+      a = a * alpha_mult;
+    maxi = r;
+    if (g > maxi) maxi = g;
+    if (b > maxi) maxi = b;
+    mult = MIN (1 / alpha_mult, 1 / maxi);
+#if 1
+    r = r * mult;
+    g = g * mult;
+    b = b * mult;
+#endif
+  }
+
+  if( ! ghid_gui_is_up )
+    return;
+
+  hidgl_flush_triangles (&buffer);
+  glColor4d (r, g, b, a);
+}
+
+void
+ghid_set_line_cap (hidGC gc, EndCapStyle style)
+{
+  gc->cap = style;
+}
+
+void
+ghid_set_line_width (hidGC gc, int width)
+{
+  gc->width = width;
+}
+
+
+void
+ghid_set_draw_xor (hidGC gc, int xor)
+{
+  // printf ("ghid_set_draw_xor (%p, %d) -- not implemented\n", gc, xor);
+  /* NOT IMPLEMENTED */
+
+  /* Only presently called when setting up a crosshair GC.
+   * We manage our own drawing model for that anyway. */
+}
+
+void
+ghid_set_draw_faded (hidGC gc, int faded)
+{
+  printf ("ghid_set_draw_faded(%p,%d) -- not implemented\n", gc, faded);
+}
+
+void
+ghid_set_line_cap_angle (hidGC gc, int x1, int y1, int x2, int y2)
+{
+  printf ("ghid_set_line_cap_angle() -- not implemented\n");
+}
+
+void
+ghid_invalidate_current_gc (void)
+{
+  current_gc = NULL;
+}
+
+static int
+use_gc (hidGC gc)
+{
+  if (gc->me_pointer != &ghid_hid)
+    {
+      fprintf (stderr, "Fatal: GC from another HID passed to GTK HID\n");
+      abort ();
+    }
+
+  if (current_gc == gc)
+    return 1;
+
+  current_gc = gc;
+
+  ghid_set_color (gc, gc->colorname);
+  return 1;
+}
+
+void
+ghid_draw_line (hidGC gc, int x1, int y1, int x2, int y2)
+{
+  USE_GC (gc);
+
+  hidgl_draw_line (gc->cap, gc->width, x1, y1, x2, y2, gport->zoom);
+}
+
+void
+ghid_draw_arc (hidGC gc, int cx, int cy, int xradius, int yradius,
+                         int start_angle, int delta_angle)
+{
+  USE_GC (gc);
+
+  hidgl_draw_arc (gc->width, cx, cy, xradius, yradius,
+                  start_angle, delta_angle, gport->zoom);
+}
+
+void
+ghid_draw_rect (hidGC gc, int x1, int y1, int x2, int y2)
+{
+  USE_GC (gc);
+
+  hidgl_draw_rect (x1, y1, x2, y2);
+}
+
+
+void
+ghid_fill_circle (hidGC gc, int cx, int cy, int radius)
+{
+  USE_GC (gc);
+
+  hidgl_fill_circle (cx, cy, radius, gport->zoom);
+}
+
+
+void
+ghid_fill_polygon (hidGC gc, int n_coords, int *x, int *y)
+{
+  USE_GC (gc);
+
+  hidgl_fill_polygon (n_coords, x, y);
+}
+
+void
+ghid_fill_rect (hidGC gc, int x1, int y1, int x2, int y2)
+{
+  USE_GC (gc);
+
+  hidgl_fill_rect (x1, y1, x2, y2);
+}
diff --git a/src/hid/gtk/gtkhid-main.c b/src/hid/gtk/gtkhid-main.c
index 8c3ff67..31fa88a 100644
--- a/src/hid/gtk/gtkhid-main.c
+++ b/src/hid/gtk/gtkhid-main.c
@@ -17,9 +17,15 @@
 #include "crosshair.h"
 #include "error.h"
 #include "../hidint.h"
-#include "gui.h"
 #include "hid/common/draw_helpers.h"
 
+#ifdef ENABLE_GL
+#  include <gtk/gtkgl.h>
+#  include <GL/gl.h>
+#  include "hid/common/hidgl.h"
+#endif
+
+#include "gui.h"
 
 #if !GTK_CHECK_VERSION(2,8,0) && defined(HAVE_GDK_GDKX_H)
 #include <gdk/gdkx.h>
@@ -35,6 +41,7 @@ RCSID ("$Id$");
 
 extern HID ghid_hid;
 
+int ghid_gui_is_up = 0;
 
 static void zoom_to (double factor, int x, int y);
 static void zoom_by (double factor, int x, int y);
@@ -320,67 +327,10 @@ ghid_invalidate_lr (int left, int right, int top, int bottom)
 void
 ghid_invalidate_all ()
 {
-  int eleft, eright, etop, ebottom;
-  BoxType region;
-
-  if (!gport->pixmap)
-    return;
-
-  region.X1 = MIN(Px(0), Px(gport->width + 1));
-  region.Y1 = MIN(Py(0), Py(gport->height + 1));
-  region.X2 = MAX(Px(0), Px(gport->width + 1));
-  region.Y2 = MAX(Py(0), Py(gport->height + 1));
-
-  eleft = Vx (0);
-  eright = Vx (PCB->MaxWidth);
-  etop = Vy (0);
-  ebottom = Vy (PCB->MaxHeight);
-  if (eleft > eright)
-    {
-      int tmp = eleft;
-      eleft = eright;
-      eright = tmp;
-    }
-  if (etop > ebottom)
-    {
-      int tmp = etop;
-      etop = ebottom;
-      ebottom = tmp;
-    }
-
-  if (eleft > 0)
-    gdk_draw_rectangle (gport->drawable, gport->offlimits_gc,
-			1, 0, 0, eleft, gport->height);
-  else
-    eleft = 0;
-  if (eright < gport->width)
-    gdk_draw_rectangle (gport->drawable, gport->offlimits_gc,
-			1, eright, 0, gport->width - eright, gport->height);
-  else
-    eright = gport->width;
-  if (etop > 0)
-    gdk_draw_rectangle (gport->drawable, gport->offlimits_gc,
-			1, eleft, 0, eright - eleft + 1, etop);
-  else
-    etop = 0;
-  if (ebottom < gport->height)
-    gdk_draw_rectangle (gport->drawable, gport->offlimits_gc,
-			1, eleft, ebottom, eright - eleft + 1,
-			gport->height - ebottom);
-  else
-    ebottom = gport->height;
-
-  gdk_draw_rectangle (gport->drawable, gport->bg_gc, 1,
-		      eleft, etop, eright - eleft + 1, ebottom - etop + 1);
-
-  ghid_draw_bg_image();
-
-  hid_expose_callback (&ghid_hid, &region, 0);
-  ghid_draw_grid ();
   if (ghidgui->need_restore_crosshair)
     RestoreCrosshair (FALSE);
   ghidgui->need_restore_crosshair = FALSE;
-  ghid_screen_update ();
+  gdk_window_invalidate_rect (gport->drawing_area->window, NULL, 1);
 }
 
 
@@ -391,8 +341,10 @@ ghid_set_layer (const char *name, int group, int empty)
 	     && group <
 	     max_layer) ? PCB->LayerGroups.Entries[group][0] : group;
 
-  if (idx >= 0 && idx < max_layer + 2)
+  if (idx >= 0 && idx < max_layer + 2) {
+    gport->trans_lines = TRUE;
     return /*pinout ? 1 : */ PCB->Data->Layer[idx].On;
+  }
   if (idx < 0)
     {
       switch (SL_TYPE (idx))
@@ -404,6 +356,8 @@ ghid_set_layer (const char *name, int group, int empty)
 	    return TEST_FLAG (SHOWMASKFLAG, PCB);
 	  return 0;
 	case SL_SILK:
+//          gport->trans_lines = TRUE;
+          gport->trans_lines = FALSE;
 	  if (SL_MYSIDE (idx) /*|| pinout */ )
 	    return PCB->ElementOn;
 	  return 0;
@@ -413,6 +367,8 @@ ghid_set_layer (const char *name, int group, int empty)
 	case SL_UDRILL:
 	  return 1;
 	case SL_RATS:
+	  if (PCB->RatOn)
+	    gport->trans_lines = TRUE;
 	  return PCB->RatOn;
 	}
     }
@@ -425,8 +381,6 @@ ghid_calibrate (double xval, double yval)
   printf (_("ghid_calibrate() -- not implemented\n"));
 }
 
-static int ghid_gui_is_up = 0;
-
 void
 ghid_notify_gui_is_up ()
 {
@@ -1131,7 +1085,7 @@ HID ghid_hid = {
   1,				/* gui */
   0,				/* printer */
   0,				/* exporter */
-  0,				/* poly before */
+  1,				/* poly before */
   1,				/* poly after */
   0,				/* poly dicer */
 
@@ -1714,7 +1668,8 @@ Benchmark (int argc, char **argv, int x, int y)
   time (&start);
   do
     {
-      hid_expose_callback (&ghid_hid, &region, 0);
+      gdk_window_invalidate_rect (gport->drawing_area->window, NULL, 1);
+      gdk_window_process_updates (gport->drawing_area->window, FALSE);
       gdk_display_sync (display);
       time (&end);
       i++;
diff --git a/src/hid/gtk/gui-output-events.c b/src/hid/gtk/gui-output-events.c
index 7230aa3..4942fc0 100644
--- a/src/hid/gtk/gui-output-events.c
+++ b/src/hid/gtk/gui-output-events.c
@@ -303,16 +303,16 @@ have_crosshair_attachments (void)
 #define VCD		8
 
 static void
-draw_right_cross (GdkGC *xor_gc, gint x, gint y)
+draw_right_cross (gint x, gint y)
 {
-  gdk_draw_line (gport->drawing_area->window, xor_gc,
-		 x, 0, x, gport->height);
-  gdk_draw_line (gport->drawing_area->window, xor_gc,
-		 0, y, gport->width, y);
+  glVertex2i (x, 0);
+  glVertex2i (x, gport->height);
+  glVertex2i (0, y);
+  glVertex2i (gport->width, y);
 }
 
 static void
-draw_slanted_cross (GdkGC *xor_gc, gint x, gint y)
+draw_slanted_cross (gint x, gint y)
 {
   gint x0, y0, x1, y1;
 
@@ -324,8 +324,9 @@ draw_slanted_cross (GdkGC *xor_gc, gint x, gint y)
   y0 = MAX(0, MIN (y0, gport->height));
   y1 = y - x;
   y1 = MAX(0, MIN (y1, gport->height));
-  gdk_draw_line (gport->drawing_area->window, xor_gc,
-		 x0, y0, x1, y1);
+  glVertex2i (x0, y0);
+  glVertex2i (x1, y1);
+
   x0 = x - (gport->height - y);
   x0 = MAX(0, MIN (x0, gport->width));
   x1 = x + y;
@@ -334,12 +335,12 @@ draw_slanted_cross (GdkGC *xor_gc, gint x, gint y)
   y0 = MAX(0, MIN (y0, gport->height));
   y1 = y - (gport->width - x);
   y1 = MAX(0, MIN (y1, gport->height));
-  gdk_draw_line (gport->drawing_area->window, xor_gc,
-		 x0, y0, x1, y1);
+  glVertex2i (x0, y0);
+  glVertex2i (x1, y1);
 }
 
 static void
-draw_dozen_cross (GdkGC *xor_gc, gint x, gint y)
+draw_dozen_cross (gint x, gint y)
 {
   gint x0, y0, x1, y1;
   gdouble tan60 = sqrt (3);
@@ -352,8 +353,8 @@ draw_dozen_cross (GdkGC *xor_gc, gint x, gint y)
   y0 = MAX(0, MIN (y0, gport->height));
   y1 = y - x * tan60;
   y1 = MAX(0, MIN (y1, gport->height));
-  gdk_draw_line (gport->drawing_area->window, xor_gc,
-		 x0, y0, x1, y1);
+  glVertex2i (x0, y0);
+  glVertex2i (x1, y1);
 
   x0 = x + (gport->height - y) * tan60;
   x0 = MAX(0, MIN (x0, gport->width));
@@ -363,8 +364,8 @@ draw_dozen_cross (GdkGC *xor_gc, gint x, gint y)
   y0 = MAX(0, MIN (y0, gport->height));
   y1 = y - x / tan60;
   y1 = MAX(0, MIN (y1, gport->height));
-  gdk_draw_line (gport->drawing_area->window, xor_gc,
-		 x0, y0, x1, y1);
+  glVertex2i (x0, y0);
+  glVertex2i (x1, y1);
 
   x0 = x - (gport->height - y) / tan60;
   x0 = MAX(0, MIN (x0, gport->width));
@@ -374,8 +375,8 @@ draw_dozen_cross (GdkGC *xor_gc, gint x, gint y)
   y0 = MAX(0, MIN (y0, gport->height));
   y1 = y - (gport->width - x) * tan60;
   y1 = MAX(0, MIN (y1, gport->height));
-  gdk_draw_line (gport->drawing_area->window, xor_gc,
-		 x0, y0, x1, y1);
+  glVertex2i (x0, y0);
+  glVertex2i (x1, y1);
 
   x0 = x - (gport->height - y) * tan60;
   x0 = MAX(0, MIN (x0, gport->width));
@@ -385,20 +386,20 @@ draw_dozen_cross (GdkGC *xor_gc, gint x, gint y)
   y0 = MAX(0, MIN (y0, gport->height));
   y1 = y - (gport->width - x) / tan60;
   y1 = MAX(0, MIN (y1, gport->height));
-  gdk_draw_line (gport->drawing_area->window, xor_gc,
-		 x0, y0, x1, y1);
+  glVertex2i (x0, y0);
+  glVertex2i (x1, y1);
 }
 
 static void
-draw_crosshair (GdkGC *xor_gc, gint x, gint y)
+draw_crosshair (gint x, gint y)
 {
   static enum crosshair_shape prev = Basic_Crosshair_Shape;
 
-  draw_right_cross (xor_gc, x, y);
+  draw_right_cross (x, y);
   if (prev == Union_Jack_Crosshair_Shape)
-    draw_slanted_cross (xor_gc, x, y);
+    draw_slanted_cross (x, y);
   if (prev == Dozen_Crosshair_Shape)
-    draw_dozen_cross (xor_gc, x, y);
+    draw_dozen_cross (x, y);
   prev = Crosshair.shape;
 }
 
@@ -407,60 +408,106 @@ ghid_show_crosshair (gboolean show)
 {
   gint x, y;
   static gint x_prev = -1, y_prev = -1;
-  static GdkGC *xor_gc;
+  static int done_once = 0;
   static GdkColor cross_color;
 
-  if (gport->x_crosshair < 0 || ghidgui->creating || !gport->has_entered)
+  if (gport->x_crosshair < 0 || ghidgui->creating) {// || !gport->has_entered) {
+    printf ("Returning\n");
     return;
+  }
 
-  if (!xor_gc)
+  if (!done_once)
     {
-      xor_gc = gdk_gc_new (ghid_port.drawing_area->window);
-      gdk_gc_copy (xor_gc, ghid_port.drawing_area->style->white_gc);
-      gdk_gc_set_function (xor_gc, GDK_XOR);
+      done_once = 1;
       /* FIXME: when CrossColor changed from config */
       ghid_map_color_string (Settings.CrossColor, &cross_color);
     }
   x = DRAW_X (gport->x_crosshair);
   y = DRAW_Y (gport->y_crosshair);
 
-  gdk_gc_set_foreground (xor_gc, &cross_color);
+  glEnable (GL_COLOR_LOGIC_OP);
+  glLogicOp (GL_XOR);
+
+  hidgl_flush_triangles (&buffer);
 
+  glColor3f (cross_color.red / 65535.,
+             cross_color.green / 65535.,
+             cross_color.blue / 65535.);
+
+  glBegin (GL_LINES);
+
+#if 1
   if (x_prev >= 0)
     {
-      draw_crosshair (xor_gc, x_prev, y_prev);
-      if (ghidgui->auto_pan_on && have_crosshair_attachments ())
-	{
-	  gdk_draw_rectangle (gport->drawing_area->window, xor_gc, TRUE,
-			      0, y_prev - VCD, VCD, VCW);
-	  gdk_draw_rectangle (gport->drawing_area->window, xor_gc, TRUE,
-			      gport->width - VCD, y_prev - VCD, VCD, VCW);
-	  gdk_draw_rectangle (gport->drawing_area->window, xor_gc, TRUE,
-			      x_prev - VCD, 0, VCW, VCD);
-	  gdk_draw_rectangle (gport->drawing_area->window, xor_gc, TRUE,
-			      x_prev - VCD, gport->height - VCD, VCW, VCD);
-	}
+      draw_crosshair (x_prev, y_prev);
+    }
+#endif
+
+  if (x >= 0 && show)
+    {
+      draw_crosshair (x, y);
+    }
+
+  glEnd ();
+
+  if (ghidgui->auto_pan_on && have_crosshair_attachments ())
+    {
+      glBegin (GL_QUADS);
+
+#if 1
+      if (x_prev >= 0)
+        {
+          glVertex2i (0,                  y_prev - VCD);
+          glVertex2i (0,                  y_prev - VCD + VCW);
+          glVertex2i (VCD,                y_prev - VCD + VCW);
+          glVertex2i (VCD,                y_prev - VCD);
+          glVertex2i (gport->width,       y_prev - VCD);
+          glVertex2i (gport->width,       y_prev - VCD + VCW);
+          glVertex2i (gport->width - VCD, y_prev - VCD + VCW);
+          glVertex2i (gport->width - VCD, y_prev - VCD);
+          glVertex2i (x_prev - VCD,       0);
+          glVertex2i (x_prev - VCD,       VCD);
+          glVertex2i (x_prev - VCD + VCW, VCD);
+          glVertex2i (x_prev - VCD + VCW, 0);
+          glVertex2i (x_prev - VCD,       gport->height - VCD);
+          glVertex2i (x_prev - VCD,       gport->height);
+          glVertex2i (x_prev - VCD + VCW, gport->height);
+          glVertex2i (x_prev - VCD + VCW, gport->height - VCD);
+        }
+#endif
+
+      if (x >= 0 && show)
+        {
+          glVertex2i (0,                  y - VCD);
+          glVertex2i (0,                  y - VCD + VCW);
+          glVertex2i (VCD,                y - VCD + VCW);
+          glVertex2i (VCD,                y - VCD);
+          glVertex2i (gport->width,       y - VCD);
+          glVertex2i (gport->width,       y - VCD + VCW);
+          glVertex2i (gport->width - VCD, y - VCD + VCW);
+          glVertex2i (gport->width - VCD, y - VCD);
+          glVertex2i (x - VCD,            0);
+          glVertex2i (x - VCD,            VCD);
+          glVertex2i (x - VCD + VCW,      VCD);
+          glVertex2i (x - VCD + VCW,      0);
+          glVertex2i (x - VCD,            gport->height - VCD);
+          glVertex2i (x - VCD,            gport->height);
+          glVertex2i (x - VCD + VCW,      gport->height);
+          glVertex2i (x - VCD + VCW,      gport->height - VCD);
+        }
+
+      glEnd ();
     }
 
   if (x >= 0 && show)
     {
-      draw_crosshair (xor_gc, x, y);
-      if (ghidgui->auto_pan_on && have_crosshair_attachments ())
-	{
-	  gdk_draw_rectangle (gport->drawing_area->window, xor_gc, TRUE,
-			      0, y - VCD, VCD, VCW);
-	  gdk_draw_rectangle (gport->drawing_area->window, xor_gc, TRUE,
-			      gport->width - VCD, y - VCD, VCD, VCW);
-	  gdk_draw_rectangle (gport->drawing_area->window, xor_gc, TRUE,
-			      x - VCD, 0, VCW, VCD);
-	  gdk_draw_rectangle (gport->drawing_area->window, xor_gc, TRUE,
-			      x - VCD, gport->height - VCD, VCW, VCD);
-	}
       x_prev = x;
       y_prev = y;
     }
   else
     x_prev = y_prev = -1;
+
+  glDisable (GL_COLOR_LOGIC_OP);
 }
 
 static gboolean
@@ -698,53 +745,151 @@ ghid_port_drawing_area_configure_event_cb (GtkWidget * widget,
   if (!first_time_done)
     {
       gport->colormap = gtk_widget_get_colormap (gport->top_window);
-      gport->bg_gc = gdk_gc_new (gport->drawable);
       if (gdk_color_parse (Settings.BackgroundColor, &gport->bg_color))
 	gdk_color_alloc (gport->colormap, &gport->bg_color);
       else
 	gdk_color_white (gport->colormap, &gport->bg_color);
-      gdk_gc_set_foreground (gport->bg_gc, &gport->bg_color);
 
-      gport->offlimits_gc = gdk_gc_new (gport->drawable);
       if (gdk_color_parse (Settings.OffLimitColor, &gport->offlimits_color))
 	gdk_color_alloc (gport->colormap, &gport->offlimits_color);
       else
 	gdk_color_white (gport->colormap, &gport->offlimits_color);
-      gdk_gc_set_foreground (gport->offlimits_gc, &gport->offlimits_color);
       first_time_done = TRUE;
       PCBChanged (0, NULL, 0, 0);
     }
-  if (gport->mask)
-    {
-      gdk_pixmap_unref (gport->mask);
-      gport->mask = gdk_pixmap_new (0, gport->width, gport->height, 1);
-    }
+//  if (gport->mask)
+//    {
+//      gdk_pixmap_unref (gport->mask);
+//      gport->mask = gdk_pixmap_new (0, gport->width, gport->height, 1);
+//    }
   ghid_port_ranges_scale (FALSE);
   ghid_invalidate_all ();
   RestoreCrosshair (TRUE);
   return 0;
 }
 
-
 void
 ghid_screen_update (void)
 {
-
+#if 0
   ghid_show_crosshair (FALSE);
   gdk_draw_drawable (gport->drawing_area->window, gport->bg_gc, gport->pixmap,
 		     0, 0, 0, 0, gport->width, gport->height);
   ghid_show_crosshair (TRUE);
+#endif
 }
 
+void DrawAttached (Boolean);
+
+#define Z_NEAR 3.0
 gboolean
 ghid_port_drawing_area_expose_event_cb (GtkWidget * widget,
 					GdkEventExpose * ev, GHidPort * port)
 {
+  BoxType region;
+  int eleft, eright, etop, ebottom;
+  extern HID ghid_hid;
+  GdkGLContext* pGlContext = gtk_widget_get_gl_context (widget);
+  GdkGLDrawable* pGlDrawable = gtk_widget_get_gl_drawable (widget);
+
+  /* make GL-context "current" */
+  if (!gdk_gl_drawable_gl_begin (pGlDrawable, pGlContext)) {
+    return FALSE;
+  }
+
   ghid_show_crosshair (FALSE);
-  gdk_draw_drawable (widget->window, port->bg_gc, port->pixmap,
-		     ev->area.x, ev->area.y, ev->area.x, ev->area.y,
-		     ev->area.width, ev->area.height);
+
+  glEnable (GL_BLEND);
+  glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+//  glEnable(GL_POLYGON_SMOOTH);
+//  glHint(GL_POLYGON_SMOOTH_HINT, [GL_FASTEST, GL_NICEST, or GL_DONT_CARE]);
+
+  glViewport (0, 0, widget->allocation.width, widget->allocation.height);
+
+  glEnable (GL_SCISSOR_TEST);
+  glScissor (ev->area.x,
+             widget->allocation.height - ev->area.height - ev->area.y,
+             ev->area.width, ev->area.height);
+
+  glMatrixMode (GL_PROJECTION);
+  glLoadIdentity ();
+  glOrtho (0, widget->allocation.width, widget->allocation.height, 0, 0, 100);
+  glMatrixMode (GL_MODELVIEW);
+  glLoadIdentity ();
+  glTranslatef (0.0f, 0.0f, -Z_NEAR);
+
+  glClearColor (gport->offlimits_color.red / 65535.,
+                gport->offlimits_color.green / 65535.,
+                gport->offlimits_color.blue / 65535.,
+                1.);
+
+  glClear (GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
+
+  region.X1 = MIN (Px (ev->area.x), Px (ev->area.x + ev->area.width + 1));
+  region.X2 = MAX (Px (ev->area.x), Px (ev->area.x + ev->area.width + 1));
+  region.Y1 = MIN (Py (ev->area.y), Py (ev->area.y + ev->area.height + 1));
+  region.Y2 = MAX (Py (ev->area.y), Py (ev->area.y + ev->area.height + 1));
+
+  eleft = Vx (0);  eright  = Vx (PCB->MaxWidth);
+  etop  = Vy (0);  ebottom = Vy (PCB->MaxHeight);
+
+  glColor3f (gport->bg_color.red / 65535.,
+             gport->bg_color.green / 65535.,
+             gport->bg_color.blue / 65535.);
+
+  glBegin (GL_QUADS);
+  glVertex3i (eleft,  etop,    0);
+  glVertex3i (eright, etop,    0);
+  glVertex3i (eright, ebottom, 0);
+  glVertex3i (eleft,  ebottom, 0);
+  glEnd ();
+
+  /* TODO: Background image */
+
+  hidgl_init_triangle_array (&buffer);
+  ghid_invalidate_current_gc ();
+
+  glPushMatrix ();
+  glScalef ((ghid_flip_x ? -1. : 1.) / gport->zoom,
+            (ghid_flip_y ? -1. : 1.) / gport->zoom,
+            (ghid_flip_x == ghid_flip_y) ? 1. : -1.);
+  glTranslatef (ghid_flip_x ? gport->view_x0 - PCB->MaxWidth  :
+                             -gport->view_x0,
+                ghid_flip_y ? gport->view_y0 - PCB->MaxHeight :
+                             -gport->view_y0, 0);
+  hid_expose_callback (&ghid_hid, &region, 0);
+  hidgl_flush_triangles (&buffer);
+  glPopMatrix ();
+
+  ghid_draw_grid ();
+
+  hidgl_init_triangle_array (&buffer);
+  ghid_invalidate_current_gc ();
+  glPushMatrix ();
+  glScalef ((ghid_flip_x ? -1. : 1.) / gport->zoom,
+            (ghid_flip_y ? -1. : 1.) / gport->zoom, 1);
+  glTranslatef (ghid_flip_x ? gport->view_x0 - PCB->MaxWidth  :
+                             -gport->view_x0,
+                ghid_flip_y ? gport->view_y0 - PCB->MaxHeight :
+                             -gport->view_y0, 0);
+  DrawAttached (TRUE);
+  DrawMark (TRUE);
+  hidgl_flush_triangles (&buffer);
+  glPopMatrix ();
+
   ghid_show_crosshair (TRUE);
+
+  hidgl_flush_triangles (&buffer);
+
+  if (gdk_gl_drawable_is_double_buffered (pGlDrawable))
+    gdk_gl_drawable_swap_buffers (pGlDrawable);
+  else
+    glFlush ();
+
+  /* end drawing to current GL-context */
+  gdk_gl_drawable_gl_end (pGlDrawable);
+
   return FALSE;
 }
 
@@ -877,6 +1022,14 @@ ghid_port_window_motion_cb (GtkWidget * widget,
   gdouble dx, dy;
   static gint x_prev = -1, y_prev = -1;
   gboolean moved;
+  GdkGLContext* pGlContext = gtk_widget_get_gl_context (widget);
+  GdkGLDrawable* pGlDrawable = gtk_widget_get_gl_drawable (widget);
+
+  /* make GL-context "current" */
+  if (!gdk_gl_drawable_gl_begin (pGlDrawable, pGlContext)) {
+    printf ("GL THingy returned\n");
+    return FALSE;
+  }
 
   if (out->panning)
     {
@@ -900,6 +1053,14 @@ ghid_port_window_motion_cb (GtkWidget * widget,
   ghid_show_crosshair (TRUE);
   if (moved && have_crosshair_attachments ())
     ghid_draw_area_update (gport, NULL);
+
+  if (gdk_gl_drawable_is_double_buffered (pGlDrawable))
+    gdk_gl_drawable_swap_buffers (pGlDrawable);
+  else
+    glFlush ();
+
+  /* end drawing to current GL-context */
+  gdk_gl_drawable_gl_end (pGlDrawable);
   return FALSE;
 }
 
@@ -939,7 +1100,7 @@ ghid_port_window_enter_cb (GtkWidget * widget,
       RestoreCrosshair (TRUE);
       cursor_in_viewport = TRUE;
     }
-	  
+
   return FALSE;
 }
 
diff --git a/src/hid/gtk/gui-pinout-preview.c b/src/hid/gtk/gui-pinout-preview.c
index 212d37a..b9d57da 100644
--- a/src/hid/gtk/gui-pinout-preview.c
+++ b/src/hid/gtk/gui-pinout-preview.c
@@ -150,12 +150,15 @@ pinout_set_data (GhidPinoutPreview * pinout, ElementType * element)
 }
 
 
+#define Z_NEAR 3.0
+
 static gboolean
-ghid_pinout_preview_expose (GtkWidget * widget, GdkEventExpose * event)
+ghid_pinout_preview_expose (GtkWidget * widget, GdkEventExpose * ev)
 {
   extern HID ghid_hid;
+  GdkGLContext* pGlContext = gtk_widget_get_gl_context (widget);
+  GdkGLDrawable* pGlDrawable = gtk_widget_get_gl_drawable (widget);
   GhidPinoutPreview *pinout = GHID_PINOUT_PREVIEW (widget);
-  GdkDrawable *save_drawable;
   double save_zoom;
   int da_w, da_h;
   int save_left, save_top;
@@ -171,9 +174,7 @@ ghid_pinout_preview_expose (GtkWidget * widget, GdkEventExpose * event)
   save_view_width = gport->view_width;
   save_view_height = gport->view_height;
 
-  /* Setup drawable and zoom factor for drawing routines
-   */
-  save_drawable = gport->drawable;
+  /* Setup zoom factor for drawing routines */
 
   gdk_window_get_geometry (widget->window, 0, 0, &da_w, &da_h, 0);
   xz = (double) pinout->x_max / da_w;
@@ -183,7 +184,6 @@ ghid_pinout_preview_expose (GtkWidget * widget, GdkEventExpose * event)
   else
     gport->zoom = yz;
 
-  gport->drawable = widget->window;
   gport->width = da_w;
   gport->height = da_h;
   gport->view_width = da_w * gport->zoom;
@@ -191,13 +191,57 @@ ghid_pinout_preview_expose (GtkWidget * widget, GdkEventExpose * event)
   gport->view_x0 = (pinout->x_max - gport->view_width) / 2;
   gport->view_y0 = (pinout->y_max - gport->view_height) / 2;
 
-  /* clear background */
-  gdk_draw_rectangle (widget->window, gport->bg_gc, TRUE, 0, 0, da_w, da_h);
+  /* make GL-context "current" */
+  if (!gdk_gl_drawable_gl_begin (pGlDrawable, pGlContext)) {
+    return FALSE;
+  }
+
+  glEnable (GL_BLEND);
+  glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+  glViewport (0, 0, widget->allocation.width, widget->allocation.height);
+
+  glEnable (GL_SCISSOR_TEST);
+  glScissor (ev->area.x,
+             widget->allocation.height - ev->area.height - ev->area.y,
+             ev->area.width, ev->area.height);
+
+  glMatrixMode (GL_PROJECTION);
+  glLoadIdentity ();
+  glOrtho (0, widget->allocation.width, widget->allocation.height, 0, 0, 100);
+  glMatrixMode (GL_MODELVIEW);
+  glLoadIdentity ();
+  glTranslatef (0.0f, 0.0f, -Z_NEAR);
+
+  glClearColor (gport->bg_color.red / 65535.,
+                gport->bg_color.green / 65535.,
+                gport->bg_color.blue / 65535.,
+                1.);
+
+  glClear (GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
 
   /* call the drawing routine */
+  hidgl_init_triangle_array (&buffer);
+  ghid_invalidate_current_gc ();
+  glPushMatrix ();
+  glScalef ((ghid_flip_x ? -1. : 1.) / gport->zoom,
+            (ghid_flip_y ? -1. : 1.) / gport->zoom, 1);
+  glTranslatef (ghid_flip_x ? gport->view_x0 - PCB->MaxWidth  :
+                             -gport->view_x0,
+                ghid_flip_y ? gport->view_y0 - PCB->MaxHeight :
+                             -gport->view_y0, 0);
   hid_expose_callback (&ghid_hid, NULL, &pinout->element);
+  hidgl_flush_triangles (&buffer);
+  glPopMatrix ();
+
+  if (gdk_gl_drawable_is_double_buffered (pGlDrawable))
+    gdk_gl_drawable_swap_buffers (pGlDrawable);
+  else
+    glFlush ();
+
+  /* end drawing to current GL-context */
+  gdk_gl_drawable_gl_end (pGlDrawable);
 
-  gport->drawable = save_drawable;
   gport->zoom = save_zoom;
   gport->width = save_width;
   gport->height = save_height;
@@ -219,6 +263,40 @@ enum
 static GObjectClass *ghid_pinout_preview_parent_class = NULL;
 
 
+/*! \brief GObject constructor
+ *
+ *  \par Function Description
+ *  Chain up and construct the object, then setup the
+ *  necessary state for our widget now it is constructed.
+ *
+ *  \param [in] type                    The GType of object to be constructed
+ *  \param [in] n_construct_properties  Number of construct properties
+ *  \param [in] contruct_params         The construct properties
+ *
+ *  \returns The GObject having just been constructed.
+ */
+static GObject *
+ghid_pinout_preview_constructor (GType type,
+                                 guint n_construct_properties,
+                                 GObjectConstructParam *construct_properties)
+{
+  GObject *object;
+
+  /* chain up to constructor of parent class */
+  object = G_OBJECT_CLASS (ghid_pinout_preview_parent_class)->
+    constructor (type, n_construct_properties, construct_properties);
+
+  gtk_widget_set_gl_capability (GTK_WIDGET (object),
+                                gport->glconfig,
+                                NULL,
+                                TRUE,
+                                GDK_GL_RGBA_TYPE);
+
+  return object;
+}
+
+
+
 /*! \brief GObject finalise handler
  *
  *  \par Function Description
@@ -310,6 +388,7 @@ ghid_pinout_preview_class_init (GhidPinoutPreviewClass * klass)
   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
   GtkWidgetClass *gtk_widget_class = GTK_WIDGET_CLASS (klass);
 
+  gobject_class->constructor = ghid_pinout_preview_constructor;
   gobject_class->finalize = ghid_pinout_preview_finalize;
   gobject_class->set_property = ghid_pinout_preview_set_property;
   gobject_class->get_property = ghid_pinout_preview_get_property;
diff --git a/src/hid/gtk/gui-render-pixmap.c b/src/hid/gtk/gui-render-pixmap.c
index b24e6c9..4caddf2 100644
--- a/src/hid/gtk/gui-render-pixmap.c
+++ b/src/hid/gtk/gui-render-pixmap.c
@@ -39,19 +39,24 @@
 RCSID ("$Id$");
 
 
+#define Z_NEAR 3.0
+
+
 GdkPixmap *
 ghid_render_pixmap (int cx, int cy, double zoom, int width, int height, int depth)
 {
   extern HID ghid_hid;
+  GdkGLConfig *glconfig;
   GdkPixmap *pixmap;
-  GdkDrawable *save_drawable;
+  GdkGLPixmap *glpixmap;
+  GdkGLContext* glcontext;
+  GdkGLDrawable* gldrawable;
   double save_zoom;
   int save_left, save_top;
   int save_width, save_height;
   int save_view_width, save_view_height;
   BoxType region;
 
-  save_drawable = gport->drawable;
   save_zoom = gport->zoom;
   save_width = gport->width;
   save_height = gport->height;
@@ -60,12 +65,21 @@ ghid_render_pixmap (int cx, int cy, double zoom, int width, int height, int dept
   save_view_width = gport->view_width;
   save_view_height = gport->view_height;
 
+  /* Setup rendering context for drawing routines
+   */
+
+  glconfig = gdk_gl_config_new_by_mode (GDK_GL_MODE_RGB     |
+                                        GDK_GL_MODE_STENCIL |
+//                                        GDK_GL_MODE_DEPTH   |
+                                        GDK_GL_MODE_SINGLE);
+
   pixmap = gdk_pixmap_new (NULL, width, height, depth);
+  glpixmap = gdk_pixmap_set_gl_capability (pixmap, glconfig, NULL);
+  gldrawable = GDK_GL_DRAWABLE (glpixmap);
+  glcontext = gdk_gl_context_new (gldrawable, NULL, FALSE, GDK_GL_RGBA_TYPE);
 
-  /* Setup drawable and zoom factor for drawing routines
-   */
+  /* Setup zoom factor for drawing routines */
 
-  gport->drawable = pixmap;
   gport->zoom = zoom;
   gport->width = width;
   gport->height = height;
@@ -76,17 +90,62 @@ ghid_render_pixmap (int cx, int cy, double zoom, int width, int height, int dept
   gport->view_y0 = ghid_flip_y ? PCB->MaxHeight - cy : cy;
   gport->view_y0 -= gport->view_width  / 2;
 
-  /* clear background */
-  gdk_draw_rectangle (pixmap, gport->bg_gc, TRUE, 0, 0, width, height);
+  /* make GL-context "current" */
+  if (!gdk_gl_drawable_gl_begin (gldrawable, glcontext)) {
+    return NULL;
+  }
+
+  glEnable (GL_BLEND);
+  glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+  glViewport (0, 0, width, height);
+
+  glEnable (GL_SCISSOR_TEST);
+  glScissor (0, 0, width, height);
+
+  glMatrixMode (GL_PROJECTION);
+  glLoadIdentity ();
+  glOrtho (0, width, height, 0, 0, 100);
+  glMatrixMode (GL_MODELVIEW);
+  glLoadIdentity ();
+  glTranslatef (0.0f, 0.0f, -Z_NEAR);
+
+  glClearColor (gport->bg_color.red / 65535.,
+                gport->bg_color.green / 65535.,
+                gport->bg_color.blue / 65535.,
+                1.);
+  glClearStencil (0);
+  glClear (GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
 
   /* call the drawing routine */
+  hidgl_init_triangle_array (&buffer);
+  ghid_invalidate_current_gc ();
+  glPushMatrix ();
+  glScalef ((ghid_flip_x ? -1. : 1.) / gport->zoom,
+            (ghid_flip_y ? -1. : 1.) / gport->zoom, 1);
+  glTranslatef (ghid_flip_x ? gport->view_x0 - PCB->MaxWidth  :
+                             -gport->view_x0,
+                ghid_flip_y ? gport->view_y0 - PCB->MaxHeight :
+                             -gport->view_y0, 0);
   region.X1 = MIN(Px(0), Px(gport->width + 1));
   region.Y1 = MIN(Py(0), Py(gport->height + 1));
   region.X2 = MAX(Px(0), Px(gport->width + 1));
   region.Y2 = MAX(Py(0), Py(gport->height + 1));
   hid_expose_callback (&ghid_hid, &region, NULL);
+  hidgl_flush_triangles (&buffer);
+  glPopMatrix ();
+
+  glFlush ();
+
+  /* end drawing to current GL-context */
+  gdk_gl_drawable_gl_end (gldrawable);
+//  gdk_gl_context_destroy (glcontext);
+
+  gdk_pixmap_unset_gl_capability (pixmap);
+
+  g_object_unref (glconfig);
+  g_object_unref (glcontext);
 
-  gport->drawable = save_drawable;
   gport->zoom = save_zoom;
   gport->width = save_width;
   gport->height = save_height;
diff --git a/src/hid/gtk/gui-top-window.c b/src/hid/gtk/gui-top-window.c
index 3d3896f..197e886 100644
--- a/src/hid/gtk/gui-top-window.c
+++ b/src/hid/gtk/gui-top-window.c
@@ -2297,6 +2297,11 @@ ghid_build_pcb_top_window (void)
   gtk_box_pack_start (GTK_BOX (hbox), viewport, TRUE, TRUE, 0);
 
   gport->drawing_area = gtk_drawing_area_new ();
+  gtk_widget_set_gl_capability (gport->drawing_area,
+                                gport->glconfig,
+                                NULL,
+                                TRUE,
+                                GDK_GL_RGBA_TYPE);
 
   gtk_widget_add_events (gport->drawing_area, GDK_EXPOSURE_MASK
 			 | GDK_LEAVE_NOTIFY_MASK | GDK_ENTER_NOTIFY_MASK
@@ -2672,11 +2677,22 @@ ghid_parse_arguments (int *argc, char ***argv)
   gtk_disable_setlocale ();
 
   gtk_init (argc, argv);
+  gtk_gl_init(argc, argv);
 
   gport = &ghid_port;
   gport->zoom = 300.0;
   pixel_slop = 300;
 
+  /* setup GL-context */
+  gport->glconfig = gdk_gl_config_new_by_mode (GDK_GL_MODE_RGBA    |
+                                               GDK_GL_MODE_STENCIL |
+//                                               GDK_GL_MODE_DEPTH   |
+                                               GDK_GL_MODE_DOUBLE);
+  if (!gport->glconfig) {
+    printf("Could not setup GL-context!\n");
+    return; /* Should we abort? */
+  }
+
   ghid_config_files_read (argc, argv);
 
   Settings.AutoPlace = 0;
diff --git a/src/hid/gtk/gui.h b/src/hid/gtk/gui.h
index 0a2e747..2ebed06 100644
--- a/src/hid/gtk/gui.h
+++ b/src/hid/gtk/gui.h
@@ -37,6 +37,17 @@
 
 #include <gtk/gtk.h>
 
+/* The Linux OpenGL ABI 1.0 spec requires that we define
+ * GL_GLEXT_PROTOTYPES before including gl.h or glx.h for extensions
+ * in order to get prototypes:
+ *   http://www.opengl.org/registry/ABI/
+ */
+#ifdef ENABLE_GL
+#  define GL_GLEXT_PROTOTYPES 1
+#  include <GL/gl.h>
+#  include <gtk/gtkgl.h>
+#  include "hid/common/hidgl.h"
+#endif
 
 
   /* Silk and rats lines are the two additional selectable to draw on.
@@ -164,7 +175,13 @@ typedef struct
   GdkDrawable *drawable;	/* Current drawable for drawing routines */
   gint width, height;
 
-  GdkGC *bg_gc, *offlimits_gc, *mask_gc, *u_gc, *grid_gc;
+#ifdef ENABLE_GL
+  GdkGLConfig *glconfig;
+#endif
+
+  gint trans_lines;
+
+//  GdkGC *bg_gc, *offlimits_gc, *mask_gc, *u_gc, *grid_gc;
 
   GdkColor bg_color, offlimits_color, grid_color;
 
@@ -279,6 +296,7 @@ void ghid_get_pointer (gint *, gint *);
 
 /* gui-output-events.c function prototypes.
 */
+
 void ghid_port_ranges_changed (void);
 void ghid_port_ranges_zoom (gdouble zoom);
 gboolean ghid_port_ranges_pan (gdouble x, gdouble y, gboolean relative);
@@ -494,7 +512,7 @@ GdkPixmap *ghid_render_pixmap (int cx,
 			       int height,
 			       int depth);
 
-/* gtkhid-gdk.c */
+/* gtkhid-gdk.c OR gtkhid-gl.c */
 hidGC ghid_make_gc (void);
 void ghid_destroy_gc (hidGC);
 void ghid_draw_grid (void);
@@ -515,7 +533,9 @@ void ghid_fill_polygon (hidGC gc, int n_coords, int *x, int *y);
 void ghid_fill_rect (hidGC gc, int x1, int y1, int x2, int y2);
 
 /* gtkhid-main.c */
+
 void ghid_invalidate_all ();
+void ghid_invalidate_current_gc ();
 void ghid_get_coords (const char *msg, int *x, int *y);
 gint PCBChanged (int argc, char **argv, int x, int y);
 

commit 1b63d27b652009e7a6581c869fc021e73013ab2a
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    Make --enable-gl default when building the GTK HID

diff --git a/configure.ac b/configure.ac
index 964e235..863e2ee 100644
--- a/configure.ac
+++ b/configure.ac
@@ -392,8 +392,12 @@ fi
 AC_MSG_CHECKING([for whether to use GL drawing])
 AC_ARG_ENABLE([gl],
 [  --enable-gl           Enable GL drawing (with GTK HID)],
-[],[enable_gl=no])
-
+[],[
+	case " $with_gui " in
+		*\ gtk\ *) enable_gl=yes;;
+		* ) enable_gl=no;;
+	esac
+])
 AC_MSG_RESULT([$enable_gl])
 AM_CONDITIONAL(USE_GL, test x$enable_gl = xyes)
 

commit 09ed7763b9805678da73dd81a8c7f79d370741c7
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    Add configure checks for GtkGLEext, add to CFLAGS and LIBS
    
    *** TODO: Need separate tests for libgl and libglut etc.. ***

diff --git a/configure.ac b/configure.ac
index a220a82..964e235 100644
--- a/configure.ac
+++ b/configure.ac
@@ -388,6 +388,45 @@ $DBUS_PKG_ERRORS])]
 
 fi
 
+
+AC_MSG_CHECKING([for whether to use GL drawing])
+AC_ARG_ENABLE([gl],
+[  --enable-gl           Enable GL drawing (with GTK HID)],
+[],[enable_gl=no])
+
+AC_MSG_RESULT([$enable_gl])
+AM_CONDITIONAL(USE_GL, test x$enable_gl = xyes)
+
+if test "x$enable_gl" = "xyes"; then
+	case " $with_gui " in
+		*\ gtk\ *) ;;
+		* ) AC_MSG_ERROR([GL drawing enabled but only works with the GTK HID.
+Either do not use --enable-gl or enable the gtk HID.])
+	;;
+	esac
+
+# FIXME... what do we need to check for determining we have GL? Is it headers, API ?
+
+	AC_CHECK_HEADERS(GL/gl.h)
+	case $ac_cv_header_GL_gl_h in
+	  no )
+	    AC_MSG_ERROR([You don't seem to have the GL library headers installed.])
+	    ;;
+	  * ) ;;
+	esac
+
+	AC_CHECK_HEADERS(GL/glu.h)
+	case $ac_cv_header_GL_glu_h in
+	  no )
+	    AC_MSG_ERROR([You don't seem to have the GL glu library headers installed.])
+	    ;;
+	  * ) ;;
+	esac
+
+	AC_DEFINE([ENABLE_GL], 1,
+		[Define to 1 if GL support is to be compiled in])
+fi
+
 AC_MSG_CHECKING([for which printer to use])
 AC_ARG_WITH([printer],
 [  --with-printer= 	  Specify the printer: lpr [[default=lpr]]],
@@ -728,6 +767,17 @@ $GTK_PKG_ERRORS])]
 	fi
 
 	GLIB_VERSION=`$PKG_CONFIG glib-2.0 --modversion`
+
+	if test "x$enable_gl" = "xyes"; then
+		# Check for GtkGLExt
+		PKG_CHECK_MODULES(GTKGLEXT, gtkglext-1.0 >= 1.0.0, , [AC_MSG_ERROR([
+*** Required version of gtkglext is not installed - please install first ***
+Please review the following errors:
+$GTKGLEXT_PKG_ERRORS])]
+		)
+	GTKGLEXT_VER=`$PKG_CONFIG gtkglext-1.0 --modversion`
+	fi
+
 	;;
 
       gcode|nelma|png )
@@ -1015,8 +1065,8 @@ AM_CONDITIONAL(DEBUG_BUILD, test x$enable_debug = xyes)
 
 # ------------- Complete set of CFLAGS and LIBS -------------------
 
-CFLAGS="$CFLAGS $X_CFLAGS $DBUS_CFLAGS $GLIB_CFLAGS $GTK_CFLAGS $CAIRO_CFLAGS"
-LIBS="$LIBS $XM_LIBS $DBUS_LIBS $X_LIBS $GLIB_LIBS $GTK_LIBS $DMALLOC_LIBS $GD_LIBS $INTLLIBS $CAIRO_LIBS"
+CFLAGS="$CFLAGS $X_CFLAGS $DBUS_CFLAGS $GLIB_CFLAGS $GTK_CFLAGS $CAIRO_CFLAGS $GTKGLEXT_CFLAGS"
+LIBS="$LIBS $XM_LIBS $DBUS_LIBS $X_LIBS $GLIB_LIBS $GTK_LIBS $DMALLOC_LIBS $GD_LIBS $INTLLIBS $CAIRO_LIBS $GTKGLEXT_LIBS"
 
 
 # if we have gcc then add -Wall

commit 56567acb4aa14cc324809c83f4dce6b0ae4cf944
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    Only snap to pads on the active layer

diff --git a/src/crosshair.c b/src/crosshair.c
index 923ab72..d54fad7 100644
--- a/src/crosshair.c
+++ b/src/crosshair.c
@@ -838,20 +838,53 @@ FitCrosshairIntoGrid (LocationType X, LocationType Y)
 
   if (PCB->RatDraw || TEST_FLAG (SNAPPINFLAG, PCB))
     ans = SearchScreenGridSlop (Crosshair.X, Crosshair.Y,
-                                PAD_TYPE | PIN_TYPE, &ptr1, &ptr2, &ptr3);
+                                PAD_TYPE, &ptr1, &ptr2, &ptr3);
   else
     ans = NO_TYPE;
 
   /* Avoid self-snapping when moving */
-  if (Settings.Mode == MOVE_MODE &&
-      Crosshair.AttachedObject.Type == ELEMENT_TYPE)
+  if (ans && Settings.Mode == MOVE_MODE &&
+      Crosshair.AttachedObject.Type == ELEMENT_TYPE &&
+      ptr1 == Crosshair.AttachedObject.Ptr1)
+    ans = NO_TYPE;
+
+  if (ans && (Settings.Mode == LINE_MODE ||
+              (Settings.Mode == MOVE_MODE &&
+               Crosshair.AttachedObject.Type == LINEPOINT_TYPE)))
     {
-      if ((ans & (PAD_TYPE | PIN_TYPE)) &&
-           ptr1 == Crosshair.AttachedObject.Ptr1)
+      PadTypePtr pad = (PadTypePtr) ptr2;
+      LayerType *desired_layer;
+      Cardinal desired_group;
+      Cardinal SLayer, CLayer;
+      int found_our_layer = false;
+
+      desired_layer = CURRENT;
+      if (Settings.Mode == MOVE_MODE &&
+          Crosshair.AttachedObject.Type == LINEPOINT_TYPE)
+        {
+          desired_layer = (LayerType *)Crosshair.AttachedObject.Ptr1;
+        }
+
+      /* find layer groups of the component side and solder side */
+      SLayer = GetLayerGroupNumberByNumber (max_layer + SOLDER_LAYER);
+      CLayer = GetLayerGroupNumberByNumber (max_layer + COMPONENT_LAYER);
+      desired_group = TEST_FLAG (ONSOLDERFLAG, pad) ? SLayer : CLayer;
+
+      GROUP_LOOP (PCB->Data, desired_group);
+      {
+        if (layer == desired_layer)
+          {
+            found_our_layer = true;
+            break;
+          }
+      }
+      END_LOOP;
+
+      if (found_our_layer == false)
         ans = NO_TYPE;
     }
 
-  if (ans & PAD_TYPE)
+  if (ans)
     {
       PadTypePtr pad = (PadTypePtr) ptr2;
       LocationType px, py;
@@ -869,7 +902,20 @@ FitCrosshairIntoGrid (LocationType X, LocationType Y)
           nearest = sq_dist;
         }
     }
-  else if (ans & PIN_TYPE)
+
+  if (PCB->RatDraw || TEST_FLAG (SNAPPINFLAG, PCB))
+    ans = SearchScreenGridSlop (Crosshair.X, Crosshair.Y,
+                                PIN_TYPE, &ptr1, &ptr2, &ptr3);
+  else
+    ans = NO_TYPE;
+
+  /* Avoid self-snapping when moving */
+  if (ans && Settings.Mode == MOVE_MODE &&
+      Crosshair.AttachedObject.Type == ELEMENT_TYPE &&
+      ptr1 == Crosshair.AttachedObject.Ptr1)
+    ans = NO_TYPE;
+
+  if (ans)
     {
       PinTypePtr pin = (PinTypePtr) ptr2;
       sq_dist = SQUARE (pin->X - Crosshair.X) + SQUARE (pin->Y - Crosshair.Y);

commit 44d00a5bee19f5b438524f7d1a7d71740f27368e
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    Improve grid snapping heuristics

diff --git a/src/crosshair.c b/src/crosshair.c
index b9a3dd2..923ab72 100644
--- a/src/crosshair.c
+++ b/src/crosshair.c
@@ -774,6 +774,7 @@ FitCrosshairIntoGrid (LocationType X, LocationType Y)
 {
   LocationType x2, y2, x0, y0;
   void *ptr1, *ptr2, *ptr3;
+  float nearest, sq_dist;
   int ans;
 
   x0 = 0;
@@ -783,41 +784,6 @@ FitCrosshairIntoGrid (LocationType X, LocationType Y)
   Crosshair.X = MIN (Crosshair.MaxX, MAX (Crosshair.MinX, X));
   Crosshair.Y = MIN (Crosshair.MaxY, MAX (Crosshair.MinY, Y));
 
-  if (PCB->RatDraw || TEST_FLAG (SNAPPINFLAG, PCB))
-    {
-      ans =
-	SearchScreen (Crosshair.X, Crosshair.Y,
-		      PAD_TYPE | PIN_TYPE, &ptr1, &ptr2, &ptr3);
-      if (ans == NO_TYPE && !PCB->RatDraw)
-	ans =
-	  SearchScreen (Crosshair.X, Crosshair.Y, VIA_TYPE | LINEPOINT_TYPE,
-			&ptr1, &ptr2, &ptr3);
-      if (ans == NO_TYPE && !PCB->RatDraw)
-	ans =
-	  SearchScreen (Crosshair.X, Crosshair.Y, ELEMENT_TYPE, &ptr1, &ptr2,
-			&ptr3);
-    }
-  else
-    ans = NO_TYPE;
-
-  /* avoid self-snapping */
-  if (Settings.Mode == MOVE_MODE)
-    {
-      switch (Crosshair.AttachedObject.Type)
-	{
-	case ELEMENT_TYPE:
-	  if ((ans & (PAD_TYPE | PIN_TYPE)) &&
-	      ptr1 == Crosshair.AttachedObject.Ptr1)
-	    ans = NO_TYPE;
-	  break;
-	case VIA_TYPE:
-	  /* just avoid snapping to any other vias */
-	  if (ans & PIN_TYPES)
-	    ans = NO_TYPE;
-	  break;
-	}
-    }
-
   if (PCB->RatDraw)
     {
       x0 = -600;
@@ -867,6 +833,24 @@ FitCrosshairIntoGrid (LocationType X, LocationType Y)
 	}
 
     }
+
+  nearest = -1;
+
+  if (PCB->RatDraw || TEST_FLAG (SNAPPINFLAG, PCB))
+    ans = SearchScreenGridSlop (Crosshair.X, Crosshair.Y,
+                                PAD_TYPE | PIN_TYPE, &ptr1, &ptr2, &ptr3);
+  else
+    ans = NO_TYPE;
+
+  /* Avoid self-snapping when moving */
+  if (Settings.Mode == MOVE_MODE &&
+      Crosshair.AttachedObject.Type == ELEMENT_TYPE)
+    {
+      if ((ans & (PAD_TYPE | PIN_TYPE)) &&
+           ptr1 == Crosshair.AttachedObject.Ptr1)
+        ans = NO_TYPE;
+    }
+
   if (ans & PAD_TYPE)
     {
       PadTypePtr pad = (PadTypePtr) ptr2;
@@ -875,64 +859,135 @@ FitCrosshairIntoGrid (LocationType X, LocationType Y)
       px = (pad->Point1.X + pad->Point2.X) / 2;
       py = (pad->Point1.Y + pad->Point2.Y) / 2;
 
-      if (!gui->shift_is_pressed()
-	  || (SQUARE (x0 - Crosshair.X) + SQUARE (y0 - Crosshair.Y) >
-	      SQUARE (px - Crosshair.X) + SQUARE (py - Crosshair.Y)))
-	{
-	  x0 = px;
-	  y0 = py;
-	}
+      sq_dist = SQUARE (px - Crosshair.X) + SQUARE (py - Crosshair.Y);
+
+      if (!gui->shift_is_pressed() ||
+          SQUARE (x0 - Crosshair.X) + SQUARE (y0 - Crosshair.Y) > sq_dist)
+        {
+          x0 = px;
+          y0 = py;
+          nearest = sq_dist;
+        }
+    }
+  else if (ans & PIN_TYPE)
+    {
+      PinTypePtr pin = (PinTypePtr) ptr2;
+      sq_dist = SQUARE (pin->X - Crosshair.X) + SQUARE (pin->Y - Crosshair.Y);
+      if ((nearest == -1 || sq_dist < nearest) &&
+          (!gui->shift_is_pressed() ||
+           SQUARE (x0 - Crosshair.X) + SQUARE (y0 - Crosshair.Y) > sq_dist))
+        {
+          x0 = pin->X;
+          y0 = pin->Y;
+          nearest = sq_dist;
+        }
+    }
+
+  if (TEST_FLAG (SNAPPINFLAG, PCB))
+    ans = SearchScreenGridSlop (Crosshair.X, Crosshair.Y,
+                                VIA_TYPE, &ptr1, &ptr2, &ptr3);
+  else
+    ans = NO_TYPE;
+
+  /* Avoid snapping vias to any other vias */
+  if (Settings.Mode == MOVE_MODE &&
+      Crosshair.AttachedObject.Type == VIA_TYPE)
+    {
+        if (ans & PIN_TYPES)
+          ans = NO_TYPE;
     }
 
-  else if (ans & (PIN_TYPE | VIA_TYPE))
+  if (ans)
     {
       PinTypePtr pin = (PinTypePtr) ptr2;
-      if (!gui->shift_is_pressed()
-	  || (SQUARE (x0 - Crosshair.X) +
-	      SQUARE (y0 - Crosshair.Y) >
-	      SQUARE (pin->X - Crosshair.X) + SQUARE (pin->Y - Crosshair.Y)))
-	{
-	  x0 = pin->X;
-	  y0 = pin->Y;
-	}
+      sq_dist = SQUARE (pin->X - Crosshair.X) + SQUARE (pin->Y - Crosshair.Y);
+      if ((nearest == -1 || sq_dist < nearest) &&
+          (!gui->shift_is_pressed() ||
+           SQUARE (x0 - Crosshair.X) + SQUARE (y0 - Crosshair.Y) > sq_dist))
+        {
+          x0 = pin->X;
+          y0 = pin->Y;
+          nearest = sq_dist;
+        }
     }
-  else if (ans & LINEPOINT_TYPE)
+
+  if (TEST_FLAG (SNAPPINFLAG, PCB))
+    ans = SearchScreenGridSlop (Crosshair.X, Crosshair.Y,
+                                LINEPOINT_TYPE, &ptr1, &ptr2, &ptr3);
+  else
+    ans = NO_TYPE;
+
+  if (ans)
     {
       PointTypePtr pnt = (PointTypePtr) ptr3;
-      if (((x0 - Crosshair.X) * (x0 - Crosshair.X) +
-	   (y0 - Crosshair.Y) * (y0 - Crosshair.Y)) >
-	  ((pnt->X - Crosshair.X) * (pnt->X - Crosshair.X) +
-	   (pnt->Y - Crosshair.Y) * (pnt->Y - Crosshair.Y)))
-	{
-	  x0 = pnt->X;
-	  y0 = pnt->Y;
-	}
+      sq_dist = SQUARE (pnt->X - Crosshair.X) + SQUARE (pnt->Y - Crosshair.Y);
+      if ((nearest == -1 || sq_dist < nearest) &&
+          (!gui->shift_is_pressed() ||
+           SQUARE (x0 - Crosshair.X) + SQUARE (y0 - Crosshair.Y) > sq_dist))
+        {
+          x0 = pnt->X;
+          y0 = pnt->Y;
+          nearest = sq_dist;
+        }
     }
-  else if (ans & ELEMENT_TYPE)
+
+  if (TEST_FLAG (SNAPPINFLAG, PCB))
+    ans = SearchScreenGridSlop (Crosshair.X, Crosshair.Y,
+                                POLYGONPOINT_TYPE, &ptr1, &ptr2, &ptr3);
+  else
+    ans = NO_TYPE;
+
+  if (ans)
+    {
+      PointTypePtr pnt = (PointTypePtr) ptr3;
+      sq_dist = SQUARE (pnt->X - Crosshair.X) + SQUARE (pnt->Y - Crosshair.Y);
+      if ((nearest == -1 || sq_dist < nearest) &&
+          (!gui->shift_is_pressed() ||
+           SQUARE (x0 - Crosshair.X) + SQUARE (y0 - Crosshair.Y) > sq_dist))
+        {
+          x0 = pnt->X;
+          y0 = pnt->Y;
+          nearest = sq_dist;
+        }
+    }
+
+
+  if (PCB->RatDraw || TEST_FLAG (SNAPPINFLAG, PCB))
+    ans = SearchScreenGridSlop (Crosshair.X, Crosshair.Y,
+                                ELEMENT_TYPE, &ptr1, &ptr2, &ptr3);
+  else
+    ans = NO_TYPE;
+
+  if (ans & ELEMENT_TYPE)
     {
       ElementTypePtr el = (ElementTypePtr) ptr1;
-      if (SQUARE (x0 - Crosshair.X) + SQUARE (y0 - Crosshair.Y) >
-	  SQUARE (el->MarkX - Crosshair.X) + SQUARE (el->MarkY - Crosshair.Y))
-	{
-	  x0 = el->MarkX;
-	  y0 = el->MarkY;
-	}
+      sq_dist = SQUARE (el->MarkX - Crosshair.X) + SQUARE (el->MarkY - Crosshair.Y);
+      if ((nearest == -1 || sq_dist < nearest) &&
+//          (!gui->shift_is_pressed() ||
+           SQUARE (x0 - Crosshair.X) + SQUARE (y0 - Crosshair.Y) > sq_dist)
+        {
+          x0 = el->MarkX;
+          y0 = el->MarkY;
+          nearest = sq_dist;
+        }
     }
+
   if (x0 >= 0 && y0 >= 0)
     {
       Crosshair.X = x0;
       Crosshair.Y = y0;
     }
+
   if (Settings.Mode == ARROW_MODE)
     {
-	ans =
-	  SearchScreen (Crosshair.X, Crosshair.Y, LINEPOINT_TYPE,
-			&ptr1, &ptr2, &ptr3);
-	if (ans == NO_TYPE)
-	  hid_action("PointCursor");
-	else if (!TEST_FLAG(SELECTEDFLAG, (LineType *)ptr2))
-	  hid_actionl("PointCursor","True", NULL);
+      ans = SearchScreenGridSlop (Crosshair.X, Crosshair.Y,
+                                  LINEPOINT_TYPE, &ptr1, &ptr2, &ptr3);
+      if (ans == NO_TYPE)
+        hid_action("PointCursor");
+      else if (!TEST_FLAG(SELECTEDFLAG, (LineType *)ptr2))
+        hid_actionl("PointCursor","True", NULL);
     }
+
   if (Settings.Mode == LINE_MODE
       && Crosshair.AttachedLine.State != STATE_FIRST
       && TEST_FLAG (AUTODRCFLAG, PCB))
diff --git a/src/search.c b/src/search.c
index 3f23ff4..c05a4b4 100644
--- a/src/search.c
+++ b/src/search.c
@@ -1601,3 +1601,17 @@ SearchScreen (LocationType X, LocationType Y, int Type, void **Result1,
 				X, Y, SLOP * pixel_slop);
   return (ans);
 }
+
+/* ---------------------------------------------------------------------------
+ * searches the cursor position for the type
+ */
+int
+SearchScreenGridSlop (LocationType X, LocationType Y, int Type, void **Result1,
+	      void **Result2, void **Result3)
+{
+  int ans;
+
+  ans = SearchObjectByLocation (Type, Result1, Result2, Result3,
+				X, Y, PCB->Grid / 2);
+  return (ans);
+}
diff --git a/src/search.h b/src/search.h
index ae71967..add5661 100644
--- a/src/search.h
+++ b/src/search.h
@@ -85,6 +85,7 @@ bool IsPointInBox (LocationType, LocationType, BoxTypePtr, BDimension);
 int SearchObjectByLocation (int, void **, void **, void **, LocationType,
 			    LocationType, BDimension);
 int SearchScreen (LocationType, LocationType, int, void **, void **, void **);
+int SearchScreenGridSlop (LocationType, LocationType, int, void **, void **, void **);
 int SearchObjectByID (DataTypePtr, void **, void **, void **, int, int);
 ElementTypePtr SearchElementByName (DataTypePtr, char *);
 

commit b55ae28e513f02657aaa6196e3d44d96a2c4759c
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    Avoid re-starting the intersection routine when we don't have to
    
    Apparently this has a nice performance win for the NoHoles dicer.

diff --git a/src/polygon1.c b/src/polygon1.c
index 1a194b3..4a761d5 100644
--- a/src/polygon1.c
+++ b/src/polygon1.c
@@ -46,6 +46,8 @@
 #include	<math.h>
 #include	<string.h>
 
+#include <glib.h>
+
 #include "global.h"
 #include "rtree.h"
 #include "heap.h"
@@ -180,26 +182,26 @@ node_add
  4 means the intersection was not on the dest point
 */
 static VNODE *
-node_add (VNODE * dest, Vector po, int *new_point)
+node_add_single (VNODE * dest, Vector po)
 {
   VNODE *p;
 
   if (vect_equal (po, dest->point))
     return dest;
   if (vect_equal (po, dest->next->point))
-    {
-      (*new_point) += 4;
-      return dest->next;
-    }
+    return dest->next;
   p = poly_CreateNode (po);
   if (p == NULL)
     return NULL;
-  (*new_point) += 5;
+#if 0
   p->prev = dest;
   p->next = dest->next;
+  dest->next->prev = p;
+  dest->next = p;
+#endif
   p->cvc_prev = p->cvc_next = NULL;
   p->Flags.status = UNKNWN;
-  return (dest->next = dest->next->prev = p);
+  return p;
 }				/* node_add */
 
 #define ISECT_BAD_PARAM (-1)
@@ -362,22 +364,24 @@ node_add_point
  return 1 if new node in b, 2 if new node in a and 3 if new node in both
 */
 
-static int
-node_add_point (VNODE * a, VNODE * b, Vector p)
+static VNODE *
+node_add_single_point (VNODE * a, Vector p)
 {
-  int res = 0;
+  VNODE *next_a, *new_node;
 
-  VNODE *node_a, *node_b;
+  next_a = a->next;
 
-  node_a = node_add (a, p, &res);
-  res += res;
-  node_b = node_add (b, p, &res);
+  new_node = node_add_single (a, p);
 
-  if (node_a == NULL || node_b == NULL)
-    return ISECT_NO_MEMORY;
-  node_b->cvc_prev = node_b->cvc_next = (CVCList *) - 1;
-  node_a->cvc_prev = node_a->cvc_next = (CVCList *) - 1;
-  return res;
+  if (new_node == NULL)
+    exit (0);
+
+  new_node->cvc_prev = new_node->cvc_next = (CVCList *) - 1;
+
+  if (new_node == a || new_node == next_a)
+    return NULL;
+
+  return new_node;
 }				/* node_add_point */
 
 /*
@@ -501,8 +505,16 @@ typedef struct seg
   BoxType box;
   VNODE *v;
   PLINE *p;
+  int intersected;
 } seg;
 
+typedef struct insert_task
+{
+  VNODE *new_node;
+  seg *seg;
+
+} insert_task;
+
 typedef struct info
 {
   double m, b;
@@ -510,6 +522,8 @@ typedef struct info
   VNODE *v;
   struct seg *s;
   jmp_buf *env, sego, *touch;
+  int need_restart;
+  GList *node_insert_list;
 } info;
 
 typedef struct contour_info
@@ -517,6 +531,8 @@ typedef struct contour_info
   PLINE *pa;
   jmp_buf restart;
   jmp_buf *getout;
+  int need_restart;
+  GList *node_insert_list;
 } contour_info;
 
 
@@ -534,6 +550,7 @@ adjust_tree (rtree_t * tree, struct seg *s)
   q = malloc (sizeof (struct seg));
   if (!q)
     return 1;
+  q->intersected = 0;
   q->v = s->v;
   q->p = s->p;
   q->box.X1 = min (q->v->point[0], q->v->next->point[0]);
@@ -544,6 +561,7 @@ adjust_tree (rtree_t * tree, struct seg *s)
   q = malloc (sizeof (struct seg));
   if (!q)
     return 1;
+  q->intersected = 0;
   q->v = s->v->next;
   q->p = s->p;
   q->box.X1 = min (q->v->point[0], q->v->next->point[0]);
@@ -594,7 +612,18 @@ seg_in_seg (const BoxType * b, void *cl)
   struct info *i = (struct info *) cl;
   struct seg *s = (struct seg *) b;
   Vector s1, s2;
-  int cnt, res;
+  int cnt;
+  VNODE *new_node;
+
+//  printf ("Looking at intersection between %p(%i) and %p(%i)\n",
+//          s->v, s->v->Flags.intersected, i->v, i->v->Flags.intersected);
+
+  if (s->intersected || i->s->intersected)
+    {
+//    printf ("Need to restart intersection\n");
+      i->need_restart = 1;
+      return 0;
+    }
 
   cnt = vect_inters2 (s->v->point, s->v->next->point,
 		      i->v->point, i->v->next->point, s1, s2);
@@ -606,30 +635,37 @@ seg_in_seg (const BoxType * b, void *cl)
   s->p->Flags.status = ISECTED;
   for (; cnt; cnt--)
     {
-      res = node_add_point (i->v, s->v, cnt > 1 ? s2 : s1);
-      if (res < 0)
-	return 1;		/* error */
-      /* adjust the bounding box and tree if necessary */
-      if (res & 2)
+      int done_insert = 0;
+      new_node = node_add_single_point (i->v, cnt > 1 ? s2 : s1);
+      if (new_node != NULL)
 	{
-	  cntrbox_adjust (i->s->p, cnt > 1 ? s2 : s1);
-	  if (adjust_tree (i->s->p->tree, i->s))
-	    return 1;
+	  insert_task *task = g_new0 (insert_task, 1);
+	  task->new_node = new_node;
+	  task->seg = i->s;
+	  task->seg->intersected = 1;
+	  i->node_insert_list = g_list_prepend (i->node_insert_list, task);
+	  done_insert = 1;
 	}
-      /* if we added a node in the tree we need to change the tree */
-      if (res & 1)
+//      else
+//        printf (".");
+      new_node = node_add_single_point (s->v, cnt > 1 ? s2 : s1);
+      if (new_node != NULL)
 	{
-	  cntrbox_adjust (s->p, cnt > 1 ? s2 : s1);
-	  if (adjust_tree (i->tree, s))
-	    return 1;
+	  insert_task *task = g_new0 (insert_task, 1);
+	  task->new_node = new_node;
+	  task->seg = s;
+	  task->seg->intersected = 1;
+	  i->node_insert_list = g_list_prepend (i->node_insert_list, task);
+	  return 0;		/* Don't do any more processing */
 	}
-      if (res & 3)		/* if a point was inserted start over */
+//      else
+//        printf (":");
+      if (done_insert)
 	{
-#ifdef DEBUG_INTERSECT
-	  DEBUGP ("new intersection at (%d, %d)\n", cnt > 1 ? s2[0] : s1[0],
-		  cnt > 1 ? s2[1] : s1[1]);
-#endif
-	  longjmp (*i->env, 1);
+//        printf ("Long-jmping back, since we intersected on i\n");
+	  longjmp (*i->env, 1);	/* Skip this contour if we intersected on i */
+	  i->need_restart = 1;	/* If we skip some processing, we definately need a restart */
+	  return 0;
 	}
     }
   return 0;
@@ -645,6 +681,7 @@ make_edge_tree (PLINE * pb)
   do
     {
       s = malloc (sizeof (struct seg));
+      s->intersected = 0;
       if (bv->point[0] < bv->next->point[0])
 	{
 	  s->box.X1 = bv->point[0];
@@ -715,10 +752,14 @@ contour_bounds_touch (const BoxType * b, void *cl)
   VNODE *av;			/* node iterators */
   struct info info;
   BoxType box;
+  jmp_buf restart;
 
   /* Have seg_in_seg return to our desired location if it touches */
-  info.env = &c_info->restart;
+//  info.env = &c_info->restart;
+  info.env = &restart;
   info.touch = c_info->getout;
+  info.need_restart = 0;
+  info.node_insert_list = c_info->node_insert_list;
 
   /* Pick which contour has the fewer points, and do the loop
    * over that. The r_tree makes hit-testing against a contour
@@ -740,6 +781,17 @@ contour_bounds_touch (const BoxType * b, void *cl)
     {
       /* check this edge for any insertions */
       double dx;
+
+#if 0
+      /* We know we will just reject any intersections found until
+         the next pass anyway */
+      if (av->Flags.intersected)
+	{
+//        printf ("skip\n");
+	  continue;
+	}
+#endif
+
       info.v = av;
       /* compute the slant for region trimming */
       dx = av->next->point[0] - av->point[0];
@@ -760,23 +812,61 @@ contour_bounds_touch (const BoxType * b, void *cl)
 	  assert (0);
 	}
 
+      /* If we're going to have another pass anyway, skip this */
+      if (info.s->intersected && info.node_insert_list != NULL)
+	continue;
+
+      if (setjmp (restart))
+	continue;
+
       /* NB: If this actually hits anything, we are teleported back to the beginning */
       info.tree = rtree_over->tree;
       if (info.tree)
 	if (UNLIKELY (r_search (info.tree, &info.s->box,
 				seg_in_region, seg_in_seg, &info)))
-	  return err_no_memory;	/* error */
+	  exit (0);
+//            return err_no_memory;     /* error */
     }
   while ((av = av->next) != &looping_over->head);
+
+  c_info->node_insert_list = info.node_insert_list;
+  if (info.need_restart)
+    {
+//    printf ("info.needs_restart says we need to restart\n");
+      c_info->need_restart = 1;
+    }
   return 0;
 }
 
+static void
+insert_new_nodes_cb (gpointer data, gpointer userdata)
+{
+  insert_task *task = data;
+  /* Do insersion */
+  // task->new_node, inserted before task->parent into PLINE task->owner
+
+//  printf ("Seg affected: %p\n", task->seg);
+  task->new_node->prev = task->seg->v;
+  task->new_node->next = task->seg->v->next;
+  task->seg->v->next->prev = task->new_node;
+  task->seg->v->next = task->new_node;
+  task->seg->p->Count++;
+
+  cntrbox_adjust (task->seg->p, task->new_node->point);
+  if (adjust_tree (task->seg->p->tree, task->seg))
+    exit (0);
+  g_free (task);
+}
+
 static int
-intersect (jmp_buf * jb, POLYAREA * b, POLYAREA * a, int add)
+intersect_impl (jmp_buf * jb, POLYAREA * b, POLYAREA * a, int add)
 {
   POLYAREA *t;
   PLINE *pa;
   contour_info c_info;
+  int need_restart = 0;
+  c_info.need_restart = 0;
+  c_info.node_insert_list = NULL;
 
   /* Search the r-tree of the object with most contours
    * We loop over the contours of "a". Swap if necessary.
@@ -788,7 +878,7 @@ intersect (jmp_buf * jb, POLYAREA * b, POLYAREA * a, int add)
       a = t;
     }
 
-  setjmp (c_info.restart);	/* we loop back here whenever a vertex is inserted */
+//  setjmp (c_info.restart);            /* we loop back here whenever a vertex is inserted */
 
   for (pa = a->contours; pa; pa = pa->next)	/* Loop over the contours of POLYAREA "a" */
     {
@@ -817,8 +907,33 @@ intersect (jmp_buf * jb, POLYAREA * b, POLYAREA * a, int add)
       sb.Y2 = pa->ymax + 1;
 
       r_search (b->contour_tree, &sb, NULL, contour_bounds_touch, &c_info);
+      if (c_info.need_restart)
+	{
+	  need_restart = 1;
+//        printf ("contour_bounds_touch: need_restart\n");
+//        break;
+	}
+    }
+
+//  printf ("----\n");
+  if (c_info.node_insert_list != NULL)
+    {
+//    printf ("Processing %i new nodes\n", g_list_length (c_info.node_insert_list));
+      need_restart = 1;		/* Any new nodes could intersect */
     }
+  g_list_foreach (c_info.node_insert_list, insert_new_nodes_cb, NULL);
+  g_list_free (c_info.node_insert_list);
+//  printf ("====\n");
+
+  return need_restart;
+}
 
+static int
+intersect (jmp_buf * jb, POLYAREA * b, POLYAREA * a, int add)
+{
+  int call_count = 1;
+  while (intersect_impl (jb, b, a, add))
+    call_count++;
   return 0;
 }
 

commit 91849e58d99465bb9ec916f6594ae89ff90219ed
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    We can just delete kicked out holes
    
    Since we don't keep holes from broken contours, if a contour is
    kicked out, we know it is destined for the bin.

diff --git a/src/polygon1.c b/src/polygon1.c
index 1127fbd..1a194b3 100644
--- a/src/polygon1.c
+++ b/src/polygon1.c
@@ -1308,7 +1308,8 @@ InsertHoles (jmp_buf * e, POLYAREA * dest, PLINE ** src)
 	}
       else
 	{
-	  /* Need to check if this new hole means we need to kick out any old ones for reprocessing */
+	  /* Need to check if this new hole means we need to kick out any old
+	   * ones for deletion */
 	  while (1)
 	    {
 	      struct find_inside_info info;
@@ -1342,10 +1343,7 @@ InsertHoles (jmp_buf * e, POLYAREA * dest, PLINE ** src)
 
 	      /* Remove hole from the contour */
 	      remove_contour (pa_info->pa, prev, info.result, TRUE);
-
-	      /* Add hole as the next on the list to be processed in this very function */
-	      info.result->next = *src;
-	      *src = info.result;
+	      poly_DelContour (&info.result);
 	    }
 	  /* End check for kicked out holes */
 

commit d4fd0a435f87c637e902787bd274a8e624a2b204
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    Various speedups to the polygon code.
    
    Attempt to fix polygon slowness by avoiding the need to create a
    completely new polygon for each boolean operation. This mostly relies
    upon r-tree searches to find contours to operate on - rather than
    searching each in turn.
    
    We avoid labelling all of the "A" polygon's contours, use the contour
    r-trees to dynamically search the required data.
    
    Added code to reparent holes which end up in the wrong polygon piece
    after inserting a new hole in InsertHoles. This means we don't have
    to dump every potental hole we encounter in the holes insersion queue,
    hopefully leading to better dynamic update performance.
    
    At this point, polygon performance has finally seen a net gain.
    
    HOWEVER: Due to differences in the order of polygon operations, the
             data-structures resulting from a boolean polygon operation
             may be sorted differently.
    
             In certain contrived cases, where a polygon is clipped into
             identically sized pieces, the resulting piece of polygon
             which PCB will keep and use on the board is different after
             this commit.

diff --git a/src/polygon1.c b/src/polygon1.c
index a0be8e6..1127fbd 100644
--- a/src/polygon1.c
+++ b/src/polygon1.c
@@ -879,12 +879,22 @@ cntrbox_inside (PLINE * c1, PLINE * c2)
 /*****************************************************************/
 /* Routines for making labels */
 
+static int
+count_contours_i_am_inside (const BoxType * b, void *cl)
+{
+  PLINE *me = cl;
+  PLINE *check = (PLINE *) b;
+
+  if (poly_ContourInContour (check, me))
+    return 1;
+  return 0;
+}
+
 /* cntr_in_M_POLYAREA
 returns poly is inside outfst ? TRUE : FALSE */
 static int
 cntr_in_M_POLYAREA (PLINE * poly, POLYAREA * outfst, BOOLp test)
 {
-  PLINE *curc;
   POLYAREA *outer = outfst;
   heap_t *heap;
 
@@ -907,18 +917,22 @@ cntr_in_M_POLYAREA (PLINE * poly, POLYAREA * outfst, BOOLp test)
       if (heap_is_empty (heap))
 	break;
       outer = (POLYAREA *) heap_remove_smallest (heap);
-      if (poly_ContourInContour (outer->contours, poly))
+
+      switch (r_search
+	      (outer->contour_tree, (BoxType *) poly, NULL,
+	       count_contours_i_am_inside, poly))
 	{
-	  for (curc = outer->contours->next; curc != NULL; curc = curc->next)
-	    if (poly_ContourInContour (curc, poly))
-	      {
-		/* it's inside a hole in the smallest polygon 
-		 * no need to check the other polygons */
-		heap_destroy (&heap);
-		return FALSE;
-	      }
+	case 0:		/* Didn't find anything in this piece, Keep looking */
+	  break;
+	case 1:		/* Found we are inside this piece, and not any of its holes */
 	  heap_destroy (&heap);
 	  return TRUE;
+	case 2:		/* Found inside a hole in the smallest polygon so far. No need to check the other polygons */
+	  heap_destroy (&heap);
+	  return FALSE;
+	default:
+	  printf ("Something strange here\n");
+	  break;
 	}
     }
   while (1);
@@ -1031,6 +1045,19 @@ cntr_label_POLYAREA (PLINE * poly, POLYAREA * ppl, BOOLp test)
 }				/* cntr_label_POLYAREA */
 
 static BOOLp
+M_POLYAREA_label_separated (PLINE * afst, POLYAREA * b, BOOLp touch)
+{
+  PLINE *curc = afst;
+
+  for (curc = afst; curc != NULL; curc = curc->next)
+    {
+      if (cntr_label_POLYAREA (curc, b, touch) && touch)
+	return TRUE;
+    }
+  return FALSE;
+}
+
+static BOOLp
 M_POLYAREA_label (POLYAREA * afst, POLYAREA * b, BOOLp touch)
 {
   POLYAREA *a = afst;
@@ -1118,6 +1145,24 @@ PutContour (jmp_buf * e, PLINE * cntr, POLYAREA ** contours, PLINE ** holes,
     }
 }				/* PutContour */
 
+static inline void
+remove_contour (POLYAREA * piece, PLINE * prev_contour, PLINE * contour,
+		int remove_rtree_entry)
+{
+  if (piece->contours == contour)
+    piece->contours = contour->next;
+  else if (prev_contour != NULL)
+    {
+      assert (prev_contour->next == contour);
+      prev_contour->next = contour->next;
+    }
+
+  contour->next = NULL;
+
+  if (remove_rtree_entry)
+    r_delete_entry (piece->contour_tree, (BoxType *) contour);
+}
+
 struct polyarea_info
 {
   BoxType BoundingBox;
@@ -1136,6 +1181,32 @@ heap_it (const BoxType * b, void *cl)
   return 1;
 }
 
+struct find_inside_info
+{
+  jmp_buf jb;
+  PLINE *want_inside;
+  PLINE *result;
+};
+
+static int
+find_inside (const BoxType * b, void *cl)
+{
+  struct find_inside_info *info = cl;
+  PLINE *check = (PLINE *) b;
+  /* Do test on check to see if it inside info->want_inside */
+  /* If it is: */
+  if (check->Flags.orient == PLF_DIR)
+    {
+      return 0;
+    }
+  if (poly_ContourInContour (info->want_inside, check))
+    {
+      info->result = check;
+      longjmp (info->jb, 1);
+    }
+  return 0;
+}
+
 static void
 InsertHoles (jmp_buf * e, POLYAREA * dest, PLINE ** src)
 {
@@ -1237,10 +1308,52 @@ InsertHoles (jmp_buf * e, POLYAREA * dest, PLINE ** src)
 	}
       else
 	{
+	  /* Need to check if this new hole means we need to kick out any old ones for reprocessing */
+	  while (1)
+	    {
+	      struct find_inside_info info;
+	      PLINE *prev;
+
+	      info.want_inside = curh;
+
+	      /* Set jump return */
+	      if (setjmp (info.jb))
+		{
+		  /* Returned here! */
+		}
+	      else
+		{
+		  info.result = NULL;
+		  /* Rtree search, calling back a routine to longjmp back with data about any hole inside the added one */
+		  /*   Be sure not to bother jumping back to report the main contour! */
+		  r_search (pa_info->pa->contour_tree, (BoxType *) curh, NULL,
+			    find_inside, &info);
+
+		  /* Nothing found? */
+		  break;
+		}
+
+	      /* We need to find the contour before it, so we can update its next pointer */
+	      prev = container;
+	      while (prev->next != info.result)
+		{
+		  prev = prev->next;
+		}
+
+	      /* Remove hole from the contour */
+	      remove_contour (pa_info->pa, prev, info.result, TRUE);
+
+	      /* Add hole as the next on the list to be processed in this very function */
+	      info.result->next = *src;
+	      *src = info.result;
+	    }
+	  /* End check for kicked out holes */
+
 	  /* link at front of hole list */
 	  curh->next = container->next;
 	  container->next = curh;
 	  r_insert_entry (pa_info->pa->contour_tree, (BoxTypePtr) curh, 0);
+
 	}
     }
   r_destroy_tree (&tree);
@@ -1634,6 +1747,384 @@ M_B_AREA_Collect (jmp_buf * e, POLYAREA * bfst, POLYAREA ** contours,
 }
 
 
+static inline int
+contour_is_first (POLYAREA * a, PLINE * cur)
+{
+  return (a->contours == cur);
+}
+
+
+static inline int
+contour_is_last (PLINE * cur)
+{
+  return (cur->next == NULL);
+}
+
+
+static inline void
+remove_polyarea (POLYAREA ** list, POLYAREA * piece)
+{
+  /* If this item was the start of the list, advance that pointer */
+  if (*list == piece)
+    *list = (*list)->f;
+
+  /* But reset it to NULL if it wraps around and hits us again */
+  if (*list == piece)
+    *list = NULL;
+
+  piece->b->f = piece->f;
+  piece->f->b = piece->b;
+  piece->f = piece->b = piece;
+}
+
+static void
+M_POLYAREA_separate_isected (jmp_buf * e, POLYAREA ** pieces,
+			     PLINE ** holes, PLINE ** isected)
+{
+  POLYAREA *a = *pieces;
+  POLYAREA *anext;
+  PLINE *curc, *next, *prev;
+  int finished;
+
+  if (a == NULL)
+    return;
+
+  /* TODO: STASH ENOUGH INFORMATION EARLIER ON, SO WE CAN REMOVE THE INTERSECTED
+     CONTOURS WITHOUT HAVING TO WALK THE FULL DATA-STRUCTURE LOOKING FOR THEM. */
+
+  do
+    {
+      int hole_contour = 0;
+      int is_outline = 1;
+
+      anext = a->f;
+      finished = (anext == *pieces);
+
+      prev = NULL;
+      for (curc = a->contours; curc != NULL; curc = next, is_outline = 0)
+	{
+	  int is_first = contour_is_first (a, curc);
+	  int is_last = contour_is_last (curc);
+	  int isect_contour = (curc->Flags.status == ISECTED);
+
+	  next = curc->next;
+
+	  if (isect_contour || hole_contour)
+	    {
+
+	      /* Reset the intersection flags, since we keep these pieces */
+	      if (curc->Flags.status != ISECTED)
+		curc->Flags.status = UNKNWN;
+
+	      remove_contour (a, prev, curc, !(is_first && is_last));
+
+	      if (isect_contour)
+		{
+		  /* Link into the list of intersected contours */
+		  curc->next = *isected;
+		  *isected = curc;
+		}
+	      else if (hole_contour)
+		{
+		  /* Link into the list of holes */
+		  curc->next = *holes;
+		  *holes = curc;
+		}
+	      else
+		{
+		  assert (0);
+		}
+
+	      if (is_first && is_last)
+		{
+		  remove_polyarea (pieces, a);
+		  poly_Free (&a);	/* NB: Sets a to NULL */
+		}
+
+	    }
+	  else
+	    {
+	      /* Note the item we just didn't delete as the next
+	         candidate for having its "next" pointer adjusted.
+	         Saves walking the contour list when we delete one. */
+	      prev = curc;
+	    }
+
+	  /* If we move or delete an outer contour, we need to move any holes
+	     we wish to keep within that contour to the holes list. */
+	  if (is_outline && isect_contour)
+	    hole_contour = 1;
+
+	}
+
+      /* If we deleted all the pieces of the polyarea, *pieces is NULL */
+    }
+  while ((a = anext), *pieces != NULL && !finished);
+}
+
+
+struct find_inside_m_pa_info
+{
+  jmp_buf jb;
+  POLYAREA *want_inside;
+  PLINE *result;
+};
+
+static int
+find_inside_m_pa (const BoxType * b, void *cl)
+{
+  struct find_inside_m_pa_info *info = cl;
+  PLINE *check = (PLINE *) b;
+  /* Don't report for the main contour */
+  if (check->Flags.orient == PLF_DIR)
+    return 0;
+  /* Don't look at contours marked as being intersected */
+  if (check->Flags.status == ISECTED)
+    return 0;
+  if (cntr_in_M_POLYAREA (check, info->want_inside, FALSE))
+    {
+      info->result = check;
+      longjmp (info->jb, 1);
+    }
+  return 0;
+}
+
+
+static void
+M_POLYAREA_update_primary (jmp_buf * e, POLYAREA ** pieces,
+			   PLINE ** holes, int action, POLYAREA * bpa)
+{
+  POLYAREA *a = *pieces;
+  POLYAREA *b;
+  POLYAREA *anext;
+  PLINE *curc, *next, *prev;
+  BoxType box;
+  int inv_inside = 0;
+  int del_inside = 0;
+  int del_outside = 0;
+  int finished;
+
+  if (a == NULL)
+    return;
+
+  switch (action)
+    {
+    case PBO_ISECT:
+      del_outside = 1;
+      break;
+    case PBO_UNITE:
+    case PBO_SUB:
+      del_inside = 1;
+      break;
+    case PBO_XOR:		/* NOT IMPLEMENTED OR USED */
+      inv_inside = 1;
+      assert (0);
+      break;
+    }
+
+  box = *((BoxType *) bpa->contours);
+  b = bpa;
+  while ((b = b->f) != bpa)
+    {
+      BoxType *b_box = (BoxType *) b->contours;
+      MAKEMIN (box.X1, b_box->X1);
+      MAKEMIN (box.Y1, b_box->Y1);
+      MAKEMAX (box.X2, b_box->X2);
+      MAKEMAX (box.Y2, b_box->Y2);
+    }
+
+  if (del_inside)
+    {
+
+      do
+	{
+	  anext = a->f;
+	  finished = (anext == *pieces);
+
+	  /* Test the outer contour first, as we may need to remove all children */
+
+	  /* We've not yet split intersected contours out, just ignore them */
+	  if (a->contours->Flags.status != ISECTED &&
+	      /* Pre-filter on bounding box */
+	      ((a->contours->xmin >= box.X1) && (a->contours->ymin >= box.Y1)
+	       && (a->contours->xmax <= box.X2)
+	       && (a->contours->ymax <= box.Y2)) &&
+	      /* Then test properly */
+	      cntr_in_M_POLYAREA (a->contours, bpa, FALSE))
+	    {
+
+	      /* Delete this contour, all children -> holes queue */
+
+	      /* Delete the outer contour */
+	      curc = a->contours;
+	      remove_contour (a, NULL, curc, FALSE);	/* Rtree deleted in poly_Free below */
+	      /* a->contours now points to the remaining holes */
+	      poly_DelContour (&curc);
+
+	      if (a->contours != NULL)
+		{
+		  /* Find the end of the list of holes */
+		  curc = a->contours;
+		  while (curc->next != NULL)
+		    curc = curc->next;
+
+		  /* Take the holes and prepend to the holes queue */
+		  curc->next = *holes;
+		  *holes = a->contours;
+		  a->contours = NULL;
+		}
+
+	      remove_polyarea (pieces, a);
+	      poly_Free (&a);	/* NB: Sets a to NULL */
+
+	      continue;
+	    }
+
+	  /* Loop whilst we find INSIDE contours to delete */
+	  while (1)
+	    {
+	      struct find_inside_m_pa_info info;
+	      PLINE *prev;
+
+	      info.want_inside = bpa;
+
+	      /* Set jump return */
+	      if (setjmp (info.jb))
+		{
+		  /* Returned here! */
+		}
+	      else
+		{
+		  info.result = NULL;
+		  /* r-tree search, calling back a routine to longjmp back with
+		   * data about any hole inside the B polygon.
+		   * NB: Does not jump back to report the main contour!
+		   */
+		  r_search (a->contour_tree, &box, NULL, find_inside_m_pa,
+			    &info);
+
+		  /* Nothing found? */
+		  break;
+		}
+
+	      /* We need to find the contour before it, so we can update its next pointer */
+	      prev = a->contours;
+	      while (prev->next != info.result)
+		{
+		  prev = prev->next;
+		}
+
+	      /* Remove hole from the contour */
+	      remove_contour (a, prev, info.result, TRUE);
+	      poly_DelContour (&info.result);
+	    }
+	  /* End check for deleted holes */
+
+	  /* If we deleted all the pieces of the polyarea, *pieces is NULL */
+	}
+      while ((a = anext), *pieces != NULL && !finished);
+
+      return;
+    }
+  else
+    {
+      /* This path isn't optimised for speed */
+    }
+
+  do
+    {
+      int hole_contour = 0;
+      int is_outline = 1;
+
+      anext = a->f;
+      finished = (anext == *pieces);
+
+      prev = NULL;
+      for (curc = a->contours; curc != NULL; curc = next, is_outline = 0)
+	{
+	  int is_first = contour_is_first (a, curc);
+	  int is_last = contour_is_last (curc);
+	  int del_contour = 0;
+
+	  next = curc->next;
+
+	  if (del_outside)
+	    del_contour = curc->Flags.status != ISECTED &&
+	      !cntr_in_M_POLYAREA (curc, bpa, FALSE);
+
+	  /* Skip intersected contours */
+	  if (curc->Flags.status == ISECTED)
+	    {
+	      prev = curc;
+	      continue;
+	    }
+
+	  /* Reset the intersection flags, since we keep these pieces */
+	  curc->Flags.status = UNKNWN;
+
+	  if (del_contour || hole_contour)
+	    {
+
+	      remove_contour (a, prev, curc, !(is_first && is_last));
+
+	      if (del_contour)
+		{
+		  /* Delete the contour */
+		  poly_DelContour (&curc);	/* NB: Sets curc to NULL */
+		}
+	      else if (hole_contour)
+		{
+		  /* Link into the list of holes */
+		  curc->next = *holes;
+		  *holes = curc;
+		}
+	      else
+		{
+		  assert (0);
+		}
+
+	      if (is_first && is_last)
+		{
+		  remove_polyarea (pieces, a);
+		  poly_Free (&a);	/* NB: Sets a to NULL */
+		}
+
+	    }
+	  else
+	    {
+	      /* Note the item we just didn't delete as the next
+	         candidate for having its "next" pointer adjusted.
+	         Saves walking the contour list when we delete one. */
+	      prev = curc;
+	    }
+
+	  /* If we move or delete an outer contour, we need to move any holes
+	     we wish to keep within that contour to the holes list. */
+	  if (is_outline && del_contour)
+	    hole_contour = 1;
+
+	}
+
+      /* If we deleted all the pieces of the polyarea, *pieces is NULL */
+    }
+  while ((a = anext), *pieces != NULL && !finished);
+}
+
+static void
+M_POLYAREA_Collect_separated (jmp_buf * e, PLINE * afst, POLYAREA ** contours,
+			      PLINE ** holes, int action, BOOLp maybe)
+{
+  PLINE **cur, **next;
+
+  for (cur = &afst; *cur != NULL; cur = next)
+    {
+      next = &((*cur)->next);
+      /* if we disappear a contour, don't advance twice */
+      if (cntr_Collect (e, cur, contours, holes, action, NULL, NULL, NULL))
+	next = cur;
+    }
+}
+
 static void
 M_POLYAREA_Collect (jmp_buf * e, POLYAREA * afst, POLYAREA ** contours,
 		    PLINE ** holes, int action, BOOLp maybe)
@@ -1726,6 +2217,7 @@ int
 poly_Boolean_free (POLYAREA * ai, POLYAREA * bi, POLYAREA ** res, int action)
 {
   POLYAREA *a = ai, *b = bi;
+  PLINE *a_isected = NULL;
   PLINE *p, *holes = NULL;
   jmp_buf e;
   int code;
@@ -1770,18 +2262,29 @@ poly_Boolean_free (POLYAREA * ai, POLYAREA * bi, POLYAREA ** res, int action)
       assert (poly_Valid (b));
 #endif
 
+      /* intersect needs to make a list of the contours in a and b which are intersected */
       M_POLYAREA_intersect (&e, a, b, TRUE);
 
-      M_POLYAREA_label (a, b, FALSE);
+      /* We could speed things up a lot here if we only processed the relevant contours */
+      /* NB: Relevant parts of a are labeled below */
       M_POLYAREA_label (b, a, FALSE);
 
-      M_POLYAREA_Collect (&e, a, res, &holes, action, b->f == b
-			  && !b->contours->next
-			  && b->contours->Flags.status != ISECTED);
-      poly_Free (&a);
+      *res = a;
+      M_POLYAREA_update_primary (&e, res, &holes, action, b);
+      M_POLYAREA_separate_isected (&e, res, &holes, &a_isected);
+      M_POLYAREA_label_separated (a_isected, b, FALSE);
+      M_POLYAREA_Collect_separated (&e, a_isected, res, &holes, action,
+				    FALSE);
       M_B_AREA_Collect (&e, b, res, &holes, action);
       poly_Free (&b);
 
+      /* free a_isected */
+      while ((p = a_isected) != NULL)
+	{
+	  a_isected = p->next;
+	  poly_DelContour (&p);
+	}
+
       InsertHoles (&e, *res, &holes);
     }
   /* delete holes if any left */

commit a34d7e1b87354c65e3d13dcf8225c1b1e02efa68
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    Use heap structure to insert holes quicker in InsertHoles()

diff --git a/src/polygon1.c b/src/polygon1.c
index 2799a67..a0be8e6 100644
--- a/src/polygon1.c
+++ b/src/polygon1.c
@@ -1118,14 +1118,21 @@ PutContour (jmp_buf * e, PLINE * cntr, POLYAREA ** contours, PLINE ** holes,
     }
 }				/* PutContour */
 
+struct polyarea_info
+{
+  BoxType BoundingBox;
+  POLYAREA *pa;
+};
+
 static int
 heap_it (const BoxType * b, void *cl)
 {
   heap_t *heap = (heap_t *) cl;
-  PLINE *p = (PLINE *) b;
+  struct polyarea_info *pa_info = (struct polyarea_info *) b;
+  PLINE *p = pa_info->pa->contours;
   if (p->Count == 0)
     return 0;			/* how did this happen? */
-  heap_insert (heap, p->area, (void *) p);
+  heap_insert (heap, p->area, pa_info);
   return 1;
 }
 
@@ -1133,23 +1140,44 @@ static void
 InsertHoles (jmp_buf * e, POLYAREA * dest, PLINE ** src)
 {
   POLYAREA *curc;
-  PLINE *curh, *container, *tmp;
+  PLINE *curh, *container;
   heap_t *heap;
   rtree_t *tree;
+  int i;
+  int num_polyareas = 0;
+  struct polyarea_info *all_pa_info, *pa_info;
 
   if (*src == NULL)
     return;			/* empty hole list */
   if (dest == NULL)
     error (err_bad_parm);	/* empty contour list */
 
-  /* make an rtree of outer contours */
+  /* Count dest polyareas */
+  curc = dest;
+  do
+    {
+      num_polyareas++;
+    }
+  while ((curc = curc->f) != dest);
+
+  /* make a polyarea info table */
+  /* make an rtree of polyarea info table */
+  all_pa_info = malloc (sizeof (struct polyarea_info) * num_polyareas);
   tree = r_create_tree (NULL, 0, 0);
+  i = 0;
   curc = dest;
   do
     {
-      r_insert_entry (tree, (const BoxType *) curc->contours, 0);
+      all_pa_info[i].BoundingBox.X1 = curc->contours->xmin;
+      all_pa_info[i].BoundingBox.Y1 = curc->contours->ymin;
+      all_pa_info[i].BoundingBox.X2 = curc->contours->xmax;
+      all_pa_info[i].BoundingBox.Y2 = curc->contours->ymax;
+      all_pa_info[i].pa = curc;
+      r_insert_entry (tree, (const BoxType *) &all_pa_info[i], 0);
+      i++;
     }
   while ((curc = curc->f) != dest);
+
   /* loop through the holes and put them where they belong */
   while ((curh = *src) != NULL)
     {
@@ -1173,24 +1201,24 @@ InsertHoles (jmp_buf * e, POLYAREA * dest, PLINE ** src)
        * in the heap, assume it is the container without the expense of
        * proving it.
        */
-      tmp = (PLINE *) heap_remove_smallest (heap);
+      pa_info = heap_remove_smallest (heap);
       if (heap_is_empty (heap))
 	{			/* only one possibility it must be the right one */
-	  assert (poly_ContourInContour (tmp, curh));
-	  container = tmp;
+	  assert (poly_ContourInContour (pa_info->pa->contours, curh));
+	  container = pa_info->pa->contours;
 	}
       else
 	{
 	  do
 	    {
-	      if (poly_ContourInContour (tmp, curh))
+	      if (poly_ContourInContour (pa_info->pa->contours, curh))
 		{
-		  container = tmp;
+		  container = pa_info->pa->contours;
 		  break;
 		}
 	      if (heap_is_empty (heap))
 		break;
-	      tmp = (PLINE *) heap_remove_smallest (heap);
+	      pa_info = heap_remove_smallest (heap);
 	    }
 	  while (1);
 	}
@@ -1212,26 +1240,11 @@ InsertHoles (jmp_buf * e, POLYAREA * dest, PLINE ** src)
 	  /* link at front of hole list */
 	  curh->next = container->next;
 	  container->next = curh;
-
-	  /* Search for which POLYAREA the containing contour belongs to */
-	  /* FIXME: Perhaps store this information in the heap structure? */
-	  curc = dest;
-	  do
-	    {
-	      if (curc->contours == container)
-		break;
-	    }
-	  while ((curc = curc->f) != dest);
-
-	  if (curc->contours == container)
-	    {
-	      r_insert_entry (curc->contour_tree, (BoxTypePtr) curh, 0);
-	    }
-	  else
-	    assert (0);
+	  r_insert_entry (pa_info->pa->contour_tree, (BoxTypePtr) curh, 0);
 	}
     }
   r_destroy_tree (&tree);
+  free (all_pa_info);
 }				/* InsertHoles */
 
 

commit ed7c2aa282fff2306d3a5451934bbb9402e4836c
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    Optimise polygon operations by keeping an rtree of POLYAREA contours
    
    Attempt to speed up the intersect() routine using this rtree rather
    than generating a new one at each call.
    
    Due to the increased overheads of keeping an r-tree up to date, there
    is a significant overall slow-down at this point in the patch series.

diff --git a/src/polyarea.h b/src/polyarea.h
index 958498b..ce427ad 100644
--- a/src/polyarea.h
+++ b/src/polyarea.h
@@ -132,6 +132,7 @@ struct POLYAREA
 {
     POLYAREA *f, *b;
     PLINE *contours;
+    rtree_t *contour_tree;
 };
 
 BOOLp poly_M_Copy0(POLYAREA ** dst, const POLYAREA * srcfst);
diff --git a/src/polygon.c b/src/polygon.c
index 474474e..eac9390 100644
--- a/src/polygon.c
+++ b/src/polygon.c
@@ -215,6 +215,7 @@ biggest (POLYAREA * p)
 {
   POLYAREA *n, *top = NULL;
   PLINE *pl;
+  rtree_t *tree;
   double big = -1;
   if (!p)
     return NULL;
@@ -248,8 +249,11 @@ biggest (POLYAREA * p)
   if (top == p)
     return p;
   pl = top->contours;
+  tree = top->contour_tree;
   top->contours = p->contours;
+  top->contour_tree = p->contour_tree;
   p->contours = pl;
+  p->contour_tree = tree;
   assert (pl);
   assert (p->f);
   assert (p->b);
@@ -1695,6 +1699,8 @@ r_NoHolesPolygonDicer (POLYAREA * pa,
   if (!pa->contours->next)                 /* no holes */
     {
       pa->contours = NULL; /* The callback now owns the contour */
+      /* Don't bother removing it from the POLYAREA's rtree
+         since we're going to free the POLYAREA below anyway */
       emit (p, user_data);
       poly_Free (&pa);
       return;
diff --git a/src/polygon1.c b/src/polygon1.c
index d2c0798..2799a67 100644
--- a/src/polygon1.c
+++ b/src/polygon1.c
@@ -775,31 +775,19 @@ static int
 intersect (jmp_buf * jb, POLYAREA * b, POLYAREA * a, int add)
 {
   POLYAREA *t;
-  PLINE *pa, *pb;
-  int ca = 0, cb = 0;
+  PLINE *pa;
   contour_info c_info;
-  rtree_t *b_contour_tree = NULL;
-
-  /* count the contours in a and b */
-  for (pa = a->contours; pa; pa = pa->next, ca++);
-  for (pb = b->contours; pb; pb = pb->next, cb++);
 
-  /* Make the contour r-tree from the one with fewest contours */
-  /* Inserting entries is more expensive than searching
-   * the r-tree. We do one ca times, the other cb times. */
-  if (ca < cb)
+  /* Search the r-tree of the object with most contours
+   * We loop over the contours of "a". Swap if necessary.
+   */
+  if (a->contour_tree->size > b->contour_tree->size)
     {
       t = b;
       b = a;
       a = t;
     }
 
-  /* make an rtree of b's contours */
-  b_contour_tree = r_create_tree (NULL, 0, 0);
-  for (pb = b->contours; pb != NULL; pb = pb->next)
-    r_insert_entry (b_contour_tree, (const BoxType *) pb, 0);
-
-  /* FIXME: We might actually need to re-build the r_tree if the geometry changes */
   setjmp (c_info.restart);	/* we loop back here whenever a vertex is inserted */
 
   for (pa = a->contours; pa; pa = pa->next)	/* Loop over the contours of POLYAREA "a" */
@@ -818,7 +806,6 @@ intersect (jmp_buf * jb, POLYAREA * b, POLYAREA * a, int add)
 	    {
 	      /* The intersection test short-circuited back here,
 	       * we need to clean up, then longjmp to jb */
-	      r_destroy_tree (&b_contour_tree);
 	      longjmp (*jb, retval);
 	    }
 	  c_info.getout = &out;
@@ -829,7 +816,7 @@ intersect (jmp_buf * jb, POLYAREA * b, POLYAREA * a, int add)
       sb.X2 = pa->xmax + 1;
       sb.Y2 = pa->ymax + 1;
 
-      r_search (b_contour_tree, &sb, NULL, contour_bounds_touch, &c_info);
+      r_search (b->contour_tree, &sb, NULL, contour_bounds_touch, &c_info);
     }
 
   return 0;
@@ -1085,31 +1072,48 @@ InsCntr (jmp_buf * e, PLINE * c, POLYAREA ** dst)
       newp->f->b = newp->b->f = newp;
     }
   newp->contours = c;
+  newp->contour_tree = r_create_tree (NULL, 0, 0);
+  r_insert_entry (newp->contour_tree, (BoxTypePtr) c, 0);
   c->next = NULL;
 }				/* InsCntr */
 
 static void
 PutContour (jmp_buf * e, PLINE * cntr, POLYAREA ** contours, PLINE ** holes,
-	    PLINE * parent)
+	    POLYAREA * owner, POLYAREA * parent, PLINE * parent_contour)
 {
   assert (cntr != NULL);
   assert (cntr->Count > 2);
   cntr->next = NULL;
+
   if (cntr->Flags.orient == PLF_DIR)
-    InsCntr (e, cntr, contours);
+    {
+      if (owner != NULL)
+	r_delete_entry (owner->contour_tree, (BoxType *) cntr);
+      InsCntr (e, cntr, contours);
+    }
   /* put hole into temporary list */
   else
     {
       /* if we know this belongs inside the parent, put it there now */
-      if (parent)
+      if (parent_contour)
 	{
-	  cntr->next = parent->next;
-	  parent->next = cntr;
+	  cntr->next = parent_contour->next;
+	  parent_contour->next = cntr;
+	  if (owner != parent)
+	    {
+	      if (owner != NULL)
+		r_delete_entry (owner->contour_tree, (BoxType *) cntr);
+	      r_insert_entry (parent->contour_tree, (BoxType *) cntr, 0);
+	    }
 	}
       else
 	{
 	  cntr->next = *holes;
 	  *holes = cntr;	/* let cntr be 1st hole in list */
+	  /* We don't insert the holes into an r-tree,
+	   * they just form a linked list */
+	  if (owner != NULL)
+	    r_delete_entry (owner->contour_tree, (BoxType *) cntr);
 	}
     }
 }				/* PutContour */
@@ -1138,7 +1142,7 @@ InsertHoles (jmp_buf * e, POLYAREA * dest, PLINE ** src)
   if (dest == NULL)
     error (err_bad_parm);	/* empty contour list */
 
-  /* make an rtree of contours */
+  /* make an rtree of outer contours */
   tree = r_create_tree (NULL, 0, 0);
   curc = dest;
   do
@@ -1206,9 +1210,25 @@ InsertHoles (jmp_buf * e, POLYAREA * dest, PLINE ** src)
       else
 	{
 	  /* link at front of hole list */
-	  tmp = container->next;
+	  curh->next = container->next;
 	  container->next = curh;
-	  curh->next = tmp;
+
+	  /* Search for which POLYAREA the containing contour belongs to */
+	  /* FIXME: Perhaps store this information in the heap structure? */
+	  curc = dest;
+	  do
+	    {
+	      if (curc->contours == container)
+		break;
+	    }
+	  while ((curc = curc->f) != dest);
+
+	  if (curc->contours == container)
+	    {
+	      r_insert_entry (curc->contour_tree, (BoxTypePtr) curh, 0);
+	    }
+	  else
+	    assert (0);
 	}
     }
   r_destroy_tree (&tree);
@@ -1443,7 +1463,7 @@ Collect1 (jmp_buf * e, VNODE * cur, DIRECTION dir, POLYAREA ** contours,
       DEBUGP ("adding contour with %d verticies and direction %c\n",
 	      p->Count, p->Flags.orient ? 'F' : 'B');
 #endif
-      PutContour (e, p, contours, holes, NULL);
+      PutContour (e, p, contours, holes, NULL, NULL, NULL);
     }
   else
     {
@@ -1477,7 +1497,8 @@ Collect (jmp_buf * e, PLINE * a, POLYAREA ** contours, PLINE ** holes,
 
 static int
 cntr_Collect (jmp_buf * e, PLINE ** A, POLYAREA ** contours, PLINE ** holes,
-	      int action, PLINE * parent)
+	      int action, POLYAREA * owner, POLYAREA * parent,
+	      PLINE * parent_contour)
 {
   PLINE *tmprev;
 
@@ -1507,10 +1528,10 @@ cntr_Collect (jmp_buf * e, PLINE ** A, POLYAREA ** contours, PLINE ** holes,
 	  if ((*A)->Flags.status == INSIDE)
 	    {
 	      tmprev = *A;
-	      /* disappear this contour */
+	      /* disappear this contour (rtree entry removed in PutContour) */
 	      *A = tmprev->next;
 	      tmprev->next = NULL;
-	      PutContour (e, tmprev, contours, holes, NULL);
+	      PutContour (e, tmprev, contours, holes, owner, NULL, NULL);
 	      return TRUE;
 	    }
 	  break;
@@ -1518,11 +1539,11 @@ cntr_Collect (jmp_buf * e, PLINE ** A, POLYAREA ** contours, PLINE ** holes,
 	  if ((*A)->Flags.status == INSIDE)
 	    {
 	      tmprev = *A;
-	      /* disappear this contour */
+	      /* disappear this contour (rtree entry removed in PutContour) */
 	      *A = tmprev->next;
 	      tmprev->next = NULL;
 	      poly_InvContour (tmprev);
-	      PutContour (e, tmprev, contours, holes, NULL);
+	      PutContour (e, tmprev, contours, holes, owner, NULL, NULL);
 	      return TRUE;
 	    }
 	  /* break; *//* Fall through (I think this is correct! pcjc2) */
@@ -1531,10 +1552,11 @@ cntr_Collect (jmp_buf * e, PLINE ** A, POLYAREA ** contours, PLINE ** holes,
 	  if ((*A)->Flags.status == OUTSIDE)
 	    {
 	      tmprev = *A;
-	      /* disappear this contour */
+	      /* disappear this contour (rtree entry removed in PutContour) */
 	      *A = tmprev->next;
 	      tmprev->next = NULL;
-	      PutContour (e, tmprev, contours, holes, parent);
+	      PutContour (e, tmprev, contours, holes, owner, parent,
+			  parent_contour);
 	      return TRUE;
 	    }
 	  break;
@@ -1571,7 +1593,7 @@ M_B_AREA_Collect (jmp_buf * e, POLYAREA * bfst, POLYAREA ** contours,
 		next = cur;
 		tmp->next = NULL;
 		tmp->Flags.status = UNKNWN;
-		PutContour (e, tmp, contours, holes, NULL);
+		PutContour (e, tmp, contours, holes, b, NULL, NULL);
 		break;
 	      case PBO_UNITE:
 		break;		/* nothing to do - already included */
@@ -1587,7 +1609,7 @@ M_B_AREA_Collect (jmp_buf * e, POLYAREA * bfst, POLYAREA ** contours,
 		next = cur;
 		tmp->next = NULL;
 		tmp->Flags.status = UNKNWN;
-		PutContour (e, tmp, contours, holes, NULL);
+		PutContour (e, tmp, contours, holes, b, NULL, NULL);
 		break;
 	      case PBO_ISECT:
 	      case PBO_SUB:
@@ -1604,7 +1626,8 @@ M_POLYAREA_Collect (jmp_buf * e, POLYAREA * afst, POLYAREA ** contours,
 		    PLINE ** holes, int action, BOOLp maybe)
 {
   POLYAREA *a = afst;
-  PLINE **cur, **next, *parent;
+  POLYAREA *parent = NULL;	/* Quiet compiler warning */
+  PLINE **cur, **next, *parent_contour;
 
   assert (a != NULL);
   while ((a = a->f) != afst);
@@ -1612,16 +1635,33 @@ M_POLYAREA_Collect (jmp_buf * e, POLYAREA * afst, POLYAREA ** contours,
   do
     {
       if (maybe && a->contours->Flags.status != ISECTED)
-	parent = a->contours;
+	parent_contour = a->contours;
       else
-	parent = NULL;
-      for (cur = &a->contours; *cur != NULL; cur = next)
+	parent_contour = NULL;
+
+      /* Take care of the first contour - so we know if we
+       * can shortcut reparenting some of its children
+       */
+      cur = &a->contours;
+      if (*cur != NULL)
+	{
+	  next = &((*cur)->next);
+	  /* if we disappear a contour, don't advance twice */
+	  if (cntr_Collect (e, cur, contours, holes, action, a, NULL, NULL))
+	    {
+	      parent = (*contours)->b;	/* InsCntr inserts behind the head */
+	      next = cur;
+	    }
+	  else
+	    parent = a;
+	  cur = next;
+	}
+      for (; *cur != NULL; cur = next)
 	{
 	  next = &((*cur)->next);
 	  /* if we disappear a contour, don't advance twice */
-	  if (cntr_Collect
-	      (e, cur, contours, holes, action,
-	       *cur == parent ? NULL : parent))
+	  if (cntr_Collect (e, cur, contours, holes, action, a, parent,
+			    parent_contour))
 	    next = cur;
 	}
     }
@@ -2110,6 +2150,7 @@ poly_Copy0 (POLYAREA ** dst, const POLYAREA * src)
     *dst = calloc (1, sizeof (POLYAREA));
   if (*dst == NULL)
     return FALSE;
+  (*dst)->contour_tree = r_create_tree (NULL, 0, 0);
 
   return poly_Copy1 (*dst, src);
 }
@@ -2126,6 +2167,7 @@ poly_Copy1 (POLYAREA * dst, const POLYAREA * src)
     {
       if (!poly_CopyContour (last, cur))
 	return FALSE;
+      r_insert_entry (dst->contour_tree, (BoxTypePtr) * last, 0);
       last = &(*last)->next;
     }
   return TRUE;
@@ -2185,6 +2227,7 @@ poly_InclContour (POLYAREA * p, PLINE * c)
       p->contours->next = c;
       c->next = tmp;
     }
+  r_insert_entry (p->contour_tree, (BoxTypePtr) c, 0);
   return TRUE;
 }
 
@@ -2454,6 +2497,7 @@ poly_Init (POLYAREA * p)
 {
   p->f = p->b = p;
   p->contours = NULL;
+  p->contour_tree = r_create_tree (NULL, 0, 0);
 }
 
 POLYAREA *
@@ -2488,11 +2532,13 @@ poly_Free (POLYAREA ** p)
   for (cur = (*p)->f; cur != *p; cur = (*p)->f)
     {
       poly_FreeContours (&cur->contours);
+      r_destroy_tree (&cur->contour_tree);
       cur->f->b = cur->b;
       cur->b->f = cur->f;
       free (cur);
     }
   poly_FreeContours (&cur->contours);
+  r_destroy_tree (&cur->contour_tree);
   free (*p), *p = NULL;
 }
 

commit 83c0c7d5eec7431e854592d0d14a0eb0b3dbc456
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    Use rtree of countours when computing an intersection
    
    NOTE: This is more complex than the existing code, and on its own,
          actually slows things down a little.
    
          The intention is that the r-tree should be maintained continually,
          so it doesn't need to be recreated with each call to intersect().

diff --git a/src/polygon.c b/src/polygon.c
index ec3db7e..474474e 100644
--- a/src/polygon.c
+++ b/src/polygon.c
@@ -872,7 +872,7 @@ subtract_accumulated (struct cpInfo *info, PolygonTypePtr polygon)
 {
   if (info->accumulate == NULL)
     return;
-  Subtract (info->accumulate, polygon, True);
+  Subtract (info->accumulate, polygon, true);
   info->accumulate = NULL;
   info->batch_size = 0;
 }
diff --git a/src/polygon1.c b/src/polygon1.c
index 329058e..d2c0798 100644
--- a/src/polygon1.c
+++ b/src/polygon1.c
@@ -509,9 +509,17 @@ typedef struct info
   rtree_t *tree;
   VNODE *v;
   struct seg *s;
-  jmp_buf env, sego, *touch;
+  jmp_buf *env, sego, *touch;
 } info;
 
+typedef struct contour_info
+{
+  PLINE *pa;
+  jmp_buf restart;
+  jmp_buf *getout;
+} contour_info;
+
+
 /*
  * adjust_tree()
  * (C) 2006 harry eaton
@@ -621,7 +629,7 @@ seg_in_seg (const BoxType * b, void *cl)
 	  DEBUGP ("new intersection at (%d, %d)\n", cnt > 1 ? s2[0] : s1[0],
 		  cnt > 1 ? s2[1] : s1[1]);
 #endif
-	  longjmp (i->env, 1);
+	  longjmp (*i->env, 1);
 	}
     }
   return 0;
@@ -679,7 +687,7 @@ get_seg (const BoxType * b, void *cl)
 }
 
 /*
- * intersect()
+ * intersect() (and helpers)
  * (C) 2006, harry eaton
  * This uses an rtree to find A-B intersections. Whenever a new vertex is
  * added, the search for intersections is re-started because the rounding
@@ -697,104 +705,133 @@ get_seg (const BoxType * b, void *cl)
  */
 
 static int
-intersect (jmp_buf * jb, POLYAREA * b, POLYAREA * a, int add)
+contour_bounds_touch (const BoxType * b, void *cl)
 {
-  PLINE *pa, *pb;		/* pline iterators */
+  contour_info *c_info = (contour_info *) cl;
+  PLINE *pa = c_info->pa;
+  PLINE *pb = (PLINE *) b;
   PLINE *rtree_over;
   PLINE *looping_over;
   VNODE *av;			/* node iterators */
   struct info info;
   BoxType box;
 
-  if (add)
-    info.touch = NULL;
+  /* Have seg_in_seg return to our desired location if it touches */
+  info.env = &c_info->restart;
+  info.touch = c_info->getout;
+
+  /* Pick which contour has the fewer points, and do the loop
+   * over that. The r_tree makes hit-testing against a contour
+   * faster, so we want to do that on the bigger contour.
+   */
+  if (pa->Count < pb->Count)
+    {
+      rtree_over = pb;
+      looping_over = pa;
+    }
   else
-    info.touch = jb;
-  setjmp (info.env);		/* we loop back here whenever a vertex is inserted */
-  {
-    pa = a->contours;
-    pb = b->contours;
-    while (pa)			/* Loop over the contours of POLYAREA "a" */
-      {
-	int found_overlapping_a_b_contour = FALSE;
-
-	while (pb)		/* Loop over the contours of POLYAREA "b" */
-	  {
-	    /* Are there overlapping bounds? */
-	    if (pb->xmin <= pa->xmax && pb->xmax >= pa->xmin &&
-		pb->ymin <= pa->ymax && pb->ymax >= pa->ymin)
-	      {
-		found_overlapping_a_b_contour = TRUE;
-		break;
-	      }
-	    pb = pb->next;
-	  }
+    {
+      rtree_over = pa;
+      looping_over = pb;
+    }
 
-	/* If we didn't find anything intersting, move onto the next "a" contour */
-	if (!found_overlapping_a_b_contour)
-	  {
-	    pa = pa->next;
-	    pb = b->contours;
-	    continue;
-	  }
+  av = &looping_over->head;
+  do				/* Loop over the nodes in the smaller contour */
+    {
+      /* check this edge for any insertions */
+      double dx;
+      info.v = av;
+      /* compute the slant for region trimming */
+      dx = av->next->point[0] - av->point[0];
+      if (dx == 0)
+	info.m = 0;
+      else
+	{
+	  info.m = (av->next->point[1] - av->point[1]) / dx;
+	  info.b = av->point[1] - info.m * av->point[0];
+	}
+      box.X2 = (box.X1 = av->point[0]) + 1;
+      box.Y2 = (box.Y1 = av->point[1]) + 1;
 
-	/* something intersects so check the edges of the contour */
+      /* fill in the segment in info corresponding to this node */
+      if (setjmp (info.sego) == 0)
+	{
+	  r_search (looping_over->tree, &box, NULL, get_seg, &info);
+	  assert (0);
+	}
 
-	/* Pick which contour has the fewer points, and do the loop
-	 * over that. The r_tree makes hit-testing against a contour
-	 * faster, so we want to do that on the bigger contour.
-	 */
-	if (pa->Count < pb->Count)
-	  {
-	    rtree_over = pb;
-	    looping_over = pa;
-	  }
-	else
-	  {
-	    rtree_over = pa;
-	    looping_over = pb;
-	  }
+      /* NB: If this actually hits anything, we are teleported back to the beginning */
+      info.tree = rtree_over->tree;
+      if (info.tree)
+	if (UNLIKELY (r_search (info.tree, &info.s->box,
+				seg_in_region, seg_in_seg, &info)))
+	  return err_no_memory;	/* error */
+    }
+  while ((av = av->next) != &looping_over->head);
+  return 0;
+}
 
-	av = &looping_over->head;
-	do			/* Loop over the nodes in the smaller contour */
-	  {
-	    /* check this edge for any insertions */
-	    double dx;
-	    info.v = av;
-	    /* compute the slant for region trimming */
-	    dx = av->next->point[0] - av->point[0];
-	    if (dx == 0)
-	      info.m = 0;
-	    else
-	      {
-		info.m = (av->next->point[1] - av->point[1]) / dx;
-		info.b = av->point[1] - info.m * av->point[0];
-	      }
-	    box.X2 = (box.X1 = av->point[0]) + 1;
-	    box.Y2 = (box.Y1 = av->point[1]) + 1;
+static int
+intersect (jmp_buf * jb, POLYAREA * b, POLYAREA * a, int add)
+{
+  POLYAREA *t;
+  PLINE *pa, *pb;
+  int ca = 0, cb = 0;
+  contour_info c_info;
+  rtree_t *b_contour_tree = NULL;
 
-	    /* fill in the segment in info corresponding to this node */
-	    if (setjmp (info.sego) == 0)
-	      {
-		r_search (looping_over->tree, &box, NULL, get_seg, &info);
-		assert (0);
-	      }
+  /* count the contours in a and b */
+  for (pa = a->contours; pa; pa = pa->next, ca++);
+  for (pb = b->contours; pb; pb = pb->next, cb++);
 
-	    /* NB: If this actually hits anything, we are teleported back to the beginning */
-	    info.tree = rtree_over->tree;
-	    if (info.tree)
-	      if (UNLIKELY (r_search (info.tree, &info.s->box,
-				      seg_in_region, seg_in_seg, &info)))
-		return err_no_memory;	/* error */
-	  }
-	while ((av = av->next) != &looping_over->head);
+  /* Make the contour r-tree from the one with fewest contours */
+  /* Inserting entries is more expensive than searching
+   * the r-tree. We do one ca times, the other cb times. */
+  if (ca < cb)
+    {
+      t = b;
+      b = a;
+      a = t;
+    }
+
+  /* make an rtree of b's contours */
+  b_contour_tree = r_create_tree (NULL, 0, 0);
+  for (pb = b->contours; pb != NULL; pb = pb->next)
+    r_insert_entry (b_contour_tree, (const BoxType *) pb, 0);
+
+  /* FIXME: We might actually need to re-build the r_tree if the geometry changes */
+  setjmp (c_info.restart);	/* we loop back here whenever a vertex is inserted */
+
+  for (pa = a->contours; pa; pa = pa->next)	/* Loop over the contours of POLYAREA "a" */
+    {
+      BoxType sb;
+      jmp_buf out;
+      int retval;
+
+      c_info.getout = NULL;
+      c_info.pa = pa;
+
+      if (!add)
+	{
+	  retval = setjmp (out);
+	  if (retval)
+	    {
+	      /* The intersection test short-circuited back here,
+	       * we need to clean up, then longjmp to jb */
+	      r_destroy_tree (&b_contour_tree);
+	      longjmp (*jb, retval);
+	    }
+	  c_info.getout = &out;
+	}
+
+      sb.X1 = pa->xmin;
+      sb.Y1 = pa->ymin;
+      sb.X2 = pa->xmax + 1;
+      sb.Y2 = pa->ymax + 1;
+
+      r_search (b_contour_tree, &sb, NULL, contour_bounds_touch, &c_info);
+    }
 
-	/* Continue the with the _same_ "a" contour,
-	 * testing it against the next "b" contour.
-	 */
-	pb = pb->next;
-      }
-  }				/* end of setjmp loop */
   return 0;
 }
 

commit 7c6ae5c49c59275e712efa453688c140f741fb3c
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    polygon.c: Accumulate vias and lines into batches before subtracting them
    
    Accumulate polygons to clear from lines and pins in batches, then
    clear from the polygon. Not quite sure why, but this _really_ seems to
    speed up loading very complex boards. (e.g. 50sec -> 10sec for one example).
    
    Possibly this is because withing the assembled batches, it is cheaper to
    produce a more unified contour (touching lines), and the complex contours
    of the main polygon are broken less frequently.
    
    It isn't quite clear why this helps so much for pins / vias (which won't
    usually touch each-other), however it changes a 50sec load time to 10 sec.
    This could perhaps be because any contours which are smashed by clearance
    of closely spaced vias / pins now only incurr the penalty of breaking the
    main contour once every batch (100 vias / pins).
    
    Batch sizes (20 for lines, 100 for pins / vias) aren't necessarily optimal!
    
    
    Also, clear pins and vias last...
    
    There is a chance these objects are simpler, and just end up as holes in
    the main polygon, rather than causing a contour intersection. This means
    it is cheaper to add them last.
    
    If we add them first, and make the polygon complex, objects (usually
    lines) which pierce the polygon's outer contour cause all the holes to
    be removed and queued for re-insersion after the new contour is
    constructed.

diff --git a/src/polygon.c b/src/polygon.c
index f2745ed..ec3db7e 100644
--- a/src/polygon.c
+++ b/src/polygon.c
@@ -109,6 +109,8 @@ RCSID ("$Id$");
 #define ROUND(x) ((long)(((x) >= 0 ? (x) + 0.5  : (x) - 0.5)))
 
 #define UNSUBTRACT_BLOAT 10
+#define SUBTRACT_PIN_VIA_BATCH_SIZE 100
+#define SUBTRACT_LINE_BATCH_SIZE 20
 
 /* ---------------------------------------------------------------------------
  * local prototypes
@@ -860,22 +862,60 @@ struct cpInfo
   LayerType *layer;
   PolygonType *polygon;
   bool solder;
+  POLYAREA *accumulate;
+  int batch_size;
   jmp_buf env;
 };
 
+static void
+subtract_accumulated (struct cpInfo *info, PolygonTypePtr polygon)
+{
+  if (info->accumulate == NULL)
+    return;
+  Subtract (info->accumulate, polygon, True);
+  info->accumulate = NULL;
+  info->batch_size = 0;
+}
+
 static int
 pin_sub_callback (const BoxType * b, void *cl)
 {
   PinTypePtr pin = (PinTypePtr) b;
   struct cpInfo *info = (struct cpInfo *) cl;
   PolygonTypePtr polygon;
+  POLYAREA *np;
+  POLYAREA *merged;
+  Cardinal i;
 
   /* don't subtract the object that was put back! */
   if (b == info->other)
     return 0;
   polygon = info->polygon;
-  if (SubtractPin (info->data, pin, info->layer, polygon) < 0)
-    longjmp (info->env, 1);
+
+  if (pin->Clearance == 0)
+    return 0;
+  i = GetLayerNumber (info->data, info->layer);
+  if (TEST_THERM (i, pin))
+    {
+      np = ThermPoly ((PCBTypePtr) (info->data->pcb), pin, i);
+      if (!np)
+        return 1;
+    }
+  else
+    {
+      np = PinPoly (pin, pin->Thickness, pin->Clearance);
+      if (!np)
+        longjmp (info->env, 1);
+    }
+
+  poly_Boolean_free (info->accumulate, np, &merged, PBO_UNITE);
+  info->accumulate = merged;
+
+  info->batch_size ++;
+
+  if (info->batch_size == SUBTRACT_PIN_VIA_BATCH_SIZE)
+    subtract_accumulated (info, polygon);
+
   return 1;
 }
 
@@ -925,6 +965,8 @@ line_sub_callback (const BoxType * b, void *cl)
   LineTypePtr line = (LineTypePtr) b;
   struct cpInfo *info = (struct cpInfo *) cl;
   PolygonTypePtr polygon;
+  POLYAREA *np;
+  POLYAREA *merged;
 
   /* don't subtract the object that was put back! */
   if (b == info->other)
@@ -932,8 +974,17 @@ line_sub_callback (const BoxType * b, void *cl)
   if (!TEST_FLAG (CLEARLINEFLAG, line))
     return 0;
   polygon = info->polygon;
-  if (SubtractLine (line, polygon) < 0)
+
+  if (!(np = LinePoly (line, line->Thickness + line->Clearance)))
     longjmp (info->env, 1);
+
+  poly_Boolean_free (info->accumulate, np, &merged, PBO_UNITE);
+  info->accumulate = merged;
+  info->batch_size ++;
+
+  if (info->batch_size == SUBTRACT_LINE_BATCH_SIZE)
+    subtract_accumulated (info, polygon);
+
   return 1;
 }
 
@@ -992,21 +1043,26 @@ clearPoly (DataTypePtr Data, LayerTypePtr Layer, PolygonType * polygon,
 
   if (setjmp (info.env) == 0)
     {
-      r = r_search (Data->via_tree, &region, NULL, pin_sub_callback, &info);
-      r += r_search (Data->pin_tree, &region, NULL, pin_sub_callback, &info);
+      r = 0;
+      info.accumulate = NULL;
+      info.batch_size = 0;
+      if (info.solder || group == Group (Data, max_layer + COMPONENT_LAYER))
+	r += r_search (Data->pad_tree, &region, NULL, pad_sub_callback, &info);
       GROUP_LOOP (Data, group);
       {
         r +=
           r_search (layer->line_tree, &region, NULL, line_sub_callback,
                     &info);
+        subtract_accumulated (&info, polygon);
         r +=
           r_search (layer->arc_tree, &region, NULL, arc_sub_callback, &info);
 	r +=
           r_search (layer->text_tree, &region, NULL, text_sub_callback, &info);
       }
       END_LOOP;
-      if (info.solder || group == Group (Data, max_layer + COMPONENT_LAYER))
-	r += r_search (Data->pad_tree, &region, NULL, pad_sub_callback, &info);
+      r += r_search (Data->via_tree, &region, NULL, pin_sub_callback, &info);
+      r += r_search (Data->pin_tree, &region, NULL, pin_sub_callback, &info);
+      subtract_accumulated (&info, polygon);
     }
   polygon->NoHolesValid = 0;
   return r;



_______________________________________________
geda-cvs mailing list
geda-cvs@xxxxxxxxxxxxxx
http://www.seul.org/cgi-bin/mailman/listinfo/geda-cvs