Skip to content

Commit 651acd0

Browse files
rh101minggo
authored andcommitted
Fix ui::Layout scissor clipping (#20352)
* Added RenderTexture::saveToFileAsNonPMA() to save images without PMA. Set the PMA parameter to true when calling initWithRawData() inside RenderTexture::newImage(), since textures are PMA. Renamed Image::premultipliedAlpha() to Image::premultiplyAlpha() to better reflect it's action, and made it public. Added Image::reversePremultipliedAlpha() to allow the reversing of the PMA. Updated CCImage-ios.mm to set the correct bitmapInfo for PMA and non-PMA images before saving a file. Updated RenderTextureTest::RenderTextureSave() to cater for non-PMA file saving. * [CCImage-ios.mm] Fixed indentation. * [UILayout.cpp] Fix for incorrect SCISSOR clipping rectangle calculation. [UILayoutTest.cpp] Test added to reproduce issue with SCISSOR clipping. * Get reference to clipping rectangle instead of a copy.
1 parent 8708e82 commit 651acd0

File tree

3 files changed

+81
-14
lines changed

3 files changed

+81
-14
lines changed

cocos/ui/UILayout.cpp

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -463,11 +463,10 @@ const Rect& Layout::getClippingRect()
463463
{
464464
if (_clippingRectDirty)
465465
{
466-
Vec2 worldPos = convertToWorldSpace(Vec2::ZERO);
467-
AffineTransform t = getNodeToWorldAffineTransform();
468-
float scissorWidth = _contentSize.width*t.a;
469-
float scissorHeight = _contentSize.height*t.d;
470-
Rect parentClippingRect;
466+
const Vec2 worldPos = convertToWorldSpace(Vec2::ZERO);
467+
const AffineTransform t = getNodeToWorldAffineTransform();
468+
const float scissorWidth = _contentSize.width * t.a;
469+
const float scissorHeight = _contentSize.height * t.d;
471470
Layout* parent = this;
472471

473472
while (parent)
@@ -485,29 +484,29 @@ const Rect& Layout::getClippingRect()
485484

486485
if (_clippingParent)
487486
{
488-
parentClippingRect = _clippingParent->getClippingRect();
489-
float finalX = worldPos.x - (scissorWidth * _anchorPoint.x);
490-
float finalY = worldPos.y - (scissorHeight * _anchorPoint.y);
487+
const Rect& parentClippingRect = _clippingParent->getClippingRect();
488+
float finalX = worldPos.x;
489+
float finalY = worldPos.y;
491490
float finalWidth = scissorWidth;
492491
float finalHeight = scissorHeight;
493492

494-
float leftOffset = worldPos.x - parentClippingRect.origin.x;
493+
const float leftOffset = worldPos.x - parentClippingRect.origin.x;
495494
if (leftOffset < 0.0f)
496495
{
497496
finalX = parentClippingRect.origin.x;
498497
finalWidth += leftOffset;
499498
}
500-
float rightOffset = (worldPos.x + scissorWidth) - (parentClippingRect.origin.x + parentClippingRect.size.width);
499+
const float rightOffset = (worldPos.x + scissorWidth) - (parentClippingRect.origin.x + parentClippingRect.size.width);
501500
if (rightOffset > 0.0f)
502501
{
503502
finalWidth -= rightOffset;
504503
}
505-
float topOffset = (worldPos.y + scissorHeight) - (parentClippingRect.origin.y + parentClippingRect.size.height);
504+
const float topOffset = (worldPos.y + scissorHeight) - (parentClippingRect.origin.y + parentClippingRect.size.height);
506505
if (topOffset > 0.0f)
507506
{
508507
finalHeight -= topOffset;
509508
}
510-
float bottomOffset = worldPos.y - parentClippingRect.origin.y;
509+
const float bottomOffset = worldPos.y - parentClippingRect.origin.y;
511510
if (bottomOffset < 0.0f)
512511
{
513512
finalY = parentClippingRect.origin.y;
@@ -528,8 +527,8 @@ const Rect& Layout::getClippingRect()
528527
}
529528
else
530529
{
531-
_clippingRect.origin.x = worldPos.x - (scissorWidth * _anchorPoint.x);
532-
_clippingRect.origin.y = worldPos.y - (scissorHeight * _anchorPoint.y);
530+
_clippingRect.origin.x = worldPos.x;
531+
_clippingRect.origin.y = worldPos.y;
533532
_clippingRect.size.width = scissorWidth;
534533
_clippingRect.size.height = scissorHeight;
535534
}

tests/cpp-tests/Classes/UITest/CocoStudioGUITest/UILayoutTest/UILayoutTest.cpp

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ UILayoutTests::UILayoutTests()
4242
ADD_TEST_CASE(UILayoutComponentTest);
4343
ADD_TEST_CASE(UILayoutComponent_Berth_Test);
4444
ADD_TEST_CASE(UILayoutComponent_Berth_Stretch_Test);
45+
ADD_TEST_CASE(UILayoutTest_Issue19890);
4546
}
4647

4748
// UILayoutTest
@@ -956,3 +957,62 @@ bool UILayoutComponent_Berth_Stretch_Test::init()
956957
}
957958
return false;
958959
}
960+
961+
bool UILayoutTest_Issue19890::init()
962+
{
963+
if (!UIScene::init())
964+
{
965+
return false;
966+
}
967+
968+
const Size widgetSize = _widget->getContentSize();
969+
970+
auto label = Text::create("Issue 19890", "fonts/Marker Felt.ttf", 32);
971+
label->setAnchorPoint(Vec2(0.5f, -1.0f));
972+
label->setPosition(Vec2(widgetSize.width / 2.0f,
973+
widgetSize.height / 2.0f + label->getContentSize().height * 1.5f));
974+
_uiLayer->addChild(label);
975+
976+
Text* alert = Text::create("3 panels should be completely visible", "fonts/Marker Felt.ttf", 20);
977+
alert->setColor(Color3B(159, 168, 176));
978+
alert->setPosition(Vec2(widgetSize.width / 2.0f,
979+
widgetSize.height / 2.0f - alert->getContentSize().height * 3.075f));
980+
_uiLayer->addChild(alert);
981+
982+
Layout* root = static_cast<Layout*>(_uiLayer->getChildByTag(81));
983+
984+
Layout* background = dynamic_cast<Layout*>(root->getChildByName("background_Panel"));
985+
const Size backgroundSize = background->getContentSize();
986+
987+
auto panel = ui::Layout::create();
988+
panel->setBackGroundColor(Color3B::RED);
989+
panel->setBackGroundColorType(ui::Layout::BackGroundColorType::SOLID);
990+
panel->setClippingType(ui::Layout::ClippingType::SCISSOR);
991+
panel->setPosition(backgroundSize / 2);
992+
panel->setAnchorPoint(Vec2::ANCHOR_MIDDLE);
993+
panel->setClippingEnabled(true);
994+
panel->setContentSize(backgroundSize); // from the left to the screen end
995+
background->addChild(panel);
996+
997+
auto panel2 = ui::Layout::create();
998+
panel2->setBackGroundColor(Color3B::BLUE);
999+
panel2->setBackGroundColorType(ui::Layout::BackGroundColorType::SOLID);
1000+
panel2->setClippingType(ui::Layout::ClippingType::SCISSOR);
1001+
panel2->setPosition(panel->getContentSize() / 2);
1002+
panel2->setAnchorPoint(Vec2::ANCHOR_MIDDLE);
1003+
panel2->setClippingEnabled(true);
1004+
panel2->setContentSize(panel->getContentSize() / 2); // from the left to the screen end
1005+
panel->addChild(panel2);
1006+
1007+
auto panel3 = ui::Layout::create();
1008+
panel3->setBackGroundColor(Color3B::GREEN);
1009+
panel3->setBackGroundColorType(ui::Layout::BackGroundColorType::SOLID);
1010+
panel3->setClippingType(ui::Layout::ClippingType::SCISSOR);
1011+
panel3->setPosition(panel2->getContentSize() / 2);
1012+
panel3->setAnchorPoint(Vec2::ANCHOR_MIDDLE);
1013+
panel3->setClippingEnabled(true);
1014+
panel3->setContentSize(panel2->getContentSize() / 2); // from the left to the screen end
1015+
panel2->addChild(panel3);
1016+
1017+
return true;
1018+
}

tests/cpp-tests/Classes/UITest/CocoStudioGUITest/UILayoutTest/UILayoutTest.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,4 +162,12 @@ class UILayoutComponent_Berth_Stretch_Test : public UILayoutComponentTest
162162
CREATE_FUNC(UILayoutComponent_Berth_Stretch_Test);
163163
};
164164

165+
class UILayoutTest_Issue19890 : public UIScene
166+
{
167+
public:
168+
virtual bool init() override;
169+
170+
CREATE_FUNC(UILayoutTest_Issue19890);
171+
};
172+
165173
#endif /* defined(__TestCpp__UILayoutTest__) */

0 commit comments

Comments
 (0)