<commit_before>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#ifndef _SVDETC_HXX
#define _SVDETC_HXX

#include <tools/string.hxx>
#include <tools/contnr.hxx>

#include <vcl/outdev.hxx>
#include <tools/shl.hxx>
#include <editeng/outliner.hxx>
#include "svx/svxdllapi.h"

////////////////////////////////////////////////////////////////////////////////////////////////////

// ExchangeFormat-Id der DrawingEngine holen. Daten koennen dann per
//   static BOOL CopyData(pData,nLen,nFormat);
// bereitgestellt werden, wobei pData/nLen einen SvMemoryStream beschreiben in
// dem ein SdrModel gestreamt wird an dem fuer die Zeitdauer des Streamens das
// Flag SdrModel::SetStreamingSdrModel(TRUE) gesetzt wird.
// ULONG SdrGetExchangeFormat(); -- JP 18.01.99 - dafuer gibt es ein define

class SdrOutliner;
class SdrModel;
class SvtSysLocale;
class CharClass;
class LocaleDataWrapper;

namespace com { namespace sun { namespace star { namespace lang {
    struct Locale;
}}}}

// Einen Outliner mit den engineglobalen
// Defaulteinstellungen auf dem Heap erzeugen.
// Ist pMod<>NULL, dann wird der MapMode des uebergebenen
// Models verwendet. Die resultierende Default-Fonthoehe bleibt
// jedoch dieselbe (die logische Fonthoehe wird umgerechnet).
SVX_DLLPUBLIC SdrOutliner* SdrMakeOutliner( USHORT nOutlinerMode, SdrModel* pMod );

// Globale Defaulteinstellungen fuer die DrawingEngine.
// Diese Einstellungen sollte man direkt beim Applikationsstart
// vornehmen, noch bevor andere Methoden der Engine gerufen werden.
class SVX_DLLPUBLIC SdrEngineDefaults
{
friend class SdrAttrObj;
    String     aFontName;
    FontFamily eFontFamily;
    Color      aFontColor;
    ULONG      nFontHeight;
    MapUnit    eMapUnit;
    Fraction   aMapFraction;

private:
    static SdrEngineDefaults& GetDefaults();

public:
    SdrEngineDefaults();
    // Default Fontname ist "Times New Roman"
    static void       SetFontName(const String& rFontName) { GetDefaults().aFontName=rFontName; }
    static String     GetFontName()                        { return GetDefaults().aFontName; }
    // Default FontFamily ist FAMILY_ROMAN
    static void       SetFontFamily(FontFamily eFam)       { GetDefaults().eFontFamily=eFam; }
    static FontFamily GetFontFamily()                      { return GetDefaults().eFontFamily; }
    // Default FontColor ist COL_BLACK
    static void       SetFontColor(const Color& rColor)    { GetDefaults().aFontColor=rColor; }
    static Color      GetFontColor()                       { return GetDefaults().aFontColor; }
    // Default FontHeight ist 847. Die Fonthoehe wird in logischen Einheiten
    // (MapUnit/MapFraction (siehe unten)) angegeben. Die Defaulteinstellung
    // 847/100mm entspricht also ca. 24 Point. Verwendet man stattdessen
    // beispielsweise Twips (SetMapUnit(MAP_TWIP)) (20 Twip = 1 Point) muss
    // man als Fonthoehe 480 angeben um 24 Point als default zu erhalten.
    static void       SetFontHeight(ULONG nHeight)         { GetDefaults().nFontHeight=nHeight; }
    static ULONG      GetFontHeight()                      { return GetDefaults().nFontHeight; }
    // Der MapMode wird fuer den globalen Outliner benoetigt.
    // Gleichzeitig bekommt auch jedes neu instanziierte SdrModel
    // diesen MapMode default zugewiesen.
    // Default MapUnit ist MAP_100TH_MM
    static void       SetMapUnit(MapUnit eMap)             { GetDefaults().eMapUnit=eMap; }
    static MapUnit    GetMapUnit()                         { return GetDefaults().eMapUnit; }
    // Default MapFraction ist 1/1.
    static void       SetMapFraction(const Fraction& rMap) { GetDefaults().aMapFraction=rMap; }
    static Fraction   GetMapFraction()                     { return GetDefaults().aMapFraction; }
    // Der Aufruf der folgenden Methode veranlasst die Engine
    // ihre sprachabhaengigen Resourcen neu zu initiallisieren.
    // Bereits bestehende Undotexte, etc. bleiben jedoch in der
    // sprache erhalten, in der sie erzeugt wurden.
    static void       LanguageHasChanged();

    // Einen Outliner mit den engineglobalen
    // Defaulteinstellungen auf dem Heap erzeugen.
    // Ist pMod<>NULL, dann wird der MapMode des uebergebenen
    // Models verwendet. Die resultierende Default-Fonthoehe bleibt
    // jedoch dieselbe (die logische Fonthoehe wird umgerechnet).
    friend SVX_DLLPUBLIC SdrOutliner* SdrMakeOutliner( USHORT nOutlinerMode, SdrModel* pMod );
};

class SfxItemSet;
// Liefert eine Ersatzdarstellung fuer einen XFillStyle
// Bei XFILL_NONE gibt's FALSE und rCol bleibt unveraendert.
SVX_DLLPUBLIC bool GetDraftFillColor(const SfxItemSet& rSet, Color& rCol);

// Ein Container fuer USHORTs (im Prinzip ein dynamisches Array)
class UShortCont {
    Container aArr;
public:
    UShortCont(USHORT nBlock, USHORT nInit, USHORT nResize): aArr(nBlock,nInit,nResize) {}
    void   Clear()                                           { aArr.Clear(); }
    void   Insert(USHORT nElem, ULONG nPos=CONTAINER_APPEND) { aArr.Insert((void*)ULONG(nElem),nPos); }
    void   Remove(ULONG nPos)                                { aArr.Remove(nPos); }
    void   Replace(USHORT nElem, ULONG nPos)                 { aArr.Replace((void*)ULONG(nElem),nPos); }
    USHORT GetObject(ULONG nPos)                       const { return USHORT(ULONG(aArr.GetObject(nPos))); }
    ULONG  GetPos(USHORT nElem)                        const { return aArr.GetPos((void*)(ULONG)nElem); }
    ULONG  GetCount()                                  const { return aArr.Count(); }
    void   Sort();
};

class ContainerSorter {
protected:
    Container& rCont;
private:
    void ImpSubSort(long nL, long nR) const;
public:
    ContainerSorter(Container& rNewCont): rCont(rNewCont) {}
    void DoSort(ULONG a=0, ULONG b=0xFFFFFFFF) const;
#ifdef This_Is_Just_For_A_Comment
    Compare() muss returnieren:
      -1 falls *pElem1<*pElem2
       0 falls *pElem1=*pElem2
      +1 falls *pElem1>*pElem2
#endif
    virtual int Compare(const void* pElem1, const void* pElem2) const=0;
private: // damit keiner vergessen wird
virtual
        void
                 Is1stLessThan2nd(const void* pElem1, const void* pElem2) const;
//  virtual bool Is1stLessThan2nd(const void* pElem1, const void* pElem2) const=NULL;
};

////////////////////////////////////////////////////////////////////////////////////////////////////

#define SDRHDC_SAVEPEN                1 /* Save Linecolor                     */
#define SDRHDC_SAVEBRUSH              2 /* Save Fillcolorn                    */
#define SDRHDC_SAVEFONT               4 /* Save Font                          */
#define SDRHDC_SAVEPENANDBRUSH        3 /* Save Line- and FillColor           */
#define SDRHDC_SAVEPENANDBRUSHANDFONT 7 /* Save Font, Line- and fillcolor     */
#define SDRHDC_SAVECLIPPING           8 /* Save Clipping                      */
#define SDRHDC_SAVEALL               15 /* Save Clipping, Font, fill- and linecolor */

class ImpClipMerk;
class ImpColorMerk;
class ImpSdrHdcMerk
{
    ImpColorMerk* pFarbMerk;
    ImpClipMerk*  pClipMerk;
    Color*        pLineColorMerk;
    USHORT        nMode;
public:
    ImpSdrHdcMerk(const OutputDevice& rOut, USHORT nNewMode=SDRHDC_SAVEALL, bool bAutoMerk = true);
    ~ImpSdrHdcMerk();
    void Save(const OutputDevice& rOut);
    bool IsSaved() const                 { return pFarbMerk!=NULL || pClipMerk!=NULL || pLineColorMerk!=NULL; }
    void Restore(OutputDevice& rOut, USHORT nMask=SDRHDC_SAVEALL) const;
};

////////////////////////////////////////////////////////////////////////////////////////////////////

// Ein ItemSet auf Outliner- bzw. EditEngine-Items durchsuchen
// Liefert TRUE, wenn der Set solchen Items enthaelt.
BOOL SearchOutlinerItems(const SfxItemSet& rSet, BOOL bInklDefaults, BOOL* pbOnlyEE=NULL);

// zurueck erhaelt man einen neuen WhichTable den
// man dann irgendwann mit delete platthauen muss.
USHORT* RemoveWhichRange(const USHORT* pOldWhichTable, USHORT nRangeBeg, USHORT nRangeEnd);

////////////////////////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////////////////////////

class Link;

// Hilfsklasse zur kommunikation zwischen dem Dialog
// zum aufbrechen von Metafiles (sd/source/ui/dlg/brkdlg.cxx),
// SdrEditView::DoImportMarkedMtf() und
// ImpSdrGDIMetaFileImport::DoImport()
class SVX_DLLPUBLIC SvdProgressInfo
{
private:
    ULONG nSumActionCount;  // Summe aller Actions
    ULONG nSumCurAction;    // Summe aller bearbeiteten Actions

    ULONG nActionCount;     // Anzahl der Actions im akt. Obj.
    ULONG nCurAction;       // Anzahl bearbeiteter Act. im akt. Obj.

    ULONG nInsertCount;     // Anzahl einzufuegender Act. im akt. Obj.
    ULONG nCurInsert;       // Anzahl bereits eingefuegter Actions

    ULONG nObjCount;        // Anzahl der selektierten Objekte
    ULONG nCurObj;          // Aktuelles Objekt

    Link *pLink;

public:
    SvdProgressInfo( Link *_pLink );

    void Init( ULONG _nSumActionCount, ULONG _nObjCount );

    BOOL SetNextObject();

    void SetActionCount( ULONG _nActionCount );
    void SetInsertCount( ULONG _nInsertCount );

    BOOL ReportActions( ULONG nAnzActions );
    BOOL ReportInserts( ULONG nAnzInserts );

    ULONG GetSumActionCount() const { return nSumActionCount; };
    ULONG GetSumCurAction() const { return nSumCurAction; };
    ULONG GetObjCount() const { return nObjCount; };
    ULONG GetCurObj() const { return nCurObj; };

    ULONG GetActionCount() const { return nActionCount; };
    ULONG GetCurAction() const { return nCurAction; };

    ULONG GetInsertCount() const { return nInsertCount; };
    ULONG GetCurInsert() const { return nCurInsert; };

    void ReportError();
    BOOL ReportRescales( ULONG nAnzRescales );
};

