910e62b5创建于 1月15日历史提交
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "pdf/draw_utils/coordinates.h"

#include <math.h>
#include <algorithm>

#include "base/check_op.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/geometry/size_f.h"

namespace chrome_pdf {
namespace draw_utils {

IndexedPage::IndexedPage(int index, const gfx::Rect& rect)
    : index(index), rect(rect) {}

IndexedPage::IndexedPage(const IndexedPage& other) = default;

IndexedPage& IndexedPage::operator=(const IndexedPage& other) = default;

IndexedPage::~IndexedPage() = default;

void AdjustBottomGapForRightSidePage(int page_x, gfx::Rect* bottom_gap) {
  bottom_gap->set_x(page_x);
  bottom_gap->set_width(bottom_gap->width() / 2);
}

void CenterRectHorizontally(int doc_width, gfx::Rect* rect) {
  DCHECK_GE(doc_width, rect->width());

  rect->set_x((doc_width - rect->width()) / 2);
}

void ExpandDocumentSize(const gfx::Size& rect_size, gfx::Size* doc_size) {
  int width_diff = std::max(0, rect_size.width() - doc_size->width());
  doc_size->Enlarge(width_diff, rect_size.height());
}

gfx::Rect GetBottomGapBetweenRects(int page_rect_bottom,
                                   const gfx::Rect& bottom_rect) {
  if (page_rect_bottom >= bottom_rect.bottom())
    return gfx::Rect(0, 0, 0, 0);

  return gfx::Rect(bottom_rect.x(), page_rect_bottom, bottom_rect.width(),
                   bottom_rect.bottom() - page_rect_bottom);
}

int GetMostVisiblePage(const std::vector<IndexedPage>& visible_pages,
                       const gfx::Rect& visible_screen) {
  if (visible_pages.empty())
    return -1;

  int most_visible_page_index = visible_pages.front().index;
  float most_visible_page_area = 0;
  for (const auto& visible_page : visible_pages) {
    float page_area = gfx::SizeF(visible_page.rect.size()).GetArea();
    // TODO(thestig): Check whether we can remove this check.
    if (page_area <= 0)
      continue;

    gfx::Rect screen_intersect =
        gfx::IntersectRects(visible_screen, visible_page.rect);
    float intersect_area =
        gfx::SizeF(screen_intersect.size()).GetArea() / page_area;
    if (intersect_area > most_visible_page_area) {
      most_visible_page_index = visible_page.index;
      most_visible_page_area = intersect_area;
    }
  }

  return most_visible_page_index;
}

gfx::Insets GetPageInsetsForTwoUpView(size_t page_index,
                                      size_t num_of_pages,
                                      const gfx::Insets& single_view_insets,
                                      int horizontal_separator) {
  DCHECK_LT(page_index, num_of_pages);

  // Don't change `two_up_insets` if the page is on the left side and is the
  // last page. In this case, the shadows on both sides should be the same size.
  gfx::Insets two_up_insets = single_view_insets;
  if (page_index % 2 == 1) {
    two_up_insets.set_left(horizontal_separator);
  } else if (page_index != num_of_pages - 1) {
    two_up_insets.set_right(horizontal_separator);
  }

  return two_up_insets;
}

gfx::Rect GetRectForSingleView(const gfx::Size& rect_size,
                               const gfx::Size& document_size) {
  gfx::Rect page_rect({0, document_size.height()}, rect_size);
  CenterRectHorizontally(document_size.width(), &page_rect);
  return page_rect;
}

gfx::Rect GetScreenRect(const gfx::Rect& rect,
                        const gfx::Point& position,
                        double zoom) {
  DCHECK_GT(zoom, 0);

  int x = static_cast<int>(rect.x() * zoom - position.x());
  int y = static_cast<int>(rect.y() * zoom - position.y());
  int right = static_cast<int>(ceil(rect.right() * zoom - position.x()));
  int bottom = static_cast<int>(ceil(rect.bottom() * zoom - position.y()));
  return gfx::Rect(x, y, right - x, bottom - y);
}

gfx::Rect GetSurroundingRect(int page_y,
                             int page_height,
                             const gfx::Insets& insets,
                             int doc_width,
                             int bottom_separator) {
  return gfx::Rect(
      0, page_y - insets.top(), doc_width,
      page_height + insets.top() + insets.bottom() + bottom_separator);
}

gfx::Rect GetLeftFillRect(const gfx::Rect& page_rect,
                          const gfx::Insets& insets,
                          int bottom_separator) {
  DCHECK_GE(page_rect.x(), insets.left());

  return gfx::Rect(
      0, page_rect.y() - insets.top(), page_rect.x() - insets.left(),
      page_rect.height() + insets.top() + insets.bottom() + bottom_separator);
}

gfx::Rect GetRightFillRect(const gfx::Rect& page_rect,
                           const gfx::Insets& insets,
                           int doc_width,
                           int bottom_separator) {
  int right_gap_x = page_rect.right() + insets.right();
  DCHECK_GE(doc_width, right_gap_x);

  return gfx::Rect(
      right_gap_x, page_rect.y() - insets.top(), doc_width - right_gap_x,
      page_rect.height() + insets.top() + insets.bottom() + bottom_separator);
}

gfx::Rect GetBottomFillRect(const gfx::Rect& page_rect,
                            const gfx::Insets& insets,
                            int bottom_separator) {
  return gfx::Rect(
      page_rect.x() - insets.left(), page_rect.bottom() + insets.bottom(),
      page_rect.width() + insets.left() + insets.right(), bottom_separator);
}

gfx::Rect GetLeftRectForTwoUpView(const gfx::Size& rect_size,
                                  const gfx::Point& position) {
  DCHECK_LE(rect_size.width(), position.x());

  return gfx::Rect(position.x() - rect_size.width(), position.y(),
                   rect_size.width(), rect_size.height());
}

gfx::Rect GetRightRectForTwoUpView(const gfx::Size& rect_size,
                                   const gfx::Point& position) {
  return gfx::Rect(position, rect_size);
}

}  // namespace draw_utils
}  // namespace chrome_pdf