source: josm/trunk/src/org/openstreetmap/josm/gui/mappaint/ElemStyle.java@ 8256

Last change on this file since 8256 was 8087, checked in by bastiK, 9 years ago

MapCSS: new @supports rule

Implementation should be mostly compatible with
the CSS Conditional 3 draft [2].

This is similar to @media, which was previously misused
for this purpose and is now deprecated.

refs:
[1] https://wiki.openstreetmap.org/wiki/MapCSS/0.2/Proposal_media_query
[2] http://dev.w3.org/csswg/css-conditional/

  • Property svn:eol-style set to native
File size: 8.5 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.mappaint;
3
4import java.awt.Font;
5import java.util.HashMap;
6import java.util.Map;
7
8import org.openstreetmap.josm.Main;
9import org.openstreetmap.josm.data.osm.OsmPrimitive;
10import org.openstreetmap.josm.data.osm.visitor.paint.MapPaintSettings;
11import org.openstreetmap.josm.data.osm.visitor.paint.StyledMapRenderer;
12import org.openstreetmap.josm.gui.mappaint.mapcss.Instruction.RelativeFloat;
13
14public abstract class ElemStyle implements StyleKeys {
15
16 protected static final int ICON_IMAGE_IDX = 0;
17 protected static final int ICON_WIDTH_IDX = 1;
18 protected static final int ICON_HEIGHT_IDX = 2;
19 protected static final int ICON_OPACITY_IDX = 3;
20 protected static final int ICON_OFFSET_X_IDX = 4;
21 protected static final int ICON_OFFSET_Y_IDX = 5;
22 public static final String[] ICON_KEYS = {ICON_IMAGE, ICON_WIDTH, ICON_HEIGHT, ICON_OPACITY, ICON_OFFSET_X, ICON_OFFSET_Y};
23 public static final String[] REPEAT_IMAGE_KEYS = {REPEAT_IMAGE, REPEAT_IMAGE_WIDTH, REPEAT_IMAGE_HEIGHT, REPEAT_IMAGE_OPACITY, null, null};
24
25 public float major_z_index;
26 public float z_index;
27 public float object_z_index;
28 public boolean isModifier; // false, if style can serve as main style for the
29 // primitive; true, if it is a highlight or modifier
30
31 public ElemStyle(float major_z_index, float z_index, float object_z_index, boolean isModifier) {
32 this.major_z_index = major_z_index;
33 this.z_index = z_index;
34 this.object_z_index = object_z_index;
35 this.isModifier = isModifier;
36 }
37
38 protected ElemStyle(Cascade c, float default_major_z_index) {
39 major_z_index = c.get(MAJOR_Z_INDEX, default_major_z_index, Float.class);
40 z_index = c.get(Z_INDEX, 0f, Float.class);
41 object_z_index = c.get(OBJECT_Z_INDEX, 0f, Float.class);
42 isModifier = c.get(MODIFIER, false, Boolean.class);
43 }
44
45 /**
46 * draws a primitive
47 * @param primitive
48 * @param paintSettings
49 * @param painter
50 * @param selected true, if primitive is selected
51 * @param outermember true, if primitive is not selected and outer member of a selected multipolygon relation
52 * @param member true, if primitive is not selected and member of a selected relation
53 */
54 public abstract void paintPrimitive(OsmPrimitive primitive, MapPaintSettings paintSettings, StyledMapRenderer painter,
55 boolean selected, boolean outermember, boolean member);
56
57 public boolean isProperLineStyle() {
58 return false;
59 }
60
61 /**
62 * Get a property value of type Width
63 * @param c the cascade
64 * @param key property key for the width value
65 * @param relativeTo reference width. Only needed, when relative width syntax
66 * is used, e.g. "+4".
67 */
68 protected static Float getWidth(Cascade c, String key, Float relativeTo) {
69 Float width = c.get(key, null, Float.class, true);
70 if (width != null) {
71 if (width > 0)
72 return width;
73 } else {
74 Keyword widthKW = c.get(key, null, Keyword.class, true);
75 if (Keyword.THINNEST.equals(widthKW))
76 return 0f;
77 if (Keyword.DEFAULT.equals(widthKW))
78 return (float) MapPaintSettings.INSTANCE.getDefaultSegmentWidth();
79 if (relativeTo != null) {
80 RelativeFloat width_rel = c.get(key, null, RelativeFloat.class, true);
81 if (width_rel != null)
82 return relativeTo + width_rel.val;
83 }
84 }
85 return null;
86 }
87
88 /* ------------------------------------------------------------------------------- */
89 /* cached values */
90 /* ------------------------------------------------------------------------------- */
91 /*
92 * Two preference values and the set of created fonts are cached in order to avoid
93 * expensive lookups and to avoid too many font objects
94 *
95 * FIXME: cached preference values are not updated if the user changes them during
96 * a JOSM session. Should have a listener listening to preference changes.
97 */
98 private static volatile String DEFAULT_FONT_NAME = null;
99 private static volatile Float DEFAULT_FONT_SIZE = null;
100 private static final Object lock = new Object();
101
102 // thread save access (double-checked locking)
103 private static Float getDefaultFontSize() {
104 Float s = DEFAULT_FONT_SIZE;
105 if (s == null) {
106 synchronized (lock) {
107 s = DEFAULT_FONT_SIZE;
108 if (s == null) {
109 DEFAULT_FONT_SIZE = s = (float) Main.pref.getInteger("mappaint.fontsize", 8);
110 }
111 }
112 }
113 return s;
114 }
115
116 private static String getDefaultFontName() {
117 String n = DEFAULT_FONT_NAME;
118 if (n == null) {
119 synchronized (lock) {
120 n = DEFAULT_FONT_NAME;
121 if (n == null) {
122 DEFAULT_FONT_NAME = n = Main.pref.get("mappaint.font", "Droid Sans");
123 }
124 }
125 }
126 return n;
127 }
128
129 private static class FontDescriptor {
130 public String name;
131 public int style;
132 public int size;
133
134 public FontDescriptor(String name, int style, int size){
135 this.name = name;
136 this.style = style;
137 this.size = size;
138 }
139
140 @Override
141 public int hashCode() {
142 final int prime = 31;
143 int result = 1;
144 result = prime * result + ((name == null) ? 0 : name.hashCode());
145 result = prime * result + size;
146 result = prime * result + style;
147 return result;
148 }
149 @Override
150 public boolean equals(Object obj) {
151 if (this == obj)
152 return true;
153 if (obj == null)
154 return false;
155 if (getClass() != obj.getClass())
156 return false;
157 FontDescriptor other = (FontDescriptor) obj;
158 if (name == null) {
159 if (other.name != null)
160 return false;
161 } else if (!name.equals(other.name))
162 return false;
163 if (size != other.size)
164 return false;
165 if (style != other.style)
166 return false;
167 return true;
168 }
169 }
170
171 private static final Map<FontDescriptor, Font> FONT_MAP = new HashMap<>();
172 private static Font getCachedFont(FontDescriptor fd) {
173 Font f = FONT_MAP.get(fd);
174 if (f != null) return f;
175 f = new Font(fd.name, fd.style, fd.size);
176 FONT_MAP.put(fd, f);
177 return f;
178 }
179
180 private static Font getCachedFont(String name, int style, int size){
181 return getCachedFont(new FontDescriptor(name, style, size));
182 }
183
184 protected static Font getFont(Cascade c, String s) {
185 String name = c.get(FONT_FAMILY, getDefaultFontName(), String.class);
186 float size = c.get(FONT_SIZE, getDefaultFontSize(), Float.class);
187 int weight = Font.PLAIN;
188 if ("bold".equalsIgnoreCase(c.get(FONT_WEIGHT, null, String.class))) {
189 weight = Font.BOLD;
190 }
191 int style = Font.PLAIN;
192 if ("italic".equalsIgnoreCase(c.get(FONT_STYLE, null, String.class))) {
193 style = Font.ITALIC;
194 }
195 Font f = getCachedFont(name, style | weight, Math.round(size));
196 if (f.canDisplayUpTo(s) == -1)
197 return f;
198 else {
199 // fallback if the string contains characters that cannot be
200 // rendered by the selected font
201 return getCachedFont("SansSerif", style | weight, Math.round(size));
202 }
203 }
204
205 @Override
206 public boolean equals(Object o) {
207 if (!(o instanceof ElemStyle))
208 return false;
209 ElemStyle s = (ElemStyle) o;
210 return major_z_index == s.major_z_index &&
211 z_index == s.z_index &&
212 object_z_index == s.object_z_index &&
213 isModifier == s.isModifier;
214 }
215
216 @Override
217 public int hashCode() {
218 int hash = 5;
219 hash = 41 * hash + Float.floatToIntBits(this.major_z_index);
220 hash = 41 * hash + Float.floatToIntBits(this.z_index);
221 hash = 41 * hash + Float.floatToIntBits(this.object_z_index);
222 hash = 41 * hash + (isModifier ? 1 : 0);
223 return hash;
224 }
225
226 @Override
227 public String toString() {
228 return String.format("z_idx=[%s/%s/%s] ", major_z_index, z_index, object_z_index) + (isModifier ? "modifier " : "");
229 }
230}
Note: See TracBrowser for help on using the repository browser.