class SdrLinkList
{
    Container aList;
protected:
    unsigned FindEntry(const Link& rLink) const;
public:
    SdrLinkList(): aList(1024,4,4)        {}
    ~SdrLinkList()                        { Clear(); }
    SVX_DLLPUBLIC void Clear();
    unsigned GetLinkCount() const            { return (unsigned)aList.Count(); }
    Link& GetLink(unsigned nNum)             { return *((Link*)(aList.GetObject(nNum))); }
    const Link& GetLink(unsigned nNum) const { return *((Link*)(aList.GetObject(nNum))); }
    void InsertLink(const Link& rLink, unsigned nPos=0xFFFF);
    void RemoveLink(const Link& rLink);
    bool HasLink(const Link& rLink) const { return FindEntry(rLink)!=0xFFFF; }
};

// Fuer die Factory in SvdObj.CXX
SdrLinkList& ImpGetUserMakeObjHdl();
SdrLinkList& ImpGetUserMakeObjUserDataHdl();

class SdrOle2Obj;
class AutoTimer;

class OLEObjCache : public Container
{
    ULONG               nSize;
    AutoTimer*          pTimer;

    void UnloadOnDemand();
    BOOL UnloadObj( SdrOle2Obj* pObj );
    DECL_LINK( UnloadCheckHdl, AutoTimer* );

public:
    OLEObjCache();
    SVX_DLLPUBLIC ~OLEObjCache();

    void SetSize(ULONG nNewSize);
    void InsertObj(SdrOle2Obj* pObj);
    void RemoveObj(SdrOle2Obj* pObj);
};

class SVX_DLLPUBLIC SdrGlobalData
{
    const SvtSysLocale*         pSysLocale;     // follows always locale settings
    const CharClass*            pCharClass;     // follows always SysLocale
    const LocaleDataWrapper*    pLocaleData;    // follows always SysLocale
public:
    SdrLinkList         aUserMakeObjHdl;
    SdrLinkList         aUserMakeObjUserDataHdl;
    SdrOutliner*        pOutliner;
    SdrEngineDefaults*  pDefaults;
    ResMgr*             pResMgr;
    ULONG               nExchangeFormat;
    OLEObjCache         aOLEObjCache;

    const SvtSysLocale*         GetSysLocale();     // follows always locale settings
    const CharClass*            GetCharClass();     // follows always SysLocale
    const LocaleDataWrapper*    GetLocaleData();    // follows always SysLocale
public:
    SdrGlobalData();
    ~SdrGlobalData();

    OLEObjCache&        GetOLEObjCache() { return aOLEObjCache; }
};

inline SdrGlobalData& GetSdrGlobalData()
{
    void** ppAppData=GetAppData(SHL_SVD);
    if (*ppAppData==NULL) {
        *ppAppData=new SdrGlobalData;
    }
    return *((SdrGlobalData*)*ppAppData);
}

namespace sdr
{

SVX_DLLPUBLIC String GetResourceString(sal_uInt16 nResID);

}

/////////////////////////////////////////////////////////////////////
// #i101872# isolated GetTextEditBackgroundColor for tooling
class SdrObjEditView;

SVX_DLLPUBLIC Color GetTextEditBackgroundColor(const SdrObjEditView& rView);

/////////////////////////////////////////////////////////////////////

#endif //_SVDETC_HXX

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<commit_msg>Move comment text from macro to comment<commit_after>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#ifndef _SVDETC_HXX
#define _SVDETC_HXX

#include <tools/string.hxx>
#include <tools/contnr.hxx>

#include <vcl/outdev.hxx>
#include <tools/shl.hxx>
#include <editeng/outliner.hxx>
#include "svx/svxdllapi.h"

////////////////////////////////////////////////////////////////////////////////////////////////////

// ExchangeFormat-Id der DrawingEngine holen. Daten koennen dann per
//   static BOOL CopyData(pData,nLen,nFormat);
// bereitgestellt werden, wobei pData/nLen einen SvMemoryStream beschreiben in
// dem ein SdrModel gestreamt wird an dem fuer die Zeitdauer des Streamens das
// Flag SdrModel::SetStreamingSdrModel(TRUE) gesetzt wird.
// ULONG SdrGetExchangeFormat(); -- JP 18.01.99 - dafuer gibt es ein define

class SdrOutliner;
class SdrModel;
class SvtSysLocale;
class CharClass;
class LocaleDataWrapper;

namespace com { namespace sun { namespace star { namespace lang {
    struct Locale;
}}}}

// Einen Outliner mit den engineglobalen
// Defaulteinstellungen auf dem Heap erzeugen.
// Ist pMod<>NULL, dann wird der MapMode des uebergebenen
// Models verwendet. Die resultierende Default-Fonthoehe bleibt
// jedoch dieselbe (die logische Fonthoehe wird umgerechnet).
SVX_DLLPUBLIC SdrOutliner* SdrMakeOutliner( USHORT nOutlinerMode, SdrModel* pMod );

// Globale Defaulteinstellungen fuer die DrawingEngine.
// Diese Einstellungen sollte man direkt beim Applikationsstart
// vornehmen, noch bevor andere Methoden der Engine gerufen werden.
class SVX_DLLPUBLIC SdrEngineDefaults
{
friend class SdrAttrObj;
    String     aFontName;
    FontFamily eFontFamily;
    Color      aFontColor;
    ULONG      nFontHeight;
    MapUnit    eMapUnit;
    Fraction   aMapFraction;

private:
    static SdrEngineDefaults& GetDefaults();

public:
    SdrEngineDefaults();
    // Default Fontname ist "Times New Roman"
    static void       SetFontName(const String& rFontName) { GetDefaults().aFontName=rFontName; }
    static String     GetFontName()                        { return GetDefaults().aFontName; }
    // Default FontFamily ist FAMILY_ROMAN
    static void       SetFontFamily(FontFamily eFam)       { GetDefaults().eFontFamily=eFam; }
    static FontFamily GetFontFamily()                      { return GetDefaults().eFontFamily; }
    // Default FontColor ist COL_BLACK
    static void       SetFontColor(const Color& rColor)    { GetDefaults().aFontColor=rColor; }
    static Color      GetFontColor()                       { return GetDefaults().aFontColor; }
    // Default FontHeight ist 847. Die Fonthoehe wird in logischen Einheiten
    // (MapUnit/MapFraction (siehe unten)) angegeben. Die Defaulteinstellung
    // 847/100mm entspricht also ca. 24 Point. Verwendet man stattdessen
    // beispielsweise Twips (SetMapUnit(MAP_TWIP)) (20 Twip = 1 Point) muss
    // man als Fonthoehe 480 angeben um 24 Point als default zu erhalten.
    static void       SetFontHeight(ULONG nHeight)         { GetDefaults().nFontHeight=nHeight; }
    static ULONG      GetFontHeight()                      { return GetDefaults().nFontHeight; }
    // Der MapMode wird fuer den globalen Outliner benoetigt.
    // Gleichzeitig bekommt auch jedes neu instanziierte SdrModel
    // diesen MapMode default zugewiesen.
    // Default MapUnit ist MAP_100TH_MM
    static void       SetMapUnit(MapUnit eMap)             { GetDefaults().eMapUnit=eMap; }
    static MapUnit    GetMapUnit()                         { return GetDefaults().eMapUnit; }
    // Default MapFraction ist 1/1.
    static void       SetMapFraction(const Fraction& rMap) { GetDefaults().aMapFraction=rMap; }
    static Fraction   GetMapFraction()                     { return GetDefaults().aMapFraction; }
    // Der Aufruf der folgenden Methode veranlasst die Engine
    // ihre sprachabhaengigen Resourcen neu zu initiallisieren.
    // Bereits bestehende Undotexte, etc. bleiben jedoch in der
    // sprache erhalten, in der sie erzeugt wurden.
    static void       LanguageHasChanged();

    // Einen Outliner mit den engineglobalen
    // Defaulteinstellungen auf dem Heap erzeugen.
    // Ist pMod<>NULL, dann wird der MapMode des uebergebenen
    // Models verwendet. Die resultierende Default-Fonthoehe bleibt
    // jedoch dieselbe (die logische Fonthoehe wird umgerechnet).
    friend SVX_DLLPUBLIC SdrOutliner* SdrMakeOutliner( USHORT nOutlinerMode, SdrModel* pMod );
};

class SfxItemSet;
// Liefert eine Ersatzdarstellung fuer einen XFillStyle
// Bei XFILL_NONE gibt's FALSE und rCol bleibt unveraendert.
SVX_DLLPUBLIC bool GetDraftFillColor(const SfxItemSet& rSet, Color& rCol);

// Ein Container fuer USHORTs (im Prinzip ein dynamisches Array)
class UShortCont {
    Container aArr;
public:
    UShortCont(USHORT nBlock, USHORT nInit, USHORT nResize): aArr(nBlock,nInit,nResize) {}
    void   Clear()                                           { aArr.Clear(); }
    void   Insert(USHORT nElem, ULONG nPos=CONTAINER_APPEND) { aArr.Insert((void*)ULONG(nElem),nPos); }
    void   Remove(ULONG nPos)                                { aArr.Remove(nPos); }
    void   Replace(USHORT nElem, ULONG nPos)                 { aArr.Replace((void*)ULONG(nElem),nPos); }
    USHORT GetObject(ULONG nPos)                       const { return USHORT(ULONG(aArr.GetObject(nPos))); }
    ULONG  GetPos(USHORT nElem)                        const { return aArr.GetPos((void*)(ULONG)nElem); }
    ULONG  GetCount()                                  const { return aArr.Count(); }
    void   Sort();
};

class ContainerSorter {
protected:
    Container& rCont;
private:
    void ImpSubSort(long nL, long nR) const;
public:
    ContainerSorter(Container& rNewCont): rCont(rNewCont) {}
    void DoSort(ULONG a=0, ULONG b=0xFFFFFFFF) const;

    // Compare() has to return:
    //  -1 if *pElem1<*pElem2
    //   0 if *pElem1=*pElem2
    //  +1 if *pElem1>*pElem2
    virtual int Compare(const void* pElem1, const void* pElem2) const=0;
private: // damit keiner vergessen wird
virtual
        void
                 Is1stLessThan2nd(const void* pElem1, const void* pElem2) const;
};

////////////////////////////////////////////////////////////////////////////////////////////////////

#define SDRHDC_SAVEPEN                1 /* Save Linecolor                     */
#define SDRHDC_SAVEBRUSH              2 /* Save Fillcolorn                    */
#define SDRHDC_SAVEFONT               4 /* Save Font                          */
#define SDRHDC_SAVEPENANDBRUSH        3 /* Save Line- and FillColor           */
#define SDRHDC_SAVEPENANDBRUSHANDFONT 7 /* Save Font, Line- and fillcolor     */
#define SDRHDC_SAVECLIPPING           8 /* Save Clipping                      */
#define SDRHDC_SAVEALL               15 /* Save Clipping, Font, fill- and linecolor */

class ImpClipMerk;
class ImpColorMerk;
class ImpSdrHdcMerk
{
    ImpColorMerk* pFarbMerk;
    ImpClipMerk*  pClipMerk;
    Color*        pLineColorMerk;
    USHORT        nMode;
public:
    ImpSdrHdcMerk(const OutputDevice& rOut, USHORT nNewMode=SDRHDC_SAVEALL, bool bAutoMerk = true);
    ~ImpSdrHdcMerk();
    void Save(const OutputDevice& rOut);
    bool IsSaved() const                 { return pFarbMerk!=NULL || pClipMerk!=NULL || pLineColorMerk!=NULL; }
    void Restore(OutputDevice& rOut, USHORT nMask=SDRHDC_SAVEALL) const;
};

