Initial commit
[profile/ivi/openjade.git] / style / Style.cxx
1 // Copyright (c) 1996 James Clark
2 // See the file copying.txt for copying permission.
3
4 #include "stylelib.h"
5 #include "Style.h"
6 #include "VM.h"
7 #include "Interpreter.h"
8 #include "InterpreterMessages.h"
9 #include "SosofoObj.h"
10 #include "macros.h"
11
12 #ifdef DSSSL_NAMESPACE
13 namespace DSSSL_NAMESPACE {
14 #endif
15
16 StyleStack::StyleStack()
17 : level_(0)
18 {
19 }
20
21 void StyleStack::pushContinue(StyleObj *style,
22                               const ProcessingMode::Rule *rule,
23                               const NodePtr &nodePtr,
24                               Messenger *mgr)
25 {
26   StyleObjIter iter;
27   style->appendIter(iter);
28   for (;;) {
29     const VarStyleObj *varStyle;
30     ConstPtr<InheritedC> spec(iter.next(varStyle));
31     if (spec.isNull())
32       break;
33     size_t ind = spec->index();
34     if (ind >= inheritedCInfo_.size())
35       inheritedCInfo_.resize(ind + 1);
36     Ptr<InheritedCInfo> &info = inheritedCInfo_[ind];
37     if (!info.isNull() && info->valLevel == level_) {
38       if (rule) {
39         ASSERT(info->rule != 0);
40         if (rule->compareSpecificity(*info->rule) == 0) {
41           mgr->setNextLocation(info->rule->location());
42           mgr->message(InterpreterMessages::ambiguousStyle,
43                        StringMessageArg(info->spec->identifier()->name()),
44                        rule->location());
45         }
46       }
47
48     }
49     else {
50       popList_->list.push_back(ind);
51       info = new InheritedCInfo(spec, varStyle, level_, level_, rule, info);
52     }
53   }
54 }
55
56 void StyleStack::pushEnd(VM &vm, FOTBuilder &fotb)
57 {
58   const PopList *oldPopList = popList_->prev.pointer();
59   if (oldPopList) {
60     for (size_t i = 0; i < oldPopList->dependingList.size(); i++) {
61       size_t d = oldPopList->dependingList[i];
62       // d is the index of a characteristic that depends on the actual
63       // value of another characteritistic
64       if (inheritedCInfo_[d]->valLevel != level_) {
65         const Vector<size_t> &dependencies = inheritedCInfo_[d]->dependencies;
66         bool changed = 0;
67         for (size_t j = 0; j < dependencies.size(); j++) {
68           const InheritedCInfo *p = inheritedCInfo_[dependencies[j]].pointer();
69           if (p && p->valLevel == level_) {
70             inheritedCInfo_[d] = new InheritedCInfo(inheritedCInfo_[d]->spec,
71                                                     inheritedCInfo_[d]->style,
72                                                     level_,
73                                                     inheritedCInfo_[d]->specLevel,
74                                                     inheritedCInfo_[d]->rule,
75                                                     inheritedCInfo_[d]);
76             popList_->list.push_back(d);
77             changed = 1;
78             break;
79           }
80         }
81         // If it changed, then doing set() on the new value will add
82         // it to the dependingList for this level.
83         if (!changed)
84           popList_->dependingList.push_back(d);
85       }
86     }
87   }
88   vm.styleStack = this;
89   for (size_t i = 0; i < popList_->list.size(); i++) {
90     InheritedCInfo &info = *inheritedCInfo_[popList_->list[i]];
91     vm.specLevel = info.specLevel;
92     info.spec->set(vm, info.style, fotb, info.cachedValue, info.dependencies);
93     if (info.dependencies.size())
94       popList_->dependingList.push_back(popList_->list[i]);
95   }
96   vm.styleStack = 0;
97 }
98
99 void StyleStack::pop()
100 {
101   for (size_t i = 0; i < popList_->list.size(); i++) {
102     size_t ind = popList_->list[i];
103     ASSERT(inheritedCInfo_[ind]->valLevel == level_);
104     Ptr<InheritedCInfo> tem(inheritedCInfo_[ind]->prev);
105     inheritedCInfo_[ind] = tem;
106   }
107   level_--;
108   Ptr<PopList> tem(popList_->prev);
109   popList_ = tem;
110 }
111
112 ELObj *StyleStack::inherited(const ConstPtr<InheritedC> &ic, unsigned specLevel,
113                              Interpreter &interp, Vector<size_t> &dependencies)
114 {
115   ASSERT(specLevel != unsigned(-1));
116   size_t ind = ic->index();
117   ConstPtr<InheritedC> spec;
118   const VarStyleObj *style = 0;
119   unsigned newSpecLevel = unsigned(-1);
120   if (ind >= inheritedCInfo_.size())
121     spec = ic;
122   else {
123     const InheritedCInfo *p = inheritedCInfo_[ind].pointer();
124     while (p != 0) {
125       if (p->specLevel < specLevel)
126         break;
127       p = p->prev.pointer();
128     }
129     if (!p)
130       spec = ic;
131     else {
132       if (p->cachedValue) {
133         // We can only use the cached value if none of the values
134         // we depended on changed since we computed it.
135         bool cacheOk = 1;
136         for (size_t i = 0; i < p->dependencies.size(); i++) {
137           size_t d = p->dependencies[i];
138           if (d < inheritedCInfo_.size()
139               && inheritedCInfo_[d]->valLevel > p->valLevel) {
140             cacheOk = 0;
141             break;
142           }
143         }
144         if (cacheOk)
145           return p->cachedValue;
146       }
147       style = p->style;
148       spec = p->spec;
149       newSpecLevel = p->specLevel;
150     }
151   }
152   VM vm(interp);
153   vm.styleStack = this;
154   vm.specLevel = newSpecLevel;
155   return spec->value(vm, style, dependencies);
156 }
157
158 ELObj *StyleStack::actual(const ConstPtr<InheritedC> &ic, const Location &loc,
159                           Interpreter &interp, Vector<size_t> &dependencies)
160 {
161   size_t ind = ic->index();
162   for (size_t i = 0; i < dependencies.size(); i++) {
163     if (dependencies[i] == ind) {
164       interp.setNextLocation(loc);
165       interp.message(InterpreterMessages::actualLoop,
166                      StringMessageArg(ic->identifier()->name()));
167       return interp.makeError();
168     }
169   }
170   dependencies.push_back(ind);
171   ConstPtr<InheritedC> spec;
172   const VarStyleObj *style = 0;
173   if (ind >= inheritedCInfo_.size())
174     spec = ic;
175   else {
176     const InheritedCInfo *p = inheritedCInfo_[ind].pointer();
177     if (!p)
178       spec = ic;
179     else if (p->cachedValue) {
180       const Vector<size_t> &dep = p->dependencies;
181       for (size_t i = 0; i < dep.size(); i++)
182         dependencies.push_back(dep[i]);
183       return p->cachedValue;
184     }
185     else {
186       style = p->style;
187       spec = p->spec;
188     }
189   }
190   VM vm(interp);
191   vm.styleStack = this;
192   vm.specLevel = level_;
193   return spec->value(vm, style, dependencies);
194 }
195
196 void StyleStack::trace(Collector &c) const
197 {
198   for (size_t i = 0; i < inheritedCInfo_.size(); i++) {
199     for (const InheritedCInfo *p = inheritedCInfo_[i].pointer();
200          p;
201          p = p->prev.pointer()) {
202       c.trace(p->style);
203       c.trace(p->cachedValue);
204     }
205   }
206 }
207
208 InheritedCInfo::InheritedCInfo(const ConstPtr<InheritedC> &sp,
209                                const VarStyleObj *so,
210                                unsigned vl,
211                                unsigned sl,
212                                const ProcessingMode::Rule *r,
213                                const Ptr<InheritedCInfo> &p)
214 : spec(sp), style(so), valLevel(vl), specLevel(sl), rule(r), prev(p), cachedValue(0)
215 {
216 }
217
218 StyleObj *StyleObj::asStyle()
219 {
220   return this;
221 }
222
223 VarStyleObj::VarStyleObj(const ConstPtr<StyleSpec> &styleSpec, StyleObj *use, ELObj **display,
224                          const NodePtr &node)
225 : styleSpec_(styleSpec), use_(use), display_(display), node_(node)
226 {
227   hasSubObjects_ = 1;
228 }
229
230 VarStyleObj::~VarStyleObj()
231 {
232   delete [] display_;
233 }
234
235 void VarStyleObj::traceSubObjects(Collector &c) const
236 {
237   c.trace(use_);
238   if (display_)
239     for (ELObj **pp = display_; *pp; pp++)
240       c.trace(*pp);
241 }
242
243 void VarStyleObj::appendIterForce(StyleObjIter &iter) const
244 {
245   if (styleSpec_->forceSpecs.size())
246     iter.append(&styleSpec_->forceSpecs, this);
247 }
248
249 void VarStyleObj::appendIterNormal(StyleObjIter &iter) const
250 {
251   if (styleSpec_->specs.size())
252     iter.append(&styleSpec_->specs, this);
253   if (use_)
254     use_->appendIter(iter);
255 }
256
257 void VarStyleObj::appendIter(StyleObjIter &iter) const
258 {
259   VarStyleObj::appendIterForce(iter);
260   VarStyleObj::appendIterNormal(iter);
261 }
262
263 OverriddenStyleObj::OverriddenStyleObj(BasicStyleObj *basic, StyleObj *override)
264 : basic_(basic), override_(override)
265 {
266   hasSubObjects_ = 1;
267 }
268
269 void OverriddenStyleObj::traceSubObjects(Collector &c) const
270 {
271   c.trace(basic_);
272   c.trace(override_);
273 }
274
275 void OverriddenStyleObj::appendIter(StyleObjIter &iter) const
276 {
277   basic_->appendIterForce(iter);
278   override_->appendIter(iter);
279   basic_->appendIterNormal(iter);
280 }
281
282 MergeStyleObj::MergeStyleObj()
283 {
284   hasSubObjects_ = 1;
285 }
286
287 void MergeStyleObj::append(StyleObj *obj)
288 {
289   styles_.push_back(obj);
290 }
291
292 void MergeStyleObj::appendIter(StyleObjIter &iter) const
293 {
294   for (size_t i = 0; i < styles_.size(); i++)
295     styles_[i]->appendIter(iter);
296 }
297
298 void MergeStyleObj::traceSubObjects(Collector &c) const
299 {
300   for (size_t i = 0; i < styles_.size(); i++)
301     c.trace(styles_[i]);
302 }
303
304 ColorObj *ColorObj::asColor()
305 {
306   return this;
307 }
308
309 DeviceRGBColorObj::DeviceRGBColorObj(unsigned char red, unsigned char green,
310                                      unsigned char blue)
311 {
312   color_.red = red;
313   color_.green = green;
314   color_.blue = blue;
315 }
316
317 void DeviceRGBColorObj::set(FOTBuilder &fotb) const
318 {
319   fotb.setColor(color_);
320 }
321
322 void DeviceRGBColorObj::setBackground(FOTBuilder &fotb) const
323 {
324   fotb.setBackgroundColor(color_);
325 }
326
327 ColorSpaceObj *ColorSpaceObj::asColorSpace()
328 {
329   return this;
330 }
331
332 // invert a 3x3 matrix A. result is returned in B
333 // both must be arrays of length 9.
334 static void
335 invert(double *A, double *B)
336 {
337   B[0] =   (A[4]*A[8] - A[5]*A[7]); 
338   B[3] = - (A[3]*A[8] - A[5]*A[6]);
339   B[6] =   (A[3]*A[7] - A[4]*A[6]);
340   B[1] = - (A[1]*A[8] - A[2]*A[7]);
341   B[4] =   (A[0]*A[8] - A[2]*A[6]);
342   B[7] = - (A[0]*A[7] - A[1]*A[6]);
343   B[2] =   (A[1]*A[5] - A[2]*A[4]);
344   B[5] = - (A[0]*A[5] - A[2]*A[3]);
345   B[8] =   (A[0]*A[4] - A[1]*A[3]);
346   double det = A[0]*B[0] + A[1]*B[3] + A[2]*B[6]; 
347   if (det < 0.0001) {
348     //FIXME message
349   }
350   B[0] /= det; B[1] /= det; B[2] /= det;           
351   B[3] /= det; B[4] /= det; B[5] /= det;          
352   B[6] /= det; B[7] /= det; B[8] /= det;         
353 }
354
355 /*
356  FIXME make color handling more flexible:
357   * pass different color types to backends
358   * move the conversion code to a separate
359     class ColorConverter, which could then
360     be used by backends to do the needed
361     conversions. 
362   * make phosphors settable 
363   * make highlight color for KX settable 
364   * whitepoint correction, making the device 
365     whitepoint/blackpoint settable
366
367  for the formulas used here, see:
368   * Computer Graphics, Principles and Practice, Second Edition,
369     Foley, van Damme, Hughes,
370     Addison-Wesley, 1987
371   * Principles of Color Technology, Second Edition, 
372     Fred W. Billmeyer, Jr. and Max Saltzman, 
373     John Wiley & Sons, Inc., 1981
374   * The color faq
375 */
376 CIEXYZColorSpaceObj::CIEXYZColorSpaceObj(const double *wp, const double *bp)
377 {
378   xyzData_ = new XYZData;
379   for (int i = 0; i < 3; i++) 
380     xyzData_->white_[i] = wp[i];
381   double tmp = wp[0] + 15*wp[1] + 3*wp[2]; 
382   xyzData_->white_u = 4*wp[0]/tmp;
383   xyzData_->white_v = 9*wp[1]/tmp;
384
385   // from the color faq
386   double xr = .64; double yr = .33; 
387   double xg = .30; double yg = .60;
388   double xb = .15; double yb = .06;
389   double U[9];
390   U[0] = xr; U[1] = xg; U[2] = xb; 
391   U[3] = yr; U[4] = yg; U[5] = yb; 
392   U[6] = 1.0 - xr - yr; U[7] = 1.0 - xg - yg; U[8] = 1.0 - xb - yb; 
393   double Uinv[9];
394   invert(U, Uinv);  
395   double C[3];
396   for (int i = 0; i < 3; i++) 
397     C[i] = Uinv[3*i]*wp[0] + Uinv[3*i+1]*wp[1] + Uinv[3*i+2]*wp[2];
398   double Minv[9];
399   Minv[0] = U[0]*C[0]; Minv[1] = U[1]*C[1]; Minv[2] = U[2]*C[2];
400   Minv[3] = U[3]*C[0]; Minv[4] = U[4]*C[1]; Minv[5] = U[5]*C[2];
401   Minv[6] = U[6]*C[0]; Minv[7] = U[7]*C[1]; Minv[8] = U[8]*C[2];
402   invert(Minv, xyzData_->M_);
403 }
404
405 CIEXYZColorSpaceObj::~CIEXYZColorSpaceObj()
406 {
407   delete xyzData_;
408 }
409
410 ELObj *CIEXYZColorSpaceObj::makeColor (const double *h, Interpreter &interp)
411 {
412  unsigned char c[3];
413  for (int i = 0; i < 3; i++) 
414    c[i] = (unsigned char) ((xyzData_->M_[3*i]*h[0] 
415                           + xyzData_->M_[3*i+1]*h[1] 
416                           + xyzData_->M_[3*i+2]*h[2])*255.0 + .5);
417
418   return new (interp) DeviceRGBColorObj(c[0], c[1], c[2]);
419 }
420
421 CIELUVColorSpaceObj::CIELUVColorSpaceObj(const double *wp, const double *bp, const double *r) 
422 : CIEXYZColorSpaceObj(wp, bp)
423 {
424   luvData_ = new LUVData;
425   for (int i = 0; i < 6; i++) 
426     luvData_->range_[i] = r ? r[i] : ((i % 2) ? 1.0 : .0);
427 }
428                                          
429 CIELUVColorSpaceObj::~CIELUVColorSpaceObj()
430 {
431   delete luvData_;
432 }
433
434 ELObj *CIELUVColorSpaceObj::makeColor(int argc, ELObj **argv,
435                                  Interpreter &interp, const Location &loc)
436 {
437   if (argc == 0)
438     return new (interp) DeviceRGBColorObj(0, 0, 0);
439   if (argc != 3) {
440     interp.setNextLocation(loc);
441     interp.message(InterpreterMessages::colorArgCount,
442                    StringMessageArg(interp.makeStringC("CIE LUV")));
443     return interp.makeError();
444   }
445   double d[3];
446   for (int i = 0; i < 3; i++) {
447     if (!argv[i]->realValue(d[i])) {
448       interp.setNextLocation(loc);
449       interp.message(InterpreterMessages::colorArgType,
450                      StringMessageArg(interp.makeStringC("CIE LUV")));
451       return interp.makeError();
452     }
453     if (d[i] < luvData_->range_[2*i] || d[i] > luvData_->range_[2*i+1]) {
454       interp.setNextLocation(loc);
455       interp.message(InterpreterMessages::colorArgRange,
456                      StringMessageArg(interp.makeStringC("CIE LUV")));
457       return interp.makeError();
458     }
459   }
460
461   double h[3];
462   if (d[0] == 0.0) {
463     h[0] = h[1] = h[2] = 0.0;
464   } else {                                   
465     if (d[0] <= 7.996968)
466       h[1] = d[0] / 903.0;
467     else { 
468       h[1] = (d[0] + 16.0) / 116.0;
469       h[1] = h[1] * h[1] * h[1];
470     }                                        
471     double uu = d[1] / (13.0 * d[0]) + xyzData_->white_u;
472     double vv = d[2] / (13.0 * d[0]) + xyzData_->white_v;    
473     double tmp = 9.0 * h[1] / vv;                 
474     h[0] = uu * tmp / 4.0;                  
475     h[2] = (tmp - 15.0 * h[1] - h[0]) / 3.0;     
476   }              
477
478   return CIEXYZColorSpaceObj::makeColor(h, interp);
479 }
480
481 CIELABColorSpaceObj::CIELABColorSpaceObj(const double *wp, const double *bp, const double *r) 
482 : CIEXYZColorSpaceObj(wp, bp)
483 {
484   labData_ = new LABData;
485   if (r)
486     for (int i = 0; i < 6; i++) 
487       labData_->range_[i] = r[i];
488   else { 
489     labData_->range_[0] = .0;
490     labData_->range_[1] = 100.0;
491     labData_->range_[2] = .0;
492     labData_->range_[3] = 1.0;
493     labData_->range_[4] = .0;
494     labData_->range_[5] = 1.0;
495   }  
496 }
497                                          
498 CIELABColorSpaceObj::~CIELABColorSpaceObj()
499 {
500   delete labData_;
501 }
502
503 ELObj *CIELABColorSpaceObj::makeColor(int argc, ELObj **argv,
504                                  Interpreter &interp, const Location &loc)
505 {
506   if (argc == 0)
507     return new (interp) DeviceRGBColorObj(0, 0, 0);
508   if (argc != 3) {
509     interp.setNextLocation(loc);
510     interp.message(InterpreterMessages::colorArgCount,
511                    StringMessageArg(interp.makeStringC("CIE LAB")));
512     return interp.makeError();
513   }
514   double d[3];
515   for (int i = 0; i < 3; i++) {
516     if (!argv[i]->realValue(d[i])) {
517       interp.setNextLocation(loc);
518       interp.message(InterpreterMessages::colorArgType,
519                      StringMessageArg(interp.makeStringC("CIE LAB")));
520       return interp.makeError();
521     }
522     if (d[i] < labData_->range_[2*i] || d[i] > labData_->range_[2*i+1]) {
523       interp.setNextLocation(loc);
524       interp.message(InterpreterMessages::colorArgRange,
525                      StringMessageArg(interp.makeStringC("CIE LAB")));
526       return interp.makeError();
527     }
528   }
529   d[0] /= 100.0;
530   
531   double h[3];
532   double tmp = (d[0] + 16.0) / 116.0;
533   h[1] = tmp * tmp * tmp;
534   if (h[1] < 0.008856) {
535     tmp = d[0] / 9.03292;
536     h[0] = xyzData_->white_[0] * ((d[1] / 3893.5) + tmp);
537     h[1] = tmp;
538     h[2] = xyzData_->white_[2] * (tmp - (d[2] / 1557.4));
539   } else {
540     double tmp2 = tmp + (d[1] / 5.0);
541     h[0] = xyzData_->white_[0] * tmp2 * tmp2 * tmp2;
542     tmp2 = tmp - (d[2] / 2.0);
543     h[2] = xyzData_->white_[2] * tmp2 * tmp2 * tmp2;
544   }
545
546   return CIEXYZColorSpaceObj::makeColor(h, interp);
547 }
548
549 CIEABCColorSpaceObj::CIEABCColorSpaceObj(const double *wp, const double *bp, 
550       const double *rabc, FunctionObj **dabc, const double *mabc, 
551       const double *rlmn, FunctionObj **dlmn, const double *mlmn) 
552 : CIEXYZColorSpaceObj(wp, bp)
553 {
554   abcData_ = new ABCData;
555   int i;
556   for (i = 0; i < 6; i++) 
557     abcData_->rangeAbc_[i] = rabc ? rabc[i] : ((i % 2) ? 1.0 : 0.0); 
558   for (i = 0; i < 3; i++)
559     abcData_->decodeAbc_[i] = dabc ? dabc[i] : 0;
560   for (i = 0; i < 9; i++)
561     abcData_->matrixAbc_[i] = mabc ? mabc[i] : ((i % 4) ? 0.0 : 1.0);
562   for (i = 0; i < 6; i++) 
563     abcData_->rangeLmn_[i] = rlmn ? rlmn[i] : ((i % 2) ? 1.0 : 0.0); 
564   for (i = 0; i < 3; i++)
565     abcData_->decodeLmn_[i] = dlmn ? dlmn[i] : 0;
566   for (i = 0; i < 9; i++)
567     abcData_->matrixLmn_[i] = mlmn ? mlmn[i] : ((i % 4) ? 0.0 : 1.0);
568 }
569
570 CIEABCColorSpaceObj::~CIEABCColorSpaceObj()
571 {
572   delete abcData_;
573 }
574
575 void CIEABCColorSpaceObj::traceSubObjects(Collector &c) const
576
577   for (int i = 0; i < 3; i++)  
578     if (abcData_->decodeAbc_[i])
579       c.trace(abcData_->decodeAbc_[i]);
580   for (int i = 0; i < 3; i++)  
581     if (abcData_->decodeLmn_[i])
582       c.trace(abcData_->decodeLmn_[i]);
583   
584 }
585
586 static 
587 bool applyFunc(Interpreter &interp, FunctionObj *f, double &d)
588 {
589   InsnPtr insns[2];
590   insns[1] = f->makeCallInsn(1, interp, Location(), InsnPtr());
591   insns[0] = InsnPtr(new ConstantInsn(new (interp) RealObj(d),insns[1]));
592   VM vm(interp);
593   ELObj *res = vm.eval(insns[0].pointer());
594   if (!res || !res->realValue(d)) 
595     return 0;
596   return 1;
597 }
598
599 ELObj *CIEABCColorSpaceObj::makeColor(int argc, ELObj **argv,
600                                  Interpreter &interp, const Location &loc)
601 {
602   if (argc == 0)
603     return new (interp) DeviceRGBColorObj(0, 0, 0);
604   if (argc != 3) {
605     interp.setNextLocation(loc);
606     interp.message(InterpreterMessages::colorArgCount,
607                    StringMessageArg(interp.makeStringC("CIE Based ABC")));
608     return interp.makeError();
609   }
610   double d[3];
611   for (int i = 0; i < 3; i++) {
612     if (!argv[i]->realValue(d[i])) {
613       interp.setNextLocation(loc);
614       interp.message(InterpreterMessages::colorArgType,
615                      StringMessageArg(interp.makeStringC("CIE Based ABC")));
616       return interp.makeError();
617     }
618     if (d[i] < abcData_->rangeAbc_[2*i] || d[i] > abcData_->rangeAbc_[2*i+1]) {
619       interp.setNextLocation(loc);
620       interp.message(InterpreterMessages::colorArgRange,
621                      StringMessageArg(interp.makeStringC("CIE Based ABC")));
622       return interp.makeError();
623     }
624     if (abcData_->decodeAbc_[i] && !applyFunc(interp, abcData_->decodeAbc_[i], d[i])) {
625       interp.setNextLocation(loc);
626       interp.message(InterpreterMessages::colorProcResType,
627                      StringMessageArg(interp.makeStringC("CIE Based ABC")));
628       return interp.makeError();
629     }
630   }
631   double l[3];
632   for (int i = 0; i < 3; i++) { 
633     l[i] = abcData_->matrixAbc_[i]*d[0] 
634          + abcData_->matrixAbc_[3+i]*d[1] 
635          + abcData_->matrixAbc_[6+i]*d[2];
636     if (l[i] < abcData_->rangeLmn_[2*i] || l[i] > abcData_->rangeLmn_[2*i+1]) {
637       interp.setNextLocation(loc);
638       interp.message(InterpreterMessages::colorArgRange,
639                      StringMessageArg(interp.makeStringC("CIE Based ABC")));
640       return interp.makeError();
641     }
642     if (abcData_->decodeLmn_[i] && !applyFunc(interp, abcData_->decodeLmn_[i], l[i])) {
643       interp.setNextLocation(loc);
644       interp.message(InterpreterMessages::colorProcResType,
645                      StringMessageArg(interp.makeStringC("CIE Based ABC")));
646       return interp.makeError();
647     }
648   }
649   double h[3];
650   for (int i = 0; i < 3; i++)  
651     h[i] = abcData_->matrixLmn_[i]*l[0] 
652          + abcData_->matrixLmn_[3+i]*l[1] 
653          + abcData_->matrixLmn_[6+i]*l[2];
654
655   return CIEXYZColorSpaceObj::makeColor(h, interp);
656 }
657
658 CIEAColorSpaceObj::CIEAColorSpaceObj(const double *wp, const double *bp, 
659       const double *ra, FunctionObj *da, const double *ma, 
660       const double *rlmn, FunctionObj **dlmn, const double *mlmn) 
661 : CIEXYZColorSpaceObj(wp, bp)
662 {
663   aData_ = new AData;
664   int i;
665   for (i = 0; i < 2; i++) 
666     aData_->rangeA_[i] = ra ? ra[i] : ((i % 2) ? 1.0 : 0.0); 
667   aData_->decodeA_ = da ? da : 0;
668   for (i = 0; i < 3; i++)
669     aData_->matrixA_[i] = ma ? ma[i] : 1.0;
670   for (i = 0; i < 6; i++) 
671     aData_->rangeLmn_[i] = rlmn ? rlmn[i] : ((i % 2) ? 1.0 : 0.0); 
672   for (i = 0; i < 3; i++)
673     aData_->decodeLmn_[i] = dlmn ? dlmn[i] : 0;
674   for (i = 0; i < 9; i++)
675     aData_->matrixLmn_[i] = mlmn ? mlmn[i] : ((i % 4) ? 0.0 : 1.0);
676 }
677
678 CIEAColorSpaceObj::~CIEAColorSpaceObj()
679 {
680   delete aData_;
681 }
682
683 void CIEAColorSpaceObj::traceSubObjects(Collector &c) const
684
685   if (aData_->decodeA_)
686     c.trace(aData_->decodeA_);
687   for (int i = 0; i < 3; i++)  
688     if (aData_->decodeLmn_[i])
689       c.trace(aData_->decodeLmn_[i]);
690 }
691
692 ELObj *CIEAColorSpaceObj::makeColor(int argc, ELObj **argv,
693                                  Interpreter &interp, const Location &loc)
694 {
695   if (argc == 0)
696     return new (interp) DeviceRGBColorObj(0, 0, 0);
697   if (argc != 1) {
698     interp.setNextLocation(loc);
699     interp.message(InterpreterMessages::colorArgCount,
700                    StringMessageArg(interp.makeStringC("CIE Based A")));
701     return interp.makeError();
702   }
703   double d;
704   if (!argv[0]->realValue(d)) {
705     interp.setNextLocation(loc);
706     interp.message(InterpreterMessages::colorArgType,
707                    StringMessageArg(interp.makeStringC("CIE Based A")));
708     return interp.makeError();
709   }
710   if (d < aData_->rangeA_[0] || d > aData_->rangeA_[1]) {
711     interp.setNextLocation(loc);
712     interp.message(InterpreterMessages::colorArgRange,
713                    StringMessageArg(interp.makeStringC("CIE Based A")));
714     return interp.makeError();
715   }
716   if (aData_->decodeA_ && !applyFunc(interp, aData_->decodeA_, d)) {
717     interp.setNextLocation(loc);
718     interp.message(InterpreterMessages::colorProcResType,
719                    StringMessageArg(interp.makeStringC("CIE Based A")));
720     return interp.makeError();
721   }
722   double l[3];
723   for (int i = 0; i < 3; i++) { 
724     l[i] = aData_->matrixA_[i]*d;  
725     if (l[i] < aData_->rangeLmn_[2*i] || l[i] > aData_->rangeLmn_[2*i+1]) {
726       interp.setNextLocation(loc);
727       interp.message(InterpreterMessages::colorArgRange,
728                      StringMessageArg(interp.makeStringC("CIE Based A")));
729       return interp.makeError();
730     }
731     if (aData_->decodeLmn_[i] && !applyFunc(interp, aData_->decodeLmn_[i], l[i])) {
732       interp.setNextLocation(loc);
733       interp.message(InterpreterMessages::colorProcResType,
734                      StringMessageArg(interp.makeStringC("CIE Based A")));
735       return interp.makeError();
736     }
737   }
738   double h[3];
739   for (int i = 0; i < 3; i++) { 
740     h[i] = aData_->matrixLmn_[i]*l[0] 
741          + aData_->matrixLmn_[3+i]*l[1] 
742          + aData_->matrixLmn_[6+i]*l[2];
743   }
744   return CIEXYZColorSpaceObj::makeColor(h, interp);
745 }
746
747 ELObj *DeviceRGBColorSpaceObj::makeColor(int argc, ELObj **argv,
748                                          Interpreter &interp, const Location &loc)
749 {
750   if (argc == 0)
751     return new (interp) DeviceRGBColorObj(0, 0, 0);
752   if (argc != 3) {
753     interp.setNextLocation(loc);
754     interp.message(InterpreterMessages::colorArgCount,
755                    StringMessageArg(interp.makeStringC("Device RGB")));
756     return interp.makeError();
757   }
758   unsigned char c[3];
759   for (int i = 0; i < 3; i++) {
760     double d;
761     if (!argv[i]->realValue(d)) {
762       interp.setNextLocation(loc);
763       interp.message(InterpreterMessages::colorArgType,
764                      StringMessageArg(interp.makeStringC("Device RGB")));
765       return interp.makeError();
766     }
767     if (d < 0.0 || d > 1.0) {
768       interp.setNextLocation(loc);
769       interp.message(InterpreterMessages::colorArgRange,
770                      StringMessageArg(interp.makeStringC("Device RGB")));
771       return interp.makeError();
772     }
773     c[i] = (unsigned char)(d*255.0 + .5);
774   }
775   return new (interp) DeviceRGBColorObj(c[0], c[1], c[2]);
776 }
777
778 ELObj *DeviceGrayColorSpaceObj::makeColor(int argc, ELObj **argv,
779                                          Interpreter &interp, const Location &loc)
780 {
781   if (argc == 0)
782     return new (interp) DeviceRGBColorObj(0, 0, 0);
783   if (argc != 1) {
784     interp.setNextLocation(loc);
785     interp.message(InterpreterMessages::colorArgCount,
786                    StringMessageArg(interp.makeStringC("Device Gray")));
787     return interp.makeError();
788   }
789   unsigned char c;
790   double d;
791   if (!argv[0]->realValue(d)) {
792     interp.setNextLocation(loc);
793     interp.message(InterpreterMessages::colorArgType,
794                    StringMessageArg(interp.makeStringC("Device Gray")));
795     return interp.makeError();
796   }
797   if (d < 0.0 || d > 1.0) {
798     interp.setNextLocation(loc);
799     interp.message(InterpreterMessages::colorArgRange,
800                    StringMessageArg(interp.makeStringC("Device Gray")));
801     return interp.makeError();
802   }
803   c = (unsigned char)(d*255.0 + .5);
804   return new (interp) DeviceRGBColorObj(c, c, c);
805 }
806
807 #define MIN(x,y) (((x) < (y)) ? (x) : (y)) 
808
809 ELObj *DeviceCMYKColorSpaceObj::makeColor(int argc, ELObj **argv,
810                                          Interpreter &interp, const Location &loc)
811 {
812   if (argc == 0)
813     return new (interp) DeviceRGBColorObj(0, 0, 0);
814   if (argc != 4) {
815     interp.setNextLocation(loc);
816     interp.message(InterpreterMessages::colorArgCount,
817                    StringMessageArg(interp.makeStringC("Device CMYK")));
818     return interp.makeError();
819   }
820   double d[4];
821   for (int i = 0; i < 4; i++) {
822     if (!argv[i]->realValue(d[i])) {
823       interp.setNextLocation(loc);
824       interp.message(InterpreterMessages::colorArgType,
825                      StringMessageArg(interp.makeStringC("Device CMYK")));
826       return interp.makeError();
827     }
828     if (d[i] < 0.0 || d[i] > 1.0) {
829       interp.setNextLocation(loc);
830       interp.message(InterpreterMessages::colorArgRange,
831                      StringMessageArg(interp.makeStringC("Device CMYK")));
832       return interp.makeError();
833     }
834   }
835   unsigned char c[3];
836   for (int i = 0; i < 3; i++) 
837     c[i] = (unsigned char)((1 - MIN(1, d[i] + d[3]))*255.0 + .5);
838   return new (interp) DeviceRGBColorObj(c[0], c[1], c[2]);
839 }
840
841 ELObj *DeviceKXColorSpaceObj::makeColor(int argc, ELObj **argv,
842                                          Interpreter &interp, const Location &loc)
843 {
844   if (argc == 0)
845     return new (interp) DeviceRGBColorObj(0, 0, 0);
846   if (argc != 2) {
847     interp.setNextLocation(loc);
848     interp.message(InterpreterMessages::colorArgCount,
849                    StringMessageArg(interp.makeStringC("Device KX")));
850     return interp.makeError();
851   }
852   double d[2];
853   for (int i = 0; i < 2; i++) {
854     if (!argv[i]->realValue(d[i])) {
855       interp.setNextLocation(loc);
856       interp.message(InterpreterMessages::colorArgType,
857                      StringMessageArg(interp.makeStringC("Device KX")));
858       return interp.makeError();
859     }
860     if (d[i] < 0.0 || d[i] > 1.0) {
861       interp.setNextLocation(loc);
862       interp.message(InterpreterMessages::colorArgRange,
863                      StringMessageArg(interp.makeStringC("Device KX")));
864       return interp.makeError();
865     }
866   }
867   unsigned char c;
868   c = (unsigned char)((1 - MIN(1, d[0] + d[1]))*255.0 + .5);
869   return new (interp) DeviceRGBColorObj(c, c, c);
870 }
871
872 VarInheritedC::VarInheritedC(const ConstPtr<InheritedC> &ic,
873                              const InsnPtr &code, const Location &loc)
874 : InheritedC(ic->identifier(), ic->index()), inheritedC_(ic), code_(code), loc_(loc)
875 {
876 }
877
878 void VarInheritedC::set(VM &vm, const VarStyleObj *style, FOTBuilder &fotb,
879                         ELObj *&cacheObj, Vector<size_t> &dependencies) const
880 {
881   if (!cacheObj) {
882     EvalContext::CurrentNodeSetter cns(style->node(), 0, vm);
883     vm.actualDependencies = &dependencies;
884     cacheObj = vm.eval(code_.pointer(), style->display());
885     ASSERT(cacheObj != 0);
886     vm.actualDependencies = 0;
887   }
888   if (!vm.interp->isError(cacheObj)) {
889     ConstPtr<InheritedC> c(inheritedC_->make(cacheObj, loc_, *vm.interp));
890     if (!c.isNull())
891       c->set(vm, 0, fotb, cacheObj, dependencies);
892   }
893 }
894
895 ConstPtr<InheritedC> VarInheritedC::make(ELObj *obj, const Location &loc, Interpreter &interp)
896      const
897 {
898   return inheritedC_->make(obj, loc, interp);
899 }
900
901 ELObj *VarInheritedC::value(VM &vm, const VarStyleObj *style,
902                             Vector<size_t> &dependencies) const
903 {
904   EvalContext::CurrentNodeSetter cns(style->node(), 0, vm);
905   vm.actualDependencies = &dependencies;
906   return vm.eval(code_.pointer(), style->display());
907 }
908
909 StyleObjIter::StyleObjIter()
910 : i_(0), vi_(0)
911 {
912 }
913
914 void StyleObjIter::append(const Vector<ConstPtr<InheritedC> > *v, const VarStyleObj *obj)
915 {
916   styleVec_.push_back(obj);
917   vecs_.push_back(v);
918 }
919
920 ConstPtr<InheritedC> StyleObjIter::next(const VarStyleObj *&style)
921 {
922   for (; vi_ < vecs_.size(); vi_++, i_ = 0) {
923     if (i_ < vecs_[vi_]->size()) {
924       style = styleVec_[vi_];
925       return (*vecs_[vi_])[i_++];
926     }
927   }
928   return ConstPtr<InheritedC>();
929 }
930
931 StyleSpec::StyleSpec(Vector<ConstPtr<InheritedC> > &fs, Vector<ConstPtr<InheritedC> > &s)
932 {
933   fs.swap(forceSpecs);
934   s.swap(specs);
935 }
936
937 #ifdef DSSSL_NAMESPACE
938 }
939 #endif
940