Skip to content

Commit 547dbe3

Browse files
committed
[Model Element] Update entity transform if the model size changes with stagemode=orbit
https://bugs.webkit.org/show_bug.cgi?id=294162 rdar://151031284 Reviewed by Mike Wyrzykowski. When stagemode is set to orbit, we ensure that the model's transform is updated such that it can be rotated within the portal (fit according to its bounding sphere). If the model size changes afterwards, we need to update its transform based on the new size following the stagemode=orbit fitting rules. To fix this, when ModelProcessModelPlayerProxy is notified of a size change and stagemode is orbit, set a flag to remember to recompute the model transform for orbit fit after frame layout. * LayoutTests/model-element/model-element-update-transform-after-resize-expected.txt: Added. * LayoutTests/model-element/model-element-update-transform-after-resize.html: Added. * Source/WebKit/ModelProcess/cocoa/ModelProcessModelPlayerProxy.h: * Source/WebKit/ModelProcess/cocoa/ModelProcessModelPlayerProxy.mm: (WebKit::ModelProcessModelPlayerProxy::updateTransformAfterLayout): If m_transformNeedsUpdateAfterNextLayout is set, call updateForCurrentStageMode() to handle the transform update instead. (WebKit::ModelProcessModelPlayerProxy::sizeDidChange): Set m_transformNeedsUpdateAfterNextLayout to true if the model size changes and stagemode is set to orbit. (WebKit::ModelProcessModelPlayerProxy::updateForCurrentStageMode): Logic moved from setStageMode(). (WebKit::ModelProcessModelPlayerProxy::setStageMode): * Source/WebKit/ModelProcess/cocoa/WKModelProcessModelLayer.mm: (-[WKModelProcessModelLayer layoutSublayers]): Call ModelProcessModelPlayerProxy::updateTransformAfterLayout() after frame layout. Canonical link: https://commits.webkit.org/296026@main
1 parent 2013017 commit 547dbe3

5 files changed

Lines changed: 105 additions & 10 deletions

File tree

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
2+
PASS <model> should not update entity transform after resize if stagemode=none
3+
PASS <model> should update entity transform after resize if stagemode=orbit
4+
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
<!DOCTYPE html> <!-- webkit-test-runner [ ModelElementEnabled=true ModelProcessEnabled=true ] -->
2+
<meta charset="utf-8">
3+
<title>&lt;model> update transform after resize</title>
4+
<script src="../resources/testharness.js"></script>
5+
<script src="../resources/testharnessreport.js"></script>
6+
<script src="resources/model-element-test-utils.js"></script>
7+
<script src="resources/model-utils.js"></script>
8+
<script src="../resources/js-test-pre.js"></script>
9+
<body>
10+
<script>
11+
'use strict';
12+
13+
promise_test(async t => {
14+
const model1 = document.createElement("model");
15+
model1.setAttribute("stagemode", "none");
16+
model1.setAttribute("width", "300px");
17+
model1.setAttribute("height", "1px");
18+
document.body.appendChild(model1);
19+
model1.appendChild(makeSource("resources/flat-rectangle.usdz"));
20+
21+
const model2 = document.createElement("model");
22+
model2.setAttribute("stagemode", "none");
23+
model2.setAttribute("width", "300px");
24+
model2.setAttribute("height", "300px");
25+
document.body.appendChild(model2);
26+
model2.appendChild(makeSource("resources/flat-rectangle.usdz"));
27+
28+
await model1.ready;
29+
await model2.ready;
30+
31+
assert_3d_matrix_not_equals(model1.entityTransform, model2.entityTransform);
32+
let originalTransformForModel1 = model1.entityTransform;
33+
34+
model1.setAttribute("height", "300px");
35+
await sleepForSeconds(0.1);
36+
assert_3d_matrix_not_equals(model1.entityTransform, model2.entityTransform);
37+
assert_3d_matrix_approx_equals(model1.entityTransform, originalTransformForModel1);
38+
}, `<model> should not update entity transform after resize if stagemode=none`);
39+
40+
promise_test(async t => {
41+
const model1 = document.createElement("model");
42+
model1.setAttribute("stagemode", "orbit");
43+
model1.setAttribute("width", "300px");
44+
model1.setAttribute("height", "1px");
45+
document.body.appendChild(model1);
46+
model1.appendChild(makeSource("resources/flat-rectangle.usdz"));
47+
48+
const model2 = document.createElement("model");
49+
model2.setAttribute("stagemode", "orbit");
50+
model2.setAttribute("width", "300px");
51+
model2.setAttribute("height", "300px");
52+
document.body.appendChild(model2);
53+
model2.appendChild(makeSource("resources/flat-rectangle.usdz"));
54+
55+
await model1.ready;
56+
await model2.ready;
57+
58+
assert_3d_matrix_not_equals(model1.entityTransform, model2.entityTransform);
59+
let originalTransformForModel1 = model1.entityTransform;
60+
61+
model1.setAttribute("height", "300px");
62+
await sleepForSeconds(0.1);
63+
assert_3d_matrix_approx_equals(model1.entityTransform, model2.entityTransform);
64+
assert_3d_matrix_not_equals(model1.entityTransform, originalTransformForModel1);
65+
}, `<model> should update entity transform after resize if stagemode=orbit`);
66+
67+
</script>
68+
</body>

Source/WebKit/ModelProcess/cocoa/ModelProcessModelPlayerProxy.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ class ModelProcessModelPlayerProxy final
8282
template<typename T> void send(T&& message);
8383

