1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements.  See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License.  You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 /* $Id: Keep.java 985537 2010-08-14 17:17:00Z jeremias $ */
19 
20 package org.apache.fop.layoutmgr;
21 
22 import org.apache.fop.fo.Constants;
23 import org.apache.fop.fo.properties.KeepProperty;
24 import org.apache.fop.fo.properties.Property;
25 
26 /**
27  * Object representing a keep constraint, corresponding
28  * to the XSL-FO <a href="http://www.w3.org/TR/xsl/#d0e26492">keep properties</a>.
29  */
30 public final class Keep {
31 
32     /** The integer value for "auto" keep strength. */
33     private static final int STRENGTH_AUTO = Integer.MIN_VALUE;
34 
35     /** The integer value for "always" keep strength. */
36     private static final int STRENGTH_ALWAYS = Integer.MAX_VALUE;
37 
38     /** keep auto */
39     public static final Keep KEEP_AUTO = new Keep(STRENGTH_AUTO, Constants.EN_AUTO);
40 
41     /** keep always */
42     public static final Keep KEEP_ALWAYS = new Keep(STRENGTH_ALWAYS, Constants.EN_LINE);
43 
44     private int strength;
45 
46     private int context;
47 
Keep(int strength, int context)48     private Keep(int strength, int context) {
49         this.strength = strength;
50         this.context = context;
51     }
52 
getKeepStrength(Property keep)53     private static int getKeepStrength(Property keep) {
54         if (keep.isAuto()) {
55             return STRENGTH_AUTO;
56         } else if (keep.getEnum() == Constants.EN_ALWAYS) {
57             return STRENGTH_ALWAYS;
58         } else {
59             return keep.getNumber().intValue();
60         }
61     }
62 
63     /**
64      * Obtain a Keep instance corresponding to the given {@link KeepProperty}
65      *
66      * @param keepProperty  the {@link KeepProperty}
67      * @return  a new instance corresponding to the given property
68      */
getKeep(KeepProperty keepProperty)69     public static Keep getKeep(KeepProperty keepProperty) {
70         Keep keep = new Keep(STRENGTH_AUTO, Constants.EN_AUTO);
71         keep.update(keepProperty.getWithinPage(),   Constants.EN_PAGE);
72         keep.update(keepProperty.getWithinColumn(), Constants.EN_COLUMN);
73         keep.update(keepProperty.getWithinLine(),   Constants.EN_LINE);
74         return keep;
75     }
76 
update(Property keep, int context)77     private void update(Property keep, int context) {
78         if (!keep.isAuto()) {
79             this.strength = getKeepStrength(keep);
80             this.context = context;
81         }
82     }
83 
84     /** @return {@code true} if the keep property was specified as "auto" */
isAuto()85     public boolean isAuto() {
86         return strength == STRENGTH_AUTO;
87     }
88 
89     /**
90      * Returns the context of this keep.
91      *
92      * @return one of {@link Constants#EN_LINE}, {@link Constants#EN_COLUMN} or
93      * {@link Constants#EN_PAGE}
94      */
getContext()95     public int getContext() {
96         return context;
97     }
98 
99     /** @return the penalty value corresponding to the strength of this Keep */
getPenalty()100     public int getPenalty() {
101         if (strength == STRENGTH_AUTO) {
102             return 0;
103         } else if (strength == STRENGTH_ALWAYS) {
104             return KnuthElement.INFINITE;
105         } else {
106             return KnuthElement.INFINITE - 1;
107         }
108     }
109 
getKeepContextPriority(int context)110     private static int getKeepContextPriority(int context) {
111         switch (context) {
112         case Constants.EN_LINE:   return 0;
113         case Constants.EN_COLUMN: return 1;
114         case Constants.EN_PAGE:   return 2;
115         case Constants.EN_AUTO:   return 3;
116         default: throw new IllegalArgumentException();
117         }
118     }
119 
120     /**
121      * Compare this Keep instance to another one, and return the
122      * stronger one if the context is the same
123      *
124      * @param other     the instance to compare to
125      * @return  the winning Keep instance
126      */
compare(Keep other)127     public Keep compare(Keep other) {
128 
129         /* check strength "always" first, regardless of priority */
130         if (this.strength == STRENGTH_ALWAYS
131                 && this.strength > other.strength) {
132             return this;
133         } else if (other.strength == STRENGTH_ALWAYS
134                 && other.strength > this.strength) {
135             return other;
136         }
137 
138         int pThis = getKeepContextPriority(this.context);
139         int pOther = getKeepContextPriority(other.context);
140 
141         /* equal priority: strongest wins */
142         if (pThis == pOther) {
143             return (strength >= other.strength) ? this : other;
144         }
145 
146         /* different priority: lowest priority wins */
147         return (pThis < pOther) ? this : other;
148     }
149 
150     /** {@inheritDoc} */
toString()151     public String toString() {
152         return (strength == STRENGTH_AUTO) ? "auto"
153                 : (strength == STRENGTH_ALWAYS) ? "always"
154                         : Integer.toString(strength);
155     }
156 }
157