PageRangeUtils.java revision a798c0a984f29f7180883a61839f68d2cbf0c6ce
1/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.printspooler.util;
18
19import android.print.PageRange;
20
21import java.util.Arrays;
22import java.util.Comparator;
23
24/**
25 * This class contains utility functions for working with page ranges.
26 */
27public final class PageRangeUtils {
28
29    private static final PageRange[] ALL_PAGES_RANGE = new PageRange[] {PageRange.ALL_PAGES};
30
31    private static final Comparator<PageRange> sComparator = new Comparator<PageRange>() {
32        @Override
33        public int compare(PageRange lhs, PageRange rhs) {
34            return lhs.getStart() - rhs.getStart();
35        }
36    };
37
38    private PageRangeUtils() {
39        /* do nothing - hide constructor */
40    }
41
42    /**
43     * Checks whether one page range array contains another one.
44     *
45     * @param ourRanges The container page ranges.
46     * @param otherRanges The contained page ranges.
47     * @return Whether the container page ranges contains the contained ones.
48     */
49    public static boolean contains(PageRange[] ourRanges, PageRange[] otherRanges) {
50        if (ourRanges == null || otherRanges == null) {
51            return false;
52        }
53
54        if (Arrays.equals(ourRanges, ALL_PAGES_RANGE)) {
55            return true;
56        }
57
58        ourRanges = normalize(ourRanges);
59        otherRanges = normalize(otherRanges);
60
61        // Note that the code below relies on the ranges being normalized
62        // which is they contain monotonically increasing non-intersecting
63        // sub-ranges whose start is less that or equal to the end.
64        int otherRangeIdx = 0;
65        final int ourRangeCount = ourRanges.length;
66        final int otherRangeCount = otherRanges.length;
67        for (int ourRangeIdx = 0; ourRangeIdx < ourRangeCount; ourRangeIdx++) {
68            PageRange ourRange = ourRanges[ourRangeIdx];
69            for (; otherRangeIdx < otherRangeCount; otherRangeIdx++) {
70                PageRange otherRange = otherRanges[otherRangeIdx];
71                if (otherRange.getStart() > ourRange.getEnd()) {
72                    break;
73                }
74                if (otherRange.getStart() < ourRange.getStart()
75                        || otherRange.getEnd() > ourRange.getEnd()) {
76                    return false;
77                }
78            }
79        }
80        if (otherRangeIdx < otherRangeCount) {
81            return false;
82        }
83        return true;
84    }
85
86    /**
87     * Normalizes a page range, which is the resulting page ranges are
88     * non-overlapping with the start lesser than or equal to the end
89     * and ordered in an ascending order.
90     *
91     * @param pageRanges The page ranges to normalize.
92     * @return The normalized page ranges.
93     */
94    public static PageRange[] normalize(PageRange[] pageRanges) {
95        if (pageRanges == null) {
96            return null;
97        }
98        final int oldRangeCount = pageRanges.length;
99        if (oldRangeCount <= 1) {
100            return pageRanges;
101        }
102        Arrays.sort(pageRanges, sComparator);
103        int newRangeCount = 1;
104        for (int i = 0; i < oldRangeCount - 1; i++) {
105            newRangeCount++;
106            PageRange currentRange = pageRanges[i];
107            PageRange nextRange = pageRanges[i + 1];
108            if (currentRange.getEnd() + 1 >= nextRange.getStart()) {
109                newRangeCount--;
110                pageRanges[i] = null;
111                pageRanges[i + 1] = new PageRange(currentRange.getStart(),
112                        Math.max(currentRange.getEnd(), nextRange.getEnd()));
113            }
114        }
115        if (newRangeCount == oldRangeCount) {
116            return pageRanges;
117        }
118        return Arrays.copyOfRange(pageRanges, oldRangeCount - newRangeCount,
119                oldRangeCount);
120    }
121
122    /**
123     * Offsets a the start and end of page ranges with the given value.
124     *
125     * @param pageRanges The page ranges to offset.
126     * @param offset The offset value.
127     */
128    public static void offset(PageRange[] pageRanges, int offset) {
129        if (offset == 0) {
130            return;
131        }
132        final int pageRangeCount = pageRanges.length;
133        for (int i = 0; i < pageRangeCount; i++) {
134            final int start = pageRanges[i].getStart() + offset;
135            final int end = pageRanges[i].getEnd() + offset;
136            pageRanges[i] = new PageRange(start, end);
137        }
138    }
139
140    /**
141     * Gets the number of pages in a normalized range array.
142     *
143     * @param pageRanges Normalized page ranges.
144     * @param layoutPageCount Page count after reported after layout pass.
145     * @return The page count in the ranges.
146     */
147    public static int getNormalizedPageCount(PageRange[] pageRanges, int layoutPageCount) {
148        int pageCount = 0;
149        final int pageRangeCount = pageRanges.length;
150        for (int i = 0; i < pageRangeCount; i++) {
151            PageRange pageRange = pageRanges[i];
152            if (PageRange.ALL_PAGES.equals(pageRange)) {
153                return layoutPageCount;
154            }
155            pageCount += pageRange.getEnd() - pageRange.getStart() + 1;
156        }
157        return pageCount;
158    }
159}
160