Skip to content

Commit e3c22d4

Browse files
keithamuskcirkel@mozilla.com
authored andcommitted
Bug 1924090 - Apply resolved position-area influenced self-alignment properties during alignment for abspos with cb r=emilio,layout-reviewers,dshin,firefox-style-system-reviewers
Differential Revision: https://phabricator.services.mozilla.com/D268152
1 parent f2dc240 commit e3c22d4

26 files changed

+260
-161
lines changed

layout/base/AnchorPositioningUtils.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -504,7 +504,8 @@ static StylePositionArea ToPhysicalPositionArea(StylePositionArea aPosArea,
504504

505505
nsRect AnchorPositioningUtils::AdjustAbsoluteContainingBlockRectForPositionArea(
506506
const nsRect& aAnchorRect, const nsRect& aCBRect, WritingMode aPositionedWM,
507-
WritingMode aCBWM, const StylePositionArea& aPosArea) {
507+
WritingMode aCBWM, const StylePositionArea& aPosArea,
508+
StylePositionArea* aOutResolvedArea) {
508509
// Get the boundaries of 3x3 grid in CB's frame space. The edges of the
509510
// default anchor box are clamped to the bounds of the CB, even if that
510511
// results in zero width/height cells.
@@ -536,6 +537,7 @@ nsRect AnchorPositioningUtils::AdjustAbsoluteContainingBlockRectForPositionArea(
536537
// PositionArea, resolved to only contain Left/Right/Top/Bottom values.
537538
StylePositionArea posArea =
538539
ToPhysicalPositionArea(aPosArea, aCBWM, aPositionedWM);
540+
*aOutResolvedArea = posArea;
539541

540542
nscoord right = ltrEdges[3];
541543
if (posArea.first == StylePositionAreaKeyword::Left) {

layout/base/AnchorPositioningUtils.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ struct AnchorPositioningUtils {
114114
static nsRect AdjustAbsoluteContainingBlockRectForPositionArea(
115115
const nsRect& aAnchorRect, const nsRect& aCBRect,
116116
WritingMode aPositionedWM, WritingMode aCBWM,
117-
const StylePositionArea& aPosArea);
117+
const StylePositionArea& aPosArea, StylePositionArea* aOutResolvedArea);
118118

119119
/**
120120
* Gets the used anchor name for an anchor positioned frame.

layout/generic/AbsoluteContainingBlock.cpp

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -506,7 +506,8 @@ static nscoord OffsetToAlignedStaticPos(
506506
const ReflowInput& aKidReflowInput, const LogicalSize& aKidSizeInAbsPosCBWM,
507507
const LogicalSize& aAbsPosCBSize,
508508
const nsContainerFrame* aPlaceholderContainer, WritingMode aAbsPosCBWM,
509-
LogicalAxis aAbsPosCBAxis, Maybe<NonAutoAlignParams> aNonAutoAlignParams) {
509+
LogicalAxis aAbsPosCBAxis, Maybe<NonAutoAlignParams> aNonAutoAlignParams,
510+
const StylePositionArea& aPositionArea) {
510511
if (!aPlaceholderContainer) {
511512
// (The placeholder container should be the thing that kicks this whole
512513
// process off, by setting PLACEHOLDER_STATICPOS_NEEDS_CSSALIGN. So it
@@ -526,6 +527,7 @@ static nscoord OffsetToAlignedStaticPos(
526527
// WritingMode. For brevity, we use the abbreviation "pc" for "placeholder
527528
// container" in variables below.
528529
WritingMode pcWM = aPlaceholderContainer->GetWritingMode();
530+
LogicalSize absPosCBSizeInPCWM = aAbsPosCBSize.ConvertTo(pcWM, aAbsPosCBWM);
529531

530532
// Find what axis aAbsPosCBAxis corresponds to, in placeholder's parent's
531533
// writing-mode.
@@ -609,7 +611,7 @@ static nscoord OffsetToAlignedStaticPos(
609611
aNonAutoAlignParams
610612
? aPlaceholderContainer
611613
->CSSAlignmentForAbsPosChildWithinContainingBlock(
612-
aKidReflowInput, pcAxis)
614+
aKidReflowInput, pcAxis, aPositionArea, absPosCBSizeInPCWM)
613615
: aPlaceholderContainer->CSSAlignmentForAbsPosChild(aKidReflowInput,
614616
pcAxis);
615617
// If the safe bit in alignConst is set, set the safe flag in |flags|.
@@ -710,7 +712,7 @@ static nscoord OffsetToAlignedStaticPos(
710712
void AbsoluteContainingBlock::ResolveSizeDependentOffsets(
711713
ReflowInput& aKidReflowInput, const LogicalSize& aLogicalCBSize,
712714
const LogicalSize& aKidSize, const LogicalMargin& aMargin,
713-
LogicalMargin& aOffsets) {
715+
const StylePositionArea& aResolvedPositionArea, LogicalMargin& aOffsets) {
714716
WritingMode wm = aKidReflowInput.GetWritingMode();
715717
WritingMode outerWM = aKidReflowInput.mParentReflowInput->GetWritingMode();
716718

@@ -745,7 +747,7 @@ void AbsoluteContainingBlock::ResolveSizeDependentOffsets(
745747
placeholderContainer = GetPlaceholderContainer(aKidReflowInput.mFrame);
746748
nscoord offset = OffsetToAlignedStaticPos(
747749
aKidReflowInput, aKidSize, logicalCBSizeOuterWM, placeholderContainer,
748-
outerWM, LogicalAxis::Inline, Nothing{});
750+
outerWM, LogicalAxis::Inline, Nothing{}, aResolvedPositionArea);
749751
// Shift IStart from its current position (at start corner of the
750752
// alignment container) by the returned offset. And set IEnd to the
751753
// distance between the kid's end edge to containing block's end edge.
@@ -765,7 +767,7 @@ void AbsoluteContainingBlock::ResolveSizeDependentOffsets(
765767
}
766768
nscoord offset = OffsetToAlignedStaticPos(
767769
aKidReflowInput, aKidSize, logicalCBSizeOuterWM, placeholderContainer,
768-
outerWM, LogicalAxis::Block, Nothing{});
770+
outerWM, LogicalAxis::Block, Nothing{}, aResolvedPositionArea);
769771
// Shift BStart from its current position (at start corner of the
770772
// alignment container) by the returned offset. And set BEnd to the
771773
// distance between the kid's end edge to containing block's end edge.
@@ -955,13 +957,14 @@ void AbsoluteContainingBlock::ReflowAbsoluteFrame(
955957

956958
do {
957959
AutoFallbackStyleSetter fallback(aKidFrame, currentFallbackStyle);
960+
auto positionArea = aKidFrame->StylePosition()->mPositionArea;
961+
StylePositionArea resolvedPositionArea;
958962
const nsRect usedCb = [&] {
959963
if (isGrid) {
960964
// TODO(emilio): how does position-area interact with grid?
961965
return nsGridContainerFrame::GridItemCB(aKidFrame);
962966
}
963967

964-
auto positionArea = aKidFrame->StylePosition()->mPositionArea;
965968
if (currentFallback && currentFallback->IsPositionArea()) {
966969
MOZ_ASSERT(currentFallback->IsPositionArea());
967970
positionArea = currentFallback->AsPositionArea();
@@ -975,7 +978,8 @@ void AbsoluteContainingBlock::ReflowAbsoluteFrame(
975978
AdjustAbsoluteContainingBlockRectForPositionArea(
976979
*defaultAnchorInfo.mRect, aOriginalContainingBlockRect,
977980
aKidFrame->GetWritingMode(),
978-
aDelegatingFrame->GetWritingMode(), positionArea);
981+
aDelegatingFrame->GetWritingMode(), positionArea,
982+
&resolvedPositionArea);
979983
}
980984
}
981985

@@ -1096,7 +1100,7 @@ void AbsoluteContainingBlock::ReflowAbsoluteFrame(
10961100
// If we're solving for start in either inline or block direction,
10971101
// then compute it now that we know the dimensions.
10981102
ResolveSizeDependentOffsets(kidReflowInput, logicalCBSize, kidSize,
1099-
margin, offsets);
1103+
margin, resolvedPositionArea, offsets);
11001104

11011105
if (kidReflowInput.mFlags.mDeferAutoMarginComputation) {
11021106
ResolveAutoMarginsAfterLayout(kidReflowInput, logicalCBSize, kidSize,
@@ -1108,10 +1112,12 @@ void AbsoluteContainingBlock::ReflowAbsoluteFrame(
11081112
// to align the child by its margin box:
11091113
// https://drafts.csswg.org/css-position-3/#abspos-layout
11101114
const auto* stylePos = aKidFrame->StylePosition();
1115+
const LogicalSize logicalCBSizeOuterWM(outerWM, usedCb.Size());
11111116
const auto anchorResolutionParams =
1112-
AnchorPosOffsetResolutionParams::UseCBFrameSize(
1117+
AnchorPosOffsetResolutionParams::ExplicitCBFrameSize(
11131118
AnchorPosResolutionParams::From(aKidFrame,
1114-
aAnchorPosReferenceData));
1119+
aAnchorPosReferenceData),
1120+
&logicalCBSizeOuterWM);
11151121
const bool iInsetAuto =
11161122
stylePos
11171123
->GetAnchorResolvedInset(LogicalSide::IStart, outerWM,
@@ -1130,7 +1136,6 @@ void AbsoluteContainingBlock::ReflowAbsoluteFrame(
11301136
->GetAnchorResolvedInset(LogicalSide::BEnd, outerWM,
11311137
anchorResolutionParams)
11321138
->IsAuto();
1133-
const LogicalSize logicalCBSizeOuterWM(outerWM, usedCb.Size());
11341139
const LogicalSize kidMarginBox{
11351140
outerWM, margin.IStartEnd(outerWM) + kidSize.ISize(outerWM),
11361141
margin.BStartEnd(outerWM) + kidSize.BSize(outerWM)};
@@ -1148,7 +1153,8 @@ void AbsoluteContainingBlock::ReflowAbsoluteFrame(
11481153
Some(NonAutoAlignParams{
11491154
offsets.IStart(outerWM),
11501155
offsets.IEnd(outerWM),
1151-
}));
1156+
}),
1157+
resolvedPositionArea);
11521158

11531159
offsets.IStart(outerWM) += alignOffset;
11541160
offsets.IEnd(outerWM) =
@@ -1165,7 +1171,8 @@ void AbsoluteContainingBlock::ReflowAbsoluteFrame(
11651171
Some(NonAutoAlignParams{
11661172
offsets.BStart(outerWM),
11671173
offsets.BEnd(outerWM),
1168-
}));
1174+
}),
1175+
resolvedPositionArea);
11691176
offsets.BStart(outerWM) += alignOffset;
11701177
offsets.BEnd(outerWM) =
11711178
logicalCBSizeOuterWM.BSize(outerWM) -

layout/generic/AbsoluteContainingBlock.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ enum class AbsPosReflowFlag : uint8_t {
2828
IsGridContainerCB,
2929
};
3030
using AbsPosReflowFlags = EnumSet<AbsPosReflowFlag>;
31+
struct StylePositionArea;
3132

3233
/**
3334
* This class contains the logic for being an absolute containing block. This
@@ -122,11 +123,10 @@ class AbsoluteContainingBlock {
122123
*
123124
* aOffset is an outparam.
124125
*/
125-
void ResolveSizeDependentOffsets(ReflowInput& aKidReflowInput,
126-
const LogicalSize& aLogicalCBSize,
127-
const LogicalSize& aKidSize,
128-
const LogicalMargin& aMargin,
129-
LogicalMargin& aOffsets);
126+
void ResolveSizeDependentOffsets(
127+
ReflowInput& aKidReflowInput, const LogicalSize& aLogicalCBSize,
128+
const LogicalSize& aKidSize, const LogicalMargin& aMargin,
129+
const StylePositionArea& aResolvedPositionArea, LogicalMargin& aOffsets);
130130

131131
/**
132132
* For frames that have intrinsic block sizes, since we want to use the

layout/generic/ReflowInput.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -981,9 +981,12 @@ struct ReflowInput : public SizeComputationInput {
981981
} // namespace mozilla
982982

983983
inline AnchorPosResolutionParams AnchorPosResolutionParams::From(
984-
const mozilla::ReflowInput* aRI) {
985-
return {aRI->mFrame, aRI->mStyleDisplay->mPosition,
986-
aRI->mStylePosition->mPositionArea, aRI->mAnchorPosReferenceData};
984+
const mozilla::ReflowInput* aRI, bool aIgnorePositionArea) {
985+
const mozilla::StylePositionArea posArea =
986+
aIgnorePositionArea ? mozilla::StylePositionArea{}
987+
: aRI->mStylePosition->mPositionArea;
988+
return {aRI->mFrame, aRI->mStyleDisplay->mPosition, posArea,
989+
aRI->mAnchorPosReferenceData};
987990
}
988991

989992
#endif // mozilla_ReflowInput_h

layout/generic/WritingModes.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2189,6 +2189,17 @@ inline AnchorResolvedInset nsStylePosition::GetAnchorResolvedInset(
21892189
return GetAnchorResolvedInset(aWM.PhysicalSide(aSide), aParams);
21902190
}
21912191

2192+
inline mozilla::Maybe<mozilla::Side> nsStylePosition::GetSingleAutoInsetInAxis(
2193+
LogicalAxis aAxis, WritingMode aWM,
2194+
const AnchorPosOffsetResolutionParams& aParams) const {
2195+
const bool isInlineAxis = (aAxis == LogicalAxis::Inline);
2196+
const mozilla::StylePhysicalAxis physicalAxis =
2197+
(isInlineAxis == aWM.IsVertical())
2198+
? mozilla::StylePhysicalAxis::Vertical
2199+
: mozilla::StylePhysicalAxis::Horizontal;
2200+
return GetSingleAutoInsetInAxis(physicalAxis, aParams);
2201+
}
2202+
21922203
inline AnchorResolvedSize nsStylePosition::ISize(
21932204
WritingMode aWM, const AnchorPosResolutionParams& aParams) const {
21942205
return aWM.IsVertical() ? GetHeight(aParams) : GetWidth(aParams);

layout/generic/nsContainerFrame.cpp

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
#include <algorithm>
1212

13+
#include "AnchorPositioningUtils.h"
1314
#include "mozilla/AbsoluteContainingBlock.h"
1415
#include "mozilla/AutoRestore.h"
1516
#include "mozilla/ComputedStyle.h"
@@ -2624,7 +2625,9 @@ StyleAlignFlags nsContainerFrame::CSSAlignmentForAbsPosChild(
26242625

26252626
StyleAlignFlags
26262627
nsContainerFrame::CSSAlignmentForAbsPosChildWithinContainingBlock(
2627-
const ReflowInput& aChildRI, LogicalAxis aLogicalAxis) const {
2628+
const ReflowInput& aChildRI, LogicalAxis aLogicalAxis,
2629+
const StylePositionArea& aResolvedPositionArea,
2630+
const LogicalSize& aCBSize) const {
26282631
MOZ_ASSERT(aChildRI.mFrame->IsAbsolutelyPositioned(),
26292632
"This method should only be called for abspos children");
26302633
// When determining the position of absolutely-positioned boxes,
@@ -2634,6 +2637,45 @@ nsContainerFrame::CSSAlignmentForAbsPosChildWithinContainingBlock(
26342637
? aChildRI.mStylePosition->UsedJustifySelf(nullptr)._0
26352638
: aChildRI.mStylePosition->UsedAlignSelf(nullptr)._0;
26362639

2640+
// Check if position-area is set - if so, it determines the default alignment
2641+
// https://drafts.csswg.org/css-anchor-position/#position-area-alignment
2642+
if (!aResolvedPositionArea.IsNone() && alignment == StyleAlignFlags::NORMAL) {
2643+
const WritingMode cbWM = GetWritingMode();
2644+
const auto anchorResolutionParams = AnchorPosResolutionParams::From(
2645+
&aChildRI, /* aIgnorePositionArea = */ true);
2646+
const auto anchorOffsetResolutionParams =
2647+
AnchorPosOffsetResolutionParams::ExplicitCBFrameSize(
2648+
anchorResolutionParams, &aCBSize);
2649+
2650+
// Check if we have exactly one auto inset in this axis (IMCB situation)
2651+
const auto singleAutoInset =
2652+
aChildRI.mStylePosition->GetSingleAutoInsetInAxis(
2653+
aLogicalAxis, cbWM, anchorOffsetResolutionParams);
2654+
2655+
// Check if exactly one inset in the axis is auto
2656+
// https://drafts.csswg.org/css-anchor-position/#position-area-alignment
2657+
// "However, if only one inset property in the relevant axis is auto, the
2658+
// default alignment is instead towards the edge with the non-auto inset;
2659+
// and this is an unsafe alignment."
2660+
if (singleAutoInset.isSome()) {
2661+
const LogicalSide startSide = aLogicalAxis == LogicalAxis::Inline
2662+
? LogicalSide::IStart
2663+
: LogicalSide::BStart;
2664+
const mozilla::Side autoSide = *singleAutoInset;
2665+
const mozilla::Side startPhysicalSide = cbWM.PhysicalSide(startSide);
2666+
// Exactly one inset is auto - align toward the non-auto edge, unsafely
2667+
alignment = (autoSide == startPhysicalSide) ? StyleAlignFlags::END
2668+
: StyleAlignFlags::START;
2669+
alignment |= StyleAlignFlags::UNSAFE;
2670+
} else {
2671+
auto keyword = aLogicalAxis == LogicalAxis::Inline
2672+
? aResolvedPositionArea.first
2673+
: aResolvedPositionArea.second;
2674+
// Use normal position-area alignment
2675+
Servo_ResolvePositionAreaSelfAlignment(&keyword, &alignment);
2676+
}
2677+
}
2678+
26372679
return MapCSSAlignment(alignment, aChildRI, aLogicalAxis, GetWritingMode());
26382680
}
26392681

layout/generic/nsContainerFrame.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ class nsOverflowContinuationTracker;
2121

2222
namespace mozilla {
2323
class PresShell;
24+
struct StylePositionArea;
2425
} // namespace mozilla
2526

2627
// Some macros for container classes to do sanity checking on
@@ -492,7 +493,9 @@ class nsContainerFrame : public nsSplittableFrame {
492493
* on its type (By overriding `CSSAlignmentForAbsPosChild`).
493494
*/
494495
mozilla::StyleAlignFlags CSSAlignmentForAbsPosChildWithinContainingBlock(
495-
const ReflowInput& aChildRI, mozilla::LogicalAxis aLogicalAxis) const;
496+
const ReflowInput& aChildRI, mozilla::LogicalAxis aLogicalAxis,
497+
const mozilla::StylePositionArea& aResolvedPositionArea,
498+
const mozilla::LogicalSize& aContainingBlockSize) const;
496499

497500
#define NS_DECLARE_FRAME_PROPERTY_FRAMELIST(prop) \
498501
NS_DECLARE_FRAME_PROPERTY_WITH_DTOR_NEVER_CALLED(prop, nsFrameList)

layout/style/nsStyleStruct.h

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -399,7 +399,8 @@ struct AnchorPosResolutionParams {
399399
static inline AnchorPosResolutionParams From(
400400
const nsIFrame* aFrame,
401401
mozilla::AnchorPosReferenceData* aAnchorPosReferenceData = nullptr);
402-
static inline AnchorPosResolutionParams From(const mozilla::ReflowInput* aRI);
402+
static inline AnchorPosResolutionParams From(
403+
const mozilla::ReflowInput* aRI, bool aIgnorePositionArea = false);
403404
static inline AnchorPosResolutionParams From(
404405
const nsComputedDOMStyle* aComputedDOMStyle);
405406
};
@@ -1089,6 +1090,40 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStylePosition {
10891090
mozilla::LogicalSide aSide, WritingMode aWM,
10901091
const AnchorPosOffsetResolutionParams& aParams) const;
10911092

1093+
// Returns the side with an auto inset if exactly one inset in the given
1094+
// physical axis is auto. Otherwise returns Nothing().
1095+
mozilla::Maybe<mozilla::Side> GetSingleAutoInsetInAxis(
1096+
mozilla::StylePhysicalAxis aAxis,
1097+
const AnchorPosOffsetResolutionParams& aParams) const {
1098+
const mozilla::Side startSide =
1099+
aAxis == mozilla::StylePhysicalAxis::Horizontal ? mozilla::eSideLeft
1100+
: mozilla::eSideTop;
1101+
const mozilla::Side endSide =
1102+
aAxis == mozilla::StylePhysicalAxis::Horizontal ? mozilla::eSideRight
1103+
: mozilla::eSideBottom;
1104+
1105+
const bool startInsetIsAuto =
1106+
AnchorResolvedInsetHelper::FromUnresolved(mOffset.Get(startSide),
1107+
startSide, aParams)
1108+
->IsAuto();
1109+
const bool endInsetIsAuto = AnchorResolvedInsetHelper::FromUnresolved(
1110+
mOffset.Get(endSide), endSide, aParams)
1111+
->IsAuto();
1112+
1113+
if (startInsetIsAuto && !endInsetIsAuto) {
1114+
return mozilla::Some(startSide);
1115+
}
1116+
if (!startInsetIsAuto && endInsetIsAuto) {
1117+
return mozilla::Some(endSide);
1118+
}
1119+
return mozilla::Nothing();
1120+
}
1121+
1122+
// Logical-axis version, defined in WritingModes.h
1123+
inline mozilla::Maybe<mozilla::Side> GetSingleAutoInsetInAxis(
1124+
LogicalAxis aAxis, WritingMode aWM,
1125+
const AnchorPosOffsetResolutionParams& aParams) const;
1126+
10921127
AnchorResolvedSize GetWidth(const AnchorPosResolutionParams& aParams) const {
10931128
return AnchorResolvedSizeHelper::FromUnresolved(
10941129
mWidth, mozilla::StylePhysicalAxis::Horizontal, aParams);

servo/components/style/values/specified/position.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ use crate::values::generics::position::ZIndex as GenericZIndex;
2121
use crate::values::generics::position::{AspectRatio as GenericAspectRatio, GenericAnchorSide};
2222
use crate::values::generics::position::{GenericAnchorFunction, GenericInset};
2323
use crate::values::specified;
24+
use crate::values::specified::align::AlignFlags;
2425
use crate::values::specified::{AllowQuirks, Integer, LengthPercentage, NonNegativeNumber};
2526
use crate::values::DashedIdent;
2627
use crate::{Atom, Zero};
@@ -1184,6 +1185,29 @@ impl PositionAreaKeyword {
11841185
let new_track = old_track.flip();
11851186
Self::from_u8((self as u8 & !TRACK_MASK) | new_track as u8).unwrap()
11861187
}
1188+
1189+
/// Returns a value for the self-alignment properties in order to resolve
1190+
/// `normal`.
1191+
///
1192+
/// <https://drafts.csswg.org/css-anchor-position/#position-area-alignment>
1193+
pub fn to_self_alignment(self) -> Option<AlignFlags> {
1194+
let track = self.track()?;
1195+
Some(match track {
1196+
// "If the only the center track in an axis is selected, the default alignment in that axis is center."
1197+
PositionAreaTrack::Center => AlignFlags::CENTER,
1198+
// "If all three tracks are selected, the default alignment in that axis is anchor-center."
1199+
PositionAreaTrack::SpanAll => AlignFlags::ANCHOR_CENTER,
1200+
// "Otherwise, the default alignment in that axis is toward the non-specified side track: if it’s
1201+
// specifying the “start” track of its axis, the default alignment in that axis is end; etc."
1202+
_ => {
1203+
if track.start() {
1204+
AlignFlags::END
1205+
} else {
1206+
AlignFlags::START
1207+
}
1208+
},
1209+
})
1210+
}
11871211
}
11881212

11891213
#[derive(

0 commit comments

Comments
 (0)