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: ConditionalBorder.java 1480018 2013-05-07 18:53:29Z vhennebert $ */ 19 20 package org.apache.fop.fo.flow.table; 21 22 import org.apache.fop.layoutmgr.table.CollapsingBorderModel; 23 24 /** 25 * A class that holds the three possible values for a border-before/after on a table-cell, 26 * in the collapsing model. These three values are (for border-before, similar for 27 * border-after): 28 * <ul> 29 * <li>normal: common case, when a cell follows the cell before on a same page;</li> 30 * <li>leading: when the table is broken and the cell appears at the top of a page, in 31 * which case its border must be resolved with the header (or the top of the table) 32 * instead of with the previous cell;</li> 33 * <li>rest: when a cell is broken over several pages; same as leading but with 34 * conditionality taken into account.</li> 35 * </ul> 36 */ 37 public class ConditionalBorder { 38 39 /** normal border */ 40 public static final int NORMAL = 0; 41 42 /** leading and trailing border */ 43 public static final int LEADING_TRAILING = 1; 44 45 /** all the rest */ 46 public static final int REST = 2; 47 48 /** Normal case, no break. */ 49 BorderSpecification normal; 50 51 /** Special case: the cell is at the top or the bottom of the page. */ 52 BorderSpecification leadingTrailing; 53 54 /** Special case: break inside the cell. */ 55 BorderSpecification rest; 56 57 /** The model used to resolve borders. */ 58 private CollapsingBorderModel collapsingBorderModel; 59 ConditionalBorder(BorderSpecification normal, BorderSpecification leadingTrailing, BorderSpecification rest, CollapsingBorderModel collapsingBorderModel)60 private ConditionalBorder(BorderSpecification normal, 61 BorderSpecification leadingTrailing, BorderSpecification rest, 62 CollapsingBorderModel collapsingBorderModel) { 63 assert collapsingBorderModel != null; 64 this.normal = normal; 65 this.leadingTrailing = leadingTrailing; 66 this.rest = rest; 67 this.collapsingBorderModel = collapsingBorderModel; 68 } 69 70 /** 71 * Creates a new conditional border. 72 * 73 * @param borderSpecification the border specification to take as a basis 74 * @param collapsingBorderModel the model that will be used to resolved borders 75 */ ConditionalBorder(BorderSpecification borderSpecification, CollapsingBorderModel collapsingBorderModel)76 ConditionalBorder(BorderSpecification borderSpecification, 77 CollapsingBorderModel collapsingBorderModel) { 78 this (borderSpecification, borderSpecification, 79 borderSpecification.getBorderInfo().getWidth().isDiscard() 80 ? BorderSpecification.getDefaultBorder() : borderSpecification, 81 collapsingBorderModel); 82 } 83 84 /** 85 * Resolves and updates the relevant parts of this border as well as the given one. 86 * 87 * @param competitor 88 * @param withNormal 89 * @param withLeadingTrailing 90 * @param withRest 91 */ resolve(ConditionalBorder competitor, boolean withNormal, boolean withLeadingTrailing, boolean withRest)92 void resolve(ConditionalBorder competitor, boolean withNormal, 93 boolean withLeadingTrailing, boolean withRest) { 94 if (withNormal) { 95 BorderSpecification resolvedBorder = collapsingBorderModel.determineWinner( 96 normal, competitor.normal); 97 if (resolvedBorder != null) { 98 normal = resolvedBorder; 99 competitor.normal = resolvedBorder; 100 } 101 } 102 if (withLeadingTrailing) { 103 BorderSpecification resolvedBorder = collapsingBorderModel.determineWinner( 104 leadingTrailing, competitor.leadingTrailing); 105 if (resolvedBorder != null) { 106 leadingTrailing = resolvedBorder; 107 competitor.leadingTrailing = resolvedBorder; 108 } 109 } 110 if (withRest) { 111 BorderSpecification resolvedBorder = collapsingBorderModel.determineWinner(rest, 112 competitor.rest); 113 if (resolvedBorder != null) { 114 rest = resolvedBorder; 115 competitor.rest = resolvedBorder; 116 } 117 } 118 } 119 120 /** 121 * Integrates the given segment in this border. Unlike for 122 * {@link #integrateSegment(ConditionalBorder, boolean, boolean, boolean)}, this 123 * method nicely handles the case where the CollapsingBorderModel returns null, by 124 * keeping the components to their old values. 125 * 126 * @param competitor 127 * @param withNormal 128 * @param withLeadingTrailing 129 * @param withRest 130 */ integrateCompetingSegment(ConditionalBorder competitor, boolean withNormal, boolean withLeadingTrailing, boolean withRest)131 void integrateCompetingSegment(ConditionalBorder competitor, boolean withNormal, 132 boolean withLeadingTrailing, boolean withRest) { 133 if (withNormal) { 134 BorderSpecification resolvedBorder = collapsingBorderModel.determineWinner( 135 normal, competitor.normal); 136 if (resolvedBorder != null) { 137 normal = resolvedBorder; 138 } 139 } 140 if (withLeadingTrailing) { 141 BorderSpecification resolvedBorder = collapsingBorderModel.determineWinner( 142 leadingTrailing, competitor.leadingTrailing); 143 if (resolvedBorder != null) { 144 leadingTrailing = resolvedBorder; 145 } 146 } 147 if (withRest) { 148 BorderSpecification resolvedBorder = collapsingBorderModel.determineWinner(rest, 149 competitor.rest); 150 if (resolvedBorder != null) { 151 rest = resolvedBorder; 152 } 153 } 154 } 155 156 /** 157 * Updates this border after taking into account the given segment. The 158 * CollapsingBorderModel is not expected to return null. 159 * 160 * @param segment 161 * @param withNormal 162 * @param withLeadingTrailing 163 * @param withRest 164 */ integrateSegment(ConditionalBorder segment, boolean withNormal, boolean withLeadingTrailing, boolean withRest)165 void integrateSegment(ConditionalBorder segment, boolean withNormal, 166 boolean withLeadingTrailing, boolean withRest) { 167 if (withNormal) { 168 normal = collapsingBorderModel.determineWinner(normal, segment.normal); 169 assert normal != null; 170 } 171 if (withLeadingTrailing) { 172 leadingTrailing = collapsingBorderModel.determineWinner(leadingTrailing, 173 segment.leadingTrailing); 174 assert leadingTrailing != null; 175 } 176 if (withRest) { 177 rest = collapsingBorderModel.determineWinner(rest, segment.rest); 178 assert rest != null; 179 } 180 } 181 182 /** 183 * Returns a shallow copy of this border. 184 * 185 * @return a copy of this border 186 */ copy()187 ConditionalBorder copy() { 188 return new ConditionalBorder(normal, leadingTrailing, rest, collapsingBorderModel); 189 } 190 191 /** {@inheritDoc} */ toString()192 public String toString() { 193 return "{normal: " + normal + ", leading: " + leadingTrailing + ", rest: " + rest + "}"; 194 } 195 196 /** 197 * Returns a default border specification. 198 * 199 * @param collapsingBorderModel the model that will be used to resolve borders 200 * @return a border with style 'none' for all of the three components 201 */ getDefaultBorder(CollapsingBorderModel collapsingBorderModel)202 static ConditionalBorder getDefaultBorder(CollapsingBorderModel collapsingBorderModel) { 203 BorderSpecification defaultBorderSpec = BorderSpecification.getDefaultBorder(); 204 return new ConditionalBorder(defaultBorderSpec, defaultBorderSpec, defaultBorderSpec, 205 collapsingBorderModel); 206 } 207 } 208