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 +}