bool AreaAllocator::Allocate(int width, int height, int& x, int& y) { if (width < 0) width = 0; if (height < 0) height = 0; PODVector<IntRect>::Iterator best; int bestFreeArea; for(;;) { best = freeAreas_.End(); bestFreeArea = M_MAX_INT; for (PODVector<IntRect>::Iterator i = freeAreas_.Begin(); i != freeAreas_.End(); ++i) { int freeWidth = i->Width(); int freeHeight = i->Height(); if (freeWidth >= width && freeHeight >= height) { // Calculate rank for free area. Lower is better int freeArea = freeWidth * freeHeight; if (freeArea < bestFreeArea) { best = i; bestFreeArea = freeArea; } } } if (best == freeAreas_.End()) { if (doubleWidth_ && size_.x_ < maxSize_.x_) { int oldWidth = size_.x_; size_.x_ <<= 1; // If no allocations yet, simply expand the single free area IntRect& first = freeAreas_.Front(); if (freeAreas_.Size() == 1 && first.left_ == 0 && first.top_ == 0 && first.right_ == oldWidth && first.bottom_ == size_.y_) first.right_ = size_.x_; else { IntRect newArea(oldWidth, 0, size_.x_, size_.y_); freeAreas_.Push(newArea); } } else if (!doubleWidth_ && size_.y_ < maxSize_.y_) { int oldHeight = size_.y_; size_.y_ <<= 1; // If no allocations yet, simply expand the single free area IntRect& first = freeAreas_.Front(); if (freeAreas_.Size() == 1 && first.left_ == 0 && first.top_ == 0 && first.right_ == size_.x_ && first.bottom_ == oldHeight) first.bottom_ = size_.y_; else { IntRect newArea(0, oldHeight, size_.x_, size_.y_); freeAreas_.Push(newArea); } } else return false; doubleWidth_ = !doubleWidth_; } else break; } IntRect reserved(best->left_, best->top_, best->left_ + width, best->top_ + height); x = best->left_; y = best->top_; if (fastMode_) { // Reserve the area by splitting up the remaining free area best->left_ = reserved.right_; if (best->Height() > 2 * height || height >= size_.y_ / 2) { IntRect splitArea(reserved.left_, reserved.bottom_, best->right_, best->bottom_); best->bottom_ = reserved.bottom_; freeAreas_.Push(splitArea); } } else { // Remove the reserved area from all free areas for (unsigned i = 0; i < freeAreas_.Size();) { if (SplitRect(freeAreas_[i], reserved)) freeAreas_.Erase(i); else ++i; } Cleanup(); } return true; }
bool AreaAllocator::Allocate(int width, int height, int& x, int& y) { if (width < 0) width = 0; if (height < 0) height = 0; PODVector<IntRect>::Iterator best = freeAreas_.End(); int bestFreeArea = M_MAX_INT; for(;;) { for (PODVector<IntRect>::Iterator i = freeAreas_.Begin(); i != freeAreas_.End(); ++i) { int freeWidth = i->Width(); int freeHeight = i->Height(); if (freeWidth >= width && freeHeight >= height) { // Calculate rank for free area. Lower is better int freeArea = freeWidth * freeHeight; if (freeArea < bestFreeArea) { best = i; bestFreeArea = freeArea; } } } if (best == freeAreas_.End()) { if (doubleWidth_ && size_.x_ < maxSize_.x_) { int oldWidth = size_.x_; size_.x_ <<= 1; IntRect newArea(oldWidth, 0, size_.x_, size_.y_); freeAreas_.Push(newArea); } else if (!doubleWidth_ && size_.y_ < maxSize_.y_) { int oldHeight = size_.y_; size_.y_ <<= 1; IntRect newArea(0, oldHeight, size_.x_, size_.y_); freeAreas_.Push(newArea); } else return false; doubleWidth_ = !doubleWidth_; } else break; } IntRect reserved(best->left_, best->top_, best->left_ + width, best->top_ + height); x = best->left_; y = best->top_; // Reserve the area by splitting up the remaining free area best->left_ = reserved.right_; if (best->Height() > 2 * height) { IntRect splitArea(reserved.left_, reserved.bottom_, best->right_, best->bottom_); best->bottom_ = reserved.bottom_; freeAreas_.Push(splitArea); } return true; }