////////////////////////////////////////////////////////////////////////////////////////////////////

// Ein ItemSet auf Outliner- bzw. EditEngine-Items durchsuchen
// Liefert TRUE, wenn der Set solchen Items enthaelt.
BOOL SearchOutlinerItems(const SfxItemSet& rSet, BOOL bInklDefaults, BOOL* pbOnlyEE=NULL);

// zurueck erhaelt man einen neuen WhichTable den
// man dann irgendwann mit delete platthauen muss.
USHORT* RemoveWhichRange(const USHORT* pOldWhichTable, USHORT nRangeBeg, USHORT nRangeEnd);

////////////////////////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////////////////////////

class Link;

// Hilfsklasse zur kommunikation zwischen dem Dialog
// zum aufbrechen von Metafiles (sd/source/ui/dlg/brkdlg.cxx),
// SdrEditView::DoImportMarkedMtf() und
// ImpSdrGDIMetaFileImport::DoImport()
class SVX_DLLPUBLIC SvdProgressInfo
{
private:
    ULONG nSumActionCount;  // Summe aller Actions
    ULONG nSumCurAction;    // Summe aller bearbeiteten Actions

    ULONG nActionCount;     // Anzahl der Actions im akt. Obj.
    ULONG nCurAction;       // Anzahl bearbeiteter Act. im akt. Obj.

    ULONG nInsertCount;     // Anzahl einzufuegender Act. im akt. Obj.
    ULONG nCurInsert;       // Anzahl bereits eingefuegter Actions

    ULONG nObjCount;        // Anzahl der selektierten Objekte
    ULONG nCurObj;          // Aktuelles Objekt

    Link *pLink;

public:
    SvdProgressInfo( Link *_pLink );

    void Init( ULONG _nSumActionCount, ULONG _nObjCount );

    BOOL SetNextObject();

    void SetActionCount( ULONG _nActionCount );
    void SetInsertCount( ULONG _nInsertCount );

    BOOL ReportActions( ULONG nAnzActions );
    BOOL ReportInserts( ULONG nAnzInserts );

    ULONG GetSumActionCount() const { return nSumActionCount; };
    ULONG GetSumCurAction() const { return nSumCurAction; };
    ULONG GetObjCount() const { return nObjCount; };
    ULONG GetCurObj() const { return nCurObj; };

    ULONG GetActionCount() const { return nActionCount; };
    ULONG GetCurAction() const { return nCurAction; };

    ULONG GetInsertCount() const { return nInsertCount; };
    ULONG GetCurInsert() const { return nCurInsert; };

    void ReportError();
    BOOL ReportRescales( ULONG nAnzRescales );
};

class SdrLinkList
{
    Container aList;
protected:
    unsigned FindEntry(const Link& rLink) const;
public:
    SdrLinkList(): aList(1024,4,4)        {}
    ~SdrLinkList()                        { Clear(); }
    SVX_DLLPUBLIC void Clear();
    unsigned GetLinkCount() const            { return (unsigned)aList.Count(); }
    Link& GetLink(unsigned nNum)             { return *((Link*)(aList.GetObject(nNum))); }
    const Link& GetLink(unsigned nNum) const { return *((Link*)(aList.GetObject(nNum))); }
    void InsertLink(const Link& rLink, unsigned nPos=0xFFFF);
    void RemoveLink(const Link& rLink);
    bool HasLink(const Link& rLink) const { return FindEntry(rLink)!=0xFFFF; }
};

// Fuer die Factory in SvdObj.CXX
SdrLinkList& ImpGetUserMakeObjHdl();
SdrLinkList& ImpGetUserMakeObjUserDataHdl();

class SdrOle2Obj;
class AutoTimer;

class OLEObjCache : public Container
{
    ULONG               nSize;
    AutoTimer*          pTimer;

    void UnloadOnDemand();
    BOOL UnloadObj( SdrOle2Obj* pObj );
    DECL_LINK( UnloadCheckHdl, AutoTimer* );

public:
    OLEObjCache();
    SVX_DLLPUBLIC ~OLEObjCache();

    void SetSize(ULONG nNewSize);
    void InsertObj(SdrOle2Obj* pObj);
    void RemoveObj(SdrOle2Obj* pObj);
};

class SVX_DLLPUBLIC SdrGlobalData
{
    const SvtSysLocale*         pSysLocale;     // follows always locale settings
    const CharClass*            pCharClass;     // follows always SysLocale
    const LocaleDataWrapper*    pLocaleData;    // follows always SysLocale
public:
    SdrLinkList         aUserMakeObjHdl;
    SdrLinkList         aUserMakeObjUserDataHdl;
    SdrOutliner*        pOutliner;
    SdrEngineDefaults*  pDefaults;
    ResMgr*             pResMgr;
    ULONG               nExchangeFormat;
    OLEObjCache         aOLEObjCache;

    const SvtSysLocale*         GetSysLocale();     // follows always locale settings
    const CharClass*            GetCharClass();     // follows always SysLocale
    const LocaleDataWrapper*    GetLocaleData();    // follows always SysLocale
public:
    SdrGlobalData();
    ~SdrGlobalData();

    OLEObjCache&        GetOLEObjCache() { return aOLEObjCache; }
};

inline SdrGlobalData& GetSdrGlobalData()
{
    void** ppAppData=GetAppData(SHL_SVD);
    if (*ppAppData==NULL) {
        *ppAppData=new SdrGlobalData;
    }
    return *((SdrGlobalData*)*ppAppData);
}

namespace sdr
{

SVX_DLLPUBLIC String GetResourceString(sal_uInt16 nResID);

}

/////////////////////////////////////////////////////////////////////
// #i101872# isolated GetTextEditBackgroundColor for tooling
class SdrObjEditView;

SVX_DLLPUBLIC Color GetTextEditBackgroundColor(const SdrObjEditView& rView);

/////////////////////////////////////////////////////////////////////

#endif //_SVDETC_HXX

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<|endoftext|>


<commit_before>/** vim: set ft=cpp ts=3 sw=3 tw=0 sts=0 et:
  *
  * @file   : sweetie-rush/board.cpp
  * @author : evilrix
  * @date   : 09/37/2014
  * @brief  : Implements the board class
  *
  */

#include <cmath>
#include <utility>
#include <algorithm>
#include <memory>

#include "sweetie.hpp"
#include "board.hpp"

namespace sweetie_rush {

   auto const delay = 100; ///< Delay in ms for sweetie animation

   board::board()
      : win_(window("Sweetie Rush!",
                    SDL_WINDOWPOS_CENTERED,  SDL_WINDOWPOS_CENTERED,
                    board_siz, board_siz,
                    SDL_WINDOW_SHOWN))
      , ren_(renderer(
                win_, -1,
                SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC))
   {
      // Our sweeties, cached - used to repaint the board
      sweets_.push_back(std::shared_ptr<sweetie>(new sweetie_blue(ren_)));
      sweets_.push_back(std::shared_ptr<sweetie>(new sweetie_green(ren_)));
      sweets_.push_back(std::shared_ptr<sweetie>(new sweetie_purple(ren_)));
      sweets_.push_back(std::shared_ptr<sweetie>(new sweetie_red(ren_)));
      sweets_.push_back(std::shared_ptr<sweetie>(new sweetie_yellow(ren_)));

      // initialise the play aread
      initialise();

      // render the play area
      render();
   }

   /*!
    * \brief Fill col.
    *
    * \param x The x coordinate.
    * \param y The y coordinate.
    */

   void board::fill_col(int x, int y)
   {
      // The size of our sweeties are defined by this rectangle
      SDL_Rect tile_rect {x*36, y*36, tile_size, tile_size};

      // to iterate throught the loaded textures so as to create a play area
      auto itr = sweets_.end();

      // process the y-axis
      for(; y >= 0 ; --y)
      {

         // set rendering position
         tile_rect.y += y*36;

         // So, when we first create the board we want to make sure that no
         // more than two of the same sweeties are touching, otherwise we
         // start off the game awarding points to the player! The following
         // section of code ensure that can't happen.
         for(;;)
         {
            // once we've worked our way though our list of textures...
            if(itr == sweets_.end())
            {
               // ...shuffle them up and start again
               std::random_shuffle(sweets_.begin(), sweets_.end());
               itr = sweets_.begin();

               // Note: The reason for the shuffling rather than just using
               // a randomised index into the vector of tiles is to avoid
               // a situation where we have three tiles in a row. In this
               // case we need to pick a different texture, depending on how
               // poor the random number generator is we could get stuck in
               // a loop (possible, but unlikely infinate). By iterating a
               // list of random unique tiles we are guaranteed that, at
               // most, we'll have to skip two tiles. This is probably
               // overkill, but I have worked on systems whose RNG was so
               // bad they just repeatedly returned the same 4 numbers!!!
            }

            // assign our initial texture
            tiles_[x][y] = tile(*itr++, &ren_, x, y);

            // now make sure we're not adding a 3rd to the X-axis
            if(x >= 2)
            {
               if(tiles_[x][y] == tiles_[x-1][y] &&
                  tiles_[x][y] == tiles_[x-2][y])
               {
                  // three in a row, pick again
                  continue;
               }
            }

            // now make sure we're not adding a 3rd to the Y-axis
            if(y < 6)
            {
               if(tiles_[x][y] == tiles_[x][y+1] &&
                  tiles_[x][y] == tiles_[x][y+2])
               {
                  // three in a row, pick again
                  continue;
               }
            }

            render();

            // all good, break out of the try/repeat loop
            break;
         }
      }
   }

   /**
    * @brief Initialises this board.
    */

   void board::initialise()
   {
      // process the Y-axis
      for(auto x = 0 ; x < board_dim ; ++x)
      {
         fill_col(x, board_dim-1);
      }
   }

   /*!
    * \brief Renders this board.
    */

   void board::render() const
   {
      // (re-)render the play area
      SDL_RenderPresent(ren_.get());
      SDL_Delay(delay);
   }

   /*!
    * \brief Handles the drops.
    *
    * \param [in,out] pt   If non-null, the point.
    * \param [in,out] pcur If non-null, the pcur.
    *
    * Swaps out current tile for the next real tile above it, moving all times
    * down to fille the gaps and then adding new tiles to the column.
    */

   void board::handle_drop(tile * pt, tile * pcur)
   {
      while(pcur->get_y() >= 0)
      {
         pt->blank();
         pt->swap(*pcur);

         render();

         if(pcur->get_y() - 1 < 0)
         {
            break;
         }

         pt = &tiles_[pt->get_x()][pt->get_y()-1];
         pcur = &tiles_[pcur->get_x()][pcur->get_y()-1];
      }

      if(pt->get_y() >= 0)
      {
         fill_col(pt->get_x(), pt->get_y());
      }
   }

   /*!
    * \brief Clears the y-axis of matches.
    *
    * \param this_click this clicked tile.
    *
    * \return true if it succeeds, false if it fails.
    */

