1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package org.htmlunit;
16
17 import static org.htmlunit.BrowserVersionFeatures.JS_WINDOW_COMPUTED_STYLE_PSEUDO_ACCEPT_WITHOUT_COLON;
18 import static org.htmlunit.BrowserVersionFeatures.JS_WINDOW_OUTER_INNER_HEIGHT_DIFF_138;
19 import static org.htmlunit.BrowserVersionFeatures.JS_WINDOW_OUTER_INNER_HEIGHT_DIFF_147;
20 import static org.htmlunit.BrowserVersionFeatures.JS_WINDOW_OUTER_INNER_HEIGHT_DIFF_91;
21 import static org.htmlunit.BrowserVersionFeatures.JS_WINDOW_OUTER_INNER_HEIGHT_DIFF_93;
22
23 import java.io.IOException;
24 import java.io.ObjectInputStream;
25 import java.io.ObjectOutputStream;
26 import java.util.ArrayList;
27 import java.util.List;
28
29 import org.apache.commons.logging.Log;
30 import org.apache.commons.logging.LogFactory;
31 import org.htmlunit.css.ComputedCssStyleDeclaration;
32 import org.htmlunit.css.CssStyleSheet;
33 import org.htmlunit.css.ElementCssStyleDeclaration;
34 import org.htmlunit.html.DomElement;
35 import org.htmlunit.html.HtmlPage;
36 import org.htmlunit.javascript.HtmlUnitScriptable;
37 import org.htmlunit.javascript.background.BackgroundJavaScriptFactory;
38 import org.htmlunit.javascript.background.JavaScriptJobManager;
39 import org.htmlunit.javascript.host.Window;
40 import org.w3c.dom.Document;
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55 public abstract class WebWindowImpl implements WebWindow {
56
57 private static final Log LOG = LogFactory.getLog(WebWindowImpl.class);
58
59 private final WebClient webClient_;
60 private final Screen screen_;
61 private Page enclosedPage_;
62 private transient HtmlUnitScriptable scriptObject_;
63 private JavaScriptJobManager jobManager_;
64 private final List<WebWindowImpl> childWindows_ = new ArrayList<>();
65 private String name_ = "";
66 private final History history_ = new History(this);
67 private boolean closed_;
68
69 private int innerHeight_;
70 private int outerHeight_;
71 private int innerWidth_;
72 private int outerWidth_;
73
74
75
76
77
78
79 public WebWindowImpl(final WebClient webClient) {
80 WebAssert.notNull("webClient", webClient);
81 webClient_ = webClient;
82 jobManager_ = BackgroundJavaScriptFactory.theFactory().createJavaScriptJobManager(this);
83
84 screen_ = new Screen(webClient);
85
86 innerHeight_ = 605;
87 innerWidth_ = 1256;
88 if (webClient.getBrowserVersion().hasFeature(JS_WINDOW_OUTER_INNER_HEIGHT_DIFF_91)) {
89 outerHeight_ = innerHeight_ + 91;
90 outerWidth_ = innerWidth_ + 12;
91 }
92 else if (webClient.getBrowserVersion().hasFeature(JS_WINDOW_OUTER_INNER_HEIGHT_DIFF_93)) {
93 outerHeight_ = innerHeight_ + 93;
94 outerWidth_ = innerWidth_ + 16;
95 }
96 else if (webClient.getBrowserVersion().hasFeature(JS_WINDOW_OUTER_INNER_HEIGHT_DIFF_138)) {
97 outerHeight_ = innerHeight_ + 138;
98 outerWidth_ = innerWidth_ + 24;
99 }
100 else if (webClient.getBrowserVersion().hasFeature(JS_WINDOW_OUTER_INNER_HEIGHT_DIFF_147)) {
101 outerHeight_ = innerHeight_ + 147;
102 outerWidth_ = innerWidth_ + 16;
103 }
104 else {
105 outerHeight_ = innerHeight_ + 115;
106 outerWidth_ = innerWidth_ + 14;
107 }
108 }
109
110
111
112
113 protected void performRegistration() {
114 webClient_.registerWebWindow(this);
115 }
116
117
118
119
120 @Override
121 public WebClient getWebClient() {
122 return webClient_;
123 }
124
125
126
127
128 @Override
129 public Screen getScreen() {
130 return screen_;
131 }
132
133
134
135
136 @Override
137 public Page getEnclosedPage() {
138 return enclosedPage_;
139 }
140
141
142
143
144 @Override
145 public void setEnclosedPage(final Page page) {
146 if (LOG.isDebugEnabled()) {
147 LOG.debug("setEnclosedPage: " + page);
148 }
149 if (page == enclosedPage_) {
150 return;
151 }
152 destroyChildren();
153
154 if (isJavaScriptInitializationNeeded(page)) {
155 webClient_.initialize(this, page);
156 }
157 if (webClient_.isJavaScriptEngineEnabled()) {
158 final Window window = getScriptableObject();
159 window.initialize(page);
160 }
161
162
163
164 enclosedPage_ = page;
165 history_.addPage(page);
166 }
167
168
169
170
171
172
173 protected abstract boolean isJavaScriptInitializationNeeded(Page page);
174
175
176
177
178 @Override
179 public <T extends HtmlUnitScriptable> void setScriptableObject(final T scriptObject) {
180 scriptObject_ = scriptObject;
181 }
182
183
184
185
186 @Override
187 @SuppressWarnings("unchecked")
188 public <T> T getScriptableObject() {
189 return (T) scriptObject_;
190 }
191
192
193
194
195 @Override
196 public JavaScriptJobManager getJobManager() {
197 return jobManager_;
198 }
199
200
201
202
203
204
205
206
207 public void setJobManager(final JavaScriptJobManager jobManager) {
208 jobManager_ = jobManager;
209 }
210
211
212
213
214
215
216
217
218 public void addChildWindow(final WebWindowImpl child) {
219 synchronized (childWindows_) {
220 childWindows_.add(child);
221 }
222 }
223
224
225
226
227 protected void destroyChildren() {
228 LOG.debug("destroyChildren");
229 getJobManager().removeAllJobs();
230
231
232 while (!childWindows_.isEmpty()) {
233 final WebWindowImpl window = childWindows_.get(0);
234 removeChildWindow(window);
235 }
236 }
237
238
239
240
241
242
243
244 public void removeChildWindow(final WebWindowImpl window) {
245 if (LOG.isDebugEnabled()) {
246 LOG.debug("closing child window: " + window);
247 }
248 window.setClosed();
249 window.getJobManager().shutdown();
250 final Page page = window.getEnclosedPage();
251 if (page != null) {
252 page.cleanUp();
253 }
254 window.destroyChildren();
255
256 synchronized (childWindows_) {
257 childWindows_.remove(window);
258 }
259 webClient_.deregisterWebWindow(window);
260 }
261
262
263
264
265 @Override
266 public String getName() {
267 return name_;
268 }
269
270
271
272
273 @Override
274 public void setName(final String name) {
275 name_ = name;
276 }
277
278
279
280
281
282 @Override
283 public History getHistory() {
284 return history_;
285 }
286
287
288
289
290 @Override
291 public boolean isClosed() {
292 return closed_;
293 }
294
295
296
297
298 protected void setClosed() {
299 closed_ = true;
300 }
301
302
303
304
305 @Override
306 public int getInnerWidth() {
307 return innerWidth_;
308 }
309
310
311
312
313 @Override
314 public void setInnerWidth(final int innerWidth) {
315 innerWidth_ = innerWidth;
316 }
317
318
319
320
321 @Override
322 public int getOuterWidth() {
323 return outerWidth_;
324 }
325
326
327
328
329 @Override
330 public void setOuterWidth(final int outerWidth) {
331 outerWidth_ = outerWidth;
332 }
333
334
335
336
337 @Override
338 public int getInnerHeight() {
339 return innerHeight_;
340 }
341
342
343
344
345 @Override
346 public void setInnerHeight(final int innerHeight) {
347 innerHeight_ = innerHeight;
348 }
349
350
351
352
353 @Override
354 public int getOuterHeight() {
355 return outerHeight_;
356 }
357
358
359
360
361 @Override
362 public void setOuterHeight(final int outerHeight) {
363 outerHeight_ = outerHeight;
364 }
365
366 private void writeObject(final ObjectOutputStream oos) throws IOException {
367 oos.defaultWriteObject();
368 oos.writeObject(scriptObject_);
369 }
370
371 private void readObject(final ObjectInputStream ois) throws ClassNotFoundException, IOException {
372 ois.defaultReadObject();
373 scriptObject_ = (HtmlUnitScriptable) ois.readObject();
374 }
375
376
377
378
379 @Override
380 public ComputedCssStyleDeclaration getComputedStyle(final DomElement element, final String pseudoElement) {
381 String normalizedPseudo = pseudoElement;
382 if (normalizedPseudo != null) {
383 if (normalizedPseudo.startsWith("::")) {
384 normalizedPseudo = normalizedPseudo.substring(1);
385 }
386 else if (getWebClient().getBrowserVersion().hasFeature(JS_WINDOW_COMPUTED_STYLE_PSEUDO_ACCEPT_WITHOUT_COLON)
387 && normalizedPseudo.length() > 0 && normalizedPseudo.charAt(0) != ':') {
388 normalizedPseudo = ":" + normalizedPseudo;
389 }
390 }
391
392 final SgmlPage sgmlPage = element.getPage();
393 if (sgmlPage instanceof HtmlPage) {
394 final ComputedCssStyleDeclaration styleFromCache =
395 ((HtmlPage) sgmlPage).getStyleFromCache(element, normalizedPseudo);
396 if (styleFromCache != null) {
397 return styleFromCache;
398 }
399 }
400
401 final ComputedCssStyleDeclaration computedsStyleDeclaration =
402 new ComputedCssStyleDeclaration(new ElementCssStyleDeclaration(element));
403
404 final Document ownerDocument = element.getOwnerDocument();
405 if (ownerDocument instanceof HtmlPage) {
406 final HtmlPage htmlPage = (HtmlPage) ownerDocument;
407
408 final WebClient webClient = getWebClient();
409
410 if (webClient.getOptions().isCssEnabled()) {
411 final boolean trace = LOG.isTraceEnabled();
412 for (final CssStyleSheet cssStyleSheet : htmlPage.getStyleSheets()) {
413 if (cssStyleSheet != null
414 && cssStyleSheet.isEnabled()
415 && cssStyleSheet.isActive()) {
416 if (trace) {
417 LOG.trace("modifyIfNecessary: " + cssStyleSheet
418 + ", " + computedsStyleDeclaration + ", " + element);
419 }
420 cssStyleSheet.modifyIfNecessary(computedsStyleDeclaration, element, normalizedPseudo);
421 }
422 }
423 }
424
425 ((HtmlPage) element.getPage()).putStyleIntoCache(element, normalizedPseudo, computedsStyleDeclaration);
426 }
427
428 return computedsStyleDeclaration;
429 }
430 }