8484
void unloadModelTimerFired();
85-
void updateTransform();
85+
void updateTransformAfterLayout();
8686
void updateOpacity();
8787
void startAnimating();
8888
void animationPlaybackStateDidUpdate();
@@ -151,12 +151,14 @@ class ModelProcessModelPlayerProxy final
151151
ModelProcessModelPlayerProxy(ModelProcessModelPlayerManagerProxy&, WebCore::ModelPlayerIdentifier, Ref<IPC::Connection>&&, const std::optional<String>&);
152152

153153
void computeTransform(bool);
154+
void updateTransform();
154155
void applyEnvironmentMapDataAndRelease();
155156
void applyStageModeOperationToDriver();
156157
bool stageModeInteractionInProgress() const;
157158
void updateTransformSRT();
158159
void notifyModelPlayerOfEntityTransformChange();
159160
void applyDefaultIBL();
161+
void updateForCurrentStageMode();
160162

161163
WebCore::ModelPlayerIdentifier m_id;
162164
bool m_isVisible { true };
@@ -178,6 +180,7 @@ class ModelProcessModelPlayerProxy final
178180
float m_yaw { 0 };
179181

180182
RESRT m_transformSRT; // SRT=Scaling/Rotation/Translation. This is stricter than a WebCore::TransformationMatrix.
183+
bool m_transformNeedsUpdateAfterNextLayout { false };
181184

182185
bool m_autoplay { false };
183186
bool m_loop { false };

Source/WebKit/ModelProcess/cocoa/ModelProcessModelPlayerProxy.mm

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,17 @@ static RESRT modelLocalizedTransformSRT(RESRT originalSRT)
476476
[m_modelRKEntity setTransform:WKEntityTransform({ m_transformSRT.scale, m_transformSRT.rotation, m_transformSRT.translation })];
477477
}
478478

479+
void ModelProcessModelPlayerProxy::updateTransformAfterLayout()
480+
{
481+
if (m_transformNeedsUpdateAfterNextLayout) {
482+
updateForCurrentStageMode();
483+
m_transformNeedsUpdateAfterNextLayout = false;
484+
return;
485+
}
486+
487+
updateTransform();
488+
}
489+
479490
void ModelProcessModelPlayerProxy::updateOpacity()
480491
{
481492
if (!m_modelRKEntity || !m_layer)
@@ -617,7 +628,11 @@ static RESRT modelLocalizedTransformSRT(RESRT originalSRT)
617628
void ModelProcessModelPlayerProxy::sizeDidChange(WebCore::LayoutSize layoutSize)
618629
{
619630
RELEASE_LOG_INFO(ModelElement, "%p - ModelProcessModelPlayerProxy::sizeDidChange w=%lf h=%lf id=%" PRIu64, this, layoutSize.width().toDouble(), layoutSize.height().toDouble(), m_id.toUInt64());
620-
[m_layer setFrame:CGRectMake(0, 0, layoutSize.width().toDouble(), layoutSize.height().toDouble())];
631+
auto width = layoutSize.width().toDouble();
632+
auto height = layoutSize.height().toDouble();
633+
if (!m_transformNeedsUpdateAfterNextLayout && m_stageModeOperation != WebCore::StageModeOperation::None && m_modelRKEntity && m_layer)
634+
m_transformNeedsUpdateAfterNextLayout = width != CGRectGetWidth([m_layer frame]) || height != CGRectGetHeight([m_layer frame]);
635+
[m_layer setFrame:CGRectMake(0, 0, width, height)];
621636
}
622637

623638
PlatformLayer* ModelProcessModelPlayerProxy::layer()
@@ -885,14 +900,9 @@ static void setIBLAssetOwnership(const String& attributionTaskID, REAssetRef ibl
885900
updateTransform();
886901
}
887902

888-
void ModelProcessModelPlayerProxy::setStageMode(WebCore::StageModeOperation stagemodeOp)
903+
void ModelProcessModelPlayerProxy::updateForCurrentStageMode()
889904
{
890-
if (m_stageModeOperation == stagemodeOp)
891-
return;
892-
893-
m_stageModeOperation = stagemodeOp;
894-
895-
if (stagemodeOp != WebCore::StageModeOperation::None) {
905+
if (m_stageModeOperation != WebCore::StageModeOperation::None) {
896906
computeTransform(false);
897907
[m_modelRKEntity recenterEntityAtTransform:WKEntityTransform({ m_transformSRT.scale, m_transformSRT.rotation, m_transformSRT.translation })];
898908
updateTransformSRT();
@@ -901,6 +911,16 @@ static void setIBLAssetOwnership(const String& attributionTaskID, REAssetRef ibl
901911
applyStageModeOperationToDriver();
902912
}
903913

914+
void ModelProcessModelPlayerProxy::setStageMode(WebCore::StageModeOperation stagemodeOp)
915+
{
916+
if (m_stageModeOperation == stagemodeOp)
917+
return;
918+
919+
m_stageModeOperation = stagemodeOp;
920+
921+
updateForCurrentStageMode();
922+
}
923+
904924
void ModelProcessModelPlayerProxy::updateTransformSRT()
905925
{
906926
WKEntityTransform entityTransform = [m_modelRKEntity transform];

Source/WebKit/ModelProcess/cocoa/WKModelProcessModelLayer.mm

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ - (void)layoutSublayers
3838
[super layoutSublayers];
3939

4040
if (RefPtr strongPlayer = _player.get())
41-
strongPlayer->updateTransform();
41+
strongPlayer->updateTransformAfterLayout();
4242
}
4343

4444
@end

0 commit comments

Comments
 (0)