   bool board::clear_y(coords const & this_click)
   {
      auto & this_tile = tiles_[this_click.x][this_click.y];
      auto & last_tile = tiles_[last_click_.x][last_click_.y];

      last_tile.selected(false);
      this_tile.selected(false);

      tile * pt = &this_tile;
      tile * pt_next = pt;

      while(pt_next)
      {
         pt_next = pt->get_y() + 1 < board_dim
                   ? &tiles_[pt->get_x()][pt->get_y() + 1] : nullptr;

         if(pt_next && *pt_next != *pt)
         {
            pt_next = nullptr;
         }

         if(pt_next)
         {
            pt = pt_next;
         }
      }

      auto pcur = pt;

      while(pcur->get_y() > 0 && *pcur == *pt)
      {
         pcur = &tiles_[pcur->get_x()][pcur->get_y()-1];
      }

      auto drop = ((pt->get_y() - pcur->get_y()) >= 2);

      if(drop)
      {
         handle_drop(pt, pcur);
      }

      return drop;
   }

   /*!
    * \brief Clears the x-axis of matches.
    *
    * \param this_click this clicked tile.
    *
    * \return true if it succeeds, false if it fails.
    */

   bool board::clear_x(coords const & this_click)
   {
      auto & this_tile = tiles_[this_click.x][this_click.y];

      tile * pt = &this_tile;
      tile * pt_next = pt;

      while(pt_next)
      {
         pt_next = pt->get_x() + 1 < board_dim
                   ? &tiles_[pt->get_x() + 1][pt->get_y()] : nullptr;

         if(pt_next && *pt_next != *pt)
         {
            pt_next = nullptr;
         }

         if(pt_next)
         {
            pt = pt_next;
         }
      }

      auto pcur = pt;

      while(pcur->get_x() > 0)
      {
         auto tmp = &tiles_[pcur->get_x()-1][pcur->get_y()];

         if(*tmp != *pcur) { break; }

         pcur = tmp;
      }

      auto drop = ((pt->get_x() - pcur->get_x()) >= 2);

      if(drop)
      {
         do
         {
            bool cleared = false;

            if(pcur == &this_tile)
            {
               cleared = clear_y(this_click);
            }

            if(!cleared)
            {
               if(pcur->get_y() == 0)
               {
                  fill_col(pcur->get_x(), pcur->get_y());
               }
               else
               {
                  handle_drop(pcur, &tiles_[pcur->get_x()][pcur->get_y()-1]);
               }
            }

            if(pcur->get_x() < board_dim - 1)
            {
               pcur = &tiles_[pcur->get_x()+1][pcur->get_y()];
            }
         }
         while(pcur->get_x() < (board_dim-1) && pcur->get_x() <= pt->get_x());
      }
      else
      {
         drop = clear_y(this_click);

         if(!drop || this_click.y != last_click_.y)
         {
            drop = drop || clear_y(last_click_);
         }
      }

      return drop;
   }

   /*!
    * \brief Clears the xy-axis of matches.
    *
    * \param this_click this clicked tile.
    */

   void board::clear_xy(coords const & this_click)
   {
      // get this tile and the last tile clicked
      auto & this_tile = tiles_[this_click.x][this_click.y];
      auto & last_tile = tiles_[last_click_.x][last_click_.y];

      // clear selections on both tiles
      last_tile.selected(false);
      this_tile.selected(false);

      // look for and file matches for clicked tile
      auto match = clear_x(this_click);

      if(!match || this_click.x != last_click_.x)
      {
         // look for and file matches for other tile
         match = match || clear_x(last_click_);
      }

      // did we file any matches?
      if(!match)
      {
         //...nope, so swap tiles back again
         auto & this_tile = tiles_[this_click.x][this_click.y];
         auto & last_tile = tiles_[last_click_.x][last_click_.y];

         last_tile.swap(this_tile);
      }

      // render the board
      render();
   }

   /*!
    * \brief Handles mouse click signals.
    *
    * \param e The SDL_Event const & to process.
    */

   void board::on_mouse_click(SDL_Event const & e)
   {
      swipe_ok = true;

      if(e.button.button & SDL_BUTTON_LEFT)
      {
         auto this_click = coords { e.button.x, e.button.y };

         // get the position down to tile granularity
         this_click.x /= tile_size;
         this_click.y /= tile_size;

         // Toggle select on this tile...
         auto & this_tile = tiles_[this_click.x][this_click.y];
         this_tile.toggle_selected();

         // If the current tile is selected we move it
         if(this_tile.is_selected())
         {
            if(move_tile(this_click))
            {
               clear_xy(this_click);
               last_click_ = coords {-1, -1};
            }
            else
            {
               last_click_ = this_click;
            }
         }
         else
         {
            last_click_ = coords {-1, -1};
         }

         render();
      }
   }

   /*!
    * \brief Handles mouse motion signals.
    *
    * \param e The SDL_Event const & to process.
    */

   void board::on_mouse_motion(SDL_Event const & e)
   {
      if(e.motion.state & SDL_BUTTON_LEFT)
      {
         auto this_click = coords { e.button.x, e.button.y };

         // get the position down to tile granularity
         this_click.x /= tile_size;
         this_click.y /= tile_size;

         if(swipe_ok)
         {
            if(move_tile(this_click))
            {
               clear_xy(this_click);
               last_click_ = coords {-1, -1};
            }
            else
            {
               last_click_ = this_click;
            }
         }

         render();
      }
   }

   /*!
    * \brief Move tile.
    *
    * \param this_click this click.
    *
    * \return true if it succeeds, false if it fails.
    */

   bool board::move_tile(coords const & this_click)
   {
      bool moved = false;
      auto & this_tile = tiles_[this_click.x][this_click.y];

      // if this click differs from the last...
      if(this_click.x != last_click_.x || this_click.y != last_click_.y)
      {
         // if we've perviously clicked a tile...
         if(last_click_.x >= 0 && last_click_.y >= 0)
         {
            auto & last_tile = tiles_[last_click_.x][last_click_.y];

            // get the x/y axis difference between this and last
            auto const x_diff = abs(this_click.x-last_click_.x);
            auto const y_diff = abs(this_click.y-last_click_.y);

            // if this tile is adjacent vertically or horizontally
            if((1 == x_diff && 1 != y_diff) ||
               (1 != x_diff && 1 == y_diff))
            {
               // swap the tiles
               last_tile.swap(this_tile);
               moved = true;

               // prevent more swiping until mouse unclicked
               swipe_ok = false;
            }

            // unselect the previous tile
            last_tile.selected(false);
         }
      }

      // render any changes to the board
      render();

      return moved;
   }
}
<commit_msg>A little bit of code cleanup and commentary<commit_after>/** vim: set ft=cpp ts=3 sw=3 tw=0 sts=0 et:
  *
  * @file   : sweetie-rush/board.cpp
  * @author : evilrix
  * @date   : 09/37/2014
  * @brief  : Implements the board class
  *
  */

#include <cmath>
#include <utility>
#include <algorithm>
#include <memory>

#include "sweetie.hpp"
#include "board.hpp"

namespace sweetie_rush {

   auto const delay = 100; ///< Delay in ms for sweetie animation

   /*!
    * \brief Initializes a new instance of the board class.
    */

   board::board()
      : win_(window("Sweetie Rush!",
                    SDL_WINDOWPOS_CENTERED,  SDL_WINDOWPOS_CENTERED,
                    board_siz, board_siz,
                    SDL_WINDOW_SHOWN))
      , ren_(renderer(
                win_, -1,
                SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC))
   {
      // Our sweeties, cached - used to repaint the board
      sweets_.push_back(std::shared_ptr<sweetie>(new sweetie_blue(ren_)));
      sweets_.push_back(std::shared_ptr<sweetie>(new sweetie_green(ren_)));
      sweets_.push_back(std::shared_ptr<sweetie>(new sweetie_purple(ren_)));
      sweets_.push_back(std::shared_ptr<sweetie>(new sweetie_red(ren_)));
      sweets_.push_back(std::shared_ptr<sweetie>(new sweetie_yellow(ren_)));

      // initialise the play aread
      initialise();

      // render the play area
      render();
   }

   /*!
    * \brief Fill col.
    *
    * \param x The x coordinate.
    * \param y The y coordinate.
    *
    * Fills the y-axis, starting from position y until full
    */

   void board::fill_col(int x, int y)
   {
      // The size of our sweeties are defined by this rectangle
      SDL_Rect tile_rect {x*36, y*36, tile_size, tile_size};

      // to iterate throught the loaded textures so as to create a play area
      auto itr = sweets_.end();

      // process the y-axis
      for(; y >= 0 ; --y)
      {

         // set rendering position
         tile_rect.y += y*36;

         // So, when we first create the board we want to make sure that no
         // more than two of the same sweeties are touching, otherwise we
         // start off the game awarding points to the player! The following
         // section of code ensure that can't happen.
         for(;;)
         {
            // once we've worked our way though our list of textures...
            if(itr == sweets_.end())
            {
               // ...shuffle them up and start again
               std::random_shuffle(sweets_.begin(), sweets_.end());
               itr = sweets_.begin();

               // Note: The reason for the shuffling rather than just using
               // a randomised index into the vector of tiles is to avoid
               // a situation where we have three tiles in a row. In this
               // case we need to pick a different texture, depending on how
               // poor the random number generator is we could get stuck in
               // a loop (possible, but unlikely infinate). By iterating a
               // list of random unique tiles we are guaranteed that, at
               // most, we'll have to skip two tiles. This is probably
               // overkill, but I have worked on systems whose RNG was so
               // bad they just repeatedly returned the same 4 numbers!!!
            }

            // assign our initial texture
            tiles_[x][y] = tile(*itr++, &ren_, x, y);

            // now make sure we're not adding a 3rd matching to the X-axis
            if(x >= 2)
            {
               if(tiles_[x][y] == tiles_[x-1][y] &&
                  tiles_[x][y] == tiles_[x-2][y])
               {
                  // three in a row, pick again
                  continue;
               }
            }

            // now make sure we're not adding a 3rd to the Y-axis
            if(y < 6)
            {
               if(tiles_[x][y] == tiles_[x][y+1] &&
                  tiles_[x][y] == tiles_[x][y+2])
               {
                  // three in a row, pick again
                  continue;
               }
            }

            // update the board
            render();

            // all good, break out of the try/repeat loop
            break;
         }
      }
   }

   /**
    * @brief Initialises this board.
    */

   void board::initialise()
   {
      // for each column, fill it
      for(auto x = 0 ; x < board_dim ; ++x)
      {
         fill_col(x, board_dim-1);
      }
   }

   /*!
    * \brief Renders this board.
    */

   void board::render() const
   {
      // (re-)render the play area
      SDL_RenderPresent(ren_.get());
      SDL_Delay(delay);
   }

   /*!
    * \brief Handles the drops.
    *
    * \param [in,out] pt   If non-null, the point.
    * \param [in,out] pcur If non-null, the pcur.
    *
    * Swaps out current tile for the next real tile above it, moving all times
    * down to fille the gaps and then adding new tiles to the column.
    *
    * TODO: as things drop they might create more matches so we should handle
    */

   void board::handle_drop(tile * pt, tile * pcur)
   {
      // firstly, remove matches and compact the space
      while(pcur->get_y() >= 0)
      {
         pt->blank();
         pt->swap(*pcur);

         render();

         if(pcur->get_y() - 1 < 0)
         {
            break;
         }

         pt = &tiles_[pt->get_x()][pt->get_y()-1];
         pcur = &tiles_[pcur->get_x()][pcur->get_y()-1];
      }

      // then fill the rest of the column with new sweeties
      if(pt->get_y() >= 0)
      {
         fill_col(pt->get_x(), pt->get_y());
      }
   }

   /*!
    * \brief Clears the y-axis of matches.
    *
    * \param this_click this clicked tile.
    *
    * \return true if it succeeds, false if it fails.
    */

   bool board::clear_y(coords const & this_click)
   {
      // find the start of the y-axis run
      auto & this_tile = tiles_[this_click.x][this_click.y];
      tile * pt = &this_tile;
      tile * pt_next = pt;

      while(pt_next)
      {
         pt_next = pt->get_y() + 1 < board_dim
                   ? &tiles_[pt->get_x()][pt->get_y() + 1] : nullptr;

         if(pt_next && *pt_next != *pt)
         {
            pt_next = nullptr;
         }

         if(pt_next)
         {
            pt = pt_next;
         }
      }

      // find the end of the y-axis run
      auto pcur = pt;

      while(pcur->get_y() > 0 && *pcur == *pt)
      {
         pcur = &tiles_[pcur->get_x()][pcur->get_y()-1];
      }

      // do we have 3 or more in a row?
      auto drop = ((pt->get_y() - pcur->get_y()) >= 2);

      // remove the matches
      if(drop)
      {
         handle_drop(pt, pcur);
      }

      return drop;
   }

   /*!
    * \brief Clears the x-axis of matches.
    *
    * \param this_click this clicked tile.
    *
    * \return true if it succeeds, false if it fails.
    */

   bool board::clear_x(coords const & this_click)
   {
      // find the start of the x-axis run
      auto & this_tile = tiles_[this_click.x][this_click.y];

      tile * pt = &this_tile;
      tile * pt_next = pt;

      while(pt_next)
      {
         pt_next = pt->get_x() + 1 < board_dim
                   ? &tiles_[pt->get_x() + 1][pt->get_y()] : nullptr;

         if(pt_next && *pt_next != *pt)
         {
            pt_next = nullptr;
         }

         if(pt_next)
         {
            pt = pt_next;
         }
      }

      // find the end of the x-axis run
      auto pcur = pt;

      while(pcur->get_x() > 0)
      {
         auto tmp = &tiles_[pcur->get_x()-1][pcur->get_y()];

         if(*tmp != *pcur) { break; }

         pcur = tmp;
      }

      // do we have 3 or more in a row?
      auto drop = ((pt->get_x() - pcur->get_x()) >= 2);

      // remove the candiate matches
      if(drop)
      {
         // for each item on the x-axis we remove we do an y-axis drop
         do
         {
            bool cleared = false;

            // if the current x-axis we're going to clear is also the tie
            // clicked we also want to check and clear the y-axis
            if(pcur == &this_tile)
            {
               cleared = clear_y(this_click);
            }

            // if we removed nothing from the y-axis
            if(!cleared)
            {
               // if this is the last row just add new
               if(pcur->get_y() == 0)
               {
                  fill_col(pcur->get_x(), pcur->get_y());
               }
               // else, clear and compact matches
               else
               {
                  handle_drop(pcur, &tiles_[pcur->get_x()][pcur->get_y()-1]);
               }
            }

            // if we have more on the x-axis, process them
            if(pcur->get_x() < board_dim - 1)
            {
               pcur = &tiles_[pcur->get_x()+1][pcur->get_y()];
            }
         }
         while(pcur->get_x() < (board_dim-1) && pcur->get_x() <= pt->get_x());
      }
      // there were no x-axis candidates, so just clean the y-axis
      else
      {
         // clean what was clicked
         drop = clear_y(this_click);

         if(!drop || this_click.y != last_click_.y)
         {
            // clean the other tile, too
            drop = drop || clear_y(last_click_);
         }
      }

      return drop;
   }

   /*!
    * \brief Clears the xy-axis of matches.
    *
    * \param this_click this clicked tile.
    */

   void board::clear_xy(coords const & this_click)
   {
      // get this tile and the last tile clicked
      auto & this_tile = tiles_[this_click.x][this_click.y];
      auto & last_tile = tiles_[last_click_.x][last_click_.y];

      // clear selections on both tiles
      last_tile.selected(false);
      this_tile.selected(false);

      // look for and file matches for clicked tile
      auto match = clear_x(this_click);

      if(!match || this_click.x != last_click_.x)
      {
         // look for and file matches for other tile
         match = match || clear_x(last_click_);
      }

      // did we file any matches?
      if(!match)
      {
         //...nope, so swap tiles back again
         auto & this_tile = tiles_[this_click.x][this_click.y];
         auto & last_tile = tiles_[last_click_.x][last_click_.y];

         last_tile.swap(this_tile);
      }

      // render the board
      render();
   }

   /*!
    * \brief Handles mouse click signals.
    *
    * \param e The SDL_Event const & to process.
    */

   void board::on_mouse_click(SDL_Event const & e)
   {
      swipe_ok = true;

      if(e.button.button & SDL_BUTTON_LEFT)
      {
         auto this_click = coords { e.button.x, e.button.y };

         // get the position down to tile granularity
         this_click.x /= tile_size;
         this_click.y /= tile_size;

         // Toggle select on this tile...
         auto & this_tile = tiles_[this_click.x][this_click.y];
         this_tile.toggle_selected();

         // If the current tile is selected we move it
         if(this_tile.is_selected())
         {
            // if we moved tiles try cleaning matches
            if(move_tile(this_click))
            {
               clear_xy(this_click);
               last_click_ = coords {-1, -1};
            }
            // no tile toggle this time, remember this tile just clicked
            else
            {
               last_click_ = this_click;
            }
         }
         else
         {
            // no tiles selected, unset last click state
            last_click_ = coords {-1, -1};
         }

         // redraw board
         render();
      }
   }

   /*!
    * \brief Handles mouse motion signals.
    *
    * \param e The SDL_Event const & to process.
    */

   void board::on_mouse_motion(SDL_Event const & e)
   {
      if(e.motion.state & SDL_BUTTON_LEFT)
      {
         auto this_click = coords { e.button.x, e.button.y };

         // get the position down to tile granularity
         this_click.x /= tile_size;
         this_click.y /= tile_size;

         // if swipes are allowed
         if(swipe_ok)
         {
            // handle moving tiles
            if(move_tile(this_click))
            {
               clear_xy(this_click);
               last_click_ = coords {-1, -1};
            }
            else
            {
               last_click_ = this_click;
            }
         }

         render();
      }
   }

   /*!
    * \brief Move tile.
    *
    * \param this_click this click.
    *
    * \return true if it succeeds, false if it fails.
    */

   bool board::move_tile(coords const & this_click)
   {
      bool moved = false;
      auto & this_tile = tiles_[this_click.x][this_click.y];

      // if this click differs from the last...
      if(this_click.x != last_click_.x || this_click.y != last_click_.y)
      {
         // if we've perviously clicked a tile...
         if(last_click_.x >= 0 && last_click_.y >= 0)
         {
            auto & last_tile = tiles_[last_click_.x][last_click_.y];

            // get the x/y axis difference between this and last
            auto const x_diff = abs(this_click.x-last_click_.x);
            auto const y_diff = abs(this_click.y-last_click_.y);

            // if this tile is adjacent vertically or horizontally
            if((1 == x_diff && 1 != y_diff) ||
               (1 != x_diff && 1 == y_diff))
            {
               // swap the tiles
               last_tile.swap(this_tile);
               moved = true;

               // prevent more swiping until mouse unclicked
               swipe_ok = false;
            }

            // unselect the previous tile
            last_tile.selected(false);
         }
      }

      // render any changes to the board
      render();

      return moved;
   }
}
<|endoftext|>


<commit_before>/*
 +----------------------------------------------------------------------+
 | Swoole                                                               |
 +----------------------------------------------------------------------+
 | Copyright (c) 2012-2018 The Swoole Group                             |
 +----------------------------------------------------------------------+
 | This source file is subject to version 2.0 of the Apache license,    |
 | that is bundled with this package in the file LICENSE, and is        |
 | available through the world-wide-web at the following url:           |
 | http://www.apache.org/licenses/LICENSE-2.0.html                      |
 | If you did not receive a copy of the Apache2.0 license and are unable|
 | to obtain it through the world-wide-web, please send a note to       |
 | license@swoole.com so we can mail you a copy immediately.            |
 +----------------------------------------------------------------------+
 | Author: Xinyu Zhu  <xyzhu1120@gmail.com>                             |
 |         Tianfeng Han <rango@swoole.com>                              |
 +----------------------------------------------------------------------+
 */

#include "php_swoole.h"

#ifdef SW_COROUTINE
#include "swoole_coroutine.h"
#include "channel.h"

using namespace swoole;

static PHP_METHOD(swoole_channel_coro, __construct);
static PHP_METHOD(swoole_channel_coro, __destruct);
static PHP_METHOD(swoole_channel_coro, push);
static PHP_METHOD(swoole_channel_coro, pop);
static PHP_METHOD(swoole_channel_coro, close);
static PHP_METHOD(swoole_channel_coro, stats);
static PHP_METHOD(swoole_channel_coro, length);
static PHP_METHOD(swoole_channel_coro, isEmpty);
static PHP_METHOD(swoole_channel_coro, isFull);

static zend_class_entry swoole_channel_coro_ce;
static zend_class_entry *swoole_channel_coro_class_entry_ptr;

ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_channel_coro_construct, 0, 0, 0)
    ZEND_ARG_INFO(0, size)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_channel_coro_push, 0, 0, 1)
    ZEND_ARG_INFO(0, data)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_channel_coro_pop, 0, 0, 1)
    ZEND_ARG_INFO(0, timeout)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_void, 0, 0, 0)
ZEND_END_ARG_INFO()

