diff --git a/internal/packing/packing.go b/internal/packing/packing.go index f587e41a0..52859bc4a 100644 --- a/internal/packing/packing.go +++ b/internal/packing/packing.go @@ -48,8 +48,8 @@ type Node struct { y int width int height int - used bool + parent *Node child0 *Node child1 *Node @@ -268,3 +268,33 @@ func (p *Page) Extend() bool { p.size = newSize return true } + +func (n *Node) clone() *Node { + if n == nil { + return nil + } + cloned := &Node{ + x: n.x, + y: n.y, + width: n.width, + height: n.height, + used: n.used, + child0: n.child0.clone(), + child1: n.child1.clone(), + } + if cloned.child0 != nil { + cloned.child0.parent = cloned + } + if cloned.child1 != nil { + cloned.child1.parent = cloned + } + return cloned +} + +func (p *Page) Clone() *Page { + return &Page{ + root: p.root.clone(), + size: p.size, + maxSize: p.maxSize, + } +} diff --git a/internal/shareable/shareable.go b/internal/shareable/shareable.go index 7c005cbc8..eb605a9fd 100644 --- a/internal/shareable/shareable.go +++ b/internal/shareable/shareable.go @@ -35,24 +35,40 @@ type backend struct { } func (b *backend) TryAlloc(width, height int) (*packing.Node, bool) { - for { - if n := b.page.Alloc(width, height); n != nil { - return n, true - } + // If the region is allocated without any extention, it's fine. + if n := b.page.Alloc(width, height); n != nil { + return n, true + } - if !b.page.Extend() { + // Simulate the extending the page and calculate the appropriate page size. + page := b.page.Clone() + nExtended := 0 + for { + if !page.Extend() { + // The page can't be extended any more. Return as failure. + return nil, false + } + nExtended++ + if n := page.Alloc(width, height); n != nil { break } - - s := b.page.Size() - newImg := restorable.NewImage(s, s, false) - w, h := b.restorable.Size() - newImg.DrawImage(b.restorable, 0, 0, w, h, nil, nil, opengl.CompositeModeCopy, graphics.FilterNearest) - - b.restorable.Dispose() - b.restorable = newImg } - return nil, false + + for i := 0; i < nExtended; i++ { + b.page.Extend() + } + s := b.page.Size() + newImg := restorable.NewImage(s, s, false) + w, h := b.restorable.Size() + newImg.DrawImage(b.restorable, 0, 0, w, h, nil, nil, opengl.CompositeModeCopy, graphics.FilterNearest) + b.restorable.Dispose() + b.restorable = newImg + + n := b.page.Alloc(width, height) + if n == nil { + panic("not reached") + } + return n, true } var (