gfx/skia/trunk/src/views/SkStackViewLayout.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/gfx/skia/trunk/src/views/SkStackViewLayout.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,273 @@
     1.4 +
     1.5 +/*
     1.6 + * Copyright 2011 Google Inc.
     1.7 + *
     1.8 + * Use of this source code is governed by a BSD-style license that can be
     1.9 + * found in the LICENSE file.
    1.10 + */
    1.11 +#include "SkStackViewLayout.h"
    1.12 +
    1.13 +SkStackViewLayout::SkStackViewLayout()
    1.14 +{
    1.15 +    fMargin.set(0, 0, 0, 0);
    1.16 +    fSpacer    = 0;
    1.17 +    fOrient    = kHorizontal_Orient;
    1.18 +    fPack    = kStart_Pack;
    1.19 +    fAlign    = kStart_Align;
    1.20 +    fRound    = false;
    1.21 +}
    1.22 +
    1.23 +void SkStackViewLayout::setOrient(Orient ori)
    1.24 +{
    1.25 +    SkASSERT((unsigned)ori < kOrientCount);
    1.26 +    fOrient = SkToU8(ori);
    1.27 +}
    1.28 +
    1.29 +void SkStackViewLayout::getMargin(SkRect* margin) const
    1.30 +{
    1.31 +    if (margin)
    1.32 +        *margin = fMargin;
    1.33 +}
    1.34 +
    1.35 +void SkStackViewLayout::setMargin(const SkRect& margin)
    1.36 +{
    1.37 +    fMargin = margin;
    1.38 +}
    1.39 +
    1.40 +void SkStackViewLayout::setSpacer(SkScalar spacer)
    1.41 +{
    1.42 +    fSpacer = spacer;
    1.43 +}
    1.44 +
    1.45 +void SkStackViewLayout::setPack(Pack pack)
    1.46 +{
    1.47 +    SkASSERT((unsigned)pack < kPackCount);
    1.48 +    fPack = SkToU8(pack);
    1.49 +}
    1.50 +
    1.51 +void SkStackViewLayout::setAlign(Align align)
    1.52 +{
    1.53 +    SkASSERT((unsigned)align < kAlignCount);
    1.54 +    fAlign = SkToU8(align);
    1.55 +}
    1.56 +
    1.57 +void SkStackViewLayout::setRound(bool r)
    1.58 +{
    1.59 +    fRound = SkToU8(r);
    1.60 +}
    1.61 +
    1.62 +////////////////////////////////////////////////////////////////////////////////
    1.63 +
    1.64 +typedef SkScalar (*AlignProc)(SkScalar childLimit, SkScalar parentLimit);
    1.65 +typedef SkScalar (SkView::*GetSizeProc)() const;
    1.66 +typedef void (SkView::*SetLocProc)(SkScalar coord);
    1.67 +typedef void (SkView::*SetSizeProc)(SkScalar coord);
    1.68 +
    1.69 +static SkScalar left_align_proc(SkScalar childLimit, SkScalar parentLimit) { return 0; }
    1.70 +static SkScalar center_align_proc(SkScalar childLimit, SkScalar parentLimit) { return SkScalarHalf(parentLimit - childLimit); }
    1.71 +static SkScalar right_align_proc(SkScalar childLimit, SkScalar parentLimit) { return parentLimit - childLimit; }
    1.72 +static SkScalar fill_align_proc(SkScalar childLimit, SkScalar parentLimit) { return 0; }
    1.73 +
    1.74 +/*    Measure the main-dimension for all the children. If a child is marked flex in that direction
    1.75 +    ignore its current value but increment the counter for flexChildren
    1.76 +*/
    1.77 +static SkScalar compute_children_limit(SkView* parent, GetSizeProc sizeProc, int* count,
    1.78 +                                       uint32_t flexMask, int* flexCount)
    1.79 +{
    1.80 +    SkView::B2FIter    iter(parent);
    1.81 +    SkView*            child;
    1.82 +    SkScalar        limit = 0;
    1.83 +    int                n = 0, flex = 0;
    1.84 +
    1.85 +    while ((child = iter.next()) != NULL)
    1.86 +    {
    1.87 +        n += 1;
    1.88 +        if (child->getFlags() & flexMask)
    1.89 +            flex += 1;
    1.90 +        else
    1.91 +            limit += (child->*sizeProc)();
    1.92 +    }
    1.93 +    if (count)
    1.94 +        *count = n;
    1.95 +    if (flexCount)
    1.96 +        *flexCount = flex;
    1.97 +    return limit;
    1.98 +}
    1.99 +
   1.100 +void SkStackViewLayout::onLayoutChildren(SkView* parent)
   1.101 +{
   1.102 +    static AlignProc gAlignProcs[] = {
   1.103 +        left_align_proc,
   1.104 +        center_align_proc,
   1.105 +        right_align_proc,
   1.106 +        fill_align_proc
   1.107 +    };
   1.108 +
   1.109 +    SkScalar            startM, endM, crossStartM, crossLimit;
   1.110 +    GetSizeProc            mainGetSizeP, crossGetSizeP;
   1.111 +    SetLocProc            mainLocP, crossLocP;
   1.112 +    SetSizeProc            mainSetSizeP, crossSetSizeP;
   1.113 +    SkView::Flag_Mask    flexMask;
   1.114 +
   1.115 +    if (fOrient == kHorizontal_Orient)
   1.116 +    {
   1.117 +        startM        = fMargin.fLeft;
   1.118 +        endM        = fMargin.fRight;
   1.119 +        crossStartM    = fMargin.fTop;
   1.120 +        crossLimit    = -fMargin.fTop - fMargin.fBottom;
   1.121 +
   1.122 +        mainGetSizeP    = &SkView::width;
   1.123 +        crossGetSizeP    = &SkView::height;
   1.124 +        mainLocP    = &SkView::setLocX;
   1.125 +        crossLocP    = &SkView::setLocY;
   1.126 +
   1.127 +        mainSetSizeP  = &SkView::setWidth;
   1.128 +        crossSetSizeP = &SkView::setHeight;
   1.129 +
   1.130 +        flexMask    = SkView::kFlexH_Mask;
   1.131 +    }
   1.132 +    else
   1.133 +    {
   1.134 +        startM        = fMargin.fTop;
   1.135 +        endM        = fMargin.fBottom;
   1.136 +        crossStartM    = fMargin.fLeft;
   1.137 +        crossLimit    = -fMargin.fLeft - fMargin.fRight;
   1.138 +
   1.139 +        mainGetSizeP    = &SkView::height;
   1.140 +        crossGetSizeP    = &SkView::width;
   1.141 +        mainLocP    = &SkView::setLocY;
   1.142 +        crossLocP    = &SkView::setLocX;
   1.143 +
   1.144 +        mainSetSizeP  = &SkView::setHeight;
   1.145 +        crossSetSizeP = &SkView::setWidth;
   1.146 +
   1.147 +        flexMask    = SkView::kFlexV_Mask;
   1.148 +    }
   1.149 +    crossLimit += (parent->*crossGetSizeP)();
   1.150 +    if (fAlign != kStretch_Align)
   1.151 +        crossSetSizeP = NULL;
   1.152 +
   1.153 +    int            childCount, flexCount;
   1.154 +    SkScalar    childLimit = compute_children_limit(parent, mainGetSizeP, &childCount, flexMask, &flexCount);
   1.155 +
   1.156 +    if (childCount == 0)
   1.157 +        return;
   1.158 +
   1.159 +    childLimit += (childCount - 1) * fSpacer;
   1.160 +
   1.161 +    SkScalar        parentLimit = (parent->*mainGetSizeP)() - startM - endM;
   1.162 +    SkScalar        pos = startM + gAlignProcs[fPack](childLimit, parentLimit);
   1.163 +    SkScalar        flexAmount = 0;
   1.164 +    SkView::B2FIter    iter(parent);
   1.165 +    SkView*            child;
   1.166 +
   1.167 +    if (flexCount > 0 && parentLimit > childLimit)
   1.168 +        flexAmount = (parentLimit - childLimit) / flexCount;
   1.169 +
   1.170 +    while ((child = iter.next()) != NULL)
   1.171 +    {
   1.172 +        if (fRound)
   1.173 +            pos = SkScalarRoundToScalar(pos);
   1.174 +        (child->*mainLocP)(pos);
   1.175 +        SkScalar crossLoc = crossStartM + gAlignProcs[fAlign]((child->*crossGetSizeP)(), crossLimit);
   1.176 +        if (fRound)
   1.177 +            crossLoc = SkScalarRoundToScalar(crossLoc);
   1.178 +        (child->*crossLocP)(crossLoc);
   1.179 +
   1.180 +        if (crossSetSizeP)
   1.181 +            (child->*crossSetSizeP)(crossLimit);
   1.182 +        if (child->getFlags() & flexMask)
   1.183 +            (child->*mainSetSizeP)(flexAmount);
   1.184 +        pos += (child->*mainGetSizeP)() + fSpacer;
   1.185 +    }
   1.186 +}
   1.187 +
   1.188 +//////////////////////////////////////////////////////////////////////////////////////
   1.189 +
   1.190 +#ifdef SK_DEBUG
   1.191 +    static void assert_no_attr(const SkDOM& dom, const SkDOM::Node* node, const char attr[])
   1.192 +    {
   1.193 +        const char* value = dom.findAttr(node, attr);
   1.194 +        if (value)
   1.195 +            SkDebugf("unknown attribute %s=\"%s\"\n", attr, value);
   1.196 +    }
   1.197 +#else
   1.198 +    #define assert_no_attr(dom, node, attr)
   1.199 +#endif
   1.200 +
   1.201 +void SkStackViewLayout::onInflate(const SkDOM& dom, const SkDOM::Node* node)
   1.202 +{
   1.203 +    int            index;
   1.204 +    SkScalar    value[4];
   1.205 +
   1.206 +    if ((index = dom.findList(node, "orient", "horizontal,vertical")) >= 0)
   1.207 +        this->setOrient((Orient)index);
   1.208 +    else {
   1.209 +        assert_no_attr(dom, node, "orient");
   1.210 +        }
   1.211 +
   1.212 +    if (dom.findScalars(node, "margin", value, 4))
   1.213 +    {
   1.214 +        SkRect    margin;
   1.215 +        margin.set(value[0], value[1], value[2], value[3]);
   1.216 +        this->setMargin(margin);
   1.217 +    }
   1.218 +    else {
   1.219 +        assert_no_attr(dom, node, "margin");
   1.220 +        }
   1.221 +
   1.222 +    if (dom.findScalar(node, "spacer", value))
   1.223 +        this->setSpacer(value[0]);
   1.224 +    else {
   1.225 +        assert_no_attr(dom, node, "spacer");
   1.226 +        }
   1.227 +
   1.228 +    if ((index = dom.findList(node, "pack", "start,center,end")) >= 0)
   1.229 +        this->setPack((Pack)index);
   1.230 +    else {
   1.231 +        assert_no_attr(dom, node, "pack");
   1.232 +        }
   1.233 +
   1.234 +    if ((index = dom.findList(node, "align", "start,center,end,stretch")) >= 0)
   1.235 +        this->setAlign((Align)index);
   1.236 +    else {
   1.237 +        assert_no_attr(dom, node, "align");
   1.238 +        }
   1.239 +}
   1.240 +
   1.241 +///////////////////////////////////////////////////////////////////////////////////////////
   1.242 +
   1.243 +SkFillViewLayout::SkFillViewLayout()
   1.244 +{
   1.245 +    fMargin.setEmpty();
   1.246 +}
   1.247 +
   1.248 +void SkFillViewLayout::getMargin(SkRect* r) const
   1.249 +{
   1.250 +    if (r)
   1.251 +        *r = fMargin;
   1.252 +}
   1.253 +
   1.254 +void SkFillViewLayout::setMargin(const SkRect& margin)
   1.255 +{
   1.256 +    fMargin = margin;
   1.257 +}
   1.258 +
   1.259 +void SkFillViewLayout::onLayoutChildren(SkView* parent)
   1.260 +{
   1.261 +    SkView::B2FIter    iter(parent);
   1.262 +    SkView*            child;
   1.263 +
   1.264 +    while ((child = iter.next()) != NULL)
   1.265 +    {
   1.266 +        child->setLoc(fMargin.fLeft, fMargin.fTop);
   1.267 +        child->setSize(    parent->width() - fMargin.fRight - fMargin.fLeft,
   1.268 +                        parent->height() - fMargin.fBottom - fMargin.fTop);
   1.269 +    }
   1.270 +}
   1.271 +
   1.272 +void SkFillViewLayout::onInflate(const SkDOM& dom, const SkDOM::Node* node)
   1.273 +{
   1.274 +    this->INHERITED::onInflate(dom, node);
   1.275 +    (void)dom.findScalars(node, "margin", (SkScalar*)&fMargin, 4);
   1.276 +}

mercurial