summaryrefslogtreecommitdiff
path: root/chromium/pdf/document_layout.h
blob: fb028424e55f9f95c5d09a72d358bb0f4290abc2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
// Copyright 2019 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.

#ifndef PDF_DOCUMENT_LAYOUT_H_
#define PDF_DOCUMENT_LAYOUT_H_

#include <cstddef>
#include <vector>

#include "base/check_op.h"
#include "pdf/draw_utils/coordinates.h"
#include "pdf/page_orientation.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size.h"

namespace base {
class Value;
}

namespace chrome_pdf {

// Layout of pages within a PDF document. Pages are placed as rectangles
// (possibly rotated) in a non-overlapping vertical sequence.
//
// All layout units are pixels.
//
// The |Options| class controls the behavior of the layout, such as the default
// orientation of pages.
class DocumentLayout final {
 public:
  // Options controlling layout behavior.
  class Options final {
   public:
    Options();

    Options(const Options& other);
    Options& operator=(const Options& other);

    ~Options();

    friend bool operator==(const Options& lhs, const Options& rhs) {
      return lhs.two_up_view_enabled() == rhs.two_up_view_enabled() &&
             lhs.default_page_orientation() == rhs.default_page_orientation();
    }

    friend bool operator!=(const Options& lhs, const Options& rhs) {
      return !(lhs == rhs);
    }

    // Serializes layout options to a base::Value.
    base::Value ToValue() const;

    // Deserializes layout options from a base::Value.
    void FromValue(const base::Value& value);

    PageOrientation default_page_orientation() const {
      return default_page_orientation_;
    }

    // Rotates default page orientation 90 degrees clockwise.
    void RotatePagesClockwise();

    // Rotates default page orientation 90 degrees counterclockwise.
    void RotatePagesCounterclockwise();

    bool two_up_view_enabled() const { return two_up_view_enabled_; }

    // Changes two-up view status.
    void set_two_up_view_enabled(bool enable) { two_up_view_enabled_ = enable; }

   private:
    PageOrientation default_page_orientation_ = PageOrientation::kOriginal;
    bool two_up_view_enabled_ = false;
  };

  static const draw_utils::PageInsetSizes kSingleViewInsets;
  static constexpr int32_t kBottomSeparator = 4;
  static constexpr int32_t kHorizontalSeparator = 1;

  DocumentLayout();

  DocumentLayout(const DocumentLayout& other) = delete;
  DocumentLayout& operator=(const DocumentLayout& other) = delete;

  ~DocumentLayout();

  // Returns the layout options.
  const Options& options() const { return options_; }

  // Sets the layout options. If certain options with immediate effect change
  // (such as the default page orientation), the layout will be marked dirty.
  //
  // TODO(kmoon): We shouldn't have layout options that take effect immediately.
  void SetOptions(const Options& options);

  // Returns true if the layout has been modified since the last call to
  // clear_dirty(). The initial state is false (clean), which assumes
  // appropriate default behavior for an initially empty layout.
  bool dirty() const { return dirty_; }

  // Clears the dirty() state of the layout. This should be called after any
  // layout changes have been applied.
  void clear_dirty() { dirty_ = false; }

  // Returns the layout's total size.
  const gfx::Size& size() const { return size_; }

  size_t page_count() const { return page_layouts_.size(); }

  // Gets the layout rectangle for a page. Only valid after computing a layout.
  const gfx::Rect& page_rect(size_t page_index) const {
    DCHECK_LT(page_index, page_count());
    return page_layouts_[page_index].outer_rect;
  }

  // Gets the layout rectangle for a page's bounds (which excludes additional
  // regions like page shadows). Only valid after computing a layout.
  const gfx::Rect& page_bounds_rect(size_t page_index) const {
    DCHECK_LT(page_index, page_count());
    return page_layouts_[page_index].inner_rect;
  }

  // Computes layout that represent |page_sizes| formatted for single view.
  //
  // TODO(kmoon): Control layout type using an option.
  void ComputeSingleViewLayout(const std::vector<gfx::Size>& page_sizes);

  // Computes layout that represent |page_sizes| formatted for two-up view.
  //
  // TODO(kmoon): Control layout type using an option.
  void ComputeTwoUpViewLayout(const std::vector<gfx::Size>& page_sizes);

 private:
  // Layout of a single page.
  struct PageLayout {
    // Bounding rectangle for the page with decorations.
    gfx::Rect outer_rect;

    // Bounding rectangle for the page without decorations.
    gfx::Rect inner_rect;
  };

  // Copies |source_rect| to |destination_rect|, setting |dirty_| to true if
  // |destination_rect| is modified as a result.
  void CopyRectIfModified(const gfx::Rect& source_rect,
                          gfx::Rect& destination_rect);

  Options options_;

  // Indicates if the layout has changed in an externally-observable way,
  // usually as a result of calling |ComputeLayout()| with different inputs.
  //
  // Some operations that may trigger layout changes:
  // * Changing page sizes
  // * Adding or removing pages
  // * Changing page orientations
  bool dirty_ = false;

  // Layout's total size.
  gfx::Size size_;

  std::vector<PageLayout> page_layouts_;
};

}  // namespace chrome_pdf

#endif  // PDF_DOCUMENT_LAYOUT_H_