Commit 4e32d1b8 authored by johnme's avatar johnme Committed by Commit bot

Revert of Move scaling of ui resources for scrollbars to the time of upload...

Revert of Move scaling of ui resources for scrollbars to the time of upload (patchset #1 id:1 of https://codereview.chromium.org/2280663002/ )

Reason for revert:
Sorry about the spam. Re-reverting now that https://codereview.chromium.org/2282433002 which depends on this patch has been reverted.

Original issue's description:
> Reland of Move scaling of ui resources for scrollbars to the time of upload (patchset #1 id:1 of https://codereview.chromium.org/2278083002/ )
>
> Reason for revert:
> Reverting this broke compile:
>
> cc/layers/painted_scrollbar_layer.cc:83:29: error: no member named 'GetRendererCapabilities' in 'cc::LayerTreeHost'
>   return layer_tree_host()->GetRendererCapabilities().max_texture_size;
>          ~~~~~~~~~~~~~~~~~  ^
>
> Original issue's description:
> > Revert of Move scaling of ui resources for scrollbars to the time of upload (patchset #6 id:100001 of https://codereview.chromium.org/2276633003/ )
> >
> > Reason for revert:
> > Sorry, seems to have caused LayerTreeHostScrollbarsPixelTest.HugeTransformScale to fail on Mac10.10 Tests,  Mac10.11 Tests, Win 7 Tests x64 (1), Win10 Tests x64, Mac10.9 Tests and Linux Tests, with failures like:
> >
> > [8034:1287:0825/033725:3059591139598:ERROR:pixel_comparator.cc(50)] Number of pixel with an error: 672
> > [8034:1287:0825/033725:3059591187709:ERROR:pixel_comparator.cc(51)] Error Bounding Box : 0,304 368x66
> > [8034:1287:0825/033725:3059610880597:ERROR:pixel_test_utils.cc(79)] Pixels do not match!
> > [8034:1287:0825/033725:3059610905829:ERROR:pixel_test_utils.cc(80)] Actual: data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAZAAAAGQCAYAAACAvzbMAAAF4ElEQVR4nO3ZQY1CQRRFwccEUWhhgQEMYAED7FGDKtJsxsCcTYdMVQt4d3eS/w9rrTUAX+g+97nNbfeMbS5zmec8t93/2XYZgK8mIAAkAgJAIiAAJAICQCIgACQCAkAiIAAkAgJAIiAAJAICQCIgACQCAkAiIAAkAgJAIiAAJAICQCIgACQCAkAiIAAkAgJAIiAAJAICQCIgACQCAkAiIAAkAgJAIiAAJAICQCIgACQCAkAiIAAkAgJAIiAAJAICQCIgACQCAkAiIAAkAgJAIiAAJAICQCIgACQCAkAiIAAkAgJAIiAAJAICQCIgACQCAkAiIAAkAgJAIiAAJAICQCIgACQCAkAiIAAkAgJAIiAAJAICQCIgACQCAkAiIAAkAgJAIiAAJAICQCIgACQCAkAiIAAkAgJAIiAAJAICQCIgACQCAkAiIAAkAgJAIiAAJAICQCIgACQCAkAiIAAkAgJAIiAAJAICQCIgACQCAkAiIAAkAgJAIiAAJAICQCIgACQCAkAiIAAkAgJAIiAAJAICQCIgACQCAkAiIAAkAgJAIiAAJAICQCIgACQCAkAiIAAkAgJAIiAAJAICQCIgACQCAkAiIAAkAgJAIiAAJAICQCIgACQCAkAiIAAkAgJAIiAAJAICQCIgACQCAkAiIAAkAgJAIiAAJAICQCIgACQCAkAiIAAkAgJAIiAAJAICQCIgACQCAkAiIAAkAgJAIiAAJAICQCIgACQCAkAiIAAkAgJAIiAAJAICQCIgACQCAkAiIAAkAgJAIiAAJAICQCIgACQCAkAiIAAkAgJAIiAAJAICQCIgACQCAkAiIAAkAgJAIiAAJAICQCIgACQCAkAiIAAkAgJAIiAAJAICQCIgACQCAkAiIAAkAgJAIiAAJAICQCIgACQCAkAiIAAkAgJAIiAAJAICQCIgACQCAkAiIAAkAgJAIiAAJAICQCIgACQCAkAiIAAkAgJAIiAAJAICQCIgACQCAkAiIAAkAgJAIiAAJAICQCIgACQCAkAiIAAkAgJAIiAAJAICQCIgACQCAkAiIAAkAgJAIiAAJAICQCIgACQCAkAiIAAkAgJAIiAAJAICQCIgACQCAkAiIAAkAgJAIiAAJAICQCIgACQCAkAiIAAkAgJAIiAAJAICQCIgACQCAkAiIAAkAgJAIiAAJAICQCIgACQCAkAiIAAkAgJAIiAAJAICQCIgACQCAkAiIAAkAgJAIiAAJAICQCIgACQCAkAiIAAkAgJAIiAAJAICQCIgACQCAkAiIAAkAgJAIiAAJAICQCIgACQCAkAiIAAkAgJAIiAAJAICQCIgACQCAkAiIAAkAgJAIiAAJAICQCIgACQCAkAiIAAkAgJAIiAAJAICQCIgACQCAkAiIAAkAgJAIiAAJAICQCIgACQCAkAiIAAkAgJAIiAAJAICQCIgACQCAkAiIAAkAgJAIiAAJAICQCIgACQCAkAiIAAkAgJAIiAAJAICQCIgACQCAkAiIAAkAgJAcnzMY/cGgOQ1r90T/rXjda67NwDwhXzCAiAREAASAQEgERAAEgEBIBEQABIBASAREAASAQEgERAAEgEBIBEQABIBASAREAASAQEgERAAEgEBIBEQABIBASAREAASAQEgERAAEgEBIBEQABIBASAREAASAQEgERAAEgEBIBEQABIBASAREAASAQEgERAAEgEBIBEQABIBASAREAASAQEgERAAEgEBIBEQABIBASAREAASAQEgERAAEgEBIBEQABIBASAREAASAQEgERAAEgEBIBEQABIBASAREAASAQEgERAAEgEBIBEQABIBASAREACS43nOuzcAEJzmtPX+4b3ea+sCAJLD79t2f60lIAD8mX8gACQCAkAiIAAkAgJAIiAAJAICQCIgACQCAkAiIAAkAgJAIiAAJAICQCIgACQCAkAiIAAkAgJAIiAAJAICQCIgACQCAkAiIAAkAgJAIiAAJAICQCIgACQCAkAiIAAkAgJAIiAAJB9NHxfMgTV5VwAAAABJRU5ErkJggg==
> > [8034:1287:0825/033725:3059610929427:ERROR:pixel_test_utils.cc(81)] Expected: data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAZAAAAGQCAYAAACAvzbMAAAF4klEQVR4nO3ZQY1CQRRFwfcJotDCYhQgAAsIQABqMEXSo2HOpkOmysC7u5N0H2utNQBf6DGPuc9994xtfuZnXvPadv+07TIAX01AAEgEBIBEQABIBASAREAASAQEgERAAEgEBIBEQABIBASAREAASAQEgERAAEgEBIBEQABIBASAREAASAQEgERAAEgEBIBEQABIBASAREAASAQEgERAAEgEBIBEQABIBASAREAASAQEgERAAEgEBIBEQABIBASAREAASAQEgERAAEgEBIBEQABIBASAREAASAQEgERAAEgEBIBEQABIBASAREAASAQEgERAAEgEBIBEQABIBASAREAASAQEgERAAEgEBIBEQABIBASAREAASAQEgERAAEgEBIBEQABIBASAREAASAQEgERAAEgEBIBEQABIBASAREAASAQEgERAAEgEBIBEQABIBASAREAASAQEgERAAEgEBIBEQABIBASAREAASAQEgERAAEgEBIBEQABIBASAREAASAQEgERAAEgEBIBEQABIBASAREAASAQEgERAAEgEBIBEQABIBASAREAASAQEgERAAEgEBIBEQABIBASAREAASAQEgERAAEgEBIBEQABIBASAREAASAQEgERAAEgEBIBEQABIBASAREAASAQEgERAAEgEBIBEQABIBASAREAASAQEgERAAEgEBIBEQABIBASAREAASAQEgERAAEgEBIBEQABIBASAREAASAQEgERAAEgEBIBEQABIBASAREAASAQEgERAAEgEBIBEQABIBASAREAASAQEgERAAEgEBIBEQABIBASAREAASAQEgERAAEgEBIBEQABIBASAREAASAQEgERAAEgEBIBEQABIBASAREAASAQEgERAAEgEBIBEQABIBASAREAASAQEgERAAEgEBIBEQABIBASAREAASAQEgERAAEgEBIBEQABIBASAREAASAQEgERAAEgEBIBEQABIBASAREAASAQEgERAAEgEBIBEQABIBASAREAASAQEgERAAEgEBIBEQABIBASAREAASAQEgERAAEgEBIBEQABIBASAREAASAQEgERAAEgEBIBEQABIBASAREAASAQEgERAAEgEBIBEQABIBASAREAASAQEgERAAEgEBIBEQABIBASAREAASAQEgERAAEgEBIBEQABIBASAREAASAQEgERAAEgEBIBEQABIBASAREAASAQEgERAAEgEBIBEQABIBASAREAASAQEgERAAEgEBIBEQABIBASAREAASAQEgERAAEgEBIBEQABIBASAREAASAQEgERAAEgEBIBEQABIBASAREAASAQEgERAAEgEBIBEQABIBASAREAASAQEgERAAEgEBIBEQABIBASAREAASAQEgERAAEgEBIBEQABIBASAREAASAQEgERAAEgEBIBEQABIBASAREAASAQEgERAAEgEBIBEQABIBASAREAASAQEgERAAEgEBIBEQABIBASAREAASAQEgERAAEgEBIDk/Jzn7g0AyXveuyf8a+fb3HZvAOALecICIBEQABIBASAREAASAQEgERAAEgEBIBEQABIBASAREAASAQEgERAAEgEBIBEQABIBASAREAASAQEgERAAEgEBIBEQABIBASAREAASAQEgERAAEgEBIBEQABIBASAREAASAQEgERAAEgEBIBEQABIBASAREAASAQEgERAAEgEBIBEQABIBASAREAASAQEgERAAEgEBIBEQABIBASAREAASAQEgERAAEgEBIBEQABIBASAREAASAQEgERAAEgEBIBEQABIBASAREAASAQEgERAAEgEBIBEQAJLzda67NwAQXOay9f7xWZ+1dQEAyWlOc8yx7f6x1hIQAP7MHwgAiYAAkAgIAImAAJAICACJgACQCAgAiYAAkAgIAImAAJAICACJgACQCAgAiYAAkAgIAImAAJAICACJgACQCAgAiYAAkAgIAImAAJAICACJgACQCAgAiYAAkAgIAImAAJAICADJLzUdF8xyVTjQAAAAAElFTkSuQmCC
> > ../../cc/test/layer_tree_pixel_test.cc:124: Failure
> > Value of: MatchesPNGFile(*result_bitmap_, ref_file_path, *pixel_comparator_)
> >   Actual: false
> > Expected: true
> >
> > Original issue's description:
> > > Move scaling of ui resources for scrollbars to the time of upload
> > >
> > > Instead of trying to figure out what the max texture size is on the
> > > main thread, and scale raster to meet that, just raster freely. Then
> > > when uploading the UIResource to a texture, we can easily tell what
> > > the max texture size is, and if the UIResource is too large, scale it
> > > down to fit in a texture.
> > >
> > > R=enne
> > > BUG=606056
> > > CQ_INCLUDE_TRYBOTS=master.tryserver.blink:linux_precise_blink_rel
> > > NOTRY=true
> > >
> > > Committed: https://crrev.com/941e52edd1522f7c3935aa4f4d763c43578b4944
> > > Cr-Commit-Position: refs/heads/master@{#414202}
> >
> > TBR=enne@chromium.org,danakj@chromium.org
> > # Skipping CQ checks because original CL landed less than 1 days ago.
> > NOPRESUBMIT=true
> > NOTREECHECKS=true
> > NOTRY=true
> > BUG=606056
> >
> > Committed: https://crrev.com/706757873f077fcf245c8e4054a5dfd8424d5ed2
> > Cr-Commit-Position: refs/heads/master@{#414391}
>
> TBR=enne@chromium.org,danakj@chromium.org
> # Skipping CQ checks because original CL landed less than 1 days ago.
> NOPRESUBMIT=true
> NOTREECHECKS=true
> NOTRY=true
> BUG=606056
>
> Committed: https://crrev.com/f56ab5d893d9c1ff735136d8df7d738b16634a7a
> Cr-Commit-Position: refs/heads/master@{#414394}

TBR=enne@chromium.org,danakj@chromium.org
# Skipping CQ checks because original CL landed less than 1 days ago.
NOPRESUBMIT=true
NOTREECHECKS=true
NOTRY=true
BUG=606056

Review-Url: https://codereview.chromium.org/2282443002
Cr-Commit-Position: refs/heads/master@{#414411}
parent 76f7fed1
......@@ -78,6 +78,26 @@ ScrollbarOrientation PaintedScrollbarLayer::orientation() const {
return scrollbar_->Orientation();
}
int PaintedScrollbarLayer::MaxTextureSize() {
DCHECK(layer_tree_host());
return layer_tree_host()->GetRendererCapabilities().max_texture_size;
}
float PaintedScrollbarLayer::ClampScaleToMaxTextureSize(float scale) {
// If the scaled bounds() is bigger than the max texture size of the
// device, we need to clamp it by rescaling, since this is used
// below to set the texture size.
gfx::Size scaled_bounds = gfx::ScaleToCeiledSize(bounds(), scale);
if (scaled_bounds.width() > MaxTextureSize() ||
scaled_bounds.height() > MaxTextureSize()) {
if (bounds().width() > bounds().height())
return (MaxTextureSize() - 1) / static_cast<float>(bounds().width());
else
return (MaxTextureSize() - 1) / static_cast<float>(bounds().height());
}
return scale;
}
void PaintedScrollbarLayer::PushPropertiesTo(LayerImpl* layer) {
Layer::PushPropertiesTo(layer);
......@@ -182,7 +202,8 @@ void PaintedScrollbarLayer::UpdateInternalContentScale() {
scale = std::max(transform_scales.x(), transform_scales.y());
}
bool changed = false;
changed |= UpdateProperty(scale, &internal_contents_scale_);
changed |= UpdateProperty(ClampScaleToMaxTextureSize(scale),
&internal_contents_scale_);
changed |=
UpdateProperty(gfx::ScaleToCeiledSize(bounds(), internal_contents_scale_),
&internal_content_bounds_);
......
......@@ -72,6 +72,9 @@ class CC_EXPORT PaintedScrollbarLayer : public ScrollbarLayerInterface,
return true;
}
int MaxTextureSize();
float ClampScaleToMaxTextureSize(float scale);
UIResourceBitmap RasterizeScrollbarPart(const gfx::Rect& layer_rect,
const gfx::Rect& content_rect,
ScrollbarPart part);
......
......@@ -26,7 +26,6 @@
#include "cc/test/layer_tree_test.h"
#include "cc/test/mock_occlusion_tracker.h"
#include "cc/test/stub_layer_tree_host_single_thread_client.h"
#include "cc/test/test_context_provider.h"
#include "cc/test/test_task_graph_runner.h"
#include "cc/test/test_web_graphics_context_3d.h"
#include "cc/trees/effect_node.h"
......@@ -741,6 +740,60 @@ TEST_F(ScrollbarLayerSolidColorThumbTest, SolidColorThumbVerticalAdjust) {
vertical_scrollbar_layer_->ComputeThumbQuadRect());
}
class ScrollbarLayerTestWithFixedScrollbarBounds : public LayerTreeTest {
public:
ScrollbarLayerTestWithFixedScrollbarBounds() {}
void SetScrollbarBounds(const gfx::Size& bounds) { bounds_ = bounds; }
void BeginTest() override {
scroll_layer_ = Layer::Create();
layer_tree()->root_layer()->AddChild(scroll_layer_);
std::unique_ptr<Scrollbar> scrollbar(new FakeScrollbar);
scrollbar_layer_ = PaintedScrollbarLayer::Create(std::move(scrollbar),
scroll_layer_->id());
scrollbar_layer_->SetScrollLayer(scroll_layer_->id());
scrollbar_layer_->SetLayerTreeHost(layer_tree_host());
scrollbar_layer_->SetBounds(bounds_);
scrollbar_layer_->SetIsDrawable(true);
layer_tree()->root_layer()->AddChild(scrollbar_layer_);
PostSetNeedsCommitToMainThread();
}
void DidCommitAndDrawFrame() override {
const int kMaxTextureSize =
layer_tree_host()->GetRendererCapabilities().max_texture_size;
// Check first that we're actually testing something.
EXPECT_GT(scrollbar_layer_->bounds().width(), kMaxTextureSize);
EXPECT_EQ(scrollbar_layer_->internal_content_bounds().width(),
kMaxTextureSize - 1);
EXPECT_EQ(scrollbar_layer_->internal_content_bounds().height(),
kMaxTextureSize - 1);
EndTest();
}
void AfterTest() override {}
private:
scoped_refptr<PaintedScrollbarLayer> scrollbar_layer_;
scoped_refptr<Layer> scroll_layer_;
gfx::Size bounds_;
};
TEST_F(ScrollbarLayerTestWithFixedScrollbarBounds, MaxTextureSize) {
std::unique_ptr<TestWebGraphicsContext3D> context =
TestWebGraphicsContext3D::Create();
int max_size = 0;
context->getIntegerv(GL_MAX_TEXTURE_SIZE, &max_size);
SetScrollbarBounds(gfx::Size(max_size + 100, max_size + 100));
RunTest(CompositorMode::THREADED);
}
class ScrollbarLayerTestResourceCreationAndRelease : public ScrollbarLayerTest {
public:
void TestResourceUpload(int num_updates,
......@@ -974,6 +1027,7 @@ class ScaledScrollbarLayerTestResourceCreation : public ScrollbarLayerTest {
scrollbar_layer->set_visible_layer_rect(
gfx::Rect(scrollbar_location, scrollbar_layer->bounds()));
testing::Mock::VerifyAndClearExpectations(layer_tree_host_.get());
EXPECT_EQ(scrollbar_layer->layer_tree_host(), layer_tree_host_.get());
layer_tree_->SetDeviceScaleFactor(test_scale);
......@@ -997,6 +1051,16 @@ class ScaledScrollbarLayerTestResourceCreation : public ScrollbarLayerTest {
scrollbar_layer->internal_content_bounds().width());
EXPECT_LE(thumb_size.height(),
scrollbar_layer->internal_content_bounds().height());
EXPECT_LE(track_size.width(),
layer_tree_host_->GetRendererCapabilities().max_texture_size);
EXPECT_LE(track_size.height(),
layer_tree_host_->GetRendererCapabilities().max_texture_size);
EXPECT_LE(thumb_size.width(),
layer_tree_host_->GetRendererCapabilities().max_texture_size);
EXPECT_LE(thumb_size.height(),
layer_tree_host_->GetRendererCapabilities().max_texture_size);
testing::Mock::VerifyAndClearExpectations(layer_tree_host_.get());
}
};
......@@ -1007,13 +1071,8 @@ TEST_F(ScaledScrollbarLayerTestResourceCreation, ScaledResourceUpload) {
TestResourceUpload(1.41f);
TestResourceUpload(4.1f);
// Try something extreme to be larger than max texture size, and make it a
// non-integer for funsies.
scoped_refptr<TestContextProvider> context = TestContextProvider::Create();
context->BindToCurrentThread();
int max_texture_size = 0;
context->ContextGL()->GetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size);
TestResourceUpload(max_texture_size / 9.9f);
// Try something extreme to make sure it gets clamped.
TestResourceUpload(2147483647.0f);
}
class ScaledScrollbarLayerTestScaledRasterization : public ScrollbarLayerTest {
......
......@@ -23,10 +23,6 @@ class CC_EXPORT UIResourceClient {
// delete a UIResourceClient object after DeleteUIResource has been called for
// all IDs associated with it. A valid bitmap always must be returned but it
// doesn't need to be the same size or format as the original.
// The bitmap's dimensions must *not* exceed the maximum texture size
// supported by the GPU. For resources that are not bigger than the viewport
// this should not be a problem, but for much larger resources, the caller is
// responsible for ensuring this.
virtual UIResourceBitmap GetBitmap(UIResourceId uid,
bool resource_lost) = 0;
virtual ~UIResourceClient() {}
......
cc/test/data/spiral_64_scale.png

1.43 KB | W: | H:

cc/test/data/spiral_64_scale.png

1.43 KB | W: | H:

cc/test/data/spiral_64_scale.png
cc/test/data/spiral_64_scale.png
cc/test/data/spiral_64_scale.png
cc/test/data/spiral_64_scale.png
  • 2-up
  • Swipe
  • Onion skin
......@@ -28,6 +28,7 @@ void FakeUIResourceLayerTreeHostImpl::CreateUIResource(
bitmap.GetSize(), ResourceProvider::TEXTURE_HINT_IMMUTABLE, RGBA_8888,
gfx::ColorSpace());
data.size = bitmap.GetSize();
data.opaque = bitmap.GetOpaque();
fake_ui_resource_map_[uid] = data;
}
......
......@@ -3761,68 +3761,21 @@ void LayerTreeHostImpl::CreateUIResource(UIResourceId uid,
format = ETC1;
break;
}
const gfx::Size source_size = bitmap.GetSize();
gfx::Size upload_size = bitmap.GetSize();
bool scaled = false;
int max_texture_size = resource_provider_->max_texture_size();
if (source_size.width() > max_texture_size ||
source_size.height() > max_texture_size) {
// Must resize the bitmap to fit within the max texture size.
scaled = true;
int edge = std::max(source_size.width(), source_size.height());
float scale = nextafterf(static_cast<float>(max_texture_size) / edge, 0);
DCHECK_LT(scale, 1.f);
upload_size = gfx::ScaleToFlooredSize(source_size, scale, scale);
}
id = resource_provider_->CreateResource(
upload_size, ResourceProvider::TEXTURE_HINT_IMMUTABLE, format,
bitmap.GetSize(), ResourceProvider::TEXTURE_HINT_IMMUTABLE, format,
gfx::ColorSpace());
if (!scaled) {
AutoLockUIResourceBitmap bitmap_lock(bitmap);
auto* pixels = bitmap_lock.GetPixels();
resource_provider_->CopyToResource(id, pixels, source_size);
} else {
// Only support auto-resizing for N32 textures (since this is primarily for
// scrollbars). Users of other types need to ensure they are not too big.
DCHECK_EQ(bitmap.GetFormat(), UIResourceBitmap::RGBA8);
float canvas_scale_x =
upload_size.width() / static_cast<float>(source_size.width());
float canvas_scale_y =
upload_size.height() / static_cast<float>(source_size.height());
// Uses kPremul_SkAlphaType since that is what SkBitmap's allocN32Pixels
// makes, and we only support the RGBA8 format here.
SkImageInfo info = SkImageInfo::MakeN32(
source_size.width(), source_size.height(), kPremul_SkAlphaType);
int row_bytes = source_size.width() * 4;
AutoLockUIResourceBitmap bitmap_lock(bitmap);
SkBitmap source_bitmap;
source_bitmap.setInfo(info, row_bytes);
source_bitmap.setPixels(const_cast<uint8_t*>(bitmap_lock.GetPixels()));
// This applies the scale to draw the |bitmap| into |scaled_bitmap|.
SkBitmap scaled_bitmap;
scaled_bitmap.allocN32Pixels(upload_size.width(), upload_size.height());
SkCanvas scaled_canvas(scaled_bitmap);
scaled_canvas.scale(canvas_scale_x, canvas_scale_y);
scaled_canvas.drawBitmap(source_bitmap, 0, 0);
SkAutoLockPixels scaled_bitmap_lock(scaled_bitmap);
auto* pixels = static_cast<uint8_t*>(scaled_bitmap.getPixels());
resource_provider_->CopyToResource(id, pixels, upload_size);
}
UIResourceData data;
data.resource_id = id;
data.size = bitmap.GetSize();
data.opaque = bitmap.GetOpaque();
ui_resource_map_[uid] = data;
AutoLockUIResourceBitmap bitmap_lock(bitmap);
resource_provider_->CopyToResource(id, bitmap_lock.GetPixels(),
bitmap.GetSize());
resource_provider_->GenerateSyncTokenForResource(id);
MarkUIResourceNotEvicted(uid);
}
......
......@@ -541,6 +541,7 @@ class CC_EXPORT LayerTreeHostImpl
struct UIResourceData {
ResourceId resource_id;
gfx::Size size;
bool opaque;
};
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment