Home | History | Annotate | Download | only in util
      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 
     17 package com.android.printspooler.util;
     18 
     19 import android.print.PageRange;
     20 import android.print.PrintDocumentInfo;
     21 
     22 import java.util.Arrays;
     23 import java.util.Comparator;
     24 
     25 /**
     26  * This class contains utility functions for working with page ranges.
     27  */
     28 public final class PageRangeUtils {
     29 
     30     private static final PageRange[] ALL_PAGES_RANGE = new PageRange[] {PageRange.ALL_PAGES};
     31 
     32     private static final Comparator<PageRange> sComparator = new Comparator<PageRange>() {
     33         @Override
     34         public int compare(PageRange lhs, PageRange rhs) {
     35             return lhs.getStart() - rhs.getStart();
     36         }
     37     };
     38 
     39     private PageRangeUtils() {
     40         /* do nothing - hide constructor */
     41     }
     42 
     43     /**
     44      * Gets whether page ranges contains a given page.
     45      *
     46      * @param pageRanges The page ranges.
     47      * @param pageIndex The page for which to check.
     48      * @return Whether the page is within the ranges.
     49      */
     50     public static boolean contains(PageRange[] pageRanges, int pageIndex) {
     51         final int rangeCount = pageRanges.length;
     52         for (int i = 0; i < rangeCount; i++) {
     53             PageRange pageRange = pageRanges[i];
     54             if (pageRange.contains(pageIndex)) {
     55                 return true;
     56             }
     57         }
     58         return false;
     59     }
     60 
     61     /**
     62      * Checks whether one page range array contains another one.
     63      *
     64      * @param ourRanges The container page ranges.
     65      * @param otherRanges The contained page ranges.
     66      * @param pageCount The total number of pages.
     67      * @return Whether the container page ranges contains the contained ones.
     68      */
     69     public static boolean contains(PageRange[] ourRanges, PageRange[] otherRanges, int pageCount) {
     70         if (ourRanges == null || otherRanges == null) {
     71             return false;
     72         }
     73 
     74         if (Arrays.equals(ourRanges, ALL_PAGES_RANGE)) {
     75             return true;
     76         }
     77 
     78         if (Arrays.equals(otherRanges, ALL_PAGES_RANGE)) {
     79             otherRanges[0] = new PageRange(0, pageCount - 1);
     80         }
     81 
     82         ourRanges = normalize(ourRanges);
     83         otherRanges = normalize(otherRanges);
     84 
     85         // Note that the code below relies on the ranges being normalized
     86         // which is they contain monotonically increasing non-intersecting
     87         // sub-ranges whose start is less that or equal to the end.
     88         int otherRangeIdx = 0;
     89         final int ourRangeCount = ourRanges.length;
     90         final int otherRangeCount = otherRanges.length;
     91         for (int ourRangeIdx = 0; ourRangeIdx < ourRangeCount; ourRangeIdx++) {
     92             PageRange ourRange = ourRanges[ourRangeIdx];
     93             for (; otherRangeIdx < otherRangeCount; otherRangeIdx++) {
     94                 PageRange otherRange = otherRanges[otherRangeIdx];
     95                 if (otherRange.getStart() > ourRange.getEnd()) {
     96                     break;
     97                 }
     98                 if (otherRange.getStart() < ourRange.getStart()
     99                         || otherRange.getEnd() > ourRange.getEnd()) {
    100                     return false;
    101                 }
    102             }
    103         }
    104         return (otherRangeIdx >= otherRangeCount);
    105     }
    106 
    107     /**
    108      * Normalizes a page range, which is the resulting page ranges are
    109      * non-overlapping with the start lesser than or equal to the end
    110      * and ordered in an ascending order.
    111      *
    112      * @param pageRanges The page ranges to normalize.
    113      * @return The normalized page ranges.
    114      */
    115     public static PageRange[] normalize(PageRange[] pageRanges) {
    116         if (pageRanges == null) {
    117             return null;
    118         }
    119 
    120         final int oldRangeCount = pageRanges.length;
    121         if (oldRangeCount <= 1) {
    122             return pageRanges;
    123         }
    124 
    125         Arrays.sort(pageRanges, sComparator);
    126 
    127         int newRangeCount = 1;
    128         for (int i = 0; i < oldRangeCount - 1; i++) {
    129             PageRange currentRange = pageRanges[i];
    130             PageRange nextRange = pageRanges[i + 1];
    131             if (currentRange.getEnd() + 1 >= nextRange.getStart()) {
    132                 pageRanges[i] = null;
    133                 pageRanges[i + 1] = new PageRange(currentRange.getStart(),
    134                         Math.max(currentRange.getEnd(), nextRange.getEnd()));
    135             } else {
    136                 newRangeCount++;
    137             }
    138         }
    139 
    140         if (newRangeCount == oldRangeCount) {
    141             return pageRanges;
    142         }
    143 
    144         int normalRangeIndex = 0;
    145         PageRange[] normalRanges = new PageRange[newRangeCount];
    146         for (int i = 0; i < oldRangeCount; i++) {
    147             PageRange normalRange = pageRanges[i];
    148             if (normalRange != null) {
    149                 normalRanges[normalRangeIndex] = normalRange;
    150                 normalRangeIndex++;
    151             }
    152         }
    153 
    154         return normalRanges;
    155     }
    156 
    157     /**
    158      * Offsets a the start and end of page ranges with the given value.
    159      *
    160      * @param pageRanges The page ranges to offset.
    161      * @param offset The offset value.
    162      */
    163     public static void offset(PageRange[] pageRanges, int offset) {
    164         if (offset == 0) {
    165             return;
    166         }
    167         final int pageRangeCount = pageRanges.length;
    168         for (int i = 0; i < pageRangeCount; i++) {
    169             final int start = pageRanges[i].getStart() + offset;
    170             final int end = pageRanges[i].getEnd() + offset;
    171             pageRanges[i] = new PageRange(start, end);
    172         }
    173     }
    174 
    175     /**
    176      * Gets the number of pages in a normalized range array.
    177      *
    178      * @param pageRanges Normalized page ranges.
    179      * @param layoutPageCount Page count after reported after layout pass.
    180      * @return The page count in the ranges.
    181      */
    182     public static int getNormalizedPageCount(PageRange[] pageRanges, int layoutPageCount) {
    183         int pageCount = 0;
    184         if (pageRanges != null) {
    185             final int pageRangeCount = pageRanges.length;
    186             for (int i = 0; i < pageRangeCount; i++) {
    187                 PageRange pageRange = pageRanges[i];
    188                 if (PageRange.ALL_PAGES.equals(pageRange)) {
    189                     return layoutPageCount;
    190                 }
    191                 pageCount += pageRange.getSize();
    192             }
    193         }
    194         return pageCount;
    195     }
    196 
    197     public static PageRange asAbsoluteRange(PageRange pageRange, int pageCount) {
    198         if (PageRange.ALL_PAGES.equals(pageRange)) {
    199             return new PageRange(0, pageCount - 1);
    200         }
    201         return pageRange;
    202     }
    203 
    204     public static boolean isAllPages(PageRange[] pageRanges) {
    205         final int pageRangeCount = pageRanges.length;
    206         for (int i = 0; i < pageRangeCount; i++) {
    207             PageRange pageRange = pageRanges[i];
    208             if (isAllPages(pageRange)) {
    209                 return true;
    210             }
    211         }
    212         return false;
    213     }
    214 
    215     public static boolean isAllPages(PageRange pageRange) {
    216         return PageRange.ALL_PAGES.equals(pageRange);
    217     }
    218 
    219     public static boolean isAllPages(PageRange[] pageRanges, int pageCount) {
    220         final int pageRangeCount = pageRanges.length;
    221         for (int i = 0; i < pageRangeCount; i++) {
    222             PageRange pageRange = pageRanges[i];
    223             if (isAllPages(pageRange, pageCount)) {
    224                 return true;
    225             }
    226         }
    227         return false;
    228     }
    229 
    230     public static boolean isAllPages(PageRange pageRanges, int pageCount) {
    231         return pageRanges.getStart() == 0 && pageRanges.getEnd() == pageCount - 1;
    232     }
    233 
    234     public static PageRange[] computePrintedPages(PageRange[] requestedPages,
    235             PageRange[] writtenPages, int pageCount) {
    236         // Adjust the print job pages based on what was requested and written.
    237         // The cases are ordered in the most expected to the least expected
    238         // with a special case first where the app does not know the page count
    239         // so we ask for all to be written.
    240         if (Arrays.equals(requestedPages, ALL_PAGES_RANGE)
    241                 && pageCount == PrintDocumentInfo.PAGE_COUNT_UNKNOWN) {
    242             return ALL_PAGES_RANGE;
    243         } else if (Arrays.equals(writtenPages, requestedPages)) {
    244             // We got a document with exactly the pages we wanted. Hence,
    245             // the printer has to print all pages in the data.
    246             return ALL_PAGES_RANGE;
    247         } else if (Arrays.equals(writtenPages, ALL_PAGES_RANGE)) {
    248             // We requested specific pages but got all of them. Hence,
    249             // the printer has to print only the requested pages.
    250             return requestedPages;
    251         } else if (PageRangeUtils.contains(writtenPages, requestedPages, pageCount)) {
    252             // We requested specific pages and got more but not all pages.
    253             // Hence, we have to offset appropriately the printed pages to
    254             // be based off the start of the written ones instead of zero.
    255             // The written pages are always non-null and not empty.
    256             final int offset = -writtenPages[0].getStart();
    257             PageRangeUtils.offset(requestedPages, offset);
    258             return requestedPages;
    259         } else if (Arrays.equals(requestedPages, ALL_PAGES_RANGE)
    260                 && isAllPages(writtenPages, pageCount)) {
    261             // We requested all pages via the special constant and got all
    262             // of them as an explicit enumeration. Hence, the printer has
    263             // to print only the requested pages.
    264             return ALL_PAGES_RANGE;
    265         }
    266 
    267         return null;
    268     }
    269 }
    270