| Index: ui/views/layout/align_layout.cc | 
| diff --git a/ui/views/layout/align_layout.cc b/ui/views/layout/align_layout.cc | 
| new file mode 100644 | 
| index 0000000000000000000000000000000000000000..917207f2d4f69f5f30fe64ca5358e2f322519f4e | 
| --- /dev/null | 
| +++ b/ui/views/layout/align_layout.cc | 
| @@ -0,0 +1,197 @@ | 
| +// Copyright (c) 2011 The Chromium Authors. All rights reserved. | 
| +// Use of this source code is governed by a BSD-style license that can be | 
| +// found in the LICENSE file. | 
| + | 
| +#include "ui/views/layout/align_layout.h" | 
| + | 
| +#include "base/logging.h" | 
| +#include "ui/views/anchor_attribute.h" | 
| + | 
| +namespace views { | 
| + | 
| +// This special value represents the absence of the align attribute. | 
| +static constexpr Fill Fill_None = | 
| +    static_cast<Fill>(static_cast<int>(Fill::Content) + 1); | 
| + | 
| +AlignLayout::AlignLayout() {} | 
| + | 
| +AlignLayout::~AlignLayout() {} | 
| + | 
| +void AlignLayout::AlignViews(View* host, | 
| +                             views::Fill fill, | 
| +                             gfx::Rect& contents) { | 
| +  View::Views fill_list; | 
| +  for (int i = 0; i < host->child_count(); ++i) { | 
| +    FillAttribute* fill_attr; | 
| +    View* child = host->child_at(i); | 
| +    if (child->visible() && child->attributes().Find(fill_attr) | 
| +            ? fill_attr->fill() == fill | 
| +            : fill == Fill_None) { | 
| +      View::Views::iterator j = fill_list.begin(); | 
| +      while (j < fill_list.end() && !ShouldInsert(child, *j, fill)) | 
| +        j++; | 
| +      fill_list.insert(j, child); | 
| +    } | 
| +  } | 
| +  for (View* child : fill_list) | 
| +    PlaceView(child, fill, contents); | 
| +} | 
| + | 
| +void AlignLayout::Layout(View* host) { | 
| +  static const Fill fillstyles[] = { | 
| +      views::Fill::Top,   views::Fill::Bottom,  views::Fill::Left, | 
| +      views::Fill::Right, views::Fill::Content, Fill_None}; | 
| +  if (ShouldAlign(host)) { | 
| +    gfx::Rect contents = host->GetContentsBounds(); | 
| +    for (std::size_t i = 0; i < sizeof(fillstyles) / sizeof(fillstyles[0]); i++) | 
| +      AlignViews(host, fillstyles[i], contents); | 
| +  } | 
| +} | 
| + | 
| +gfx::Size AlignLayout::GetPreferredSize(const View* host) const { | 
| +  return gfx::Size(); | 
| +} | 
| + | 
| +int AlignLayout::GetPreferredHeightForWidth(const View* host, int width) const { | 
| +  return 0; | 
| +} | 
| + | 
| +static int MulDiv(int Number, int Numerator, int Denominator) { | 
| +  return static_cast<int>((static_cast<int64_t>(Number) * Numerator) / | 
| +                          Denominator); | 
| +} | 
| + | 
| +void AlignLayout::PlaceView(View* view, | 
| +                            views::Fill fill, | 
| +                            gfx::Rect& contents) { | 
| +  AnchorAttribute* anchor = nullptr; | 
| +  AnchorContent local_content; | 
| +  AnchorContent& content = | 
| +      view->attributes().Find(anchor) ? anchor->GetContent() : local_content; | 
| +  if (fill == Fill_None || | 
| +      content.anchors() != AnchorContent::AnchorFill(fill)) { | 
| +    if (!content.LastParentSize().IsEmpty()) { | 
| +      int new_left = view->x(); | 
| +      int new_top = view->y(); | 
| +      int new_width = view->width(); | 
| +      int new_height = view->height(); | 
| +      Anchors anchors = content.anchors(); | 
| +      gfx::Size parent_size = view->parent()->GetContentsBounds().size(); | 
| +      if (anchors.Contains(Anchor::Right)) | 
| +        if (anchors.Contains(Anchor::Left)) | 
| +          new_width = parent_size.width() - (content.LastParentSize().width() - | 
| +                                             content.anchorBasis().x()); | 
| +        else | 
| +          new_left = parent_size.width() - (content.LastParentSize().width() - | 
| +                                            content.anchorBasis().x()); | 
| +      else if (!anchors.Contains(Anchor::Left)) | 
| +        new_left = MulDiv(content.anchorBasis().x(), parent_size.width(), | 
| +                          content.LastParentSize().width()) - | 
| +                   new_width / 2; | 
| +      if (anchors.Contains(Anchor::Bottom)) | 
| +        if (anchors.Contains(Anchor::Top)) | 
| +          new_height = | 
| +              parent_size.height() - | 
| +              (content.LastParentSize().height() - content.anchorBasis().y()); | 
| +        else | 
| +          new_top = parent_size.height() - (content.LastParentSize().height() - | 
| +                                            content.anchorBasis().y()); | 
| +      else if (!anchors.Contains(Anchor::Top)) | 
| +        new_top = MulDiv(content.anchorBasis().y(), parent_size.height(), | 
| +                         content.LastParentSize().height()) - | 
| +                  new_height / 2; | 
| +      view->SetBounds(new_left, new_top, new_width, new_height); | 
| +    } | 
| +    if (fill == Fill_None) | 
| +      return; | 
| +  } | 
| +  int new_width = contents.size().width(); | 
| +  if (new_width < 0 || fill == views::Fill::Left || | 
| +      fill == views::Fill::Right) | 
| +    new_width = view->width(); | 
| +  int new_height = contents.size().height(); | 
| +  if (new_height < 0 || fill == views::Fill::Top || | 
| +      fill == views::Fill::Bottom) | 
| +    new_height = view->height(); | 
| +  int new_left = contents.x(); | 
| +  int new_top = contents.y(); | 
| +  switch (fill) { | 
| +    case views::Fill::Top: { | 
| +      contents.Inset(0, new_height, 0, 0); | 
| +      break; | 
| +    } | 
| +    case views::Fill::Bottom: { | 
| +      contents.Inset(0, 0, 0, new_height); | 
| +      new_top = contents.bottom(); | 
| +      break; | 
| +    } | 
| +    case views::Fill::Left: { | 
| +      contents.Inset(new_width, 0, 0, 0); | 
| +      break; | 
| +    } | 
| +    case views::Fill::Right: { | 
| +      contents.Inset(0, 0, new_width, 0); | 
| +      new_left = contents.right(); | 
| +      // Fall through | 
| +    } | 
| +    default: | 
| +      break; | 
| +  } | 
| +  view->SetBounds(new_left, new_top, new_width, new_height); | 
| +  // If the view's bounds are constrained in some other manner, this | 
| +  // will ensure the content rect is adjusted based on the actual | 
| +  // size of the view. | 
| +  if (view->width() != new_width || view->height() != new_height) { | 
| +    switch (fill) { | 
| +      case views::Fill::Top: { | 
| +        contents.set_y(contents.y() - (new_height - view->height())); | 
| +        break; | 
| +      } | 
| +      case views::Fill::Bottom: { | 
| +        contents.set_height(contents.height() + (new_height - view->height())); | 
| +        break; | 
| +      } | 
| +      case views::Fill::Left: { | 
| +        contents.set_x(contents.x() - (new_width - view->width())); | 
| +        break; | 
| +      } | 
| +      case views::Fill::Right: { | 
| +        contents.set_width(contents.width() + (new_width - view->width())); | 
| +        break; | 
| +      } | 
| +      case views::Fill::Content: { | 
| +        contents.set_width(contents.width() + (new_width - view->width())); | 
| +        contents.set_height(contents.height() + (new_height - view->width())); | 
| +      } | 
| +    } | 
| +  } | 
| +} | 
| + | 
| +bool AlignLayout::ShouldAlign(View* host) { | 
| +  for (int i = 0; i < host->child_count(); ++i) { | 
| +    FillAttribute* fill_attr; | 
| +    AnchorAttribute* anchor_attr; | 
| +    View* view = host->child_at(i); | 
| +    if (view->visible() && (view->attributes().Find(fill_attr) || | 
| +                            view->attributes().Find(anchor_attr))) | 
| +      return true; | 
| +  } | 
| +  return false; | 
| +} | 
| + | 
| +bool AlignLayout::ShouldInsert(View* child1, View* child2, views::Fill fill) { | 
| +  switch (fill) { | 
| +    case views::Fill::Top: | 
| +      return child1->y() < child2->y(); | 
| +    case views::Fill::Bottom: | 
| +      return child1->bounds().bottom() >= child2->bounds().bottom(); | 
| +    case views::Fill::Left: | 
| +      return child1->x() < child2->x(); | 
| +    case views::Fill::Right: | 
| +      return child1->bounds().right() >= child2->bounds().right(); | 
| +    default: | 
| +      return false; | 
| +  } | 
| +} | 
| + | 
| +}  // namespace views | 
|  |