1 2 /* 3 * Copyright 2006 The Android Open Source Project 4 * 5 * Use of this source code is governed by a BSD-style license that can be 6 * found in the LICENSE file. 7 */ 8 9 10 #include "SkDisplayPost.h" 11 #include "SkAnimateMaker.h" 12 #include "SkAnimator.h" 13 #include "SkDisplayMovie.h" 14 #include "SkPostParts.h" 15 #include "SkScript.h" 16 #ifdef SK_DEBUG 17 #include "SkDump.h" 18 #include "SkTime.h" 19 #endif 20 21 enum SkPost_Properties { 22 SK_PROPERTY(target), 23 SK_PROPERTY(type) 24 }; 25 26 #if SK_USE_CONDENSED_INFO == 0 27 28 const SkMemberInfo SkPost::fInfo[] = { 29 SK_MEMBER(delay, MSec), 30 // SK_MEMBER(initialized, Boolean), 31 SK_MEMBER(mode, EventMode), 32 SK_MEMBER(sink, String), 33 SK_MEMBER_PROPERTY(target, String), 34 SK_MEMBER_PROPERTY(type, String) 35 }; 36 37 #endif 38 39 DEFINE_GET_MEMBER(SkPost); 40 41 SkPost::SkPost() : delay(0), /*initialized(SkBool(-1)), */ mode(kImmediate), fMaker(NULL), 42 fSinkID(0), fTargetMaker(NULL), fChildHasID(false), fDirty(false) { 43 } 44 45 SkPost::~SkPost() { 46 for (SkDataInput** part = fParts.begin(); part < fParts.end(); part++) 47 delete *part; 48 } 49 50 bool SkPost::add(SkAnimateMaker& , SkDisplayable* child) { 51 SkASSERT(child && child->isDataInput()); 52 SkDataInput* part = (SkDataInput*) child; 53 *fParts.append() = part; 54 return true; 55 } 56 57 bool SkPost::childrenNeedDisposing() const { 58 return false; 59 } 60 61 void SkPost::dirty() { 62 fDirty = true; 63 } 64 65 #ifdef SK_DUMP_ENABLED 66 void SkPost::dump(SkAnimateMaker* maker) { 67 dumpBase(maker); 68 SkString* eventType = new SkString(); 69 fEvent.getType(eventType); 70 if (eventType->equals("user")) { 71 const char* target = fEvent.findString("id"); 72 SkDebugf("target=\"%s\" ", target); 73 } 74 else 75 SkDebugf("type=\"%s\" ", eventType->c_str()); 76 delete eventType; 77 78 if (delay > 0) { 79 #ifdef SK_CAN_USE_FLOAT 80 SkDebugf("delay=\"%g\" ", SkScalarToFloat(SkScalarDiv(delay, 1000))); 81 #else 82 SkDebugf("delay=\"%x\" ", SkScalarDiv(delay, 1000)); 83 #endif 84 } 85 // if (initialized == false) 86 // SkDebugf("(uninitialized) "); 87 SkString string; 88 SkDump::GetEnumString(SkType_EventMode, mode, &string); 89 if (!string.equals("immediate")) 90 SkDebugf("mode=\"%s\" ", string.c_str()); 91 // !!! could enhance this to search through make hierarchy to show name of sink 92 if (sink.size() > 0) { 93 SkDebugf("sink=\"%s\" sinkID=\"%d\" ", sink.c_str(), fSinkID); 94 } else if (fSinkID != maker->getAnimator()->getSinkID() && fSinkID != 0) { 95 SkDebugf("sinkID=\"%d\" ", fSinkID); 96 } 97 const SkMetaData& meta = fEvent.getMetaData(); 98 SkMetaData::Iter iter(meta); 99 SkMetaData::Type type; 100 int number; 101 const char* name; 102 bool closedYet = false; 103 SkDisplayList::fIndent += 4; 104 //this seems to work, but kinda hacky 105 //for some reason the last part is id, which i don't want 106 //and the parts seem to be in the reverse order from the one in which we find the 107 //data itself 108 //SkDataInput** ptr = fParts.end(); 109 //SkDataInput* data; 110 //const char* ID; 111 while ((name = iter.next(&type, &number)) != NULL) { 112 //ptr--; 113 if (strcmp(name, "id") == 0) 114 continue; 115 if (closedYet == false) { 116 SkDebugf(">\n"); 117 closedYet = true; 118 } 119 //data = *ptr; 120 //if (data->id) 121 // ID = data->id; 122 //else 123 // ID = ""; 124 SkDebugf("%*s<data name=\"%s\" ", SkDisplayList::fIndent, "", name); 125 switch (type) { 126 case SkMetaData::kS32_Type: { 127 int32_t s32; 128 meta.findS32(name, &s32); 129 SkDebugf("int=\"%d\" ", s32); 130 } break; 131 case SkMetaData::kScalar_Type: { 132 SkScalar scalar; 133 meta.findScalar(name, &scalar); 134 #ifdef SK_CAN_USE_FLOAT 135 SkDebugf("float=\"%g\" ", SkScalarToFloat(scalar)); 136 #else 137 SkDebugf("float=\"%x\" ", scalar); 138 #endif 139 } break; 140 case SkMetaData::kString_Type: 141 SkDebugf("string=\"%s\" ", meta.findString(name)); 142 break; 143 case SkMetaData::kPtr_Type: {//when do we have a pointer 144 void* ptr; 145 meta.findPtr(name, &ptr); 146 SkDebugf("0x%08x ", ptr); 147 } break; 148 case SkMetaData::kBool_Type: { 149 bool boolean; 150 meta.findBool(name, &boolean); 151 SkDebugf("boolean=\"%s\" ", boolean ? "true " : "false "); 152 } break; 153 default: 154 break; 155 } 156 SkDebugf("/>\n"); 157 //ptr++; 158 /* perhaps this should only be done in the case of a pointer? 159 SkDisplayable* displayable; 160 if (maker->find(name, &displayable)) 161 displayable->dump(maker); 162 else 163 SkDebugf("\n");*/ 164 } 165 SkDisplayList::fIndent -= 4; 166 if (closedYet) 167 dumpEnd(maker); 168 else 169 SkDebugf("/>\n"); 170 171 } 172 #endif 173 174 bool SkPost::enable(SkAnimateMaker& maker ) { 175 if (maker.hasError()) 176 return true; 177 if (fDirty) { 178 if (sink.size() > 0) 179 findSinkID(); 180 if (fChildHasID) { 181 SkString preserveID(fEvent.findString("id")); 182 fEvent.getMetaData().reset(); 183 if (preserveID.size() > 0) 184 fEvent.setString("id", preserveID); 185 for (SkDataInput** part = fParts.begin(); part < fParts.end(); part++) { 186 if ((*part)->add()) 187 maker.setErrorCode(SkDisplayXMLParserError::kErrorAddingDataToPost); 188 } 189 } 190 fDirty = false; 191 } 192 #ifdef SK_DUMP_ENABLED 193 if (maker.fDumpPosts) { 194 SkDebugf("post enable: "); 195 dump(&maker); 196 } 197 #if defined SK_DEBUG_ANIMATION_TIMING 198 SkString debugOut; 199 SkMSec time = maker.getAppTime(); 200 debugOut.appendS32(time - maker.fDebugTimeBase); 201 debugOut.append(" post id="); 202 debugOut.append(_id); 203 debugOut.append(" enable="); 204 debugOut.appendS32(maker.fEnableTime - maker.fDebugTimeBase); 205 debugOut.append(" delay="); 206 debugOut.appendS32(delay); 207 #endif 208 #endif 209 // SkMSec adjustedDelay = maker.adjustDelay(maker.fEnableTime, delay); 210 SkMSec futureTime = maker.fEnableTime + delay; 211 fEvent.setFast32(futureTime); 212 #if defined SK_DEBUG && defined SK_DEBUG_ANIMATION_TIMING 213 debugOut.append(" future="); 214 debugOut.appendS32(futureTime - maker.fDebugTimeBase); 215 SkDebugf("%s\n", debugOut.c_str()); 216 #endif 217 SkEventSinkID targetID = fSinkID; 218 bool isAnimatorEvent = true; 219 SkAnimator* anim = maker.getAnimator(); 220 if (targetID == 0) { 221 isAnimatorEvent = fEvent.findString("id") != NULL; 222 if (isAnimatorEvent) 223 targetID = anim->getSinkID(); 224 else if (maker.fHostEventSinkID) 225 targetID = maker.fHostEventSinkID; 226 else 227 return true; 228 } else 229 anim = fTargetMaker->getAnimator(); 230 if (delay == 0) { 231 if (isAnimatorEvent && mode == kImmediate) 232 fTargetMaker->doEvent(fEvent); 233 else 234 anim->onEventPost(new SkEvent(fEvent), targetID); 235 } else 236 anim->onEventPostTime(new SkEvent(fEvent), targetID, futureTime); 237 return true; 238 } 239 240 void SkPost::findSinkID() { 241 // get the next delimiter '.' if any 242 fTargetMaker = fMaker; 243 const char* ch = sink.c_str(); 244 do { 245 const char* end = strchr(ch, '.'); 246 size_t len = end ? end - ch : strlen(ch); 247 SkDisplayable* displayable = NULL; 248 if (SK_LITERAL_STR_EQUAL("parent", ch, len)) { 249 if (fTargetMaker->fParentMaker) 250 fTargetMaker = fTargetMaker->fParentMaker; 251 else { 252 fTargetMaker->setErrorCode(SkDisplayXMLParserError::kNoParentAvailable); 253 return; 254 } 255 } else { 256 fTargetMaker->find(ch, len, &displayable); 257 if (displayable == NULL || displayable->getType() != SkType_Movie) { 258 fTargetMaker->setErrorCode(SkDisplayXMLParserError::kExpectedMovie); 259 return; 260 } 261 SkDisplayMovie* movie = (SkDisplayMovie*) displayable; 262 fTargetMaker = movie->fMovie.fMaker; 263 } 264 if (end == NULL) 265 break; 266 ch = ++end; 267 } while (true); 268 SkAnimator* anim = fTargetMaker->getAnimator(); 269 fSinkID = anim->getSinkID(); 270 } 271 272 bool SkPost::hasEnable() const { 273 return true; 274 } 275 276 void SkPost::onEndElement(SkAnimateMaker& maker) { 277 fTargetMaker = fMaker = &maker; 278 if (fChildHasID == false) { 279 for (SkDataInput** part = fParts.begin(); part < fParts.end(); part++) 280 delete *part; 281 fParts.reset(); 282 } 283 } 284 285 void SkPost::setChildHasID() { 286 fChildHasID = true; 287 } 288 289 bool SkPost::setProperty(int index, SkScriptValue& value) { 290 SkASSERT(value.fType == SkType_String); 291 SkString* string = value.fOperand.fString; 292 switch(index) { 293 case SK_PROPERTY(target): { 294 fEvent.setType("user"); 295 fEvent.setString("id", *string); 296 mode = kImmediate; 297 } break; 298 case SK_PROPERTY(type): 299 fEvent.setType(*string); 300 break; 301 default: 302 SkASSERT(0); 303 return false; 304 } 305 return true; 306 } 307 308