Changeset 250188 in webkit


Ignore:
Timestamp:
Sep 21, 2019 7:40:44 PM (5 years ago)
Author:
Brent Fulgham
Message:

[FTW] Resolve crashes found while running canvas tests
https://bugs.webkit.org/show_bug.cgi?id=202062

Reviewed by Don Olmstead.

  • platform/graphics/Pattern.h:
  • platform/graphics/win/Direct2DOperations.cpp:

(WebCore::Direct2D::FillSource::FillSource): Take GraphicsContext as argument, rather than
a PlatformContextDirect2D since downstream operations require the former.
(WebCore::Direct2D::StrokeSource::StrokeSource): Ditto.
(WebCore::Direct2D::clip): Use new 'pushClip' helper function.

  • platform/graphics/win/Direct2DOperations.h:
  • platform/graphics/win/GraphicsContextDirect2D.cpp:

(WebCore::GraphicsContext::drawPath):
(WebCore::GraphicsContext::fillPath):
(WebCore::GraphicsContext::strokePath):
(WebCore::GraphicsContext::fillRect):
(WebCore::GraphicsContext::fillRectWithRoundedHole):
(WebCore::GraphicsContext::strokeRect):

  • platform/graphics/win/GraphicsContextImplDirect2D.cpp:

(WebCore::GraphicsContextImplDirect2D::fillRect): Update to pass GraphicsContext.
(WebCore::GraphicsContextImplDirect2D::fillRectWithRoundedHole): Ditto.
(WebCore::GraphicsContextImplDirect2D::fillPath): Ditto.
(WebCore::GraphicsContextImplDirect2D::strokeRect): Ditto.
(WebCore::GraphicsContextImplDirect2D::strokePath): Ditto.
(WebCore::GraphicsContextImplDirect2D::drawGlyphs): Ditto.

  • platform/graphics/win/ImageBufferDataDirect2D.cpp:

(WebCore::ImageBufferData::copyRectFromSourceToData): Correct return behavior.
(WebCore::ImageBufferData::compatibleBitmap): Make a copy if the render target is
backed by the ID2D1Bitmap we are trying to draw with.

  • platform/graphics/win/PatternDirect2D.cpp:

(WebCore::Pattern::createPlatformPattern const): Remove 'PlatformContextDirect2D' contructor,
since we always need a GraphicsContext for the Image class.

  • platform/graphics/win/PlatformContextDirect2D.cpp:

(WebCore::PlatformContextDirect2D::clipLayer const): Added.
(WebCore::PlatformContextDirect2D::clearClips): Added.
(WebCore::PlatformContextDirect2D::restore): Update to use m_stateStack, rather than
the m_renderStates vector.
(WebCore::PlatformContextDirect2D::save): Ditto.
(WebCore::PlatformContextDirect2D::pushRenderClip): Ditto.
(WebCore::PlatformContextDirect2D::setActiveLayer): Ditto.
(WebCore::PlatformContextDirect2D::endDraw): Ditto.
(WebCore::PlatformContextDirect2D::notifyPostDrawObserver): Ditto.
(WebCore::PlatformContextDirect2D::pushClip): Ditto.

  • platform/graphics/win/PlatformContextDirect2D.h:

(WebCore::PlatformContextDirect2D::hasSavedState const):
(WebCore::PlatformContextDirect2D::clipLayer const): Deleted.

