summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornobody <nobody@gnome.org>2005-01-25 12:31:44 +0000
committernobody <nobody@gnome.org>2005-01-25 12:31:44 +0000
commitd3c859d05d0c4972ec99ac4c13f45a00fc886ae5 (patch)
treec68e48ba3b085a8231d438f549a29091cd9da5aa
parent75184c2309143d2e132324000c04b5aa50732abe (diff)
This commit was manufactured by cvs2svn to create tagOOO_BUILD_1_9_72-second_try
'OOO_BUILD_1_9_72-second_try'.
-rw-r--r--patches/src680/buildfix-forms.diff38
-rw-r--r--patches/src680/buildfix-sfx2.diff14
-rw-r--r--patches/src680/buildfix-vcl.diff52
-rw-r--r--patches/src680/cleanup-vcl-nwf.diff1691
-rw-r--r--patches/src680/desktop-bootstrap-debug.diff25
-rw-r--r--patches/src680/fix-vcl-kde.diff96
-rw-r--r--patches/src680/fpicker-gnome-build.diff28
-rw-r--r--patches/src680/icons-config_office.diff45
-rw-r--r--patches/src680/icons-instsetoo_native.diff35
-rw-r--r--patches/src680/install-rework.diff217
-rw-r--r--patches/src680/parallel-libxml2-makefile_mk.diff10
-rw-r--r--patches/src680/scp-vclplug-kde.diff27
-rw-r--r--patches/src680/setup2-update-symlink.diff10
-rw-r--r--patches/src680/speed-lang-cache.diff20
-rw-r--r--patches/src680/system-libstdcpp.diff71
-rw-r--r--patches/src680/system-mozilla-moz.diff17
-rw-r--r--patches/src680/system-mozilla-xmlsecurity-nssrenam.diff52
-rw-r--r--patches/src680/vcl-force-desktop.diff15
-rw-r--r--patches/src680/vcl-gtk-rtl-fix.diff64
-rw-r--r--patches/src680/vcl-prelight-industrial.diff21
-rw-r--r--patches/src680/vcl-util-makefile-kde.diff11
-rw-r--r--patches/src680/win32-internal-libart.diff4082
-rw-r--r--patches/src680/win32-libart-build.diff106
-rw-r--r--src/openabout_nld.pngbin0 -> 14501 bytes
-rw-r--r--src/openintro_nld.pngbin0 -> 39979 bytes
25 files changed, 6747 insertions, 0 deletions
diff --git a/patches/src680/buildfix-forms.diff b/patches/src680/buildfix-forms.diff
new file mode 100644
index 000000000..38dd40e11
--- /dev/null
+++ b/patches/src680/buildfix-forms.diff
@@ -0,0 +1,38 @@
+Index: forms/source/xforms/submission/makefile.mk
+===================================================================
+RCS file: /cvs/gsl/forms/source/xforms/submission/makefile.mk,v
+retrieving revision 1.2
+diff -u -r1.2 makefile.mk
+--- forms/source/xforms/submission/makefile.mk 16 Nov 2004 10:58:30 -0000 1.2
++++ forms/source/xforms/submission/makefile.mk 14 Dec 2004 10:26:23 -0000
+@@ -71,8 +71,11 @@
+
+ .INCLUDE : settings.mk
+
+-# --- Files --------------------------------------------------------
++.IF "$(SYSTEM_LIBXML)" == "YES"
++CFLAGS+=-DSYSTEM_LIBXML $(LIBXML_CFLAGS)
++.ENDIF
+
++# --- Files --------------------------------------------------------
+
+ SLOFILES = \
+ $(SLO)$/serialization_app_xml.obj \
+Index: forms/source/xforms/xpathlib/makefile.mk
+===================================================================
+RCS file: /cvs/gsl/forms/source/xforms/xpathlib/makefile.mk,v
+retrieving revision 1.2
+diff -u -r1.2 makefile.mk
+--- forms/source/xforms/xpathlib/makefile.mk 16 Nov 2004 11:02:09 -0000 1.2
++++ forms/source/xforms/xpathlib/makefile.mk 14 Dec 2004 10:26:23 -0000
+@@ -73,6 +73,10 @@
+
+ INCPRE+=$(PRJ)$/source$/inc
+
++.IF "$(SYSTEM_LIBXML)" == "YES"
++CFLAGS+=-DSYSTEM_LIBXML $(LIBXML_CFLAGS)
++.ENDIF
++
+ # --- Files --------------------------------------------------------
+
+ SLOFILES = \
diff --git a/patches/src680/buildfix-sfx2.diff b/patches/src680/buildfix-sfx2.diff
new file mode 100644
index 000000000..79bce9c93
--- /dev/null
+++ b/patches/src680/buildfix-sfx2.diff
@@ -0,0 +1,14 @@
+--- sfx2/source/doc/doctempl.cxx 2004-12-07 13:00:04.100380992 +0100
++++ sfx2/source/doc/doctempl.cxx 2004-12-07 13:01:15.993451584 +0100
+@@ -2678,7 +2678,10 @@ sal_Bool getTextProperty_Impl( Content&
+ aAnyValue >>= rPropValue;
+
+ if ( SfxURLRelocator_Impl::propertyCanContainOfficeDir( rPropName ) )
+- SfxURLRelocator_Impl( ::comphelper::getProcessServiceFactory() ).makeAbsoluteURL( rPropValue );
++ {
++ SfxURLRelocator_Impl aRelocImpl( ::comphelper::getProcessServiceFactory() );
++ aRelocImpl.makeAbsoluteURL( rPropValue );
++ }
+
+ bGotProperty = sal_True;
+ }
diff --git a/patches/src680/buildfix-vcl.diff b/patches/src680/buildfix-vcl.diff
new file mode 100644
index 000000000..96124f411
--- /dev/null
+++ b/patches/src680/buildfix-vcl.diff
@@ -0,0 +1,52 @@
+--- vcl/source/window/dockingarea.cxx 16 Nov 2004 15:10:38 -0000 1.2
++++ vcl/source/window/dockingarea.cxx 6 Dec 2004 16:09:51 -0000
+@@ -209,10 +209,11 @@
+ if( !ImplGetSVData()->maNWFData.mbDockingAreaSeparateTB )
+ {
+ // draw a single toolbar background covering the whole docking area
+- Region aCtrlRegion( Rectangle( Point(), GetOutputSizePixel() ) );
++ Point tmp;
++ Region aCtrlRegion( Rectangle( tmp, GetOutputSizePixel() ) );
+
+ DrawNativeControl( CTRL_TOOLBAR, IsHorizontal() ? PART_DRAW_BACKGROUND_HORZ : PART_DRAW_BACKGROUND_VERT,
+- aCtrlRegion, nState, aControlValue, rtl::OUString() );
++ aCtrlRegion, (int)nState, aControlValue, rtl::OUString() );
+ }
+ else
+ {
+--- vcl/source/window/menu.cxx 17 Nov 2004 13:19:35 -0000 1.114
++++ vcl/source/window/menu.cxx 6 Dec 2004 16:10:01 -0000
+@@ -2201,11 +2201,12 @@
+ ImplControlValue aVal;
+ Region aNativeBounds;
+ Region aNativeContent;
+- Region aCtrlRegion( Rectangle( Point( 0, 0 ), Size( 100, 15 ) ) );
++ Point tmp( 0, 0 );
++ Region aCtrlRegion( Rectangle( tmp, Size( 100, 15 ) ) );
+ if( pWindow->GetNativeControlRegion( ControlType(CTRL_MENUBAR),
+ ControlPart(PART_ENTIRE_CONTROL),
+ aCtrlRegion,
+- ControlState(CTRL_STATE_ENABLED),
++ (int) ControlState(CTRL_STATE_ENABLED),
+ aVal,
+ OUString(),
+ aNativeBounds,
+@@ -4837,7 +4838,8 @@
+ aMenubarValue.maTopDockingAreaHeight = ImplGetTopDockingAreaHeight( this );
+ aControlValue.setOptionalVal( (void *)(&aMenubarValue) );
+
+- Region aBgRegion( Rectangle( Point(0,0), GetOutputSizePixel() ) );
++ Point tmp(0,0);
++ Region aBgRegion( Rectangle( tmp, GetOutputSizePixel() ) );
+ DrawNativeControl( CTRL_MENUBAR, PART_ENTIRE_CONTROL,
+ aBgRegion,
+ CTRL_STATE_ENABLED,
+@@ -4847,7 +4849,7 @@
+ // draw selected item
+ DrawNativeControl( CTRL_MENUBAR, PART_MENU_ITEM,
+ Region( aRect ),
+- CTRL_STATE_ENABLED | CTRL_STATE_SELECTED,
++ (int)(CTRL_STATE_ENABLED | CTRL_STATE_SELECTED),
+ aControlValue,
+ OUString() );
+ }
diff --git a/patches/src680/cleanup-vcl-nwf.diff b/patches/src680/cleanup-vcl-nwf.diff
new file mode 100644
index 000000000..176526c96
--- /dev/null
+++ b/patches/src680/cleanup-vcl-nwf.diff
@@ -0,0 +1,1691 @@
+--- vcl/unx/source/app/makefile.mk 2004-09-20 10:41:50.000000000 +0200
++++ vcl/unx/source/app/makefile.mk 2004-11-03 18:38:02.888617216 +0100
+@@ -110,10 +110,6 @@ CDEFS+=-DHAVE_LIBSN
+ CFLAGS+=$(LIBSN_CFLAGS)
+ .ENDIF
+
+-.IF "$(WITH_WIDGETSET)"!=""
+-CFLAGS+= $(WIDGETSET_CFLAGS)
+-.ENDIF
+-
+ .IF "$(USE_XINERAMA)" != "NO"
+ CDEFS+=-DUSE_XINERAMA
+ .ENDIF
+--- vcl/unx/source/gdi/makefile.mk 2004-05-10 17:58:32.000000000 +0200
++++ vcl/unx/source/gdi/makefile.mk 2004-11-03 18:38:56.573455880 +0100
+@@ -93,17 +93,9 @@ SLOFILES= \
+ $(SLO)$/xlfd_extd.obj \
+ $(SLO)$/xlfd_smpl.obj \
+ $(SLO)$/salgdi3.obj \
++ $(SLO)$/kdeint.obj \
+ $(SLO)$/pspgraphics.obj
+
+-.IF "$(WITH_WIDGETSET)"=="kde"
+- # salnativewidgets-kde.cxx contains own implementation of KDEintegrator
+- SLOFILES+=$(SLO)/salnativewidgets-kde.obj
+- CFLAGS+=$(WIDGETSET_CFLAGS)
+-.ELSE
+- SLOFILES+= \
+- $(SLO)$/kdeint.obj
+-.ENDIF
+-
+ .IF "$(USE_XPRINT)" == "TRUE"
+ CFLAGS+=-D_USE_PRINT_EXTENSION_=1
+ SLOFILES+=$(SLO)$/xprintext.obj
+--- vcl/unx/source/gdi/salnativewidgets-kde.cxx 2004-10-13 10:59:33.000000000 +0200
++++ vcl/unx/source/gdi/salnativewidgets-kde.cxx 1970-01-01 01:00:00.000000000 +0100
+@@ -1,1641 +0,0 @@
+-/*************************************************************************
+- *
+- * $RCSfile: salnativewidgets-kde.cxx,v $
+- *
+- * $Revision: 1.3 $
+- *
+- * last change: $Author: hr $ $Date: 2004/10/13 08:59:33 $
+- *
+- * The Contents of this file are made available subject to the terms of
+- * either of the following licenses
+- *
+- * - GNU Lesser General Public License Version 2.1
+- * - Sun Industry Standards Source License Version 1.1
+- *
+- * Sun Microsystems Inc., October, 2000
+- *
+- * GNU Lesser General Public License Version 2.1
+- * =============================================
+- * Copyright 2000 by Sun Microsystems, Inc.
+- * 901 San Antonio Road, Palo Alto, CA 94303, USA
+- *
+- * This library is free software; you can redistribute it and/or
+- * modify it under the terms of the GNU Lesser General Public
+- * License version 2.1, as published by the Free Software Foundation.
+- *
+- * This library 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
+- * Lesser General Public License for more details.
+- *
+- * You should have received a copy of the GNU Lesser General Public
+- * License along with this library; if not, write to the Free Software
+- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+- * MA 02111-1307 USA
+- *
+- *
+- * Sun Industry Standards Source License Version 1.1
+- * =================================================
+- * The contents of this file are subject to the Sun Industry Standards
+- * Source 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.openoffice.org/license.html.
+- *
+- * Software provided under this License is provided on an "AS IS" basis,
+- * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
+- * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
+- * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
+- * See the License for the specific provisions governing your rights and
+- * obligations concerning the Software.
+- *
+- * The Initial Developer of the Original Code is: Sun Microsystems, Inc.
+- *
+- * Copyright: 2000 by Sun Microsystems, Inc.
+- *
+- * All Rights Reserved.
+- *
+- * Contributor(s): Juergen Keil
+- * Jan Holesovsky <kendy@artax.karlin.mff.cuni.cz>
+- * Lukas Tinkl <lukas@kde.org>
+- *
+- *
+- ************************************************************************/
+-
+-#define _SV_SALNATIVEWIDGETS_KDE_CXX
+-
+-// Hack, but needed because of conflicting types...
+-#define Region QtXRegion
+-
+-#include <qcheckbox.h>
+-#include <qcombobox.h>
+-#include <qframe.h>
+-#include <qlineedit.h>
+-#include <qlistview.h>
+-#include <qpainter.h>
+-#include <qpushbutton.h>
+-#include <qradiobutton.h>
+-#include <qrangecontrol.h>
+-#include <qtabbar.h>
+-#include <qtabwidget.h>
+-#include <qwidget.h>
+-
+-#include <kaboutdata.h>
+-#include <kapplication.h>
+-#include <kcmdlineargs.h>
+-#include <kconfig.h>
+-#include <kglobal.h>
+-#include <kmainwindow.h>
+-#include <kmenubar.h>
+-#include <kstyle.h>
+-
+-#undef Region
+-
+-#include <salunx.h>
+-
+-#ifndef _SV_SALDATA_HXX
+-#include <saldata.hxx>
+-#endif
+-
+-#ifndef _SV_SALDISP_HXX
+-#include <saldisp.hxx>
+-#endif
+-
+-#ifndef _SV_SALGDI_HXX
+-#include <salgdi.hxx>
+-#endif
+-
+-#ifndef _SV_KDEINT_HXX
+-#include <kdeint.hxx>
+-#endif
+-
+-#ifndef _SV_SETTINGS_HXX
+-#include <settings.hxx>
+-#endif
+-
+-#include <iostream>
+-
+-using namespace ::rtl;
+-
+-/** Cached native widgets.
+-
+- A class which caches and paints the native widgets.
+-*/
+-class WidgetPainter
+-{
+- protected:
+- /** Cached push button.
+-
+- It is necessary for the QStyle::drawControl(). The buttons are created
+- on demand and they are still hidden (no QWidget::show() is called).
+- */
+- QPushButton *m_pPushButton;
+-
+- /** Cached radio button.
+-
+- @see m_pPushButton
+- */
+- QRadioButton *m_pRadioButton;
+-
+- /** Cached check box.
+-
+- @see m_pPushButton
+- */
+- QCheckBox *m_pCheckBox;
+-
+- /** Cached combo box.
+-
+- @see m_pPushButton
+- */
+- QComboBox *m_pComboBox;
+-
+- /** Cached editable combo box.
+-
+- Needed, because some styles do not like dynamic changes
+- (QComboBox::setEditable()).
+-
+- @see m_pPushButton
+- */
+- QComboBox *m_pEditableComboBox;
+-
+- /** Cached line edit box.
+-
+- @see m_pPushButton
+- */
+- QLineEdit *m_pLineEdit;
+-
+- /** Cached spin box.
+-
+- @see m_pPushButton
+- */
+- QSpinWidget *m_pSpinWidget;
+-
+- /** Cached spin box'es line edit.
+-
+- @see m_pPushButton
+- */
+- QLineEdit *m_pSpinEdit;
+-
+- /** Cached tab.
+-
+- Left, middle, right tab and a tab which is alone.
+-
+- @see m_pPushButton
+- */
+- QTab *m_pTabLeft, *m_pTabMiddle, *m_pTabRight, *m_pTabAlone;
+-
+- /** Cached tab bar's parent widget.
+-
+- Needed, because the Qt windows style checks for the availability
+- of tab bar's parent. We cannot use m_pTabWidget, because
+- TabWidget::setTabBar() and TabWidget::tabBar() methods are
+- protected.
+-
+- @see m_pPushButton, m_pTabWidget
+- */
+- QWidget *m_pTabBarParent;
+-
+- /** Cached tab bar widget.
+-
+- @see m_pPushButton
+- */
+- QTabBar *m_pTabBar;
+-
+- /** Cached tab widget.
+-
+- We need it to draw the tab page. It cannot be used to draw the
+- tabs themselves, because the drawing has to be tweaked a little
+- due to not enough information from VCL.
+-
+- @see m_pPushButton, m_pTabBarParent
+- */
+- QTabWidget *m_pTabWidget;
+-
+- /** Cached list view.
+-
+- @see m_pPushButton
+- */
+- QListView *m_pListView;
+-
+- /** Cached scroll bar.
+-
+- @see m_pPushButton
+- */
+- QScrollBar *m_pScrollBar;
+-
+- // TODO other widgets
+-
+- public:
+- /** Implicit constructor.
+-
+- It creates an empty WidgetPainter with all the cached widgets initialized
+- to NULL. The widgets are created on demand and they are still hidden
+- (no QWidget::show()), because they are needed just as a parameter for
+- QStyle::drawControl().
+-
+- @see m_pPushButton
+- */
+- WidgetPainter( void );
+-
+- /** Destructor.
+-
+- Destruct all the cached widgets.
+- */
+- virtual ~WidgetPainter( void );
+-
+- /** Paints the specified widget to the X window.
+-
+- Use X calls to bitblt (bit block transfer) the widget qWidget to
+- the window specified by drawable with the style defined by nStyle.
+-
+- @param qWidget
+- A pointer to the cached widget.
+-
+- @param nState
+- The state of the control (focused, on/off, ...)
+-
+- @param aValue
+- The value (true/false, ...)
+-
+- @param dpy
+- The display to be used by the X calls.
+-
+- @param drawable
+- The destination X window.
+-
+- @param gc
+- The graphics context.
+- */
+- BOOL drawStyledWidget( QWidget *pWidget,
+- ControlState nState, const ImplControlValue& aValue,
+- Display *dpy, XLIB_Window drawable, GC gc );
+-
+- /** 'Get' method for push button.
+-
+- The method returns the cached push button. It is constructed if it
+- does not exist. It has NULL as a parent and it stays hidden, but it
+- is necessary for the drawStyledWidget() method.
+-
+- @return valid push button.
+- */
+- QPushButton *pushButton( const Region& rControlRegion, BOOL bDefault );
+-
+- /** 'Get' method for radio button.
+-
+- @see pushButton()
+- */
+- QRadioButton *radioButton( const Region& rControlRegion );
+-
+- /** 'Get' method for check box.
+-
+- @see pushButton()
+- */
+- QCheckBox *checkBox( const Region& rControlRegion );
+-
+- /** 'Get' method for combo box.
+-
+- It returns m_pComboBox or m_pEditableComboBox according to
+- bEditable.
+-
+- @see pushButton(), m_pEditableComboBox
+- */
+- QComboBox *comboBox( const Region& rControlRegion, BOOL bEditable );
+-
+- /** 'Get' method for line edit box.
+-
+- @see pushButton()
+- */
+- QLineEdit *lineEdit( const Region& rControlRegion );
+-
+- /** 'Get' method for spin box.
+-
+- @see pushButton()
+- */
+- QSpinWidget *spinWidget( const Region& rControlRegion );
+-
+- /** 'Get' method for tab bar.
+-
+- @see pushButton()
+- */
+- QTabBar *tabBar( const Region& rControlRegion );
+-
+- /** 'Get' method for tab widget.
+-
+- @see pushButton()
+- */
+- QTabWidget *tabWidget( const Region& rControlRegion );
+-
+- /** 'Get' method for list view.
+-
+- @see pushButton()
+- */
+- QListView *listView( const Region& rControlRegion );
+-
+- /** 'Get' method for scroll bar.
+-
+- @see pushButton()
+- */
+- QScrollBar *scrollBar( const Region& rControlRegion,
+- BOOL bHorizontal, const ImplControlValue& aValue );
+-
+- // TODO other widgets
+-
+- protected:
+- /** Style conversion function.
+-
+- Conversion function between VCL ControlState together with
+- ImplControlValue and Qt state flags.
+-
+- @param nState
+- State of the widget (default, focused, ...) as defined in Native
+- Widget Framework.
+-
+- @param aValue
+- Value held by the widget (on, off, ...)
+- */
+- QStyle::SFlags vclStateValue2SFlags( ControlState nState, const ImplControlValue& aValue );
+-
+- public:
+- /** Convert VCL Region to QRect.
+-
+- @param rControlRegion
+- The region to convert.
+-
+- @return
+- The bounding box of the region.
+- */
+- static QRect region2QRect( const Region& rControlRegion );
+-};
+-
+-WidgetPainter::WidgetPainter( void )
+- : m_pPushButton( NULL ),
+- m_pRadioButton( NULL ),
+- m_pCheckBox( NULL ),
+- m_pComboBox( NULL ),
+- m_pEditableComboBox( NULL ),
+- m_pLineEdit( NULL ),
+- m_pSpinWidget( NULL ),
+- m_pSpinEdit( NULL ),
+- m_pTabLeft( NULL ),
+- m_pTabMiddle( NULL ),
+- m_pTabRight( NULL ),
+- m_pTabAlone( NULL ),
+- m_pTabBarParent( NULL ),
+- m_pTabBar( NULL ),
+- m_pTabWidget( NULL ),
+- m_pListView( NULL ),
+- m_pScrollBar( NULL )
+-{
+-}
+-
+-WidgetPainter::~WidgetPainter( void )
+-{
+- delete m_pPushButton, m_pPushButton = NULL;
+- delete m_pRadioButton, m_pRadioButton = NULL;
+- delete m_pCheckBox, m_pCheckBox = NULL;
+- delete m_pComboBox, m_pComboBox = NULL;
+- delete m_pEditableComboBox, m_pEditableComboBox = NULL;
+- delete m_pLineEdit, m_pLineEdit = NULL;
+- delete m_pSpinWidget, m_pSpinWidget = NULL;
+- delete m_pSpinEdit, m_pSpinEdit = NULL;
+- delete m_pTabLeft, m_pTabLeft = NULL;
+- delete m_pTabMiddle, m_pTabMiddle = NULL;
+- delete m_pTabRight, m_pTabRight = NULL;
+- delete m_pTabAlone, m_pTabAlone = NULL;
+- delete m_pTabBarParent, m_pTabBarParent = NULL;
+- delete m_pTabBar, m_pTabBar = NULL;
+- delete m_pTabWidget, m_pTabWidget = NULL;
+- delete m_pListView, m_pListView = NULL;
+- delete m_pScrollBar, m_pScrollBar = NULL;
+-}
+-
+-BOOL WidgetPainter::drawStyledWidget( QWidget *pWidget,
+- ControlState nState, const ImplControlValue& aValue,
+- Display *dpy, XLIB_Window drawable, GC gc )
+-{
+- if ( !pWidget )
+- return FALSE;
+-
+- // Normalize the widget
+- QPoint qWidgetPos( pWidget->pos() );
+- pWidget->move( 0, 0 );
+-
+- // Enable/disable the widget
+- pWidget->setEnabled( nState & CTRL_STATE_ENABLED );
+-
+- // Create pixmap to paint to
+- QPixmap qPixmap( pWidget->width(), pWidget->height() );
+- QPainter qPainter( &qPixmap );
+- QRect qRect( 0, 0, pWidget->width(), pWidget->height() );
+-
+- // Use the background of the widget
+- qPixmap.fill( pWidget, QPoint(0, 0) );
+-
+- // Convert the flags
+- QStyle::SFlags nStyle = vclStateValue2SFlags( nState, aValue );
+-
+- // Store the widget class
+- const char *pClassName = pWidget->className();
+-
+- // Draw the widget to the pixmap
+- if ( strcmp( "QPushButton", pClassName ) == 0 )
+- {
+- // Workaround for the Platinum style.
+- // Platinum takes the state directly from the widget, not from SFlags.
+- QPushButton *pPushButton = static_cast<QPushButton *>( pWidget->qt_cast( "QPushButton" ) );
+- if ( pPushButton )
+- {
+- pPushButton->setDown ( nStyle & QStyle::Style_Down );
+- pPushButton->setOn ( nStyle & QStyle::Style_On );
+- pPushButton->setEnabled( nStyle & QStyle::Style_Enabled );
+- }
+-
+- kapp->style().drawControl( QStyle::CE_PushButton,
+- &qPainter, pWidget, qRect,
+- pWidget->colorGroup(), nStyle );
+- }
+- else if ( strcmp( "QRadioButton", pClassName ) == 0 )
+- {
+- // Bitblt from the screen, because the radio buttons are usually not
+- // rectangular, and there could be a bitmap under them
+- GC aTmpGC = XCreateGC( dpy, qPixmap.handle(), 0, NULL );
+- XCopyArea( dpy,
+- drawable, qPixmap.handle(),
+- aTmpGC,
+- qWidgetPos.x(), qWidgetPos.y(), qRect.width(), qRect.height(),
+- 0, 0 );
+- XFreeGC( dpy, aTmpGC );
+-
+- kapp->style().drawControl( QStyle::CE_RadioButton,
+- &qPainter, pWidget, qRect,
+- pWidget->colorGroup(), nStyle );
+- }
+- else if ( strcmp( "QCheckBox", pClassName ) == 0 )
+- {
+- kapp->style().drawControl( QStyle::CE_CheckBox,
+- &qPainter, pWidget, qRect,
+- pWidget->colorGroup(), nStyle );
+- }
+- else if ( strcmp( "QComboBox", pClassName ) == 0 )
+- {
+- kapp->style().drawComplexControl( QStyle::CC_ComboBox,
+- &qPainter, pWidget, qRect,
+- pWidget->colorGroup(), nStyle );
+-
+- // Editable combo box uses the background of the associated edit box
+- QComboBox *pComboBox = static_cast<QComboBox *>( pWidget->qt_cast( "QComboBox" ) );
+- if ( pComboBox && pComboBox->editable() && pComboBox->lineEdit() )
+- {
+- QColorGroup::ColorRole eColorRole = ( pComboBox->isEnabled() )?
+- QColorGroup::Base: QColorGroup::Background;
+- qPainter.fillRect(
+- kapp->style().querySubControlMetrics( QStyle::CC_ComboBox,
+- pComboBox, QStyle::SC_ComboBoxEditField ),
+- pComboBox->lineEdit()->colorGroup().brush( eColorRole ) );
+- }
+- }
+- else if ( strcmp( "QLineEdit", pClassName ) == 0 )
+- {
+- kapp->style().drawPrimitive( QStyle::PE_PanelLineEdit,
+- &qPainter, qRect,
+- pWidget->colorGroup(), nStyle | QStyle::Style_Sunken );
+- }
+- else if ( strcmp( "QSpinWidget", pClassName ) == 0 )
+- {
+- SpinbuttonValue *pValue = static_cast<SpinbuttonValue *> ( aValue.getOptionalVal() );
+-
+- // Is any of the buttons pressed?
+- QStyle::SCFlags eActive = QStyle::SC_None;
+- if ( pValue )
+- {
+- if ( pValue->mnUpperState & CTRL_STATE_PRESSED )
+- eActive = QStyle::SC_SpinWidgetUp;
+- else if ( pValue->mnLowerState & CTRL_STATE_PRESSED )
+- eActive = QStyle::SC_SpinWidgetDown;
+-
+- // Update the enable/disable state of the widget
+- if ( ( nState & CTRL_STATE_ENABLED ) ||
+- ( pValue->mnUpperState & CTRL_STATE_ENABLED ) ||
+- ( pValue->mnLowerState & CTRL_STATE_ENABLED ) )
+- {
+- pWidget->setEnabled( true );
+- nStyle |= QStyle::Style_Enabled;
+- }
+- else
+- pWidget->setEnabled( false );
+-
+- // Mouse-over effect
+- if ( (pValue->mnUpperState & CTRL_STATE_ROLLOVER) ||
+- (pValue->mnLowerState & CTRL_STATE_ROLLOVER) )
+- nStyle |= QStyle::Style_MouseOver;
+- }
+-
+- // Spin widget uses the background of the associated edit box
+- QSpinWidget *pSpinWidget = static_cast<QSpinWidget *>( pWidget->qt_cast( "QSpinWidget" ) );
+- if ( pSpinWidget && pSpinWidget->editWidget() )
+- {
+- QColorGroup::ColorRole eColorRole = ( pSpinWidget->isEnabled() )?
+- QColorGroup::Base: QColorGroup::Background;
+- qPainter.fillRect(
+- kapp->style().querySubControlMetrics( QStyle::CC_SpinWidget,
+- pSpinWidget, QStyle::SC_SpinWidgetEditField ),
+- pSpinWidget->editWidget()->colorGroup().brush( eColorRole ) );
+- }
+-
+- // Adjust the frame (needed for Motif Plus style)
+- QRect qFrameRect = kapp->style().querySubControlMetrics( QStyle::CC_SpinWidget,
+- pWidget, QStyle::SC_SpinWidgetFrame );
+-
+- kapp->style().drawComplexControl( QStyle::CC_SpinWidget,
+- &qPainter, pWidget, qFrameRect,
+- pWidget->colorGroup(), nStyle,
+- QStyle::SC_All, eActive );
+- }
+- else if ( strcmp( "QTabBar", pClassName ) == 0 )
+- {
+- TabitemValue *pValue = static_cast<TabitemValue *> ( aValue.getOptionalVal() );
+-
+- QTab *pTab = NULL;
+- if ( pValue )
+- {
+- if ( ( pValue->isFirst() || pValue->isLeftAligned() ) && ( pValue->isLast() || pValue->isRightAligned() ) )
+- pTab = m_pTabAlone;
+- else if ( pValue->isFirst() || pValue->isLeftAligned() )
+- pTab = m_pTabLeft;
+- else if ( pValue->isLast() || pValue->isRightAligned() )
+- pTab = m_pTabRight;
+- else
+- pTab = m_pTabMiddle;
+- }
+- if ( !pTab )
+- return FALSE;
+-
+- pTab->setRect( qRect );
+-
+- kapp->style().drawControl( QStyle::CE_TabBarTab,
+- &qPainter, pWidget, qRect,
+- pWidget->colorGroup(), nStyle,
+- QStyleOption( pTab ) );
+- }
+- else if ( strcmp( "QTabWidget", pClassName ) == 0 )
+- {
+- kapp->style().drawPrimitive( QStyle::PE_PanelTabWidget,
+- &qPainter, qRect,
+- pWidget->colorGroup(), nStyle );
+- }
+- else if ( strcmp( "QListView", pClassName ) == 0 )
+- {
+- kapp->style().drawPrimitive( QStyle::PE_Panel,
+- &qPainter, qRect,
+- pWidget->colorGroup(), nStyle | QStyle::Style_Sunken );
+- }
+- else if ( strcmp( "QScrollBar", pClassName ) == 0 )
+- {
+- ScrollbarValue *pValue = static_cast<ScrollbarValue *> ( aValue.getOptionalVal() );
+-
+- QStyle::SCFlags eActive = QStyle::SC_None;
+- if ( pValue )
+- {
+- // Workaround for Style_MouseOver-aware themes.
+- // Quite ugly, but I do not know about a better solution.
+- const char *pStyleName = kapp->style().className();
+- if ( strcmp( "QMotifPlusStyle", pStyleName ) == 0 )
+- {
+- nStyle |= QStyle::Style_MouseOver;
+- if ( pValue->mnThumbState & CTRL_STATE_ROLLOVER )
+- eActive = QStyle::SC_ScrollBarSlider;
+- }
+- else if ( strcmp( "QSGIStyle", pStyleName ) == 0 )
+- {
+- nStyle |= QStyle::Style_MouseOver;
+- if ( pValue->mnButton1State & CTRL_STATE_ROLLOVER )
+- eActive = QStyle::SC_ScrollBarSubLine;
+- else if ( pValue->mnButton2State & CTRL_STATE_ROLLOVER )
+- eActive = QStyle::SC_ScrollBarAddLine;
+- else if ( pValue->mnThumbState & CTRL_STATE_ROLLOVER )
+- eActive = QStyle::SC_ScrollBarSlider;
+- }
+-
+- if ( pValue->mnButton1State & CTRL_STATE_PRESSED )
+- eActive = QStyle::SC_ScrollBarSubLine;
+- else if ( pValue->mnButton2State & CTRL_STATE_PRESSED )
+- eActive = QStyle::SC_ScrollBarAddLine;
+- else if ( pValue->mnThumbState & CTRL_STATE_PRESSED )
+- eActive = QStyle::SC_ScrollBarSlider;
+- else if ( pValue->mnPage1State & CTRL_STATE_PRESSED )
+- eActive = QStyle::SC_ScrollBarSubPage;
+- else if ( pValue->mnPage2State & CTRL_STATE_PRESSED )
+- eActive = QStyle::SC_ScrollBarAddPage;
+-
+- // Update the enable/disable state of the widget
+- if ( ( nState & CTRL_STATE_ENABLED ) ||
+- ( pValue->mnButton1State & CTRL_STATE_ENABLED ) ||
+- ( pValue->mnButton2State & CTRL_STATE_ENABLED ) ||
+- ( pValue->mnThumbState & CTRL_STATE_ENABLED ) ||
+- ( pValue->mnPage1State & CTRL_STATE_ENABLED ) ||
+- ( pValue->mnPage2State & CTRL_STATE_ENABLED ) )
+- {
+- pWidget->setEnabled( true );
+- nStyle |= QStyle::Style_Enabled;
+- }
+- else
+- pWidget->setEnabled( false );
+- }
+-
+- // Is it a horizontal scroll bar?
+- QScrollBar *pScrollBar = static_cast<QScrollBar *> ( pWidget->qt_cast( "QScrollBar" ) );
+- QStyle::StyleFlags eHoriz = QStyle::Style_Default;
+- if ( pScrollBar && pScrollBar->orientation() == Qt::Horizontal )
+- eHoriz = QStyle::Style_Horizontal;
+-
+- kapp->style().drawComplexControl( QStyle::CC_ScrollBar,
+- &qPainter, pWidget, qRect,
+- pWidget->colorGroup(), nStyle | eHoriz,
+- QStyle::SC_All, eActive );
+- }
+- else
+- return FALSE;
+-
+- // Bitblt it to the screen
+- XCopyArea( dpy,
+- qPixmap.handle(), drawable,
+- gc,
+- 0, 0, qRect.width(), qRect.height(),
+- qWidgetPos.x(), qWidgetPos.y() );
+-
+- // Restore widget's position
+- pWidget->move( qWidgetPos );
+-
+- return TRUE;
+-}
+-
+-QPushButton *WidgetPainter::pushButton( const Region& rControlRegion,
+- BOOL bDefault )
+-{
+- if ( !m_pPushButton )
+- m_pPushButton = new QPushButton( NULL, "push_button" );
+-
+- QRect qRect = region2QRect( rControlRegion );
+-
+- // Workaround for broken styles which do not add
+- // QStyle::PM_ButtonDefaultIndicator to the size of the default button
+- // (for example Keramik)
+- // FIXME Fix Keramik style to be consistant with Qt built-in styles. Aargh!
+- if ( bDefault )
+- {
+- QSize qContentsSize( 50, 50 );
+- m_pPushButton->setDefault( false );
+- QSize qNormalSize = kapp->style().sizeFromContents( QStyle::CT_PushButton,
+- m_pPushButton, qContentsSize );
+- m_pPushButton->setDefault( true );
+- QSize qDefSize = kapp->style().sizeFromContents( QStyle::CT_PushButton,
+- m_pPushButton, qContentsSize );
+-
+- int nIndicatorSize = kapp->style().pixelMetric(
+- QStyle::PM_ButtonDefaultIndicator, m_pPushButton );
+- if ( qNormalSize.width() == qDefSize.width() )
+- qRect.addCoords( nIndicatorSize, 0, -nIndicatorSize, 0 );
+- if ( qNormalSize.height() == qDefSize.height() )
+- qRect.addCoords( 0, nIndicatorSize, 0, -nIndicatorSize );
+- }
+-
+- m_pPushButton->move( qRect.topLeft() );
+- m_pPushButton->resize( qRect.size() );
+- m_pPushButton->setDefault( bDefault );
+-
+- return m_pPushButton;
+-}
+-
+-QRadioButton *WidgetPainter::radioButton( const Region& rControlRegion )
+-{
+- if ( !m_pRadioButton )
+- m_pRadioButton = new QRadioButton( NULL, "radio_button" );
+-
+- QRect qRect = region2QRect( rControlRegion );
+-
+- // Workaround for broken themes which do not honor the given size.
+- // Quite ugly, but I do not know about a better solution.
+- const char *pStyleName = kapp->style().className();
+- if ( strcmp( "KThemeStyle", pStyleName ) == 0 )
+- {
+- QRect qOldRect( qRect );
+-
+- qRect.setWidth( kapp->style().pixelMetric(
+- QStyle::PM_ExclusiveIndicatorWidth, m_pRadioButton ) );
+- qRect.setHeight( kapp->style().pixelMetric(
+- QStyle::PM_ExclusiveIndicatorHeight, m_pRadioButton ) );
+-
+- qRect.moveBy( ( qOldRect.width() - qRect.width() ) / 2,
+- ( qOldRect.height() - qRect.height() ) / 2 );
+- }
+-
+- m_pRadioButton->move( qRect.topLeft() );
+- m_pRadioButton->resize( qRect.size() );
+-
+- return m_pRadioButton;
+-}
+-
+-QCheckBox *WidgetPainter::checkBox( const Region& rControlRegion )
+-{
+- if ( !m_pCheckBox )
+- m_pCheckBox = new QCheckBox( NULL, "check_box" );
+-
+- QRect qRect = region2QRect( rControlRegion );
+-
+- // Workaround for broken themes which do not honor the given size.
+- // Quite ugly, but I do not know about a better solution.
+- const char *pStyleName = kapp->style().className();
+- if ( strcmp( "KThemeStyle", pStyleName ) == 0 )
+- {
+- QRect qOldRect( qRect );
+-
+- qRect.setWidth( kapp->style().pixelMetric(
+- QStyle::PM_IndicatorWidth, m_pCheckBox ) );
+- qRect.setHeight( kapp->style().pixelMetric(
+- QStyle::PM_IndicatorHeight, m_pCheckBox ) );
+-
+- qRect.moveBy( ( qOldRect.width() - qRect.width() ) / 2,
+- ( qOldRect.height() - qRect.height() ) / 2 );
+- }
+-
+- m_pCheckBox->move( qRect.topLeft() );
+- m_pCheckBox->resize( qRect.size() );
+-
+- return m_pCheckBox;
+-}
+-
+-QComboBox *WidgetPainter::comboBox( const Region& rControlRegion,
+- BOOL bEditable )
+-{
+- QComboBox *pComboBox = NULL;
+- if ( bEditable )
+- {
+- if ( !m_pEditableComboBox )
+- m_pEditableComboBox = new QComboBox( true, NULL, "combo_box_edit" );
+- pComboBox = m_pEditableComboBox;
+- }
+- else
+- {
+- if ( !m_pComboBox )
+- m_pComboBox = new QComboBox( false, NULL, "combo_box" );
+- pComboBox = m_pComboBox;
+- }
+-
+- QRect qRect = region2QRect( rControlRegion );
+-
+- pComboBox->move( qRect.topLeft() );
+- pComboBox->resize( qRect.size() );
+-
+- return pComboBox;
+-}
+-
+-QLineEdit *WidgetPainter::lineEdit( const Region& rControlRegion )
+-{
+- if ( !m_pLineEdit )
+- m_pLineEdit = new QLineEdit( NULL, "line_edit" );
+-
+- QRect qRect = region2QRect( rControlRegion );
+-
+- m_pLineEdit->move( qRect.topLeft() );
+- m_pLineEdit->resize( qRect.size() );
+-
+- return m_pLineEdit;
+-}
+-
+-QSpinWidget *WidgetPainter::spinWidget( const Region& rControlRegion )
+-{
+- if ( !m_pSpinWidget )
+- {
+- m_pSpinWidget = new QSpinWidget( NULL, "spin_widget" );
+-
+- m_pSpinEdit = new QLineEdit( NULL, "line_edit_spin" );
+- m_pSpinWidget->setEditWidget( m_pSpinEdit );
+- }
+-
+- QRect qRect = region2QRect( rControlRegion );
+-
+- m_pSpinWidget->move( qRect.topLeft() );
+- m_pSpinWidget->resize( qRect.size() );
+- m_pSpinWidget->arrange();
+-
+- return m_pSpinWidget;
+-}
+-
+-QTabBar *WidgetPainter::tabBar( const Region& rControlRegion )
+-{
+- if ( !m_pTabBar )
+- {
+- if ( !m_pTabBarParent )
+- m_pTabBarParent = new QWidget( NULL, "tab_bar_parent" );
+-
+- m_pTabBar = new QTabBar( m_pTabBarParent, "tab_bar" );
+-
+- m_pTabLeft = new QTab();
+- m_pTabMiddle = new QTab();
+- m_pTabRight = new QTab();
+- m_pTabAlone = new QTab();
+-
+- m_pTabBar->addTab( m_pTabLeft );
+- m_pTabBar->addTab( m_pTabMiddle );
+- m_pTabBar->addTab( m_pTabRight );
+- }
+-
+- QRect qRect = region2QRect( rControlRegion );
+-
+- m_pTabBar->move( qRect.topLeft() );
+- m_pTabBar->resize( qRect.size() );
+-
+- m_pTabBar->setShape( QTabBar::RoundedAbove );
+-
+- return m_pTabBar;
+-}
+-
+-QTabWidget *WidgetPainter::tabWidget( const Region& rControlRegion )
+-{
+- if ( !m_pTabWidget )
+- m_pTabWidget = new QTabWidget( NULL, "tab_widget" );
+-
+- QRect qRect = region2QRect( rControlRegion );
+- --qRect.rTop();
+-
+- m_pTabWidget->move( qRect.topLeft() );
+- m_pTabWidget->resize( qRect.size() );
+-
+- return m_pTabWidget;
+-}
+-
+-QListView *WidgetPainter::listView( const Region& rControlRegion )
+-{
+- if ( !m_pListView )
+- m_pListView = new QListView( NULL, "list_view" );
+-
+- QRect qRect = region2QRect( rControlRegion );
+-
+- m_pListView->move( qRect.topLeft() );
+- m_pListView->resize( qRect.size() );
+-
+- return m_pListView;
+-}
+-
+-QScrollBar *WidgetPainter::scrollBar( const Region& rControlRegion,
+- BOOL bHorizontal, const ImplControlValue& aValue )
+-{
+- if ( !m_pScrollBar )
+- {
+- m_pScrollBar = new QScrollBar( NULL, "scroll_bar" );
+- m_pScrollBar->setTracking( false );
+- m_pScrollBar->setLineStep( 1 );
+- }
+-
+- QRect qRect = region2QRect( rControlRegion );
+-
+- m_pScrollBar->move( qRect.topLeft() );
+- m_pScrollBar->resize( qRect.size() );
+- m_pScrollBar->setOrientation( bHorizontal? Qt::Horizontal: Qt::Vertical );
+-
+- ScrollbarValue *pValue = static_cast<ScrollbarValue *> ( aValue.getOptionalVal() );
+- if ( pValue )
+- {
+- m_pScrollBar->setMinValue( pValue->mnMin );
+- m_pScrollBar->setMaxValue( pValue->mnMax - pValue->mnVisibleSize );
+- m_pScrollBar->setValue( pValue->mnCur );
+- m_pScrollBar->setPageStep( pValue->mnVisibleSize );
+- }
+-
+- return m_pScrollBar;
+-}
+-
+-QStyle::SFlags WidgetPainter::vclStateValue2SFlags( ControlState nState,
+- const ImplControlValue& aValue )
+-{
+- QStyle::SFlags nStyle =
+- ( (nState & CTRL_STATE_DEFAULT)? QStyle::Style_ButtonDefault: QStyle::Style_Default ) |
+- ( (nState & CTRL_STATE_ENABLED)? QStyle::Style_Enabled: QStyle::Style_Default ) |
+- ( (nState & CTRL_STATE_FOCUSED)? QStyle::Style_HasFocus: QStyle::Style_Default ) |
+- ( (nState & CTRL_STATE_PRESSED)? QStyle::Style_Down: QStyle::Style_Raised ) |
+- ( (nState & CTRL_STATE_SELECTED)? QStyle::Style_Selected : QStyle::Style_Default ) |
+- ( (nState & CTRL_STATE_ROLLOVER)? QStyle::Style_MouseOver: QStyle::Style_Default );
+- //TODO ( (nState & CTRL_STATE_HIDDEN)? QStyle::Style_: QStyle::Style_Default ) |
+-
+- switch ( aValue.getTristateVal() )
+- {
+- case BUTTONVALUE_ON: nStyle |= QStyle::Style_On; break;
+- case BUTTONVALUE_OFF: nStyle |= QStyle::Style_Off; break;
+- case BUTTONVALUE_MIXED: nStyle |= QStyle::Style_NoChange; break;
+- }
+-
+- return nStyle;
+-}
+-
+-QRect WidgetPainter::region2QRect( const Region& rControlRegion )
+-{
+- Rectangle aRect = rControlRegion.GetBoundRect();
+-
+- return QRect( QPoint( aRect.Left(), aRect.Top() ),
+- QPoint( aRect.Right(), aRect.Bottom() ) );
+-}
+-
+-/** Instance of WidgetPainter.
+-
+- It is used to paint the widgets requested by NWF.
+-*/
+-static WidgetPainter widgetPainter;
+-
+-
+-/** Initialization of KDE and local stuff.
+-
+- It creates an instance of KApplication.
+-*/
+-void VCLInitNativeWidgets( void )
+-{
+- KAboutData *kAboutData = new KAboutData( "OpenOffice.org",
+- I18N_NOOP( "OpenOffice.org" ),
+- "1.1.0",
+- I18N_NOOP( "OpenOffice.org with KDE Native Widget Support." ),
+- KAboutData::License_LGPL,
+- "(c) 2003, Jan Holesovsky",
+- I18N_NOOP( "OpenOffice.org is an office suite.\n" ),
+- "http://kde.openoffice.org/index.html",
+- "dev@kde.openoffice.org");
+- kAboutData->addAuthor( "Jan Holesovsky",
+- I18N_NOOP( "Original author and maintainer of the KDE NWF." ),
+- "kendy@artax.karlin.mff.cuni.cz",
+- "http://artax.karlin.mff.cuni.cz/~kendy" );
+-
+- // We ignore the arguments, KApplication has to be initialized according
+- // to the OOo's display.
+- int argc = 0;
+- char *argv[20] = { "soffice.bin", 0 };
+- KCmdLineArgs::init( argc, argv, kAboutData );
+-
+- // Get display
+- SalDisplay *pSalDisplay = GetSalData()->GetCurDisp();
+- if ( !pSalDisplay )
+- ::std::cerr << "Cannot get current display!" << ::std::endl;
+- else
+- new KApplication( pSalDisplay->GetDisplay(), argc, argv, "soffice.bin" );
+-}
+-
+-/** Release KDE and local stuff
+-
+- No operation for KDE.
+-*/
+-void VCLDeinitNativeWidgets( void )
+-{
+-}
+-
+-/** What widgets can be drawn the native way.
+-
+- @param nType
+- Type of the widget.
+-
+- @param nPart
+- Specification of the widget's part if it consists of more than one.
+-
+- @return TRUE if the platform supports native drawing of the widget nType
+- defined by nPart.
+-*/
+-BOOL SalGraphics::IsNativeControlSupported( ControlType nType, ControlPart nPart )
+-{
+- return
+- ( (nType == CTRL_PUSHBUTTON) && (nPart == PART_ENTIRE_CONTROL) ) ||
+- ( (nType == CTRL_RADIOBUTTON) && (nPart == PART_ENTIRE_CONTROL) ) ||
+- ( (nType == CTRL_CHECKBOX) && (nPart == PART_ENTIRE_CONTROL) ) ||
+- ( (nType == CTRL_COMBOBOX) && (nPart == PART_ENTIRE_CONTROL || nPart == HAS_BACKGROUND_TEXTURE) ) ||
+- ( (nType == CTRL_EDITBOX) && (nPart == PART_ENTIRE_CONTROL || nPart == HAS_BACKGROUND_TEXTURE) ) ||
+- ( (nType == CTRL_MULTILINE_EDITBOX) && (nPart == PART_ENTIRE_CONTROL || nPart == HAS_BACKGROUND_TEXTURE) ) ||
+- ( (nType == CTRL_LISTBOX) && (nPart == PART_ENTIRE_CONTROL || nPart == PART_WINDOW) ) ||
+- ( (nType == CTRL_SPINBOX) && (nPart == PART_ENTIRE_CONTROL || nPart == HAS_BACKGROUND_TEXTURE) ) ||
+- // no CTRL_SPINBUTTONS for KDE
+- ( (nType == CTRL_TAB_ITEM) && (nPart == PART_ENTIRE_CONTROL) ) ||
+- ( (nType == CTRL_TAB_PANE) && (nPart == PART_ENTIRE_CONTROL) ) ||
+- // no CTRL_TAB_BODY for KDE
+- ( (nType == CTRL_SCROLLBAR) && (nPart == PART_ENTIRE_CONTROL || nPart == PART_DRAW_BACKGROUND_HORZ || nPart == PART_DRAW_BACKGROUND_VERT) ) ||
+- ( (nType == CTRL_SCROLLBAR) && (nPart == HAS_THREE_BUTTONS) ); // TODO small optimization is possible here: return this only if the style really has 3 buttons
+- // CTRL_GROUPBOX not supported
+- // CTRL_FIXEDLINE not supported
+- // CTRL_FIXEDBORDER not supported
+-}
+-
+-
+-/** Test whether the position is in the native widget.
+-
+- If the return value is TRUE, bIsInside contains information whether
+- aPos was or was not inside the native widget specified by the
+- nType/nPart combination.
+-*/
+-BOOL SalGraphics::HitTestNativeControl( ControlType nType, ControlPart nPart,
+- const Region& rControlRegion, const Point& aPos,
+- SalControlHandle& rControlHandle, BOOL& rIsInside,
+- const OutputDevice* )
+-{
+- if ( nType == CTRL_SCROLLBAR )
+- {
+- rIsInside = FALSE;
+-
+- BOOL bHorizontal = ( nPart == PART_BUTTON_LEFT || nPart == PART_BUTTON_RIGHT );
+-
+- QScrollBar *pScrollBar = widgetPainter.scrollBar( rControlRegion,
+- bHorizontal, ImplControlValue() );
+- QRect qRectSubLine = kapp->style().querySubControlMetrics(
+- QStyle::CC_ScrollBar, pScrollBar, QStyle::SC_ScrollBarSubLine );
+- QRect qRectAddLine = kapp->style().querySubControlMetrics(
+- QStyle::CC_ScrollBar, pScrollBar, QStyle::SC_ScrollBarAddLine );
+-
+- // There are 2 buttons on the right/bottom side of the scrollbar
+- BOOL bTwoSubButtons = FALSE;
+-
+- // It is a Platinum style scroll bar
+- BOOL bPlatinumStyle = FALSE;
+-
+- // Workaround for Platinum and 3 button style scroll bars.
+- // It makes the right/down button bigger.
+- if ( bHorizontal )
+- {
+- qRectAddLine.setLeft( kapp->style().querySubControlMetrics(
+- QStyle::CC_ScrollBar, pScrollBar,
+- QStyle::SC_ScrollBarAddPage ).right() + 1 );
+- if ( qRectAddLine.width() > qRectSubLine.width() )
+- bTwoSubButtons = TRUE;
+- if ( qRectSubLine.left() > kapp->style().querySubControlMetrics( QStyle::CC_ScrollBar, pScrollBar, QStyle::SC_ScrollBarSubPage ).left() )
+- bPlatinumStyle = TRUE;
+- }
+- else
+- {
+- qRectAddLine.setTop( kapp->style().querySubControlMetrics(
+- QStyle::CC_ScrollBar, pScrollBar,
+- QStyle::SC_ScrollBarAddPage ).bottom() + 1 );
+- if ( qRectAddLine.height() > qRectSubLine.height() )
+- bTwoSubButtons = TRUE;
+- if ( qRectSubLine.top() > kapp->style().querySubControlMetrics( QStyle::CC_ScrollBar, pScrollBar, QStyle::SC_ScrollBarSubPage ).top() )
+- bPlatinumStyle = TRUE;
+- }
+-
+- switch ( nPart )
+- {
+- case PART_BUTTON_LEFT:
+- if ( !bPlatinumStyle && qRectSubLine.contains( aPos.getX(), aPos.getY() ) )
+- rIsInside = TRUE;
+- else if ( bTwoSubButtons )
+- {
+- qRectAddLine.setWidth( qRectAddLine.width() / 2 );
+- rIsInside = qRectAddLine.contains( aPos.getX(), aPos.getY() );
+- }
+- break;
+-
+- case PART_BUTTON_UP:
+- if ( !bPlatinumStyle && qRectSubLine.contains( aPos.getX(), aPos.getY() ) )
+- rIsInside = TRUE;
+- else if ( bTwoSubButtons )
+- {
+- qRectAddLine.setHeight( qRectAddLine.height() / 2 );
+- rIsInside = qRectAddLine.contains( aPos.getX(), aPos.getY() );
+- }
+- break;
+-
+- case PART_BUTTON_RIGHT:
+- if ( bTwoSubButtons )
+- qRectAddLine.setLeft( qRectAddLine.left() + qRectAddLine.width() / 2 );
+-
+- rIsInside = qRectAddLine.contains( aPos.getX(), aPos.getY() );
+- break;
+-
+- case PART_BUTTON_DOWN:
+- if ( bTwoSubButtons )
+- qRectAddLine.setTop( qRectAddLine.top() + qRectAddLine.height() / 2 );
+-
+- rIsInside = qRectAddLine.contains( aPos.getX(), aPos.getY() );
+- break;
+- }
+-
+- return TRUE;
+- }
+-
+- return FALSE;
+-}
+-
+-
+-/** Draw the requested control described by nPart/nState.
+-
+- @param rControlRegion
+- The bounding region of the complete control in VCL frame coordinates.
+-
+- @param aValue
+- An optional value (tristate/numerical/string).
+-
+- @param rControlHandle
+- Carries platform dependent data and is maintained by the SalFrame implementation.
+-
+- @param aCaption
+- A caption or title string (like button text etc.)
+-*/
+-BOOL SalGraphics::DrawNativeControl( ControlType nType, ControlPart nPart,
+- const Region& rControlRegion, ControlState nState,
+- const ImplControlValue& aValue, SalControlHandle& rControlHandle,
+- OUString aCaption, const OutputDevice* )
+-{
+- BOOL bReturn = FALSE;
+-
+- Display *dpy = maGraphicsData.GetXDisplay();
+- XLIB_Window drawable = maGraphicsData.GetDrawable();
+- GC gc = maGraphicsData.SelectFont(); // GC with current clipping region set
+-
+- if ( (nType == CTRL_PUSHBUTTON) && (nPart == PART_ENTIRE_CONTROL) )
+- {
+- bReturn = widgetPainter.drawStyledWidget(
+- widgetPainter.pushButton( rControlRegion, (nState & CTRL_STATE_DEFAULT) ),
+- nState, aValue,
+- dpy, drawable, gc );
+- }
+- else if ( (nType == CTRL_RADIOBUTTON) && (nPart == PART_ENTIRE_CONTROL) )
+- {
+- bReturn = widgetPainter.drawStyledWidget(
+- widgetPainter.radioButton( rControlRegion ),
+- nState, aValue,
+- dpy, drawable, gc );
+- }
+- else if ( (nType == CTRL_CHECKBOX) && (nPart == PART_ENTIRE_CONTROL) )
+- {
+- bReturn = widgetPainter.drawStyledWidget(
+- widgetPainter.checkBox( rControlRegion ),
+- nState, aValue,
+- dpy, drawable, gc );
+- }
+- else if ( (nType == CTRL_COMBOBOX) && (nPart == PART_ENTIRE_CONTROL) )
+- {
+- bReturn = widgetPainter.drawStyledWidget(
+- widgetPainter.comboBox( rControlRegion, TRUE ),
+- nState, aValue,
+- dpy, drawable, gc );
+- }
+- else if ( (nType == CTRL_EDITBOX) && (nPart == PART_ENTIRE_CONTROL) )
+- {
+- bReturn = widgetPainter.drawStyledWidget(
+- widgetPainter.lineEdit( rControlRegion ),
+- nState, aValue,
+- dpy, drawable, gc );
+- }
+- else if ( (nType == CTRL_MULTILINE_EDITBOX) && (nPart == PART_ENTIRE_CONTROL) )
+- {
+- bReturn = widgetPainter.drawStyledWidget(
+- widgetPainter.lineEdit( rControlRegion ),
+- nState, aValue,
+- dpy, drawable, gc );
+- }
+- else if ( (nType == CTRL_LISTBOX) && (nPart == PART_ENTIRE_CONTROL) )
+- {
+- bReturn = widgetPainter.drawStyledWidget(
+- widgetPainter.comboBox( rControlRegion, FALSE ),
+- nState, aValue,
+- dpy, drawable, gc );
+- }
+- else if ( (nType == CTRL_LISTBOX) && (nPart == PART_WINDOW) )
+- {
+- bReturn = widgetPainter.drawStyledWidget(
+- widgetPainter.listView( rControlRegion ),
+- nState, aValue,
+- dpy, drawable, gc );
+- }
+- else if ( (nType == CTRL_SPINBOX) && (nPart == PART_ENTIRE_CONTROL) )
+- {
+- bReturn = widgetPainter.drawStyledWidget(
+- widgetPainter.spinWidget( rControlRegion ),
+- nState, aValue,
+- dpy, drawable, gc );
+- }
+- else if ( (nType==CTRL_TAB_ITEM) && (nPart == PART_ENTIRE_CONTROL) )
+- {
+- bReturn = widgetPainter.drawStyledWidget(
+- widgetPainter.tabBar( rControlRegion ),
+- nState, aValue,
+- dpy, drawable, gc );
+- }
+- else if ( (nType==CTRL_TAB_PANE) && (nPart == PART_ENTIRE_CONTROL) )
+- {
+- bReturn = widgetPainter.drawStyledWidget(
+- widgetPainter.tabWidget( rControlRegion ),
+- nState, aValue,
+- dpy, drawable, gc );
+- }
+- else if ( (nType == CTRL_SCROLLBAR) && (nPart == PART_DRAW_BACKGROUND_HORZ || nPart == PART_DRAW_BACKGROUND_VERT) )
+- {
+- bReturn = widgetPainter.drawStyledWidget(
+- widgetPainter.scrollBar( rControlRegion, nPart == PART_DRAW_BACKGROUND_HORZ, aValue ),
+- nState, aValue,
+- dpy, drawable, gc );
+- }
+-
+- return bReturn;
+-}
+-
+-
+-/** Draw text on the widget.
+-
+- OPTIONAL. Draws the requested text for the control described by nPart/nState.
+- Used if text is not drawn by DrawNativeControl().
+-
+- @param rControlRegion
+- The bounding region of the complete control in VCL frame coordinates.
+-
+- @param aValue
+- An optional value (tristate/numerical/string)
+-
+- @param rControlHandle
+- Carries platform dependent data and is maintained by the SalFrame implementation.
+-
+- @param aCaption
+- A caption or title string (like button text etc.)
+-*/
+-BOOL SalGraphics::DrawNativeControlText( ControlType nType, ControlPart nPart,
+- const Region& rControlRegion, ControlState nState,
+- const ImplControlValue& aValue, SalControlHandle& rControlHandle,
+- OUString aCaption, const OutputDevice* )
+-{
+- return FALSE;
+-}
+-
+-/** Check if the bounding regions match.
+-
+- If the return value is TRUE, rNativeBoundingRegion
+- contains the true bounding region covered by the control
+- including any adornment, while rNativeContentRegion contains the area
+- within the control that can be safely drawn into without drawing over
+- the borders of the control.
+-
+- @param rControlRegion
+- The bounding region of the control in VCL frame coordinates.
+-
+- @param aValue
+- An optional value (tristate/numerical/string)
+-
+- @param rControlHandle
+- Carries platform dependent data and is maintained by the SalFrame implementation.
+-
+- @param aCaption
+- A caption or title string (like button text etc.)
+-*/
+-BOOL SalGraphics::GetNativeControlRegion( ControlType nType, ControlPart nPart,
+- const Region& rControlRegion, ControlState nState,
+- const ImplControlValue& aValue, SalControlHandle& rControlHandle,
+- OUString aCaption,
+- Region &rNativeBoundingRegion, Region &rNativeContentRegion,
+- const OutputDevice* )
+-{
+- BOOL bReturn = FALSE;
+- QRect qBoundingRect = WidgetPainter::region2QRect( rControlRegion );
+- QRect qRect;
+-
+- QWidget *pWidget = NULL;
+- switch ( nType )
+- {
+- // Metrics of the push button
+- case CTRL_PUSHBUTTON:
+- pWidget = widgetPainter.pushButton( rControlRegion, ( nState & CTRL_STATE_DEFAULT ) );
+-
+- switch ( nPart )
+- {
+- case PART_ENTIRE_CONTROL:
+- qRect = qBoundingRect;
+-
+- if ( nState & CTRL_STATE_DEFAULT )
+- {
+- int nIndicatorSize = kapp->style().pixelMetric(
+- QStyle::PM_ButtonDefaultIndicator, pWidget );
+- qBoundingRect.addCoords( -nIndicatorSize, -nIndicatorSize,
+- nIndicatorSize, nIndicatorSize );
+- bReturn = TRUE;
+- }
+- break;
+- }
+- break;
+-
+- // Metrics of the combo box
+- case CTRL_COMBOBOX:
+- case CTRL_LISTBOX:
+- pWidget = widgetPainter.comboBox( rControlRegion, ( nType == CTRL_COMBOBOX ) );
+- switch ( nPart )
+- {
+- case PART_BUTTON_DOWN:
+- qRect = kapp->style().querySubControlMetrics(
+- QStyle::CC_ComboBox, pWidget, QStyle::SC_ComboBoxArrow );
+- qRect.setLeft( kapp->style().querySubControlMetrics(
+- QStyle::CC_ComboBox, pWidget,
+- QStyle::SC_ComboBoxEditField ).right() + 1 );
+- bReturn = TRUE;
+- break;
+-
+- case PART_SUB_EDIT:
+- qRect = kapp->style().querySubControlMetrics(
+- QStyle::CC_ComboBox, pWidget, QStyle::SC_ComboBoxEditField );
+- bReturn = TRUE;
+- break;
+- }
+- break;
+-
+- // Metrics of the spin box
+- case CTRL_SPINBOX:
+- pWidget = widgetPainter.spinWidget( rControlRegion );
+- switch ( nPart )
+- {
+- case PART_BUTTON_UP:
+- qRect = kapp->style().querySubControlMetrics(
+- QStyle::CC_SpinWidget, pWidget, QStyle::SC_SpinWidgetUp );
+- bReturn = TRUE;
+- break;
+-
+- case PART_BUTTON_DOWN:
+- qRect = kapp->style().querySubControlMetrics(
+- QStyle::CC_SpinWidget, pWidget, QStyle::SC_SpinWidgetDown );
+- bReturn = TRUE;
+- break;
+- }
+- break;
+-
+- // Metrics of the scroll bar
+- case CTRL_SCROLLBAR:
+- pWidget = widgetPainter.scrollBar( rControlRegion,
+- ( nPart == PART_BUTTON_LEFT || nPart == PART_BUTTON_RIGHT ),
+- ImplControlValue() );
+- switch ( nPart )
+- {
+- case PART_BUTTON_LEFT:
+- case PART_BUTTON_UP:
+- qRect = kapp->style().querySubControlMetrics(
+- QStyle::CC_ScrollBar, pWidget, QStyle::SC_ScrollBarSubLine );
+-
+- // Workaround for Platinum style scroll bars. It makes the
+- // left/up button invisible.
+- if ( nPart == PART_BUTTON_LEFT )
+- {
+- if ( qRect.left() > kapp->style().querySubControlMetrics(
+- QStyle::CC_ScrollBar, pWidget,
+- QStyle::SC_ScrollBarSubPage ).left() )
+- {
+- qRect.setLeft( 0 );
+- qRect.setRight( 0 );
+- }
+- }
+- else
+- {
+- if ( qRect.top() > kapp->style().querySubControlMetrics(
+- QStyle::CC_ScrollBar, pWidget,
+- QStyle::SC_ScrollBarSubPage ).top() )
+- {
+- qRect.setTop( 0 );
+- qRect.setBottom( 0 );
+- }
+- }
+-
+- bReturn = TRUE;
+- break;
+-
+- case PART_BUTTON_RIGHT:
+- case PART_BUTTON_DOWN:
+- qRect = kapp->style().querySubControlMetrics(
+- QStyle::CC_ScrollBar, pWidget, QStyle::SC_ScrollBarAddLine );
+-
+- // Workaround for Platinum and 3 button style scroll bars.
+- // It makes the right/down button bigger.
+- if ( nPart == PART_BUTTON_RIGHT )
+- qRect.setLeft( kapp->style().querySubControlMetrics(
+- QStyle::CC_ScrollBar, pWidget,
+- QStyle::SC_ScrollBarAddPage ).right() + 1 );
+- else
+- qRect.setTop( kapp->style().querySubControlMetrics(
+- QStyle::CC_ScrollBar, pWidget,
+- QStyle::SC_ScrollBarAddPage ).bottom() + 1 );
+-
+- bReturn = TRUE;
+- break;
+- }
+- }
+-
+- // Fill rNativeBoundingRegion and rNativeContentRegion
+- if ( bReturn )
+- {
+- // Bounding region
+- Point aBPoint( qBoundingRect.x(), qBoundingRect.y() );
+- Size aBSize( qBoundingRect.width(), qBoundingRect.height() );
+- rNativeBoundingRegion = Region( Rectangle( aBPoint, aBSize ) );
+-
+- // Region of the content
+- Point aPoint( qRect.x(), qRect.y() );
+- Size aSize( qRect.width(), qRect.height() );
+- rNativeContentRegion = Region( Rectangle( aPoint, aSize ) );
+- }
+-
+- return bReturn;
+-}
+-
+-/** Constructor.
+-*/
+-SalControlHandleData::SalControlHandleData( void )
+-{
+-}
+-
+-/** Destructor.
+-*/
+-SalControlHandleData::~SalControlHandleData( void )
+-{
+-}
+-
+-// -----------------------------------------------------------------------
+-// KDEIntegrator implementation
+-// -----------------------------------------------------------------------
+-
+-/** Constructor of the KDE integrator.
+-*/
+-KDEIntegrator::KDEIntegrator( SalFrame* pFrame ) :
+- DtIntegrator( pFrame )
+-{
+- meType = DtKDE;
+-}
+-
+-/** Destructor of the KDE integrator.
+-*/
+-KDEIntegrator::~KDEIntegrator()
+-{
+-}
+-
+-/** Helper function to convert colors.
+-*/
+-Color toColor( const QColor &rColor )
+-{
+- return Color( rColor.red(), rColor.green(), rColor.blue() );
+-}
+-
+-/** Helper function to read color from KConfig configuration repository.
+-*/
+-Color readColor( KConfig *pConfig, const char *pKey )
+-{
+- return toColor( pConfig->readColorEntry( pKey ) );
+-}
+-
+-/** Helper function to add information to Font from QFont.
+-*/
+-void modifyFont( Font &rFont, const QFont &rQFont )
+-{
+- QFontInfo qFontInfo( rQFont );
+-
+- rFont.SetName( String( qFontInfo.family().utf8(), RTL_TEXTENCODING_UTF8 ) );
+-
+- // Do not set the height, it does not look good
+- // rFont.SetHeight( qFontInfo.pointSize() );
+-
+- rFont.SetItalic( qFontInfo.italic()? ITALIC_NORMAL: ITALIC_NONE );
+-
+- FontWeight eWeight = WEIGHT_DONTKNOW;
+- int nWeight = qFontInfo.weight();
+- if ( nWeight <= QFont::Light )
+- eWeight = WEIGHT_LIGHT;
+- else if ( nWeight <= QFont::Normal )
+- eWeight = WEIGHT_NORMAL;
+- else if ( nWeight <= QFont::DemiBold )
+- eWeight = WEIGHT_SEMIBOLD;
+- else if ( nWeight <= QFont::Bold )
+- eWeight = WEIGHT_BOLD;
+- else
+- eWeight = WEIGHT_BLACK;
+- rFont.SetWeight( eWeight );
+-}
+-
+-/** Implementation of KDE integration's main method.
+-*/
+-void KDEIntegrator::GetSystemLook( AllSettings& rSettings )
+-{
+- StyleSettings aStyleSettings( rSettings.GetStyleSettings() );
+-
+- // WM settings
+- KConfig *pConfig = KGlobal::config();
+- if ( pConfig )
+- {
+- pConfig->setGroup( "WM" );
+- const char *pKey;
+-
+- pKey = "activeBackground";
+- if ( pConfig->hasKey( pKey ) )
+- aStyleSettings.SetActiveColor( readColor( pConfig, pKey ) );
+-
+- pKey = "activeBlend";
+- if ( pConfig->hasKey( pKey ) )
+- aStyleSettings.SetActiveColor2( readColor( pConfig, pKey ) );
+-
+- pKey = "inactiveBackground";
+- if ( pConfig->hasKey( pKey ) )
+- aStyleSettings.SetDeactiveColor( readColor( pConfig, pKey ) );
+-
+- pKey = "inactiveBlend";
+- if ( pConfig->hasKey( pKey ) )
+- aStyleSettings.SetDeactiveColor2( readColor( pConfig, pKey ) );
+-
+- pKey = "inactiveForeground";
+- if ( pConfig->hasKey( pKey ) )
+- aStyleSettings.SetDeactiveTextColor( readColor( pConfig, pKey ) );
+-
+- pKey = "activeForeground";
+- if ( pConfig->hasKey( pKey ) )
+- aStyleSettings.SetActiveTextColor( readColor( pConfig, pKey ) );
+-
+- pKey = "titleFont";
+- if ( pConfig->hasKey( pKey ) )
+- {
+- Font aFont= aStyleSettings.GetTitleFont();
+- modifyFont( aFont, pConfig->readFontEntry( pKey ) );
+- aStyleSettings.SetTitleFont( aFont );
+- }
+- }
+-
+- // General settings
+- QColorGroup qColorGroup = kapp->palette().active();
+-
+- // Foreground
+- Color aFore = toColor( qColorGroup.foreground() );
+- aStyleSettings.SetRadioCheckTextColor( aFore );
+- aStyleSettings.SetLabelTextColor( aFore );
+- aStyleSettings.SetInfoTextColor( aFore );
+- aStyleSettings.SetDialogTextColor( aFore );
+- aStyleSettings.SetGroupTextColor( aFore );
+-
+- // Input boxes, list boxes
+- aStyleSettings.SetFieldColor( toColor( qColorGroup.base() ) );
+- aStyleSettings.SetFieldTextColor( toColor( qColorGroup.text() ) );
+-
+- // Buttons
+- aStyleSettings.SetButtonTextColor( toColor( qColorGroup.buttonText() ) );
+-
+- // Disable color
+- aStyleSettings.SetDisableColor( toColor( qColorGroup.mid() ) );
+-
+- // Background
+- Color aBack = toColor( qColorGroup.background() );
+- aStyleSettings.Set3DColors( aBack );
+- aStyleSettings.SetFaceColor( aBack );
+- aStyleSettings.SetDialogColor( aBack );
+- if( aBack == COL_LIGHTGRAY )
+- aStyleSettings.SetCheckedColor( Color( 0xCC, 0xCC, 0xCC ) );
+- else
+- {
+- Color aColor2 = aStyleSettings.GetLightColor();
+- aStyleSettings.
+- SetCheckedColor( Color( (BYTE)(((USHORT)aBack.GetRed()+(USHORT)aColor2.GetRed())/2),
+- (BYTE)(((USHORT)aBack.GetGreen()+(USHORT)aColor2.GetGreen())/2),
+- (BYTE)(((USHORT)aBack.GetBlue()+(USHORT)aColor2.GetBlue())/2)
+- ) );
+- }
+-
+- // Selection
+- aStyleSettings.SetHighlightColor( toColor( qColorGroup.highlight() ) );
+- aStyleSettings.SetHighlightTextColor( toColor( qColorGroup.highlightedText() ) );
+-
+- // Font
+- Font aFont= aStyleSettings.GetAppFont();
+- modifyFont( aFont, kapp->font() );
+-
+- aStyleSettings.SetAppFont( aFont );
+- aStyleSettings.SetHelpFont( aFont );
+- aStyleSettings.SetMenuFont( aFont ); // will be changed according to pMenuBar
+- aStyleSettings.SetToolFont( aFont ); // will be changed according to pToolBar
+- aStyleSettings.SetLabelFont( aFont );
+- aStyleSettings.SetInfoFont( aFont );
+- aStyleSettings.SetRadioCheckFont( aFont );
+- aStyleSettings.SetPushButtonFont( aFont );
+- aStyleSettings.SetFieldFont( aFont );
+- aStyleSettings.SetIconFont( aFont );
+- aStyleSettings.SetGroupFont( aFont );
+-
+- // Menu
+- KMainWindow qMainWindow;
+- qMainWindow.createGUI();
+-
+- KMenuBar *pMenuBar = qMainWindow.menuBar();
+- if ( pMenuBar )
+- {
+- // Color
+- QColorGroup qMenuCG = pMenuBar->colorGroup();
+- aStyleSettings.SetMenuTextColor( toColor( qMenuCG.buttonText() ) );
+- aStyleSettings.SetMenuColor( toColor( qMenuCG.button() ) );
+- aStyleSettings.SetMenuBarColor( toColor( qMenuCG.button() ) );
+- aStyleSettings.SetMenuHighlightColor( toColor ( qMenuCG.highlight() ) );
+- aStyleSettings.SetMenuHighlightTextColor( toColor ( qMenuCG.highlightedText() ) );
+-
+- // Font
+- Font aFont= aStyleSettings.GetMenuFont();
+- modifyFont( aFont, pMenuBar->font() );
+- aStyleSettings.SetMenuFont( aFont );
+- }
+-
+- // Tool bar
+- KToolBar *pToolBar = qMainWindow.toolBar();
+- if ( pToolBar )
+- {
+- Font aFont= aStyleSettings.GetToolFont();
+- modifyFont( aFont, pToolBar->font() );
+- aStyleSettings.SetToolFont( aFont );
+- }
+-
+- // Scroll bar size
+- aStyleSettings.SetScrollBarSize( kapp->style().pixelMetric( QStyle::PM_ScrollBarExtent ) );
+-
+- rSettings.SetStyleSettings( aStyleSettings );
+-}
+-
+-/* vim: set tabstop=8 shiftwidth=4: */
+--- vcl/unx/source/window/makefile.mk 2004-05-10 18:00:26.000000000 +0200
++++ vcl/unx/source/window/makefile.mk 2004-11-03 18:39:13.333907904 +0100
+@@ -86,10 +86,6 @@ dummy:
+ SLOFILES= \
+ $(SLO)/FWS.obj $(SLO)/salframe.obj $(SLO)/salobj.obj $(SLO)/salmenu.obj
+
+-.IF "$(WITH_WIDGETSET)"!=""
+-CFLAGS+= $(WIDGETSET_CFLAGS)
+-.ENDIF
+-
+ .ENDIF # "$(GUIBASE)"!="unx"
+
+ # --- Targets ------------------------------------------------------
diff --git a/patches/src680/desktop-bootstrap-debug.diff b/patches/src680/desktop-bootstrap-debug.diff
new file mode 100644
index 000000000..23c9662e7
--- /dev/null
+++ b/patches/src680/desktop-bootstrap-debug.diff
@@ -0,0 +1,25 @@
+--- desktop/source/app/appinit.cxx 2004-09-20 13:01:04.000000000 +0100
++++ desktop/source/app/appinit.cxx 2004-11-12 17:13:35.049198904 +0000
+@@ -61,6 +61,7 @@
+
+ #include <algorithm>
+
++#include <stdio.h>
+ #include "app.hxx"
+ #include "cmdlineargs.hxx"
+
+@@ -334,9 +335,11 @@
+
+ return xMS;
+ }
+- catch( ::com::sun::star::uno::Exception& )
+- {
+- }
++ catch( ::com::sun::star::uno::Exception& e)
++ {
++ OString s = OUStringToOString (e.Message, RTL_TEXTENCODING_UTF8);
++ fprintf (stderr, "Bootstrap failing: '%s'\n", s.getStr());
++ }
+
+ return Reference< XMultiServiceFactory >();
+ }
diff --git a/patches/src680/fix-vcl-kde.diff b/patches/src680/fix-vcl-kde.diff
new file mode 100644
index 000000000..5dd62835e
--- /dev/null
+++ b/patches/src680/fix-vcl-kde.diff
@@ -0,0 +1,96 @@
+--- vcl/unx/kde/kdedata.cxx 2004-09-08 17:37:08.000000000 +0200
++++ vcl/unx/kde/kdedata.cxx 2004-11-03 18:10:47.846181448 +0100
+@@ -173,7 +173,9 @@ void KDEXLib::Init()
+
+ KCmdLineArgs::init( nFakeArgc, pFakeArgv, kAboutData );
+
++ KApplication::disableAutoDcopRegistration();
+ new KApplication();
++
+ Display* pDisp = QPaintDevice::x11AppDisplay();
+ XVisualInfo aVI;
+ Colormap aColMap;
+--- vcl/unx/kde/makefile.mk 2004-11-03 18:15:44.184131232 +0100
++++ vcl/unx/kde/makefile.mk 2004-11-03 18:19:25.333511416 +0100
+@@ -84,7 +84,7 @@ dummy:
+
+ .IF "$(ENABLE_KDE)" != ""
+
+-CFLAGS+=$(WIDGETSET_KDE_CFLAGS)
++CFLAGS+=$(KDE_CFLAGS)
+
+ SLOFILES=\
+ $(SLO)$/kdedata.obj \
+--- vcl/unx/kde/salnativewidgets-kde.cxx 2004-09-08 17:37:30.000000000 +0200
++++ vcl/unx/kde/salnativewidgets-kde.cxx 2004-11-03 18:10:47.921170048 +0100
+@@ -108,10 +108,6 @@
+ #include <salframe.h>
+ #endif
+
+-#ifndef _SV_KDEINT_HXX
+-#include <kdeint.hxx>
+-#endif
+-
+ #ifndef _SV_SETTINGS_HXX
+ #include <settings.hxx>
+ #endif
+@@ -116,6 +112,10 @@
+ #include <settings.hxx>
+ #endif
+
++#ifndef _RTL_USTRBUF_HXX_
++#include <rtl/ustrbuf.hxx>
++#endif
++
+ #ifndef _VCL_KDEDATA_HXX
+ #include <plugins/kde/kdedata.hxx>
+ #endif
+@@ -404,12 +404,12 @@ WidgetPainter::~WidgetPainter( void )
+ delete m_pLineEdit, m_pLineEdit = NULL;
+ delete m_pSpinWidget, m_pSpinWidget = NULL;
+ delete m_pSpinEdit, m_pSpinEdit = NULL;
+- delete m_pTabLeft, m_pTabLeft = NULL;
+- delete m_pTabMiddle, m_pTabMiddle = NULL;
+- delete m_pTabRight, m_pTabRight = NULL;
+ delete m_pTabAlone, m_pTabAlone = NULL;
+ delete m_pTabBarParent, m_pTabBarParent = NULL;
+- delete m_pTabBar, m_pTabBar = NULL;
++ m_pTabBar = NULL; // Deleted in m_pTabBarParent's destructor
++ m_pTabLeft = NULL;
++ m_pTabMiddle = NULL;
++ m_pTabRight = NULL;
+ delete m_pTabWidget, m_pTabWidget = NULL;
+ delete m_pListView, m_pListView = NULL;
+ delete m_pScrollBar, m_pScrollBar = NULL;
+@@ -1428,9 +1428,28 @@ static void modifyFont( Font &rFont, con
+ {
+ QFontInfo qFontInfo( rQFont );
+
+- rFont.SetName( String( qFontInfo.family().utf8(), RTL_TEXTENCODING_UTF8 ) );
+-
+- rFont.SetHeight( qFontInfo.pointSize() );
++ // Prepend the KDE font, do not override
++ OUString aQFontName = String( rQFont.family().utf8(), RTL_TEXTENCODING_UTF8 );
++ OUString aFontName = rFont.GetName();
++
++ if ( aQFontName.getLength() > 0 &&
++ aFontName.compareTo( aQFontName, aQFontName.getLength() ) != 0 )
++ {
++ OUStringBuffer aBuffer( 1024 );
++ aBuffer.append( aQFontName );
++ aBuffer.appendAscii( ";", 1 );
++ aBuffer.append( aFontName );
++
++ rFont.SetName( aBuffer.makeStringAndClear() );
++ }
++
++ // QFontInfo should give the right point size, but sometimes it does not,
++ // it seems.
++ int nPointSize = qFontInfo.pointSize();
++ if ( nPointSize <= 0 )
++ nPointSize = rQFont.pointSize();
++ if ( nPointSize > 0 )
++ rFont.SetHeight( nPointSize );
+
+ rFont.SetItalic( qFontInfo.italic()? ITALIC_NORMAL: ITALIC_NONE );
+
diff --git a/patches/src680/fpicker-gnome-build.diff b/patches/src680/fpicker-gnome-build.diff
new file mode 100644
index 000000000..90aba1914
--- /dev/null
+++ b/patches/src680/fpicker-gnome-build.diff
@@ -0,0 +1,28 @@
+--- fpicker/source/unx/gnome/makefile.mk 2004-11-11 14:52:41.349831648 +0100
++++ fpicker/source/unx/gnome/makefile.mk 2004-11-11 14:54:01.520643832 +0100
+@@ -76,14 +76,13 @@ ENABLE_EXCEPTIONS=TRUE
+ .IF "$(ENABLE_GTK)" != "TRUE"
+
+ dummy:
+- @echo "Nothing to build. GUIBASE == $(GUIBASE), WITH_WIDGETSET == $(WITH_WIDGETSET)"
++ @echo "Nothing to build."
+
+ .ELSE # we build for GNOME
+
+ #.INCLUDE : ..$/..$/cppumaker.mk
+
+-CFLAGS+= $(WIDGETSET_CFLAGS)
+-CFLAGS+=`pkg-config --cflags gtk+-2.0`
++CFLAGS+= $(GTK_CFLAGS)
+
+ # --- Files --------------------------------------------------------
+
+@@ -96,7 +95,7 @@ SLOFILES =\
+ $(SLO)$/filepickereventnotification.obj \
+ $(SLO)$/FPentry.obj
+
+-.ENDIF # "$(GUIBASE)" != "unx" || "$(WITH_WIDGETSET)" != "gnome"
++.ENDIF # "$(ENABLE_GTK)" != "TRUE"
+
+ # --- Targets ------------------------------------------------------
+
diff --git a/patches/src680/icons-config_office.diff b/patches/src680/icons-config_office.diff
new file mode 100644
index 000000000..a3a870a9c
--- /dev/null
+++ b/patches/src680/icons-config_office.diff
@@ -0,0 +1,45 @@
+--- config_office/configure.in 2004-10-26 15:17:20.072058712 +0200
++++ config_office/configure.in 2004-10-26 15:44:33.812692384 +0200
+@@ -103,6 +103,12 @@ AC_ARG_ENABLE(kde,
+ [ --enable-kde Determines whether to use Qt/KDE vclplug on platforms
+ where Qt and KDE are available.
+ ],,)
++AC_ARG_WITH(gnome-icons,
++[ --with-gnome-icons Zip archive with icons for Gnome session.
++],,)
++AC_ARG_WITH(kde-icons,
++[ --with-kde-icons Zip archive with icons for KDE session.
++],,)
+ AC_ARG_ENABLE(binfilter,
+ [ --disable-binfilter: Disable legacy binary file formats filters
+ ],,)
+@@ -2565,6 +2580,18 @@ AC_SUBST(WIDGETSET_KDE_LIBS)
+ AC_SUBST(KDE_CFLAGS)
+ AC_SUBST(KDE_LIBS)
+
++ICONS_GNOME=
++ICONS_KDE=
++if test -f "$with_gnome_icons"; then
++ ICONS_GNOME="$with_gnome_icons"
++fi
++if test -f "$with_kde_icons"; then
++ ICONS_KDE="$with_kde_icons"
++fi
++
++AC_SUBST(ICONS_GNOME)
++AC_SUBST(ICONS_KDE)
++
+ dnl ===================================================================
+ dnl Test for the presence of libstartup-notification
+ dnl ===================================================================
+--- config_office/set_soenv.in 2004-10-26 15:19:05.986957200 +0200
++++ config_office/set_soenv.in 2004-10-26 15:21:36.285108408 +0200
+@@ -1428,6 +1428,8 @@ ToFile( "WIDGETSET_GTK_CFLAGS", "@WIDGE
+ ToFile( "ENABLE_KDE", "@ENABLE_KDE@", "e" );
+ ToFile( "KDE_CFLAGS", "@KDE_CFLAGS@", "e" );
+ ToFile( "KDE_LIBS", "@KDE_LIBS@", "e" );
++ToFile( "ICONS_GNOME", "@ICONS_GNOME@", "e" );
++ToFile( "ICONS_KDE", "@ICONS_KDE@", "e" );
+ ToFile( "PSPRINT", "TRUE", "e" );
+ # [ed] 5/14/02 If we're building Aqua graphics, insert a C macro to indicate this.
+ # There may be a better way to do this, like splitting unxmacxp into two, but
diff --git a/patches/src680/icons-instsetoo_native.diff b/patches/src680/icons-instsetoo_native.diff
new file mode 100644
index 000000000..91bb87ca0
--- /dev/null
+++ b/patches/src680/icons-instsetoo_native.diff
@@ -0,0 +1,35 @@
+Index: instsetoo_native/packimages/makefile.mk
+===================================================================
+RCS file: /cvs/installation/instsetoo_native/packimages/makefile.mk,v
+retrieving revision 1.7
+diff -u -p -u -r1.7 makefile.mk
+--- instsetoo_native/packimages/makefile.mk 17 Nov 2004 18:10:31 -0000 1.7
++++ instsetoo_native/packimages/makefile.mk 1 Dec 2004 08:51:07 -0000
+@@ -69,7 +69,17 @@ TARGET=packimages
+ RSCCUSTOMIMG*=$(PRJNAME)$/util
+ .INCLUDE: target.mk
+
+-ALLTAR : $(COMMONBIN)$/images.zip
++IMAGES := $(COMMONBIN)$/images.zip
++
++.IF "$(ICONS_GNOME)" != ""
++IMAGES += $(COMMONBIN)$/images_gnome.zip
++.ENDIF
++
++.IF "$(ICONS_KDE)" != ""
++IMAGES += $(COMMONBIN)$/images_kde.zip
++.ENDIF
++
++ALLTAR : $(IMAGES)
+
+ $(RES)$/img$/commandimagelist.ilst .PHONY :
+ +-$(MKDIR) $(RES)$/img
+@@ -84,3 +94,8 @@ $(RES)$/img$/commandimagelist.ilst .PHON
+ $(COMMONBIN)$/images.zip .PHONY: $(RES)$/img$/commandimagelist.ilst
+ +$(PERL) $(SOLARENV)$/bin$/packimages.pl -g $(SOLARSRC)$/$(RSCDEFIMG) -m $(SOLARSRC)$/$(RSCDEFIMG) -c $(SOLARSRC)$/$(RSCCUSTOMIMG) -l $(SOLARCOMMONRESDIR)$/img -l $(RES)$/img -o $@
+
++$(COMMONBIN)$/images_gnome.zip: $(ICONS_GNOME)
++ +$(COPY) $< $@
++
++$(COMMONBIN)$/images_kde.zip: $(ICONS_KDE)
++ +$(COPY) $< $@
diff --git a/patches/src680/install-rework.diff b/patches/src680/install-rework.diff
new file mode 100644
index 000000000..caf77f591
--- /dev/null
+++ b/patches/src680/install-rework.diff
@@ -0,0 +1,217 @@
+Index: solenv/bin/make_installer.pl
+===================================================================
+RCS file: /cvs/tools/solenv/bin/make_installer.pl,v
+retrieving revision 1.20
+diff -u -p -u -r1.20 make_installer.pl
+--- solenv/bin/make_installer.pl 18 Oct 2004 13:51:13 -0000 1.20
++++ solenv/bin/make_installer.pl 11 Nov 2004 15:47:35 -0000
+@@ -117,6 +117,65 @@ use installer::windows::shortcut;
+ use installer::windows::upgrade;
+ use installer::ziplist;
+
++sub install_simple ($$$$)
++{
++ my ($packagename, $directoriesarray, $filesarray, $linksarray) = @_;
++ my $destdir = $installer::globals::destdir;
++ my @lines = ();
++
++ `mkdir -p $destdir` if $destdir ne "";
++ `mkdir -p $destdir$installer::globals::rootpath`;
++
++ # Create Directories
++ for ( my $i = 0; $i <= $#{$directoriesarray}; $i++ )
++ {
++ my $onedir = ${$directoriesarray}[$i];
++ my $dir = "";
++
++ if ( $onedir->{'Dir'} ) { $dir = $onedir->{'Dir'}; }
++
++ if ((!($dir =~ /\bPREDEFINED_/ )) || ( $dir =~ /\bPREDEFINED_PROGDIR\b/ ))
++ {
++# printf "mkdir $destdir$onedir->{'HostName'}\n";
++ mkdir $destdir . $onedir->{'HostName'};
++ push @lines, "%dir " . $onedir->{'HostName'} . "\n";
++ }
++ }
++
++ for ( my $i = 0; $i <= $#{$filesarray}; $i++ )
++ {
++ my $onefile = ${$filesarray}[$i];
++ my $unixrights = $onefile->{'UnixRights'};
++ my $destination = $onefile->{'destination'};
++ my $sourcepath = $onefile->{'sourcepath'};
++
++# printf "mv $sourcepath $destdir$destination\n";
++ `cp -af '$sourcepath' '$destdir$destination'`;
++ `chmod $unixrights '$destdir$destination'`;
++ push @lines, "$destination\n";
++ }
++
++ for ( my $i = 0; $i <= $#{$linksarray}; $i++ )
++ {
++ my $onelink = ${$linksarray}[$i];
++ my $destination = $onelink->{'destination'};
++ my $destinationfile = $onelink->{'destinationfile'};
++
++# print "link $destinationfile -> $destdir$destination\n";
++ `ln -sf '$destinationfile' '$destdir$destination'`;
++ push @lines, "$destination\n";
++ }
++
++ if ( $destdir ne "" )
++ {
++ my $filelist;
++ my $fname = $installer::globals::destdir . "/$packagename";
++ open ($filelist, ">$fname") || die "Can't open $fname: $!";
++ print $filelist @lines;
++ close ($filelist);
++ }
++}
++
+ #################################################
+ # Main program
+ #################################################
+@@ -1060,36 +1119,44 @@ for ( my $n = 0; $n <= $#installer::glob
+ # The source field specifies the file to link to
+
+ my $epmfilename = "epm_" . $installer::globals::product . "_" . $onepackagename . "_" . $installer::globals::compiler . "_" . $installer::globals::build . "_" . $installer::globals::minor . "_" . $$languagestringref . ".lst";
+-
+- print "... creating epm list file $epmfilename ... \n";
+-
+ my $completeepmfilename = $listfiledir . $installer::globals::separator . $epmfilename;
+
+ my @epmfile = ();
+
+- my $epmheaderref = installer::epmfile::create_epm_header($allvariableshashref, $filesinproductlanguageresolvedarrayref, $languagesarrayref, $onepackage);
+- installer::epmfile::adding_header_to_epm_file(\@epmfile, $epmheaderref);
++ my $staticpath = "";
++ my $relocatablepath = "";
+
+- # adding directories, files and links into epm file
+-
+- installer::epmfile::put_directories_into_epmfile($dirsinpackage, \@epmfile );
+- installer::epmfile::put_files_into_epmfile($filesinpackage, \@epmfile );
+- installer::epmfile::put_links_into_epmfile($linksinpackage, \@epmfile );
++ if ( $installer::globals::simple )
++ {
++ print "... installing module $onepackagename ... \n";
++ install_simple ($onepackagename, $dirsinpackage, $filesinpackage, $linksinpackage);
++ }
++ else # use EPM to package
++ {
++ print "... creating epm list file $epmfilename ... \n";
+
+- if ((!( $shellscriptsfilename eq "" )) && (!($installer::globals::iswindowsbuild))) { installer::epmfile::adding_shellscripts_to_epm_file(\@epmfile, $shellscriptsfilename, $packagerootpath, $allvariableshashref); }
++ my $epmheaderref = installer::epmfile::create_epm_header($allvariableshashref, $filesinproductlanguageresolvedarrayref, $languagesarrayref, $onepackage);
++ installer::epmfile::adding_header_to_epm_file(\@epmfile, $epmheaderref);
+
+- installer::files::save_file($completeepmfilename ,\@epmfile);
++ # adding directories, files and links into epm file
++
++ installer::epmfile::put_directories_into_epmfile($dirsinpackage, \@epmfile );
++ installer::epmfile::put_files_into_epmfile($filesinpackage, \@epmfile );
++ installer::epmfile::put_links_into_epmfile($linksinpackage, \@epmfile );
++
++ if ((!( $shellscriptsfilename eq "" )) && (!($installer::globals::iswindowsbuild))) { installer::epmfile::adding_shellscripts_to_epm_file(\@epmfile, $shellscriptsfilename, $packagerootpath, $allvariableshashref); }
+
+- # ... splitting the rootpath into a relocatable part and a static part, if possible
++ installer::files::save_file($completeepmfilename ,\@epmfile);
+
+- my $staticpath = "";
+- my $relocatablepath = "";
+- installer::epmfile::analyze_rootpath($packagerootpath, \$staticpath, \$relocatablepath);
++ # ... splitting the rootpath into a relocatable part and a static part, if possible
+
+- # ... replacing the variable PRODUCTDIRECTORYNAME in the shellscriptfile by $staticpath
++ installer::epmfile::analyze_rootpath($packagerootpath, \$staticpath, \$relocatablepath);
+
+- installer::epmfile::resolve_path_in_epm_list_before_packaging(\@epmfile, $completeepmfilename, "PRODUCTDIRECTORYNAME", $staticpath);
+- installer::files::save_file($completeepmfilename ,\@epmfile);
++ # ... replacing the variable PRODUCTDIRECTORYNAME in the shellscriptfile by $staticpath
++
++ installer::epmfile::resolve_path_in_epm_list_before_packaging(\@epmfile, $completeepmfilename, "PRODUCTDIRECTORYNAME", $staticpath);
++ installer::files::save_file($completeepmfilename ,\@epmfile);
++ }
+
+ # changing into the "install" directory to create installation sets
+
+@@ -1168,8 +1235,11 @@ for ( my $n = 0; $n <= $#installer::glob
+ }
+ else # this is the standard epm (not relocatable) or ( nonlinux and nonsolaris )
+ {
+- installer::epmfile::resolve_path_in_epm_list_before_packaging(\@epmfile, $completeepmfilename, "\$\$PRODUCTINSTALLLOCATION", $relocatablepath);
+- installer::files::save_file($completeepmfilename ,\@epmfile);
++ if ( !$installer::globals::simple )
++ {
++ installer::epmfile::resolve_path_in_epm_list_before_packaging(\@epmfile, $completeepmfilename, "\$\$PRODUCTINSTALLLOCATION", $relocatablepath);
++ installer::files::save_file($completeepmfilename ,\@epmfile);
++ }
+
+ if ( $installer::globals::call_epm )
+ {
+Index: solenv/bin/modules/installer/globals.pm
+===================================================================
+RCS file: /cvs/tools/solenv/bin/modules/installer/globals.pm,v
+retrieving revision 1.18
+diff -u -p -u -r1.18 globals.pm
+--- solenv/bin/modules/installer/globals.pm 18 Oct 2004 13:52:14 -0000 1.18
++++ solenv/bin/modules/installer/globals.pm 11 Nov 2004 15:47:35 -0000
+@@ -77,6 +77,7 @@ BEGIN
+ $product = "";
+ $languagelist = "";
+
++ $destdir = "";
+ $rootpath = "";
+
+ $productextension = "";
+@@ -129,6 +130,7 @@ BEGIN
+ $is_special_epm = 0;
+ $epm_in_path = 0;
+ $epm_path = "";
++ $simple = 0;
+ $call_epm = 1;
+ $packageformat = "";
+ $packagename = "";
+Index: solenv/bin/modules/installer/parameter.pm
+===================================================================
+RCS file: /cvs/tools/solenv/bin/modules/installer/parameter.pm,v
+retrieving revision 1.10
+diff -u -p -u -r1.10 parameter.pm
+--- solenv/bin/modules/installer/parameter.pm 18 Oct 2004 13:53:07 -0000 1.10
++++ solenv/bin/modules/installer/parameter.pm 11 Nov 2004 15:47:35 -0000
+@@ -88,6 +88,7 @@ The following parameter are needed:
+ -l: Language of the product (comma and hash) (optional, defined in productlist)
+ -b: Build, e.g. srx645 (optional)
+ -m: Minor, e.g. m10 (optional)
++-simple: Path to do a simple install to
+ -c: Compiler, e.g. wntmsci8, unxlngi5, unxsols4, ... (optional)
+ -u: Path, in which zipfiles are unpacked (optional)
+ -msitemplate: Source of the msi file templates (Windows compiler only)
+@@ -159,6 +160,7 @@ sub getparameter
+ {
+ if ( $installer::globals::debug ) { installer::logger::debuginfo("installer::parameter::getparameter"); }
+
++ my $destdir;
+ while ( $#ARGV >= 0 )
+ {
+ my $param = shift(@ARGV);
+@@ -190,6 +192,19 @@ sub getparameter
+ elsif ($param eq "-copyproject") { $installer::globals::is_copy_only_project = 1; }
+ elsif ($param eq "-languagepack") { $installer::globals::languagepack = 1; }
+ elsif ($param eq "-addchildprojects") { $installer::globals::addchildprojects = 1; }
++ elsif ($param eq "-destdir")
++ {
++ $installer::globals::rootpath ne "" && die "must set destdir before -i or -simple";
++ $installer::globals::destdir = shift @ARGV;
++ }
++ elsif ($param eq "-simple")
++ {
++ $installer::globals::simple = 1;
++ $installer::globals::call_epm = 0;
++ my $path = shift(@ARGV);
++ $path =~ s/^$installer::globals::destdir//;
++ $installer::globals::rootpath = $path;
++ }
+ else
+ {
+ print("\n*************************************\n");
diff --git a/patches/src680/parallel-libxml2-makefile_mk.diff b/patches/src680/parallel-libxml2-makefile_mk.diff
new file mode 100644
index 000000000..ad434af11
--- /dev/null
+++ b/patches/src680/parallel-libxml2-makefile_mk.diff
@@ -0,0 +1,10 @@
+--- libxml2/makefile.mk.orig 2004-10-19 18:14:27.041976704 +0200
++++ libxml2/makefile.mk 2004-10-19 18:47:40.073989784 +0200
+@@ -100,6 +100,7 @@ CONFIGURE_ACTION=.$/configure
+ CONFIGURE_FLAGS=--enable-ipv6=no --without-python --enable-static=no
+ BUILD_ACTION=$(GNUMAKE)
+ BUILD_DIR=$(CONFIGURE_DIR)
++BUILD_FLAGS+= -j$(MAXPROCESS)
+ .ENDIF
+
+
diff --git a/patches/src680/scp-vclplug-kde.diff b/patches/src680/scp-vclplug-kde.diff
new file mode 100644
index 000000000..d700e230d
--- /dev/null
+++ b/patches/src680/scp-vclplug-kde.diff
@@ -0,0 +1,27 @@
+--- scp2/source/ooo/file_library_ooo.scp 2004-10-12 17:43:00.993275112 +0200
++++ scp2/source/ooo/file_library_ooo.scp 2004-10-12 17:52:23.606744864 +0200
+@@ -1333,6 +1333,11 @@ STD_SETUPZIP_LIB_FILE( gid_File_Lib_Vclp
+ STD_SETUPZIP_LIB_FILE( gid_File_Lib_Vclplug_Gtk, vclplug_gtk )
+ #endif
+ #endif
++#ifdef ENABLE_KDE
++#ifndef MACOSX
++STD_SETUPZIP_LIB_FILE( gid_File_Lib_Vclplug_Kde, vclplug_kde )
++#endif
++#endif
+ #endif
+
+ File gid_File_Lib_Rdbtdp
+--- scp2/source/ooo/makefile.mk 2004-10-12 18:06:58.133796544 +0200
++++ scp2/source/ooo/makefile.mk 2004-10-12 18:07:23.540934072 +0200
+@@ -86,6 +86,10 @@ SCPDEFS+=-DINCLUDE_JAVA_ACCESSBRIDGE
+ SCPDEFS+=-DENABLE_GTK
+ .ENDIF
+
++.IF "$(ENABLE_KDE)" != ""
++SCPDEFS+=-DENABLE_KDE
++.ENDIF
++
+ .IF "$(ENABLE_DIRECTX)" != ""
+ SCPDEFS+=-DENABLE_DIRECTX
+ .ENDIF
diff --git a/patches/src680/setup2-update-symlink.diff b/patches/src680/setup2-update-symlink.diff
new file mode 100644
index 000000000..a76c8c041
--- /dev/null
+++ b/patches/src680/setup2-update-symlink.diff
@@ -0,0 +1,10 @@
+--- setup2/mow/source/system/mowos.cxx.old 2004-09-24 19:57:23.000000000 +0200
++++ setup2/mow/source/system/mowos.cxx 2004-09-27 19:53:17.000000000 +0200
+@@ -324,6 +324,7 @@
+ ByteString const& aDest
+ )
+ {
++ unlink(aDest.GetBuffer());
+ return symlink(aSource.GetBuffer(),aDest.GetBuffer()) == 0;
+ }
+
diff --git a/patches/src680/speed-lang-cache.diff b/patches/src680/speed-lang-cache.diff
new file mode 100644
index 000000000..3c9fc5eab
--- /dev/null
+++ b/patches/src680/speed-lang-cache.diff
@@ -0,0 +1,20 @@
+Index: svx/source/stbctrls/pszctrl.cxx
+===================================================================
+RCS file: /cvs/graphics/svx/source/stbctrls/pszctrl.cxx,v
+retrieving revision 1.5
+diff -u -r1.5 pszctrl.cxx
+--- svx/source/stbctrls/pszctrl.cxx 10 Jul 2001 11:22:50 -0000 1.5
++++ svx/source/stbctrls/pszctrl.cxx 6 Dec 2002 16:41:37 -0000
+@@ -143,10 +143,9 @@
+ eInUnit = FUNIT_100TH_MM;
+
+ String sMetric;
+- LocaleDataWrapper aLocaleWrapper( ::comphelper::getProcessServiceFactory(), Application::GetSettings().GetLocale() );
+- const sal_Unicode cSep = aLocaleWrapper.getNumDecimalSep().GetChar(0);
++ const sal_Unicode cSep = Application::GetSettings().GetLocaleDataWrapper().getNumDecimalSep().GetChar(0);
+ long nConvVal = MetricField::ConvertValue( nVal * 100, 0L, 0,
+- eInUnit, eOutUnit );
++ eInUnit, eOutUnit );
+
+ if ( nConvVal < 0 && ( nConvVal / 100 == 0 ) )
+ sMetric += '-';
diff --git a/patches/src680/system-libstdcpp.diff b/patches/src680/system-libstdcpp.diff
new file mode 100644
index 000000000..7366e7623
--- /dev/null
+++ b/patches/src680/system-libstdcpp.diff
@@ -0,0 +1,71 @@
+Index: scp2/source/ooo/file_library_ooo.scp
+===================================================================
+RCS file: /cvs/installation/scp2/source/ooo/file_library_ooo.scp,v
+retrieving revision 1.65
+diff -u -r1.65 file_library_ooo.scp
+--- scp2/source/ooo/file_library_ooo.scp 9 Nov 2004 16:51:31 -0000 1.65
++++ scp2/source/ooo/file_library_ooo.scp 3 Dec 2004 09:32:21 -0000
+@@ -687,36 +703,6 @@
+
+ STD_UNO_LIB_FILE( gid_File_Lib_Fwl , fwl)
+
+-// Temporary solution/hack: at the moment libstdc++.so and libgcc_s.so are
+-// needed for unxlngi4 environment (setup is linked against it).
+-
+-#if ! (defined (FREEBSD) || defined (NETBSD) || defined(MACOSX) )
+-#if defined( _gcc3 )
+-
+-File gid_File_Lib_Gcc
+- TXT_FILE_BODY;
+- Name = STRING(libgcc_s.so.1);
+- Dir = gid_Dir_Program;
+- Styles = (PACKED, SETUPZIP);
+-End
+-
+-#endif
+-
+-#endif
+-
+-#if ! (defined (FREEBSD) || defined (NETBSD) || defined(MACOSX) )
+-#if defined( _gcc3 )
+-
+-File gid_File_Lib_Stdc
+- TXT_FILE_BODY;
+- Name = STRING(CONCAT2(libstdc++.so.,SHORTSTDCPP3));
+- Dir = gid_Dir_Program;
+- Styles = (PACKED, SETUPZIP);
+-End
+-
+-#endif
+-
+-#endif
+
+ #if defined(LINUX) || defined(FREEBSD) || defined(NETBSD) || defined(IRIX) || defined(MACOSX)
+
+Index: scp2/source/ooo/shortcut_ooo.scp
+===================================================================
+RCS file: /cvs/installation/scp2/source/ooo/shortcut_ooo.scp,v
+retrieving revision 1.12
+diff -u -r1.12 shortcut_ooo.scp
+--- scp2/source/ooo/shortcut_ooo.scp 9 Nov 2004 12:09:23 -0000 1.12
++++ scp2/source/ooo/shortcut_ooo.scp 3 Dec 2004 09:48:56 -0000
+@@ -364,19 +364,6 @@
+
+ #endif
+
+-#if ! (defined (FREEBSD) || defined (NETBSD) || defined(MACOSX) )
+-#if ( defined( _gcc3 ) && ( defined( C300 ) || defined( C322 ) ))
+-
+-Shortcut gid_Shortcut_Lib_Stdc
+- FileID = gid_File_Lib_Stdc;
+- Dir = gid_Dir_Program;
+- Name = STRING(libstdc++.so);
+- Styles = (NETWORK,RELATIVE);
+-End
+-
+-#endif
+-#endif
+-
+ #ifdef UNX
+
+ Shortcut gid_Shortcut_Lib_Store_Linker
diff --git a/patches/src680/system-mozilla-moz.diff b/patches/src680/system-mozilla-moz.diff
new file mode 100644
index 000000000..1a41f5b9d
--- /dev/null
+++ b/patches/src680/system-mozilla-moz.diff
@@ -0,0 +1,17 @@
+? noworkspace-systemmozilla.moz.patch
+Index: zipped/makefile.mk
+===================================================================
+RCS file: /cvs/external/moz/zipped/makefile.mk,v
+retrieving revision 1.10
+diff -u -p -r1.10 makefile.mk
+--- moz/zipped/makefile.mk 31 Aug 2004 12:44:55 -0000 1.10
++++ moz/zipped/makefile.mk 27 Oct 2004 17:33:48 -0000
+@@ -71,7 +71,7 @@ TARGET=moz_unzip
+
+ # --- Files --------------------------------------------------------
+
+-.IF "$(OS)" == "MACOSX" || "$(WITH_MOZILLA)" == "NO"
++.IF "$(OS)" == "MACOSX" || "$(SYSTEM_MOZILLA)" == "YES"
+
+ dummy:
+ @echo "Nothing to build for OS $(OS)"
diff --git a/patches/src680/system-mozilla-xmlsecurity-nssrenam.diff b/patches/src680/system-mozilla-xmlsecurity-nssrenam.diff
new file mode 100644
index 000000000..2c5c55c9c
--- /dev/null
+++ b/patches/src680/system-mozilla-xmlsecurity-nssrenam.diff
@@ -0,0 +1,52 @@
+--- /dev/null
++++ xmlsecurity/inc/nssrenam.h
+@@ -0,0 +1,49 @@
++/*
++ * 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/
++ *
++ * Software distributed under the License is distributed on an "AS
++ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
++ * implied. See the License for the specific language governing
++ * rights and limitations under the License.
++ *
++ * The Original Code is the Netscape security libraries.
++ *
++ * The Initial Developer of the Original Code is Netscape
++ * Communications Corporation. Portions created by Netscape are
++ * Copyright (C) 2001 Netscape Communications Corporation. All
++ * Rights Reserved.
++ *
++ * Contributor(s):
++ *
++ * Alternatively, the contents of this file may be used under the
++ * terms of the GNU General Public License Version 2 or later (the
++ * "GPL"), in which case the provisions of the GPL are applicable
++ * instead of those above. If you wish to allow use of your
++ * version of this file only under the terms of the GPL and not to
++ * allow others to use your version of this file under the MPL,
++ * indicate your decision by deleting the provisions above and
++ * replace them with the notice and other provisions required by
++ * the GPL. If you do not delete the provisions above, a recipient
++ * may use your version of this file under either the MPL or the
++ * GPL.
++ */
++
++#ifndef __nssrenam_h_
++#define __nssrenam_h_
++
++#define CERT_NewTempCertificate __CERT_NewTempCertificate
++#define PK11_CreateContextByRawKey __PK11_CreateContextByRawKey
++#define PK11_GetKeyData __PK11_GetKeyData
++#define nss_InitLock __nss_InitLock
++#define CERT_ClosePermCertDB __CERT_ClosePermCertDB
++#define CERT_DecodeDERCertificate __CERT_DecodeDERCertificate
++#define CERT_TraversePermCertsForNickname __CERT_TraversePermCertsForNickname
++#define CERT_TraversePermCertsForSubject __CERT_TraversePermCertsForSubject
++#define PBE_CreateContext __PBE_CreateContext
++#define PBE_DestroyContext __PBE_DestroyContext
++#define PBE_GenerateBits __PBE_GenerateBits
++
++#endif /* __nssrenam_h_ */
diff --git a/patches/src680/vcl-force-desktop.diff b/patches/src680/vcl-force-desktop.diff
new file mode 100644
index 000000000..45250d0f4
--- /dev/null
+++ b/patches/src680/vcl-force-desktop.diff
@@ -0,0 +1,15 @@
+--- vcl/unx/source/plugadapt/salplug.cxx 2004-08-23 16:17:32.000000000 -0700
++++ vcl/unx/source/plugadapt/salplug.cxx 2004-08-23 17:43:17.000000000 -0700
+@@ -398,7 +398,11 @@ static const char * get_desktop_environm
+ {
+ XErrorHandler pOldHdl = XSetErrorHandler( autodect_error_handler );
+
+- if ( is_gnome_desktop( pDisplay ) )
++ if ( NULL != getenv( "GNOME_DESKTOP_SESSION_ID" ) )
++ pRet = desktop_strings[DESKTOP_GNOME];
++ else if ( NULL != getenv( "KDE_FULL_SESSION" ) )
++ pRet = desktop_strings[DESKTOP_KDE];
++ else if ( is_gnome_desktop( pDisplay ) )
+ pRet = desktop_strings[DESKTOP_GNOME];
+ else if ( is_kde_desktop( pDisplay ) )
+ pRet = desktop_strings[DESKTOP_KDE];
diff --git a/patches/src680/vcl-gtk-rtl-fix.diff b/patches/src680/vcl-gtk-rtl-fix.diff
new file mode 100644
index 000000000..bc043a9d3
--- /dev/null
+++ b/patches/src680/vcl-gtk-rtl-fix.diff
@@ -0,0 +1,64 @@
+--- vcl/unx/gtk/window/gtkframe.cxx.bak 2004-11-24 11:28:39.000000000 +0530
++++ vcl/unx/gtk/window/gtkframe.cxx 2004-11-30 10:51:59.785225136 +0530
+@@ -76,6 +76,8 @@
+ #include <dlfcn.h>
+ #include <soicon.hxx>
+
++#include <svapp.hxx>
++
+ #if OSL_DEBUG_LEVEL > 1
+ #include <cstdio>
+ #endif
+@@ -795,6 +797,8 @@
+ {
+ if( m_pParent )
+ {
++ if( Application::GetSettings().GetLayoutRTL() )
++ nX = m_pParent->maGeometry.nWidth-maGeometry.nWidth-1-nX;
+ nX += m_pParent->maGeometry.nX;
+ nY += m_pParent->maGeometry.nY;
+ }
+@@ -1568,6 +1570,10 @@
+ gdk_display_pointer_ungrab( pThis->getGdkDisplay(), GDK_CURRENT_TIME );
+ }
+
++ // --- RTL --- (mirror mouse pos)
++ if( Application::GetSettings().GetLayoutRTL() )
++ aEvent.mnX = pThis->maGeometry.nWidth-1-aEvent.mnX;
++
+ GTK_YIELD_GRAB();
+
+ vcl::DeletionListener aDel( pThis );
+@@ -1628,6 +1630,10 @@
+ aEvent.mnCode = GetModCode( pSEvent->state );
+ aEvent.mbHorz = (pSEvent->direction == GDK_SCROLL_LEFT || pSEvent->direction == GDK_SCROLL_RIGHT);
+
++ // --- RTL --- (mirror mouse pos)
++ if( Application::GetSettings().GetLayoutRTL() )
++ aEvent.mnX = pThis->maGeometry.nWidth-1-aEvent.mnX;
++
+ GTK_YIELD_GRAB();
+ pThis->CallCallback( SALEVENT_WHEELMOUSE, &aEvent );
+
+@@ -1645,7 +1645,10 @@
+ aEvent.mnCode = GetModCode( pEvent->state );
+ aEvent.mnButton = 0;
+
+
++ // --- RTL --- (mirror mouse pos)
++ if( Application::GetSettings().GetLayoutRTL() )
++ aEvent.mnX = pThis->maGeometry.nWidth-1-aEvent.mnX;
+ GTK_YIELD_GRAB();
+
+ vcl::DeletionListener aDel( pThis );
+@@ -1703,6 +1702,10 @@
+ aEvent.mnBoundWidth = pEvent->area.width;
+ aEvent.mnBoundHeight = pEvent->area.height;
+
++ // --- RTL --- (mirror mouse pos)
++ if( Application::GetSettings().GetLayoutRTL() )
++ aEvent.mnBoundX = pThis->maGeometry.nWidth-aEvent.mnBoundWidth-aEvent.mnBoundX;
++
+ GTK_YIELD_GRAB();
+ pThis->CallCallback( SALEVENT_PAINT, &aEvent );
+
diff --git a/patches/src680/vcl-prelight-industrial.diff b/patches/src680/vcl-prelight-industrial.diff
new file mode 100644
index 000000000..57f85deb3
--- /dev/null
+++ b/patches/src680/vcl-prelight-industrial.diff
@@ -0,0 +1,21 @@
+Index: vcl/source/window/window.cxx
+===================================================================
+RCS file: /cvs/gsl/vcl/source/window/window.cxx,v
+retrieving revision 1.199
+diff -u -r1.199 window.cxx
+--- vcl/source/window/window.cxx 9 Sep 2004 16:23:08 -0000 1.199
++++ vcl/source/window/window.cxx 15 Oct 2004 15:55:32 -0000
+@@ -8769,8 +8769,13 @@
+ Color aSelectionBorderCol( GetSettings().GetStyleSettings().GetHighlightColor() );
+ Color aSelectionFillCol( aSelectionBorderCol );
+
++#ifdef HORRIBLE_WITH_INDUSTRIAL_THEME
+ BOOL bDark = GetSettings().GetStyleSettings().GetFaceColor().IsDark();
+ BOOL bBright = GetSettings().GetStyleSettings().GetFaceColor().IsBright();
++#else
++ BOOL bDark = FALSE;
++ BOOL bBright = FALSE;
++#endif
+
+ int c1 = aSelectionBorderCol.GetLuminance();
+ int c2 = GetDisplayBackground().GetColor().GetLuminance();
diff --git a/patches/src680/vcl-util-makefile-kde.diff b/patches/src680/vcl-util-makefile-kde.diff
new file mode 100644
index 000000000..788dd8dfe
--- /dev/null
+++ b/patches/src680/vcl-util-makefile-kde.diff
@@ -0,0 +1,11 @@
+--- vcl/util/makefile.mk.orig 2004-11-22 15:26:46.618142224 +0100
++++ vcl/util/makefile.mk 2004-11-22 15:26:58.762296032 +0100
+@@ -391,7 +391,7 @@ SHL5TARGET=vclplug_kde$(UPD)$(DLLPOSTFIX
+ SHL5IMPLIB=ikde_plug_
+ SHL5LIBS=$(LIB5TARGET)
+ # libs for KDE plugin
+-SHL5STDLIBS=$(WIDGETSET_KDE_LIBS)
++SHL5STDLIBS=$(KDE_LIBS)
+ SHL5STDLIBS+=-l$(SHL2TARGET)
+ SHL5STDLIBS+=$(SHL3STDLIBS) -lX11 -ldl
+ .ENDIF # "$(ENABLE_KDE)" != ""
diff --git a/patches/src680/win32-internal-libart.diff b/patches/src680/win32-internal-libart.diff
new file mode 100644
index 000000000..c9de18f6d
--- /dev/null
+++ b/patches/src680/win32-internal-libart.diff
@@ -0,0 +1,4082 @@
+diff -u -r --new-file /tmp/empty/art_config.h tools/source/generic/libart_lgpl/art_config.h
+--- tools/source/generic/libart_lgpl/art_config.h 1970-01-01 01:00:00.000000000 +0100
++++ tools/source/generic/libart_lgpl/art_config.h 2004-04-06 17:43:36.000000000 +0100
+@@ -0,0 +1,10 @@
++/* Automatically generated by gen_art_config.c */
++
++#define ART_SIZEOF_CHAR 1
++#define ART_SIZEOF_SHORT 2
++#define ART_SIZEOF_INT 4
++#define ART_SIZEOF_LONG 4
++
++typedef unsigned char art_u8;
++typedef unsigned short art_u16;
++typedef unsigned int art_u32;
+diff -u -r --new-file tools/source/generic/libart_lgpl/art_misc.c tools/source/generic/libart_lgpl/art_misc.c
+--- tools/source/generic/libart_lgpl/art_misc.c 1970-01-01 01:00:00.000000000 +0100
++++ tools/source/generic/libart_lgpl/art_misc.c 2004-04-06 17:43:45.000000000 +0100
+@@ -0,0 +1,79 @@
++/* Libart_LGPL - library of basic graphic primitives
++ * Copyright (C) 1998 Raph Levien
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the
++ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
++ * Boston, MA 02111-1307, USA.
++ */
++
++/* Various utility functions RLL finds useful. */
++
++#include "config.h"
++#include "art_misc.h"
++
++#ifdef HAVE_UINSTD_H
++#include <unistd.h>
++#endif
++#include <stdio.h>
++#include <stdarg.h>
++
++/**
++ * art_die: Print the error message to stderr and exit with a return code of 1.
++ * @fmt: The printf-style format for the error message.
++ *
++ * Used for dealing with severe errors.
++ **/
++void
++art_die (const char *fmt, ...)
++{
++ va_list ap;
++
++ va_start (ap, fmt);
++ vfprintf (stderr, fmt, ap);
++ va_end (ap);
++ exit (1);
++}
++
++/**
++ * art_warn: Print the warning message to stderr.
++ * @fmt: The printf-style format for the warning message.
++ *
++ * Used for generating warnings.
++ **/
++void
++art_warn (const char *fmt, ...)
++{
++ va_list ap;
++
++ va_start (ap, fmt);
++ vfprintf (stderr, fmt, ap);
++ va_end (ap);
++}
++
++/**
++ * art_dprint: Print the debug message to stderr.
++ * @fmt: The printf-style format for the debug message.
++ *
++ * Used for generating debug output.
++ **/
++void
++art_dprint (const char *fmt, ...)
++{
++ va_list ap;
++
++ va_start (ap, fmt);
++ vfprintf (stderr, fmt, ap);
++ va_end (ap);
++}
++
+diff -u -r --new-file tools/source/generic/libart_lgpl/art_misc.h tools/source/generic/libart_lgpl/art_misc.h
+--- tools/source/generic/libart_lgpl/art_misc.h 1970-01-01 01:00:00.000000000 +0100
++++ tools/source/generic/libart_lgpl/art_misc.h 2004-04-06 17:43:49.000000000 +0100
+@@ -0,0 +1,96 @@
++/* Libart_LGPL - library of basic graphic primitives
++ * Copyright (C) 1998 Raph Levien
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the
++ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
++ * Boston, MA 02111-1307, USA.
++ */
++
++/* Simple macros to set up storage allocation and basic types for libart
++ functions. */
++
++#ifndef __ART_MISC_H__
++#define __ART_MISC_H__
++
++#include <stdlib.h> /* for malloc, etc. */
++
++/* The art_config.h file is automatically generated by
++ gen_art_config.c and contains definitions of
++ ART_SIZEOF_{CHAR,SHORT,INT,LONG} and art_u{8,16,32}. */
++#ifdef LIBART_COMPILATION
++#include "art_config.h"
++#else
++#include <libart_lgpl/art_config.h>
++#endif
++
++#define art_alloc malloc
++#define art_free free
++#define art_realloc realloc
++
++/* These aren't, strictly speaking, configuration macros, but they're
++ damn handy to have around, and may be worth playing with for
++ debugging. */
++#define art_new(type, n) ((type *)art_alloc ((n) * sizeof(type)))
++
++#define art_renew(p, type, n) ((type *)art_realloc (p, (n) * sizeof(type)))
++
++/* This one must be used carefully - in particular, p and max should
++ be variables. They can also be pstruct->el lvalues. */
++#define art_expand(p, type, max) do { if(max) { p = art_renew (p, type, max <<= 1); } else { max = 1; p = art_new(type, 1); } } while (0)
++
++typedef int art_boolean;
++#define ART_FALSE 0
++#define ART_TRUE 1
++
++/* define pi */
++#ifndef M_PI
++#define M_PI 3.14159265358979323846
++#endif /* M_PI */
++
++#ifndef M_SQRT2
++#define M_SQRT2 1.41421356237309504880 /* sqrt(2) */
++#endif /* M_SQRT2 */
++
++/* Provide macros to feature the GCC function attribute.
++ */
++#if defined(__GNUC__) && (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 4))
++#define ART_GNUC_PRINTF( format_idx, arg_idx ) \
++ __attribute__((format (printf, format_idx, arg_idx)))
++#define ART_GNUC_NORETURN \
++ __attribute__((noreturn))
++#else /* !__GNUC__ */
++#define ART_GNUC_PRINTF( format_idx, arg_idx )
++#define ART_GNUC_NORETURN
++#endif /* !__GNUC__ */
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++void ART_GNUC_NORETURN
++art_die (const char *fmt, ...) ART_GNUC_PRINTF (1, 2);
++
++void
++art_warn (const char *fmt, ...) ART_GNUC_PRINTF (1, 2);
++
++void
++art_dprint (const char *fmt, ...) ART_GNUC_PRINTF (1, 2);
++
++#ifdef __cplusplus
++}
++#endif
++
++#define ART_USE_NEW_INTERSECTOR
++
++#endif /* __ART_MISC_H__ */
+diff -u -r --new-file tools/source/generic/libart_lgpl/art_pathcode.h tools/source/generic/libart_lgpl/art_pathcode.h
+--- tools/source/generic/libart_lgpl/art_pathcode.h 1970-01-01 01:00:00.000000000 +0100
++++ tools/source/generic/libart_lgpl/art_pathcode.h 2004-04-06 17:43:56.000000000 +0100
+@@ -0,0 +1,39 @@
++/* Libart_LGPL - library of basic graphic primitives
++ * Copyright (C) 1998 Raph Levien
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the
++ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
++ * Boston, MA 02111-1307, USA.
++ */
++
++#ifndef __ART_PATHCODE_H__
++#define __ART_PATHCODE_H__
++
++#ifdef __cplusplus
++extern "C" {
++#endif /* __cplusplus */
++
++typedef enum {
++ ART_MOVETO,
++ ART_MOVETO_OPEN,
++ ART_CURVETO,
++ ART_LINETO,
++ ART_END
++} ArtPathcode;
++
++#ifdef __cplusplus
++}
++#endif /* __cplusplus */
++
++#endif /* __ART_PATHCODE_H__ */
+diff -u -r --new-file tools/source/generic/libart_lgpl/art_point.h tools/source/generic/libart_lgpl/art_point.h
+--- tools/source/generic/libart_lgpl/art_point.h 1970-01-01 01:00:00.000000000 +0100
++++ tools/source/generic/libart_lgpl/art_point.h 2004-04-06 17:44:02.000000000 +0100
+@@ -0,0 +1,38 @@
++/* Libart_LGPL - library of basic graphic primitives
++ * Copyright (C) 1998 Raph Levien
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the
++ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
++ * Boston, MA 02111-1307, USA.
++ */
++
++#ifndef __ART_POINT_H__
++#define __ART_POINT_H__
++
++#ifdef __cplusplus
++extern "C" {
++#endif /* __cplusplus */
++
++typedef struct _ArtPoint ArtPoint;
++
++struct _ArtPoint {
++ /*< public >*/
++ double x, y;
++};
++
++#ifdef __cplusplus
++}
++#endif /* __cplusplus */
++
++#endif /* __ART_POINT_H__ */
+diff -u -r --new-file tools/source/generic/libart_lgpl/art_rect.c tools/source/generic/libart_lgpl/art_rect.c
+--- tools/source/generic/libart_lgpl/art_rect.c 1970-01-01 01:00:00.000000000 +0100
++++ tools/source/generic/libart_lgpl/art_rect.c 2004-04-06 17:44:23.000000000 +0100
+@@ -0,0 +1,215 @@
++/* Libart_LGPL - library of basic graphic primitives
++ * Copyright (C) 1998 Raph Levien
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the
++ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
++ * Boston, MA 02111-1307, USA.
++ */
++
++#include "config.h"
++#include "art_rect.h"
++
++#include <math.h>
++
++#ifndef MAX
++#define MAX(a, b) (((a) > (b)) ? (a) : (b))
++#endif /* MAX */
++
++#ifndef MIN
++#define MIN(a, b) (((a) < (b)) ? (a) : (b))
++#endif /* MIN */
++
++/* rectangle primitives stolen from gzilla */
++
++/**
++ * art_irect_copy: Make a copy of an integer rectangle.
++ * @dest: Where the copy is stored.
++ * @src: The source rectangle.
++ *
++ * Copies the rectangle.
++ **/
++void
++art_irect_copy (ArtIRect *dest, const ArtIRect *src) {
++ dest->x0 = src->x0;
++ dest->y0 = src->y0;
++ dest->x1 = src->x1;
++ dest->y1 = src->y1;
++}
++
++/**
++ * art_irect_union: Find union of two integer rectangles.
++ * @dest: Where the result is stored.
++ * @src1: A source rectangle.
++ * @src2: Another source rectangle.
++ *
++ * Finds the smallest rectangle that includes @src1 and @src2.
++ **/
++void
++art_irect_union (ArtIRect *dest, const ArtIRect *src1, const ArtIRect *src2) {
++ if (art_irect_empty (src1)) {
++ art_irect_copy (dest, src2);
++ } else if (art_irect_empty (src2)) {
++ art_irect_copy (dest, src1);
++ } else {
++ dest->x0 = MIN (src1->x0, src2->x0);
++ dest->y0 = MIN (src1->y0, src2->y0);
++ dest->x1 = MAX (src1->x1, src2->x1);
++ dest->y1 = MAX (src1->y1, src2->y1);
++ }
++}
++
++/**
++ * art_irect_intersection: Find intersection of two integer rectangles.
++ * @dest: Where the result is stored.
++ * @src1: A source rectangle.
++ * @src2: Another source rectangle.
++ *
++ * Finds the intersection of @src1 and @src2.
++ **/
++void
++art_irect_intersect (ArtIRect *dest, const ArtIRect *src1, const ArtIRect *src2) {
++ dest->x0 = MAX (src1->x0, src2->x0);
++ dest->y0 = MAX (src1->y0, src2->y0);
++ dest->x1 = MIN (src1->x1, src2->x1);
++ dest->y1 = MIN (src1->y1, src2->y1);
++}
++
++/**
++ * art_irect_empty: Determine whether integer rectangle is empty.
++ * @src: The source rectangle.
++ *
++ * Return value: TRUE if @src is an empty rectangle, FALSE otherwise.
++ **/
++int
++art_irect_empty (const ArtIRect *src) {
++ return (src->x1 <= src->x0 || src->y1 <= src->y0);
++}
++
++#if 0
++gboolean irect_point_inside (ArtIRect *rect, GzwPoint *point) {
++ return (point->x >= rect->x0 && point->y >= rect->y0 &&
++ point->x < rect->x1 && point->y < rect->y1);
++}
++#endif
++
++/**
++ * art_drect_copy: Make a copy of a rectangle.
++ * @dest: Where the copy is stored.
++ * @src: The source rectangle.
++ *
++ * Copies the rectangle.
++ **/
++void
++art_drect_copy (ArtDRect *dest, const ArtDRect *src) {
++ dest->x0 = src->x0;
++ dest->y0 = src->y0;
++ dest->x1 = src->x1;
++ dest->y1 = src->y1;
++}
++
++/**
++ * art_drect_union: Find union of two rectangles.
++ * @dest: Where the result is stored.
++ * @src1: A source rectangle.
++ * @src2: Another source rectangle.
++ *
++ * Finds the smallest rectangle that includes @src1 and @src2.
++ **/
++void
++art_drect_union (ArtDRect *dest, const ArtDRect *src1, const ArtDRect *src2) {
++ if (art_drect_empty (src1)) {
++ art_drect_copy (dest, src2);
++ } else if (art_drect_empty (src2)) {
++ art_drect_copy (dest, src1);
++ } else {
++ dest->x0 = MIN (src1->x0, src2->x0);
++ dest->y0 = MIN (src1->y0, src2->y0);
++ dest->x1 = MAX (src1->x1, src2->x1);
++ dest->y1 = MAX (src1->y1, src2->y1);
++ }
++}
++
++/**
++ * art_drect_intersection: Find intersection of two rectangles.
++ * @dest: Where the result is stored.
++ * @src1: A source rectangle.
++ * @src2: Another source rectangle.
++ *
++ * Finds the intersection of @src1 and @src2.
++ **/
++void
++art_drect_intersect (ArtDRect *dest, const ArtDRect *src1, const ArtDRect *src2) {
++ dest->x0 = MAX (src1->x0, src2->x0);
++ dest->y0 = MAX (src1->y0, src2->y0);
++ dest->x1 = MIN (src1->x1, src2->x1);
++ dest->y1 = MIN (src1->y1, src2->y1);
++}
++
++/**
++ * art_irect_empty: Determine whether rectangle is empty.
++ * @src: The source rectangle.
++ *
++ * Return value: TRUE if @src is an empty rectangle, FALSE otherwise.
++ **/
++int
++art_drect_empty (const ArtDRect *src) {
++ return (src->x1 <= src->x0 || src->y1 <= src->y0);
++}
++
++/**
++ * art_drect_affine_transform: Affine transform rectangle.
++ * @dst: Where to store the result.
++ * @src: The source rectangle.
++ * @matrix: The affine transformation.
++ *
++ * Find the smallest rectangle enclosing the affine transformed @src.
++ * The result is exactly the affine transformation of @src when
++ * @matrix specifies a rectilinear affine transformation, otherwise it
++ * is a conservative approximation.
++ **/
++void
++art_drect_affine_transform (ArtDRect *dst, const ArtDRect *src, const double matrix[6])
++{
++ double x00, y00, x10, y10;
++ double x01, y01, x11, y11;
++
++ x00 = src->x0 * matrix[0] + src->y0 * matrix[2] + matrix[4];
++ y00 = src->x0 * matrix[1] + src->y0 * matrix[3] + matrix[5];
++ x10 = src->x1 * matrix[0] + src->y0 * matrix[2] + matrix[4];
++ y10 = src->x1 * matrix[1] + src->y0 * matrix[3] + matrix[5];
++ x01 = src->x0 * matrix[0] + src->y1 * matrix[2] + matrix[4];
++ y01 = src->x0 * matrix[1] + src->y1 * matrix[3] + matrix[5];
++ x11 = src->x1 * matrix[0] + src->y1 * matrix[2] + matrix[4];
++ y11 = src->x1 * matrix[1] + src->y1 * matrix[3] + matrix[5];
++ dst->x0 = MIN (MIN (x00, x10), MIN (x01, x11));
++ dst->y0 = MIN (MIN (y00, y10), MIN (y01, y11));
++ dst->x1 = MAX (MAX (x00, x10), MAX (x01, x11));
++ dst->y1 = MAX (MAX (y00, y10), MAX (y01, y11));
++}
++
++/**
++ * art_drect_to_irect: Convert rectangle to integer rectangle.
++ * @dst: Where to store resulting integer rectangle.
++ * @src: The source rectangle.
++ *
++ * Find the smallest integer rectangle that encloses @src.
++ **/
++void
++art_drect_to_irect (ArtIRect *dst, ArtDRect *src)
++{
++ dst->x0 = floor (src->x0);
++ dst->y0 = floor (src->y0);
++ dst->x1 = ceil (src->x1);
++ dst->y1 = ceil (src->y1);
++}
+diff -u -r --new-file tools/source/generic/libart_lgpl/art_rect.h tools/source/generic/libart_lgpl/art_rect.h
+--- tools/source/generic/libart_lgpl/art_rect.h 1970-01-01 01:00:00.000000000 +0100
++++ tools/source/generic/libart_lgpl/art_rect.h 2004-04-06 17:44:23.000000000 +0100
+@@ -0,0 +1,78 @@
++/* Libart_LGPL - library of basic graphic primitives
++ * Copyright (C) 1998 Raph Levien
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the
++ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
++ * Boston, MA 02111-1307, USA.
++ */
++
++#ifndef __ART_RECT_H__
++#define __ART_RECT_H__
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++typedef struct _ArtDRect ArtDRect;
++typedef struct _ArtIRect ArtIRect;
++
++struct _ArtDRect {
++ /*< public >*/
++ double x0, y0, x1, y1;
++};
++
++struct _ArtIRect {
++ /*< public >*/
++ int x0, y0, x1, y1;
++};
++
++/* Make a copy of the rectangle. */
++void art_irect_copy (ArtIRect *dest, const ArtIRect *src);
++
++/* Find the smallest rectangle that includes both source rectangles. */
++void art_irect_union (ArtIRect *dest,
++ const ArtIRect *src1, const ArtIRect *src2);
++
++/* Return the intersection of the two rectangles */
++void art_irect_intersect (ArtIRect *dest,
++ const ArtIRect *src1, const ArtIRect *src2);
++
++/* Return true if the rectangle is empty. */
++int art_irect_empty (const ArtIRect *src);
++
++/* Make a copy of the rectangle. */
++void art_drect_copy (ArtDRect *dest, const ArtDRect *src);
++
++/* Find the smallest rectangle that includes both source rectangles. */
++void art_drect_union (ArtDRect *dest,
++ const ArtDRect *src1, const ArtDRect *src2);
++
++/* Return the intersection of the two rectangles */
++void art_drect_intersect (ArtDRect *dest,
++ const ArtDRect *src1, const ArtDRect *src2);
++
++/* Return true if the rectangle is empty. */
++int art_drect_empty (const ArtDRect *src);
++
++void
++art_drect_affine_transform (ArtDRect *dst, const ArtDRect *src,
++ const double matrix[6]);
++
++void art_drect_to_irect (ArtIRect *dst, ArtDRect *src);
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif
+diff -u -r --new-file tools/source/generic/libart_lgpl/art_svp.c tools/source/generic/libart_lgpl/art_svp.c
+--- tools/source/generic/libart_lgpl/art_svp.c 1970-01-01 01:00:00.000000000 +0100
++++ tools/source/generic/libart_lgpl/art_svp.c 2004-04-06 17:44:29.000000000 +0100
+@@ -0,0 +1,152 @@
++/* Libart_LGPL - library of basic graphic primitives
++ * Copyright (C) 1998 Raph Levien
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the
++ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
++ * Boston, MA 02111-1307, USA.
++ */
++
++/* Basic constructors and operations for sorted vector paths */
++
++#include "config.h"
++#include "art_svp.h"
++
++#include "art_misc.h"
++
++/* Add a new segment. The arguments can be zero and NULL if the caller
++ would rather fill them in later.
++
++ We also realloc one auxiliary array of ints of size n_segs if
++ desired.
++*/
++/**
++ * art_svp_add_segment: Add a segment to an #ArtSVP structure.
++ * @p_vp: Pointer to where the #ArtSVP structure is stored.
++ * @pn_segs_max: Pointer to the allocated size of *@p_vp.
++ * @pn_points_max: Pointer to where auxiliary array is stored.
++ * @n_points: Number of points for new segment.
++ * @dir: Direction for new segment; 0 is up, 1 is down.
++ * @points: Points for new segment.
++ * @bbox: Bounding box for new segment.
++ *
++ * Adds a new segment to an ArtSVP structure. This routine reallocates
++ * the structure if necessary, updating *@p_vp and *@pn_segs_max as
++ * necessary.
++ *
++ * The new segment is simply added after all other segments. Thus,
++ * this routine should be called in order consistent with the #ArtSVP
++ * sorting rules.
++ *
++ * If the @bbox argument is given, it is simply stored in the new
++ * segment. Otherwise (if it is NULL), the bounding box is computed
++ * from the @points given.
++ **/
++int
++art_svp_add_segment (ArtSVP **p_vp, int *pn_segs_max,
++ int **pn_points_max,
++ int n_points, int dir, ArtPoint *points,
++ ArtDRect *bbox)
++{
++ int seg_num;
++ ArtSVP *svp;
++ ArtSVPSeg *seg;
++
++ svp = *p_vp;
++ seg_num = svp->n_segs++;
++ if (*pn_segs_max == seg_num)
++ {
++ *pn_segs_max <<= 1;
++ svp = (ArtSVP *)art_realloc (svp, sizeof(ArtSVP) +
++ (*pn_segs_max - 1) * sizeof(ArtSVPSeg));
++ *p_vp = svp;
++ if (pn_points_max != NULL)
++ *pn_points_max = art_renew (*pn_points_max, int, *pn_segs_max);
++ }
++ seg = &svp->segs[seg_num];
++ seg->n_points = n_points;
++ seg->dir = dir;
++ seg->points = points;
++ if (bbox)
++ seg->bbox = *bbox;
++ else if (points)
++ {
++ double x_min, x_max;
++ int i;
++
++ x_min = x_max = points[0].x;
++ for (i = 1; i < n_points; i++)
++ {
++ if (x_min > points[i].x)
++ x_min = points[i].x;
++ if (x_max < points[i].x)
++ x_max = points[i].x;
++ }
++ seg->bbox.x0 = x_min;
++ seg->bbox.y0 = points[0].y;
++
++ seg->bbox.x1 = x_max;
++ seg->bbox.y1 = points[n_points - 1].y;
++ }
++ return seg_num;
++}
++
++
++/**
++ * art_svp_free: Free an #ArtSVP structure.
++ * @svp: #ArtSVP to free.
++ *
++ * Frees an #ArtSVP structure and all the segments in it.
++ **/
++void
++art_svp_free (ArtSVP *svp)
++{
++ int n_segs = svp->n_segs;
++ int i;
++
++ for (i = 0; i < n_segs; i++)
++ art_free (svp->segs[i].points);
++ art_free (svp);
++}
++
++#ifdef ART_USE_NEW_INTERSECTOR
++#define EPSILON 0
++#else
++#define EPSILON 1e-6
++#endif
++
++/**
++ * art_svp_seg_compare: Compare two segments of an svp.
++ * @seg1: First segment to compare.
++ * @seg2: Second segment to compare.
++ *
++ * Compares two segments of an svp. Return 1 if @seg2 is below or to the
++ * right of @seg1, -1 otherwise.
++ **/
++int
++art_svp_seg_compare (const void *s1, const void *s2)
++{
++ const ArtSVPSeg *seg1 = s1;
++ const ArtSVPSeg *seg2 = s2;
++
++ if (seg1->points[0].y - EPSILON > seg2->points[0].y) return 1;
++ else if (seg1->points[0].y + EPSILON < seg2->points[0].y) return -1;
++ else if (seg1->points[0].x - EPSILON > seg2->points[0].x) return 1;
++ else if (seg1->points[0].x + EPSILON < seg2->points[0].x) return -1;
++ else if ((seg1->points[1].x - seg1->points[0].x) *
++ (seg2->points[1].y - seg2->points[0].y) -
++ (seg1->points[1].y - seg1->points[0].y) *
++ (seg2->points[1].x - seg2->points[0].x) > 0) return 1;
++ else return -1;
++}
++
+diff -u -r --new-file tools/source/generic/libart_lgpl/art_svp.h tools/source/generic/libart_lgpl/art_svp.h
+--- tools/source/generic/libart_lgpl/art_svp.h 1970-01-01 01:00:00.000000000 +0100
++++ tools/source/generic/libart_lgpl/art_svp.h 2004-04-06 17:44:29.000000000 +0100
+@@ -0,0 +1,68 @@
++/* Libart_LGPL - library of basic graphic primitives
++ * Copyright (C) 1998 Raph Levien
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the
++ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
++ * Boston, MA 02111-1307, USA.
++ */
++
++#ifndef __ART_SVP_H__
++#define __ART_SVP_H__
++
++/* Basic data structures and constructors for sorted vector paths */
++
++#ifdef LIBART_COMPILATION
++#include "art_rect.h"
++#include "art_point.h"
++#else
++#include <libart_lgpl/art_rect.h>
++#include <libart_lgpl/art_point.h>
++#endif
++
++#ifdef __cplusplus
++extern "C" {
++#endif /* __cplusplus */
++
++typedef struct _ArtSVP ArtSVP;
++typedef struct _ArtSVPSeg ArtSVPSeg;
++
++struct _ArtSVPSeg {
++ int n_points;
++ int dir; /* == 0 for "up", 1 for "down" */
++ ArtDRect bbox;
++ ArtPoint *points;
++};
++
++struct _ArtSVP {
++ int n_segs;
++ ArtSVPSeg segs[1];
++};
++
++int
++art_svp_add_segment (ArtSVP **p_vp, int *pn_segs_max,
++ int **pn_points_max,
++ int n_points, int dir, ArtPoint *points,
++ ArtDRect *bbox);
++
++void
++art_svp_free (ArtSVP *svp);
++
++int
++art_svp_seg_compare (const void *s1, const void *s2);
++
++#ifdef __cplusplus
++}
++#endif /* __cplusplus */
++
++#endif /* __ART_SVP_H__ */
+diff -u -r --new-file tools/source/generic/libart_lgpl/art_svp_intersect.c tools/source/generic/libart_lgpl/art_svp_intersect.c
+--- tools/source/generic/libart_lgpl/art_svp_intersect.c 1970-01-01 01:00:00.000000000 +0100
++++ tools/source/generic/libart_lgpl/art_svp_intersect.c 2004-04-06 17:44:51.000000000 +0100
+@@ -0,0 +1,1803 @@
++/* Libart_LGPL - library of basic graphic primitives
++ * Copyright (C) 2001 Raph Levien
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the
++ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
++ * Boston, MA 02111-1307, USA.
++ */
++
++/* This file contains a testbed implementation of the new intersection
++ code.
++*/
++
++#include "config.h"
++#include "art_svp_intersect.h"
++
++#include <math.h> /* for sqrt */
++
++/* Sanitychecking verifies the main invariant on every priority queue
++ point. Do not use in production, as it slows things down way too
++ much. */
++#define noSANITYCHECK
++
++/* This can be used in production, to prevent hangs. Eventually, it
++ should not be necessary. */
++#define CHEAP_SANITYCHECK
++
++#define noVERBOSE
++
++#include "art_misc.h"
++
++/* A priority queue - perhaps move to a separate file if it becomes
++ needed somewhere else */
++
++#define ART_PRIQ_USE_HEAP
++
++typedef struct _ArtPriQ ArtPriQ;
++typedef struct _ArtPriPoint ArtPriPoint;
++
++struct _ArtPriQ {
++ int n_items;
++ int n_items_max;
++ ArtPriPoint **items;
++};
++
++struct _ArtPriPoint {
++ double x;
++ double y;
++ void *user_data;
++};
++
++static ArtPriQ *
++art_pri_new (void)
++{
++ ArtPriQ *result = art_new (ArtPriQ, 1);
++
++ result->n_items = 0;
++ result->n_items_max = 16;
++ result->items = art_new (ArtPriPoint *, result->n_items_max);
++ return result;
++}
++
++static void
++art_pri_free (ArtPriQ *pq)
++{
++ art_free (pq->items);
++ art_free (pq);
++}
++
++static art_boolean
++art_pri_empty (ArtPriQ *pq)
++{
++ return pq->n_items == 0;
++}
++
++#ifdef ART_PRIQ_USE_HEAP
++
++/* This heap implementation is based on Vasek Chvatal's course notes:
++ http://www.cs.rutgers.edu/~chvatal/notes/pq.html#heap */
++
++static void
++art_pri_bubble_up (ArtPriQ *pq, int vacant, ArtPriPoint *missing)
++{
++ ArtPriPoint **items = pq->items;
++ int parent;
++
++ parent = (vacant - 1) >> 1;
++ while (vacant > 0 && (missing->y < items[parent]->y ||
++ (missing->y == items[parent]->y &&
++ missing->x < items[parent]->x)))
++ {
++ items[vacant] = items[parent];
++ vacant = parent;
++ parent = (vacant - 1) >> 1;
++ }
++
++ items[vacant] = missing;
++}
++
++static void
++art_pri_insert (ArtPriQ *pq, ArtPriPoint *point)
++{
++ if (pq->n_items == pq->n_items_max)
++ art_expand (pq->items, ArtPriPoint *, pq->n_items_max);
++
++ art_pri_bubble_up (pq, pq->n_items++, point);
++}
++
++static void
++art_pri_sift_down_from_root (ArtPriQ *pq, ArtPriPoint *missing)
++{
++ ArtPriPoint **items = pq->items;
++ int vacant = 0, child = 2;
++ int n = pq->n_items;
++
++ while (child < n)
++ {
++ if (items[child - 1]->y < items[child]->y ||
++ (items[child - 1]->y == items[child]->y &&
++ items[child - 1]->x < items[child]->x))
++ child--;
++ items[vacant] = items[child];
++ vacant = child;
++ child = (vacant + 1) << 1;
++ }
++ if (child == n)
++ {
++ items[vacant] = items[n - 1];
++ vacant = n - 1;
++ }
++
++ art_pri_bubble_up (pq, vacant, missing);
++}
++
++static ArtPriPoint *
++art_pri_choose (ArtPriQ *pq)
++{
++ ArtPriPoint *result = pq->items[0];
++
++ art_pri_sift_down_from_root (pq, pq->items[--pq->n_items]);
++ return result;
++}
++
++#else
++
++/* Choose least point in queue */
++static ArtPriPoint *
++art_pri_choose (ArtPriQ *pq)
++{
++ int i;
++ int best = 0;
++ double best_x, best_y;
++ double y;
++ ArtPriPoint *result;
++
++ if (pq->n_items == 0)
++ return NULL;
++
++ best_x = pq->items[best]->x;
++ best_y = pq->items[best]->y;
++
++ for (i = 1; i < pq->n_items; i++)
++ {
++ y = pq->items[i]->y;
++ if (y < best_y || (y == best_y && pq->items[i]->x < best_x))
++ {
++ best = i;
++ best_x = pq->items[best]->x;
++ best_y = y;
++ }
++ }
++ result = pq->items[best];
++ pq->items[best] = pq->items[--pq->n_items];
++ return result;
++}
++
++static void
++art_pri_insert (ArtPriQ *pq, ArtPriPoint *point)
++{
++ if (pq->n_items == pq->n_items_max)
++ art_expand (pq->items, ArtPriPoint *, pq->n_items_max);
++
++ pq->items[pq->n_items++] = point;
++}
++
++#endif
++
++#ifdef TEST_PRIQ
++
++#include <stdlib.h> /* for rand() */
++#include <stdio.h>
++
++static double
++double_rand (double lo, double hi, int quant)
++{
++ int tmp = rand () / (RAND_MAX * (1.0 / quant)) + 0.5;
++ return lo + tmp * ((hi - lo) / quant);
++}
++
++/*
++ * This custom allocator for priority queue points is here so I can
++ * test speed. It doesn't look like it will be that significant, but
++ * if I want a small improvement later, it's something.
++ */
++
++typedef ArtPriPoint *ArtPriPtPool;
++
++static ArtPriPtPool *
++art_pri_pt_pool_new (void)
++{
++ ArtPriPtPool *result = art_new (ArtPriPtPool, 1);
++ *result = NULL;
++ return result;
++}
++
++static ArtPriPoint *
++art_pri_pt_alloc (ArtPriPtPool *pool)
++{
++ ArtPriPoint *result = *pool;
++ if (result == NULL)
++ return art_new (ArtPriPoint, 1);
++ else
++ {
++ *pool = result->user_data;
++ return result;
++ }
++}
++
++static void
++art_pri_pt_free (ArtPriPtPool *pool, ArtPriPoint *pt)
++{
++ pt->user_data = *pool;
++ *pool = pt;
++}
++
++static void
++art_pri_pt_pool_free (ArtPriPtPool *pool)
++{
++ ArtPriPoint *pt = *pool;
++ while (pt != NULL)
++ {
++ ArtPriPoint *next = pt->user_data;
++ art_free (pt);
++ pt = next;
++ }
++ art_free (pool);
++}
++
++int
++main (int argc, char **argv)
++{
++ ArtPriPtPool *pool = art_pri_pt_pool_new ();
++ ArtPriQ *pq;
++ int i, j;
++ const int n_iter = 1;
++ const int pq_size = 100;
++
++ for (j = 0; j < n_iter; j++)
++ {
++ pq = art_pri_new ();
++
++ for (i = 0; i < pq_size; i++)
++ {
++ ArtPriPoint *pt = art_pri_pt_alloc (pool);
++ pt->x = double_rand (0, 1, 100);
++ pt->y = double_rand (0, 1, 100);
++ pt->user_data = (void *)i;
++ art_pri_insert (pq, pt);
++ }
++
++ while (!art_pri_empty (pq))
++ {
++ ArtPriPoint *pt = art_pri_choose (pq);
++ if (n_iter == 1)
++ printf ("(%g, %g), %d\n", pt->x, pt->y, (int)pt->user_data);
++ art_pri_pt_free (pool, pt);
++ }
++
++ art_pri_free (pq);
++ }
++ art_pri_pt_pool_free (pool);
++ return 0;
++}
++
++#else /* TEST_PRIQ */
++
++/* A virtual class for an "svp writer". A client of this object creates an
++ SVP by repeatedly calling "add segment" and "add point" methods on it.
++*/
++
++typedef struct _ArtSvpWriterRewind ArtSvpWriterRewind;
++
++/* An implementation of the svp writer virtual class that applies the
++ winding rule. */
++
++struct _ArtSvpWriterRewind {
++ ArtSvpWriter super;
++ ArtWindRule rule;
++ ArtSVP *svp;
++ int n_segs_max;
++ int *n_points_max;
++};
++
++static int
++art_svp_writer_rewind_add_segment (ArtSvpWriter *self, int wind_left,
++ int delta_wind, double x, double y)
++{
++ ArtSvpWriterRewind *swr = (ArtSvpWriterRewind *)self;
++ ArtSVP *svp;
++ ArtSVPSeg *seg;
++ art_boolean left_filled, right_filled;
++ int wind_right = wind_left + delta_wind;
++ int seg_num;
++ const int init_n_points_max = 4;
++
++ switch (swr->rule)
++ {
++ case ART_WIND_RULE_NONZERO:
++ left_filled = (wind_left != 0);
++ right_filled = (wind_right != 0);
++ break;
++ case ART_WIND_RULE_INTERSECT:
++ left_filled = (wind_left > 1);
++ right_filled = (wind_right > 1);
++ break;
++ case ART_WIND_RULE_ODDEVEN:
++ left_filled = (wind_left & 1);
++ right_filled = (wind_right & 1);
++ break;
++ case ART_WIND_RULE_POSITIVE:
++ left_filled = (wind_left > 0);
++ right_filled = (wind_right > 0);
++ break;
++ default:
++ art_die ("Unknown wind rule %d\n", swr->rule);
++ }
++ if (left_filled == right_filled)
++ {
++ /* discard segment now */
++#ifdef VERBOSE
++ art_dprint ("swr add_segment: %d += %d (%g, %g) --> -1\n",
++ wind_left, delta_wind, x, y);
++#endif
++ return -1;
++ }
++
++ svp = swr->svp;
++ seg_num = svp->n_segs++;
++ if (swr->n_segs_max == seg_num)
++ {
++ swr->n_segs_max <<= 1;
++ svp = (ArtSVP *)art_realloc (svp, sizeof(ArtSVP) +
++ (swr->n_segs_max - 1) *
++ sizeof(ArtSVPSeg));
++ swr->svp = svp;
++ swr->n_points_max = art_renew (swr->n_points_max, int,
++ swr->n_segs_max);
++ }
++ seg = &svp->segs[seg_num];
++ seg->n_points = 1;
++ seg->dir = right_filled;
++ swr->n_points_max[seg_num] = init_n_points_max;
++ seg->bbox.x0 = x;
++ seg->bbox.y0 = y;
++ seg->bbox.x1 = x;
++ seg->bbox.y1 = y;
++ seg->points = art_new (ArtPoint, init_n_points_max);
++ seg->points[0].x = x;
++ seg->points[0].y = y;
++#ifdef VERBOSE
++ art_dprint ("swr add_segment: %d += %d (%g, %g) --> %d(%s)\n",
++ wind_left, delta_wind, x, y, seg_num,
++ seg->dir ? "v" : "^");
++#endif
++ return seg_num;
++}
++
++static void
++art_svp_writer_rewind_add_point (ArtSvpWriter *self, int seg_id,
++ double x, double y)
++{
++ ArtSvpWriterRewind *swr = (ArtSvpWriterRewind *)self;
++ ArtSVPSeg *seg;
++ int n_points;
++
++#ifdef VERBOSE
++ art_dprint ("swr add_point: %d (%g, %g)\n", seg_id, x, y);
++#endif
++ if (seg_id < 0)
++ /* omitted segment */
++ return;
++
++ seg = &swr->svp->segs[seg_id];
++ n_points = seg->n_points++;
++ if (swr->n_points_max[seg_id] == n_points)
++ art_expand (seg->points, ArtPoint, swr->n_points_max[seg_id]);
++ seg->points[n_points].x = x;
++ seg->points[n_points].y = y;
++ if (x < seg->bbox.x0)
++ seg->bbox.x0 = x;
++ if (x > seg->bbox.x1)
++ seg->bbox.x1 = x;
++ seg->bbox.y1 = y;
++}
++
++static void
++art_svp_writer_rewind_close_segment (ArtSvpWriter *self, int seg_id)
++{
++ /* Not needed for this simple implementation. A potential future
++ optimization is to merge segments that can be merged safely. */
++#ifdef SANITYCHECK
++ ArtSvpWriterRewind *swr = (ArtSvpWriterRewind *)self;
++ ArtSVPSeg *seg;
++
++ if (seg_id >= 0)
++ {
++ seg = &swr->svp->segs[seg_id];
++ if (seg->n_points < 2)
++ art_warn ("*** closing segment %d with only %d point%s\n",
++ seg_id, seg->n_points, seg->n_points == 1 ? "" : "s");
++ }
++#endif
++
++#ifdef VERBOSE
++ art_dprint ("swr close_segment: %d\n", seg_id);
++#endif
++}
++
++ArtSVP *
++art_svp_writer_rewind_reap (ArtSvpWriter *self)
++{
++ ArtSvpWriterRewind *swr = (ArtSvpWriterRewind *)self;
++ ArtSVP *result = swr->svp;
++
++ art_free (swr->n_points_max);
++ art_free (swr);
++ return result;
++}
++
++ArtSvpWriter *
++art_svp_writer_rewind_new (ArtWindRule rule)
++{
++ ArtSvpWriterRewind *result = art_new (ArtSvpWriterRewind, 1);
++
++ result->super.add_segment = art_svp_writer_rewind_add_segment;
++ result->super.add_point = art_svp_writer_rewind_add_point;
++ result->super.close_segment = art_svp_writer_rewind_close_segment;
++
++ result->rule = rule;
++ result->n_segs_max = 16;
++ result->svp = art_alloc (sizeof(ArtSVP) +
++ (result->n_segs_max - 1) * sizeof(ArtSVPSeg));
++ result->svp->n_segs = 0;
++ result->n_points_max = art_new (int, result->n_segs_max);
++
++ return &result->super;
++}
++
++/* Now, data structures for the active list */
++
++typedef struct _ArtActiveSeg ArtActiveSeg;
++
++/* Note: BNEG is 1 for \ lines, and 0 for /. Thus,
++ x[(flags & BNEG) ^ 1] <= x[flags & BNEG] */
++#define ART_ACTIVE_FLAGS_BNEG 1
++
++/* This flag is set if the segment has been inserted into the active
++ list. */
++#define ART_ACTIVE_FLAGS_IN_ACTIVE 2
++
++/* This flag is set when the segment is to be deleted in the
++ horiz commit process. */
++#define ART_ACTIVE_FLAGS_DEL 4
++
++/* This flag is set if the seg_id is a valid output segment. */
++#define ART_ACTIVE_FLAGS_OUT 8
++
++/* This flag is set if the segment is in the horiz list. */
++#define ART_ACTIVE_FLAGS_IN_HORIZ 16
++
++struct _ArtActiveSeg {
++ int flags;
++ int wind_left, delta_wind;
++ ArtActiveSeg *left, *right; /* doubly linked list structure */
++
++ const ArtSVPSeg *in_seg;
++ int in_curs;
++
++ double x[2];
++ double y0, y1;
++ double a, b, c; /* line equation; ax+by+c = 0 for the line, a^2 + b^2 = 1,
++ and a>0 */
++
++ /* bottom point and intersection point stack */
++ int n_stack;
++ int n_stack_max;
++ ArtPoint *stack;
++
++ /* horiz commit list */
++ ArtActiveSeg *horiz_left, *horiz_right;
++ double horiz_x;
++ int horiz_delta_wind;
++ int seg_id;
++};
++
++typedef struct _ArtIntersectCtx ArtIntersectCtx;
++
++struct _ArtIntersectCtx {
++ const ArtSVP *in;
++ ArtSvpWriter *out;
++
++ ArtPriQ *pq;
++
++ ArtActiveSeg *active_head;
++
++ double y;
++ ArtActiveSeg *horiz_first;
++ ArtActiveSeg *horiz_last;
++
++ /* segment index of next input segment to be added to pri q */
++ int in_curs;
++};
++
++#define EPSILON_A 1e-5 /* Threshold for breaking lines at point insertions */
++
++/**
++ * art_svp_intersect_setup_seg: Set up an active segment from input segment.
++ * @seg: Active segment.
++ * @pri_pt: Priority queue point to initialize.
++ *
++ * Sets the x[], a, b, c, flags, and stack fields according to the
++ * line from the current cursor value. Sets the priority queue point
++ * to the bottom point of this line. Also advances the input segment
++ * cursor.
++ **/
++static void
++art_svp_intersect_setup_seg (ArtActiveSeg *seg, ArtPriPoint *pri_pt)
++{
++ const ArtSVPSeg *in_seg = seg->in_seg;
++ int in_curs = seg->in_curs++;
++ double x0, y0, x1, y1;
++ double dx, dy, s;
++ double a, b, r2;
++
++ x0 = in_seg->points[in_curs].x;
++ y0 = in_seg->points[in_curs].y;
++ x1 = in_seg->points[in_curs + 1].x;
++ y1 = in_seg->points[in_curs + 1].y;
++ pri_pt->x = x1;
++ pri_pt->y = y1;
++ dx = x1 - x0;
++ dy = y1 - y0;
++ r2 = dx * dx + dy * dy;
++ s = r2 == 0 ? 1 : 1 / sqrt (r2);
++ seg->a = a = dy * s;
++ seg->b = b = -dx * s;
++ seg->c = -(a * x0 + b * y0);
++ seg->flags = (seg->flags & ~ART_ACTIVE_FLAGS_BNEG) | (dx > 0);
++ seg->x[0] = x0;
++ seg->x[1] = x1;
++ seg->y0 = y0;
++ seg->y1 = y1;
++ seg->n_stack = 1;
++ seg->stack[0].x = x1;
++ seg->stack[0].y = y1;
++}
++
++/**
++ * art_svp_intersect_add_horiz: Add point to horizontal list.
++ * @ctx: Intersector context.
++ * @seg: Segment with point to insert into horizontal list.
++ *
++ * Inserts @seg into horizontal list, keeping it in ascending horiz_x
++ * order.
++ *
++ * Note: the horiz_commit routine processes "clusters" of segs in the
++ * horiz list, all sharing the same horiz_x value. The cluster is
++ * processed in active list order, rather than horiz list order. Thus,
++ * the order of segs in the horiz list sharing the same horiz_x
++ * _should_ be irrelevant. Even so, we use b as a secondary sorting key,
++ * as a "belt and suspenders" defensive coding tactic.
++ **/
++static void
++art_svp_intersect_add_horiz (ArtIntersectCtx *ctx, ArtActiveSeg *seg)
++{
++ ArtActiveSeg **pp = &ctx->horiz_last;
++ ArtActiveSeg *place;
++ ArtActiveSeg *place_right = NULL;
++
++
++#ifdef CHEAP_SANITYCHECK
++ if (seg->flags & ART_ACTIVE_FLAGS_IN_HORIZ)
++ {
++ art_warn ("*** attempt to put segment in horiz list twice\n");
++ return;
++ }
++ seg->flags |= ART_ACTIVE_FLAGS_IN_HORIZ;
++#endif
++
++#ifdef VERBOSE
++ art_dprint ("add_horiz %lx, x = %g\n", (unsigned long) seg, seg->horiz_x);
++#endif
++ for (place = *pp; place != NULL && (place->horiz_x > seg->horiz_x ||
++ (place->horiz_x == seg->horiz_x &&
++ place->b < seg->b));
++ place = *pp)
++ {
++ place_right = place;
++ pp = &place->horiz_left;
++ }
++ *pp = seg;
++ seg->horiz_left = place;
++ seg->horiz_right = place_right;
++ if (place == NULL)
++ ctx->horiz_first = seg;
++ else
++ place->horiz_right = seg;
++}
++
++static void
++art_svp_intersect_push_pt (ArtIntersectCtx *ctx, ArtActiveSeg *seg,
++ double x, double y)
++{
++ ArtPriPoint *pri_pt;
++ int n_stack = seg->n_stack;
++
++ if (n_stack == seg->n_stack_max)
++ art_expand (seg->stack, ArtPoint, seg->n_stack_max);
++ seg->stack[n_stack].x = x;
++ seg->stack[n_stack].y = y;
++ seg->n_stack++;
++
++ seg->x[1] = x;
++ seg->y1 = y;
++
++ pri_pt = art_new (ArtPriPoint, 1);
++ pri_pt->x = x;
++ pri_pt->y = y;
++ pri_pt->user_data = seg;
++ art_pri_insert (ctx->pq, pri_pt);
++}
++
++typedef enum {
++ ART_BREAK_LEFT = 1,
++ ART_BREAK_RIGHT = 2
++} ArtBreakFlags;
++
++/**
++ * art_svp_intersect_break: Break an active segment.
++ *
++ * Note: y must be greater than the top point's y, and less than
++ * the bottom's.
++ *
++ * Return value: x coordinate of break point.
++ */
++static double
++art_svp_intersect_break (ArtIntersectCtx *ctx, ArtActiveSeg *seg,
++ double x_ref, double y, ArtBreakFlags break_flags)
++{
++ double x0, y0, x1, y1;
++ const ArtSVPSeg *in_seg = seg->in_seg;
++ int in_curs = seg->in_curs;
++ double x;
++
++ x0 = in_seg->points[in_curs - 1].x;
++ y0 = in_seg->points[in_curs - 1].y;
++ x1 = in_seg->points[in_curs].x;
++ y1 = in_seg->points[in_curs].y;
++ x = x0 + (x1 - x0) * ((y - y0) / (y1 - y0));
++ if ((break_flags == ART_BREAK_LEFT && x > x_ref) ||
++ (break_flags == ART_BREAK_RIGHT && x < x_ref))
++ {
++#ifdef VERBOSE
++ art_dprint ("art_svp_intersect_break: limiting x to %f, was %f, %s\n",
++ x_ref, x, break_flags == ART_BREAK_LEFT ? "left" : "right");
++ x = x_ref;
++#endif
++ }
++
++ /* I think we can count on min(x0, x1) <= x <= max(x0, x1) with sane
++ arithmetic, but it might be worthwhile to check just in case. */
++
++ if (y > ctx->y)
++ art_svp_intersect_push_pt (ctx, seg, x, y);
++ else
++ {
++ seg->x[0] = x;
++ seg->y0 = y;
++ seg->horiz_x = x;
++ art_svp_intersect_add_horiz (ctx, seg);
++ }
++
++ return x;
++}
++
++/**
++ * art_svp_intersect_add_point: Add a point, breaking nearby neighbors.
++ * @ctx: Intersector context.
++ * @x: X coordinate of point to add.
++ * @y: Y coordinate of point to add.
++ * @seg: "nearby" segment, or NULL if leftmost.
++ *
++ * Return value: Segment immediately to the left of the new point, or
++ * NULL if the new point is leftmost.
++ **/
++static ArtActiveSeg *
++art_svp_intersect_add_point (ArtIntersectCtx *ctx, double x, double y,
++ ArtActiveSeg *seg, ArtBreakFlags break_flags)
++{
++ ArtActiveSeg *left, *right;
++ double x_min = x, x_max = x;
++ art_boolean left_live, right_live;
++ double d;
++ double new_x;
++ ArtActiveSeg *test, *result = NULL;
++ double x_test;
++
++ left = seg;
++ if (left == NULL)
++ right = ctx->active_head;
++ else
++ right = left->right;
++ left_live = (break_flags & ART_BREAK_LEFT) && (left != NULL);
++ right_live = (break_flags & ART_BREAK_RIGHT) && (right != NULL);
++ while (left_live || right_live)
++ {
++ if (left_live)
++ {
++ if (x <= left->x[left->flags & ART_ACTIVE_FLAGS_BNEG] &&
++ /* It may be that one of these conjuncts turns out to be always
++ true. We test both anyway, to be defensive. */
++ y != left->y0 && y < left->y1)
++ {
++ d = x_min * left->a + y * left->b + left->c;
++ if (d < EPSILON_A)
++ {
++ new_x = art_svp_intersect_break (ctx, left, x_min, y,
++ ART_BREAK_LEFT);
++ if (new_x > x_max)
++ {
++ x_max = new_x;
++ right_live = (right != NULL);
++ }
++ else if (new_x < x_min)
++ x_min = new_x;
++ left = left->left;
++ left_live = (left != NULL);
++ }
++ else
++ left_live = ART_FALSE;
++ }
++ else
++ left_live = ART_FALSE;
++ }
++ else if (right_live)
++ {
++ if (x >= right->x[(right->flags & ART_ACTIVE_FLAGS_BNEG) ^ 1] &&
++ /* It may be that one of these conjuncts turns out to be always
++ true. We test both anyway, to be defensive. */
++ y != right->y0 && y < right->y1)
++ {
++ d = x_max * right->a + y * right->b + right->c;
++ if (d > -EPSILON_A)
++ {
++ new_x = art_svp_intersect_break (ctx, right, x_max, y,
++ ART_BREAK_RIGHT);
++ if (new_x < x_min)
++ {
++ x_min = new_x;
++ left_live = (left != NULL);
++ }
++ else if (new_x >= x_max)
++ x_max = new_x;
++ right = right->right;
++ right_live = (right != NULL);
++ }
++ else
++ right_live = ART_FALSE;
++ }
++ else
++ right_live = ART_FALSE;
++ }
++ }
++
++ /* Ascending order is guaranteed by break_flags. Thus, we don't need
++ to actually fix up non-ascending pairs. */
++
++ /* Now, (left, right) defines an interval of segments broken. Sort
++ into ascending x order. */
++ test = left == NULL ? ctx->active_head : left->right;
++ result = left;
++ if (test != NULL && test != right)
++ {
++ if (y == test->y0)
++ x_test = test->x[0];
++ else /* assert y == test->y1, I think */
++ x_test = test->x[1];
++ for (;;)
++ {
++ if (x_test <= x)
++ result = test;
++ test = test->right;
++ if (test == right)
++ break;
++ new_x = x_test;
++ if (new_x < x_test)
++ {
++ art_warn ("art_svp_intersect_add_point: non-ascending x\n");
++ }
++ x_test = new_x;
++ }
++ }
++ return result;
++}
++
++static void
++art_svp_intersect_swap_active (ArtIntersectCtx *ctx,
++ ArtActiveSeg *left_seg, ArtActiveSeg *right_seg)
++{
++ right_seg->left = left_seg->left;
++ if (right_seg->left != NULL)
++ right_seg->left->right = right_seg;
++ else
++ ctx->active_head = right_seg;
++ left_seg->right = right_seg->right;
++ if (left_seg->right != NULL)
++ left_seg->right->left = left_seg;
++ left_seg->left = right_seg;
++ right_seg->right = left_seg;
++}
++
++/**
++ * art_svp_intersect_test_cross: Test crossing of a pair of active segments.
++ * @ctx: Intersector context.
++ * @left_seg: Left segment of the pair.
++ * @right_seg: Right segment of the pair.
++ * @break_flags: Flags indicating whether to break neighbors.
++ *
++ * Tests crossing of @left_seg and @right_seg. If there is a crossing,
++ * inserts the intersection point into both segments.
++ *
++ * Return value: True if the intersection took place at the current
++ * scan line, indicating further iteration is needed.
++ **/
++static art_boolean
++art_svp_intersect_test_cross (ArtIntersectCtx *ctx,
++ ArtActiveSeg *left_seg, ArtActiveSeg *right_seg,
++ ArtBreakFlags break_flags)
++{
++ double left_x0, left_y0, left_x1;
++ double left_y1 = left_seg->y1;
++ double right_y1 = right_seg->y1;
++ double d;
++
++ const ArtSVPSeg *in_seg;
++ int in_curs;
++ double d0, d1, t;
++ double x, y; /* intersection point */
++
++#ifdef VERBOSE
++ static int count = 0;
++
++ art_dprint ("art_svp_intersect_test_cross %lx <-> %lx: count=%d\n",
++ (unsigned long)left_seg, (unsigned long)right_seg, count++);
++#endif
++
++ if (left_seg->y0 == right_seg->y0 && left_seg->x[0] == right_seg->x[0])
++ {
++ /* Top points of left and right segments coincide. This case
++ feels like a bit of duplication - we may want to merge it
++ with the cases below. However, this way, we're sure that this
++ logic makes only localized changes. */
++
++ if (left_y1 < right_y1)
++ {
++ /* Test left (x1, y1) against right segment */
++ double left_x1 = left_seg->x[1];
++
++ if (left_x1 <
++ right_seg->x[(right_seg->flags & ART_ACTIVE_FLAGS_BNEG) ^ 1] ||
++ left_y1 == right_seg->y0)
++ return ART_FALSE;
++ d = left_x1 * right_seg->a + left_y1 * right_seg->b + right_seg->c;
++ if (d < -EPSILON_A)
++ return ART_FALSE;
++ else if (d < EPSILON_A)
++ {
++ /* I'm unsure about the break flags here. */
++ double right_x1 = art_svp_intersect_break (ctx, right_seg,
++ left_x1, left_y1,
++ ART_BREAK_RIGHT);
++ if (left_x1 <= right_x1)
++ return ART_FALSE;
++ }
++ }
++ else if (left_y1 > right_y1)
++ {
++ /* Test right (x1, y1) against left segment */
++ double right_x1 = right_seg->x[1];
++
++ if (right_x1 > left_seg->x[left_seg->flags & ART_ACTIVE_FLAGS_BNEG] ||
++ right_y1 == left_seg->y0)
++ return ART_FALSE;
++ d = right_x1 * left_seg->a + right_y1 * left_seg->b + left_seg->c;
++ if (d > EPSILON_A)
++ return ART_FALSE;
++ else if (d > -EPSILON_A)
++ {
++ /* See above regarding break flags. */
++ double left_x1 = art_svp_intersect_break (ctx, left_seg,
++ right_x1, right_y1,
++ ART_BREAK_LEFT);
++ if (left_x1 <= right_x1)
++ return ART_FALSE;
++ }
++ }
++ else /* left_y1 == right_y1 */
++ {
++ double left_x1 = left_seg->x[1];
++ double right_x1 = right_seg->x[1];
++
++ if (left_x1 <= right_x1)
++ return ART_FALSE;
++ }
++ art_svp_intersect_swap_active (ctx, left_seg, right_seg);
++ return ART_TRUE;
++ }
++
++ if (left_y1 < right_y1)
++ {
++ /* Test left (x1, y1) against right segment */
++ double left_x1 = left_seg->x[1];
++
++ if (left_x1 <
++ right_seg->x[(right_seg->flags & ART_ACTIVE_FLAGS_BNEG) ^ 1] ||
++ left_y1 == right_seg->y0)
++ return ART_FALSE;
++ d = left_x1 * right_seg->a + left_y1 * right_seg->b + right_seg->c;
++ if (d < -EPSILON_A)
++ return ART_FALSE;
++ else if (d < EPSILON_A)
++ {
++ double right_x1 = art_svp_intersect_break (ctx, right_seg,
++ left_x1, left_y1,
++ ART_BREAK_RIGHT);
++ if (left_x1 <= right_x1)
++ return ART_FALSE;
++ }
++ }
++ else if (left_y1 > right_y1)
++ {
++ /* Test right (x1, y1) against left segment */
++ double right_x1 = right_seg->x[1];
++
++ if (right_x1 > left_seg->x[left_seg->flags & ART_ACTIVE_FLAGS_BNEG] ||
++ right_y1 == left_seg->y0)
++ return ART_FALSE;
++ d = right_x1 * left_seg->a + right_y1 * left_seg->b + left_seg->c;
++ if (d > EPSILON_A)
++ return ART_FALSE;
++ else if (d > -EPSILON_A)
++ {
++ double left_x1 = art_svp_intersect_break (ctx, left_seg,
++ right_x1, right_y1,
++ ART_BREAK_LEFT);
++ if (left_x1 <= right_x1)
++ return ART_FALSE;
++ }
++ }
++ else /* left_y1 == right_y1 */
++ {
++ double left_x1 = left_seg->x[1];
++ double right_x1 = right_seg->x[1];
++
++ if (left_x1 <= right_x1)
++ return ART_FALSE;
++ }
++
++ /* The segments cross. Find the intersection point. */
++
++ in_seg = left_seg->in_seg;
++ in_curs = left_seg->in_curs;
++ left_x0 = in_seg->points[in_curs - 1].x;
++ left_y0 = in_seg->points[in_curs - 1].y;
++ left_x1 = in_seg->points[in_curs].x;
++ left_y1 = in_seg->points[in_curs].y;
++ d0 = left_x0 * right_seg->a + left_y0 * right_seg->b + right_seg->c;
++ d1 = left_x1 * right_seg->a + left_y1 * right_seg->b + right_seg->c;
++ if (d0 == d1)
++ {
++ x = left_x0;
++ y = left_y0;
++ }
++ else
++ {
++ /* Is this division always safe? It could possibly overflow. */
++ t = d0 / (d0 - d1);
++ if (t <= 0)
++ {
++ x = left_x0;
++ y = left_y0;
++ }
++ else if (t >= 1)
++ {
++ x = left_x1;
++ y = left_y1;
++ }
++ else
++ {
++ x = left_x0 + t * (left_x1 - left_x0);
++ y = left_y0 + t * (left_y1 - left_y0);
++ }
++ }
++
++ /* Make sure intersection point is within bounds of right seg. */
++ if (y < right_seg->y0)
++ {
++ x = right_seg->x[0];
++ y = right_seg->y0;
++ }
++ else if (y > right_seg->y1)
++ {
++ x = right_seg->x[1];
++ y = right_seg->y1;
++ }
++ else if (x < right_seg->x[(right_seg->flags & ART_ACTIVE_FLAGS_BNEG) ^ 1])
++ x = right_seg->x[(right_seg->flags & ART_ACTIVE_FLAGS_BNEG) ^ 1];
++ else if (x > right_seg->x[right_seg->flags & ART_ACTIVE_FLAGS_BNEG])
++ x = right_seg->x[right_seg->flags & ART_ACTIVE_FLAGS_BNEG];
++
++ if (y == left_seg->y0)
++ {
++ if (y != right_seg->y0)
++ {
++#ifdef VERBOSE
++ art_dprint ("art_svp_intersect_test_cross: intersection (%g, %g) matches former y0 of %lx, %lx\n",
++ x, y, (unsigned long)left_seg, (unsigned long)right_seg);
++#endif
++ art_svp_intersect_push_pt (ctx, right_seg, x, y);
++ if ((break_flags & ART_BREAK_RIGHT) && right_seg->right != NULL)
++ art_svp_intersect_add_point (ctx, x, y, right_seg->right,
++ break_flags);
++ }
++ else
++ {
++ /* Intersection takes place at current scan line; process
++ immediately rather than queueing intersection point into
++ priq. */
++ ArtActiveSeg *winner, *loser;
++
++ /* Choose "most vertical" segement */
++ if (left_seg->a > right_seg->a)
++ {
++ winner = left_seg;
++ loser = right_seg;
++ }
++ else
++ {
++ winner = right_seg;
++ loser = left_seg;
++ }
++
++ loser->x[0] = winner->x[0];
++ loser->horiz_x = loser->x[0];
++ loser->horiz_delta_wind += loser->delta_wind;
++ winner->horiz_delta_wind -= loser->delta_wind;
++
++ art_svp_intersect_swap_active (ctx, left_seg, right_seg);
++ return ART_TRUE;
++ }
++ }
++ else if (y == right_seg->y0)
++ {
++#ifdef VERBOSE
++ art_dprint ("*** art_svp_intersect_test_cross: intersection (%g, %g) matches latter y0 of %lx, %lx\n",
++ x, y, (unsigned long)left_seg, (unsigned long)right_seg);
++#endif
++ art_svp_intersect_push_pt (ctx, left_seg, x, y);
++ if ((break_flags & ART_BREAK_LEFT) && left_seg->left != NULL)
++ art_svp_intersect_add_point (ctx, x, y, left_seg->left,
++ break_flags);
++ }
++ else
++ {
++#ifdef VERBOSE
++ art_dprint ("Inserting (%g, %g) into %lx, %lx\n",
++ x, y, (unsigned long)left_seg, (unsigned long)right_seg);
++#endif
++ /* Insert the intersection point into both segments. */
++ art_svp_intersect_push_pt (ctx, left_seg, x, y);
++ art_svp_intersect_push_pt (ctx, right_seg, x, y);
++ if ((break_flags & ART_BREAK_LEFT) && left_seg->left != NULL)
++ art_svp_intersect_add_point (ctx, x, y, left_seg->left, break_flags);
++ if ((break_flags & ART_BREAK_RIGHT) && right_seg->right != NULL)
++ art_svp_intersect_add_point (ctx, x, y, right_seg->right, break_flags);
++ }
++ return ART_FALSE;
++}
++
++/**
++ * art_svp_intersect_active_delete: Delete segment from active list.
++ * @ctx: Intersection context.
++ * @seg: Segment to delete.
++ *
++ * Deletes @seg from the active list.
++ **/
++static /* todo inline */ void
++art_svp_intersect_active_delete (ArtIntersectCtx *ctx, ArtActiveSeg *seg)
++{
++ ArtActiveSeg *left = seg->left, *right = seg->right;
++
++ if (left != NULL)
++ left->right = right;
++ else
++ ctx->active_head = right;
++ if (right != NULL)
++ right->left = left;
++}
++
++/**
++ * art_svp_intersect_active_free: Free an active segment.
++ * @seg: Segment to delete.
++ *
++ * Frees @seg.
++ **/
++static /* todo inline */ void
++art_svp_intersect_active_free (ArtActiveSeg *seg)
++{
++ art_free (seg->stack);
++#ifdef VERBOSE
++ art_dprint ("Freeing %lx\n", (unsigned long) seg);
++#endif
++ art_free (seg);
++}
++
++/**
++ * art_svp_intersect_insert_cross: Test crossings of newly inserted line.
++ *
++ * Tests @seg against its left and right neighbors for intersections.
++ * Precondition: the line in @seg is not purely horizontal.
++ **/
++static void
++art_svp_intersect_insert_cross (ArtIntersectCtx *ctx,
++ ArtActiveSeg *seg)
++{
++ ArtActiveSeg *left = seg, *right = seg;
++
++ for (;;)
++ {
++ if (left != NULL)
++ {
++ ArtActiveSeg *leftc;
++
++ for (leftc = left->left; leftc != NULL; leftc = leftc->left)
++ if (!(leftc->flags & ART_ACTIVE_FLAGS_DEL))
++ break;
++ if (leftc != NULL &&
++ art_svp_intersect_test_cross (ctx, leftc, left,
++ ART_BREAK_LEFT))
++ {
++ if (left == right || right == NULL)
++ right = left->right;
++ }
++ else
++ {
++ left = NULL;
++ }
++ }
++ else if (right != NULL && right->right != NULL)
++ {
++ ArtActiveSeg *rightc;
++
++ for (rightc = right->right; rightc != NULL; rightc = rightc->right)
++ if (!(rightc->flags & ART_ACTIVE_FLAGS_DEL))
++ break;
++ if (rightc != NULL &&
++ art_svp_intersect_test_cross (ctx, right, rightc,
++ ART_BREAK_RIGHT))
++ {
++ if (left == right || left == NULL)
++ left = right->left;
++ }
++ else
++ {
++ right = NULL;
++ }
++ }
++ else
++ break;
++ }
++}
++
++/**
++ * art_svp_intersect_horiz: Add horizontal line segment.
++ * @ctx: Intersector context.
++ * @seg: Segment on which to add horizontal line.
++ * @x0: Old x position.
++ * @x1: New x position.
++ *
++ * Adds a horizontal line from @x0 to @x1, and updates the current
++ * location of @seg to @x1.
++ **/
++static void
++art_svp_intersect_horiz (ArtIntersectCtx *ctx, ArtActiveSeg *seg,
++ double x0, double x1)
++{
++ ArtActiveSeg *hs;
++
++ if (x0 == x1)
++ return;
++
++ hs = art_new (ArtActiveSeg, 1);
++
++ hs->flags = ART_ACTIVE_FLAGS_DEL | (seg->flags & ART_ACTIVE_FLAGS_OUT);
++ if (seg->flags & ART_ACTIVE_FLAGS_OUT)
++ {
++ ArtSvpWriter *swr = ctx->out;
++
++ swr->add_point (swr, seg->seg_id, x0, ctx->y);
++ }
++ hs->seg_id = seg->seg_id;
++ hs->horiz_x = x0;
++ hs->horiz_delta_wind = seg->delta_wind;
++ hs->stack = NULL;
++
++ /* Ideally, the (a, b, c) values will never be read. However, there
++ are probably some tests remaining that don't check for _DEL
++ before evaluating the line equation. For those, these
++ initializations will at least prevent a UMR of the values, which
++ can crash on some platforms. */
++ hs->a = 0.0;
++ hs->b = 0.0;
++ hs->c = 0.0;
++
++ seg->horiz_delta_wind -= seg->delta_wind;
++
++ art_svp_intersect_add_horiz (ctx, hs);
++
++ if (x0 > x1)
++ {
++ ArtActiveSeg *left;
++ art_boolean first = ART_TRUE;
++
++ for (left = seg->left; left != NULL; left = seg->left)
++ {
++ int left_bneg = left->flags & ART_ACTIVE_FLAGS_BNEG;
++
++ if (left->x[left_bneg] <= x1)
++ break;
++ if (left->x[left_bneg ^ 1] <= x1 &&
++ x1 * left->a + ctx->y * left->b + left->c >= 0)
++ break;
++ if (left->y0 != ctx->y && left->y1 != ctx->y)
++ {
++ art_svp_intersect_break (ctx, left, x1, ctx->y, ART_BREAK_LEFT);
++ }
++#ifdef VERBOSE
++ art_dprint ("x0=%g > x1=%g, swapping %lx, %lx\n",
++ x0, x1, (unsigned long)left, (unsigned long)seg);
++#endif
++ art_svp_intersect_swap_active (ctx, left, seg);
++ if (first && left->right != NULL)
++ {
++ art_svp_intersect_test_cross (ctx, left, left->right,
++ ART_BREAK_RIGHT);
++ first = ART_FALSE;
++ }
++ }
++ }
++ else
++ {
++ ArtActiveSeg *right;
++ art_boolean first = ART_TRUE;
++
++ for (right = seg->right; right != NULL; right = seg->right)
++ {
++ int right_bneg = right->flags & ART_ACTIVE_FLAGS_BNEG;
++
++ if (right->x[right_bneg ^ 1] >= x1)
++ break;
++ if (right->x[right_bneg] >= x1 &&
++ x1 * right->a + ctx->y * right->b + right->c <= 0)
++ break;
++ if (right->y0 != ctx->y && right->y1 != ctx->y)
++ {
++ art_svp_intersect_break (ctx, right, x1, ctx->y,
++ ART_BREAK_LEFT);
++ }
++#ifdef VERBOSE
++ art_dprint ("[right]x0=%g < x1=%g, swapping %lx, %lx\n",
++ x0, x1, (unsigned long)seg, (unsigned long)right);
++#endif
++ art_svp_intersect_swap_active (ctx, seg, right);
++ if (first && right->left != NULL)
++ {
++ art_svp_intersect_test_cross (ctx, right->left, right,
++ ART_BREAK_RIGHT);
++ first = ART_FALSE;
++ }
++ }
++ }
++
++ seg->x[0] = x1;
++ seg->x[1] = x1;
++ seg->horiz_x = x1;
++ seg->flags &= ~ART_ACTIVE_FLAGS_OUT;
++}
++
++/**
++ * art_svp_intersect_insert_line: Insert a line into the active list.
++ * @ctx: Intersector context.
++ * @seg: Segment containing line to insert.
++ *
++ * Inserts the line into the intersector context, taking care of any
++ * intersections, and adding the appropriate horizontal points to the
++ * active list.
++ **/
++static void
++art_svp_intersect_insert_line (ArtIntersectCtx *ctx, ArtActiveSeg *seg)
++{
++ if (seg->y1 == seg->y0)
++ {
++#ifdef VERBOSE
++ art_dprint ("art_svp_intersect_insert_line: %lx is horizontal\n",
++ (unsigned long)seg);
++#endif
++ art_svp_intersect_horiz (ctx, seg, seg->x[0], seg->x[1]);
++ }
++ else
++ {
++ art_svp_intersect_insert_cross (ctx, seg);
++ art_svp_intersect_add_horiz (ctx, seg);
++ }
++}
++
++static void
++art_svp_intersect_process_intersection (ArtIntersectCtx *ctx,
++ ArtActiveSeg *seg)
++{
++ int n_stack = --seg->n_stack;
++ seg->x[1] = seg->stack[n_stack - 1].x;
++ seg->y1 = seg->stack[n_stack - 1].y;
++ seg->x[0] = seg->stack[n_stack].x;
++ seg->y0 = seg->stack[n_stack].y;
++ seg->horiz_x = seg->x[0];
++ art_svp_intersect_insert_line (ctx, seg);
++}
++
++static void
++art_svp_intersect_advance_cursor (ArtIntersectCtx *ctx, ArtActiveSeg *seg,
++ ArtPriPoint *pri_pt)
++{
++ const ArtSVPSeg *in_seg = seg->in_seg;
++ int in_curs = seg->in_curs;
++ ArtSvpWriter *swr = seg->flags & ART_ACTIVE_FLAGS_OUT ? ctx->out : NULL;
++
++ if (swr != NULL)
++ swr->add_point (swr, seg->seg_id, seg->x[1], seg->y1);
++ if (in_curs + 1 == in_seg->n_points)
++ {
++ ArtActiveSeg *left = seg->left, *right = seg->right;
++
++#if 0
++ if (swr != NULL)
++ swr->close_segment (swr, seg->seg_id);
++ seg->flags &= ~ART_ACTIVE_FLAGS_OUT;
++#endif
++ seg->flags |= ART_ACTIVE_FLAGS_DEL;
++ art_svp_intersect_add_horiz (ctx, seg);
++ art_svp_intersect_active_delete (ctx, seg);
++ if (left != NULL && right != NULL)
++ art_svp_intersect_test_cross (ctx, left, right,
++ ART_BREAK_LEFT | ART_BREAK_RIGHT);
++ art_free (pri_pt);
++ }
++ else
++ {
++ seg->horiz_x = seg->x[1];
++
++ art_svp_intersect_setup_seg (seg, pri_pt);
++ art_pri_insert (ctx->pq, pri_pt);
++ art_svp_intersect_insert_line (ctx, seg);
++ }
++}
++
++static void
++art_svp_intersect_add_seg (ArtIntersectCtx *ctx, const ArtSVPSeg *in_seg)
++{
++ ArtActiveSeg *seg = art_new (ArtActiveSeg, 1);
++ ArtActiveSeg *test;
++ double x0, y0;
++ ArtActiveSeg *beg_range;
++ ArtActiveSeg *last = NULL;
++ ArtActiveSeg *left, *right;
++ ArtPriPoint *pri_pt = art_new (ArtPriPoint, 1);
++
++ seg->flags = 0;
++ seg->in_seg = in_seg;
++ seg->in_curs = 0;
++
++ seg->n_stack_max = 4;
++ seg->stack = art_new (ArtPoint, seg->n_stack_max);
++
++ seg->horiz_delta_wind = 0;
++
++ seg->wind_left = 0;
++
++ pri_pt->user_data = seg;
++ art_svp_intersect_setup_seg (seg, pri_pt);
++ art_pri_insert (ctx->pq, pri_pt);
++
++ /* Find insertion place for new segment */
++ /* This is currently a left-to-right scan, but should be replaced
++ with a binary search as soon as it's validated. */
++
++ x0 = in_seg->points[0].x;
++ y0 = in_seg->points[0].y;
++ beg_range = NULL;
++ for (test = ctx->active_head; test != NULL; test = test->right)
++ {
++ double d;
++ int test_bneg = test->flags & ART_ACTIVE_FLAGS_BNEG;
++
++ if (x0 < test->x[test_bneg])
++ {
++ if (x0 < test->x[test_bneg ^ 1])
++ break;
++ d = x0 * test->a + y0 * test->b + test->c;
++ if (d < 0)
++ break;
++ }
++ last = test;
++ }
++
++ left = art_svp_intersect_add_point (ctx, x0, y0, last, ART_BREAK_LEFT | ART_BREAK_RIGHT);
++ seg->left = left;
++ if (left == NULL)
++ {
++ right = ctx->active_head;
++ ctx->active_head = seg;
++ }
++ else
++ {
++ right = left->right;
++ left->right = seg;
++ }
++ seg->right = right;
++ if (right != NULL)
++ right->left = seg;
++
++ seg->delta_wind = in_seg->dir ? 1 : -1;
++ seg->horiz_x = x0;
++
++ art_svp_intersect_insert_line (ctx, seg);
++}
++
++#ifdef SANITYCHECK
++static void
++art_svp_intersect_sanitycheck_winding (ArtIntersectCtx *ctx)
++{
++#if 0
++ /* At this point, we seem to be getting false positives, so it's
++ turned off for now. */
++
++ ArtActiveSeg *seg;
++ int winding_number = 0;
++
++ for (seg = ctx->active_head; seg != NULL; seg = seg->right)
++ {
++ /* Check winding number consistency. */
++ if (seg->flags & ART_ACTIVE_FLAGS_OUT)
++ {
++ if (winding_number != seg->wind_left)
++ art_warn ("*** art_svp_intersect_sanitycheck_winding: seg %lx has wind_left of %d, expected %d\n",
++ (unsigned long) seg, seg->wind_left, winding_number);
++ winding_number = seg->wind_left + seg->delta_wind;
++ }
++ }
++ if (winding_number != 0)
++ art_warn ("*** art_svp_intersect_sanitycheck_winding: non-balanced winding number %d\n",
++ winding_number);
++#endif
++}
++#endif
++
++/**
++ * art_svp_intersect_horiz_commit: Commit points in horiz list to output.
++ * @ctx: Intersection context.
++ *
++ * The main function of the horizontal commit is to output new
++ * points to the output writer.
++ *
++ * This "commit" pass is also where winding numbers are assigned,
++ * because doing it here provides much greater tolerance for inputs
++ * which are not in strict SVP order.
++ *
++ * Each cluster in the horiz_list contains both segments that are in
++ * the active list (ART_ACTIVE_FLAGS_DEL is false) and that are not,
++ * and are scheduled to be deleted (ART_ACTIVE_FLAGS_DEL is true). We
++ * need to deal with both.
++ **/
++static void
++art_svp_intersect_horiz_commit (ArtIntersectCtx *ctx)
++{
++ ArtActiveSeg *seg;
++ int winding_number = 0; /* initialization just to avoid warning */
++ int horiz_wind = 0;
++ double last_x = 0; /* initialization just to avoid warning */
++
++#ifdef VERBOSE
++ art_dprint ("art_svp_intersect_horiz_commit: y=%g\n", ctx->y);
++ for (seg = ctx->horiz_first; seg != NULL; seg = seg->horiz_right)
++ art_dprint (" %lx: %g %+d\n",
++ (unsigned long)seg, seg->horiz_x, seg->horiz_delta_wind);
++#endif
++
++ /* Output points to svp writer. */
++ for (seg = ctx->horiz_first; seg != NULL;)
++ {
++ /* Find a cluster with common horiz_x, */
++ ArtActiveSeg *curs;
++ double x = seg->horiz_x;
++
++ /* Generate any horizontal segments. */
++ if (horiz_wind != 0)
++ {
++ ArtSvpWriter *swr = ctx->out;
++ int seg_id;
++
++ seg_id = swr->add_segment (swr, winding_number, horiz_wind,
++ last_x, ctx->y);
++ swr->add_point (swr, seg_id, x, ctx->y);
++ swr->close_segment (swr, seg_id);
++ }
++
++ /* Find first active segment in cluster. */
++
++ for (curs = seg; curs != NULL && curs->horiz_x == x;
++ curs = curs->horiz_right)
++ if (!(curs->flags & ART_ACTIVE_FLAGS_DEL))
++ break;
++
++ if (curs != NULL && curs->horiz_x == x)
++ {
++ /* There exists at least one active segment in this cluster. */
++
++ /* Find beginning of cluster. */
++ for (; curs->left != NULL; curs = curs->left)
++ if (curs->left->horiz_x != x)
++ break;
++
++ if (curs->left != NULL)
++ winding_number = curs->left->wind_left + curs->left->delta_wind;
++ else
++ winding_number = 0;
++
++ do
++ {
++#ifdef VERBOSE
++ art_dprint (" curs %lx: winding_number = %d += %d\n",
++ (unsigned long)curs, winding_number, curs->delta_wind);
++#endif
++ if (!(curs->flags & ART_ACTIVE_FLAGS_OUT) ||
++ curs->wind_left != winding_number)
++ {
++ ArtSvpWriter *swr = ctx->out;
++
++ if (curs->flags & ART_ACTIVE_FLAGS_OUT)
++ {
++ swr->add_point (swr, curs->seg_id,
++ curs->horiz_x, ctx->y);
++ swr->close_segment (swr, curs->seg_id);
++ }
++
++ curs->seg_id = swr->add_segment (swr, winding_number,
++ curs->delta_wind,
++ x, ctx->y);
++ curs->flags |= ART_ACTIVE_FLAGS_OUT;
++ }
++ curs->wind_left = winding_number;
++ winding_number += curs->delta_wind;
++ curs = curs->right;
++ }
++ while (curs != NULL && curs->horiz_x == x);
++ }
++
++ /* Skip past cluster. */
++ do
++ {
++ ArtActiveSeg *next = seg->horiz_right;
++
++ seg->flags &= ~ART_ACTIVE_FLAGS_IN_HORIZ;
++ horiz_wind += seg->horiz_delta_wind;
++ seg->horiz_delta_wind = 0;
++ if (seg->flags & ART_ACTIVE_FLAGS_DEL)
++ {
++ if (seg->flags & ART_ACTIVE_FLAGS_OUT)
++ {
++ ArtSvpWriter *swr = ctx->out;
++ swr->close_segment (swr, seg->seg_id);
++ }
++ art_svp_intersect_active_free (seg);
++ }
++ seg = next;
++ }
++ while (seg != NULL && seg->horiz_x == x);
++
++ last_x = x;
++ }
++ ctx->horiz_first = NULL;
++ ctx->horiz_last = NULL;
++#ifdef SANITYCHECK
++ art_svp_intersect_sanitycheck_winding (ctx);
++#endif
++}
++
++#ifdef VERBOSE
++static void
++art_svp_intersect_print_active (ArtIntersectCtx *ctx)
++{
++ ArtActiveSeg *seg;
++
++ art_dprint ("Active list (y = %g):\n", ctx->y);
++ for (seg = ctx->active_head; seg != NULL; seg = seg->right)
++ {
++ art_dprint (" %lx: (%g, %g)-(%g, %g), (a, b, c) = (%g, %g, %g)\n",
++ (unsigned long)seg,
++ seg->x[0], seg->y0, seg->x[1], seg->y1,
++ seg->a, seg->b, seg->c);
++ }
++}
++#endif
++
++#ifdef SANITYCHECK
++static void
++art_svp_intersect_sanitycheck (ArtIntersectCtx *ctx)
++{
++ ArtActiveSeg *seg;
++ ArtActiveSeg *last = NULL;
++ double d;
++
++ for (seg = ctx->active_head; seg != NULL; seg = seg->right)
++ {
++ if (seg->left != last)
++ {
++ art_warn ("*** art_svp_intersect_sanitycheck: last=%lx, seg->left=%lx\n",
++ (unsigned long)last, (unsigned long)seg->left);
++ }
++ if (last != NULL)
++ {
++ /* pairwise compare with previous seg */
++
++ /* First the top. */
++ if (last->y0 < seg->y0)
++ {
++ }
++ else
++ {
++ }
++
++ /* Then the bottom. */
++ if (last->y1 < seg->y1)
++ {
++ if (!((last->x[1] <
++ seg->x[(seg->flags & ART_ACTIVE_FLAGS_BNEG) ^ 1]) ||
++ last->y1 == seg->y0))
++ {
++ d = last->x[1] * seg->a + last->y1 * seg->b + seg->c;
++ if (d >= -EPSILON_A)
++ art_warn ("*** bottom (%g, %g) of %lx is not clear of %lx to right (d = %g)\n",
++ last->x[1], last->y1, (unsigned long) last,
++ (unsigned long) seg, d);
++ }
++ }
++ else if (last->y1 > seg->y1)
++
++ {
++ if (!((seg->x[1] >
++ last->x[last->flags & ART_ACTIVE_FLAGS_BNEG]) ||
++ seg->y1 == last->y0))
++ {
++ d = seg->x[1] * last->a + seg->y1 * last->b + last->c;
++ if (d <= EPSILON_A)
++ art_warn ("*** bottom (%g, %g) of %lx is not clear of %lx to left (d = %g)\n",
++ seg->x[1], seg->y1, (unsigned long) seg,
++ (unsigned long) last, d);
++ }
++ }
++ else
++ {
++ if (last->x[1] > seg->x[1])
++ art_warn ("*** bottoms (%g, %g) of %lx and (%g, %g) of %lx out of order\n",
++ last->x[1], last->y1, (unsigned long)last,
++ seg->x[1], seg->y1, (unsigned long)seg);
++ }
++ }
++ last = seg;
++ }
++}
++#endif
++
++void
++art_svp_intersector (const ArtSVP *in, ArtSvpWriter *out)
++{
++ ArtIntersectCtx *ctx;
++ ArtPriQ *pq;
++ ArtPriPoint *first_point;
++#ifdef VERBOSE
++ int count = 0;
++#endif
++
++ if (in->n_segs == 0)
++ return;
++
++ ctx = art_new (ArtIntersectCtx, 1);
++ ctx->in = in;
++ ctx->out = out;
++ pq = art_pri_new ();
++ ctx->pq = pq;
++
++ ctx->active_head = NULL;
++
++ ctx->horiz_first = NULL;
++ ctx->horiz_last = NULL;
++
++ ctx->in_curs = 0;
++ first_point = art_new (ArtPriPoint, 1);
++ first_point->x = in->segs[0].points[0].x;
++ first_point->y = in->segs[0].points[0].y;
++ first_point->user_data = NULL;
++ ctx->y = first_point->y;
++ art_pri_insert (pq, first_point);
++
++ while (!art_pri_empty (pq))
++ {
++ ArtPriPoint *pri_point = art_pri_choose (pq);
++ ArtActiveSeg *seg = (ArtActiveSeg *)pri_point->user_data;
++
++#ifdef VERBOSE
++ art_dprint ("\nIntersector step %d\n", count++);
++ art_svp_intersect_print_active (ctx);
++ art_dprint ("priq choose (%g, %g) %lx\n", pri_point->x, pri_point->y,
++ (unsigned long)pri_point->user_data);
++#endif
++#ifdef SANITYCHECK
++ art_svp_intersect_sanitycheck(ctx);
++#endif
++
++ if (ctx->y != pri_point->y)
++ {
++ art_svp_intersect_horiz_commit (ctx);
++ ctx->y = pri_point->y;
++ }
++
++ if (seg == NULL)
++ {
++ /* Insert new segment from input */
++ const ArtSVPSeg *in_seg = &in->segs[ctx->in_curs++];
++ art_svp_intersect_add_seg (ctx, in_seg);
++ if (ctx->in_curs < in->n_segs)
++ {
++ const ArtSVPSeg *next_seg = &in->segs[ctx->in_curs];
++ pri_point->x = next_seg->points[0].x;
++ pri_point->y = next_seg->points[0].y;
++ /* user_data is already NULL */
++ art_pri_insert (pq, pri_point);
++ }
++ else
++ art_free (pri_point);
++ }
++ else
++ {
++ int n_stack = seg->n_stack;
++
++ if (n_stack > 1)
++ {
++ art_svp_intersect_process_intersection (ctx, seg);
++ art_free (pri_point);
++ }
++ else
++ {
++ art_svp_intersect_advance_cursor (ctx, seg, pri_point);
++ }
++ }
++ }
++
++ art_svp_intersect_horiz_commit (ctx);
++
++ art_pri_free (pq);
++ art_free (ctx);
++}
++
++#endif /* not TEST_PRIQ */
+diff -u -r --new-file tools/source/generic/libart_lgpl/art_svp_intersect.h tools/source/generic/libart_lgpl/art_svp_intersect.h
+--- tools/source/generic/libart_lgpl/art_svp_intersect.h 1970-01-01 01:00:00.000000000 +0100
++++ tools/source/generic/libart_lgpl/art_svp_intersect.h 2004-04-06 17:44:51.000000000 +0100
+@@ -0,0 +1,70 @@
++/* Libart_LGPL - library of basic graphic primitives
++ * Copyright (C) 2001 Raph Levien
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the
++ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
++ * Boston, MA 02111-1307, USA.
++ */
++
++#ifndef __ART_SVP_INTERSECT_H__
++#define __ART_SVP_INTERSECT_H__
++
++/* The funky new SVP intersector. */
++
++#ifdef LIBART_COMPILATION
++#include "art_svp.h"
++#else
++#include <libart_lgpl/art_svp.h>
++#endif
++
++#ifdef __cplusplus
++extern "C" {
++#endif /* __cplusplus */
++
++#ifndef ART_WIND_RULE_DEFINED
++#define ART_WIND_RULE_DEFINED
++typedef enum {
++ ART_WIND_RULE_NONZERO,
++ ART_WIND_RULE_INTERSECT,
++ ART_WIND_RULE_ODDEVEN,
++ ART_WIND_RULE_POSITIVE
++} ArtWindRule;
++#endif
++
++typedef struct _ArtSvpWriter ArtSvpWriter;
++
++struct _ArtSvpWriter {
++ int (*add_segment) (ArtSvpWriter *self, int wind_left, int delta_wind,
++ double x, double y);
++ void (*add_point) (ArtSvpWriter *self, int seg_id, double x, double y);
++ void (*close_segment) (ArtSvpWriter *self, int seg_id);
++};
++
++ArtSvpWriter *
++art_svp_writer_rewind_new (ArtWindRule rule);
++
++ArtSVP *
++art_svp_writer_rewind_reap (ArtSvpWriter *self);
++
++int
++art_svp_seg_compare (const void *s1, const void *s2);
++
++void
++art_svp_intersector (const ArtSVP *in, ArtSvpWriter *out);
++
++#ifdef __cplusplus
++}
++#endif /* __cplusplus */
++
++#endif /* __ART_SVP_INTERSECT_H__ */
+diff -u -r --new-file tools/source/generic/libart_lgpl/art_svp_ops.c tools/source/generic/libart_lgpl/art_svp_ops.c
+--- tools/source/generic/libart_lgpl/art_svp_ops.c 1970-01-01 01:00:00.000000000 +0100
++++ tools/source/generic/libart_lgpl/art_svp_ops.c 2004-04-06 17:44:58.000000000 +0100
+@@ -0,0 +1,401 @@
++/* Libart_LGPL - library of basic graphic primitives
++ * Copyright (C) 1998-2000 Raph Levien
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the
++ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
++ * Boston, MA 02111-1307, USA.
++ */
++
++#define noVERBOSE
++
++/* Vector path set operations, over sorted vpaths. */
++
++#include "config.h"
++#include "art_svp_ops.h"
++
++#include "art_misc.h"
++
++#include "art_svp.h"
++#include "art_vpath.h"
++#include "art_svp_vpath.h"
++#include "art_svp.h"
++#ifdef ART_USE_NEW_INTERSECTOR
++#include "art_svp_intersect.h"
++#else
++#include "art_svp_wind.h"
++#endif
++#include "art_vpath_svp.h"
++
++/* Merge the segments of the two svp's. The resulting svp will share
++ segments with args passed in, so be super-careful with the
++ allocation. */
++/**
++ * art_svp_merge: Merge the segments of two svp's.
++ * @svp1: One svp to merge.
++ * @svp2: The other svp to merge.
++ *
++ * Merges the segments of two SVP's into a new one. The resulting
++ * #ArtSVP data structure will share the segments of the argument
++ * svp's, so it is probably a good idea to free it shallowly,
++ * especially if the arguments will be freed with art_svp_free().
++ *
++ * Return value: The merged #ArtSVP.
++ **/
++static ArtSVP *
++art_svp_merge (const ArtSVP *svp1, const ArtSVP *svp2)
++{
++ ArtSVP *svp_new;
++ int ix;
++ int ix1, ix2;
++
++ svp_new = (ArtSVP *)art_alloc (sizeof(ArtSVP) +
++ (svp1->n_segs + svp2->n_segs - 1) *
++ sizeof(ArtSVPSeg));
++ ix1 = 0;
++ ix2 = 0;
++ for (ix = 0; ix < svp1->n_segs + svp2->n_segs; ix++)
++ {
++ if (ix1 < svp1->n_segs &&
++ (ix2 == svp2->n_segs ||
++ art_svp_seg_compare (&svp1->segs[ix1], &svp2->segs[ix2]) < 1))
++ svp_new->segs[ix] = svp1->segs[ix1++];
++ else
++ svp_new->segs[ix] = svp2->segs[ix2++];
++ }
++
++ svp_new->n_segs = ix;
++ return svp_new;
++}
++
++#ifdef VERBOSE
++
++#define XOFF 50
++#define YOFF 700
++
++static void
++print_ps_vpath (ArtVpath *vpath)
++{
++ int i;
++
++ printf ("gsave %d %d translate 1 -1 scale\n", XOFF, YOFF);
++ for (i = 0; vpath[i].code != ART_END; i++)
++ {
++ switch (vpath[i].code)
++ {
++ case ART_MOVETO:
++ printf ("%g %g moveto\n", vpath[i].x, vpath[i].y);
++ break;
++ case ART_LINETO:
++ printf ("%g %g lineto\n", vpath[i].x, vpath[i].y);
++ break;
++ default:
++ break;
++ }
++ }
++ printf ("stroke grestore showpage\n");
++}
++
++#define DELT 4
++
++static void
++print_ps_svp (ArtSVP *vpath)
++{
++ int i, j;
++
++ printf ("%% begin\n");
++ for (i = 0; i < vpath->n_segs; i++)
++ {
++ printf ("%g setgray\n", vpath->segs[i].dir ? 0.7 : 0);
++ for (j = 0; j < vpath->segs[i].n_points; j++)
++ {
++ printf ("%g %g %s\n",
++ XOFF + vpath->segs[i].points[j].x,
++ YOFF - vpath->segs[i].points[j].y,
++ j ? "lineto" : "moveto");
++ }
++ printf ("%g %g moveto %g %g lineto %g %g lineto %g %g lineto stroke\n",
++ XOFF + vpath->segs[i].points[0].x - DELT,
++ YOFF - DELT - vpath->segs[i].points[0].y,
++ XOFF + vpath->segs[i].points[0].x - DELT,
++ YOFF - vpath->segs[i].points[0].y,
++ XOFF + vpath->segs[i].points[0].x + DELT,
++ YOFF - vpath->segs[i].points[0].y,
++ XOFF + vpath->segs[i].points[0].x + DELT,
++ YOFF - DELT - vpath->segs[i].points[0].y);
++ printf ("%g %g moveto %g %g lineto %g %g lineto %g %g lineto stroke\n",
++ XOFF + vpath->segs[i].points[j - 1].x - DELT,
++ YOFF + DELT - vpath->segs[i].points[j - 1].y,
++ XOFF + vpath->segs[i].points[j - 1].x - DELT,
++ YOFF - vpath->segs[i].points[j - 1].y,
++ XOFF + vpath->segs[i].points[j - 1].x + DELT,
++ YOFF - vpath->segs[i].points[j - 1].y,
++ XOFF + vpath->segs[i].points[j - 1].x + DELT,
++ YOFF + DELT - vpath->segs[i].points[j - 1].y);
++ printf ("stroke\n");
++ }
++
++ printf ("showpage\n");
++}
++#endif
++
++#ifndef ART_USE_NEW_INTERSECTOR
++static ArtSVP *
++art_svp_merge_perturbed (const ArtSVP *svp1, const ArtSVP *svp2)
++{
++ ArtVpath *vpath1, *vpath2;
++ ArtVpath *vpath1_p, *vpath2_p;
++ ArtSVP *svp1_p, *svp2_p;
++ ArtSVP *svp_new;
++
++ vpath1 = art_vpath_from_svp (svp1);
++ vpath1_p = art_vpath_perturb (vpath1);
++ art_free (vpath1);
++ svp1_p = art_svp_from_vpath (vpath1_p);
++ art_free (vpath1_p);
++
++ vpath2 = art_vpath_from_svp (svp2);
++ vpath2_p = art_vpath_perturb (vpath2);
++ art_free (vpath2);
++ svp2_p = art_svp_from_vpath (vpath2_p);
++ art_free (vpath2_p);
++
++ svp_new = art_svp_merge (svp1_p, svp2_p);
++#ifdef VERBOSE
++ print_ps_svp (svp1_p);
++ print_ps_svp (svp2_p);
++ print_ps_svp (svp_new);
++#endif
++ art_free (svp1_p);
++ art_free (svp2_p);
++
++ return svp_new;
++}
++#endif
++
++/* Compute the union of two vector paths.
++
++ Status of this routine:
++
++ Basic correctness: Seems to work.
++
++ Numerical stability: We cheat (adding random perturbation). Thus,
++ it seems very likely that no numerical stability problems will be
++ seen in practice.
++
++ Speed: Would be better if we didn't go to unsorted vector path
++ and back to add the perturbation.
++
++ Precision: The perturbation fuzzes the coordinates slightly. In
++ cases of butting segments, razor thin long holes may appear.
++
++*/
++/**
++ * art_svp_union: Compute the union of two sorted vector paths.
++ * @svp1: One sorted vector path.
++ * @svp2: The other sorted vector path.
++ *
++ * Computes the union of the two argument svp's. Given two svp's with
++ * winding numbers of 0 and 1 everywhere, the resulting winding number
++ * will be 1 where either (or both) of the argument svp's has a
++ * winding number 1, 0 otherwise. The result is newly allocated.
++ *
++ * Currently, this routine has accuracy problems pending the
++ * implementation of the new intersector.
++ *
++ * Return value: The union of @svp1 and @svp2.
++ **/
++ArtSVP *
++art_svp_union (const ArtSVP *svp1, const ArtSVP *svp2)
++{
++#ifdef ART_USE_NEW_INTERSECTOR
++ ArtSVP *svp3, *svp_new;
++ ArtSvpWriter *swr;
++
++ svp3 = art_svp_merge (svp1, svp2);
++ swr = art_svp_writer_rewind_new (ART_WIND_RULE_POSITIVE);
++ art_svp_intersector (svp3, swr);
++ svp_new = art_svp_writer_rewind_reap (swr);
++ art_free (svp3); /* shallow free because svp3 contains shared segments */
++
++ return svp_new;
++#else
++ ArtSVP *svp3, *svp4, *svp_new;
++
++ svp3 = art_svp_merge_perturbed (svp1, svp2);
++ svp4 = art_svp_uncross (svp3);
++ art_svp_free (svp3);
++
++ svp_new = art_svp_rewind_uncrossed (svp4, ART_WIND_RULE_POSITIVE);
++#ifdef VERBOSE
++ print_ps_svp (svp4);
++ print_ps_svp (svp_new);
++#endif
++ art_svp_free (svp4);
++ return svp_new;
++#endif
++}
++
++/* Compute the intersection of two vector paths.
++
++ Status of this routine:
++
++ Basic correctness: Seems to work.
++
++ Numerical stability: We cheat (adding random perturbation). Thus,
++ it seems very likely that no numerical stability problems will be
++ seen in practice.
++
++ Speed: Would be better if we didn't go to unsorted vector path
++ and back to add the perturbation.
++
++ Precision: The perturbation fuzzes the coordinates slightly. In
++ cases of butting segments, razor thin long isolated segments may
++ appear.
++
++*/
++
++/**
++ * art_svp_intersect: Compute the intersection of two sorted vector paths.
++ * @svp1: One sorted vector path.
++ * @svp2: The other sorted vector path.
++ *
++ * Computes the intersection of the two argument svp's. Given two
++ * svp's with winding numbers of 0 and 1 everywhere, the resulting
++ * winding number will be 1 where both of the argument svp's has a
++ * winding number 1, 0 otherwise. The result is newly allocated.
++ *
++ * Currently, this routine has accuracy problems pending the
++ * implementation of the new intersector.
++ *
++ * Return value: The intersection of @svp1 and @svp2.
++ **/
++ArtSVP *
++art_svp_intersect (const ArtSVP *svp1, const ArtSVP *svp2)
++{
++#ifdef ART_USE_NEW_INTERSECTOR
++ ArtSVP *svp3, *svp_new;
++ ArtSvpWriter *swr;
++
++ svp3 = art_svp_merge (svp1, svp2);
++ swr = art_svp_writer_rewind_new (ART_WIND_RULE_INTERSECT);
++ art_svp_intersector (svp3, swr);
++ svp_new = art_svp_writer_rewind_reap (swr);
++ art_free (svp3); /* shallow free because svp3 contains shared segments */
++
++ return svp_new;
++#else
++ ArtSVP *svp3, *svp4, *svp_new;
++
++ svp3 = art_svp_merge_perturbed (svp1, svp2);
++ svp4 = art_svp_uncross (svp3);
++ art_svp_free (svp3);
++
++ svp_new = art_svp_rewind_uncrossed (svp4, ART_WIND_RULE_INTERSECT);
++ art_svp_free (svp4);
++ return svp_new;
++#endif
++}
++
++/* Compute the symmetric difference of two vector paths.
++
++ Status of this routine:
++
++ Basic correctness: Seems to work.
++
++ Numerical stability: We cheat (adding random perturbation). Thus,
++ it seems very likely that no numerical stability problems will be
++ seen in practice.
++
++ Speed: We could do a lot better by scanning through the svp
++ representations and culling out any segments that are exactly
++ identical. It would also be better if we didn't go to unsorted
++ vector path and back to add the perturbation.
++
++ Precision: Awful. In the case of inputs which are similar (the
++ common case for canvas display), the entire outline is "hairy." In
++ addition, the perturbation fuzzes the coordinates slightly. It can
++ be used as a conservative approximation.
++
++*/
++
++/**
++ * art_svp_diff: Compute the symmetric difference of two sorted vector paths.
++ * @svp1: One sorted vector path.
++ * @svp2: The other sorted vector path.
++ *
++ * Computes the symmetric of the two argument svp's. Given two svp's
++ * with winding numbers of 0 and 1 everywhere, the resulting winding
++ * number will be 1 where either, but not both, of the argument svp's
++ * has a winding number 1, 0 otherwise. The result is newly allocated.
++ *
++ * Currently, this routine has accuracy problems pending the
++ * implementation of the new intersector.
++ *
++ * Return value: The symmetric difference of @svp1 and @svp2.
++ **/
++ArtSVP *
++art_svp_diff (const ArtSVP *svp1, const ArtSVP *svp2)
++{
++#ifdef ART_USE_NEW_INTERSECTOR
++ ArtSVP *svp3, *svp_new;
++ ArtSvpWriter *swr;
++
++ svp3 = art_svp_merge (svp1, svp2);
++ swr = art_svp_writer_rewind_new (ART_WIND_RULE_ODDEVEN);
++ art_svp_intersector (svp3, swr);
++ svp_new = art_svp_writer_rewind_reap (swr);
++ art_free (svp3); /* shallow free because svp3 contains shared segments */
++
++ return svp_new;
++#else
++ ArtSVP *svp3, *svp4, *svp_new;
++
++ svp3 = art_svp_merge_perturbed (svp1, svp2);
++ svp4 = art_svp_uncross (svp3);
++ art_svp_free (svp3);
++
++ svp_new = art_svp_rewind_uncrossed (svp4, ART_WIND_RULE_ODDEVEN);
++ art_svp_free (svp4);
++ return svp_new;
++#endif
++}
++
++#ifdef ART_USE_NEW_INTERSECTOR
++ArtSVP *
++art_svp_minus (const ArtSVP *svp1, const ArtSVP *svp2)
++{
++ ArtSVP *svp2_mod;
++ ArtSVP *svp3, *svp_new;
++ ArtSvpWriter *swr;
++ int i;
++
++ svp2_mod = (ArtSVP *) svp2; /* get rid of the const for a while */
++
++ /* First invert svp2 to "turn it inside out" */
++ for (i = 0; i < svp2_mod->n_segs; i++)
++ svp2_mod->segs[i].dir = !svp2_mod->segs[i].dir;
++
++ svp3 = art_svp_merge (svp1, svp2_mod);
++ swr = art_svp_writer_rewind_new (ART_WIND_RULE_POSITIVE);
++ art_svp_intersector (svp3, swr);
++ svp_new = art_svp_writer_rewind_reap (swr);
++ art_free (svp3); /* shallow free because svp3 contains shared segments */
++
++ /* Flip svp2 back to its original state */
++ for (i = 0; i < svp2_mod->n_segs; i++)
++ svp2_mod->segs[i].dir = !svp2_mod->segs[i].dir;
++
++ return svp_new;
++}
++#endif /* ART_USE_NEW_INTERSECTOR */
+diff -u -r --new-file tools/source/generic/libart_lgpl/art_svp_ops.h tools/source/generic/libart_lgpl/art_svp_ops.h
+--- tools/source/generic/libart_lgpl/art_svp_ops.h 1970-01-01 01:00:00.000000000 +0100
++++ tools/source/generic/libart_lgpl/art_svp_ops.h 2004-04-06 17:44:58.000000000 +0100
+@@ -0,0 +1,44 @@
++/* Libart_LGPL - library of basic graphic primitives
++ * Copyright (C) 1998 Raph Levien
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the
++ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
++ * Boston, MA 02111-1307, USA.
++ */
++
++#ifndef __ART_SVP_OPS_H__
++#define __ART_SVP_OPS_H__
++
++#ifdef LIBART_COMPILATION
++#include "art_svp.h"
++#else
++#include <libart_lgpl/art_svp.h>
++#endif
++
++#ifdef __cplusplus
++extern "C" {
++#endif /* __cplusplus */
++
++/* Vector path set operations, over sorted vpaths. */
++
++ArtSVP *art_svp_union (const ArtSVP *svp1, const ArtSVP *svp2);
++ArtSVP *art_svp_intersect (const ArtSVP *svp1, const ArtSVP *svp2);
++ArtSVP *art_svp_diff (const ArtSVP *svp1, const ArtSVP *svp2);
++ArtSVP *art_svp_minus (const ArtSVP *svp1, const ArtSVP *svp2);
++
++#ifdef __cplusplus
++}
++#endif /* __cplusplus */
++
++#endif /* __ART_SVP_OPS_H__ */
+diff -u -r --new-file tools/source/generic/libart_lgpl/art_svp_vpath.c tools/source/generic/libart_lgpl/art_svp_vpath.c
+--- tools/source/generic/libart_lgpl/art_svp_vpath.c 1970-01-01 01:00:00.000000000 +0100
++++ tools/source/generic/libart_lgpl/art_svp_vpath.c 2004-04-06 17:49:09.000000000 +0100
+@@ -0,0 +1,215 @@
++/* Libart_LGPL - library of basic graphic primitives
++ * Copyright (C) 1998-2000 Raph Levien
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the
++ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
++ * Boston, MA 02111-1307, USA.
++ */
++
++/* Sort vector paths into sorted vector paths */
++
++#include "config.h"
++#include "art_svp_vpath.h"
++
++#include <stdlib.h>
++#include <math.h>
++
++#include "art_misc.h"
++
++#include "art_vpath.h"
++#include "art_svp.h"
++
++
++/* reverse a list of points in place */
++static void
++reverse_points (ArtPoint *points, int n_points)
++{
++ int i;
++ ArtPoint tmp_p;
++
++ for (i = 0; i < (n_points >> 1); i++)
++ {
++ tmp_p = points[i];
++ points[i] = points[n_points - (i + 1)];
++ points[n_points - (i + 1)] = tmp_p;
++ }
++}
++
++/**
++ * art_svp_from_vpath: Convert a vpath to a sorted vector path.
++ * @vpath: #ArtVPath to convert.
++ *
++ * Converts a vector path into sorted vector path form. The svp form is
++ * more efficient for rendering and other vector operations.
++ *
++ * Basically, the implementation is to traverse the vector path,
++ * generating a new segment for each "run" of points in the vector
++ * path with monotonically increasing Y values. All the resulting
++ * values are then sorted.
++ *
++ * Note: I'm not sure that the sorting rule is correct with respect
++ * to numerical stability issues.
++ *
++ * Return value: Resulting sorted vector path.
++ **/
++ArtSVP *
++art_svp_from_vpath (ArtVpath *vpath)
++{
++ int n_segs, n_segs_max;
++ ArtSVP *svp;
++ int dir;
++ int new_dir;
++ int i;
++ ArtPoint *points;
++ int n_points, n_points_max;
++ double x, y;
++ double x_min, x_max;
++
++ n_segs = 0;
++ n_segs_max = 16;
++ svp = (ArtSVP *)art_alloc (sizeof(ArtSVP) +
++ (n_segs_max - 1) * sizeof(ArtSVPSeg));
++
++ dir = 0;
++ n_points = 0;
++ n_points_max = 0;
++ points = NULL;
++ i = 0;
++
++ x = y = 0; /* unnecessary, given "first code must not be LINETO" invariant,
++ but it makes gcc -Wall -ansi -pedantic happier */
++ x_min = x_max = 0; /* same */
++
++ while (vpath[i].code != ART_END) {
++ if (vpath[i].code == ART_MOVETO || vpath[i].code == ART_MOVETO_OPEN)
++ {
++ if (points != NULL && n_points >= 2)
++ {
++ if (n_segs == n_segs_max)
++ {
++ n_segs_max <<= 1;
++ svp = (ArtSVP *)art_realloc (svp, sizeof(ArtSVP) +
++ (n_segs_max - 1) *
++ sizeof(ArtSVPSeg));
++ }
++ svp->segs[n_segs].n_points = n_points;
++ svp->segs[n_segs].dir = (dir > 0);
++ if (dir < 0)
++ reverse_points (points, n_points);
++ svp->segs[n_segs].points = points;
++ svp->segs[n_segs].bbox.x0 = x_min;
++ svp->segs[n_segs].bbox.x1 = x_max;
++ svp->segs[n_segs].bbox.y0 = points[0].y;
++ svp->segs[n_segs].bbox.y1 = points[n_points - 1].y;
++ n_segs++;
++ points = NULL;
++ }
++
++ if (points == NULL)
++ {
++ n_points_max = 4;
++ points = art_new (ArtPoint, n_points_max);
++ }
++
++ n_points = 1;
++ points[0].x = x = vpath[i].x;
++ points[0].y = y = vpath[i].y;
++ x_min = x;
++ x_max = x;
++ dir = 0;
++ }
++ else /* must be LINETO */
++ {
++ new_dir = (vpath[i].y > y ||
++ (vpath[i].y == y && vpath[i].x > x)) ? 1 : -1;
++ if (dir && dir != new_dir)
++ {
++ /* new segment */
++ x = points[n_points - 1].x;
++ y = points[n_points - 1].y;
++ if (n_segs == n_segs_max)
++ {
++ n_segs_max <<= 1;
++ svp = (ArtSVP *)art_realloc (svp, sizeof(ArtSVP) +
++ (n_segs_max - 1) *
++ sizeof(ArtSVPSeg));
++ }
++ svp->segs[n_segs].n_points = n_points;
++ svp->segs[n_segs].dir = (dir > 0);
++ if (dir < 0)
++ reverse_points (points, n_points);
++ svp->segs[n_segs].points = points;
++ svp->segs[n_segs].bbox.x0 = x_min;
++ svp->segs[n_segs].bbox.x1 = x_max;
++ svp->segs[n_segs].bbox.y0 = points[0].y;
++ svp->segs[n_segs].bbox.y1 = points[n_points - 1].y;
++ n_segs++;
++
++ n_points = 1;
++ n_points_max = 4;
++ points = art_new (ArtPoint, n_points_max);
++ points[0].x = x;
++ points[0].y = y;
++ x_min = x;
++ x_max = x;
++ }
++
++ if (points != NULL)
++ {
++ if (n_points == n_points_max)
++ art_expand (points, ArtPoint, n_points_max);
++ points[n_points].x = x = vpath[i].x;
++ points[n_points].y = y = vpath[i].y;
++ if (x < x_min) x_min = x;
++ else if (x > x_max) x_max = x;
++ n_points++;
++ }
++ dir = new_dir;
++ }
++ i++;
++ }
++
++ if (points != NULL)
++ {
++ if (n_points >= 2)
++ {
++ if (n_segs == n_segs_max)
++ {
++ n_segs_max <<= 1;
++ svp = (ArtSVP *)art_realloc (svp, sizeof(ArtSVP) +
++ (n_segs_max - 1) *
++ sizeof(ArtSVPSeg));
++ }
++ svp->segs[n_segs].n_points = n_points;
++ svp->segs[n_segs].dir = (dir > 0);
++ if (dir < 0)
++ reverse_points (points, n_points);
++ svp->segs[n_segs].points = points;
++ svp->segs[n_segs].bbox.x0 = x_min;
++ svp->segs[n_segs].bbox.x1 = x_max;
++ svp->segs[n_segs].bbox.y0 = points[0].y;
++ svp->segs[n_segs].bbox.y1 = points[n_points - 1].y;
++ n_segs++;
++ }
++ else
++ art_free (points);
++ }
++
++ svp->n_segs = n_segs;
++
++ qsort (&svp->segs, n_segs, sizeof (ArtSVPSeg), art_svp_seg_compare);
++
++ return svp;
++}
++
+diff -u -r --new-file tools/source/generic/libart_lgpl/art_svp_vpath.h tools/source/generic/libart_lgpl/art_svp_vpath.h
+--- tools/source/generic/libart_lgpl/art_svp_vpath.h 1970-01-01 01:00:00.000000000 +0100
++++ tools/source/generic/libart_lgpl/art_svp_vpath.h 2004-04-06 17:49:09.000000000 +0100
+@@ -0,0 +1,44 @@
++/* Libart_LGPL - library of basic graphic primitives
++ * Copyright (C) 1998 Raph Levien
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the
++ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
++ * Boston, MA 02111-1307, USA.
++ */
++
++#ifndef __ART_SVP_VPATH_H__
++#define __ART_SVP_VPATH_H__
++
++#ifdef LIBART_COMPILATION
++#include "art_svp.h"
++#include "art_vpath.h"
++#else
++#include <libart_lgpl/art_svp.h>
++#include <libart_lgpl/art_vpath.h>
++#endif
++
++/* Sort vector paths into sorted vector paths. */
++
++#ifdef __cplusplus
++extern "C" {
++#endif /* __cplusplus */
++
++ArtSVP *
++art_svp_from_vpath (ArtVpath *vpath);
++
++#ifdef __cplusplus
++}
++#endif /* __cplusplus */
++
++#endif /* __ART_SVP_VPATH_H__ */
+diff -u -r --new-file tools/source/generic/libart_lgpl/art_vpath.c tools/source/generic/libart_lgpl/art_vpath.c
+--- tools/source/generic/libart_lgpl/art_vpath.c 1970-01-01 01:00:00.000000000 +0100
++++ tools/source/generic/libart_lgpl/art_vpath.c 2004-04-06 17:49:16.000000000 +0100
+@@ -0,0 +1,241 @@
++/* Libart_LGPL - library of basic graphic primitives
++ * Copyright (C) 1998-2000 Raph Levien
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the
++ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
++ * Boston, MA 02111-1307, USA.
++ */
++
++/* Basic constructors and operations for vector paths */
++
++#include "config.h"
++#include "art_vpath.h"
++
++#include <math.h>
++#include <stdlib.h>
++
++#include "art_misc.h"
++
++#include "art_rect.h"
++
++/**
++ * art_vpath_add_point: Add point to vpath.
++ * @p_vpath: Where the pointer to the #ArtVpath structure is stored.
++ * @pn_points: Pointer to the number of points in *@p_vpath.
++ * @pn_points_max: Pointer to the number of points allocated.
++ * @code: The pathcode for the new point.
++ * @x: The X coordinate of the new point.
++ * @y: The Y coordinate of the new point.
++ *
++ * Adds a new point to *@p_vpath, reallocating and updating *@p_vpath
++ * and *@pn_points_max as necessary. *@pn_points is incremented.
++ *
++ * This routine always adds the point after all points already in the
++ * vpath. Thus, it should be called in the order the points are
++ * desired.
++ **/
++void
++art_vpath_add_point (ArtVpath **p_vpath, int *pn_points, int *pn_points_max,
++ ArtPathcode code, double x, double y)
++{
++ int i;
++
++ i = (*pn_points)++;
++ if (i == *pn_points_max)
++ art_expand (*p_vpath, ArtVpath, *pn_points_max);
++ (*p_vpath)[i].code = code;
++ (*p_vpath)[i].x = x;
++ (*p_vpath)[i].y = y;
++}
++
++/* number of steps should really depend on radius. */
++#define CIRCLE_STEPS 128
++
++/**
++ * art_vpath_new_circle: Create a new circle.
++ * @x: X coordinate of center.
++ * @y: Y coordinate of center.
++ * @r: radius.
++ *
++ * Creates a new polygon closely approximating a circle with center
++ * (@x, @y) and radius @r. Currently, the number of points used in the
++ * approximation is fixed, but that will probably change.
++ *
++ * Return value: The newly created #ArtVpath.
++ **/
++ArtVpath *
++art_vpath_new_circle (double x, double y, double r)
++{
++ int i;
++ ArtVpath *vec;
++ double theta;
++
++ vec = art_new (ArtVpath, CIRCLE_STEPS + 2);
++
++ for (i = 0; i < CIRCLE_STEPS + 1; i++)
++ {
++ vec[i].code = i ? ART_LINETO : ART_MOVETO;
++ theta = (i & (CIRCLE_STEPS - 1)) * (M_PI * 2.0 / CIRCLE_STEPS);
++ vec[i].x = x + r * cos (theta);
++ vec[i].y = y - r * sin (theta);
++ }
++ vec[i].code = ART_END;
++
++ return vec;
++}
++
++/**
++ * art_vpath_affine_transform: Affine transform a vpath.
++ * @src: Source vpath to transform.
++ * @matrix: Affine transform.
++ *
++ * Computes the affine transform of the vpath, using @matrix as the
++ * transform. @matrix is stored in the same format as PostScript, ie.
++ * x' = @matrix[0] * x + @matrix[2] * y + @matrix[4]
++ * y' = @matrix[1] * x + @matrix[3] * y + @matrix[5]
++ *
++ * Return value: the newly allocated vpath resulting from the transform.
++**/
++ArtVpath *
++art_vpath_affine_transform (const ArtVpath *src, const double matrix[6])
++{
++ int i;
++ int size;
++ ArtVpath *new;
++ double x, y;
++
++ for (i = 0; src[i].code != ART_END; i++);
++ size = i;
++
++ new = art_new (ArtVpath, size + 1);
++
++ for (i = 0; i < size; i++)
++ {
++ new[i].code = src[i].code;
++ x = src[i].x;
++ y = src[i].y;
++ new[i].x = matrix[0] * x + matrix[2] * y + matrix[4];
++ new[i].y = matrix[1] * x + matrix[3] * y + matrix[5];
++ }
++ new[i].code = ART_END;
++
++ return new;
++}
++
++/**
++ * art_vpath_bbox_drect: Determine bounding box of vpath.
++ * @vec: Source vpath.
++ * @drect: Where to store bounding box.
++ *
++ * Determines bounding box of @vec, and stores it in @drect.
++ **/
++void
++art_vpath_bbox_drect (const ArtVpath *vec, ArtDRect *drect)
++{
++ int i;
++ double x0, y0, x1, y1;
++
++ if (vec[0].code == ART_END)
++ {
++ x0 = y0 = x1 = y1 = 0;
++ }
++ else
++ {
++ x0 = x1 = vec[0].x;
++ y0 = y1 = vec[0].y;
++ for (i = 1; vec[i].code != ART_END; i++)
++ {
++ if (vec[i].x < x0) x0 = vec[i].x;
++ if (vec[i].x > x1) x1 = vec[i].x;
++ if (vec[i].y < y0) y0 = vec[i].y;
++ if (vec[i].y > y1) y1 = vec[i].y;
++ }
++ }
++ drect->x0 = x0;
++ drect->y0 = y0;
++ drect->x1 = x1;
++ drect->y1 = y1;
++}
++
++/**
++ * art_vpath_bbox_irect: Determine integer bounding box of vpath.
++ * @vec: Source vpath.
++ * idrect: Where to store bounding box.
++ *
++ * Determines integer bounding box of @vec, and stores it in @irect.
++ **/
++void
++art_vpath_bbox_irect (const ArtVpath *vec, ArtIRect *irect)
++{
++ ArtDRect drect;
++
++ art_vpath_bbox_drect (vec, &drect);
++ art_drect_to_irect (irect, &drect);
++}
++
++#define PERTURBATION 2e-3
++
++/**
++ * art_vpath_perturb: Perturb each point in vpath by small random amount.
++ * @src: Source vpath.
++ *
++ * Perturbs each of the points by a small random amount. This is
++ * helpful for cheating in cases when algorithms haven't attained
++ * numerical stability yet.
++ *
++ * Return value: Newly allocated vpath containing perturbed @src.
++ **/
++ArtVpath *
++art_vpath_perturb (ArtVpath *src)
++{
++ int i;
++ int size;
++ ArtVpath *new;
++ double x, y;
++ double x_start, y_start;
++ int open;
++
++ for (i = 0; src[i].code != ART_END; i++);
++ size = i;
++
++ new = art_new (ArtVpath, size + 1);
++
++ x_start = 0;
++ y_start = 0;
++ open = 0;
++ for (i = 0; i < size; i++)
++ {
++ new[i].code = src[i].code;
++ x = src[i].x + (PERTURBATION * rand ()) / RAND_MAX - PERTURBATION * 0.5;
++ y = src[i].y + (PERTURBATION * rand ()) / RAND_MAX - PERTURBATION * 0.5;
++ if (src[i].code == ART_MOVETO)
++ {
++ x_start = x;
++ y_start = y;
++ open = 0;
++ }
++ else if (src[i].code == ART_MOVETO_OPEN)
++ open = 1;
++ if (!open && (i + 1 == size || src[i + 1].code != ART_LINETO))
++ {
++ x = x_start;
++ y = y_start;
++ }
++ new[i].x = x;
++ new[i].y = y;
++ }
++ new[i].code = ART_END;
++
++ return new;
++}
+diff -u -r --new-file tools/source/generic/libart_lgpl/art_vpath.h tools/source/generic/libart_lgpl/art_vpath.h
+--- tools/source/generic/libart_lgpl/art_vpath.h 1970-01-01 01:00:00.000000000 +0100
++++ tools/source/generic/libart_lgpl/art_vpath.h 2004-04-06 17:49:16.000000000 +0100
+@@ -0,0 +1,71 @@
++/* Libart_LGPL - library of basic graphic primitives
++ * Copyright (C) 1998 Raph Levien
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the
++ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
++ * Boston, MA 02111-1307, USA.
++ */
++
++#ifndef __ART_VPATH_H__
++#define __ART_VPATH_H__
++
++#ifdef LIBART_COMPILATION
++#include "art_rect.h"
++#include "art_pathcode.h"
++#else
++#include <libart_lgpl/art_rect.h>
++#include <libart_lgpl/art_pathcode.h>
++#endif
++
++/* Basic data structures and constructors for simple vector paths */
++
++#ifdef __cplusplus
++extern "C" {
++#endif /* __cplusplus */
++
++typedef struct _ArtVpath ArtVpath;
++
++/* CURVETO is not allowed! */
++struct _ArtVpath {
++ ArtPathcode code;
++ double x;
++ double y;
++};
++
++/* Some of the functions need to go into their own modules */
++
++void
++art_vpath_add_point (ArtVpath **p_vpath, int *pn_points, int *pn_points_max,
++ ArtPathcode code, double x, double y);
++
++ArtVpath *
++art_vpath_new_circle (double x, double y, double r);
++
++ArtVpath *
++art_vpath_affine_transform (const ArtVpath *src, const double matrix[6]);
++
++void
++art_vpath_bbox_drect (const ArtVpath *vec, ArtDRect *drect);
++
++void
++art_vpath_bbox_irect (const ArtVpath *vec, ArtIRect *irect);
++
++ArtVpath *
++art_vpath_perturb (ArtVpath *src);
++
++#ifdef __cplusplus
++}
++#endif /* __cplusplus */
++
++#endif /* __ART_VPATH_H__ */
+diff -u -r --new-file tools/source/generic/libart_lgpl/art_vpath_svp.c tools/source/generic/libart_lgpl/art_vpath_svp.c
+--- tools/source/generic/libart_lgpl/art_vpath_svp.c 1970-01-01 01:00:00.000000000 +0100
++++ tools/source/generic/libart_lgpl/art_vpath_svp.c 2004-04-06 17:49:23.000000000 +0100
+@@ -0,0 +1,196 @@
++/* Libart_LGPL - library of basic graphic primitives
++ * Copyright (C) 1998-2000 Raph Levien
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the
++ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
++ * Boston, MA 02111-1307, USA.
++ */
++
++/* "Unsort" a sorted vector path into an ordinary vector path. */
++
++#include "config.h"
++#include "art_vpath_svp.h"
++
++#include <stdio.h> /* for printf - debugging */
++#include "art_misc.h"
++
++#include "art_vpath.h"
++#include "art_svp.h"
++
++typedef struct _ArtVpathSVPEnd ArtVpathSVPEnd;
++
++struct _ArtVpathSVPEnd {
++ int seg_num;
++ int which; /* 0 = top, 1 = bottom */
++ double x, y;
++};
++
++#define EPSILON 1e-6
++
++static int
++art_vpath_svp_point_compare (double x1, double y1, double x2, double y2)
++{
++ if (y1 - EPSILON > y2) return 1;
++ if (y1 + EPSILON < y2) return -1;
++ if (x1 - EPSILON > x2) return 1;
++ if (x1 + EPSILON < x2) return -1;
++ return 0;
++}
++
++static int
++art_vpath_svp_compare (const void *s1, const void *s2)
++{
++ const ArtVpathSVPEnd *e1 = s1;
++ const ArtVpathSVPEnd *e2 = s2;
++
++ return art_vpath_svp_point_compare (e1->x, e1->y, e2->x, e2->y);
++}
++
++/* Convert from sorted vector path representation into regular
++ vector path representation.
++
++ Status of this routine:
++
++ Basic correctness: Only works with closed paths.
++
++ Numerical stability: Not known to work when more than two segments
++ meet at a point.
++
++ Speed: Should be pretty good.
++
++ Precision: Does not degrade precision.
++
++*/
++/**
++ * art_vpath_from_svp: Convert from svp to vpath form.
++ * @svp: Original #ArtSVP.
++ *
++ * Converts the sorted vector path @svp into standard vpath form.
++ *
++ * Return value: the newly allocated vpath.
++ **/
++ArtVpath *
++art_vpath_from_svp (const ArtSVP *svp)
++{
++ int n_segs = svp->n_segs;
++ ArtVpathSVPEnd *ends;
++ ArtVpath *new;
++ int *visited;
++ int n_new, n_new_max;
++ int i, k;
++ int j = 0; /* Quiet compiler */
++ int seg_num;
++ int first;
++ double last_x, last_y;
++ int n_points;
++ int pt_num;
++
++ last_x = 0; /* to eliminate "uninitialized" warning */
++ last_y = 0;
++
++ ends = art_new (ArtVpathSVPEnd, n_segs * 2);
++ for (i = 0; i < svp->n_segs; i++)
++ {
++ int lastpt;
++
++ ends[i * 2].seg_num = i;
++ ends[i * 2].which = 0;
++ ends[i * 2].x = svp->segs[i].points[0].x;
++ ends[i * 2].y = svp->segs[i].points[0].y;
++
++ lastpt = svp->segs[i].n_points - 1;
++ ends[i * 2 + 1].seg_num = i;
++ ends[i * 2 + 1].which = 1;
++ ends[i * 2 + 1].x = svp->segs[i].points[lastpt].x;
++ ends[i * 2 + 1].y = svp->segs[i].points[lastpt].y;
++ }
++ qsort (ends, n_segs * 2, sizeof (ArtVpathSVPEnd), art_vpath_svp_compare);
++
++ n_new = 0;
++ n_new_max = 16; /* I suppose we _could_ estimate this from traversing
++ the svp, so we don't have to reallocate */
++ new = art_new (ArtVpath, n_new_max);
++
++ visited = art_new (int, n_segs);
++ for (i = 0; i < n_segs; i++)
++ visited[i] = 0;
++
++ first = 1;
++ for (i = 0; i < n_segs; i++)
++ {
++ if (!first)
++ {
++ /* search for the continuation of the existing subpath */
++ /* This could be a binary search (which is why we sorted, above) */
++ for (j = 0; j < n_segs * 2; j++)
++ {
++ if (!visited[ends[j].seg_num] &&
++ art_vpath_svp_point_compare (last_x, last_y,
++ ends[j].x, ends[j].y) == 0)
++ break;
++ }
++ if (j == n_segs * 2)
++ first = 1;
++ }
++ if (first)
++ {
++ /* start a new subpath */
++ for (j = 0; j < n_segs * 2; j++)
++ if (!visited[ends[j].seg_num])
++ break;
++ }
++ if (j == n_segs * 2)
++ {
++ printf ("failure\n");
++ }
++ seg_num = ends[j].seg_num;
++ n_points = svp->segs[seg_num].n_points;
++ for (k = 0; k < n_points; k++)
++ {
++ pt_num = svp->segs[seg_num].dir ? k : n_points - (1 + k);
++ if (k == 0)
++ {
++ if (first)
++ {
++ art_vpath_add_point (&new, &n_new, &n_new_max,
++ ART_MOVETO,
++ svp->segs[seg_num].points[pt_num].x,
++ svp->segs[seg_num].points[pt_num].y);
++ }
++ }
++ else
++ {
++ art_vpath_add_point (&new, &n_new, &n_new_max,
++ ART_LINETO,
++ svp->segs[seg_num].points[pt_num].x,
++ svp->segs[seg_num].points[pt_num].y);
++ if (k == n_points - 1)
++ {
++ last_x = svp->segs[seg_num].points[pt_num].x;
++ last_y = svp->segs[seg_num].points[pt_num].y;
++ /* to make more robust, check for meeting first_[xy],
++ set first if so */
++ }
++ }
++ first = 0;
++ }
++ visited[seg_num] = 1;
++ }
++
++ art_vpath_add_point (&new, &n_new, &n_new_max,
++ ART_END, 0, 0);
++ art_free (visited);
++ art_free (ends);
++ return new;
++}
+diff -u -r --new-file tools/source/generic/libart_lgpl/art_vpath_svp.h tools/source/generic/libart_lgpl/art_vpath_svp.h
+--- tools/source/generic/libart_lgpl/art_vpath_svp.h 1970-01-01 01:00:00.000000000 +0100
++++ tools/source/generic/libart_lgpl/art_vpath_svp.h 2004-04-06 17:49:23.000000000 +0100
+@@ -0,0 +1,43 @@
++/* Libart_LGPL - library of basic graphic primitives
++ * Copyright (C) 1998 Raph Levien
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the
++ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
++ * Boston, MA 02111-1307, USA.
++ */
++
++#ifndef __ART_VPATH_SVP_H__
++#define __ART_VPATH_SVP_H__
++
++/* "Unsort" a sorted vector path into an ordinary vector path. */
++
++#ifdef LIBART_COMPILATION
++#include "art_svp.h"
++#include "art_vpath.h"
++#else
++#include <libart_lgpl/art_svp.h>
++#include <libart_lgpl/art_vpath.h>
++#endif
++
++#ifdef __cplusplus
++extern "C" {
++#endif /* __cplusplus */
++
++ArtVpath *art_vpath_from_svp (const ArtSVP *svp);
++
++#ifdef __cplusplus
++}
++#endif /* __cplusplus */
++
++#endif /* __ART_VPATH_SVP_H__ */
+diff -u -r --new-file tools/source/generic/libart_lgpl/makefile.mk tools/source/generic/libart_lgpl/makefile.mk
+--- tools/source/generic/libart_lgpl/makefile.mk 1970-01-01 01:00:00.000000000 +0100
++++ tools/source/generic/libart_lgpl/makefile.mk 2004-04-06 17:50:44.000000000 +0100
+@@ -0,0 +1,93 @@
++#*************************************************************************
++#
++# $RCSfile$
++#
++# $Revision$
++#
++# last change: $Author$ $Date$
++#
++# The Contents of this file are made available subject to the terms of
++# either of the following licenses
++#
++# - GNU Lesser General Public License Version 2.1
++# - Sun Industry Standards Source License Version 1.1
++#
++# Sun Microsystems Inc., October, 2000
++#
++# GNU Lesser General Public License Version 2.1
++# =============================================
++# Copyright 2000 by Sun Microsystems, Inc.
++# 901 San Antonio Road, Palo Alto, CA 94303, USA
++#
++# This library is free software; you can redistribute it and/or
++# modify it under the terms of the GNU Lesser General Public
++# License version 2.1, as published by the Free Software Foundation.
++#
++# This library 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
++# Lesser General Public License for more details.
++#
++# You should have received a copy of the GNU Lesser General Public
++# License along with this library; if not, write to the Free Software
++# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
++# MA 02111-1307 USA
++#
++#
++# Sun Industry Standards Source License Version 1.1
++# =================================================
++# The contents of this file are subject to the Sun Industry Standards
++# Source 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.openoffice.org/license.html.
++#
++# Software provided under this License is provided on an "AS IS" basis,
++# WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
++# WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
++# MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
++# See the License for the specific provisions governing your rights and
++# obligations concerning the Software.
++#
++# The Initial Developer of the Original Code is: Sun Microsystems, Inc.
++#
++# Copyright: 2000 by Sun Microsystems, Inc.
++#
++# All Rights Reserved.
++#
++# Contributor(s): _______________________________________
++#
++#
++#
++#*************************************************************************
++
++PRJ=..$/..$/..
++
++PRJNAME=tools
++TARGET=libart
++VERSION=$(UPD)
++
++# --- Settings -----------------------------------------------------
++
++.INCLUDE : svpre.mk
++.INCLUDE : settings.mk
++.INCLUDE : sv.mk
++
++# --- Files --------------------------------------------------------
++
++INCPRE=..
++# This is a nasty hack - but then so is everything to
++# do with the Windows build it seems.
++SLOFILES = $(SLO)$/art_svp_intersect.obj $(SLO)$/art_misc.obj \
++ $(SLO)$/art_rect.obj $(SLO)$/art_svp.obj \
++ $(SLO)$/art_svp_ops.obj $(SLO)$/art_svp_vpath.obj \
++ $(SLO)$/art_vpath.obj $(SLO)$/art_vpath_svp.obj
++SHL1LIBS=$(LIB1TARGET)
++SHL1TARGET = libart
++SHL1IMPLIB = $(TARGET)
++SHL1LIBS = $(SLB)$/$(TARGET).lib
++DEF1NAME=$(SHL1TARGET)
++
++
++# --- Targets ------------------------------------------------------
++
++.INCLUDE : target.mk
+
+--- /source/generic/libart_lgpl/config.h
++++ tools/source/generic/libart_lgpl/config.h
+@@ -0,0 +1 @@
++/* this page deliberately left blank */
+
diff --git a/patches/src680/win32-libart-build.diff b/patches/src680/win32-libart-build.diff
new file mode 100644
index 000000000..34b408eda
--- /dev/null
+++ b/patches/src680/win32-libart-build.diff
@@ -0,0 +1,106 @@
+Index: tools/prj/build.lst
+===================================================================
+RCS file: /cvs/util/tools/prj/build.lst,v
+retrieving revision 1.13
+diff -u -p -u -r1.13 build.lst
+--- tools/prj/build.lst 24 Apr 2003 13:27:35 -0000 1.13
++++ tools/prj/build.lst 6 Apr 2004 17:44:36 -0000
+@@ -11,7 +11,8 @@ tl tools\prj usr7 - all tl_deliver
+ tl tools\prj usr7 - all tl_deliver NULL
+ tl tools\prj usr42 - all tl_zn NULL
+ tl tools\source\testtoolloader nmake - all tl_ttloader NULL
+-tl tools\source\generic nmake - all tl_gen tl_fsys NULL
++tl tools\source\generic\libart_lgpl nmake - all tl_libart NULL
++tl tools\source\generic nmake - all tl_gen tl_libart tl_fsys tl_sol.u NULL
+ tl tools\source\memtools nmake - all tl_mem tl_fsys NULL
+ tl tools\source\memmgr nmake - all tl_mgr tl_fsys NULL
+ tl tools\source\debug nmake - all tl_deb tl_fsys NULL
+
+
+Index: tools/prj/d.lst
+===================================================================
+RCS file: /cvs/util/tools/prj/d.lst,v
+retrieving revision 1.24.56.1
+diff -u -p -u -r1.24.56.1 d.lst
+--- tools/prj/d.lst 28 Jan 2004 10:54:29 -0000 1.24.56.1
++++ tools/prj/d.lst 6 Apr 2004 17:44:36 -0000
+@@ -29,6 +29,8 @@ mkdir: %_DEST%\inc%_EXT%\testshl
+ ..\%__SRC%\slb\btstrpsh.lib %_DEST%\lib%_EXT%\btstrpsh.lib
+ ..\%__SRC%\lib\tstutil.lib %_DEST%\lib%_EXT%\tstutil.lib
+ ..\%__SRC%\bin\testshl.exe %_DEST%\bin%_EXT%\testshl.exe
++..\%__SRC%\bin\libart.dll %_DEST%\bin%_EXT%\libart.dll
++..\%__SRC%\lib\libart.lib %_DEST%\lib%_EXT%\libart.lib
+
+
+ hedabu: ..\%__SRC%\inc\svconf.h %_DEST%\inc%_EXT%\tools\svconf.h
+Index: tools/source/generic/makefile.mk
+===================================================================
+RCS file: /cvs/util/tools/source/generic/makefile.mk,v
+retrieving revision 1.7
+diff -u -p -u -r1.7 makefile.mk
+--- tools/source/generic/makefile.mk 16 Jul 2003 17:15:14 -0000 1.7
++++ tools/source/generic/makefile.mk 6 Apr 2004 17:44:36 -0000
+@@ -71,13 +71,8 @@ TARGET=gen
+ .INCLUDE : settings.mk
+ .INCLUDE : sv.mk
+
+-.IF "$(WITH_GPC)"!="NO"
+-CDEFS+=-DHAVE_GPC_H
+-.ENDIF
+-.IF "$(WITH_LIBART)"!="NO"
+ CDEFS+=-DHAVE_LIBART_H
+-CFLAGS+=$(LIBART_CFLAGS)
+-.ENDIF
++INCPRE+=libart_lgpl
+
+ # --- Files --------------------------------------------------------
+
+
+Index: config_office/configure.in
+===================================================================
+RCS file: /cvs/tools/config_office/configure.in,v
+retrieving revision 1.55.6.7
+diff -u -p -u -r1.55.6.7 configure.in
+--- config_office/configure.in 19 Feb 2004 10:59:25 -0000 1.55.6.7
++++ config_office/configure.in 6 Apr 2004 17:47:13 -0000
+@@ -2457,7 +2457,6 @@ WITH_GPC=NO
+ WITH_LIBART=NO
+
+ if test -n "$enable_libart"; then
+- PKG_CHECK_MODULES( LIBART, libart-2.0 >= 2.3.13 )
+ WITH_LIBART=YES
+
+ elif test "$with_gpc" != "no" ; then
+
+
+Index: tools/util/makefile.mk
+===================================================================
+RCS file: /cvs/util/tools/util/makefile.mk,v
+retrieving revision 1.11.12.1
+diff -u -p -u -r1.11.12.1 makefile.mk
+--- tools/util/makefile.mk 15 Aug 2003 11:30:50 -0000 1.11.12.1
++++ tools/util/makefile.mk 6 Apr 2004 19:57:47 -0000
+@@ -142,7 +142,8 @@ LIB7FILES= $(LB)$/gen.lib \
+ $(LB)$/ref.lib \
+ $(LB)$/rc.lib \
+ $(LB)$/inet.lib \
+- $(LB)$/debug.lib
++ $(LB)$/debug.lib \
++ $(LB)$/libart.lib
+
+
+ LIB7FILES+= $(LB)$/dll.lib
+@@ -199,12 +200,7 @@ SHL1LIBS= $(LIB1TARGET)
+ SHL1DEF= $(MISC)$/$(SHL1TARGET).def
+ SHL1IMPLIB= itools
+ SHL1STDLIBS+= $(SALLIB) $(VOSLIB) $(BASEGFXLIB)
+-
+-.IF "$(WITH_LIBART)"=="YES"
+-SHL1STDLIBS+= $(LIBART_LIBS)
+-.ELSE
+-SHL1STDLIBS+= $(GPC3RDLIB)
+-.ENDIF
++SHL1STDLIBS+= $(SLB)$/libart.lib
+
+
+ .IF "$(GUI)"=="WNT"
diff --git a/src/openabout_nld.png b/src/openabout_nld.png
new file mode 100644
index 000000000..42ae90cd9
--- /dev/null
+++ b/src/openabout_nld.png
Binary files differ
diff --git a/src/openintro_nld.png b/src/openintro_nld.png
new file mode 100644
index 000000000..096fc42f9
--- /dev/null
+++ b/src/openintro_nld.png
Binary files differ