forked from flutter/engine
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Replace use of Skia's private GrRectanizer with a copy of the equival…
…ent code (flutter#42430) Skia would like clients to not use their private types. This ports the same functionality into Flutter's codebase with tests. The implementation was copied from [Skia](https://github.com/google/skia/blob/fa87b7c5ba222f8ceb603f36011e7bbdc4bf1084/src/gpu/RectanizerSkyline.cpp) and then modified to match Flutter's style and have a unit test. ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide] and the [C++, Objective-C, Java style guides]. - [ ] I listed at least one issue that this PR fixes in the description above. - [x] I added new tests to check the change I am making or feature I am adding, or Hixie said the PR is test-exempt. See [testing the engine] for instructions on writing and running engine tests. - [x] I updated/added relevant documentation (doc comments with `///`). - [x] I signed the [CLA]. - [x] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/wiki/Tree-hygiene#overview [Tree Hygiene]: https://github.com/flutter/flutter/wiki/Tree-hygiene [Flutter Style Guide]: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo [C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style [testing the engine]: https://github.com/flutter/flutter/wiki/Testing-the-engine [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/wiki/Tree-hygiene#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/wiki/Chat
- Loading branch information
Showing
9 changed files
with
312 additions
and
18 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,173 @@ | ||
// Copyright 2013 The Flutter Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
#include "impeller/typographer/rectangle_packer.h" | ||
|
||
#include <algorithm> | ||
#include <vector> | ||
|
||
namespace impeller { | ||
|
||
// Pack rectangles and track the current silhouette | ||
// Based, in part, on Jukka Jylanki's work at http://clb.demon.fi | ||
// and ported from Skia's implementation | ||
// https://github.com/google/skia/blob/b5de4b8ae95c877a9ecfad5eab0765bc22550301/src/gpu/RectanizerSkyline.cpp | ||
class SkylineRectanglePacker final : public RectanglePacker { | ||
public: | ||
SkylineRectanglePacker(int w, int h) : RectanglePacker(w, h) { | ||
this->reset(); | ||
} | ||
|
||
~SkylineRectanglePacker() final {} | ||
|
||
void reset() final { | ||
areaSoFar_ = 0; | ||
skyline_.clear(); | ||
skyline_.push_back(SkylineSegment{0, 0, this->width()}); | ||
} | ||
|
||
bool addRect(int w, int h, IPoint16* loc) final; | ||
|
||
float percentFull() const final { | ||
return areaSoFar_ / ((float)this->width() * this->height()); | ||
} | ||
|
||
private: | ||
struct SkylineSegment { | ||
int x_; | ||
int y_; | ||
int width_; | ||
}; | ||
|
||
std::vector<SkylineSegment> skyline_; | ||
|
||
int32_t areaSoFar_; | ||
|
||
// Can a width x height rectangle fit in the free space represented by | ||
// the skyline segments >= 'skylineIndex'? If so, return true and fill in | ||
// 'y' with the y-location at which it fits (the x location is pulled from | ||
// 'skylineIndex's segment. | ||
bool rectangleFits(int skylineIndex, int width, int height, int* y) const; | ||
// Update the skyline structure to include a width x height rect located | ||
// at x,y. | ||
void addSkylineLevel(int skylineIndex, int x, int y, int width, int height); | ||
}; | ||
|
||
bool SkylineRectanglePacker::addRect(int width, int height, IPoint16* loc) { | ||
if ((unsigned)width > (unsigned)this->width() || | ||
(unsigned)height > (unsigned)this->height()) { | ||
return false; | ||
} | ||
|
||
// find position for new rectangle | ||
int bestWidth = this->width() + 1; | ||
int bestX = 0; | ||
int bestY = this->height() + 1; | ||
int bestIndex = -1; | ||
for (int i = 0; i < (int)skyline_.size(); ++i) { | ||
int y; | ||
if (this->rectangleFits(i, width, height, &y)) { | ||
// minimize y position first, then width of skyline | ||
if (y < bestY || (y == bestY && skyline_[i].width_ < bestWidth)) { | ||
bestIndex = i; | ||
bestWidth = skyline_[i].width_; | ||
bestX = skyline_[i].x_; | ||
bestY = y; | ||
} | ||
} | ||
} | ||
|
||
// add rectangle to skyline | ||
if (-1 != bestIndex) { | ||
this->addSkylineLevel(bestIndex, bestX, bestY, width, height); | ||
loc->x_ = bestX; | ||
loc->y_ = bestY; | ||
|
||
areaSoFar_ += width * height; | ||
return true; | ||
} | ||
|
||
loc->x_ = 0; | ||
loc->y_ = 0; | ||
return false; | ||
} | ||
|
||
bool SkylineRectanglePacker::rectangleFits(int skylineIndex, | ||
int width, | ||
int height, | ||
int* ypos) const { | ||
int x = skyline_[skylineIndex].x_; | ||
if (x + width > this->width()) { | ||
return false; | ||
} | ||
|
||
int widthLeft = width; | ||
int i = skylineIndex; | ||
int y = skyline_[skylineIndex].y_; | ||
while (widthLeft > 0 && i < (int)skyline_.size()) { | ||
y = std::max(y, skyline_[i].y_); | ||
if (y + height > this->height()) { | ||
return false; | ||
} | ||
widthLeft -= skyline_[i].width_; | ||
++i; | ||
} | ||
|
||
*ypos = y; | ||
return true; | ||
} | ||
|
||
void SkylineRectanglePacker::addSkylineLevel(int skylineIndex, | ||
int x, | ||
int y, | ||
int width, | ||
int height) { | ||
SkylineSegment newSegment; | ||
newSegment.x_ = x; | ||
newSegment.y_ = y + height; | ||
newSegment.width_ = width; | ||
skyline_.insert(std::next(skyline_.begin(), skylineIndex), newSegment); | ||
|
||
FML_DCHECK(newSegment.x_ + newSegment.width_ <= this->width()); | ||
FML_DCHECK(newSegment.y_ <= this->height()); | ||
|
||
// delete width of the new skyline segment from following ones | ||
for (int i = skylineIndex + 1; i < (int)skyline_.size(); ++i) { | ||
// The new segment subsumes all or part of skyline_[i] | ||
FML_DCHECK(skyline_[i - 1].x_ <= skyline_[i].x_); | ||
|
||
if (skyline_[i].x_ < skyline_[i - 1].x_ + skyline_[i - 1].width_) { | ||
int shrink = skyline_[i - 1].x_ + skyline_[i - 1].width_ - skyline_[i].x_; | ||
|
||
skyline_[i].x_ += shrink; | ||
skyline_[i].width_ -= shrink; | ||
|
||
if (skyline_[i].width_ <= 0) { | ||
// fully consumed, remove item at index i | ||
skyline_.erase(std::next(skyline_.begin(), i)); | ||
--i; | ||
} else { | ||
// only partially consumed | ||
break; | ||
} | ||
} else { | ||
break; | ||
} | ||
} | ||
|
||
// merge skyline_s | ||
for (int i = 0; i < ((int)skyline_.size()) - 1; ++i) { | ||
if (skyline_[i].y_ == skyline_[i + 1].y_) { | ||
skyline_[i].width_ += skyline_[i + 1].width_; | ||
skyline_.erase(std::next(skyline_.begin(), i)); | ||
--i; | ||
} | ||
} | ||
} | ||
|
||
RectanglePacker* RectanglePacker::Factory(int width, int height) { | ||
return new SkylineRectanglePacker(width, height); | ||
} | ||
|
||
} // namespace impeller |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
// Copyright 2013 The Flutter Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
#pragma once | ||
|
||
#include "flutter/fml/logging.h" | ||
|
||
#include <cstdint> | ||
|
||
namespace impeller { | ||
|
||
struct IPoint16 { | ||
int16_t x() const { return x_; } | ||
int16_t y() const { return y_; } | ||
|
||
int16_t x_; | ||
int16_t y_; | ||
}; | ||
|
||
//------------------------------------------------------------------------------ | ||
/// @brief Packs rectangles into a specified area without rotating them. | ||
/// | ||
class RectanglePacker { | ||
public: | ||
//---------------------------------------------------------------------------- | ||
/// @brief Return an empty packer with area specified by width and height. | ||
/// | ||
static RectanglePacker* Factory(int width, int height); | ||
|
||
virtual ~RectanglePacker() {} | ||
|
||
//---------------------------------------------------------------------------- | ||
/// @brief Attempt to add a rect without moving already placed rectangles. | ||
/// | ||
/// @param[in] width The width of the rectangle to add. | ||
/// @param[in] height The height of the rectangle to add. | ||
/// @param[out] loc If successful, will be set to the position of the | ||
/// upper-left corner of the rectangle. | ||
/// | ||
/// @return Return true on success; false on failure. | ||
/// | ||
virtual bool addRect(int width, int height, IPoint16* loc) = 0; | ||
|
||
//---------------------------------------------------------------------------- | ||
/// @brief Returns how much area has been filled with rectangles. | ||
/// | ||
/// @return Percentage as a decimal between 0.0 and 1.0 | ||
/// | ||
virtual float percentFull() const = 0; | ||
|
||
//---------------------------------------------------------------------------- | ||
/// @brief Empty out all previously added rectangles. | ||
/// | ||
virtual void reset() = 0; | ||
|
||
protected: | ||
RectanglePacker(int width, int height) : width_(width), height_(height) { | ||
FML_DCHECK(width >= 0); | ||
FML_DCHECK(height >= 0); | ||
} | ||
|
||
int width() const { return width_; } | ||
int height() const { return height_; } | ||
|
||
private: | ||
const int width_; | ||
const int height_; | ||
}; | ||
|
||
} // namespace impeller |
Oops, something went wrong.