Design dettagliato del layout di Gecko
Articolo originale: http://lxr.mozilla.org/seamonkey/source/layout/doc/DD-SpaceManager.html
Traduzione: Gabriele Romanato (20 febbraio 2008)
Design dettagliato dello Space Manager
Sguardo d'insieme
Lo Space Manager, e le relative classi e strutture, sono una parte importante del Layout System di Gecko, nello specifico del layout Block. Si veda il documento sul design di alto livello per una panoramica sullo Space Manager, e questo documento come introduzione alle classi, strutture e algoritmi.
nsSpaceManager
Lo Space Manager è la classe centrale di un gruppo di classi che gestisce lo spazio occupato e disponibile che esiste nelle fasce lungo il canvas. L'obiettivo primario dello Space Manager è quello di fornire informazioni su queste fasce per supportare il concetto CSS di elementi flottati.
Tre sono le parti importanti della API dello Space Manager: le parti che gestiscono le coordinate di spazio dello Space Manager, le parti che gestiscono le regioni controllate dallo Space Manager e le parti che gestiscono gli intervalli dell'impatto dei float.
La classe nsSpaceManager viene dichiarata nel file nsSpaceManger.h. La classe viene usata solo nel modulo del layout e non può essere esportata al di fuori di questo modulo (non ve n'è il bisogno). Non è una classe a scopo generale, e non vi sono sottoclassi.
Ecco la dichiarazione della classe, presa dal file sorgente dell'8 gennaio 2002.
/*** Classe per gestire le fasce di spazio disponibile. Lo space manager* definisce una coordinata di spazio con origine a (0, 0) che cresce verso il basso* e verso destra.*/class nsSpaceManager {public:nsSpaceManager(nsIPresShell* aPresShell, nsIFrame* aFrame);~nsSpaceManager();void* operator new(size_t aSize);void operator delete(void* aPtr, size_t aSize);static void Shutdown();/** Ottiene il frame associato con lo space manager. Questo frame* ha creato lo space manager, e la coordinata globale di spazio è* relativa a questo frame.** Potete usare QueryInterface() su questo frame per ottenere qualsiasi* interfaccia aggiuntiva.*/nsIFrame* GetFrame() const { return mFrame; }/*** Traduce l'origine corrente nelle specifiche (dx, dy). Questo* crea una nuova coordinata di spazio locale relativa alla corrente* coordinata di spazio.*/void Translate(nscoord aDx, nscoord aDy) { mX += aDx; mY += aDy; }/*** Restituisce la traduzione corrente dalla coordinata locale di spazio alla* coordinata di spazio globale. Rappresenta le chiamate accumulate a* Translate().*/void GetTranslation(nscoord& aX, nscoord& aY) const { aX = mX; aY = mY; }/*** Restituisce la coordinata y maggiore della fascia più inferiore o 0 se non ci sono fasce.** @return PR_TRUE se ci sono fasce PR_FALSE se non ce ne sono*/PRBool YMost(nscoord& aYMost) const;/*** Restituisce una fascia a partire dall'offset-y specificato. I dati della fascia
* indicano quali parti della fascia sono disponibili, e quali parti
* non sono disponibili
*
* I dati della fascia restituiti si trovano nella coordinata di spazio del
* sistema di coordinate locali.
*
* L'origine delle coordinate di spazio locali, lo offset-y e la dimensione massima
* descrivono un rettangolo usato per ritagliare la fascia sottostante di
* spazio disponibile, ossia
* {0, aYOffset, aMaxSize.width, aMaxSize.height} nello spazio
* di coordinate locali
*
* @param aYOffset lo offset-y di dove inizia la fascia. La coordinata è
* relativa all'angolo superiore sinistro delle coordinate di spazio locali
* @param aMaxSize la dimensione usata per limitare i dati della fascia
* @param aBandData [in,out] usata per restituire l'elenco di trapezoidi che
* descrivono lo spazio disponibile e non disponibile
* @return NS_OK se ha successo e NS_ERROR_FAILURE se i dati della fascia non sono
* grandi abbastanza. Il membro 'count' della struttura dei dati della fascia
* indica quanto grande deve essere l'array di trapezoidi
*/nsresult GetBandData(nscoord aYOffset,const nsSize& aMaxSize,nsBandData& aBandData) const;/**
* Aggiunge una regione di spazio non disponibile. Lo spazio è
* relativo al sistema di coordinate locali.
*
* La regione viene marcata con un frame
*
* @param aFrame il frame usato per identificare la regione. Non deve essere NULL
* @param aUnavailableSpace il rettangolo circostante di spazio non disponibile
* @return NS_OK se ha successo
* NS_ERROR_FAILURE se c'è una regione marcata con aFrame
*/nsresult AddRectRegion(nsIFrame* aFrame,const nsRect& aUnavailableSpace);/**
* Ridimensiona la regione rettangolare associata con aFrame dei
* delta specificati. Il cambiamento dell'altezza si applica sempre al limite inferiore del rettangolo
* esistente. Specificate se il cambiamento della larghezza si applica al limite sinistro o destro
*
* Restituisce NS_OK se ha successo, NS_ERROR_INVALID_ARG se non c'è una regione
* marcata con aFrame
*/enum AffectedEdge {LeftEdge, RightEdge};nsresult ResizeRectRegion(nsIFrame* aFrame,nscoord aDeltaWidth,nscoord aDeltaHeight,AffectedEdge aEdge = RightEdge);/**
* Sposta la regione associata con aFrame della misura specificata.
*
* Restituisce NS_OK se ha successo, NS_ERROR_INVALID_ARG se non c'è una regione
* marcata con aFrame
*/nsresult OffsetRegion(nsIFrame* aFrame, nscoord dx, nscoord dy);/**
* Rimuove la regione associata con aFrame.
*
* Restituisce NS_OK se ha successo e NS_ERROR_INVALID_ARG se non c'è una regione
* marcata con aFrame
*/nsresult RemoveRegion(nsIFrame* aFrame);/**
* Pulisce l'elenco delle regioni che rappresentano lo spazio non disponibile.
*/void ClearRegions();/**
* Metodi per gestire la propagazione del danno dei float durante il
* reflow.
*/PRBool HasFloatDamage(){return !mFloatDamage.IsEmpty();}void IncludeInDamage(nscoord aIntervalBegin, nscoord aIntervalEnd){mFloatDamage.IncludeInterval(aIntervalBegin + mY, aIntervalEnd + mY);}PRBool IntersectsDamage(nscoord aIntervalBegin, nscoord aIntervalEnd){return mFloatDamage.Intersects(aIntervalBegin + mY, aIntervalEnd + mY);}#ifdef DEBUG/**
* Invia lo stato dello Space Manager ad un file
*/nsresult List(FILE* out);void SizeOf(nsISizeOfHandler* aHandler, PRUint32* aResult) const;#endifprivate:// Struttura che conserva le informazioni sulla regione associata
// ad un particolare framestruct FrameInfo {nsIFrame* const mFrame;nsRect mRect; // regione rettangolareFrameInfo* mNext;FrameInfo(nsIFrame* aFrame, const nsRect& aRect);#ifdef NS_BUILD_REFCNT_LOGGING~FrameInfo();#endif};// Elenco doubly-linked di rettangoli di fasciastruct BandRect : PRCListStr {nscoord mLeft, mTop;nscoord mRight, mBottom;PRIntn mNumFrames; // numero di frame che occupano questo rettangolounion {nsIFrame* mFrame; // frame singolo che occupa lo spazionsVoidArray* mFrames; // elenco di frame che occupano lo spazio};BandRect(nscoord aLeft, nscoord aTop,nscoord aRight, nscoord aBottom,nsIFrame*);BandRect(nscoord aLeft, nscoord aTop,nscoord aRight, nscoord aBottom,nsVoidArray*);~BandRect();// Elenco di operazioniBandRect* Next() const {return (BandRect*)PR_NEXT_LINK(this);}
BandRect* Prev() const {return (BandRect*)PR_PREV_LINK(this);}
void InsertBefore(BandRect* aBandRect) {PR_INSERT_BEFORE(aBandRect, this);}
void InsertAfter(BandRect* aBandRect) {PR_INSERT_AFTER(aBandRect, this);}
void Remove() {PR_REMOVE_LINK(this);}// Divide il rettangolo di fascia in due in verticale, con questo rettangolo di fascia che diventa
// la parte superiore, e un nuovo rettangolo di fascia che viene allocato e restituito per la
// parte inferiore
//
// Non inserisce il nuovo rettangolo di fascia nell'elenco linkatoBandRect* SplitVertically(nscoord aBottom);// Divide il rettangolo di fascia in due in orizzontale, con questo rettangolo di fascia che diventa
// la parte sinistra, e un nuovo rettangolo di fascia che viene allocato e restituito per la
// parte destra
//
// Non inserisce il nuovo rettangolo di fascia nell'elenco linkatoBandRect* SplitHorizontally(nscoord aRight);// Funzioni accessoriePRBool IsOccupiedBy(const nsIFrame*) const;
void AddFrame(const nsIFrame*);
void RemoveFrame(const nsIFrame*);
PRBool HasSameFrameList(const BandRect* aBandRect) const;
PRInt32 Length() const;
};// Elenco linkato circolare di rettangoli di fasciastruct BandList : BandRect {BandList();// AccessoriPRBool IsEmpty() const {return PR_CLIST_IS_EMPTY((PRCListStr*)this);}
BandRect* Head() const {return (BandRect*)PR_LIST_HEAD(this);}
BandRect* Tail() const {return (BandRect*)PR_LIST_TAIL(this);}// Operazionivoid Append(BandRect* aBandRect) {PR_APPEND_LINK(aBandRect, this);}// Rimuove e cancella tutti i rettangoli di fascia nell'elencovoid Clear();};FrameInfo* GetFrameInfoFor(nsIFrame* aFrame);
FrameInfo* CreateFrameInfo(nsIFrame* aFrame, const nsRect& aRect);
void DestroyFrameInfo(FrameInfo*);void ClearFrameInfo();
void ClearBandRects();BandRect* GetNextBand(const BandRect* aBandRect) const;
void DivideBand(BandRect* aBand, nscoord aBottom);
PRBool CanJoinBands(BandRect* aBand, BandRect* aPrevBand);
PRBool JoinBands(BandRect* aBand, BandRect* aPrevBand);
void AddRectToBand(BandRect* aBand, BandRect* aBandRect);
void InsertBandRect(BandRect* aBandRect);nsresult GetBandAvailableSpace(const BandRect* aBand,nscoord aY,
const nsSize& aMaxSize,
nsBandData& aAvailableSpace) const;nsIFrame* const mFrame; // frame associato con lo Space Manager
nscoord mX, mY; // traduzione da coordinata di spazio locale a globale
BandList mBandList; // header/sentinel per un elenco linkato circolare di rettangoli di fascia
FrameInfo* mFrameInfoMap;
nsIntervalSet mFloatDamage;static PRInt32 sCachedSpaceManagerCount;
static void* sCachedSpaceManagers[NS_SPACE_MANAGER_CACHE_SIZE];nsSpaceManager(const nsSpaceManager&); // nessuna implementazione
void operator=(const nsSpaceManager&); // nessuna implementazione};
API pubblica
Ciclo di vita
Il costruttore richiede una Presentation Shell, usata soprattutto per le operazioni di allocazione, e un frame a cui questo Space Manager è legato. La coordinata di spazio di questo Space Manager è relativa al frame passato al costruttore.
nsSpaceManager(nsIPresShell* aPresShell, nsIFrame* aFrame);~nsSpaceManager();
Gli operatori 'new' e 'delete' vengono sovrascritti per supportare un recycler.
Le istanze dello Space Manager vanno e vengono con una certa frequenza, e
questo recycler impedisce le eccessive allocazioni nell'heap e le diminuzioni
nella performance ad esse associate.
#define NS_SPACE_MANAGER_CACHE_SIZE viene usato per controllare il numero di istanze dello
Space Manager che possono essere presenti nel recycler, attualmente
4. Se più di NS_SPACE_MANAGER_CACHE_SIZE vengono allocate in una volta,
allora si usa l'allocazione standard.
void* operator new(size_t aSize);void operator delete(void* aPtr, size_t aSize);
Un metodo static viene usato per interrompere il recycling dello Space Manager. Questo metodo cancella tutti gli Space Manager nel recycler, e impedisce un ulteriore recycling. È concepito per essere chiamato quando viene terminato il modulo del layout.
static void Shutdown();
Origine/coordinate della traduzione di spazio
/**
* Traduce l'origine corrente alle specifiche (dx, dy). Questo
* crea una nuova coordinata di spazio locale relativa all'attuale
* coordinata di spazio.
*/void Translate(nscoord aDx, nscoord aDy) { mX += aDx; mY += aDy; }/**
* Restituisce l'attuale traduzione dalla coordinata di spazio locale alla
* coordinata di spazio globale. Rappresenta le chiamate accumulate a
* Translate().
*/void GetTranslation(nscoord& aX, nscoord& aY) const { aX = mX; aY = mY; }/**
* Restituisce la coordinata y maggiore della fascia più inferiore o 0 se non ci sono fasce.
*
* @return PR_TRUE se ci sono fasce e PR_FALSE se non ci sono fasce
*/PRBool YMost(nscoord& aYMost) const;
Gestione delle regioni
/**
* Restituisce una fascia a partire dallo offset-y specificato. I dati di fascia
* indicano quali parti della fascia sono disponibili e quali parti
* non lo sono
*
* I dati di fascia restituiti sono le coordinate di spazio del
* sistema di coordinate locali.
*
* L'origine delle coordinate di spazio locali, lo offset-y e la dimensione massima
* descrivono un rettangolo usato per ritagliare la fascia sottostante di
* spazio disponibile, ossia
* {0, aYOffset, aMaxSize.width, aMaxSize.height} nella coordinata di
* spazio locale
*
* @param aYOffset offset-y di dove comincia la fascia. La coordinata è
* relativa all'angolo superiore sinistro della coordinata di spazio locale
* @param aMaxSize la dimensione usata per limitare i dati della fascia
* @param aBandData [in,out] usata per restituire un elenco di trapezoidi che
* descrivono lo spazio disponibile e non disponibile
* @return NS_OK se ha successo e NS_ERROR_FAILURE se i dati della fascia
* non sono abbastanza grandi. Il membro 'count' della struttura dei dati della fascia
* indica quanto grande deve essere l'array di trapezoidi
*/nsresult GetBandData(nscoord aYOffset,const nsSize& aMaxSize,
nsBandData& aBandData) const;/**
* Aggiunge una regione rettangolare di spazio non disponibile. Lo spazio è
* al sistema di coordinate locale.
*
* La regione viene marcata con un frame
*
* @param aFrame il frame usato per identificare la regione. Non deve essere NULL
* @param aUnavailableSpace il rettangolo circostante di spazio non disponibile
* @return NS_OK se ha successo
* NS_ERROR_FAILURE se vi è una regione marcata con aFrame
*/nsresult AddRectRegion(nsIFrame* aFrame,const nsRect& aUnavailableSpace);/**
* Ridimensiona la regione rettangolare marcata con aFrame dei
* delta specificati. La modifica all'altezza si applica sempre al limite inferiore del rettangolo
* esistente. Specificate se la modifica alla larghezza si applica al limite sinistro o destro
*
* Restituisce NS_OK se ha successo, NS_ERROR_INVALID_ARG se non c'è una regione
* marcata con aFrame
*/enum AffectedEdge {LeftEdge, RightEdge};
nsresult ResizeRectRegion(nsIFrame* aFrame,nscoord aDeltaWidth,
nscoord aDeltaHeight,
AffectedEdge aEdge = RightEdge);/**
* Sposta la regione associata con aFrame della misura specificata.
*
* Restituisce NS_OK se ha successo, NS_ERROR_INVALID_ARG se non c'è una regione
* marcata con aFrame
*/nsresult OffsetRegion(nsIFrame* aFrame, nscoord dx, nscoord dy);/**
* Rimuove la regione associata con aFrame.
*
* Restituisce NS_OK se ha successo e NS_ERROR_INVALID_ARG se non c'è una regione
* marcata con aFrame
*/nsresult RemoveRegion(nsIFrame* aFrame);/**
* Pulisce l'elenco di regioni che rappresentano lo spazio non disponibile.
*/void ClearRegions();
Impatto dei float
/**
* Metodi per gestire la propagazione del danno dei float durante il
* reflow.
*/PRBool HasFloatDamage()
{return !mFloatDamage.IsEmpty();}void IncludeInDamage(nscoord aIntervalBegin, nscoord aIntervalEnd)
{mFloatDamage.IncludeInterval(aIntervalBegin + mY, aIntervalEnd + mY);}PRBool IntersectsDamage(nscoord aIntervalBegin, nscoord aIntervalEnd)
{return mFloatDamage.Intersects(aIntervalBegin + mY, aIntervalEnd + mY);}
Metodi per il solo debug
/**
* Invia lo stato dello Space Manager ad un file
*/nsresult List(FILE* out);
void SizeOf(nsISizeOfHandler* aHandler, PRUint32* aResult) const;
Metodi non usati/obsoleti
/*
* Ottiene il frame associato con lo Space Manager. Questo frame
* ha creato lo Space Manager e la coordinata di spazio globale è
* relativa a questo frame.
*
* Potete usare QueryInterface() su questo frame per ottenere qualsiasi
* interfaccia aggiuntiva.
*/nsIFrame* GetFrame() const { return mFrame; }
Note sull'implementazione
Algoritmo 1: GetBandData
GetBandData viene usato per fornire informazioni ai client su quanto spazio è disponibile in una fascia di spazio. Il client fornisce un offset verticale, l'offset-y, che corrisponde alla fascia presa in considerazione. Questo sarà lo spostamento lungo l'asse y del frame che ha il reflow. Il chiamante fornisce anche una collezione di oggetti BandData (un array) e il numero di voci che la collezione può gestire. Se la collezione è troppo piccola, viene restituito un errore e il conteggio viene aggiornato per indicare la dimensione richiesta.
L'algoritmo per fornire i dati della fascia è il seguente:
- Ottenere un offset verticale in coordinate globali (invece che in coordinate relative al frame) aggiungendo l'origine-y dello Space Manager all'offset y passato
- Se il valore y (sistemato) passato è maggiore della fascia più grande da gestire, allora tutto lo spazio è disponibile e viene restituito un singolo trapezoide, marcato come disponibile e dimensionato secondo il valore (passato) massimo di dimensione.
- Se l'offset y (sistemato) interseca una fascia, allora si reperiscano
i dati della fascia:
- si passi in rassegna l'elenco BandData interno dall'inizio alla fine
- per ogni voce, si veda se la parte superiore della fascia è maggiore dell'offset y (sistemato) richiesto
- in caso affermativo, la fascia è al di sotto dell'offset richiesto, quindi l'area tra la fascia e l'offset y è disponibile – si crei un trapezoide con tale regione e lo si restituisca.
- Se l'offset y (sistemato) si trova tra la parte superiore ed inferiore della fascia, allora si ottenga lo spazio disponibile per la fascia chiamando GetBandAvailableSpace
- altrimenti, si passi alla fascia successiva.
GetBandAvailableSpace
Questo metodo viene chiamato solo da GetBandData. Passa in rassegna tutte le fasce nello Space Manager e determina quali fasce intersecano la fascia passata, e se all'interno di queste fasce ci sono regioni disponibili o occupate.
- Si passino in rassegna tutte le fasce fino a quando non si trova una fascia alla destra dell'offset desiderato
- Iniziando da quella fascia, si passino in rassegna le rimanenti fasce:
- se la fascia corrente si trova alla destra della fascia richiesta, allora
c'è spazio disponibile.
- se c'è più spazio nella collezione BandData, allora si aggiunga una trapezoide alla collezione tale che sia marcato come disponibile e abbia un rettangolo che rappresenti lo spazio tra le fascia di riferimento e la fascia da esaminare
- se non c'è più spazio nella collezione BandData, estimate the si faccia uno stima del numero di voci richieste come conteggio corrente più due volte il numero delle fasce al di sotto della fascia di riferimento, più due. Si restituisca un errore, in modo che il chiamante possa riallocare la collezione e provare di nuovo.
- si verifichi di nuovo la dimensione della collezione e se non c'è rimasto spazio si faccia una stima del numero di voci richieste come conteggio corrente più due volte il numero di fasce al di sotto della fascia in questione, più uno.
- si crei un nuovo trapezoide nella collezione che abbia una regione corrispondente al rettangolo della fascia di riferimento, marcato come occupato da un singolo frame o da frame multipli.
- si passi alla fascia successiva
- se la fascia corrente si trova alla destra della fascia richiesta, allora
c'è spazio disponibile.
- dopo aver passato in rassegna tutti i dati della fascia, se abbiamo raggiunto il limite destro della fascia.
- Se non lo abbiamo raggiunto, si verifichi lo spazio nella collezione
- se non vi è più spazio, si imposti il conteggio sul conteggio corrente più 1 e si restituisca un errore.
- altrimenti, si crei una nuova voce nella collezione, marcata come disponibile e con un rettangolo corrispondente all'area che resta nella fascia (per esempio dal limite destro dell'ultimo rettangolo della fascia fino al limite destro della fascia stessa).
Algoritmo 2: AddRectRegion
I client chiamano questo metodo per notificare allo Space Manager che un nuovo frame sta occupando dello spazio.
- Per prima cosa cerchiamo di ottenere delle informazioni dal frame. Se vengono trovate, si restituisca un errore dato che il frame è già associato con una regione nello Space Manager.
- Quindi creiamo un rettangolo dallo spazio occupato passato dal chiamante, trasformandolo in coordinate globali aggiungendo l'offset dello Space Manager allo spazio passato dal rettangolo occupato.
- Si crei una nuova istanza Frame Info per il frame e il rettangolo, restituendo un errore se l'allocazione fallisce.
- Si verifichi che lo spazio occupato dal rettangolo sia vuoto. In caso affermativo, si restituisca un errore (NOTA: questo potrebbe essere stato fatto prima o impedito dal chiamante)
- Si allochi una nuova istanza BandRect con il frame e il rettangolo come argomenti del costruttore, e la si inserisca nella collezione tramite InsertBandRect
InsertBandRect
Metodo interno per inserire un rettangolo di fascia nella BandList nella locazione corrente. Ci sono diversi casi che deve gestire, come specificato nei commenti del file sorgente.
Quando si fa la comparazione tra un rettangolo e una fascia ci sono diversi casi da considerare. 'R' è il rettangolo e 'B' è la fascia (band).