static const zend_function_entry swoole_channel_coro_methods[] =
{
    PHP_ME(swoole_channel_coro, __construct, arginfo_swoole_channel_coro_construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
    PHP_ME(swoole_channel_coro, __destruct, arginfo_swoole_void, ZEND_ACC_PUBLIC | ZEND_ACC_DTOR)
    PHP_ME(swoole_channel_coro, push, arginfo_swoole_channel_coro_push, ZEND_ACC_PUBLIC)
    PHP_ME(swoole_channel_coro, pop,  arginfo_swoole_channel_coro_pop,  ZEND_ACC_PUBLIC)
    PHP_ME(swoole_channel_coro, isEmpty, arginfo_swoole_void, ZEND_ACC_PUBLIC)
    PHP_ME(swoole_channel_coro, isFull, arginfo_swoole_void, ZEND_ACC_PUBLIC)
    PHP_ME(swoole_channel_coro, close, arginfo_swoole_void, ZEND_ACC_PUBLIC)
    PHP_ME(swoole_channel_coro, stats, arginfo_swoole_void, ZEND_ACC_PUBLIC)
    PHP_ME(swoole_channel_coro, length, arginfo_swoole_void, ZEND_ACC_PUBLIC)
    PHP_FE_END
};

void swoole_channel_coro_init(int module_number)
{
    INIT_CLASS_ENTRY(swoole_channel_coro_ce, "Swoole\\Coroutine\\Channel", swoole_channel_coro_methods);
    swoole_channel_coro_class_entry_ptr = zend_register_internal_class(&swoole_channel_coro_ce);

    if (SWOOLE_G(use_shortname))
    {
        sw_zend_register_class_alias("chan", swoole_channel_coro_class_entry_ptr);
    }

    zend_declare_property_long(swoole_channel_coro_class_entry_ptr, SW_STRL("capacity")-1, 0, ZEND_ACC_PUBLIC);
    zend_declare_property_long(swoole_channel_coro_class_entry_ptr, SW_STRL("errCode")-1, 0, ZEND_ACC_PUBLIC);
}

static PHP_METHOD(swoole_channel_coro, __construct)
{
    zend_long capacity = 0;

    if (zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &capacity) == FAILURE)
    {
        RETURN_FALSE;
    }
    if (capacity <= 0)
    {
        capacity = 1;
    }

    php_swoole_check_reactor();

    Channel *chan = new Channel(capacity);
    zend_update_property_long(swoole_channel_coro_class_entry_ptr, getThis(), ZEND_STRL("capacity"), capacity);

    swoole_set_object(getThis(), chan);
}

static PHP_METHOD(swoole_channel_coro, __destruct)
{
    SW_PREVENT_USER_DESTRUCT;

    Channel *chan = (Channel *) swoole_get_object(getThis());
    while (chan->length() > 0)
    {
        zval *data = (zval *) chan->pop_data();
        if (data)
        {
            sw_zval_free(data);
        }
    }
    delete chan;
    swoole_set_object(getThis(), NULL);
}

static PHP_METHOD(swoole_channel_coro, push)
{
    coro_check();

    Channel *chan = (Channel *) swoole_get_object(getThis());
    if (chan->closed)
    {
        zend_update_property_long(swoole_channel_coro_class_entry_ptr, getThis(), SW_STRL("errCode")-1, -2);
        RETURN_FALSE;
    }

    zval *zdata;
    if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &zdata) == FAILURE)
    {
        RETURN_FALSE;
    }

    Z_TRY_ADDREF_P(zdata);
    if (chan->push(sw_zval_dup(zdata)))
    {
        RETURN_TRUE;
    }
    else
    {
        Z_TRY_DELREF_P(zdata);
        RETURN_FALSE;
    }
}

static PHP_METHOD(swoole_channel_coro, pop)
{
    coro_check();

    Channel *chan = (Channel *) swoole_get_object(getThis());
    if (chan->closed)
    {
        zend_update_property_long(swoole_channel_coro_class_entry_ptr, getThis(), SW_STRL("errCode")-1, -2);
        RETURN_FALSE;
    }

    double timeout = -1;
    if (zend_parse_parameters(ZEND_NUM_ARGS(), "|d", &timeout) == FAILURE)
    {
        RETURN_FALSE;
    }
    zval *data = (zval *) chan->pop(timeout);
    if (data)
    {
        RETVAL_ZVAL(data, 0, 0);
        efree(data);
    }
    else
    {
        zend_update_property_long(swoole_channel_coro_class_entry_ptr, getThis(), SW_STRL("errCode")-1, chan->closed ? -2 : -1);
        RETURN_FALSE;
    }
}

static PHP_METHOD(swoole_channel_coro, close)
{
    Channel *chan = (Channel *) swoole_get_object(getThis());
    RETURN_BOOL(chan->close());
}

static PHP_METHOD(swoole_channel_coro, length)
{
    Channel *chan = (Channel *) swoole_get_object(getThis());
    RETURN_LONG(chan->length());
}

static PHP_METHOD(swoole_channel_coro, isEmpty)
{
    Channel *chan = (Channel *) swoole_get_object(getThis());
    RETURN_BOOL(chan->is_empty());
}

static PHP_METHOD(swoole_channel_coro, isFull)
{
    Channel *chan = (Channel *) swoole_get_object(getThis());
    RETURN_BOOL(chan->is_full());
}

static PHP_METHOD(swoole_channel_coro, stats)
{
    Channel *chan = (Channel *) swoole_get_object(getThis());
    array_init(return_value);
    add_assoc_long_ex(return_value, ZEND_STRL("consumer_num"), chan->consumer_num());
    add_assoc_long_ex(return_value, ZEND_STRL("producer_num"), chan->producer_num());
    if (chan)
    {
        add_assoc_long_ex(return_value, ZEND_STRL("queue_num"), chan->length());
    }
}

#endif
<commit_msg>update chan->pop args<commit_after>/*
 +----------------------------------------------------------------------+
 | Swoole                                                               |
 +----------------------------------------------------------------------+
 | Copyright (c) 2012-2018 The Swoole Group                             |
 +----------------------------------------------------------------------+
 | This source file is subject to version 2.0 of the Apache license,    |
 | that is bundled with this package in the file LICENSE, and is        |
 | available through the world-wide-web at the following url:           |
 | http://www.apache.org/licenses/LICENSE-2.0.html                      |
 | If you did not receive a copy of the Apache2.0 license and are unable|
 | to obtain it through the world-wide-web, please send a note to       |
 | license@swoole.com so we can mail you a copy immediately.            |
 +----------------------------------------------------------------------+
 | Author: Xinyu Zhu  <xyzhu1120@gmail.com>                             |
 |         Tianfeng Han <rango@swoole.com>                              |
 +----------------------------------------------------------------------+
 */

#include "php_swoole.h"

#ifdef SW_COROUTINE
#include "swoole_coroutine.h"
#include "channel.h"

using namespace swoole;

static PHP_METHOD(swoole_channel_coro, __construct);
static PHP_METHOD(swoole_channel_coro, __destruct);
static PHP_METHOD(swoole_channel_coro, push);
static PHP_METHOD(swoole_channel_coro, pop);
static PHP_METHOD(swoole_channel_coro, close);
static PHP_METHOD(swoole_channel_coro, stats);
static PHP_METHOD(swoole_channel_coro, length);
static PHP_METHOD(swoole_channel_coro, isEmpty);
static PHP_METHOD(swoole_channel_coro, isFull);

static zend_class_entry swoole_channel_coro_ce;
static zend_class_entry *swoole_channel_coro_class_entry_ptr;

ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_channel_coro_construct, 0, 0, 0)
    ZEND_ARG_INFO(0, size)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_channel_coro_push, 0, 0, 1)
    ZEND_ARG_INFO(0, data)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_channel_coro_pop, 0, 0, 0)
    ZEND_ARG_INFO(0, timeout)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_void, 0, 0, 0)
ZEND_END_ARG_INFO()

static const zend_function_entry swoole_channel_coro_methods[] =
{
    PHP_ME(swoole_channel_coro, __construct, arginfo_swoole_channel_coro_construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
    PHP_ME(swoole_channel_coro, __destruct, arginfo_swoole_void, ZEND_ACC_PUBLIC | ZEND_ACC_DTOR)
    PHP_ME(swoole_channel_coro, push, arginfo_swoole_channel_coro_push, ZEND_ACC_PUBLIC)
    PHP_ME(swoole_channel_coro, pop,  arginfo_swoole_channel_coro_pop,  ZEND_ACC_PUBLIC)
    PHP_ME(swoole_channel_coro, isEmpty, arginfo_swoole_void, ZEND_ACC_PUBLIC)
    PHP_ME(swoole_channel_coro, isFull, arginfo_swoole_void, ZEND_ACC_PUBLIC)
    PHP_ME(swoole_channel_coro, close, arginfo_swoole_void, ZEND_ACC_PUBLIC)
    PHP_ME(swoole_channel_coro, stats, arginfo_swoole_void, ZEND_ACC_PUBLIC)
    PHP_ME(swoole_channel_coro, length, arginfo_swoole_void, ZEND_ACC_PUBLIC)
    PHP_FE_END
};

void swoole_channel_coro_init(int module_number)
{
    INIT_CLASS_ENTRY(swoole_channel_coro_ce, "Swoole\\Coroutine\\Channel", swoole_channel_coro_methods);
    swoole_channel_coro_class_entry_ptr = zend_register_internal_class(&swoole_channel_coro_ce);

    if (SWOOLE_G(use_shortname))
    {
        sw_zend_register_class_alias("chan", swoole_channel_coro_class_entry_ptr);
    }

    zend_declare_property_long(swoole_channel_coro_class_entry_ptr, SW_STRL("capacity")-1, 0, ZEND_ACC_PUBLIC);
    zend_declare_property_long(swoole_channel_coro_class_entry_ptr, SW_STRL("errCode")-1, 0, ZEND_ACC_PUBLIC);
}

static PHP_METHOD(swoole_channel_coro, __construct)
{
    zend_long capacity = 0;

    if (zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &capacity) == FAILURE)
    {
        RETURN_FALSE;
    }
    if (capacity <= 0)
    {
        capacity = 1;
    }

    php_swoole_check_reactor();

    Channel *chan = new Channel(capacity);
    zend_update_property_long(swoole_channel_coro_class_entry_ptr, getThis(), ZEND_STRL("capacity"), capacity);

    swoole_set_object(getThis(), chan);
}

static PHP_METHOD(swoole_channel_coro, __destruct)
{
    SW_PREVENT_USER_DESTRUCT;

    Channel *chan = (Channel *) swoole_get_object(getThis());
    while (chan->length() > 0)
    {
        zval *data = (zval *) chan->pop_data();
        if (data)
        {
            sw_zval_free(data);
        }
    }
    delete chan;
    swoole_set_object(getThis(), NULL);
}

static PHP_METHOD(swoole_channel_coro, push)
{
    coro_check();

    Channel *chan = (Channel *) swoole_get_object(getThis());
    if (chan->closed)
    {
        zend_update_property_long(swoole_channel_coro_class_entry_ptr, getThis(), SW_STRL("errCode")-1, -2);
        RETURN_FALSE;
    }

    zval *zdata;
    if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &zdata) == FAILURE)
    {
        RETURN_FALSE;
    }

    Z_TRY_ADDREF_P(zdata);
    if (chan->push(sw_zval_dup(zdata)))
    {
        RETURN_TRUE;
    }
    else
    {
        Z_TRY_DELREF_P(zdata);
        RETURN_FALSE;
    }
}

static PHP_METHOD(swoole_channel_coro, pop)
{
    coro_check();

    Channel *chan = (Channel *) swoole_get_object(getThis());
    if (chan->closed)
    {
        zend_update_property_long(swoole_channel_coro_class_entry_ptr, getThis(), SW_STRL("errCode")-1, -2);
        RETURN_FALSE;
    }

    double timeout = -1;
    if (zend_parse_parameters(ZEND_NUM_ARGS(), "|d", &timeout) == FAILURE)
    {
        RETURN_FALSE;
    }
    zval *data = (zval *) chan->pop(timeout);
    if (data)
    {
        RETVAL_ZVAL(data, 0, 0);
        efree(data);
    }
    else
    {
        zend_update_property_long(swoole_channel_coro_class_entry_ptr, getThis(), SW_STRL("errCode")-1, chan->closed ? -2 : -1);
        RETURN_FALSE;
    }
}