Location:
trunk/Source/WebCore
Files:
10 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r250182 r250188  
     12019-09-21  Brent Fulgham  <bfulgham@apple.com>
     2
     3        [FTW] Resolve crashes found while running canvas tests
     4        https://bugs.webkit.org/show_bug.cgi?id=202062
     5
     6        Reviewed by Don Olmstead.
     7
     8        * platform/graphics/Pattern.h:
     9        * platform/graphics/win/Direct2DOperations.cpp:
     10        (WebCore::Direct2D::FillSource::FillSource): Take GraphicsContext as argument, rather than
     11        a PlatformContextDirect2D since downstream operations require the former.       
     12        (WebCore::Direct2D::StrokeSource::StrokeSource): Ditto.
     13        (WebCore::Direct2D::clip): Use new 'pushClip' helper function.
     14        * platform/graphics/win/Direct2DOperations.h:
     15        * platform/graphics/win/GraphicsContextDirect2D.cpp:
     16        (WebCore::GraphicsContext::drawPath):
     17        (WebCore::GraphicsContext::fillPath):
     18        (WebCore::GraphicsContext::strokePath):
     19        (WebCore::GraphicsContext::fillRect):
     20        (WebCore::GraphicsContext::fillRectWithRoundedHole):
     21        (WebCore::GraphicsContext::strokeRect):
     22        * platform/graphics/win/GraphicsContextImplDirect2D.cpp:
     23        (WebCore::GraphicsContextImplDirect2D::fillRect): Update to pass GraphicsContext.
     24        (WebCore::GraphicsContextImplDirect2D::fillRectWithRoundedHole): Ditto.
     25        (WebCore::GraphicsContextImplDirect2D::fillPath): Ditto.
     26        (WebCore::GraphicsContextImplDirect2D::strokeRect): Ditto.
     27        (WebCore::GraphicsContextImplDirect2D::strokePath): Ditto.
     28        (WebCore::GraphicsContextImplDirect2D::drawGlyphs): Ditto.
     29        * platform/graphics/win/ImageBufferDataDirect2D.cpp:
     30        (WebCore::ImageBufferData::copyRectFromSourceToData): Correct return behavior.
     31        (WebCore::ImageBufferData::compatibleBitmap): Make a copy if the render target is
     32        backed by the ID2D1Bitmap we are trying to draw with.
     33        * platform/graphics/win/PatternDirect2D.cpp:
     34        (WebCore::Pattern::createPlatformPattern const): Remove 'PlatformContextDirect2D' contructor,
     35        since we always need a GraphicsContext for the Image class.
     36        * platform/graphics/win/PlatformContextDirect2D.cpp:
     37        (WebCore::PlatformContextDirect2D::clipLayer const): Added.
     38        (WebCore::PlatformContextDirect2D::clearClips): Added.
     39        (WebCore::PlatformContextDirect2D::restore): Update to use m_stateStack, rather than
     40        the m_renderStates vector.
     41        (WebCore::PlatformContextDirect2D::save): Ditto.
     42        (WebCore::PlatformContextDirect2D::pushRenderClip): Ditto.
     43        (WebCore::PlatformContextDirect2D::setActiveLayer): Ditto.
     44        (WebCore::PlatformContextDirect2D::endDraw): Ditto.
     45        (WebCore::PlatformContextDirect2D::notifyPostDrawObserver): Ditto.
     46        (WebCore::PlatformContextDirect2D::pushClip): Ditto.
     47        * platform/graphics/win/PlatformContextDirect2D.h:
     48        (WebCore::PlatformContextDirect2D::hasSavedState const):
     49        (WebCore::PlatformContextDirect2D::clipLayer const): Deleted.
     50
    1512019-09-20  Antoine Quint  <graouts@apple.com>
    252
  • trunk/Source/WebCore/platform/graphics/Pattern.h

    r248020 r250188  
    6767    PlatformPatternPtr createPlatformPattern(const AffineTransform& userSpaceTransformation) const;
    6868#else
    69     PlatformPatternPtr createPlatformPattern(PlatformGraphicsContext&, float alpha, const AffineTransform& userSpaceTransformation) const;
    7069    PlatformPatternPtr createPlatformPattern(const GraphicsContext&, float alpha, const AffineTransform& userSpaceTransformation) const;
    7170#endif
  • trunk/Source/WebCore/platform/graphics/win/Direct2DOperations.cpp

    r250085 r250188  
    290290} // namespace State
    291291
    292 FillSource::FillSource(const GraphicsContextState& state, PlatformContextDirect2D& platformContext)
     292FillSource::FillSource(const GraphicsContextState& state, const GraphicsContext& context)
    293293    : globalAlpha(state.alpha)
    294294    , color(state.fillColor)
    295295    , fillRule(state.fillRule)
    296296{
     297    ASSERT(context.hasPlatformContext());
     298    auto& platformContext = *context.platformContext();
     299
    297300    if (state.fillPattern) {
    298301        AffineTransform userToBaseCTM; // FIXME: This isn't really needed on Windows
    299         brush = state.fillPattern->createPlatformPattern(platformContext, state.alpha, userToBaseCTM);
    300     } else if (state.fillGradient)
     302        brush = state.fillPattern->createPlatformPattern(context, state.alpha, userToBaseCTM);
     303    } else if (state.fillGradient && !state.fillGradient->stops().isEmpty())
    301304        brush = state.fillGradient->createPlatformGradientIfNecessary(platformContext.renderTarget());
    302305    else
     
    304307}
    305308
    306 StrokeSource::StrokeSource(const GraphicsContextState& state, PlatformContextDirect2D& platformContext)
     309StrokeSource::StrokeSource(const GraphicsContextState& state, const GraphicsContext& context)
    307310    : globalAlpha(state.alpha)
    308311    , thickness(state.strokeThickness)
    309312    , color(state.strokeColor)
    310313{
     314    ASSERT(context.hasPlatformContext());
     315    auto& platformContext = *context.platformContext();
     316
    311317    if (state.strokePattern) {
    312318        AffineTransform userToBaseCTM; // FIXME: This isn't really needed on Windows
    313         brush = state.strokePattern->createPlatformPattern(platformContext, state.alpha, userToBaseCTM);
     319        brush = state.strokePattern->createPlatformPattern(context, state.alpha, userToBaseCTM);
    314320    } else if (state.strokeGradient)
    315321        brush = state.strokeGradient->createPlatformGradientIfNecessary(platformContext.renderTarget());
     
    11171123void clip(PlatformContextDirect2D& platformContext, const FloatRect& rect)
    11181124{
    1119     if (platformContext.m_renderStates.isEmpty())
    1120         save(platformContext);
    1121 
    11221125    platformContext.renderTarget()->PushAxisAlignedClip(rect, D2D1_ANTIALIAS_MODE_PER_PRIMITIVE);
    1123     platformContext.m_renderStates.last().m_clips.append(PlatformContextDirect2D::AxisAlignedClip);
     1126    platformContext.pushClip(PlatformContextDirect2D::AxisAlignedClip);
    11241127
    11251128    if (auto* graphicsContextPrivate = platformContext.graphicsContextPrivate())
  • trunk/Source/WebCore/platform/graphics/win/Direct2DOperations.h

    r249335 r250188  
    7575struct FillSource {
    7676    FillSource() = default;
    77     explicit FillSource(const GraphicsContextState&, PlatformContextDirect2D&);
     77    explicit FillSource(const GraphicsContextState&, const GraphicsContext&);
    7878
    7979    float globalAlpha { 0 };
     
    8686struct StrokeSource {
    8787    StrokeSource() = default;
    88     explicit StrokeSource(const GraphicsContextState&, PlatformContextDirect2D&);
     88    explicit StrokeSource(const GraphicsContextState&, const GraphicsContext&);
    8989
    9090    float globalAlpha { 0 };
  • trunk/Source/WebCore/platform/graphics/win/GraphicsContextDirect2D.cpp

    r249921 r250188  
    590590    auto& state = this->state();
    591591    auto& context = *platformContext();
    592     Direct2D::drawPath(context, path, Direct2D::StrokeSource(state, context), Direct2D::ShadowState(state));
     592    Direct2D::drawPath(context, path, Direct2D::StrokeSource(state, *this), Direct2D::ShadowState(state));
    593593}
    594594
     
    606606    auto& state = this->state();
    607607    auto& context = *platformContext();
    608     Direct2D::fillPath(context, path, Direct2D::FillSource(state, context), Direct2D::ShadowState(state));
     608    Direct2D::fillPath(context, path, Direct2D::FillSource(state, *this), Direct2D::ShadowState(state));
    609609}
    610610
     
    622622    auto& state = this->state();
    623623    auto& context = *platformContext();
    624     Direct2D::strokePath(context, path, Direct2D::StrokeSource(state, context), Direct2D::ShadowState(state));
     624    Direct2D::strokePath(context, path, Direct2D::StrokeSource(state, *this), Direct2D::ShadowState(state));
    625625}
    626626
     
    638638    auto& state = this->state();
    639639    auto& context = *platformContext();
    640     Direct2D::fillRect(context, rect, Direct2D::FillSource(state, context), Direct2D::ShadowState(state));
     640    Direct2D::fillRect(context, rect, Direct2D::FillSource(state, *this), Direct2D::ShadowState(state));
    641641}
    642642
     
    682682    auto& state = this->state();
    683683    auto& context = *platformContext();
    684     Direct2D::fillRectWithRoundedHole(context, rect, roundedHoleRect, Direct2D::FillSource(state, context), Direct2D::ShadowState(state));
     684    Direct2D::fillRectWithRoundedHole(context, rect, roundedHoleRect, Direct2D::FillSource(state, *this), Direct2D::ShadowState(state));
    685685}
    686686
     
    862862    auto& state = this->state();
    863863    auto& context = *platformContext();
    864     Direct2D::strokeRect(context, rect, lineWidth, Direct2D::StrokeSource(state, context), Direct2D::ShadowState(state));
     864    Direct2D::strokeRect(context, rect, lineWidth, Direct2D::StrokeSource(state, *this), Direct2D::ShadowState(state));
    865865}
    866866
  • trunk/Source/WebCore/platform/graphics/win/GraphicsContextImplDirect2D.cpp

    r249335 r250188  
    146146{
    147147    auto& state = graphicsContext().state();
    148     Direct2D::fillRect(m_platformContext, rect, Direct2D::FillSource(state, m_platformContext), Direct2D::ShadowState(state));
     148    Direct2D::fillRect(m_platformContext, rect, Direct2D::FillSource(state, graphicsContext()), Direct2D::ShadowState(state));
    149149}
    150150
     
    193193    auto& state = graphicsContext().state();
    194194
    195     Direct2D::FillSource fillSource(state, m_platformContext);
     195    Direct2D::FillSource fillSource(state, graphicsContext());
    196196    fillSource.brush = m_platformContext.brushWithColor(color);
    197197
     
    202202{
    203203    auto& state = graphicsContext().state();
    204     Direct2D::fillPath(m_platformContext, path, Direct2D::FillSource(state, m_platformContext), Direct2D::ShadowState(state));
     204    Direct2D::fillPath(m_platformContext, path, Direct2D::FillSource(state, graphicsContext()), Direct2D::ShadowState(state));
    205205}
    206206
     
    215215{
    216216    auto& state = graphicsContext().state();
    217     Direct2D::strokeRect(m_platformContext, rect, lineWidth, Direct2D::StrokeSource(state, m_platformContext), Direct2D::ShadowState(state));
     217    Direct2D::strokeRect(m_platformContext, rect, lineWidth, Direct2D::StrokeSource(state, graphicsContext()), Direct2D::ShadowState(state));
    218218}
    219219
     
    221221{
    222222    auto& state = graphicsContext().state();
    223     Direct2D::strokePath(m_platformContext, path, Direct2D::StrokeSource(state, m_platformContext), Direct2D::ShadowState(state));
     223    Direct2D::strokePath(m_platformContext, path, Direct2D::StrokeSource(state, graphicsContext()), Direct2D::ShadowState(state));
    224224}
    225225
     
    264264
    265265    auto& state = graphicsContext().state();
    266     Direct2D::drawGlyphs(m_platformContext, Direct2D::FillSource(state, m_platformContext), Direct2D::StrokeSource(state, m_platformContext),
     266    Direct2D::drawGlyphs(m_platformContext, Direct2D::FillSource(state, graphicsContext()), Direct2D::StrokeSource(state, graphicsContext()),
    267267        Direct2D::ShadowState(state), point, font, syntheticBoldOffset, glyphs, horizontalAdvances, glyphOffsets, xOffset,
    268268        state.textDrawingMode, state.strokeThickness, state.shadowOffset, state.shadowColor);
  • trunk/Source/WebCore/platform/graphics/win/ImageBufferDataDirect2D.cpp

    r250085 r250188  
    429429
    430430    if (byteFormat == AlphaPremultiplication::Unpremultiplied)
    431         copyRectFromSourceToDestAndSetPremultiplication<AlphaPremultiplication::Unpremultiplied>(sourceRect, sourceRect.size(), source.data(), backingStoreSize, data.data(), destBufferPosition);
    432     else
    433         copyRectFromSourceToDestAndSetPremultiplication<AlphaPremultiplication::Premultiplied>(sourceRect, sourceRect.size(), source.data(), backingStoreSize, data.data(), destBufferPosition);
     431        return copyRectFromSourceToDestAndSetPremultiplication<AlphaPremultiplication::Unpremultiplied>(sourceRect, sourceRect.size(), source.data(), backingStoreSize, data.data(), destBufferPosition);
     432
     433    return copyRectFromSourceToDestAndSetPremultiplication<AlphaPremultiplication::Premultiplied>(sourceRect, sourceRect.size(), source.data(), backingStoreSize, data.data(), destBufferPosition);
    434434}
    435435
     
    479479        return bitmap;
    480480
    481     if (platformContext->renderTarget() == renderTarget)
    482         return bitmap;
     481    if (platformContext->renderTarget() == renderTarget) {
     482        COMPtr<ID2D1BitmapRenderTarget> bitmapTarget(Query, renderTarget);
     483        if (bitmapTarget) {
     484            COMPtr<ID2D1Bitmap> backingBitmap;
     485            if (SUCCEEDED(bitmapTarget->GetBitmap(&backingBitmap))) {
     486                if (backingBitmap != bitmap)
     487                    return bitmap;
     488
     489                // We can't draw an ID2D1Bitmap to itself. Must return a copy.
     490                COMPtr<ID2D1Bitmap> copiedBitmap;
     491                if (SUCCEEDED(renderTarget->CreateBitmap(bitmap->GetPixelSize(), Direct2D::bitmapProperties(), &copiedBitmap))) {
     492                    if (SUCCEEDED(copiedBitmap->CopyFromBitmap(nullptr, bitmap.get(), nullptr)))
     493                        return copiedBitmap;
     494                }
     495            }
     496        }
     497    }
    483498
    484499    auto size = bitmap->GetPixelSize();
  • trunk/Source/WebCore/platform/graphics/win/PatternDirect2D.cpp

    r249110 r250188  
    4040ID2D1BitmapBrush* Pattern::createPlatformPattern(const GraphicsContext& context, float alpha, const AffineTransform& userSpaceTransformation) const
    4141{
    42     auto platformContext = context.platformContext();
    43     RELEASE_ASSERT(platformContext);
    44 
    45     return createPlatformPattern(*platformContext, alpha, userSpaceTransformation);
    46 }
    47 
    48 ID2D1BitmapBrush* Pattern::createPlatformPattern(PlatformGraphicsContext& context, float alpha, const AffineTransform& userSpaceTransformation) const
    49 {
    5042    AffineTransform patternTransform = userSpaceTransformation * m_patternSpaceTransformation;
    5143    auto bitmapBrushProperties = D2D1::BitmapBrushProperties();
     
    5850
    5951    auto& patternImage = tileImage();
    60     auto nativeImage = patternImage.nativeImage(nullptr);
     52    auto nativeImage = patternImage.nativeImage(&context);
     53    if (!nativeImage)
     54        return nullptr;
     55
     56    auto platformContext = context.platformContext();
     57    RELEASE_ASSERT(platformContext);
    6158
    6259    ID2D1BitmapBrush* patternBrush = nullptr;
    63     HRESULT hr = context.renderTarget()->CreateBitmapBrush(nativeImage.get(), &bitmapBrushProperties, &brushProperties, &patternBrush);
     60    HRESULT hr = platformContext->renderTarget()->CreateBitmapBrush(nativeImage.get(), &bitmapBrushProperties, &brushProperties, &patternBrush);
    6461    ASSERT(SUCCEEDED(hr));
    6562    return patternBrush;
  • trunk/Source/WebCore/platform/graphics/win/PlatformContextDirect2D.cpp

    r250085 r250188  
    3939public:
    4040    State() = default;
     41
     42    COMPtr<ID2D1DrawingStateBlock> m_drawingStateBlock;
     43    COMPtr<ID2D1Layer> m_activeLayer;
     44    Vector<Direct2DLayerType> m_clips;
    4145};
    4246
     
    5054}
    5155
     56ID2D1Layer* PlatformContextDirect2D::clipLayer() const
     57{
     58    return m_state->m_activeLayer.get();
     59}
     60
     61void PlatformContextDirect2D::clearClips(Vector<Direct2DLayerType>& clips)
     62{
     63    for (auto clipType = clips.rbegin(); clipType != clips.rend(); ++clipType) {
     64        if (*clipType == AxisAlignedClip)
     65            m_renderTarget->PopAxisAlignedClip();
     66        else
     67            m_renderTarget->PopLayer();
     68    }
     69
     70    clips.clear();
     71}
     72
    5273void PlatformContextDirect2D::restore()
    5374{
     
    6182        return;
    6283
    63     if (!m_renderStates.isEmpty()) {
    64         auto restoreState = m_renderStates.takeLast();
     84    auto& restoreState = m_stateStack.last();
     85    if (restoreState.m_drawingStateBlock) {
    6586        m_renderTarget->RestoreDrawingState(restoreState.m_drawingStateBlock.get());
    66 
    67         for (auto clipType = restoreState.m_clips.rbegin(); clipType != restoreState.m_clips.rend(); ++clipType) {
    68             if (*clipType == AxisAlignedClip)
    69                 m_renderTarget->PopAxisAlignedClip();
    70             else
    71                 m_renderTarget->PopLayer();
    72         }
    73     }
     87        restoreState.m_drawingStateBlock = nullptr;
     88    }
     89
     90    clearClips(restoreState.m_clips);
    7491
    7592    m_stateStack.removeLast();
     
    88105    m_state = &m_stateStack.last();
    89106
    90     RenderState currentState;
    91     GraphicsContext::systemFactory()->CreateDrawingStateBlock(&currentState.m_drawingStateBlock);
    92 
    93     m_renderTarget->SaveDrawingState(currentState.m_drawingStateBlock.get());
    94 
    95     m_renderStates.append(currentState);
     107    GraphicsContext::systemFactory()->CreateDrawingStateBlock(&m_state->m_drawingStateBlock);
     108
     109    m_renderTarget->SaveDrawingState(m_state->m_drawingStateBlock.get());
    96110}
    97111
     
    99113{
    100114    ASSERT(hasSavedState());
    101     m_renderStates.last().m_clips.append(clipType);
     115    m_state->m_clips.append(clipType);
    102116}
    103117
     
    105119{
    106120    ASSERT(hasSavedState());
    107     m_renderStates.last().m_activeLayer = layer;
     121    m_state->m_activeLayer = layer;
    108122}
    109123
     
    265279    ASSERT(m_renderTarget);
    266280
    267     while (!m_renderStates.isEmpty())
     281    while (m_stateStack.size() > 1)
    268282        restore();
     283
     284    clearClips(m_state->m_clips);
    269285
    270286    ASSERT(m_stateStack.size() >= 1);
     
    299315}
    300316
     317void PlatformContextDirect2D::pushClip(Direct2DLayerType clipType)
     318{
     319    m_state->m_clips.append(clipType);
     320}
     321
    301322} // namespace WebCore
    302323
  • trunk/Source/WebCore/platform/graphics/win/PlatformContextDirect2D.h

    r249921 r250188  
    6262    void setGraphicsContextPrivate(GraphicsContextPlatformPrivate* graphicsContextPrivate) { m_graphicsContextPrivate = graphicsContextPrivate; }
    6363
    64     ID2D1Layer* clipLayer() const { return m_renderStates.last().m_activeLayer.get(); }
     64    ID2D1Layer* clipLayer() const;
    6565    ID2D1StrokeStyle* strokeStyle();
    6666    D2D1_STROKE_STYLE_PROPERTIES strokeStyleProperties() const;
     
    7272    void restore();
    7373
    74     bool hasSavedState() const { return !m_renderStates.isEmpty(); }
     74    bool hasSavedState() const { return !m_stateStack.isEmpty(); }
    7575
    7676    void beginDraw();
     
    8383    void recomputeStrokeStyle();
    8484    float strokeThickness() const { return m_strokeThickness; }
    85 
    86     struct RenderState {
    87         COMPtr<ID2D1DrawingStateBlock> m_drawingStateBlock;
    88         COMPtr<ID2D1Layer> m_activeLayer;
    89         Vector<Direct2DLayerType> m_clips;
    90     };
    91     Vector<RenderState> m_renderStates;
    9285
    9386    struct TransparencyLayerState {
     
    118111    void notifyPostDrawObserver();
    119112
     113    void pushClip(Direct2DLayerType);
     114
    120115private:
     116    void clearClips(Vector<Direct2DLayerType>&);
     117
    121118    GraphicsContextPlatformPrivate* m_graphicsContextPrivate { nullptr };
    122119
Note: See TracChangeset for help on using the changeset viewer.