summaryrefslogtreecommitdiffstats
path: root/layout/generic/nsILineIterator.h
blob: 743eaaffaebd0d2809ecbbe8d078f290f5b14387 (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
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef nsILineIterator_h___
#define nsILineIterator_h___

#include "nscore.h"
#include "nsINode.h"
#include "nsRect.h"
#include "mozilla/Attributes.h"
#include "mozilla/Result.h"
#include "mozilla/WritingModes.h"

class nsIFrame;

/**
 * Line iterator API.
 *
 * Lines are numbered from 0 to N, where 0 is the top line and N is
 * the bottom line.
 *
 * Obtain this interface from frames via nsIFrame::GetLineIterator.
 * This iterator belongs to the frame from which it was obtained, and should
 * not be deleted by the caller.
 * Note that any modification of the frame will invalidate the iterator!
 * Users must get a new iterator any time the target may have been touched.
 */
class nsILineIterator {
 protected:
  ~nsILineIterator() = default;

 public:
  /**
   * The number of lines in the block
   */
  virtual int32_t GetNumLines() const = 0;

  /**
   * Returns whether our lines are rtl.
   */
  virtual bool IsLineIteratorFlowRTL() = 0;

  struct LineInfo {
    /** The first frame on the line. */
    nsIFrame* mFirstFrameOnLine = nullptr;
    /** The numbers of frames on the line. */
    int32_t mNumFramesOnLine = 0;
    /**
     * The bounding box of the line (which is based on the in-flow position of
     * the frames on the line; if a frame was moved because of relative
     * positioning then its coordinates may be outside the line bounds)
     */
    nsRect mLineBounds;
    /** Whether the line is wrapped at the end */
    bool mIsWrapped = false;

    /**
     * Return last frame of the line if there is no enough siblings of
     * mFirstFrameOnLine.
     * Otherwise, nullptr including in the unexpected error cases.
     */
    nsIFrame* GetLastFrameOnLine() const;
  };

  // Return miscellaneous information about a line.
  virtual mozilla::Result<LineInfo, nsresult> GetLine(int32_t aLineNumber) = 0;

  /**
   * Given a frame that's a child of the block, find which line its on
   * and return that line index, as long as it's at least as big as
   * aStartLine.  Returns -1 if the frame cannot be found on lines
   * starting with aStartLine.
   */
  virtual int32_t FindLineContaining(nsIFrame* aFrame,
                                     int32_t aStartLine = 0) = 0;

  // Given a line number and a coordinate, find the frame on the line
  // that is nearest to aPos along the inline axis. (The block-axis coord
  // of aPos is irrelevant.)
  // The aPosIsBeforeFirstFrame and aPosIsAfterLastFrame flags are updated
  // appropriately.
  NS_IMETHOD FindFrameAt(int32_t aLineNumber, nsPoint aPos,
                         nsIFrame** aFrameFound, bool* aPosIsBeforeFirstFrame,
                         bool* aPosIsAfterLastFrame) = 0;

  // Check whether visual and logical order of frames within a line are
  // identical.
  //  If not, return the first and last visual frames
  NS_IMETHOD CheckLineOrder(int32_t aLine, bool* aIsReordered,
                            nsIFrame** aFirstVisual,
                            nsIFrame** aLastVisual) = 0;
};

namespace mozilla {

// Helper struct for FindFrameAt.
struct LineFrameFinder {
  LineFrameFinder(const nsPoint& aPos, const nsSize& aContainerSize,
                  WritingMode aWM, bool aIsReversed)
      : mPos(aWM, aPos, aContainerSize),
        mContainerSize(aContainerSize),
        mWM(aWM),
        mIsReversed(aIsReversed) {}

  void Scan(nsIFrame*);
  void Finish(nsIFrame**, bool* aPosIsBeforeFirstFrame,
              bool* aPosIsAfterLastFrame);

  const LogicalPoint mPos;
  const nsSize mContainerSize;
  const WritingMode mWM;
  const bool mIsReversed;

  bool IsDone() const { return mDone; }

 private:
  bool mDone = false;
  nsIFrame* mFirstFrame = nullptr;
  nsIFrame* mClosestFromStart = nullptr;
  nsIFrame* mClosestFromEnd = nullptr;
};

}  // namespace mozilla

/**
 * Helper intended to be used in a scope where we're using an nsILineIterator
 * and want to verify that no DOM mutations (which would invalidate the
 * iterator) occur while we're using it.
 */
class MOZ_STACK_CLASS AutoAssertNoDomMutations final {
#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
  nsMutationGuard mGuard;
#endif
 public:
  ~AutoAssertNoDomMutations() { MOZ_DIAGNOSTIC_ASSERT(!mGuard.Mutated(0)); }
};

#endif /* nsILineIterator_h___ */