static PHP_METHOD(swoole_channel_coro, close)
{
    Channel *chan = (Channel *) swoole_get_object(getThis());
    RETURN_BOOL(chan->close());
}

static PHP_METHOD(swoole_channel_coro, length)
{
    Channel *chan = (Channel *) swoole_get_object(getThis());
    RETURN_LONG(chan->length());
}

static PHP_METHOD(swoole_channel_coro, isEmpty)
{
    Channel *chan = (Channel *) swoole_get_object(getThis());
    RETURN_BOOL(chan->is_empty());
}

static PHP_METHOD(swoole_channel_coro, isFull)
{
    Channel *chan = (Channel *) swoole_get_object(getThis());
    RETURN_BOOL(chan->is_full());
}

static PHP_METHOD(swoole_channel_coro, stats)
{
    Channel *chan = (Channel *) swoole_get_object(getThis());
    array_init(return_value);
    add_assoc_long_ex(return_value, ZEND_STRL("consumer_num"), chan->consumer_num());
    add_assoc_long_ex(return_value, ZEND_STRL("producer_num"), chan->producer_num());
    if (chan)
    {
        add_assoc_long_ex(return_value, ZEND_STRL("queue_num"), chan->length());
    }
}

#endif
<|endoftext|>


<commit_before>/*
 +----------------------------------------------------------------------+
 | Swoole                                                               |
 +----------------------------------------------------------------------+
 | Copyright (c) 2012-2018 The Swoole Group                             |
 +----------------------------------------------------------------------+
 | This source file is subject to version 2.0 of the Apache license,    |
 | that is bundled with this package in the file LICENSE, and is        |
 | available through the world-wide-web at the following url:           |
 | http://www.apache.org/licenses/LICENSE-2.0.html                      |
 | If you did not receive a copy of the Apache2.0 license and are unable|
 | to obtain it through the world-wide-web, please send a note to       |
 | license@swoole.com so we can mail you a copy immediately.            |
 +----------------------------------------------------------------------+
 | Author: Xinyu Zhu  <xyzhu1120@gmail.com>                             |
 |         Tianfeng Han <rango@swoole.com>                              |
 +----------------------------------------------------------------------+
 */

#include "php_swoole_cxx.h"

#include "coroutine_channel.h"

using swoole::coroutine::Channel;

static zend_class_entry *swoole_channel_coro_ce;
static zend_object_handlers swoole_channel_coro_handlers;

typedef struct
{
    Channel *chan;
    zend_object std;
} channel_coro;

static PHP_METHOD(swoole_channel_coro, __construct);
static PHP_METHOD(swoole_channel_coro, push);
static PHP_METHOD(swoole_channel_coro, pop);
static PHP_METHOD(swoole_channel_coro, close);
static PHP_METHOD(swoole_channel_coro, stats);
static PHP_METHOD(swoole_channel_coro, length);
static PHP_METHOD(swoole_channel_coro, isEmpty);
static PHP_METHOD(swoole_channel_coro, isFull);

ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_channel_coro_construct, 0, 0, 0)
    ZEND_ARG_INFO(0, size)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_channel_coro_push, 0, 0, 1)
    ZEND_ARG_INFO(0, data)
    ZEND_ARG_INFO(0, timeout)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_channel_coro_pop, 0, 0, 0)
    ZEND_ARG_INFO(0, timeout)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_void, 0, 0, 0)
ZEND_END_ARG_INFO()

static const zend_function_entry swoole_channel_coro_methods[] =
{
    PHP_ME(swoole_channel_coro, __construct, arginfo_swoole_channel_coro_construct, ZEND_ACC_PUBLIC)
    PHP_ME(swoole_channel_coro, push, arginfo_swoole_channel_coro_push, ZEND_ACC_PUBLIC)
    PHP_ME(swoole_channel_coro, pop,  arginfo_swoole_channel_coro_pop,  ZEND_ACC_PUBLIC)
    PHP_ME(swoole_channel_coro, isEmpty, arginfo_swoole_void, ZEND_ACC_PUBLIC)
    PHP_ME(swoole_channel_coro, isFull, arginfo_swoole_void, ZEND_ACC_PUBLIC)
    PHP_ME(swoole_channel_coro, close, arginfo_swoole_void, ZEND_ACC_PUBLIC)
    PHP_ME(swoole_channel_coro, stats, arginfo_swoole_void, ZEND_ACC_PUBLIC)
    PHP_ME(swoole_channel_coro, length, arginfo_swoole_void, ZEND_ACC_PUBLIC)
    PHP_FE_END
};

enum swChannelErrorCode
{
    SW_CHANNEL_OK = 0,
    SW_CHANNEL_TIMEOUT = -1,
    SW_CHANNEL_CLOSED = -2,
};

static sw_inline channel_coro* swoole_channel_coro_fetch_object(zend_object *obj)
{
    return (channel_coro *) ((char *) obj - swoole_channel_coro_handlers.offset);
}

static sw_inline Channel * swoole_get_channel(zval *zobject)
{
    Channel *chan = swoole_channel_coro_fetch_object(Z_OBJ_P(zobject))->chan;
    if (UNEXPECTED(!chan))
    {
        php_swoole_fatal_error(E_ERROR, "you must call Channel constructor first");
    }
    return chan;
}

static void swoole_channel_coro_free_object(zend_object *object)
{
    channel_coro *chan_t = swoole_channel_coro_fetch_object(object);
    Channel *chan = chan_t->chan;
    if (chan)
    {
        zval *data;
        while ((data = (zval *) chan->pop_data()))
        {
            sw_zval_free(data);
        }
        delete chan;
    }
    zend_object_std_dtor(&chan_t->std);
}

static zend_object *swoole_channel_coro_create_object(zend_class_entry *ce)
{
    channel_coro *chan_t = (channel_coro *) ecalloc(1, sizeof(channel_coro) + zend_object_properties_size(ce));
    zend_object_std_init(&chan_t->std, ce);
    object_properties_init(&chan_t->std, ce);
    chan_t->std.handlers = &swoole_channel_coro_handlers;
    return &chan_t->std;
}

void php_swoole_channel_coro_minit(int module_number)
{
    SW_INIT_CLASS_ENTRY(swoole_channel_coro, "Swoole\\Coroutine\\Channel", NULL, "Co\\Channel", swoole_channel_coro_methods);
    SW_SET_CLASS_SERIALIZABLE(swoole_channel_coro, zend_class_serialize_deny, zend_class_unserialize_deny);
    SW_SET_CLASS_CLONEABLE(swoole_channel_coro, sw_zend_class_clone_deny);
    SW_SET_CLASS_UNSET_PROPERTY_HANDLER(swoole_channel_coro, sw_zend_class_unset_property_deny);
    SW_SET_CLASS_CUSTOM_OBJECT(swoole_channel_coro, swoole_channel_coro_create_object, swoole_channel_coro_free_object, channel_coro, std);
    if (SWOOLE_G(use_shortname))
    {
        SW_CLASS_ALIAS("Chan", swoole_channel_coro);
    }

    zend_declare_property_long(swoole_channel_coro_ce, ZEND_STRL("capacity"), 0, ZEND_ACC_PUBLIC);
    zend_declare_property_long(swoole_channel_coro_ce, ZEND_STRL("errCode"), 0, ZEND_ACC_PUBLIC);

    SW_REGISTER_LONG_CONSTANT("SWOOLE_CHANNEL_OK", SW_CHANNEL_OK);
    SW_REGISTER_LONG_CONSTANT("SWOOLE_CHANNEL_TIMEOUT", SW_CHANNEL_TIMEOUT);
    SW_REGISTER_LONG_CONSTANT("SWOOLE_CHANNEL_CLOSED", SW_CHANNEL_CLOSED);
}

static PHP_METHOD(swoole_channel_coro, __construct)
{
    zend_long capacity = 1;

    ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 0, 1)
        Z_PARAM_OPTIONAL
        Z_PARAM_LONG(capacity)
    ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);

    if (capacity <= 0)
    {
        capacity = 1;
    }

    channel_coro *chan_t = swoole_channel_coro_fetch_object(Z_OBJ_P(ZEND_THIS));
    chan_t->chan = new Channel(capacity);
    zend_update_property_long(swoole_channel_coro_ce, ZEND_THIS, ZEND_STRL("capacity"), capacity);
}

static PHP_METHOD(swoole_channel_coro, push)
{
    Channel *chan = swoole_get_channel(ZEND_THIS);
    if (chan->is_closed())
    {
        zend_update_property_long(swoole_channel_coro_ce, ZEND_THIS, ZEND_STRL("errCode"), SW_CHANNEL_CLOSED);
        RETURN_FALSE;
    }
    else
    {
        zend_update_property_long(swoole_channel_coro_ce, ZEND_THIS, ZEND_STRL("errCode"), SW_CHANNEL_OK);
    }

    zval *zdata;
    double timeout = -1;

    ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 1, 2)
        Z_PARAM_ZVAL(zdata)
        Z_PARAM_OPTIONAL
        Z_PARAM_DOUBLE(timeout)
    ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);

    Z_TRY_ADDREF_P(zdata);
    zdata = sw_zval_dup(zdata);
    if (chan->push(zdata, timeout))
    {
        RETURN_TRUE;
    }
    else
    {
        zend_update_property_long(swoole_channel_coro_ce, ZEND_THIS, ZEND_STRL("errCode"), chan->is_closed() ? SW_CHANNEL_CLOSED : SW_CHANNEL_TIMEOUT);
        Z_TRY_DELREF_P(zdata);
        efree(zdata);
        RETURN_FALSE;
    }
}

static PHP_METHOD(swoole_channel_coro, pop)
{
    Channel *chan = swoole_get_channel(ZEND_THIS);
    if (chan->is_closed())
    {
        zend_update_property_long(swoole_channel_coro_ce, ZEND_THIS, ZEND_STRL("errCode"), SW_CHANNEL_CLOSED);
        RETURN_FALSE;
    }
    else
    {
        zend_update_property_long(swoole_channel_coro_ce, ZEND_THIS, ZEND_STRL("errCode"), SW_CHANNEL_OK);
    }

    double timeout = -1;

    ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 0, 1)
        Z_PARAM_OPTIONAL
        Z_PARAM_DOUBLE(timeout)
    ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);

    zval *data = (zval *) chan->pop(timeout);
    if (data)
    {
        RETVAL_ZVAL(data, 0, 0);
        efree(data);
    }
    else
    {
        zend_update_property_long(swoole_channel_coro_ce, ZEND_THIS, ZEND_STRL("errCode"), chan->is_closed() ? SW_CHANNEL_CLOSED : SW_CHANNEL_TIMEOUT);
        RETURN_FALSE;
    }
}

static PHP_METHOD(swoole_channel_coro, close)
{
    Channel *chan = swoole_get_channel(ZEND_THIS);
    RETURN_BOOL(chan->close());
}

static PHP_METHOD(swoole_channel_coro, length)
{
    Channel *chan = swoole_get_channel(ZEND_THIS);
    RETURN_LONG(chan->length());
}

static PHP_METHOD(swoole_channel_coro, isEmpty)
{
    Channel *chan = swoole_get_channel(ZEND_THIS);
    RETURN_BOOL(chan->is_empty());
}

