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