- Per prima cosa si verifichi il caso più semplice, dove non ci sono rettangoli di fascia esistenti o il rettangolo passato è al di sotto del rettangolo più inferiore. In questo caso si aggiunga solo il rettangolo e lo si restituisca.
- Iniziando dalla testa dell'elenco di BandRects, si verifichi
l'intersezione con il rettangolo passato:
- caso 1: il rettangolo è completamente al di sopra del rettangolo di fascia corrente, così si inserisce un nuovo rettangolo di fascia prima del BandRect corrente
- casi 2 e 7: il rettangolo è parzialmente al di sopra del rettangolo di fascia, così viene diviso in due BandRects, uno completamente sopra la fascia e l'altro contenente quello che resta del rettangolo. Si inserisca la parte che si trova completamente sopra al BandRect prima del BandRect corrente, come nel caso 1, e si sistemi l'altro rettangolo in modo da escludere la parte già aggiunta.
- caso 5: il rettangolo è completamente al di sotto del BandRect corrente, così si salti alla fascia successiva
- casi 3 e 4: il rettangolo si trova parzialmente nell'intersezione con BandRect, quindi si divida la fascia corrente in due parti, dove la parte superiore è sopra il rettangolo corrente. Si passi alla nuova fascia appena creata, che è la fascia successiva.
- caso 6: il rettangolo condivide la parte inferiore e l'altezza con il BandRect, quindi si aggiunga il rettangolo alla fascia.
- casi 4 e 7: si crei un nuovo rettangolo per la parte che si sovrappone a BandRect, e lo si aggiunga al BandRect corrente (simile al caso 6) e quindi si passi alla fascia successiva, rimuovendo questa parte dal rettangolo passato. Se non ci sono più fasce, si aggiunga il rettangolo passato alla fine dell'elenco BandRect.
Questo algoritmo è abbastanza confuso – quello che deve accadere è che i rettangoli e le fasce siano divisi in modo che casi complicati come il 2, 4, e 7, siano ridotti a casi più semplici dove i rettangoli si trovano completamente sopra, sotto e nel mezzo di un rettangolo di fascia. Dall'implementazione corrente, potrebbe essere importante verificare che il risultato finale degli inserimenti sia un elenco correttamente ordinato di BandRects (solo modalità di debug).
Algoritmo 3: RemoveRegion
Quando un float viene rimosso, lo Space Manager viene avvertito con una chiamata a RemoveRegion, passando il frame che è stato rimosso.
- Ottenere il FrameInfo per il frame passato. Se non viene trovato, viene restituito un errore.
- Se il rettangolo per il frame non è vuoto, allora
si vada a vedere ogni fascia nella BandList:
- per ogni rettangolo nella fascia:
- se BandRect è occupato dal frame, si rimuova il frame da BandRect (se non ci sono altri frame che lo condividono) e ci si ricordi che è condiviso
- altrimenti si rimuova solo BandRect (nessun altro frame lo condivide).
- se BandRect fosse condiviso, si cerchi di unire i BandRects adiacenti
- se il precedente BandRect segue direttamente il BandRect corrente e se hanno lo stesso frame si faccia coprire l'intera regione del BandRect precedente (si aggiusti il limite sinistro in modo che sia quello del precedente BandRect) e si rimuova il precedente BandRect.
- se la fascia corrente o precedente hanno un rettangolo occupato dal frame, si cerchi di unire le due fasce tramite JoinBands
- Infine, si distrugga il frameInfo per il frame.
- per ogni rettangolo nella fascia: