diff options
author | nobody <nobody@gnome.org> | 2005-01-25 12:31:44 +0000 |
---|---|---|
committer | nobody <nobody@gnome.org> | 2005-01-25 12:31:44 +0000 |
commit | d3c859d05d0c4972ec99ac4c13f45a00fc886ae5 (patch) | |
tree | c68e48ba3b085a8231d438f549a29091cd9da5aa | |
parent | 75184c2309143d2e132324000c04b5aa50732abe (diff) |
This commit was manufactured by cvs2svn to create tagOOO_BUILD_1_9_72-second_try
'OOO_BUILD_1_9_72-second_try'.
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 Binary files differnew file mode 100644 index 000000000..42ae90cd9 --- /dev/null +++ b/src/openabout_nld.png diff --git a/src/openintro_nld.png b/src/openintro_nld.png Binary files differnew file mode 100644 index 000000000..096fc42f9 --- /dev/null +++ b/src/openintro_nld.png |