static PHP_METHOD(swoole_channel_coro, isFull)
{
    Channel *chan = swoole_get_channel(ZEND_THIS);
    RETURN_BOOL(chan->is_full());
}

static PHP_METHOD(swoole_channel_coro, stats)
{
    Channel *chan = swoole_get_channel(ZEND_THIS);
    array_init(return_value);
    add_assoc_long_ex(return_value, ZEND_STRL("consumer_num"), chan->consumer_num());
    add_assoc_long_ex(return_value, ZEND_STRL("producer_num"), chan->producer_num());
    add_assoc_long_ex(return_value, ZEND_STRL("queue_num"), chan->length());
}

<commit_msg>Fix channel free_object<commit_after>/*
 +----------------------------------------------------------------------+
 | Swoole                                                               |
 +----------------------------------------------------------------------+
 | Copyright (c) 2012-2018 The Swoole Group                             |
 +----------------------------------------------------------------------+
 | This source file is subject to version 2.0 of the Apache license,    |
 | that is bundled with this package in the file LICENSE, and is        |
 | available through the world-wide-web at the following url:           |
 | http://www.apache.org/licenses/LICENSE-2.0.html                      |
 | If you did not receive a copy of the Apache2.0 license and are unable|
 | to obtain it through the world-wide-web, please send a note to       |
 | license@swoole.com so we can mail you a copy immediately.            |
 +----------------------------------------------------------------------+
 | Author: Xinyu Zhu  <xyzhu1120@gmail.com>                             |
 |         Tianfeng Han <rango@swoole.com>                              |
 +----------------------------------------------------------------------+
 */

#include "php_swoole_cxx.h"

#include "coroutine_channel.h"

using swoole::coroutine::Channel;

static zend_class_entry *swoole_channel_coro_ce;
static zend_object_handlers swoole_channel_coro_handlers;

typedef struct
{
    Channel *chan;
    zend_object std;
} channel_coro;

static PHP_METHOD(swoole_channel_coro, __construct);
static PHP_METHOD(swoole_channel_coro, push);
static PHP_METHOD(swoole_channel_coro, pop);
static PHP_METHOD(swoole_channel_coro, close);
static PHP_METHOD(swoole_channel_coro, stats);
static PHP_METHOD(swoole_channel_coro, length);
static PHP_METHOD(swoole_channel_coro, isEmpty);
static PHP_METHOD(swoole_channel_coro, isFull);

ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_channel_coro_construct, 0, 0, 0)
    ZEND_ARG_INFO(0, size)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_channel_coro_push, 0, 0, 1)
    ZEND_ARG_INFO(0, data)
    ZEND_ARG_INFO(0, timeout)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_channel_coro_pop, 0, 0, 0)
    ZEND_ARG_INFO(0, timeout)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_void, 0, 0, 0)
ZEND_END_ARG_INFO()

static const zend_function_entry swoole_channel_coro_methods[] =
{
    PHP_ME(swoole_channel_coro, __construct, arginfo_swoole_channel_coro_construct, ZEND_ACC_PUBLIC)
    PHP_ME(swoole_channel_coro, push, arginfo_swoole_channel_coro_push, ZEND_ACC_PUBLIC)
    PHP_ME(swoole_channel_coro, pop,  arginfo_swoole_channel_coro_pop,  ZEND_ACC_PUBLIC)
    PHP_ME(swoole_channel_coro, isEmpty, arginfo_swoole_void, ZEND_ACC_PUBLIC)
    PHP_ME(swoole_channel_coro, isFull, arginfo_swoole_void, ZEND_ACC_PUBLIC)
    PHP_ME(swoole_channel_coro, close, arginfo_swoole_void, ZEND_ACC_PUBLIC)
    PHP_ME(swoole_channel_coro, stats, arginfo_swoole_void, ZEND_ACC_PUBLIC)
    PHP_ME(swoole_channel_coro, length, arginfo_swoole_void, ZEND_ACC_PUBLIC)
    PHP_FE_END
};

enum swChannelErrorCode
{
    SW_CHANNEL_OK = 0,
    SW_CHANNEL_TIMEOUT = -1,
    SW_CHANNEL_CLOSED = -2,
};

static sw_inline channel_coro* swoole_channel_coro_fetch_object(zend_object *obj)
{
    return (channel_coro *) ((char *) obj - swoole_channel_coro_handlers.offset);
}

static sw_inline Channel * swoole_get_channel(zval *zobject)
{
    Channel *chan = swoole_channel_coro_fetch_object(Z_OBJ_P(zobject))->chan;
    if (UNEXPECTED(!chan))
    {
        php_swoole_fatal_error(E_ERROR, "you must call Channel constructor first");
    }
    return chan;
}

static void swoole_channel_coro_free_object(zend_object *object)
{
    channel_coro *chan_t = swoole_channel_coro_fetch_object(object);
    Channel *chan = chan_t->chan;
    if (chan)
    {
        chan->close();
        zval *data;
        while ((data = (zval *) chan->pop_data()))
        {
            sw_zval_free(data);
        }
        delete chan;
    }
    zend_object_std_dtor(&chan_t->std);
}

static zend_object *swoole_channel_coro_create_object(zend_class_entry *ce)
{
    channel_coro *chan_t = (channel_coro *) ecalloc(1, sizeof(channel_coro) + zend_object_properties_size(ce));
    zend_object_std_init(&chan_t->std, ce);
    object_properties_init(&chan_t->std, ce);
    chan_t->std.handlers = &swoole_channel_coro_handlers;
    return &chan_t->std;
}

void php_swoole_channel_coro_minit(int module_number)
{
    SW_INIT_CLASS_ENTRY(swoole_channel_coro, "Swoole\\Coroutine\\Channel", NULL, "Co\\Channel", swoole_channel_coro_methods);
    SW_SET_CLASS_SERIALIZABLE(swoole_channel_coro, zend_class_serialize_deny, zend_class_unserialize_deny);
    SW_SET_CLASS_CLONEABLE(swoole_channel_coro, sw_zend_class_clone_deny);
    SW_SET_CLASS_UNSET_PROPERTY_HANDLER(swoole_channel_coro, sw_zend_class_unset_property_deny);
    SW_SET_CLASS_CUSTOM_OBJECT(swoole_channel_coro, swoole_channel_coro_create_object, swoole_channel_coro_free_object, channel_coro, std);
    if (SWOOLE_G(use_shortname))
    {
        SW_CLASS_ALIAS("Chan", swoole_channel_coro);
    }

    zend_declare_property_long(swoole_channel_coro_ce, ZEND_STRL("capacity"), 0, ZEND_ACC_PUBLIC);
    zend_declare_property_long(swoole_channel_coro_ce, ZEND_STRL("errCode"), 0, ZEND_ACC_PUBLIC);

    SW_REGISTER_LONG_CONSTANT("SWOOLE_CHANNEL_OK", SW_CHANNEL_OK);
    SW_REGISTER_LONG_CONSTANT("SWOOLE_CHANNEL_TIMEOUT", SW_CHANNEL_TIMEOUT);
    SW_REGISTER_LONG_CONSTANT("SWOOLE_CHANNEL_CLOSED", SW_CHANNEL_CLOSED);
}

static PHP_METHOD(swoole_channel_coro, __construct)
{
    zend_long capacity = 1;

    ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 0, 1)
        Z_PARAM_OPTIONAL
        Z_PARAM_LONG(capacity)
    ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);

    if (capacity <= 0)
    {
        capacity = 1;
    }

    channel_coro *chan_t = swoole_channel_coro_fetch_object(Z_OBJ_P(ZEND_THIS));
    chan_t->chan = new Channel(capacity);
    zend_update_property_long(swoole_channel_coro_ce, ZEND_THIS, ZEND_STRL("capacity"), capacity);
}

static PHP_METHOD(swoole_channel_coro, push)
{
    Channel *chan = swoole_get_channel(ZEND_THIS);
    if (chan->is_closed())
    {
        zend_update_property_long(swoole_channel_coro_ce, ZEND_THIS, ZEND_STRL("errCode"), SW_CHANNEL_CLOSED);
        RETURN_FALSE;
    }
    else
    {
        zend_update_property_long(swoole_channel_coro_ce, ZEND_THIS, ZEND_STRL("errCode"), SW_CHANNEL_OK);
    }

    zval *zdata;
    double timeout = -1;

    ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 1, 2)
        Z_PARAM_ZVAL(zdata)
        Z_PARAM_OPTIONAL
        Z_PARAM_DOUBLE(timeout)
    ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);

    Z_TRY_ADDREF_P(zdata);
    zdata = sw_zval_dup(zdata);
    if (chan->push(zdata, timeout))
    {
        RETURN_TRUE;
    }
    else
    {
        zend_update_property_long(swoole_channel_coro_ce, ZEND_THIS, ZEND_STRL("errCode"), chan->is_closed() ? SW_CHANNEL_CLOSED : SW_CHANNEL_TIMEOUT);
        Z_TRY_DELREF_P(zdata);
        efree(zdata);
        RETURN_FALSE;
    }
}

static PHP_METHOD(swoole_channel_coro, pop)
{
    Channel *chan = swoole_get_channel(ZEND_THIS);
    if (chan->is_closed())
    {
        zend_update_property_long(swoole_channel_coro_ce, ZEND_THIS, ZEND_STRL("errCode"), SW_CHANNEL_CLOSED);
        RETURN_FALSE;
    }
    else
    {
        zend_update_property_long(swoole_channel_coro_ce, ZEND_THIS, ZEND_STRL("errCode"), SW_CHANNEL_OK);
    }

    double timeout = -1;

    ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 0, 1)
        Z_PARAM_OPTIONAL
        Z_PARAM_DOUBLE(timeout)
    ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);

    zval *zdata = (zval *) chan->pop(timeout);
    if (zdata)
    {
        RETVAL_ZVAL(zdata, 0, 0);
        efree(zdata);
    }
    else
    {
        zend_update_property_long(swoole_channel_coro_ce, ZEND_THIS, ZEND_STRL("errCode"), chan->is_closed() ? SW_CHANNEL_CLOSED : SW_CHANNEL_TIMEOUT);
        RETURN_FALSE;
    }
}

static PHP_METHOD(swoole_channel_coro, close)
{
    Channel *chan = swoole_get_channel(ZEND_THIS);
    RETURN_BOOL(chan->close());
}

static PHP_METHOD(swoole_channel_coro, length)
{
    Channel *chan = swoole_get_channel(ZEND_THIS);
    RETURN_LONG(chan->length());
}

static PHP_METHOD(swoole_channel_coro, isEmpty)
{
    Channel *chan = swoole_get_channel(ZEND_THIS);
    RETURN_BOOL(chan->is_empty());
}

static PHP_METHOD(swoole_channel_coro, isFull)
{
    Channel *chan = swoole_get_channel(ZEND_THIS);
    RETURN_BOOL(chan->is_full());
}

static PHP_METHOD(swoole_channel_coro, stats)
{
    Channel *chan = swoole_get_channel(ZEND_THIS);
    array_init(return_value);
    add_assoc_long_ex(return_value, ZEND_STRL("consumer_num"), chan->consumer_num());
    add_assoc_long_ex(return_value, ZEND_STRL("producer_num"), chan->producer_num());
    add_assoc_long_ex(return_value, ZEND_STRL("queue_num"), chan->length());
}

<|endoftext|>